From 8adff4bf72b2193858f94f6be5ff46a8570a09c5 Mon Sep 17 00:00:00 2001 From: Tomasz Sapeta Date: Mon, 11 May 2026 18:40:55 +0200 Subject: [PATCH 01/15] [app-metrics][android] Persist and dispatch log events (#45549) --- .../modules/appmetrics/AppMetricsModule.kt | 42 +++- .../logevents/AttributeValidation.kt | 127 +++++++++++ .../logevents/EventBodyValidation.kt | 43 ++++ .../logevents/EventNameValidation.kt | 47 ++++ .../appmetrics/logevents/LogEventOptions.kt | 15 ++ .../modules/appmetrics/logevents/Severity.kt | 40 ++++ .../appmetrics/storage/MetricsDatabase.kt | 65 +++++- .../appmetrics/storage/SessionManager.kt | 58 +++++ .../appmetrics/storage/SessionMappers.kt | 60 ++--- .../expo/modules/appmetrics/utils/JsonAny.kt | 59 +++++ .../logevents/AttributeValidationTest.kt | 151 +++++++++++++ .../logevents/EventBodyValidationTest.kt | 52 +++++ .../logevents/EventNameValidationTest.kt | 56 +++++ .../appmetrics/storage/SessionManagerTest.kt | 94 ++++++++ .../appmetrics/storage/SessionMappersTest.kt | 96 ++++++++ .../main/java/expo/modules/observe/Event.kt | 38 +++- .../expo/modules/observe/EventDispatcher.kt | 89 +++++--- .../modules/observe/OTAnyValueSerializer.kt | 111 ++++++++++ .../observe/ObservabilityBackgroundWorker.kt | 6 +- .../modules/observe/ObservabilityManager.kt | 56 +++++ .../expo/modules/observe/ObserveModule.kt | 5 +- .../expo/modules/observe/OpenTelemetry.kt | 205 +++++++++++++++++- .../observe/storage/ObserveDatabase.kt | 26 ++- .../observe/storage/PendingLogsManager.kt | 38 ++++ .../observe/BaseObservabilityManagerTest.kt | 7 +- .../expo/modules/observe/OTAnyValueTest.kt | 177 +++++++++++++++ .../expo/modules/observe/OpenTelemetryTest.kt | 45 ++++ 27 files changed, 1739 insertions(+), 69 deletions(-) create mode 100644 packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/AttributeValidation.kt create mode 100644 packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/EventBodyValidation.kt create mode 100644 packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/EventNameValidation.kt create mode 100644 packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/LogEventOptions.kt create mode 100644 packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/Severity.kt create mode 100644 packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/utils/JsonAny.kt create mode 100644 packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/AttributeValidationTest.kt create mode 100644 packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/EventBodyValidationTest.kt create mode 100644 packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/EventNameValidationTest.kt create mode 100644 packages/expo-observe/android/src/main/java/expo/modules/observe/OTAnyValueSerializer.kt create mode 100644 packages/expo-observe/android/src/main/java/expo/modules/observe/storage/PendingLogsManager.kt create mode 100644 packages/expo-observe/android/src/test/java/expo/modules/observe/OTAnyValueTest.kt diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/AppMetricsModule.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/AppMetricsModule.kt index 5c1da95ec5a5a9..3793021a44b75d 100644 --- a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/AppMetricsModule.kt +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/AppMetricsModule.kt @@ -2,8 +2,15 @@ package expo.modules.appmetrics import android.content.Context import expo.modules.appmetrics.appstartup.AppStartupManager +import expo.modules.appmetrics.logevents.LogEventOptions +import expo.modules.appmetrics.logevents.Severity +import expo.modules.appmetrics.logevents.attributesToJsonObject +import expo.modules.appmetrics.logevents.sanitizeLogEventAttributes +import expo.modules.appmetrics.logevents.validateEventBody +import expo.modules.appmetrics.logevents.validateEventName import expo.modules.appmetrics.memory.MemoryMetricsManager import expo.modules.appmetrics.storage.JsSession +import expo.modules.appmetrics.storage.LogRecord import expo.modules.appmetrics.storage.Metric import expo.modules.appmetrics.storage.SessionManager import expo.modules.appmetrics.updates.UpdatesMonitoring @@ -70,6 +77,35 @@ class AppMetricsModule : Module(), UpdatesStateChangeListener { } } + Function("logEvent") { name: String, options: LogEventOptions? -> + val validatedName = validateEventName(name) ?: return@Function + val validatedBody = validateEventBody(options?.body) + val sanitized = sanitizeLogEventAttributes(options?.attributes) + val severity = options?.severity ?: Severity.INFO + + scope.launch { + // Attach any pending startup metrics first so the session has them + // alongside whatever's being logged. The session row itself is + // already persisted eagerly in `OnCreate`, so this is purely about + // ordering startup-metric writes ahead of caller-driven log events. + saveStartupMetricsIfNotSaved() + sessionManager.addLogs( + listOf( + LogRecord( + sessionId = appSessionId, + timestamp = TimeUtils.getCurrentTimestampInISOFormat(), + name = validatedName, + body = validatedBody, + severity = severity.rawValue, + attributes = sanitized.attributes?.let { Json.encodeToString(attributesToJsonObject(it)) }, + droppedAttributesCount = sanitized.droppedCount + ) + ), + sessionId = appSessionId + ) + } + } + OnCreate { sessionManager = SessionManager(context) @@ -180,9 +216,9 @@ class AppMetricsModule : Module(), UpdatesStateChangeListener { if (UpdatesStateEvent.fromMap(event)?.type == UpdatesStateEvent.EventType.DownloadCompleteWithUpdate) { updatesMonitoring.downloadTimeMetric(subscription)?.let { metric -> scope.launch { - // Ensure the session row exists before inserting the metric, - // since the session may not have been saved yet if the download - // completes before markInteractive or app backgrounding. + // Attach any pending startup metrics first so the download-time + // metric lands alongside them. The session row itself is already + // persisted eagerly in `OnCreate`. saveStartupMetricsIfNotSaved() sessionManager.addMetrics(listOf(metric), sessionId = appSessionId) } diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/AttributeValidation.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/AttributeValidation.kt new file mode 100644 index 00000000000000..8a40ffed392702 --- /dev/null +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/AttributeValidation.kt @@ -0,0 +1,127 @@ +package expo.modules.appmetrics.logevents + +import android.util.Log +import expo.modules.appmetrics.TAG +import expo.modules.appmetrics.utils.JsonAny +import kotlinx.serialization.json.JsonObject + +/** + * Patterns that match attribute keys reserved by the SDK. Caller-provided + * attributes whose key matches any of these are dropped: + * + * - The `expo.*` namespace, owned entirely by the SDK (e.g. `expo.app.name`, + * `expo.eas_client.id`). + * - Specific OTel Semantic Convention keys the SDK sets on every record + * (e.g. `session.id`, `event.name`). Letting callers set these would + * produce duplicate-attribute errors on the collector. + */ +private val RESERVED_ATTRIBUTE_PATTERNS: List = listOf( + Regex("^expo\\..+"), + Regex("^session\\.id$"), + Regex("^event\\.name$") +) + +/** + * Maximum number of attributes accepted per log record. Mirrors the OTel SDK + * default (`OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT`) — collectors and backends + * start to push back well before this limit, so we cap eagerly and surface the + * overflow via `droppedAttributesCount`. + * + * Spec: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#logrecord-limits + */ +private const val MAX_ATTRIBUTE_COUNT = 128 + +/** + * Result of sanitizing caller-provided log-event attributes. + * + * - `attributes`: the attributes that survived validation, or `null` when the + * input was `null` or every entry was dropped. + * - `droppedCount`: number of attributes that were dropped during validation. + * Surfaced on the OTel wire as `droppedAttributesCount` so backends know the + * record was filtered. + */ +data class SanitizedLogAttributes( + val attributes: Map?, + val droppedCount: Int +) + +/** + * Filters caller-provided log-event attributes. Drops: + * + * - keys that are empty after trimming whitespace, + * - keys under the reserved `expo.*` namespace or matching SDK-set keys, + * - everything past the per-record attribute count cap. + * + * Each rule warns with its own message so the developer can tell at a glance + * which rule fired. + */ +internal fun sanitizeLogEventAttributes(attributes: Map?): SanitizedLogAttributes { + if (attributes == null) { + return SanitizedLogAttributes(attributes = null, droppedCount = 0) + } + + val sanitized = mutableMapOf() + var emptyKeyDrops = 0 + val reservedKeyDrops = mutableListOf() + + for ((key, value) in attributes) { + val trimmedKey = key.trim() + if (trimmedKey.isEmpty()) { + emptyKeyDrops += 1 + continue + } + if (RESERVED_ATTRIBUTE_PATTERNS.any { it.matches(trimmedKey) }) { + reservedKeyDrops += key + continue + } + sanitized[trimmedKey] = value + } + + // Apply the per-record cap last so the count reflects every other rule first. + // Sort by key for a stable choice of which entries survive the cap; otherwise + // map iteration order would make this nondeterministic. Note this biases + // retention toward alphabetically-earlier keys when the cap is hit — + // acceptable for accidental-overflow cases (loop bug, typo); a caller that + // genuinely needs >128 attributes should split them across multiple events. + var overflowDrops = 0 + if (sanitized.size > MAX_ATTRIBUTE_COUNT) { + val droppedKeys = sanitized.keys.sorted().drop(MAX_ATTRIBUTE_COUNT).toSet() + overflowDrops = droppedKeys.size + sanitized.keys.removeAll(droppedKeys) + } + + if (emptyKeyDrops > 0) { + Log.w( + TAG, + "[AppMetrics] logEvent dropped $emptyKeyDrops attribute(s) with empty or whitespace-only keys." + ) + } + if (reservedKeyDrops.isNotEmpty()) { + val formattedKeys = reservedKeyDrops.sorted().joinToString(", ") { "`$it`" } + Log.w( + TAG, + "[AppMetrics] logEvent dropped attributes that overlap SDK-set keys or use the reserved `expo.` namespace: $formattedKeys." + ) + } + if (overflowDrops > 0) { + Log.w( + TAG, + "[AppMetrics] logEvent dropped $overflowDrops attribute(s) past the $MAX_ATTRIBUTE_COUNT-attribute per-record cap." + ) + } + + return SanitizedLogAttributes( + attributes = if (sanitized.isEmpty()) null else sanitized, + droppedCount = emptyKeyDrops + reservedKeyDrops.size + overflowDrops + ) +} + +/** + * Converts a sanitized attribute map to a `JsonObject` for storage. Values + * whose type cannot be represented in OTLP (e.g. `Date`, NaN/Infinity doubles) + * are encoded as JSON `null` here; the typed-attribute encoder at dispatch + * time will skip them and add to `droppedAttributesCount` accordingly. + */ +internal fun attributesToJsonObject(attributes: Map): JsonObject { + return JsonObject(attributes.mapValues { (_, value) -> JsonAny.toElement(value) }) +} diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/EventBodyValidation.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/EventBodyValidation.kt new file mode 100644 index 00000000000000..d7d1f02d9aa8ac --- /dev/null +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/EventBodyValidation.kt @@ -0,0 +1,43 @@ +package expo.modules.appmetrics.logevents + +import android.util.Log +import expo.modules.appmetrics.TAG + +/** + * Maximum length of a log event body, measured in UTF-16 code units (Kotlin + * `String.length`). Bodies longer than this are truncated rather than dropped, + * preserving the prefix (most useful for "what happened") and appending an + * ellipsis suffix so consumers can tell the value was cut. + * + * The OTel spec leaves the equivalent log-record body limit unset by default + * (https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#logrecord-limits); + * 4096 is our own cap, chosen to match the SDK's default + * `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT` for symmetry with attribute values. + */ +private const val MAX_EVENT_BODY_LENGTH = 4096 + +/** + * Suffix appended to truncated bodies. Single character so the prefix stays + * close to the original length budget. + */ +private const val TRUNCATION_SUFFIX = "…" + +/** + * Truncates a caller-provided log event body to `MAX_EVENT_BODY_LENGTH` characters, + * logging a warning when truncation happens. Returns `null` for `null` input so + * the call site can pass the result through unchanged. + */ +internal fun validateEventBody(body: String?): String? { + if (body == null) { + return null + } + if (body.length <= MAX_EVENT_BODY_LENGTH) { + return body + } + val truncated = body.substring(0, MAX_EVENT_BODY_LENGTH - TRUNCATION_SUFFIX.length) + TRUNCATION_SUFFIX + Log.w( + TAG, + "[AppMetrics] logEvent truncated body from ${body.length} characters to the $MAX_EVENT_BODY_LENGTH-character limit." + ) + return truncated +} diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/EventNameValidation.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/EventNameValidation.kt new file mode 100644 index 00000000000000..68674215985ddf --- /dev/null +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/EventNameValidation.kt @@ -0,0 +1,47 @@ +package expo.modules.appmetrics.logevents + +import android.util.Log +import expo.modules.appmetrics.TAG + +/** + * Prefix reserved for internal Expo event names. Callers cannot use it so SDK-emitted + * events stay distinguishable from app-emitted ones in the backend. + */ +private const val RESERVED_EVENT_NAME_PREFIX = "expo." + +/** + * Maximum length of a log event name in characters. Names beyond this length are + * dropped with a warning — most log backends balk on very long names and a runaway + * template literal can easily blow past a few hundred characters by accident. + */ +private const val MAX_EVENT_NAME_LENGTH = 256 + +/** + * Validates and normalizes a caller-provided log event name. + * + * Returns the trimmed name on success, or `null` when the name should be rejected. + * In the rejection case, a warning is logged explaining why so the developer can + * fix the call site without the app crashing over a telemetry concern. + */ +internal fun validateEventName(name: String): String? { + val trimmedName = name.trim() + if (trimmedName.isEmpty()) { + Log.w(TAG, "[AppMetrics] logEvent dropped: event name must not be empty.") + return null + } + if (trimmedName.startsWith(RESERVED_EVENT_NAME_PREFIX)) { + Log.w( + TAG, + "[AppMetrics] logEvent dropped: event name `$trimmedName` uses the reserved `expo.` prefix." + ) + return null + } + if (trimmedName.length > MAX_EVENT_NAME_LENGTH) { + Log.w( + TAG, + "[AppMetrics] logEvent dropped: event name is ${trimmedName.length} characters long, exceeding the $MAX_EVENT_NAME_LENGTH-character limit." + ) + return null + } + return trimmedName +} diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/LogEventOptions.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/LogEventOptions.kt new file mode 100644 index 00000000000000..6ea78dbb19c5b7 --- /dev/null +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/LogEventOptions.kt @@ -0,0 +1,15 @@ +package expo.modules.appmetrics.logevents + +import expo.modules.kotlin.records.Field +import expo.modules.kotlin.records.Record + +/** + * Options accepted by the `logEvent` module function. The event name is + * passed as a separate positional argument and is therefore not part of this + * record. + */ +data class LogEventOptions( + @Field val body: String? = null, + @Field val attributes: Map? = null, + @Field val severity: Severity? = null +) : Record diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/Severity.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/Severity.kt new file mode 100644 index 00000000000000..53a58ea31526d1 --- /dev/null +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/logevents/Severity.kt @@ -0,0 +1,40 @@ +package expo.modules.appmetrics.logevents + +import expo.modules.kotlin.types.Enumerable + +/** + * Severity of a log event. The `rawValue: String` constructor parameter is the + * single field Expo's `Enumerable` converter inspects when coercing an incoming + * JS string, so it must stay the only primary-constructor argument. The + * matching OpenTelemetry severity number + * (https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber) + * is exposed via the `severityNumber` extension property below. + */ +enum class Severity(val rawValue: String) : Enumerable { + TRACE("trace"), + DEBUG("debug"), + INFO("info"), + WARN("warn"), + ERROR("error"), + FATAL("fatal"); + + /** OpenTelemetry `severityNumber` value for this case. */ + val severityNumber: Int + get() = when (this) { + TRACE -> 1 + DEBUG -> 5 + INFO -> 9 + WARN -> 13 + ERROR -> 17 + FATAL -> 21 + } + + /** Severity text suitable for the OpenTelemetry `severityText` field. */ + val severityText: String + get() = rawValue.uppercase() + + companion object { + fun fromRawValue(value: String?): Severity? = + value?.let { raw -> entries.firstOrNull { it.rawValue == raw } } + } +} diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/MetricsDatabase.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/MetricsDatabase.kt index 4c781947e022f6..83e7a6b01ebe96 100644 --- a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/MetricsDatabase.kt +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/MetricsDatabase.kt @@ -25,13 +25,15 @@ object MetricsConstants { } @Database( - entities = [Metric::class, Session::class], - version = 14, + entities = [Metric::class, LogRecord::class, Session::class], + version = 15, exportSchema = false ) abstract class MetricsDatabase : RoomDatabase() { abstract fun metricDao(): MetricDao + abstract fun logDao(): LogDao + abstract fun sessionDao(): SessionDao companion object { @@ -122,9 +124,50 @@ data class SessionWithMetrics( parentColumn = "id", entityColumn = "sessionId" ) - @Field val metrics: List + @Field val metrics: List, + @Relation( + parentColumn = "id", + entityColumn = "sessionId" + ) + @Field val logs: List = emptyList() +) : Record + +@Entity( + tableName = "logs", + indices = [Index("sessionId")], + foreignKeys = [ + ForeignKey( + entity = Session::class, + parentColumns = ["id"], + childColumns = ["sessionId"], + onDelete = ForeignKey.CASCADE + ) + ] +) +@Serializable +data class LogRecord( + @PrimaryKey @Field val logId: String = UUID.randomUUID().toString(), + @Field val sessionId: String, + // ISO 8601 date string + @Field val timestamp: String, + @Field val name: String, + @Field val body: String? = null, + // Lowercase severity case name (`trace`, `debug`, `info`, `warn`, `error`, `fatal`). + @Field val severity: String, + // JSON string. Typed encoding happens at OTel time, not at storage time. + @Field val attributes: String? = null, + @Field val droppedAttributesCount: Int = 0 ) : Record +data class SessionWithLogs( + @Embedded val session: Session, + @Relation( + parentColumn = "id", + entityColumn = "sessionId" + ) + val logs: List +) + @Dao interface MetricDao { @Insert(onConflict = OnConflictStrategy.IGNORE) @@ -137,6 +180,18 @@ interface MetricDao { suspend fun delete(metrics: List) } +@Dao +interface LogDao { + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insertAll(logs: List) + + @Delete + suspend fun delete(logs: List) + + @Query("DELETE FROM logs WHERE timestamp < :cutoffTimestamp") + suspend fun deleteLogsOlderThan(cutoffTimestamp: String) +} + @Dao interface SessionDao { @Insert(onConflict = OnConflictStrategy.IGNORE) @@ -194,4 +249,8 @@ interface SessionDao { @Transaction @Query("SELECT DISTINCT s.* FROM sessions s INNER JOIN metrics m ON s.id = m.sessionId WHERE m.metricId IN (:metricIds)") suspend fun getSessionsWithMetricsByMetricIds(metricIds: List): List + + @Transaction + @Query("SELECT DISTINCT s.* FROM sessions s INNER JOIN logs l ON s.id = l.sessionId WHERE l.logId IN (:logIds)") + suspend fun getSessionsWithLogsByLogIds(logIds: List): List } diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/SessionManager.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/SessionManager.kt index 58be12b6ea0684..92f88dd20fa361 100644 --- a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/SessionManager.kt +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/SessionManager.kt @@ -25,7 +25,12 @@ class SessionManager( suspend fun onMetricsInserted(metricIds: List) } + fun interface LogsInsertListener { + suspend fun onLogsInserted(logIds: List) + } + private val metricsInsertListeners = CopyOnWriteArrayList() + private val logsInsertListeners = CopyOnWriteArrayList() fun addMetricsInsertListener(listener: MetricsInsertListener) { metricsInsertListeners.add(listener) @@ -35,6 +40,14 @@ class SessionManager( metricsInsertListeners.remove(listener) } + fun addLogsInsertListener(listener: LogsInsertListener) { + logsInsertListeners.add(listener) + } + + fun removeLogsInsertListener(listener: LogsInsertListener) { + logsInsertListeners.remove(listener) + } + fun createSessionId(): String = UUID.randomUUID().toString() suspend fun startSessionWithIdAt( @@ -139,6 +152,27 @@ class SessionManager( database.sessionDao().deleteSessionsOlderThan(cutoffTimestamp) } + suspend fun addLogs( + logs: List, + sessionId: String + ) { + val logsWithSession = logs.map { it.copy(sessionId = sessionId) } + database.logDao().insertAll(logsWithSession) + val logIds = logsWithSession.map { it.logId } + logsInsertListeners.forEach { listener -> + try { + listener.onLogsInserted(logIds) + } catch (e: Exception) { + Log.e(TAG, "LogsInsertListener failed", e) + } + } + } + + suspend fun cleanupOldLogs() { + val cutoffTimestamp = TimeUtils.getTimestampInISOFormatFromPast(MetricsConstants.SECONDS_TO_REMOVE_OLD_METRICS) + database.logDao().deleteLogsOlderThan(cutoffTimestamp) + } + suspend fun updateEnvironmentForActiveSessions(environment: String) { database.sessionDao().updateEnvironmentForActiveSessions(environment) } @@ -166,4 +200,28 @@ class SessionManager( ) } } + + suspend fun getSessionsWithLogs(logIds: List): List { + val logIdSet = logIds.toSet() + if (logIds.size <= SQLITE_MAX_BIND_VARIABLES) { + return database.sessionDao().getSessionsWithLogsByLogIds(logIds).map { sessionWithLogs -> + sessionWithLogs.copy(logs = sessionWithLogs.logs.filter { it.logId in logIdSet }) + } + } + + val allResults = logIds.chunked(SQLITE_MAX_BIND_VARIABLES).flatMap { chunk -> + database.sessionDao().getSessionsWithLogsByLogIds(chunk) + } + return allResults + .groupBy { it.session.id } + .map { (_, sessions) -> + SessionWithLogs( + session = sessions.first().session, + logs = sessions + .flatMap { it.logs } + .distinctBy { it.logId } + .filter { it.logId in logIdSet } + ) + } + } } diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/SessionMappers.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/SessionMappers.kt index 05400a59ac359d..43b8bac389e6cd 100644 --- a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/SessionMappers.kt +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/storage/SessionMappers.kt @@ -1,16 +1,11 @@ package expo.modules.appmetrics.storage +import expo.modules.appmetrics.utils.JsonAny import expo.modules.kotlin.records.Field import expo.modules.kotlin.records.Record import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.booleanOrNull -import kotlinx.serialization.json.doubleOrNull -import kotlinx.serialization.json.longOrNull /** * JS-facing shape of a session. Field names mirror the TypeScript `Session` @@ -28,9 +23,7 @@ data class JsSession( @Field val startDate: String, @Field val endDate: String?, @Field val metrics: List, - // Android doesn't collect log events yet; emitted as an empty list so - // consumers can rely on the same shape iOS produces. - @Field val logs: List = emptyList() + @Field val logs: List ) : Record { companion object { fun fromSessionWithMetrics(value: SessionWithMetrics): JsSession = @@ -39,7 +32,8 @@ data class JsSession( type = "main", startDate = value.session.startTimestamp, endDate = value.session.endTimestamp, - metrics = value.metrics.map { JsMetric.fromMetric(it) } + metrics = value.metrics.map { JsMetric.fromMetric(it) }, + logs = value.logs.map { JsLogRecord.fromLogRecord(it) } ) } } @@ -71,6 +65,34 @@ data class JsMetric( } } +/** + * JS-facing shape of a log event. Mirrors the TypeScript `LogRecord` type and + * decodes the storage-only JSON `attributes` column into a typed map. + * + * `logId`, `sessionId`, and `droppedAttributesCount` are storage- and + * dispatch-side concerns: JS consumers see the record under its parent + * `Session.logs` (so the parent ID is implicit), and the dropped-attribute + * bookkeeping is only meaningful on the OTel wire payload. + */ +data class JsLogRecord( + @Field val timestamp: String, + @Field val name: String, + @Field val body: String?, + @Field val severity: String, + @Field val attributes: Map? +) : Record { + companion object { + fun fromLogRecord(log: LogRecord): JsLogRecord = + JsLogRecord( + timestamp = log.timestamp, + name = log.name, + body = log.body, + severity = log.severity, + attributes = decodeJsonObject(log.attributes) + ) + } +} + /** * Decodes a JSON-encoded object string into a `Map` whose values * are plain Kotlin primitives (`String`, `Long`, `Double`, `Boolean`, `List`, @@ -86,22 +108,6 @@ private fun decodeJsonObject(jsonString: String?): Map? { if (element !is JsonObject) { return@runCatching null } - element.mapValues { (_, v) -> jsonElementToAny(v) } + element.mapValues { (_, v) -> JsonAny.fromElement(v) } }.getOrNull() } - -private fun jsonElementToAny(element: JsonElement): Any? { - return when (element) { - is JsonNull -> null - is JsonPrimitive -> when { - element.isString -> element.content - else -> - element.booleanOrNull - ?: element.longOrNull - ?: element.doubleOrNull - ?: element.content - } - is JsonObject -> element.mapValues { (_, v) -> jsonElementToAny(v) } - is JsonArray -> element.map { jsonElementToAny(it) } - } -} diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/utils/JsonAny.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/utils/JsonAny.kt new file mode 100644 index 00000000000000..3e265d086b1da1 --- /dev/null +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/utils/JsonAny.kt @@ -0,0 +1,59 @@ +package expo.modules.appmetrics.utils + +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.booleanOrNull +import kotlinx.serialization.json.doubleOrNull +import kotlinx.serialization.json.longOrNull + +/** + * Bidirectional converters between caller-supplied `Map` (typed + * Kotlin primitives) and `JsonElement` (storage form). The two operations + * are inverses; keeping them together prevents the encode/decode rules from + * drifting apart. + * + * Decode is best-effort — values whose type cannot be represented in the OTLP + * `AnyValue` shape (e.g. `Date`, NaN/Infinity doubles) are encoded as JSON + * `null`, and the dispatch-time encoder folds them into + * `droppedAttributesCount`. + */ +object JsonAny { + fun toElement(value: Any?): JsonElement { + return when (value) { + null -> JsonNull + is Boolean -> JsonPrimitive(value) + is Int -> JsonPrimitive(value) + is Long -> JsonPrimitive(value) + is Double -> if (value.isFinite()) JsonPrimitive(value) else JsonNull + is Float -> if (value.isFinite()) JsonPrimitive(value.toDouble()) else JsonNull + is Number -> JsonPrimitive(value.toDouble()) + is String -> JsonPrimitive(value) + is Map<*, *> -> JsonObject( + value.entries + .filter { it.key is String } + .associate { (k, v) -> (k as String) to toElement(v) } + ) + is List<*> -> JsonArray(value.map { toElement(it) }) + is Array<*> -> JsonArray(value.map { toElement(it) }) + else -> JsonNull + } + } + + fun fromElement(element: JsonElement): Any? { + return when (element) { + is JsonNull -> null + is JsonPrimitive -> when { + element.isString -> element.content + else -> element.booleanOrNull + ?: element.longOrNull + ?: element.doubleOrNull + ?: element.content + } + is JsonObject -> element.mapValues { (_, v) -> fromElement(v) } + is JsonArray -> element.map { fromElement(it) } + } + } +} diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/AttributeValidationTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/AttributeValidationTest.kt new file mode 100644 index 00000000000000..66296ca0815bf5 --- /dev/null +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/AttributeValidationTest.kt @@ -0,0 +1,151 @@ +package expo.modules.appmetrics.logevents + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE, sdk = [28]) +class AttributeValidationTest { + @Test + fun `returns null when input is null`() { + val result = sanitizeLogEventAttributes(null) + assertNull(result.attributes) + assertEquals(0, result.droppedCount) + } + + @Test + fun `passes through normal attributes unchanged`() { + val result = sanitizeLogEventAttributes(mapOf("userId" to "u_42", "attempt" to 2)) + assertEquals(0, result.droppedCount) + val attributes = result.attributes!! + assertEquals(2, attributes.size) + assertEquals("u_42", attributes["userId"]) + assertEquals(2, attributes["attempt"]) + } + + @Test + fun `trims whitespace from valid keys`() { + val result = sanitizeLogEventAttributes(mapOf(" userId " to "u_42")) + assertEquals(0, result.droppedCount) + val attributes = result.attributes!! + assertEquals("u_42", attributes["userId"]) + assertNull(attributes[" userId "]) + } + + @Test + fun `drops empty and whitespace-only keys`() { + val result = sanitizeLogEventAttributes( + mapOf("" to "x", " " to "y", "valid" to "z") + ) + assertEquals(2, result.droppedCount) + val attributes = result.attributes!! + assertEquals(1, attributes.size) + assertEquals("z", attributes["valid"]) + } + + @Test + fun `drops keys under the reserved expo namespace`() { + val result = sanitizeLogEventAttributes( + mapOf( + "expo.app.name" to "spoofed", + "expo.eas_client.id" to "spoofed", + "userId" to "u_42" + ) + ) + assertEquals(2, result.droppedCount) + val attributes = result.attributes!! + assertEquals(1, attributes.size) + assertEquals("u_42", attributes["userId"]) + } + + @Test + fun `drops SDK-set OTel keys (event_name and session_id)`() { + val result = sanitizeLogEventAttributes( + mapOf( + "event.name" to "spoofed", + "session.id" to "spoofed", + "ok" to true + ) + ) + assertEquals(2, result.droppedCount) + val attributes = result.attributes!! + assertEquals(1, attributes.size) + assertEquals(true, attributes["ok"]) + } + + @Test + fun `applies reserved-prefix check after trimming whitespace`() { + val result = sanitizeLogEventAttributes(mapOf(" expo.foo " to "x")) + assertEquals(1, result.droppedCount) + assertNull(result.attributes) + } + + @Test + fun `applies SDK-set check after trimming whitespace`() { + val result = sanitizeLogEventAttributes(mapOf(" event.name " to "x")) + assertEquals(1, result.droppedCount) + assertNull(result.attributes) + } + + @Test + fun `does not match keys that merely start with a reserved word but aren't the namespace`() { + val result = sanitizeLogEventAttributes( + mapOf( + "expoFoo" to "ok", + "expo" to "ok", + "session.idx" to "ok", + "event.name.extra" to "ok" + ) + ) + assertEquals(0, result.droppedCount) + val attributes = result.attributes!! + assertEquals(4, attributes.size) + } + + @Test + fun `caps attributes at 128 entries and reports the overflow`() { + val input = LinkedHashMap() + for (i in 0 until 200) { + // Pad keys so sort order is deterministic and predictable. + input[String.format("k%03d", i)] = i + } + val result = sanitizeLogEventAttributes(input) + assertEquals(72, result.droppedCount) + val attributes = result.attributes!! + assertEquals(128, attributes.size) + // Sorted-ascending kept set means the first 128 keys (k000…k127) survive. + assertEquals(0, attributes["k000"]) + assertEquals(127, attributes["k127"]) + assertNull(attributes["k128"]) + } + + @Test + fun `returns null attributes when every entry is dropped`() { + val result = sanitizeLogEventAttributes( + mapOf("expo.foo" to "x", "expo.bar" to "y") + ) + assertNull(result.attributes) + assertEquals(2, result.droppedCount) + } + + @Test + fun `combines multiple drop categories in the count`() { + val result = sanitizeLogEventAttributes( + mapOf( + "" to "empty-key-drop", + "expo.foo" to "namespace-drop", + "session.id" to "sdk-drop", + "valid" to "ok" + ) + ) + assertEquals(3, result.droppedCount) + val attributes = result.attributes!! + assertEquals(1, attributes.size) + assertEquals("ok", attributes["valid"]) + } +} diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/EventBodyValidationTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/EventBodyValidationTest.kt new file mode 100644 index 00000000000000..c4b0d2d8b255dc --- /dev/null +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/EventBodyValidationTest.kt @@ -0,0 +1,52 @@ +package expo.modules.appmetrics.logevents + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE, sdk = [28]) +class EventBodyValidationTest { + @Test + fun `returns null when input is null`() { + assertNull(validateEventBody(null)) + } + + @Test + fun `passes through a short body unchanged`() { + assertEquals("hello", validateEventBody("hello")) + } + + @Test + fun `passes through a body exactly at the cap`() { + val atLimit = "a".repeat(4096) + assertEquals(atLimit, validateEventBody(atLimit)) + } + + @Test + fun `truncates a body just past the cap`() { + val oversized = "a".repeat(4097) + val result = validateEventBody(oversized)!! + assertEquals(4096, result.length) + assertTrue(result.endsWith("…")) + } + + @Test + fun `truncates a long body and appends the ellipsis`() { + val oversized = "x".repeat(10_000) + val result = validateEventBody(oversized)!! + assertEquals(4096, result.length) + assertTrue(result.endsWith("…")) + // Prefix is preserved (start of the original body survives). + assertTrue(result.startsWith("xxxx")) + } + + @Test + fun `passes through an empty body`() { + assertEquals("", validateEventBody("")) + } +} diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/EventNameValidationTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/EventNameValidationTest.kt new file mode 100644 index 00000000000000..963634bf4fcd2f --- /dev/null +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/EventNameValidationTest.kt @@ -0,0 +1,56 @@ +package expo.modules.appmetrics.logevents + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE, sdk = [28]) +class EventNameValidationTest { + @Test + fun `accepts a regular name and returns it unchanged`() { + assertEquals("auth.login_failed", validateEventName("auth.login_failed")) + } + + @Test + fun `trims surrounding whitespace`() { + assertEquals("user.signed_in", validateEventName(" user.signed_in\n")) + } + + @Test + fun `rejects an empty name`() { + assertNull(validateEventName("")) + } + + @Test + fun `rejects a whitespace-only name`() { + assertNull(validateEventName(" \t\n")) + } + + @Test + fun `rejects names that use the reserved expo prefix`() { + assertNull(validateEventName("expo.app_startup.tti")) + assertNull(validateEventName("expo.something")) + } + + @Test + fun `accepts names containing 'expo' as long as it isn't the prefix`() { + assertEquals("my_expo.event", validateEventName("my_expo.event")) + assertEquals("app.expo.thing", validateEventName("app.expo.thing")) + } + + @Test + fun `rejects names longer than the cap`() { + val oversized = "a".repeat(257) + assertNull(validateEventName(oversized)) + } + + @Test + fun `accepts names exactly at the cap`() { + val atLimit = "a".repeat(256) + assertEquals(atLimit, validateEventName(atLimit)) + } +} diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionManagerTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionManagerTest.kt index 5a8a27e96df392..0553cd0ac117e5 100644 --- a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionManagerTest.kt +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionManagerTest.kt @@ -599,6 +599,32 @@ class SessionManagerTest { assertEquals(600, s2.metrics.size) } + @Test + fun `getSessionsWithMetrics yields empty logs from the chunked merger path`() = + runTest { + // Arrange — the chunked-merger branch in `getSessionsWithMetrics` + // constructs `SessionWithMetrics(...)` without passing logs and relies on + // the `= emptyList()` default. The session DOES have logs in storage, + // but the merger projects metrics-only. This test fails loudly if the + // default is removed or the merger ever needs to surface logs too. + val sessionId = "session-with-logs" + sessionManager.startSessionWithIdAt(sessionId, "2025-01-01T00:00:00.000Z") + + val metricIds = (1..1100).map { "metric-$it" } + metricIds.chunked(500).forEach { chunk -> + database.metricDao().insertAll(chunk.map { createMetric(it, sessionId) }) + } + // Also insert logs so an accidental relation-load would surface them. + database.logDao().insertAll(listOf(createLog("log-a", sessionId))) + + // Act — 1100 IDs forces the chunked path + val result = sessionManager.getSessionsWithMetrics(metricIds) + + // Assert + assertEquals(1, result.size) + assertEquals(emptyList(), result[0].logs) + } + // endregion // region Data Cleanup Tests @@ -694,6 +720,56 @@ class SessionManagerTest { assertTrue("fresh stopped session should be preserved", remaining.contains(freshStoppedId)) } + @Test + fun `getAllSessions populates the logs relation alongside metrics`() = + runTest { + // Arrange — exercises the Room `@Relation` for `LogRecord` end-to-end. + // Unit-level mapper tests construct `SessionWithMetrics` directly and + // never hit the DAO, so this is the only path that catches a schema or + // foreign-key misconfiguration. + val sessionId = "session-with-mixed-events" + sessionManager.startSessionWithIdAt(sessionId, "2025-01-01T00:00:00.000Z") + database.metricDao().insertAll( + listOf( + createMetric("metric-a", sessionId), + createMetric("metric-b", sessionId) + ) + ) + database.logDao().insertAll( + listOf( + createLog("log-a", sessionId, name = "auth.login_failed", severity = "warn"), + createLog("log-b", sessionId, name = "user.signed_in", severity = "info"), + createLog("log-c", sessionId, name = "cache.miss", severity = "debug") + ) + ) + + // Act + val sessions = sessionManager.getAllSessions() + + // Assert + val session = sessions.single { it.session.id == sessionId } + assertEquals(2, session.metrics.size) + assertEquals(3, session.logs.size) + assertEquals(setOf("log-a", "log-b", "log-c"), session.logs.map { it.logId }.toSet()) + } + + @Test + fun `getAllSessions yields an empty logs list when no logs exist for the session`() = + runTest { + // Arrange — a session with metrics but no logs. The relation should + // populate as an empty list, not null. + val sessionId = "session-no-logs" + sessionManager.startSessionWithIdAt(sessionId, "2025-01-01T00:00:00.000Z") + database.metricDao().insertAll(listOf(createMetric("metric-1", sessionId))) + + // Act + val sessions = sessionManager.getAllSessions() + + // Assert + val session = sessions.single { it.session.id == sessionId } + assertEquals(emptyList(), session.logs) + } + // endregion // region Helper Methods @@ -716,6 +792,24 @@ class SessionManagerTest { params = null ) + private fun createLog( + logId: String, + sessionId: String, + name: String = "test.event", + severity: String = "info", + attributes: String? = null + ): LogRecord = + LogRecord( + logId = logId, + sessionId = sessionId, + timestamp = "2025-01-01T00:00:00.000Z", + name = name, + body = null, + severity = severity, + attributes = attributes, + droppedAttributesCount = 0 + ) + private fun createTestMetadata( appName: String? = "TestApp", appIdentifier: String = "com.test.app", diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionMappersTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionMappersTest.kt index a01182b551482e..5b537798f0180c 100644 --- a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionMappersTest.kt +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionMappersTest.kt @@ -35,6 +35,21 @@ class SessionMappersTest { params = params ) + private fun makeLog( + logId: String = "log-1", + sessionId: String = "session-1", + name: String = "auth.login_failed", + attributes: String? = null + ): LogRecord = LogRecord( + logId = logId, + sessionId = sessionId, + timestamp = "2025-01-01T00:00:02.000Z", + name = name, + body = "invalid_credentials", + severity = "warn", + attributes = attributes + ) + @Test fun `JsSession_fromSessionWithMetrics exposes the JS-facing field names`() { val swm = SessionWithMetrics( @@ -100,4 +115,85 @@ class SessionMappersTest { assertEquals(1.5, js.value, 0.0) assertEquals("2025-01-01T00:00:01.000Z", js.timestamp) } + + @Test + fun `JsSession_fromSessionWithMetrics surfaces stored logs`() { + val swm = SessionWithMetrics( + session = makeSession(), + metrics = emptyList(), + logs = listOf( + makeLog(logId = "l-1", name = "first.event"), + makeLog(logId = "l-2", name = "second.event") + ) + ) + + val js = JsSession.fromSessionWithMetrics(swm) + + assertEquals(2, js.logs.size) + assertEquals("first.event", js.logs[0].name) + assertEquals("second.event", js.logs[1].name) + } + + @Test + fun `JsLogRecord_fromLogRecord decodes attributes from JSON`() { + val log = makeLog(attributes = """{"userId":"u_42","attempt":2,"retry":true}""") + + val js = JsLogRecord.fromLogRecord(log) + + val attributes = js.attributes + assertEquals("u_42", attributes?.get("userId")) + assertEquals(2L, attributes?.get("attempt")) + assertEquals(true, attributes?.get("retry")) + } + + @Test + fun `JsLogRecord_fromLogRecord yields null attributes when storage column is null`() { + val js = JsLogRecord.fromLogRecord(makeLog(attributes = null)) + + assertNull(js.attributes) + } + + @Test + fun `JsLogRecord_fromLogRecord yields null attributes when storage column is malformed JSON`() { + val js = JsLogRecord.fromLogRecord(makeLog(attributes = "{ this is not valid json")) + + assertNull(js.attributes) + } + + @Test + fun `JsLogRecord_fromLogRecord copies scalar fields verbatim`() { + val js = JsLogRecord.fromLogRecord(makeLog()) + + assertEquals("auth.login_failed", js.name) + assertEquals("invalid_credentials", js.body) + assertEquals("warn", js.severity) + assertEquals("2025-01-01T00:00:02.000Z", js.timestamp) + } + + @Test + fun `JsLogRecord and JsMetric decode nested JSON objects identically`() { + // The shared `decodeJsonObject` helper handles both `params` and + // `attributes`. This test pins down behavior for a non-trivial nested + // payload so the two callers can't quietly drift. + val payload = """{"user":{"id":"u_42","prefs":{"theme":"dark"}},"tags":["a","b"]}""" + + val metricResult = JsMetric.fromMetric(makeMetric(params = payload)).params + val logResult = JsLogRecord.fromLogRecord(makeLog(attributes = payload)).attributes + + // Both should decode the nested user object the same way. + @Suppress("UNCHECKED_CAST") + val metricUser = metricResult?.get("user") as? Map + @Suppress("UNCHECKED_CAST") + val logUser = logResult?.get("user") as? Map + assertEquals(metricUser, logUser) + assertEquals("u_42", metricUser?.get("id")) + + @Suppress("UNCHECKED_CAST") + val prefs = metricUser?.get("prefs") as? Map + assertEquals("dark", prefs?.get("theme")) + + // And arrays decode identically too. + assertEquals(listOf("a", "b"), metricResult?.get("tags")) + assertEquals(metricResult?.get("tags"), logResult?.get("tags")) + } } diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/Event.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/Event.kt index 3907ec2a071f66..b0e44465501f82 100644 --- a/packages/expo-observe/android/src/main/java/expo/modules/observe/Event.kt +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/Event.kt @@ -1,5 +1,6 @@ package expo.modules.observe +import expo.modules.appmetrics.storage.LogRecord import expo.modules.appmetrics.storage.Metric import expo.modules.appmetrics.storage.Session import kotlinx.serialization.Serializable @@ -104,8 +105,43 @@ data class EASMetric( } } +/** + * Wire shape of a log event ready for dispatch. Distinct from the storage-side + * `LogRecord`: this form has the JSON `attributes` blob already parsed back + * into a structured object (so the OTel encoder can map values to typed + * `OTAnyValue`s) and drops storage-only columns like `logId`. + */ +@Serializable +data class LogEvent( + val sessionId: String, + val timestamp: String, + val name: String, + val body: String? = null, + val severity: String, + val attributes: JsonObject? = null, + val droppedAttributesCount: Int = 0 +) { + companion object { + fun fromLogRecord(log: LogRecord): LogEvent = + LogEvent( + sessionId = log.sessionId, + timestamp = log.timestamp, + name = log.name, + body = log.body, + severity = log.severity, + // Stored as a JSON string; parse defensively, falling back to no + // attributes if the blob is somehow malformed. + attributes = log.attributes?.let { + runCatching { Json.decodeFromString(it) }.getOrNull() + }, + droppedAttributesCount = log.droppedAttributesCount + ) + } +} + @Serializable data class Event( val metadata: Metadata, - val metrics: List + val metrics: List, + val logs: List = emptyList() ) diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/EventDispatcher.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/EventDispatcher.kt index db4d9f3b6cd1ac..3d9751ce25629d 100644 --- a/packages/expo-observe/android/src/main/java/expo/modules/observe/EventDispatcher.kt +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/EventDispatcher.kt @@ -21,15 +21,18 @@ class EventDispatcher( private val useOpenTelemetry: Boolean = false, private val httpClient: OkHttpClient = OkHttpClient() ) { - private fun endpointUrl(): String { - val base = when (baseUrl.endsWith("/")) { + private val baseProjectUrl: String + get() = when (baseUrl.endsWith("/")) { true -> "${baseUrl}$projectId" else -> "$baseUrl/$projectId" } - return if (useOpenTelemetry) "$base/v1/metrics" else base - } - suspend fun dispatch(events: List) = + private fun metricsEndpointUrl(): String = + if (useOpenTelemetry) "$baseProjectUrl/v1/metrics" else baseProjectUrl + + private fun logsEndpointUrl(): String = "$baseProjectUrl/v1/logs" + + suspend fun dispatch(events: List): Boolean = suspendCancellableCoroutine { continuation -> if (events.isEmpty()) { continuation.resume(false) @@ -54,28 +57,7 @@ class EventDispatcher( json.encodeToString(Payload.serializer(), payload) } - val endpointUrl = endpointUrl() - - Log.d(TAG, "Sending events to $endpointUrl") - - val request = Request - .Builder() - .url(endpointUrl) - .post(body.toRequestBody("application/json".toMediaType())) - .build() - - Log.d(TAG, body) - - val call = httpClient.newCall(request) - - continuation.invokeOnCancellation { - call.cancel() - } - - val response = call.execute() - Log.d(TAG, "Server responded with: ${response.body?.string()}") - - continuation.resume(response.code in 200..299) + executePost(continuation, metricsEndpointUrl(), body) } catch (e: Exception) { Log.w( TAG, @@ -85,6 +67,59 @@ class EventDispatcher( } } + /** + * Dispatches log records to `{baseUrl}/{projectId}/v1/logs`. Always uses the + * OTLP wire shape — there is no legacy logs endpoint. + */ + suspend fun dispatchLogs(events: List): Boolean = + suspendCancellableCoroutine { continuation -> + val easId = EASClientID(context).uuid.toString() + val resourceLogs = events + .filter { it.logs.isNotEmpty() } + .map { it.toOTResourceLogs(easId) } + if (resourceLogs.isEmpty()) { + continuation.resume(false) + return@suspendCancellableCoroutine Unit + } + try { + val body = OTLogsRequestBody(resourceLogs = resourceLogs).toJson(prettyPrint = true) + executePost(continuation, logsEndpointUrl(), body) + } catch (e: Exception) { + Log.w( + TAG, + "Dispatching the logs has thrown an error: ${e.message}" + ) + continuation.resumeWithException(e) + } + } + + private fun executePost( + continuation: kotlinx.coroutines.CancellableContinuation, + endpointUrl: String, + body: String + ) { + Log.d(TAG, "Sending events to $endpointUrl") + + val request = Request + .Builder() + .url(endpointUrl) + .post(body.toRequestBody("application/json".toMediaType())) + .build() + + Log.d(TAG, body) + + val call = httpClient.newCall(request) + + continuation.invokeOnCancellation { + call.cancel() + } + + val response = call.execute() + Log.d(TAG, "Server responded with: ${response.body?.string()}") + + continuation.resume(response.code in 200..299) + } + companion object { private const val TAG = "EasObserve" } diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/OTAnyValueSerializer.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/OTAnyValueSerializer.kt new file mode 100644 index 00000000000000..ff199607d4d19d --- /dev/null +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/OTAnyValueSerializer.kt @@ -0,0 +1,111 @@ +package expo.modules.observe + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonEncoder +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.boolean +import kotlinx.serialization.json.booleanOrNull +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.doubleOrNull +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.longOrNull + +/** + * Custom serializer that emits the OTLP-correct wire shape for `OTAnyValue`. + * Each variant becomes a single-key JSON object: + * - Str -> {"stringValue": "..."} + * - Int64 -> {"intValue": "42"} (string per OTLP int64 mapping) + * - Dbl -> {"doubleValue": 3.14} + * - Bln -> {"boolValue": true} + * - Arr -> {"arrayValue": {"values": [...]}} + * - KvList -> {"kvlistValue": {"values": [{"key": "...", "value": ...}]}} + */ +internal object OTAnyValueSerializer : KSerializer { + override val descriptor: SerialDescriptor = + buildClassSerialDescriptor("expo.modules.observe.OTAnyValue") + + override fun serialize(encoder: Encoder, value: OTAnyValue) { + val jsonEncoder = encoder as? JsonEncoder + ?: error("OTAnyValue is only serializable to JSON (got ${encoder::class}).") + + val element: JsonElement = when (value) { + is OTAnyValue.Str -> buildJsonObject { put("stringValue", JsonPrimitive(value.value)) } + is OTAnyValue.Int64 -> buildJsonObject { put("intValue", JsonPrimitive(value.value.toString())) } + is OTAnyValue.Dbl -> buildJsonObject { put("doubleValue", JsonPrimitive(value.value)) } + is OTAnyValue.Bln -> buildJsonObject { put("boolValue", JsonPrimitive(value.value)) } + is OTAnyValue.Arr -> buildJsonObject { + put( + "arrayValue", + buildJsonObject { + put( + "values", + jsonEncoder.json.encodeToJsonElement( + ListSerializer(OTAnyValueSerializer), + value.values + ) + ) + } + ) + } + is OTAnyValue.KvList -> buildJsonObject { + put( + "kvlistValue", + buildJsonObject { + put( + "values", + jsonEncoder.json.encodeToJsonElement( + ListSerializer(OTKeyValue.serializer()), + value.values + ) + ) + } + ) + } + } + + jsonEncoder.encodeJsonElement(element) + } + + override fun deserialize(decoder: Decoder): OTAnyValue { + val jsonDecoder = decoder as? JsonDecoder + ?: error("OTAnyValue is only deserializable from JSON (got ${decoder::class}).") + val obj = jsonDecoder.decodeJsonElement().jsonObject + + obj["stringValue"]?.let { + return OTAnyValue.Str(it.jsonPrimitive.contentOrNull ?: "") + } + obj["intValue"]?.let { + val parsed = it.jsonPrimitive.contentOrNull?.toLongOrNull() + ?: it.jsonPrimitive.longOrNull + ?: error("OTAnyValue.intValue could not be parsed as Long: $it") + return OTAnyValue.Int64(parsed) + } + obj["doubleValue"]?.let { + return OTAnyValue.Dbl(it.jsonPrimitive.doubleOrNull ?: error("OTAnyValue.doubleValue not a number: $it")) + } + obj["boolValue"]?.let { + return OTAnyValue.Bln(it.jsonPrimitive.booleanOrNull ?: it.jsonPrimitive.boolean) + } + obj["arrayValue"]?.let { arr -> + val values = arr.jsonObject["values"]?.jsonArray + ?: error("OTAnyValue.arrayValue is missing `values`") + return OTAnyValue.Arr(values.map { jsonDecoder.json.decodeFromJsonElement(OTAnyValueSerializer, it) }) + } + obj["kvlistValue"]?.let { kv -> + val values = kv.jsonObject["values"]?.jsonArray + ?: error("OTAnyValue.kvlistValue is missing `values`") + return OTAnyValue.KvList(values.map { jsonDecoder.json.decodeFromJsonElement(OTKeyValue.serializer(), it) }) + } + error("OTAnyValue has no recognized variant: $obj") + } +} diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/ObservabilityBackgroundWorker.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/ObservabilityBackgroundWorker.kt index 1d5c773927646c..6986b09cc62b61 100644 --- a/packages/expo-observe/android/src/main/java/expo/modules/observe/ObservabilityBackgroundWorker.kt +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/ObservabilityBackgroundWorker.kt @@ -15,6 +15,7 @@ import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import androidx.work.WorkerParameters import androidx.work.workDataOf +import expo.modules.observe.storage.PendingLogsManager import expo.modules.observe.storage.PendingMetricsManager import expo.modules.appmetrics.storage.SessionManager @@ -43,12 +44,14 @@ class ObservabilityBackgroundWorker( ) val pendingMetricsManager = PendingMetricsManager(context) + val pendingLogsManager = PendingLogsManager(context) BaseObservabilityManager( context = context, projectId = projectId, sessionManager = sessionManager, pendingMetricsManager = pendingMetricsManager, + pendingLogsManager = pendingLogsManager, baseUrl = baseUrl, isDebugBuild = BuildConfig.DEBUG, useOpenTelemetry = useOpenTelemetry @@ -81,7 +84,8 @@ class ObservabilityBackgroundWorker( // This also adds a side benefit of cleaning up even if dispatch fails observabilityManager.cleanup() observabilityManager.dispatchUnsentMetrics() - Log.d(OBSERVE_TAG, "Successfully dispatched unsent metrics") + observabilityManager.dispatchUnsentLogs() + Log.d(OBSERVE_TAG, "Successfully dispatched unsent metrics and logs") Result.success() } catch (e: Exception) { Log.e(OBSERVE_TAG, "Failed to dispatch metrics", e) diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/ObservabilityManager.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/ObservabilityManager.kt index b9c051971cfb6a..37ccc6d6724520 100644 --- a/packages/expo-observe/android/src/main/java/expo/modules/observe/ObservabilityManager.kt +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/ObservabilityManager.kt @@ -2,6 +2,7 @@ package expo.modules.observe import android.content.Context import expo.modules.easclient.EASClientID +import expo.modules.observe.storage.PendingLogsManager import expo.modules.observe.storage.PendingMetricsManager import expo.modules.appmetrics.storage.SessionManager import expo.modules.interfaces.constants.ConstantsInterface @@ -30,11 +31,13 @@ class ObservabilityManager( useOpenTelemetry = manifest.useOpenTelemetry val pendingMetricsManager = PendingMetricsManager(context) + val pendingLogsManager = PendingLogsManager(context) baseManager = BaseObservabilityManager( context = context, sessionManager = sessionManager, pendingMetricsManager = pendingMetricsManager, + pendingLogsManager = pendingLogsManager, projectId = projectId, baseUrl = baseUrl, isDebugBuild = BuildConfig.DEBUG, @@ -44,12 +47,19 @@ class ObservabilityManager( sessionManager.addMetricsInsertListener { metricIds -> pendingMetricsManager.addPendingMetrics(metricIds) } + sessionManager.addLogsInsertListener { logIds -> + pendingLogsManager.addPendingLogs(logIds) + } } suspend fun dispatchUnsentMetrics() { baseManager.dispatchUnsentMetrics() } + suspend fun dispatchUnsentLogs() { + baseManager.dispatchUnsentLogs() + } + fun scheduleBackgroundDispatch() { ObservabilityBackgroundWorker.scheduleBackgroundDispatch( context = context, @@ -64,6 +74,7 @@ class BaseObservabilityManager( private val context: Context, private val sessionManager: SessionManager, private val pendingMetricsManager: PendingMetricsManager, + private val pendingLogsManager: PendingLogsManager, val projectId: String, val baseUrl: String, private val isDebugBuild: Boolean = false, @@ -116,6 +127,49 @@ class BaseObservabilityManager( } } + /** + * Dispatches log events to `/v1/logs`. Independent from the metrics path — + * a logs failure doesn't affect the metrics pending table and vice versa. + */ + suspend fun dispatchUnsentLogs() { + val pendingIds = pendingLogsManager.getAllPendingLogIds() + if (pendingIds.isEmpty()) { + return + } + + if (!shouldDispatch()) { + pendingLogsManager.removePendingLogs(pendingIds) + return + } + + val sessionsWithPendingLogs = sessionManager.getSessionsWithLogs(pendingIds) + + // Clean up orphaned pending IDs (logs deleted from the `logs` table but + // still tracked in `pending_logs`). + val resolvedLogIds = sessionsWithPendingLogs.flatMap { it.logs }.map { it.logId }.toSet() + val orphanedIds = pendingIds.filter { it !in resolvedLogIds } + if (orphanedIds.isNotEmpty()) { + pendingLogsManager.removePendingLogs(orphanedIds) + } + + if (sessionsWithPendingLogs.isEmpty()) { + return + } + + val events = sessionsWithPendingLogs.map { sessionWithLogs -> + Event( + metadata = Metadata.fromSessionMetadata(sessionWithLogs.session), + metrics = emptyList(), + logs = sessionWithLogs.logs.map { LogEvent.fromLogRecord(it) } + ) + } + + if (eventDispatcher.dispatchLogs(events)) { + val dispatchedLogIds = sessionsWithPendingLogs.flatMap { it.logs }.map { it.logId } + pendingLogsManager.removePendingLogs(dispatchedLogIds) + } + } + private fun isInSample(): Boolean { val rate = ObservePreferences.getConfig(context)?.sampleRate ?: return true val clamped = rate.coerceIn(0.0, 1.0) @@ -136,7 +190,9 @@ class BaseObservabilityManager( suspend fun cleanup() { pendingMetricsManager.cleanupOldPendingMetrics() + pendingLogsManager.cleanupOldPendingLogs() // TODO(@ubax): Move sessionManager.cleanupOldSessions out of eas observe sessionManager.cleanupOldSessions() + sessionManager.cleanupOldLogs() } } diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/ObserveModule.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/ObserveModule.kt index fcaab08a025580..bf08456b6caf7c 100644 --- a/packages/expo-observe/android/src/main/java/expo/modules/observe/ObserveModule.kt +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/ObserveModule.kt @@ -50,7 +50,10 @@ class ObserveModule : Module() { observabilityManager.scheduleBackgroundDispatch() } - AsyncFunction("dispatchEvents") Coroutine { -> observabilityManager.dispatchUnsentMetrics() } + AsyncFunction("dispatchEvents") Coroutine { -> + observabilityManager.dispatchUnsentMetrics() + observabilityManager.dispatchUnsentLogs() + } Function("configure") { config: Config -> ObservePreferences.setConfig( diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/OpenTelemetry.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/OpenTelemetry.kt index 7b8064563927c2..dd9d3e5408dbc8 100644 --- a/packages/expo-observe/android/src/main/java/expo/modules/observe/OpenTelemetry.kt +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/OpenTelemetry.kt @@ -2,26 +2,67 @@ package expo.modules.observe import expo.modules.appmetrics.AppStartupMetric import expo.modules.appmetrics.MetricCategory +import expo.modules.appmetrics.logevents.Severity import expo.modules.appmetrics.utils.TimeUtils.timestampToDateNS import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.booleanOrNull +import kotlinx.serialization.json.doubleOrNull +import kotlinx.serialization.json.longOrNull // MARK: -- Open Telemetry data classes +/** + * Wire shape for the OTel `body` field on `LogRecord` — always carries a string. + * Kept distinct from `OTAnyValue.Str` because the body field on the log record + * is positional in OTLP (no `stringValue` wrapper key on the value side). + */ @Serializable data class OTStringValue( val stringValue: String ) +/** + * Tagged union mirroring the OTLP `AnyValue` shape — encodes as a JSON object + * with exactly one of `stringValue` / `intValue` / `doubleValue` / `boolValue` / + * `arrayValue` / `kvlistValue`, depending on the variant. + * + * OTLP encodes 64-bit integers as JSON strings to avoid precision loss; we follow + * that convention so collectors that rely on the protobuf-JSON mapping accept the + * payload. + */ +@Serializable(with = OTAnyValueSerializer::class) +sealed class OTAnyValue { + data class Str(val value: String) : OTAnyValue() + data class Int64(val value: Long) : OTAnyValue() + data class Dbl(val value: Double) : OTAnyValue() + data class Bln(val value: Boolean) : OTAnyValue() + data class Arr(val values: List) : OTAnyValue() + data class KvList(val values: List) : OTAnyValue() +} + +/** + * Key/value pair used inside `kvlistValue` (and at the top level for span + * attributes). Same shape as `OTAttribute` but split out for the recursive case. + */ +@Serializable +data class OTKeyValue( + val key: String, + val value: OTAnyValue +) + @Serializable data class OTAttribute( val key: String, - val value: OTStringValue + val value: OTAnyValue ) { companion object { fun of(key: String, rawValue: String) = OTAttribute( key = key, - value = OTStringValue(stringValue = rawValue) + value = OTAnyValue.Str(rawValue) ) } } @@ -65,7 +106,32 @@ data class OTScopeMetrics( @Serializable data class OTEvent( val resource: OTMetadata, - val scopeMetrics: List + val scopeMetrics: List, + val schemaUrl: String +) + +@Serializable +data class OTLogRecord( + val timeUnixNano: Long, + val observedTimeUnixNano: Long, + val severityNumber: Int, + val severityText: String, + val body: OTStringValue, + val attributes: List, + val droppedAttributesCount: Int? = null +) + +@Serializable +data class OTScopeLogs( + val scope: OTScope, + val logRecords: List +) + +@Serializable +data class OTResourceLogs( + val resource: OTMetadata, + val scopeLogs: List, + val schemaUrl: String ) // MARK: -- Request body for Open Telemetry events @@ -82,6 +148,30 @@ data class OTRequestBody( } } +@Serializable +data class OTLogsRequestBody( + val resourceLogs: List +) { + fun toJson(prettyPrint: Boolean = false): String { + val json = Json { + this.prettyPrint = prettyPrint + } + return json.encodeToString(serializer(), this) + } +} + +/** + * OpenTelemetry Semantic Conventions schema URL referenced by the resource on + * every dispatched payload. Bumping this constant signals that our attribute + * names follow a newer revision of the conventions. + * + * Before bumping, audit the attribute keys we set in `toOTMetadata` and + * `toOTLogRecord` against the SemConv changelog at + * https://github.com/open-telemetry/semantic-conventions/blob/main/CHANGELOG.md + * — a renamed key would silently mismatch the declared schema otherwise. + */ +internal const val SEMCONV_SCHEMA_URL = "https://opentelemetry.io/schemas/1.27.0" + // This must be kept in sync with the INTERNAL_TO_OTEL map in universe // https://github.com/expo/universe/blob/main/server/www/src/middleware/easObserveRoutes.ts#L209 private val metricNameMap = mapOf( @@ -199,6 +289,113 @@ fun Event.toOTEvent(easClientId: String): OTEvent { scope = OTScope(name = "expo-observe", version = BuildConfig.EXPO_OBSERVE_VERSION), metrics = metrics.map { it.toOTMetric() } ) - ) + ), + schemaUrl = SEMCONV_SCHEMA_URL + ) +} + +/** + * Maps a caller-supplied JSON attribute object (values stored after the JSON + * roundtrip) to typed `OTAttribute`s. Returns the mapped attributes plus a + * count of entries that could not be represented (a value type we don't + * support, or a deeply unrepresentable nested structure) so callers can fold + * the count into the OTel `droppedAttributesCount`. + */ +internal fun otAttributesFromJsonObject( + obj: JsonObject +): Pair, Int> { + val attributes = mutableListOf() + var droppedCount = 0 + for ((key, element) in obj) { + val mapped = otAnyValueFromJsonElement(element) + if (mapped != null) { + attributes.add(OTAttribute(key = key, value = mapped)) + } else { + droppedCount += 1 + } + } + return attributes to droppedCount +} + +/** + * Converts a `JsonElement` (the storage form of a caller attribute value) into + * a typed `OTAnyValue`. Returns `null` for `JsonNull` and for any element we + * cannot represent, so the caller can fold it into `droppedAttributesCount`. + */ +fun LogEvent.toOTLogRecord(): OTLogRecord { + val attributes = mutableListOf( + OTAttribute.of(key = "session.id", rawValue = sessionId), + OTAttribute.of(key = "event.name", rawValue = name) + ) + + var encodeTimeDrops = 0 + this.attributes?.let { attrs -> + val (typed, dropped) = otAttributesFromJsonObject(attrs) + attributes.addAll(typed) + encodeTimeDrops = dropped + } + + val totalDrops = droppedAttributesCount + encodeTimeDrops + val timeNs = timestampToDateNS(timestamp) + // Both `severityNumber` and `severityText` come off the same enum case so + // they can't disagree. Unknown raw values (e.g. a future case shipped on JS + // ahead of the native side) fall back to INFO rather than producing an + // internally-inconsistent OTel record. + val resolvedSeverity = Severity.fromRawValue(severity) ?: Severity.INFO + return OTLogRecord( + timeUnixNano = timeNs, + observedTimeUnixNano = timeNs, + severityNumber = resolvedSeverity.severityNumber, + severityText = resolvedSeverity.severityText, + body = OTStringValue(stringValue = body ?: ""), + attributes = attributes, + droppedAttributesCount = if (totalDrops > 0) totalDrops else null ) } + +fun Event.toOTResourceLogs(easClientId: String): OTResourceLogs { + return OTResourceLogs( + resource = toOTMetadata(easClientId), + scopeLogs = listOf( + OTScopeLogs( + scope = OTScope(name = "expo-observe", version = BuildConfig.EXPO_OBSERVE_VERSION), + logRecords = logs.map { it.toOTLogRecord() } + ) + ), + schemaUrl = SEMCONV_SCHEMA_URL + ) +} + +internal fun otAnyValueFromJsonElement(element: JsonElement): OTAnyValue? { + if (element is kotlinx.serialization.json.JsonNull) { + return null + } + return when (element) { + is JsonPrimitive -> { + // Booleans first — JsonPrimitive.booleanOrNull only matches `true`/`false`, + // not numeric primitives, so order isn't strictly load-bearing, but matching + // the iOS ordering keeps the ports symmetric. + element.booleanOrNull?.let { return OTAnyValue.Bln(it) } + // `isString` distinguishes "42" (string) from 42 (number) since the JSON + // primitive representation is the same string-of-digits. + if (element.isString) { + return OTAnyValue.Str(element.content) + } + element.longOrNull?.let { return OTAnyValue.Int64(it) } + element.doubleOrNull?.let { return if (it.isFinite()) OTAnyValue.Dbl(it) else null } + null + } + is JsonObject -> { + val pairs = mutableListOf() + for ((k, v) in element) { + val mapped = otAnyValueFromJsonElement(v) ?: return null + pairs.add(OTKeyValue(key = k, value = mapped)) + } + OTAnyValue.KvList(pairs) + } + is kotlinx.serialization.json.JsonArray -> { + val mapped = element.map { otAnyValueFromJsonElement(it) ?: return null } + OTAnyValue.Arr(mapped) + } + } +} diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/storage/ObserveDatabase.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/storage/ObserveDatabase.kt index 2f10b55906300b..24245ed19b8487 100644 --- a/packages/expo-observe/android/src/main/java/expo/modules/observe/storage/ObserveDatabase.kt +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/storage/ObserveDatabase.kt @@ -18,6 +18,13 @@ data class PendingMetric( val addedAt: String ) +@Entity(tableName = "pending_logs") +data class PendingLog( + @PrimaryKey val logId: String, + // ISO 8601 timestamp + val addedAt: String +) + @Dao interface PendingMetricDao { @Insert(onConflict = OnConflictStrategy.IGNORE) @@ -33,10 +40,27 @@ interface PendingMetricDao { suspend fun deleteOlderThan(cutoffTimestamp: String) } -@Database(entities = [PendingMetric::class], version = 1, exportSchema = false) +@Dao +interface PendingLogDao { + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insertAll(logs: List) + + @Query("SELECT logId FROM pending_logs") + suspend fun getAllLogIds(): List + + @Query("DELETE FROM pending_logs WHERE logId IN (:logIds)") + suspend fun deleteByIds(logIds: List) + + @Query("DELETE FROM pending_logs WHERE addedAt < :cutoffTimestamp") + suspend fun deleteOlderThan(cutoffTimestamp: String) +} + +@Database(entities = [PendingMetric::class, PendingLog::class], version = 2, exportSchema = false) abstract class ObserveDatabase : RoomDatabase() { abstract fun pendingMetricDao(): PendingMetricDao + abstract fun pendingLogDao(): PendingLogDao + companion object { @Volatile private var INSTANCE: ObserveDatabase? = null diff --git a/packages/expo-observe/android/src/main/java/expo/modules/observe/storage/PendingLogsManager.kt b/packages/expo-observe/android/src/main/java/expo/modules/observe/storage/PendingLogsManager.kt new file mode 100644 index 00000000000000..5d2cc4b4316de5 --- /dev/null +++ b/packages/expo-observe/android/src/main/java/expo/modules/observe/storage/PendingLogsManager.kt @@ -0,0 +1,38 @@ +package expo.modules.observe.storage + +import android.content.Context +import androidx.room.withTransaction +import expo.modules.appmetrics.utils.TimeUtils +import expo.modules.observe.SQLITE_MAX_BIND_VARIABLES + +class PendingLogsManager( + context: Context, + database: ObserveDatabase? = null +) { + private val database: ObserveDatabase = database ?: ObserveDatabase.getDatabase(context) + + suspend fun addPendingLogs(logIds: List) { + val now = TimeUtils.getCurrentTimestampInISOFormat() + val pendingLogs = logIds.map { PendingLog(logId = it, addedAt = now) } + database.pendingLogDao().insertAll(pendingLogs) + } + + suspend fun getAllPendingLogIds(): List = database.pendingLogDao().getAllLogIds() + + suspend fun removePendingLogs(logIds: List) { + database.withTransaction { + logIds.chunked(SQLITE_MAX_BIND_VARIABLES).forEach { chunk -> + database.pendingLogDao().deleteByIds(chunk) + } + } + } + + suspend fun cleanupOldPendingLogs() { + val cutoffTimestamp = TimeUtils.getTimestampInISOFormatFromPast(SECONDS_TO_REMOVE_OLD_PENDING_LOGS) + database.pendingLogDao().deleteOlderThan(cutoffTimestamp) + } + + companion object { + private const val SECONDS_TO_REMOVE_OLD_PENDING_LOGS: Long = 7 * 24 * 60 * 60 // 7 days in seconds + } +} diff --git a/packages/expo-observe/android/src/test/java/expo/modules/observe/BaseObservabilityManagerTest.kt b/packages/expo-observe/android/src/test/java/expo/modules/observe/BaseObservabilityManagerTest.kt index cd8f2b03b2c3ae..dc8e23088b2494 100644 --- a/packages/expo-observe/android/src/test/java/expo/modules/observe/BaseObservabilityManagerTest.kt +++ b/packages/expo-observe/android/src/test/java/expo/modules/observe/BaseObservabilityManagerTest.kt @@ -25,6 +25,7 @@ class BaseObservabilityManagerTest { private lateinit var mockSessionManager: SessionManager private lateinit var mockEventDispatcher: EventDispatcher private lateinit var mockPendingMetricsManager: PendingMetricsManager + private lateinit var mockPendingLogsManager: expo.modules.observe.storage.PendingLogsManager private val testProjectId = "test-project-123" private val testBaseUrl = "https://test.example.com/" @@ -35,6 +36,7 @@ class BaseObservabilityManagerTest { mockSessionManager = mockk(relaxed = true) mockEventDispatcher = mockk(relaxed = true) mockPendingMetricsManager = mockk(relaxed = true) + mockPendingLogsManager = mockk(relaxed = true) // Default to enabled so existing tests aren't short-circuited mockkObject(ObservePreferences) @@ -753,7 +755,7 @@ class BaseObservabilityManagerTest { // region Cleanup tests @Test - fun `cleanup prunes pending metrics and stale sessions`() = + fun `cleanup prunes pending metrics, pending logs, stale sessions, and stale logs`() = runTest { // Arrange val manager = createManager() @@ -763,7 +765,9 @@ class BaseObservabilityManagerTest { // Assert coVerify(exactly = 1) { mockPendingMetricsManager.cleanupOldPendingMetrics() } + coVerify(exactly = 1) { mockPendingLogsManager.cleanupOldPendingLogs() } coVerify(exactly = 1) { mockSessionManager.cleanupOldSessions() } + coVerify(exactly = 1) { mockSessionManager.cleanupOldLogs() } } // endregion @@ -1009,6 +1013,7 @@ class BaseObservabilityManagerTest { context = mockContext, sessionManager = mockSessionManager, pendingMetricsManager = mockPendingMetricsManager, + pendingLogsManager = mockPendingLogsManager, projectId = testProjectId, baseUrl = testBaseUrl, isDebugBuild = isDebugBuild, diff --git a/packages/expo-observe/android/src/test/java/expo/modules/observe/OTAnyValueTest.kt b/packages/expo-observe/android/src/test/java/expo/modules/observe/OTAnyValueTest.kt new file mode 100644 index 00000000000000..9bbb839177ee63 --- /dev/null +++ b/packages/expo-observe/android/src/test/java/expo/modules/observe/OTAnyValueTest.kt @@ -0,0 +1,177 @@ +package expo.modules.observe + +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.boolean +import kotlinx.serialization.json.buildJsonArray +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.double +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE, sdk = [28]) +class OTAnyValueCodableTest { + private val json = Json + + private fun encode(value: OTAnyValue): JsonObject { + return json.encodeToJsonElement(OTAnyValueSerializer, value).jsonObject + } + + @Test + fun `encodes Str under stringValue`() { + val obj = encode(OTAnyValue.Str("hello")) + assertEquals(1, obj.size) + assertEquals("hello", obj["stringValue"]!!.jsonPrimitive.content) + } + + @Test + fun `encodes Int64 under intValue as a string`() { + val obj = encode(OTAnyValue.Int64(42)) + assertEquals(1, obj.size) + // OTLP encodes int64 as a JSON string to avoid JS-number precision loss. + assertEquals("42", obj["intValue"]!!.jsonPrimitive.content) + assertTrue(obj["intValue"]!!.jsonPrimitive.isString) + } + + @Test + fun `encodes Dbl under doubleValue as a JSON number`() { + val obj = encode(OTAnyValue.Dbl(3.14)) + assertEquals(1, obj.size) + assertEquals(3.14, obj["doubleValue"]!!.jsonPrimitive.double, 0.0) + } + + @Test + fun `encodes Bln under boolValue`() { + val obj = encode(OTAnyValue.Bln(true)) + assertEquals(1, obj.size) + assertEquals(true, obj["boolValue"]!!.jsonPrimitive.boolean) + } + + @Test + fun `encodes Arr as arrayValue with values list`() { + val obj = encode(OTAnyValue.Arr(listOf(OTAnyValue.Int64(1), OTAnyValue.Str("x")))) + assertEquals(1, obj.size) + val values = obj["arrayValue"]!!.jsonObject["values"]!!.jsonArray + assertEquals(2, values.size) + assertEquals("1", values[0].jsonObject["intValue"]!!.jsonPrimitive.content) + assertEquals("x", values[1].jsonObject["stringValue"]!!.jsonPrimitive.content) + } + + @Test + fun `encodes KvList as kvlistValue with key value pairs`() { + val obj = encode( + OTAnyValue.KvList( + listOf( + OTKeyValue(key = "a", value = OTAnyValue.Int64(1)), + OTKeyValue(key = "b", value = OTAnyValue.Str("x")) + ) + ) + ) + assertEquals(1, obj.size) + val values = obj["kvlistValue"]!!.jsonObject["values"]!!.jsonArray + assertEquals(2, values.size) + assertEquals("a", values[0].jsonObject["key"]!!.jsonPrimitive.content) + assertEquals("1", values[0].jsonObject["value"]!!.jsonObject["intValue"]!!.jsonPrimitive.content) + } + + @Test + fun `roundtrips through serialization`() { + val original: OTAnyValue = OTAnyValue.KvList( + listOf( + OTKeyValue(key = "name", value = OTAnyValue.Str("hello")), + OTKeyValue(key = "count", value = OTAnyValue.Int64(3)), + OTKeyValue(key = "ratio", value = OTAnyValue.Dbl(0.5)), + OTKeyValue(key = "ok", value = OTAnyValue.Bln(true)), + OTKeyValue( + key = "tags", + value = OTAnyValue.Arr(listOf(OTAnyValue.Str("a"), OTAnyValue.Str("b"))) + ) + ) + ) + val encoded = json.encodeToString(OTAnyValueSerializer, original) + val decoded = json.decodeFromString(OTAnyValueSerializer, encoded) + require(decoded is OTAnyValue.KvList) + assertEquals(5, decoded.values.size) + } +} + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE, sdk = [28]) +class OTAnyValueConversionTest { + private fun jsonObj(block: kotlinx.serialization.json.JsonObjectBuilder.() -> Unit) = + buildJsonObject(block) + + @Test + fun `maps a JSON boolean to Bln`() { + val value = otAnyValueFromJsonElement(JsonPrimitive(true)) + assertTrue(value is OTAnyValue.Bln) + assertEquals(true, (value as OTAnyValue.Bln).value) + } + + @Test + fun `maps a JSON integer to Int64`() { + val value = otAnyValueFromJsonElement(JsonPrimitive(42)) + assertTrue(value is OTAnyValue.Int64) + assertEquals(42L, (value as OTAnyValue.Int64).value) + } + + @Test + fun `maps a JSON double to Dbl`() { + val value = otAnyValueFromJsonElement(JsonPrimitive(3.14)) + assertTrue(value is OTAnyValue.Dbl) + assertEquals(3.14, (value as OTAnyValue.Dbl).value, 0.0) + } + + @Test + fun `maps a JSON string to Str`() { + val value = otAnyValueFromJsonElement(JsonPrimitive("hello")) + assertTrue(value is OTAnyValue.Str) + assertEquals("hello", (value as OTAnyValue.Str).value) + } + + @Test + fun `drops a JSON non-finite double`() { + // JSON cannot encode NaN/Infinity directly; validate the code path that + // checks `isFinite` against a manually-constructed primitive. + assertNull(otAnyValueFromJsonElement(JsonPrimitive(Double.NaN))) + assertNull(otAnyValueFromJsonElement(JsonPrimitive(Double.POSITIVE_INFINITY))) + assertNull(otAnyValueFromJsonElement(JsonPrimitive(Double.NEGATIVE_INFINITY))) + } + + @Test + fun `maps a JSON array to Arr`() { + val element = buildJsonArray { + add(JsonPrimitive(1)) + add(JsonPrimitive("x")) + } + val value = otAnyValueFromJsonElement(element) + assertTrue(value is OTAnyValue.Arr) + assertEquals(2, (value as OTAnyValue.Arr).values.size) + } + + @Test + fun `maps a JSON object to KvList`() { + val element = jsonObj { + put("a", JsonPrimitive(1)) + put("b", JsonPrimitive("x")) + } + val value = otAnyValueFromJsonElement(element) + assertTrue(value is OTAnyValue.KvList) + assertEquals(2, (value as OTAnyValue.KvList).values.size) + } + + @Test + fun `drops a JSON null value`() { + assertNull(otAnyValueFromJsonElement(kotlinx.serialization.json.JsonNull)) + } +} diff --git a/packages/expo-observe/android/src/test/java/expo/modules/observe/OpenTelemetryTest.kt b/packages/expo-observe/android/src/test/java/expo/modules/observe/OpenTelemetryTest.kt index 2cb640a210f975..b2049d79bff944 100644 --- a/packages/expo-observe/android/src/test/java/expo/modules/observe/OpenTelemetryTest.kt +++ b/packages/expo-observe/android/src/test/java/expo/modules/observe/OpenTelemetryTest.kt @@ -476,3 +476,48 @@ class OpenTelemetryTest { assertEquals(testSessionId, sessionAttr["value"]!!.jsonObject["stringValue"]!!.jsonPrimitive.content) } } + +/** + * Test-only convenience for pulling the inner string out of an [OTAnyValue]. + * Returns `null` for non-string variants — the metric tests in this file only + * produce string-valued attributes, so a null result is a real assertion + * failure. + */ +internal val OTAnyValue.stringValue: String? + get() = (this as? OTAnyValue.Str)?.value + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE, sdk = [28]) +class LogEventToOTLogRecordTest { + private fun makeLog(severity: String): LogEvent = + LogEvent( + sessionId = "session-1", + timestamp = "2025-01-01T00:00:00.000Z", + name = "auth.login_failed", + body = "invalid_credentials", + severity = severity, + attributes = null, + droppedAttributesCount = 0 + ) + + @Test + fun `renders severityText and severityNumber consistently for known cases`() { + val warn = makeLog(severity = "warn").toOTLogRecord() + assertEquals("WARN", warn.severityText) + assertEquals(13, warn.severityNumber) + + val error = makeLog(severity = "error").toOTLogRecord() + assertEquals("ERROR", error.severityText) + assertEquals(17, error.severityNumber) + } + + @Test + fun `falls back to INFO consistently for an unknown severity string`() { + // The previous code uppercased the raw value verbatim while the number + // path fell back to 9, producing internally-inconsistent records like + // (severityText="FROBNICATE", severityNumber=9). This pins the fix. + val ot = makeLog(severity = "frobnicate").toOTLogRecord() + assertEquals("INFO", ot.severityText) + assertEquals(9, ot.severityNumber) + } +} From 09bf3b9f2af3a8eefb8cd5e2dc83565e51c23e70 Mon Sep 17 00:00:00 2001 From: Jakub Tkacz <32908614+Ubax@users.noreply.github.com> Date: Mon, 11 May 2026 18:42:12 +0200 Subject: [PATCH 02/15] [expo-codemod] Warn when no paths are specified (#45411) # Why When no paths params were passed to codemod, it showed help without direct cta # How 1. When no path is passed, display no path warning Screenshot 2026-05-06 at 10 50 08 2. When wrong transform is passed and no path is specified, display the wrong transform warning Screenshot 2026-05-06 at 10 50 28 # Test Plan 1. CI 2. Manual testing # Checklist - [ ] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/expo-codemod/CHANGELOG.md | 2 ++ packages/expo-codemod/build/run/index.js | 7 ++++++- packages/expo-codemod/build/run/index.js.map | 2 +- .../src/run/__tests__/index-test.ts | 20 ++++++++++++++++--- packages/expo-codemod/src/run/index.ts | 10 +++++++++- 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/packages/expo-codemod/CHANGELOG.md b/packages/expo-codemod/CHANGELOG.md index 132066031b1cb4..82190918425e45 100644 --- a/packages/expo-codemod/CHANGELOG.md +++ b/packages/expo-codemod/CHANGELOG.md @@ -6,6 +6,8 @@ ### 🎉 New features +- Warn when no paths are specified ([#45411](https://github.com/expo/expo/pull/45411) by [@Ubax](https://github.com/Ubax)) + ### 🐛 Bug fixes ### 💡 Others diff --git a/packages/expo-codemod/build/run/index.js b/packages/expo-codemod/build/run/index.js index 5dfad6a12cacb6..b7c096896c6330 100644 --- a/packages/expo-codemod/build/run/index.js +++ b/packages/expo-codemod/build/run/index.js @@ -63,7 +63,7 @@ async function parseAndValidateArgs(argv) { }); const transforms = await (0, transforms_1.listTransformsAsync)(); const [transform, ...paths] = positionals; - if (values.help || !transform || paths.length === 0) { + if (values.help || !transform) { (0, args_1.printHelp)('Run a codemod transform against the given paths.', 'npx expo-codemod ', [ ' (required) name of transform to apply to files', ' (see a list of transforms available below)', @@ -75,6 +75,11 @@ async function parseAndValidateArgs(argv) { if (!transforms.includes(transform)) { Log.exit(`Transform "${transform}" does not exist. Valid options: ${transforms.join(', ')}`); } + if (paths.length === 0) { + Log.exit(`No paths provided to expo-codemod. Pass one or more file paths or globs to apply the "${transform}" transform to.\n` + + `Example: npx expo-codemod ${transform} 'src/**/*.{ts,tsx,js,jsx}'\n` + + `Run "npx expo-codemod --help" to see all options.`); + } return { transform, paths }; } /** diff --git a/packages/expo-codemod/build/run/index.js.map b/packages/expo-codemod/build/run/index.js.map index ebd5e495df3936..9913bd0e27c332 100644 --- a/packages/expo-codemod/build/run/index.js.map +++ b/packages/expo-codemod/build/run/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/run/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/run/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,oDAyCC;AAMD,gDAqDC;AA7HD,kDAA0B;AAC1B,gDAAwB;AACxB,2CAAkC;AAGlC,4CAA8B;AAC9B,8CAAoD;AACpD,wCAA2D;AAC3D,4CAAoD;AAEpD,MAAM,eAAe,GAAG,CAAC,UAAoB,EAAU,EAAE,CACvD,CAAC,EAAE,EAAE,KAAK,eAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAC5F,IAAI,CACL,CAAC;AAOJ;;;;GAIG;AACI,KAAK,UAAU,oBAAoB,CAAC,IAA0B;IACnE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,sBAAe,EAAC;QAC9C,IAAI,EAAE,IAAI;QACV,OAAO,EAAE;YACP,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;SACtC;QACD,gBAAgB,EAAE,IAAI;QACtB,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,MAAM,IAAA,gCAAmB,GAAE,CAAC;IAC/C,MAAM,CAAC,SAAS,EAAE,GAAG,KAAK,CAAC,GAAG,WAAW,CAAC;IAE1C,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAC9B,IAAA,gBAAS,EACP,kDAAkD,EAClD,yCAAyC,EACzC;YACE,8EAA8E;YAC9E,0EAA0E;YAC1E,8EAA8E;YAC9E,uDAAuD;YACvD,qDAAqD;SACtD,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,eAAe,CAAC,UAAU,CAAC,CAC5B,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,GAAG,CAAC,IAAI,CAAC,cAAc,SAAS,oCAAoC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,GAAG,CAAC,IAAI,CACN,yFAAyF,SAAS,mBAAmB;YACnH,6BAA6B,SAAS,+BAA+B;YACrE,mDAAmD,CACtD,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,kBAAkB,CAAC,OAAsB;IAC7D,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,IAAA,iBAAI,EAAC,KAAK,EAAE;QACjC,MAAM,EAAE,CAAC,oBAAoB,CAAC;KAC/B,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,GAAG,KAAK,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aACnC,IAAI,GAAG,KAAK,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aACtC,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,QAAQ,GAAG;QACf,EAAE,EAAE,OAAO;QACX,GAAG,EAAE,QAAQ;QACb,GAAG,EAAE,QAAQ;KACL,CAAC;IAEX,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;SACrB,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;SACpC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE;QAC7B,GAAG,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACzE,OAAO,MAAM,IAAA,0BAAiB,EAAC;YAC7B,KAAK;YACL,MAAM,EAAE,MAA+B;YACvC,SAAS;SACV,CAAC,CAAC;IACL,CAAC,CAAC,CACL,CAAC;IAEF,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAChC,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;QACpD,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,KAAK;QACxB,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE;QACf,QAAQ,EAAE,GAAG,CAAC,QAAQ,GAAG,QAAQ;QACjC,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,IAAI;QACrB,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;KAC5D,CAAC,EACF,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAC1D,CAAC;IAEF,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACZ,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpB,GAAG,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,aAAa,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;IACtD,mEAAmE;IACnE,GAAG,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,KAAK,aAAa,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC;IACzD,GAAG,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,KAAK,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACjD,GAAG,CAAC,GAAG,CAAC,mBAAmB,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACtE,CAAC;AAEM,MAAM,UAAU,GAAY,KAAK,EAAE,IAAI,EAAE,EAAE;IAChD,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC,CAAC;AAHW,QAAA,UAAU,cAGrB"} \ No newline at end of file diff --git a/packages/expo-codemod/src/run/__tests__/index-test.ts b/packages/expo-codemod/src/run/__tests__/index-test.ts index ef22b72e74ca6b..8e1bce12d5473d 100644 --- a/packages/expo-codemod/src/run/__tests__/index-test.ts +++ b/packages/expo-codemod/src/run/__tests__/index-test.ts @@ -64,9 +64,14 @@ describe('parseAndValidateArgs', () => { expect(exitMock).toHaveBeenCalledWith(expect.any(String), 0); }); - test('prints help and exits when transform has no paths', async () => { - await expect(parseAndValidateArgs([TRANSFORM])).rejects.toThrow(); - expect(exitMock).toHaveBeenCalledWith(expect.any(String), 0); + test('exits with code 1 and warns about missing paths when transform has no paths', async () => { + await expect(parseAndValidateArgs([TRANSFORM])).rejects.toThrow(/path/i); + expect(exitMock).toHaveBeenCalledTimes(1); + const [message, code] = exitMock.mock.calls[0]; + expect(message).toEqual(expect.stringContaining(TRANSFORM)); + expect(message).toEqual(expect.stringContaining('src/**/*.{ts,tsx,js,jsx}')); + expect(message).toEqual(expect.stringContaining('--help')); + expect(code).toBeUndefined(); }); test('exits with code 1 when an unknown flag is passed', async () => { @@ -85,6 +90,15 @@ describe('parseAndValidateArgs', () => { expect.stringContaining('Transform "does-not-exist" does not exist. Valid options:') ); }); + + test('validates transform before checking for paths', async () => { + await expect(parseAndValidateArgs(['does-not-exist'])).rejects.toThrow( + /Transform "does-not-exist" does not exist/ + ); + expect(exitMock).toHaveBeenCalledWith( + expect.stringContaining('Transform "does-not-exist" does not exist. Valid options:') + ); + }); }); describe('resolveAndDispatch', () => { diff --git a/packages/expo-codemod/src/run/index.ts b/packages/expo-codemod/src/run/index.ts index 37bac8f79e35d2..875f230a45f4c9 100644 --- a/packages/expo-codemod/src/run/index.ts +++ b/packages/expo-codemod/src/run/index.ts @@ -36,7 +36,7 @@ export async function parseAndValidateArgs(argv: string[] | undefined): Promise< const transforms = await listTransformsAsync(); const [transform, ...paths] = positionals; - if (values.help || !transform || paths.length === 0) { + if (values.help || !transform) { printHelp( 'Run a codemod transform against the given paths.', 'npx expo-codemod ', @@ -55,6 +55,14 @@ export async function parseAndValidateArgs(argv: string[] | undefined): Promise< Log.exit(`Transform "${transform}" does not exist. Valid options: ${transforms.join(', ')}`); } + if (paths.length === 0) { + Log.exit( + `No paths provided to expo-codemod. Pass one or more file paths or globs to apply the "${transform}" transform to.\n` + + `Example: npx expo-codemod ${transform} 'src/**/*.{ts,tsx,js,jsx}'\n` + + `Run "npx expo-codemod --help" to see all options.` + ); + } + return { transform, paths }; } From e5c8c590c0f433e0a7c63e47efd57ce47897086d Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 11 May 2026 18:09:55 +0100 Subject: [PATCH 03/15] perf(cli,metro-config): Swap and pack internal SourceMap representation (#45594) # Why Currently, all internal source-map representations take up a huge chunk of memory that's redundant, since they're essentially a `number[][]` tuple-array structure. This makes up the largest possible win in the Expo dev-server's memory usage, if reduced. > [!NOTE] > Marking as 'ready for review', but I might still rewrite and reformat this PR later, so while the implementation and functionality is nailed down, code may still change and be refactored. # How This PR swaps the internal use of source-maps to use [jridgewell's sourcemaps](https://github.com/jridgewell/sourcemaps) instead. As source-maps are used, the internal `Int32Array` representation is used, and when we serialize or store source-maps, they're stored as packed `number[]` arrays. When Metro (legacy code paths) utilise the `map` property, they're repacked into the "usual" in-memory representation instead. **Side-note:** All the added `@jridgewell/*` packages are already in our module graph in an Expo app because of Babel. The codepaths modified in this PR avoid any repacking and only mostly rely on the packed transfers. This is cache incompatible but has little negative effects. Performance is mostly neutral (apart from a net-positive reduction of `.map` requests), but retained memory shrinks by about 20-30% (depends on amount of modules in graph), since every module holds on to a more compact source-map representation than before. # Test Plan - Unit tests amended, manually checked `expo start` and `expo export` - Some tests are still outstanding, - **NOTE:** That's why the branch is marked as an experiment
Heap Summary Before (532MB) Heap Summary After (348MB)
Summary Before Summary After
Heap Details Before (175MB module mem) Heap Details After (48MB module mem)
Heap Details Before Heap Details After
Impact is **-35%** on a typical `expo start` (`apps/router-e2e`) after bundling a web+server build. # Checklist - [ ] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/@expo/cli/CHANGELOG.md | 2 + .../cli/src/export/embed/exportEmbedAsync.ts | 8 + .../server/metro/MetroBundlerDevServer.ts | 22 +- .../start/server/metro/instantiateMetro.ts | 8 + packages/@expo/metro-config/CHANGELOG.md | 2 + .../build/serializer/exportHermes.js | 4 +- .../build/serializer/exportHermes.js.map | 2 +- .../build/serializer/jsOutput.d.ts | 5 +- .../build/serializer/jsOutput.js.map | 2 +- .../build/serializer/packedMap.d.ts | 48 ++ .../build/serializer/packedMap.js | 416 +++++++++++ .../build/serializer/packedMap.js.map | 1 + .../reconcileTransformSerializerPlugin.js | 48 +- .../reconcileTransformSerializerPlugin.js.map | 2 +- .../build/serializer/serializeChunks.js | 42 +- .../build/serializer/serializeChunks.js.map | 2 +- .../build/serializer/sourceMap.d.ts | 43 ++ .../build/serializer/sourceMap.js | 304 ++++++++ .../build/serializer/sourceMap.js.map | 1 + .../build/serializer/withExpoSerializers.js | 14 +- .../serializer/withExpoSerializers.js.map | 2 +- .../build/transform-worker/count-lines.d.ts | 14 - .../build/transform-worker/count-lines.js | 43 -- .../build/transform-worker/count-lines.js.map | 1 - .../metro-transform-worker.d.ts | 7 +- .../metro-transform-worker.js | 59 +- .../metro-transform-worker.js.map | 2 +- .../transform-worker/transform-worker.d.ts | 5 +- .../transform-worker/transform-worker.js.map | 2 +- packages/@expo/metro-config/package.json | 5 +- .../serializer/__tests__/packedMap.test.ts | 692 ++++++++++++++++++ .../serializer/__tests__/sourceMap.test.ts | 689 +++++++++++++++++ .../src/serializer/exportHermes.ts | 3 +- .../fork/__tests__/mini-metro.test.ts | 173 ++--- .../serializer/fork/__tests__/mini-metro.ts | 43 +- .../metro-config/src/serializer/jsOutput.ts | 15 +- .../metro-config/src/serializer/packedMap.ts | 455 ++++++++++++ .../reconcileTransformSerializerPlugin.ts | 57 +- .../src/serializer/serializeChunks.ts | 50 +- .../metro-config/src/serializer/sourceMap.ts | 471 ++++++++++++ .../src/serializer/withExpoSerializers.ts | 15 +- .../__tests__/metro-transform-worker.test.ts | 15 +- .../src/transform-worker/count-lines.ts | 51 -- .../metro-transform-worker.ts | 81 +- .../src/transform-worker/transform-worker.ts | 12 +- pnpm-lock.yaml | 11 +- 46 files changed, 3483 insertions(+), 466 deletions(-) create mode 100644 packages/@expo/metro-config/build/serializer/packedMap.d.ts create mode 100644 packages/@expo/metro-config/build/serializer/packedMap.js create mode 100644 packages/@expo/metro-config/build/serializer/packedMap.js.map create mode 100644 packages/@expo/metro-config/build/serializer/sourceMap.d.ts create mode 100644 packages/@expo/metro-config/build/serializer/sourceMap.js create mode 100644 packages/@expo/metro-config/build/serializer/sourceMap.js.map delete mode 100644 packages/@expo/metro-config/build/transform-worker/count-lines.d.ts delete mode 100644 packages/@expo/metro-config/build/transform-worker/count-lines.js delete mode 100644 packages/@expo/metro-config/build/transform-worker/count-lines.js.map create mode 100644 packages/@expo/metro-config/src/serializer/__tests__/packedMap.test.ts create mode 100644 packages/@expo/metro-config/src/serializer/__tests__/sourceMap.test.ts create mode 100644 packages/@expo/metro-config/src/serializer/packedMap.ts create mode 100644 packages/@expo/metro-config/src/serializer/sourceMap.ts delete mode 100644 packages/@expo/metro-config/src/transform-worker/count-lines.ts diff --git a/packages/@expo/cli/CHANGELOG.md b/packages/@expo/cli/CHANGELOG.md index ec49f5214b5461..7dff547eccdd92 100644 --- a/packages/@expo/cli/CHANGELOG.md +++ b/packages/@expo/cli/CHANGELOG.md @@ -10,6 +10,8 @@ ### 💡 Others +- Deserialize new `@expo/metro-config` packed source-map format and update to use new source-map representation internally ([#45594](https://github.com/expo/expo/pull/45594) by [@kitten](https://github.com/kitten)) + ## 56.1.0 — 2026-05-08 ### 🎉 New features diff --git a/packages/@expo/cli/src/export/embed/exportEmbedAsync.ts b/packages/@expo/cli/src/export/embed/exportEmbedAsync.ts index eee780f53612bc..1766e27970b06f 100644 --- a/packages/@expo/cli/src/export/embed/exportEmbedAsync.ts +++ b/packages/@expo/cli/src/export/embed/exportEmbedAsync.ts @@ -10,6 +10,8 @@ import Server from '@expo/metro/metro/Server'; import splitBundleOptions from '@expo/metro/metro/lib/splitBundleOptions'; import * as output from '@expo/metro/metro/shared/output/bundle'; import type { BundleOptions } from '@expo/metro/metro/shared/types'; +import { patchTransformFileForPackedMaps } from '@expo/metro-config/build/serializer/packedMap'; +import { patchMetroSourceMapStringForPackedMaps } from '@expo/metro-config/build/serializer/sourceMap'; import getMetroAssets from '@expo/metro-config/build/transform-worker/getAssets'; import assert from 'assert'; import fs from 'fs'; @@ -383,6 +385,12 @@ export async function createMetroServerAndBundleRequestAsync( }), })); + // The dev server applies the same patch from `instantiateMetro.ts`; + // this is the export-embed / `expo-updates` path, where `data.map` + // would otherwise reach Metro's readers in the unwrapped wire shape. + patchTransformFileForPackedMaps(metro.getBundler().getBundler()); + patchMetroSourceMapStringForPackedMaps(); + return { server: metro, bundleRequest }; } diff --git a/packages/@expo/cli/src/start/server/metro/MetroBundlerDevServer.ts b/packages/@expo/cli/src/start/server/metro/MetroBundlerDevServer.ts index eb26b8d699b8d6..424304a00ca42a 100644 --- a/packages/@expo/cli/src/start/server/metro/MetroBundlerDevServer.ts +++ b/packages/@expo/cli/src/start/server/metro/MetroBundlerDevServer.ts @@ -8,15 +8,7 @@ import type { ExpoConfig } from '@expo/config'; import { getConfig } from '@expo/config'; import { getMetroServerRoot, resolveRelativeEntryPoint } from '@expo/config/paths'; import baseJSBundle from '@expo/metro/metro/DeltaBundler/Serializers/baseJSBundle'; -import { - sourceMapGeneratorNonBlocking, - type SourceMapGeneratorOptions, -} from '@expo/metro/metro/DeltaBundler/Serializers/sourceMapGenerator'; -import type { - Module, - DeltaResult, - TransformInputOptions, -} from '@expo/metro/metro/DeltaBundler/types'; +import type { DeltaResult, TransformInputOptions } from '@expo/metro/metro/DeltaBundler/types'; import type { default as MetroHmrServer, Client as MetroHmrClient, @@ -28,6 +20,7 @@ import getGraphId from '@expo/metro/metro/lib/getGraphId'; import type { TransformProfile } from '@expo/metro/metro-babel-transformer'; import type { CustomResolverOptions } from '@expo/metro/metro-resolver'; import type { SerialAsset } from '@expo/metro-config/build/serializer/serializerAssets'; +import { sourceMapStringNonBlocking } from '@expo/metro-config/build/serializer/sourceMap'; import type { GetStreamingContentOptions } from '@expo/router-server/build/server/renderStreamingContent'; import type { GetStaticContentOptions } from '@expo/router-server/build/static/renderStaticContent'; import assert from 'assert'; @@ -2239,7 +2232,7 @@ export class MetroBundlerDevServer extends BundlerDevServer { prepend = []; } - bundleMap = await sourceMapStringAsync( + bundleMap = await sourceMapStringNonBlocking( [ // ...prepend, @@ -2351,15 +2344,6 @@ function wrapBundle(str: string) { return str.replace(/^(__r\(.*\);)$/gm, 'module.exports = $1'); } -async function sourceMapStringAsync( - modules: readonly Module[], - options: SourceMapGeneratorOptions -): Promise { - return (await sourceMapGeneratorNonBlocking(modules, options)).toString(undefined, { - excludeSource: options.excludeSource, - }); -} - function unique(array: T[]): T[] { return Array.from(new Set(array)); } diff --git a/packages/@expo/cli/src/start/server/metro/instantiateMetro.ts b/packages/@expo/cli/src/start/server/metro/instantiateMetro.ts index f197a6a0512841..4b315bb60af1f0 100644 --- a/packages/@expo/cli/src/start/server/metro/instantiateMetro.ts +++ b/packages/@expo/cli/src/start/server/metro/instantiateMetro.ts @@ -13,6 +13,8 @@ import { mergeConfig, resolveConfig, type ConfigT } from '@expo/metro/metro-conf import { Terminal } from '@expo/metro/metro-core'; import type { createStableModuleIdFactory } from '@expo/metro-config'; import { getDefaultConfig } from '@expo/metro-config'; +import { patchTransformFileForPackedMaps } from '@expo/metro-config/build/serializer/packedMap'; +import { patchMetroSourceMapStringForPackedMaps } from '@expo/metro-config/build/serializer/sourceMap'; import { resolveBabelrcName } from '@expo/metro-config/exports'; import chalk from 'chalk'; import type http from 'http'; @@ -494,6 +496,12 @@ export async function instantiateMetroAsync( ); }; + // Layered on top of the prune patch above. Both fresh worker results + // and cache hits flow through `Bundler.transformFile`, so wrapping + // here covers both. + patchTransformFileForPackedMaps(metro.getBundler().getBundler()); + patchMetroSourceMapStringForPackedMaps(); + setEventReporter(eventsSocket.reportMetroEvent); // This function ensures that modules in source maps are sorted in the same diff --git a/packages/@expo/metro-config/CHANGELOG.md b/packages/@expo/metro-config/CHANGELOG.md index 68034b3db289b8..fbcc8d2ae6ea7a 100644 --- a/packages/@expo/metro-config/CHANGELOG.md +++ b/packages/@expo/metro-config/CHANGELOG.md @@ -4,6 +4,8 @@ ### 🛠 Breaking changes +- Replace source-map representation used internally, and source-map format returned by transformer, reducing peak and retained memory usage ([#45594](https://github.com/expo/expo/pull/45594) by [@kitten](https://github.com/kitten)) + ### 🎉 New features ### 🐛 Bug fixes diff --git a/packages/@expo/metro-config/build/serializer/exportHermes.js b/packages/@expo/metro-config/build/serializer/exportHermes.js index dbde56a13c1e52..297b161ebe5921 100644 --- a/packages/@expo/metro-config/build/serializer/exportHermes.js +++ b/packages/@expo/metro-config/build/serializer/exportHermes.js @@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildHermesBundleAsync = buildHermesBundleAsync; -const metro_source_map_1 = require("@expo/metro/metro-source-map"); const spawn_async_1 = __importDefault(require("@expo/spawn-async")); const chalk_1 = __importDefault(require("chalk")); const fs_1 = __importDefault(require("fs")); @@ -12,6 +11,7 @@ const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); const process_1 = __importDefault(require("process")); const resolve_from_1 = __importDefault(require("resolve-from")); +const sourceMap_1 = require("./sourceMap"); const debug = require('debug')('expo:metro:hermes'); function importHermesCommandFromProject(projectRoot) { const platformExecutable = getHermesCommandPlatform(); @@ -113,6 +113,6 @@ async function createHermesSourcemapAsync(sourcemap, hermesMapFile) { const bundlerSourcemap = JSON.parse(sourcemap); const hermesSourcemapContent = await fs_1.default.promises.readFile(hermesMapFile, 'utf8'); const hermesSourcemap = JSON.parse(hermesSourcemapContent); - return JSON.stringify((0, metro_source_map_1.composeSourceMaps)([bundlerSourcemap, hermesSourcemap])); + return JSON.stringify((0, sourceMap_1.composeSourceMaps)([bundlerSourcemap, hermesSourcemap])); } //# sourceMappingURL=exportHermes.js.map \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/exportHermes.js.map b/packages/@expo/metro-config/build/serializer/exportHermes.js.map index b33882bbb43dad..8e59d8d332b22f 100644 --- a/packages/@expo/metro-config/build/serializer/exportHermes.js.map +++ b/packages/@expo/metro-config/build/serializer/exportHermes.js.map @@ -1 +1 @@ -{"version":3,"file":"exportHermes.js","sourceRoot":"","sources":["../../src/serializer/exportHermes.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"exportHermes.js","sourceRoot":"","sources":["../../src/serializer/exportHermes.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/jsOutput.d.ts b/packages/@expo/metro-config/build/serializer/jsOutput.d.ts index 10bf721847579b..d4c8dd773f8370 100644 --- a/packages/@expo/metro-config/build/serializer/jsOutput.d.ts +++ b/packages/@expo/metro-config/build/serializer/jsOutput.d.ts @@ -7,13 +7,16 @@ import type { types as t } from '@babel/core'; import type { FBSourceFunctionMap, MetroSourceMapSegmentTuple } from '@expo/metro/metro-source-map'; import type { JsTransformerConfig } from '@expo/metro/metro-transform-worker'; +import type { PackedMap, SerializableSourceMap } from './packedMap'; import type { Options as CollectDependenciesOptions } from '../transform-worker/collect-dependencies'; export type JSFileType = 'js/script' | 'js/module' | 'js/module/asset'; +export type ModuleSourceMap = SerializableSourceMap | MetroSourceMapSegmentTuple[]; export type JsOutput = { data: { code: string; lineCount: number; - map: MetroSourceMapSegmentTuple[]; + map: ModuleSourceMap; + readonly __packedMap?: PackedMap; functionMap: FBSourceFunctionMap | null; css?: { code: string; diff --git a/packages/@expo/metro-config/build/serializer/jsOutput.js.map b/packages/@expo/metro-config/build/serializer/jsOutput.js.map index 3aec0b6a36d34a..ad58c776062c48 100644 --- a/packages/@expo/metro-config/build/serializer/jsOutput.js.map +++ b/packages/@expo/metro-config/build/serializer/jsOutput.js.map @@ -1 +1 @@ -{"version":3,"file":"jsOutput.js","sourceRoot":"","sources":["../../src/serializer/jsOutput.ts"],"names":[],"mappings":";;AAiFA,wCAEC;AAID,0DAEC;AARD,SAAgB,cAAc,CAAC,MAAW;IACxC,OAAO,MAAM,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC7D,CAAC;AAED,+FAA+F;AAC/F,sDAAsD;AACtD,SAAgB,uBAAuB,CAAC,MAAW;IACjD,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,GAAG,CAAC;AAChE,CAAC"} \ No newline at end of file +{"version":3,"file":"jsOutput.js","sourceRoot":"","sources":["../../src/serializer/jsOutput.ts"],"names":[],"mappings":";;AA8FA,wCAEC;AAID,0DAEC;AARD,SAAgB,cAAc,CAAC,MAAW;IACxC,OAAO,MAAM,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC7D,CAAC;AAED,+FAA+F;AAC/F,sDAAsD;AACtD,SAAgB,uBAAuB,CAAC,MAAW;IACjD,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,GAAG,CAAC;AAChE,CAAC"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/packedMap.d.ts b/packages/@expo/metro-config/build/serializer/packedMap.d.ts new file mode 100644 index 00000000000000..c1321c2ea8f0c6 --- /dev/null +++ b/packages/@expo/metro-config/build/serializer/packedMap.d.ts @@ -0,0 +1,48 @@ +/** + * Copyright © 2026 650 Industries. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import type { BabelSourceMapSegment, MetroSourceMapSegmentTuple } from '@expo/metro/metro-source-map'; +export declare const STRIDE = 5; +export declare const SENTINEL = -1; +export interface SerializableSourceMap { + __packed: number[]; + __names: string[]; + __count: number; + __version: 1; +} +export declare function isSerializableSourceMap(x: unknown): x is SerializableSourceMap; +export declare class PackedMap { + readonly count: number; + readonly names: string[]; + readonly buf: Int32Array; + private constructor(); + static deserialize(input: SerializableSourceMap): PackedMap; + static fromInts(buf: Int32Array, names: string[], count: number): PackedMap; + serialize(): SerializableSourceMap; +} +export declare function tupleAt(p: PackedMap, i: number): MetroSourceMapSegmentTuple | undefined; +export declare function installPackedMap(data: { + map?: unknown; + __packedMap?: PackedMap; +}, source: SerializableSourceMap | readonly MetroSourceMapSegmentTuple[]): void; +export declare function wrapTransformResultMaps(result: T): T; +export declare function patchTransformFileForPackedMaps(bundler: { + transformFile: (...args: any[]) => Promise; +}): void; +export declare function materializeMap(map: SerializableSourceMap | readonly MetroSourceMapSegmentTuple[] | null | undefined): MetroSourceMapSegmentTuple[]; +export declare function emptySourceMap(): SerializableSourceMap; +export declare function packRawMappings(rawMappings: readonly BabelSourceMapSegment[]): SerializableSourceMap; +export declare function packDecodedMappings(input: { + mappings: string; + names: readonly string[]; +}): SerializableSourceMap; +export declare function countLinesAndTerminateSourceMap(code: string, sourceMap: SerializableSourceMap): { + lineCount: number; + sourceMap: SerializableSourceMap; +}; +export declare function makeProxy(packed: PackedMap): MetroSourceMapSegmentTuple[]; diff --git a/packages/@expo/metro-config/build/serializer/packedMap.js b/packages/@expo/metro-config/build/serializer/packedMap.js new file mode 100644 index 00000000000000..40ea4da583a801 --- /dev/null +++ b/packages/@expo/metro-config/build/serializer/packedMap.js @@ -0,0 +1,416 @@ +"use strict"; +/** + * Copyright © 2026 650 Industries. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PackedMap = exports.SENTINEL = exports.STRIDE = void 0; +exports.isSerializableSourceMap = isSerializableSourceMap; +exports.tupleAt = tupleAt; +exports.installPackedMap = installPackedMap; +exports.wrapTransformResultMaps = wrapTransformResultMaps; +exports.patchTransformFileForPackedMaps = patchTransformFileForPackedMaps; +exports.materializeMap = materializeMap; +exports.emptySourceMap = emptySourceMap; +exports.packRawMappings = packRawMappings; +exports.packDecodedMappings = packDecodedMappings; +exports.countLinesAndTerminateSourceMap = countLinesAndTerminateSourceMap; +exports.makeProxy = makeProxy; +// Layout per segment, starting at `i * STRIDE`. Fixed stride so segments +// are indexable in O(1); missing fields use sentinel `-1`. Lines are +// 1-based to match `MetroSourceMapSegmentTuple`. +// [0] generated line +// [1] generated column +// [2] source line (-1 if sourceless) +// [3] source column (-1 if sourceless) +// [4] name index (-1 if no name) +exports.STRIDE = 5; +exports.SENTINEL = -1; +function isSerializableSourceMap(x) { + if (x == null || typeof x !== 'object') + return false; + const o = x; + return (o.__version === 1 && + Array.isArray(o.__packed) && + Array.isArray(o.__names) && + typeof o.__count === 'number'); +} +class PackedMap { + count; + names; + // `Int32Array` storage: 4 bytes/int off-heap vs 8 bytes/slot for the + // tagged `number[]` shape that `SerializableSourceMap` carries. + // Materialized eagerly so a `data.map` whose encoder never iterates + // (e.g. SSR-eval'd modules — the bundle is concatenated and + // `_compile`-ed without anyone calling `.buf`) doesn't strand a + // serialized-shape array on the JS heap. + buf; + constructor(buf, names, count) { + this.buf = buf; + this.names = names; + this.count = count; + } + static deserialize(input) { + return new PackedMap(Int32Array.from(input.__packed), input.__names, input.__count); + } + static fromInts(buf, names, count) { + return new PackedMap(buf, names, count); + } + serialize() { + const buf = this.buf; + const out = new Array(buf.length); + for (let i = 0; i < buf.length; i++) + out[i] = buf[i]; + return { + __version: 1, + __count: this.count, + __names: this.names.slice(), + __packed: out, + }; + } +} +exports.PackedMap = PackedMap; +// Returns the variable-length form (2, 4, or 5) that matches Metro's +// tuple union. A fixed-length-5 tuple with `-1` sentinels would fool +// `symbolicate.js`'s `mapping.length < 4` sourceless-check and resolve to +// garbage source positions. +function tupleAt(p, i) { + if (i < 0 || i >= p.count) + return undefined; + const buf = p.buf; + const off = i * exports.STRIDE; + const genL = buf[off]; + const genC = buf[off + 1]; + const srcL = buf[off + 2]; + if (srcL === exports.SENTINEL) { + return [genL, genC]; + } + const srcC = buf[off + 3]; + const nameIdx = buf[off + 4]; + if (nameIdx === exports.SENTINEL) { + return [genL, genC, srcL, srcC]; + } + // A `SerializableSourceMap` with `nameIdx >= __names.length` is malformed; throw a + // clear error rather than silently producing `[..., undefined]`, which + // would corrupt names through the encoder without any obvious symptom. + const name = p.names[nameIdx]; + if (name === undefined) { + throw new Error(`[expo-metro-config] PackedMap segment ${i} references name index ${nameIdx}, ` + + `but only ${p.names.length} names exist. The serialized entry is corrupt; ` + + `clear the metro cache (\`expo start --clear\`) and rebuild.`); + } + return [genL, genC, srcL, srcC, name]; +} +function* iterateTuples(p) { + for (let i = 0; i < p.count; i++) { + yield tupleAt(p, i); + } +} +const NODE_INSPECT = Symbol.for('nodejs.util.inspect.custom'); +// Replace `data.map` with the `Array.isArray`-true Proxy and attach the +// underlying `PackedMap` as non-enumerable `data.__packedMap` for the +// encoder fast path. Accepts either a `SerializableSourceMap` (worker output, +// cache hits) or plain tuples (reconcile-style serializer plugins). +// Idempotent: both fields are defined `configurable: true`, so re-running +// on a previously-installed `data` object is safe. +function installPackedMap(data, source) { + // Tuple input goes straight to a typed-array-backed `PackedMap` — going + // via `packTuples` would allocate a `number[]` that + // `PackedMap.deserialize` would then drop on first `.buf` access. + const packed = isSerializableSourceMap(source) + ? PackedMap.deserialize(source) + : packTuplesToPackedMap(source); + // Lazy accessor for `data.map`: builds that never symbolicate (typical + // CI / quiet dev sessions) read `data.__packedMap` exclusively via the + // encoder fast path, so the Proxy is never allocated. Cached on first + // read so consumers that hold onto `data.map` (e.g. + // `getExplodedSourceMap`) see a stable identity. + let cachedProxy; + Object.defineProperty(data, 'map', { + get() { + if (!cachedProxy) + cachedProxy = makeProxy(packed); + return cachedProxy; + }, + enumerable: true, + configurable: true, + }); + Object.defineProperty(data, '__packedMap', { + value: packed, + enumerable: false, + writable: false, + configurable: true, + }); +} +// The single chokepoint between "worker emits SerializableSourceMap" and "main-thread +// readers expect array-shaped tuples". Used in production via the +// `Bundler.transformFile` patch and called directly in tests. +function wrapTransformResultMaps(result) { + if (!result || !Array.isArray(result.output)) + return result; + for (const out of result.output) { + const data = out?.data; + if (!data) + continue; + // Skip without touching `data.map` — reading it would fire the lazy + // getter and materialize a Proxy we don't need. + if (data.__packedMap) + continue; + if (isSerializableSourceMap(data.map)) { + installPackedMap(data, data.map); + } + } + return result; +} +// Idempotent: chaining is safe because `installPackedMap` only fires +// when `data.map` is still a `SerializableSourceMap`. +function patchTransformFileForPackedMaps(bundler) { + const originalTransformFile = bundler.transformFile.bind(bundler); + bundler.transformFile = async (...args) => { + return wrapTransformResultMaps((await originalTransformFile(...args))); + }; +} +// Materialize any `data.map` shape (serialized, Proxy, or plain tuples) into a +// plain `MetroSourceMapSegmentTuple[]`. NOT a hot path — allocates a +// fresh tuple per segment; production readers go through the Proxy or +// the encoder fast path. +function materializeMap(map) { + if (map == null) + return []; + if (isSerializableSourceMap(map)) { + const packed = PackedMap.deserialize(map); + const out = new Array(packed.count); + for (let i = 0; i < packed.count; i++) { + out[i] = tupleAt(packed, i); + } + return out; + } + // The Proxy is `Array.isArray`-true and iterates via `Symbol.iterator`. + return Array.isArray(map) ? Array.from(map) : []; +} +function indexOrInsert(names, name) { + const existing = names.get(name); + if (existing !== undefined) + return existing; + const idx = names.size; + names.set(name, idx); + return idx; +} +function emptySourceMap() { + return { __version: 1, __count: 0, __names: [], __packed: [] }; +} +// Convert Babel’s `result.rawMappings` directly to a `SerializableSourceMap`. The +// worker's terminal storage is `SerializableSourceMap`, so going via an +// intermediate `MetroSourceMapSegmentTuple[]` (one heap-allocated Array +// per segment) is wasted work; for an N-module bundle averaging M +// segments per module that's N×M transient tuple allocations per +// transform pass. `BabelSourceMapSegment` lines are 1-based (matching +// the serialized shape). +function packRawMappings(rawMappings) { + const names = new Map(); + const out = new Array(rawMappings.length * exports.STRIDE); + let off = 0; + for (const m of rawMappings) { + out[off] = m.generated.line; + out[off + 1] = m.generated.column; + if (m.original == null) { + out[off + 2] = exports.SENTINEL; + out[off + 3] = exports.SENTINEL; + out[off + 4] = exports.SENTINEL; + } + else { + out[off + 2] = m.original.line; + out[off + 3] = m.original.column; + out[off + 4] = typeof m.name === 'string' ? indexOrInsert(names, m.name) : exports.SENTINEL; + } + off += exports.STRIDE; + } + return { + __version: 1, + __count: rawMappings.length, + __names: [...names.keys()], + __packed: out, + }; +} +// Decode a minifier’s encoded sourcemap straight to a `SerializableSourceMap`. `decode` +// returns 0-based outer indices and 0-based source lines; the serialized form is +// 1-based for both — adjust at the boundary. The minifier already +// deduplicates names, so `input.names` becomes the output `__names` +// directly without re-interning. +function packDecodedMappings(input) { + const decoded = loadSourceMapCodec().decode(input.mappings); + let total = 0; + for (const line of decoded) + total += line.length; + const out = new Array(total * exports.STRIDE); + let off = 0; + let count = 0; + for (let lineIdx = 0; lineIdx < decoded.length; lineIdx++) { + const genLine = lineIdx + 1; + for (const seg of decoded[lineIdx]) { + out[off] = genLine; + out[off + 1] = seg[0]; + if (seg.length === 1) { + out[off + 2] = exports.SENTINEL; + out[off + 3] = exports.SENTINEL; + out[off + 4] = exports.SENTINEL; + } + else { + out[off + 2] = seg[2] + 1; + out[off + 3] = seg[3]; + out[off + 4] = seg.length === 5 ? seg[4] : exports.SENTINEL; + } + off += exports.STRIDE; + count++; + } + } + return { + __version: 1, + __count: count, + __names: input.names.slice(), + __packed: out, + }; +} +// Append the trailing `(lineCount+1, lastLineLength)` terminator to the +// `SerializableSourceMap`’s `__packed` if it isn’t already there. Without this, an +// out-of-bounds lookup at the tail of the bundle would alias to the +// last real mapping rather than resolving to nothing — same invariant +// as the legacy tuple-array form, but applied in place on the flat +// `number[]` storage. +// +// ASSUMPTION: Mappings are generated in order of increasing line and +// column. +function countLinesAndTerminateSourceMap(code, sourceMap) { + const NEWLINE = /\r\n?|\n|\u2028|\u2029/g; + let lineCount = 1; + let lastLineStart = 0; + for (const match of code.matchAll(NEWLINE)) { + if (match.index == null) + continue; + lineCount++; + lastLineStart = match.index + match[0].length; + } + const lastLineLength = code.length - lastLineStart; + const lastIdx = sourceMap.__count - 1; + if (lastIdx >= 0) { + const off = lastIdx * exports.STRIDE; + if (sourceMap.__packed[off] === lineCount && sourceMap.__packed[off + 1] === lastLineLength) { + return { lineCount, sourceMap }; + } + } + return { + lineCount, + sourceMap: { + __version: 1, + __count: sourceMap.__count + 1, + __names: sourceMap.__names, + __packed: [...sourceMap.__packed, lineCount, lastLineLength, exports.SENTINEL, exports.SENTINEL, exports.SENTINEL], + }, + }; +} +let _sourceMapCodec; +function loadSourceMapCodec() { + if (!_sourceMapCodec) { + _sourceMapCodec = require('@jridgewell/sourcemap-codec'); + } + return _sourceMapCodec; +} +// Pack tuples straight into an `Int32Array`-backed `PackedMap`, skipping +// a `SerializableSourceMap`. Used by `installPackedMap` when the caller already lives +// on the main thread (reconcile, in-memory refits) and never needs the +// JSON-faithful serialized shape for IPC. +function packTuplesToPackedMap(tuples) { + const names = new Map(); + const buf = new Int32Array(tuples.length * exports.STRIDE); + let off = 0; + for (const tuple of tuples) { + buf[off] = tuple[0]; + buf[off + 1] = tuple[1]; + if (tuple.length === 2) { + buf[off + 2] = exports.SENTINEL; + buf[off + 3] = exports.SENTINEL; + buf[off + 4] = exports.SENTINEL; + } + else { + buf[off + 2] = tuple[2]; + buf[off + 3] = tuple[3]; + buf[off + 4] = tuple.length === 5 ? indexOrInsert(names, tuple[4]) : exports.SENTINEL; + } + off += exports.STRIDE; + } + return PackedMap.fromInts(buf, [...names.keys()], tuples.length); +} +// Target is `[]` (a real Array) so `Array.isArray(proxy)` returns true +// per ECMA-262 §7.2.2 — required by Metro's `symbolicate`. +function makeProxy(packed) { + const target = []; + const handler = { + get(_t, prop) { + if (prop === 'length') + return packed.count; + if (prop === Symbol.iterator) + return () => iterateTuples(packed); + if (prop === 'toJSON') + return () => packed.serialize(); + if (prop === NODE_INSPECT) { + return () => `PackedMap(count=${packed.count})`; + } + if (typeof prop === 'string') { + const n = +prop; + if (Number.isInteger(n) && String(n) === prop && n >= 0) { + return tupleAt(packed, n); + } + } + // Array.prototype methods (`forEach`, `map`, …) reach us back + // through numeric-index `get` and `length`, both covered above. + return Reflect.get(target, prop); + }, + has(_t, prop) { + if (prop === 'length' || prop === Symbol.iterator || prop === 'toJSON') + return true; + if (typeof prop === 'string') { + const n = +prop; + if (Number.isInteger(n) && String(n) === prop && n >= 0 && n < packed.count) { + return true; + } + } + return Reflect.has(target, prop); + }, + ownKeys(t) { + const keys = new Array(packed.count); + for (let i = 0; i < packed.count; i++) + keys[i] = String(i); + return keys.concat(Reflect.ownKeys(t)); + }, + getOwnPropertyDescriptor(t, prop) { + if (typeof prop === 'string') { + const n = +prop; + if (Number.isInteger(n) && String(n) === prop && n >= 0 && n < packed.count) { + return { + value: tupleAt(packed, n), + writable: false, + enumerable: true, + configurable: true, + }; + } + } + // Delegate `length` to the real Array target so the Proxy invariant + // for non-configurable own keys holds. + return Reflect.getOwnPropertyDescriptor(t, prop); + }, + set() { + throw new TypeError('[expo-metro-config] data.map is read-only — backed by a PackedMap. ' + + 'Modify the underlying source map or rebuild with a fresh transform instead.'); + }, + deleteProperty() { + throw new TypeError('[expo-metro-config] data.map is read-only — backed by a PackedMap.'); + }, + defineProperty() { + throw new TypeError('[expo-metro-config] data.map is read-only — backed by a PackedMap.'); + }, + }; + return new Proxy(target, handler); +} +//# sourceMappingURL=packedMap.js.map \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/packedMap.js.map b/packages/@expo/metro-config/build/serializer/packedMap.js.map new file mode 100644 index 00000000000000..f9f64a47f3a216 --- /dev/null +++ b/packages/@expo/metro-config/build/serializer/packedMap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"packedMap.js","sourceRoot":"","sources":["../../src/serializer/packedMap.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/reconcileTransformSerializerPlugin.js b/packages/@expo/metro-config/build/serializer/reconcileTransformSerializerPlugin.js index 1cd9115bf51b95..35f1f36bb7cae9 100644 --- a/packages/@expo/metro-config/build/serializer/reconcileTransformSerializerPlugin.js +++ b/packages/@expo/metro-config/build/serializer/reconcileTransformSerializerPlugin.js @@ -43,14 +43,13 @@ const generator_1 = __importDefault(require("@babel/generator")); const JsFileWrapping = __importStar(require("@expo/metro/metro/ModuleGraph/worker/JsFileWrapping")); const importLocationsPlugin_1 = require("@expo/metro/metro/ModuleGraph/worker/importLocationsPlugin"); const isResolvedDependency_1 = require("@expo/metro/metro/lib/isResolvedDependency"); -const metro_source_map_1 = require("@expo/metro/metro-source-map"); const metro_transform_plugins_1 = require("@expo/metro/metro-transform-plugins"); const assert_1 = __importDefault(require("assert")); const node_util_1 = __importDefault(require("node:util")); const jsOutput_1 = require("./jsOutput"); +const packedMap_1 = require("./packedMap"); const sideEffects_1 = require("./sideEffects"); const collect_dependencies_1 = __importStar(require("../transform-worker/collect-dependencies")); -const count_lines_1 = require("../transform-worker/count-lines"); const metro_transform_worker_1 = require("../transform-worker/metro-transform-worker"); const debug = require('debug')('expo:treeshaking'); const FORCE_REQUIRE_NAME_HINTS = false; @@ -229,31 +228,38 @@ async function reconcileTransformSerializerPlugin(entryPoint, preModules, graph, sourceFileName: value.path, sourceMaps: true, }, outputItem.data.code); - // @ts-expect-error: incorrectly typed upstream - let map = result.rawMappings ? result.rawMappings.map(metro_source_map_1.toSegmentTuple) : []; + // `rawMappings` is omitted from `@types/babel__generator`'s + // `GeneratorResult`, but Babel emits it whenever `sourceMaps: true`. + const rawMappings = result.rawMappings ?? []; let code = result.code; + let sourceMap; if (reconcile.minify) { const source = value.getSource().toString('utf-8'); - ({ map, code } = await (0, metro_transform_worker_1.minifyCode)(reconcile.minify, value.path, result.code, source, map, reserved)); + ({ sourceMap, code } = await (0, metro_transform_worker_1.minifyCode)(reconcile.minify, value.path, result.code, source, rawMappings, reserved)); + } + else { + sourceMap = (0, packedMap_1.packRawMappings)(rawMappings); } let lineCount; - ({ lineCount, map } = (0, count_lines_1.countLinesAndTerminateMap)(code, map)); - return { - ...outputItem, - data: { - ...outputItem.data, - code, - map, - lineCount, - functionMap: - // @ts-expect-error: https://github.com/facebook/metro/blob/6151e7eb241b15f3bb13b6302abeafc39d2ca3ad/packages/metro-transform-worker/src/index.js#L508-L512 - ast.metadata?.metro?.functionMap ?? - // @ts-expect-error: Fallback to deprecated explicitly-generated `functionMap` - ast.functionMap ?? - outputItem.data.functionMap ?? - null, - }, + ({ lineCount, sourceMap } = (0, packedMap_1.countLinesAndTerminateSourceMap)(code, sourceMap)); + const newData = { + ...outputItem.data, + code, + lineCount, + functionMap: + // @ts-expect-error: https://github.com/facebook/metro/blob/6151e7eb241b15f3bb13b6302abeafc39d2ca3ad/packages/metro-transform-worker/src/index.js#L508-L512 + ast.metadata?.metro?.functionMap ?? + // @ts-expect-error: Fallback to deprecated explicitly-generated `functionMap` + ast.functionMap ?? + outputItem.data.functionMap ?? + null, }; + // Reconcile runs post-graph-build, so it bypasses the + // `Bundler.transformFile` wrapper that normally installs the packed + // shape from worker output. Install it here directly so the encoder + // fast path stays live for reconciled modules. + (0, packedMap_1.installPackedMap)(newData, sourceMap); + return { ...outputItem, data: newData }; } } //# sourceMappingURL=reconcileTransformSerializerPlugin.js.map \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/reconcileTransformSerializerPlugin.js.map b/packages/@expo/metro-config/build/serializer/reconcileTransformSerializerPlugin.js.map index b8b130c227c606..f94ebe79a78dbf 100644 --- a/packages/@expo/metro-config/build/serializer/reconcileTransformSerializerPlugin.js.map +++ b/packages/@expo/metro-config/build/serializer/reconcileTransformSerializerPlugin.js.map @@ -1 +1 @@ -{"version":3,"file":"reconcileTransformSerializerPlugin.js","sourceRoot":"","sources":["../../src/serializer/reconcileTransformSerializerPlugin.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"reconcileTransformSerializerPlugin.js","sourceRoot":"","sources":["../../src/serializer/reconcileTransformSerializerPlugin.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,4CAkFC;AAMD,oCAGC;AAGD,gFAoMC;AAjVD,iEAAwC;AAOxC,oGAAsF;AACtF,sGAAsF;AACtF,qFAAkF;AAElF,iFAA6E;AAC7E,oDAA4B;AAC5B,0DAA6B;AAG7B,yCAA4C;AAC5C,2CAKqB;AACrB,+CAA4D;AAG5D,iGAIkD;AAClD,uFAIoD;AAMpD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAuB,CAAC;AAEzE,MAAM,wBAAwB,GAAG,KAAK,CAAC;AAEvC,iFAAiF;AACjF,iEAAiE;AACjE,SAAgB,gBAAgB,CAC9B,YAAmC,EACnC,WAAmC;IAEnC,iFAAiF;IACjF,iEAAiE;IACjE,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAsB,CAAC;IAEvD,MAAM,cAAc,GAAG,CACrB,GAGE,EACF,EAAE;QACF,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/C,8DAA8D;QAC9D,EAAE;QACF,qHAAqH;QACrH,gGAAgG;QAChG,EAAE;QACF,mGAAmG;QACnG,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,oHAAoH;QACpH,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,IAAA,8BAAO,EACxB,IAAA,0CAAmB,EAAC;gBAClB,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS;gBAC7B,WAAW,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW;gBAClC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,aAAa,EAAE,GAAG,CAAC,IAAI,CAAC,aAAa;aACtC,CAAC,CACH,CAAC;YAEF,IAAI,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChC,OAAO,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;QAED,uEAAuE;QACvE,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,CACH,uCAAuC,EACvC,mBAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAC7C,mBAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CACtD,CAAC;QAEF,MAAM,IAAI,KAAK,CACb,cAAc,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,gFAAgF,KAAK,CAAC,IAAI,CAC/H,WAAW,CAAC,OAAO,EAAE,CACtB;aACE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;aAChD,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;IACJ,CAAC,CAAC;IAEF,mGAAmG;IACnG,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAErC,sFAAsF;QACtF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE;gBACjC,uFAAuF;gBACvF,IAAI,EAAE,GAAG;aACV,CAAC,CAAC;QACL,CAAC;QAED,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE;YACjC,GAAG,QAAQ;YACX,uFAAuF;YACvF,IAAI,EAAE,GAAG;SACV,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAoB;IAC7C,OAAO,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACzC,CAAC;AAED,SAAgB,YAAY,CAAC,KAAoB,EAAE,IAAY;IAC7D,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,sBAAsB;QAAE,OAAO,KAAK,CAAC;IACjE,OAAO,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,KAAK,MAAM,CAAC;AAChF,CAAC;AAED,yLAAyL;AAClL,KAAK,UAAU,kCAAkC,CACtD,UAAkB,EAClB,UAA0C,EAC1C,KAAoB,EACpB,OAA0B;IAE1B,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAED,oFAAoF;IACpF,+GAA+G;IAC/G,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;QAChD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnC,IAAI,IAAA,yBAAc,EAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,sCAAsC;gBACtC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;oBACjB,EAAE;oBACF,MAAM,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAEhD,KAAK,UAAU,yBAAyB,CACtC,KAA0B,EAC1B,UAAwB;QAExB,IACE,UAAU,CAAC,IAAI,KAAK,WAAW;YAC/B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,EACnC,CAAC;YACD,KAAK,CAAC,6CAA6C,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YAClE,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,2FAA2F;QAC3F,0DAA0D;QAC1D,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;QAE5C,IAAA,gBAAM,EAAC,SAAS,EAAE,yEAAyE,CAAC,CAAC;QAE7F,IAAI,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;QAC9B,IAAA,gBAAM,EAAC,GAAG,EAAE,0BAA0B,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACrD,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;QAE3B,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;QAE/C,MAAM,oBAAoB,GAAG,GAAG,EAAE,CAChC,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;aAC7B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;YACd,MAAM,OAAO,GAAG,IAAA,2CAAoB,EAAC,GAAG,CAAC;gBACvC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;gBAC1C,CAAC,CAAC,SAAS,CAAC;YACd,OAAO,OAAO,IAAI,IAAA,yCAA2B,EAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5E,CAAC,CAAC;aACD,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEjC,MAAM,IAAI,GAAG,IAAA,2CAAkB,EAAC,GAAG,EAAE;YACnC,gBAAgB,EAAE,IAAI;YACtB,QAAQ,EAAE,KAAK,CAAC,IAAI;YACpB,SAAS;YACT,aAAa;YACb,OAAO,EAAE;gBACP,oCAAoC;gBACpC,GAAG,KAAK,CAAC,gBAAgB;gBAEzB,yBAAyB,EAAE,IAAI;gBAE/B,cAAc,EAAE,SAAS,CAAC,cAAc;gBACxC,uCAAuC;gBACvC,kBAAkB,EAAE,SAAS,CAAC,cAAc;oBAC1C,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,kBAAkB;wBACzC,CAAC,CAAC,oBAAoB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,kBAAkB,CAAC;wBAC1E,CAAC,CAAC,oBAAoB,EAAE;oBAC1B,CAAC,CAAC,EAAE;aACP;SACF,CAAC,CAAC;QAEH,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QAEf,IAAI,iBAAiB,GAAG,EAAE,CAAC;QAC3B,IAAI,YAAmC,CAAC;QAExC,MAAM,qBAAqB,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,8BAA8B,IAAI,IAAI,CAAC;QAC3F,oEAAoE;QACpE,IAAI,CAAC;YACH,wEAAwE;YACxE,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,iBAAiB,EAAE,GAAG,IAAA,8BAAmB,EAAC,GAAG,EAAE;gBACnE,GAAG,SAAS,CAAC,0BAA0B;gBACvC,4BAA4B,EAC1B,qBAAqB,IAAI,IAAI;oBAC3B,CAAC,CAAC,CAAC,GAAqB,EAAE,EAAE;wBACxB,OAAO,qBAAqB,CAAC,GAAG,CAAC,IAAA,gCAAQ,EAAC,GAAG,CAAC,CAAC,CAAC;oBAClD,CAAC;oBACH,CAAC,CAAC,IAAI;gBACV,WAAW,EAAE,KAAK;gBAClB,uCAAuC;gBACvC,gBAAgB,EAAE,wBAAwB;gBAC1C,gFAAgF;gBAChF,qBAAqB,EAAE,SAAS;aACjC,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,8CAA+B,EAAE,CAAC;gBACrD,MAAM,IAAI,gDAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,iDAAiD;QACjD,KAAK,CAAC,YAAY;YAChB,EAAE;YACF,gBAAgB,CAAC,YAAY,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAErD,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC,UAAU,CACnD,GAAG,EACH,SAAS,CAAC,aAAa,EACvB,SAAS,CAAC,SAAS,EACnB,iBAAiB,EACjB,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,sBAAsB,KAAK,KAAK,CAC3C,CAAC;QAEF,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,SAAS,CAAC,kCAAkC,IAAI,IAAI,EAAE,CAAC;YACzD,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,SAAS,CAAC,sBAAsB,EAAE,CAAC;YACrC,sEAAsE;YACtE,QAAQ,CAAC,IAAI,CACX,GAAG,IAAA,gDAAsB,EAAC,UAAU,EAAE;gBACpC,aAAa,EAAE,QAAQ;aACxB,CAAC,CACH,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,mBAAQ,EACrB,UAAU,EACV;YACE,kBAAkB;YAClB,mIAAmI;YACnI,OAAO,EAAE,SAAS,CAAC,sBAAsB;YACzC,QAAQ,EAAE,KAAK,CAAC,IAAI;YACpB,WAAW,EAAE,KAAK;YAClB,cAAc,EAAE,KAAK,CAAC,IAAI;YAC1B,UAAU,EAAE,IAAI;SACjB,EACD,UAAU,CAAC,IAAI,CAAC,IAAI,CACrB,CAAC;QAEF,4DAA4D;QAC5D,qEAAqE;QACrE,MAAM,WAAW,GAAI,MAAoD,CAAC,WAAW,IAAI,EAAE,CAAC;QAC5F,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACvB,IAAI,SAAgC,CAAC;QAErC,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAEnD,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,mCAAU,EACrC,SAAS,CAAC,MAAM,EAChB,KAAK,CAAC,IAAI,EACV,MAAM,CAAC,IAAI,EACX,MAAM,EACN,WAAW,EACX,QAAQ,CACT,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,IAAA,2BAAe,EAAC,WAAW,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,SAAS,CAAC;QACd,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,IAAA,2CAA+B,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;QAE9E,MAAM,OAAO,GAAG;YACd,GAAG,UAAU,CAAC,IAAI;YAClB,IAAI;YACJ,SAAS;YACT,WAAW;YACT,2JAA2J;YAC3J,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW;gBAChC,8EAA8E;gBAC9E,GAAG,CAAC,WAAW;gBACf,UAAU,CAAC,IAAI,CAAC,WAAW;gBAC3B,IAAI;SACP,CAAC;QACF,sDAAsD;QACtD,oEAAoE;QACpE,oEAAoE;QACpE,+CAA+C;QAC/C,IAAA,4BAAgB,EAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACrC,OAAO,EAAE,GAAG,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC1C,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/serializeChunks.js b/packages/@expo/metro-config/build/serializer/serializeChunks.js index b7cc4ad0f012c8..fdc710176ca82c 100644 --- a/packages/@expo/metro-config/build/serializer/serializeChunks.js +++ b/packages/@expo/metro-config/build/serializer/serializeChunks.js @@ -13,6 +13,7 @@ const path_1 = __importDefault(require("path")); const debugId_1 = require("./debugId"); const exportPath_1 = require("./exportPath"); const getCssDeps_1 = require("./getCssDeps"); +const sourceMap_1 = require("./sourceMap"); const getAssets_1 = __importDefault(require("../transform-worker/getAssets")); const filePath_1 = require("../utils/filePath"); // Lazy-loaded to avoid pulling in metro-source-map at startup @@ -23,15 +24,6 @@ function getBuildHermesBundleAsync() { } return _buildHermesBundleAsync; } -// Lazy-loaded to avoid pulling in metro's getAppendScripts -> sourceMapString -> @babel/traverse at startup -let _sourceMapString; -function getSourceMapString() { - if (!_sourceMapString) { - _sourceMapString = - require('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString').sourceMapString; - } - return _sourceMapString; -} let _baseJSBundleWithDependencies; function getBaseJSBundleWithDependencies() { if (!_baseJSBundleWithDependencies) { @@ -296,19 +288,13 @@ class Chunk { source: jsCode.code, }; const assets = [jsAsset]; - const mutateSourceMapWithDebugId = (sourceMap) => { - // TODO: Upstream this so we don't have to parse the source map back and forth. - if (!debugId) { - return sourceMap; - } - // NOTE: debugId isn't required for inline source maps because the source map is included in the same file, therefore - // we don't need to disambiguate between multiple source maps. - const sourceMapObject = JSON.parse(sourceMap); - sourceMapObject.debugId = debugId; - // NOTE: Sentry does this, but bun does not. - // sourceMapObject.debug_id = debugId; - return JSON.stringify(sourceMapObject); - }; + // debugId is passed into `sourceMapString` so the bundler-map path + // emits it inline rather than a JSON.parse + JSON.stringify + // roundtrip; the Hermes branch below has to splice into a finished + // JSON string because `buildHermesBundleAsync` is opaque. + // NOTE: skipped for inline source maps since they don't need + // disambiguation. We only emit `debugId` (Sentry also reads + // `debug_id`, but bun doesn't). if ( // Only include the source map if the `options.sourceMapUrl` option is provided and we are exporting a static build. includeSourceMaps && @@ -331,11 +317,13 @@ class Chunk { } return module; }); - // TODO: We may not need to mutate the original source map with a `debugId` when hermes is enabled since we'll have different source maps. - const sourceMap = mutateSourceMapWithDebugId(getSourceMapString()(modules, { + // TODO: We may not need to set `debugId` on the bundler sourcemap when + // Hermes is enabled, since we ship a separate `.hbc.map` for that case. + const sourceMap = (0, sourceMap_1.sourceMapString)(modules, { excludeSource: false, ...this.options, - })); + debugId, + }); assets.push({ filename: this.options.dev ? jsAsset.filename + '.map' : outputFile + '.map', originFilename: jsAsset.originFilename, @@ -379,7 +367,9 @@ class Chunk { } } if (assets[1] && hermesBundleOutput.sourcemap) { - assets[1].source = mutateSourceMapWithDebugId(hermesBundleOutput.sourcemap); + assets[1].source = debugId + ? (0, sourceMap_1.appendDebugIdToSourceMap)(hermesBundleOutput.sourcemap, debugId) + : hermesBundleOutput.sourcemap; assets[1].filename = assets[1].filename.replace(/\.js\.map$/, '.hbc.map'); } } diff --git a/packages/@expo/metro-config/build/serializer/serializeChunks.js.map b/packages/@expo/metro-config/build/serializer/serializeChunks.js.map index f6f1c7ee2a09f7..c89ea97f23db06 100644 --- a/packages/@expo/metro-config/build/serializer/serializeChunks.js.map +++ b/packages/@expo/metro-config/build/serializer/serializeChunks.js.map @@ -1 +1 @@ -{"version":3,"file":"serializeChunks.js","sourceRoot":"","sources":["../../src/serializer/serializeChunks.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"serializeChunks.js","sourceRoot":"","sources":["../../src/serializer/serializeChunks.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/sourceMap.d.ts b/packages/@expo/metro-config/build/serializer/sourceMap.d.ts new file mode 100644 index 00000000000000..07e4103c93b28f --- /dev/null +++ b/packages/@expo/metro-config/build/serializer/sourceMap.d.ts @@ -0,0 +1,43 @@ +/** + * Copyright © 2026 650 Industries. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import type { SourceMapGeneratorOptions } from '@expo/metro/metro/DeltaBundler/Serializers/sourceMapGenerator'; +import type { Module } from '@expo/metro/metro/DeltaBundler/types'; +import type { BabelSourceMapSegment, BasicSourceMap, FBSourceFunctionMap, HermesFunctionOffsets, MetroSourceMapSegmentTuple, MixedSourceMap } from '@expo/metro/metro-source-map'; +export type { BabelSourceMapSegment, BasicSourceMap, FBSourceFunctionMap, HermesFunctionOffsets, MetroSourceMapSegmentTuple, MixedSourceMap, SourceMapGeneratorOptions, }; +export interface ComposableSourceMap { + version: number; + file?: string; + mappings: string; + names: string[]; + sources: (string | null)[]; + sourcesContent?: (string | null)[]; + sourceRoot?: string; + ignoreList?: number[]; + x_google_ignoreList?: number[]; + x_hermes_function_offsets?: HermesFunctionOffsets; +} +export interface ExpoSourceMapOptions extends SourceMapGeneratorOptions { + debugId?: string; +} +export declare function appendDebugIdToSourceMap(sourceMap: string, debugId: string): string; +export declare function sourceMapString(modules: readonly Module[], options: ExpoSourceMapOptions): string; +export declare function sourceMapStringNonBlocking(modules: readonly Module[], options: ExpoSourceMapOptions): Promise; +export declare function patchMetroSourceMapStringForPackedMaps(): void; +export declare function composeSourceMaps(maps: readonly ComposableSourceMap[]): ComposableSourceMap; +export interface EncodedTransformerSourceMap { + version: 3; + file?: string; + mappings: string; + names: string[]; + sources: string[]; + sourcesContent?: (string | null)[]; +} +export declare function rawMappingsToEncodedMap(opts: { + filename: string; + source: string; + rawMappings: readonly BabelSourceMapSegment[]; +}): EncodedTransformerSourceMap; diff --git a/packages/@expo/metro-config/build/serializer/sourceMap.js b/packages/@expo/metro-config/build/serializer/sourceMap.js new file mode 100644 index 00000000000000..1412ea81c60da5 --- /dev/null +++ b/packages/@expo/metro-config/build/serializer/sourceMap.js @@ -0,0 +1,304 @@ +"use strict"; +/** + * Copyright © 2026 650 Industries. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.appendDebugIdToSourceMap = appendDebugIdToSourceMap; +exports.sourceMapString = sourceMapString; +exports.sourceMapStringNonBlocking = sourceMapStringNonBlocking; +exports.patchMetroSourceMapStringForPackedMaps = patchMetroSourceMapStringForPackedMaps; +exports.composeSourceMaps = composeSourceMaps; +exports.rawMappingsToEncodedMap = rawMappingsToEncodedMap; +const packedMap_1 = require("./packedMap"); +let _remapping; +function loadRemapping() { + if (!_remapping) { + _remapping = require('@jridgewell/remapping'); + } + return _remapping; +} +let _Generator; +function loadGenerator() { + if (!_Generator) { + _Generator = require('@expo/metro/metro-source-map/Generator').default; + } + return _Generator; +} +let _isJsModule; +function loadMetroSerializerHelpers() { + if (!_isJsModule) { + _isJsModule = require('@expo/metro/metro/DeltaBundler/Serializers/helpers/js.js').isJsModule; + } + return { isJsModule: _isJsModule }; +} +function feedModuleSegments(generator, tuples, carryOver) { + for (let i = 0, n = tuples.length; i < n; i++) { + const tuple = tuples[i]; + const line = tuple[0] + carryOver; + const column = tuple[1]; + if (tuple.length === 2) { + generator.addSimpleMapping(line, column); + } + else if (tuple.length === 4) { + generator.addSourceMapping(line, column, tuple[2], tuple[3]); + } + else { + generator.addNamedSourceMapping(line, column, tuple[2], tuple[3], tuple[4]); + } + } +} +// Encoder fast path: read the `Int32Array` directly, skipping the Proxy +// and the tuple-per-segment allocation that Proxy iteration would incur. +// Without this, encoding a large bundle would allocate millions of +// transient tuples per pass — defeating the in-memory storage win. +function feedModuleSegmentsPacked(generator, packed, carryOver) { + const buf = packed.buf; + const names = packed.names; + const count = packed.count; + for (let i = 0; i < count; i++) { + const off = i * packedMap_1.STRIDE; + const line = buf[off] + carryOver; + const column = buf[off + 1]; + const srcLine = buf[off + 2]; + if (srcLine === packedMap_1.SENTINEL) { + generator.addSimpleMapping(line, column); + continue; + } + const srcCol = buf[off + 3]; + const nameIdx = buf[off + 4]; + if (nameIdx === packedMap_1.SENTINEL) { + generator.addSourceMapping(line, column, srcLine, srcCol); + } + else { + generator.addNamedSourceMapping(line, column, srcLine, srcCol, names[nameIdx]); + } + } +} +// Inlined rather than going through Metro's `getSourceMapInfo` because +// it spreads `data` and drops the non-enumerable `__packedMap`, +// silently forcing the encoder onto the slow Proxy path. +function readSourceMapInfo(module, options) { + const data = getModuleJsData(module); + // Don't read `data.map` when `__packedMap` is set — `data.map` is a + // lazy accessor that materializes the Proxy on first read, and the + // fast path below doesn't need it. + let packed = data.data.__packedMap; + let map; + if (!packed) { + map = data.data.map; + // Self-heal a `SerializableSourceMap` `data.map` that bypassed the wrapper. + if ((0, packedMap_1.isSerializableSourceMap)(map)) { + packed = packedMap_1.PackedMap.deserialize(map); + map = undefined; + } + } + return { + path: options.getSourceUrl?.(module) ?? module.path, + source: options.excludeSource || data.type === 'js/module/asset' ? '' : module.getSource().toString(), + functionMap: data.data.functionMap, + isIgnored: options.shouldAddToIgnoreList(module), + map, + packed, + lineCount: data.data.lineCount, + }; +} +function getModuleJsData(module) { + for (const out of module.output) { + const type = out.type; + if (typeof type === 'string' && type.startsWith('js/')) { + return out; + } + } + throw new Error(`[expo-metro-config] Module "${module.path}" has no JS output. Cannot build a sourcemap entry.`); +} +function processModuleIntoGenerator(generator, module, options, carryOver) { + const info = readSourceMapInfo(module, options); + generator.startFile(info.path, info.source, info.functionMap ?? null, { + addToIgnoreList: info.isIgnored, + }); + if (info.packed) { + feedModuleSegmentsPacked(generator, info.packed, carryOver); + } + else if (Array.isArray(info.map)) { + // Legacy plain-tuple path — hits for cache entries written before + // `data.map` switched to `SerializableSourceMap`, and for modules from custom + // transformers that don't emit packed format. + feedModuleSegments(generator, info.map, carryOver); + } + generator.endFile(); + return carryOver + info.lineCount; +} +function filterModules(modules, processModuleFilter) { + const { isJsModule } = loadMetroSerializerHelpers(); + const out = []; + for (const m of modules) { + if (isJsModule(m) && processModuleFilter(m)) { + out.push(m); + } + } + return out; +} +// Splice `,"debugId":"..."` in front of the trailing `}` of an already +// JSON-encoded sourcemap. Used for Hermes output where we don't control +// the JSON producer. +function appendDebugIdToSourceMap(sourceMap, debugId) { + return sourceMap.slice(0, -1) + `,"debugId":${JSON.stringify(debugId)}}`; +} +function emitGeneratorJson(generator, options) { + const json = generator.toString(undefined, { excludeSource: options.excludeSource }); + return options.debugId ? appendDebugIdToSourceMap(json, options.debugId) : json; +} +function sourceMapString(modules, options) { + const Generator = loadGenerator(); + const generator = new Generator(); + const filtered = filterModules(modules, options.processModuleFilter); + let carryOver = 0; + for (const mod of filtered) { + carryOver = processModuleIntoGenerator(generator, mod, options, carryOver); + } + return emitGeneratorJson(generator, options); +} +// Yields back to the event loop every ~50 ms so the node server stays +// responsive on very large bundles. Matches Metro's `getSourceMapInfosImpl` +// pacing. +async function sourceMapStringNonBlocking(modules, options) { + const Generator = loadGenerator(); + const generator = new Generator(); + const filtered = filterModules(modules, options.processModuleFilter); + const NS_IN_MS = 1_000_000; + const SLICE_NS = 50 * NS_IN_MS; + let carryOver = 0; + let i = 0; + await new Promise((resolve) => { + const tick = () => { + const start = process.hrtime(); + while (i < filtered.length) { + carryOver = processModuleIntoGenerator(generator, filtered[i], options, carryOver); + i++; + const diff = process.hrtime(start); + if (diff[1] > SLICE_NS || diff[0] > 0) { + setImmediate(tick); + return; + } + } + resolve(); + }; + tick(); + }); + return emitGeneratorJson(generator, options); +} +// Metro's `Server._processSourceMapRequest` calls +// `sourceMapStringNonBlocking` directly, bypassing the `customSerializer` +// chain — so without rerouting it, every dev `.map` fetch iterates the +// `data.map` Proxy and the encoder fast path is unreachable. +function patchMetroSourceMapStringForPackedMaps() { + const stock = require('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString'); + stock.sourceMapString = sourceMapString; + stock.sourceMapStringNonBlocking = sourceMapStringNonBlocking; +} +// `maps[0]` is the original-most transform; `maps[maps.length - 1]` is +// the most recent. Built on `@jridgewell/remapping` instead of mozilla's +// `SourceMapConsumer`-based composer. +// +// Two shims around remapping: +// - Translate `x_google_ignoreList` to the standard `ignoreList` on +// each input. Metro's `Generator` emits only the legacy alias, but +// remapping's `TraceMap` reads only the standard field, so without +// this ignore-list info disappears across compose. +// - Carry over `x_hermes_function_offsets` (load-bearing for Hermes +// bytecode-frame symbolication) and re-emit the legacy +// `x_google_ignoreList` alias for devtools that haven't yet picked up +// the rename. +// +// `x_facebook_sources` is deliberately dropped — Expo doesn't ship to FB +// symbolicators. +function composeSourceMaps(maps) { + if (maps.length < 1) { + throw new Error('composeSourceMaps: Expected at least one map'); + } + const normalized = maps.map((map) => { + if (map.ignoreList || !map.x_google_ignoreList) { + return map; + } + return { ...map, ignoreList: map.x_google_ignoreList }; + }); + // Metro convention is original-first; remapping is most-recent first. + const reversed = normalized.slice().reverse(); + const composed = loadRemapping()(reversed, () => null); + // Re-emit as a plain object — remapping returns a `SourceMap` class + // instance, which doesn't round-trip JSON cleanly. + const result = { + version: composed.version, + mappings: composed.mappings, + names: composed.names, + sources: composed.sources, + }; + if (composed.file != null) { + result.file = composed.file; + } + if (composed.sourceRoot != null) { + result.sourceRoot = composed.sourceRoot; + } + if (composed.sourcesContent) { + result.sourcesContent = composed.sourcesContent; + } + // Required by Hermes for bytecode-frame symbolication. Lives on the + // most-recent map (the Hermes map) and passes through unchanged. + const last = maps[maps.length - 1]; + if (last.x_hermes_function_offsets) { + result.x_hermes_function_offsets = last.x_hermes_function_offsets; + } + // Emit both standard and legacy keys so devtools either side of the + // rename keep working. + if (composed.ignoreList && composed.ignoreList.length > 0) { + result.ignoreList = composed.ignoreList; + result.x_google_ignoreList = composed.ignoreList; + } + return result; +} +let _genMapping; +function loadGenMapping() { + if (!_genMapping) { + _genMapping = require('@jridgewell/gen-mapping'); + } + return _genMapping; +} +// Convert Babel's `result.rawMappings` directly to an encoded sourcemap +// for feeding into a minifier. `BabelSourceMapSegment` lines are +// 1-based; `gen-mapping`'s `addSegment` is 0-based — subtract 1 at the +// boundary. Skipping a tuple intermediate avoids one Array allocation +// per segment. +function rawMappingsToEncodedMap(opts) { + const { GenMapping, addSegment, setSourceContent, toEncodedMap } = loadGenMapping(); + const map = new GenMapping({ file: opts.filename }); + setSourceContent(map, opts.filename, opts.source); + for (const m of opts.rawMappings) { + const genLine = m.generated.line - 1; + const genCol = m.generated.column; + if (m.original == null) { + addSegment(map, genLine, genCol); + } + else if (typeof m.name !== 'string') { + addSegment(map, genLine, genCol, opts.filename, m.original.line - 1, m.original.column); + } + else { + addSegment(map, genLine, genCol, opts.filename, m.original.line - 1, m.original.column, m.name); + } + } + const encoded = toEncodedMap(map); + // gen-mapping always registers `opts.filename` as the single source, so + // hard-coding avoids a `.map(...)` allocation and a `(string | null)[]` + // narrowing. + return { + version: encoded.version, + file: encoded.file ?? undefined, + mappings: encoded.mappings, + names: encoded.names, + sources: [opts.filename], + sourcesContent: encoded.sourcesContent, + }; +} +//# sourceMappingURL=sourceMap.js.map \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/sourceMap.js.map b/packages/@expo/metro-config/build/serializer/sourceMap.js.map new file mode 100644 index 00000000000000..2eef24d9bcbad8 --- /dev/null +++ b/packages/@expo/metro-config/build/serializer/sourceMap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sourceMap.js","sourceRoot":"","sources":["../../src/serializer/sourceMap.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/serializer/withExpoSerializers.js b/packages/@expo/metro-config/build/serializer/withExpoSerializers.js index 93b704f9214643..bd0a34ede02d6c 100644 --- a/packages/@expo/metro-config/build/serializer/withExpoSerializers.js +++ b/packages/@expo/metro-config/build/serializer/withExpoSerializers.js @@ -12,16 +12,8 @@ const jsc_safe_url_1 = require("jsc-safe-url"); const debugId_1 = require("./debugId"); const environmentVariableSerializerPlugin_1 = require("./environmentVariableSerializerPlugin"); const serializeChunks_1 = require("./serializeChunks"); +const sourceMap_1 = require("./sourceMap"); const env_1 = require("../env"); -// Lazy-loaded to avoid pulling in metro-source-map and @babel/traverse at startup (~100ms savings) -let _sourceMapString; -function getSourceMapString() { - if (!_sourceMapString) { - _sourceMapString = - require('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString').sourceMapString; - } - return _sourceMapString; -} // Lazy-loaded to avoid pulling in @babel/generator, @babel/core at startup let _reconcileTransformSerializerPlugin; function getReconcileTransformSerializerPlugin() { @@ -38,7 +30,7 @@ function getTreeShakeSerializer() { } return _treeShakeSerializer; } -// Lazy-loaded to avoid pulling in metro's getAppendScripts -> sourceMapString chain at startup +// Lazy-loaded to avoid pulling in metro's getAppendScripts at startup let _baseJSBundle; function getBaseJSBundle() { if (!_baseJSBundle) { @@ -135,7 +127,7 @@ function createDefaultExportCustomSerializer(config, configOptions = {}) { })).code; } const getEnsuredMaps = () => { - bundleMap ??= getSourceMapString()([...premodulesToBundle, ...(0, serializeChunks_1.getSortedModules)([...graph.dependencies.values()], options)], { + bundleMap ??= (0, sourceMap_1.sourceMapString)([...premodulesToBundle, ...(0, serializeChunks_1.getSortedModules)([...graph.dependencies.values()], options)], { excludeSource: options.serializerOptions?.excludeSource ?? false, processModuleFilter: options.processModuleFilter, shouldAddToIgnoreList: options.shouldAddToIgnoreList, diff --git a/packages/@expo/metro-config/build/serializer/withExpoSerializers.js.map b/packages/@expo/metro-config/build/serializer/withExpoSerializers.js.map index e6788ded63f881..33e2b45409a883 100644 --- a/packages/@expo/metro-config/build/serializer/withExpoSerializers.js.map +++ b/packages/@expo/metro-config/build/serializer/withExpoSerializers.js.map @@ -1 +1 @@ -{"version":3,"file":"withExpoSerializers.js","sourceRoot":"","sources":["../../src/serializer/withExpoSerializers.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"withExpoSerializers.js","sourceRoot":"","sources":["../../src/serializer/withExpoSerializers.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/transform-worker/count-lines.d.ts b/packages/@expo/metro-config/build/transform-worker/count-lines.d.ts deleted file mode 100644 index e3447a37402052..00000000000000 --- a/packages/@expo/metro-config/build/transform-worker/count-lines.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright 2024-present 650 Industries (Expo). All rights reserved. - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * https://github.com/facebook/metro/blob/96c6b893eb77b5929b6050d7189905232ddf6d6d/packages/metro-transform-worker/src/index.js#L679 - */ -import type { MetroSourceMapSegmentTuple } from '@expo/metro/metro-source-map'; -export declare function countLinesAndTerminateMap(code: string, map: readonly MetroSourceMapSegmentTuple[]): { - lineCount: number; - map: MetroSourceMapSegmentTuple[]; -}; diff --git a/packages/@expo/metro-config/build/transform-worker/count-lines.js b/packages/@expo/metro-config/build/transform-worker/count-lines.js deleted file mode 100644 index 6393e7b70acdaf..00000000000000 --- a/packages/@expo/metro-config/build/transform-worker/count-lines.js +++ /dev/null @@ -1,43 +0,0 @@ -"use strict"; -/** - * Copyright 2024-present 650 Industries (Expo). All rights reserved. - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * https://github.com/facebook/metro/blob/96c6b893eb77b5929b6050d7189905232ddf6d6d/packages/metro-transform-worker/src/index.js#L679 - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.countLinesAndTerminateMap = countLinesAndTerminateMap; -function countLinesAndTerminateMap(code, map) { - const NEWLINE = /\r\n?|\n|\u2028|\u2029/g; - let lineCount = 1; - let lastLineStart = 0; - // Count lines and keep track of where the last line starts - for (const match of code.matchAll(NEWLINE)) { - if (match.index == null) - continue; - lineCount++; - lastLineStart = match.index + match[0].length; - } - const lastLineLength = code.length - lastLineStart; - const lastLineIndex1Based = lineCount; - const lastLineNextColumn0Based = lastLineLength; - // If there isn't a mapping at one-past-the-last column of the last line, - // add one that maps to nothing. This ensures out-of-bounds lookups hit the - // null mapping rather than aliasing to whichever mapping happens to be last. - // ASSUMPTION: Mappings are generated in order of increasing line and column. - const lastMapping = map[map.length - 1]; - const terminatingMapping = [lastLineIndex1Based, lastLineNextColumn0Based]; - if (!lastMapping || - lastMapping[0] !== terminatingMapping[0] || - lastMapping[1] !== terminatingMapping[1]) { - return { - lineCount, - map: map.concat([terminatingMapping]), - }; - } - return { lineCount, map: [...map] }; -} -//# sourceMappingURL=count-lines.js.map \ No newline at end of file diff --git a/packages/@expo/metro-config/build/transform-worker/count-lines.js.map b/packages/@expo/metro-config/build/transform-worker/count-lines.js.map deleted file mode 100644 index 25e2b4d15d9103..00000000000000 --- a/packages/@expo/metro-config/build/transform-worker/count-lines.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"count-lines.js","sourceRoot":"","sources":["../../src/transform-worker/count-lines.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AAIH,8DAsCC;AAtCD,SAAgB,yBAAyB,CACvC,IAAY,EACZ,GAA0C;IAK1C,MAAM,OAAO,GAAG,yBAAyB,CAAC;IAC1C,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,2DAA2D;IAC3D,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI;YAAE,SAAS;QAClC,SAAS,EAAE,CAAC;QACZ,aAAa,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAChD,CAAC;IACD,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC;IACnD,MAAM,mBAAmB,GAAG,SAAS,CAAC;IACtC,MAAM,wBAAwB,GAAG,cAAc,CAAC;IAEhD,yEAAyE;IACzE,2EAA2E;IAC3E,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACxC,MAAM,kBAAkB,GAAqB,CAAC,mBAAmB,EAAE,wBAAwB,CAAC,CAAC;IAC7F,IACE,CAAC,WAAW;QACZ,WAAW,CAAC,CAAC,CAAC,KAAK,kBAAkB,CAAC,CAAC,CAAC;QACxC,WAAW,CAAC,CAAC,CAAC,KAAK,kBAAkB,CAAC,CAAC,CAAC,EACxC,CAAC;QACD,OAAO;YACL,SAAS;YACT,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;SACtC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;AACtC,CAAC"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.d.ts b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.d.ts index 8bc88a7d6aaffb..7f3ad5074e0dcf 100644 --- a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.d.ts +++ b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.d.ts @@ -9,11 +9,12 @@ * https://github.com/facebook/metro/blob/412771475c540b6f85d75d9dcd5a39a6e0753582/packages/metro-transform-worker/src/index.js#L1 */ import { types as t } from '@babel/core'; -import type { MetroSourceMapSegmentTuple } from '@expo/metro/metro-source-map'; import type { JsTransformerConfig, JsTransformOptions } from '@expo/metro/metro-transform-worker'; import type { CollectedDependencies, Options as CollectDependenciesOptions } from './collect-dependencies'; import { InvalidRequireCallError as InternalInvalidRequireCallError } from './collect-dependencies'; import type { ExpoJsOutput } from '../serializer/jsOutput'; +import { type SerializableSourceMap } from '../serializer/packedMap'; +import { type BabelSourceMapSegment } from '../serializer/sourceMap'; export { JsTransformOptions }; interface TransformResponse { readonly dependencies: CollectedDependencies['dependencies']; @@ -24,9 +25,9 @@ export declare class InvalidRequireCallError extends Error { filename: string; constructor(innerError: InternalInvalidRequireCallError, filename: string); } -export declare const minifyCode: (config: Pick, filename: string, code: string, source: string, map: MetroSourceMapSegmentTuple[], reserved?: string[]) => Promise<{ +export declare const minifyCode: (config: Pick, filename: string, code: string, source: string, rawMappings: readonly BabelSourceMapSegment[], reserved?: string[]) => Promise<{ code: string; - map: MetroSourceMapSegmentTuple[]; + sourceMap: SerializableSourceMap; }>; export declare function applyImportSupport(ast: TFile, { filename, options, importDefault, importAll, collectLocations, performConstantFolding, }: { filename: string; diff --git a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js index 3ff83c984d035e..d265b882837a37 100644 --- a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js +++ b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js @@ -63,8 +63,9 @@ const metroTransformPlugins = __importStar(require("@expo/metro/metro-transform- const node_assert_1 = __importDefault(require("node:assert")); const assetTransformer = __importStar(require("./asset-transformer")); const collect_dependencies_1 = __importStar(require("./collect-dependencies")); -const count_lines_1 = require("./count-lines"); const resolveOptions_1 = require("./resolveOptions"); +const packedMap_1 = require("../serializer/packedMap"); +const sourceMap_1 = require("../serializer/sourceMap"); const transform_plugins_1 = require("../transform-plugins"); const getMinifier_1 = require("./utils/getMinifier"); class InvalidRequireCallError extends Error { @@ -94,19 +95,8 @@ function getDynamicDepsBehavior(inPackages, filename) { throw new Error(`invalid value for dynamic deps behavior: \`${inPackages}\``); } } -const minifyCode = async (config, filename, code, source, map, reserved = []) => { - const sourceMap = (0, metro_source_map_1.fromRawMappings)([ - { - code, - source, - map, - // functionMap is overridden by the serializer - functionMap: null, - path: filename, - // isIgnored is overriden by the serializer - isIgnored: false, - }, - ]).toMap(undefined, {}); +const minifyCode = async (config, filename, code, source, rawMappings, reserved = []) => { + const sourceMap = (0, sourceMap_1.rawMappingsToEncodedMap)({ filename, source, rawMappings }); const minify = (0, getMinifier_1.getMinifier)(config.minifierPath); try { const minified = await minify({ @@ -118,7 +108,9 @@ const minifyCode = async (config, filename, code, source, map, reserved = []) => }); return { code: minified.code, - map: minified.map ? (0, metro_source_map_1.toBabelSegments)(minified.map).map(metro_source_map_1.toSegmentTuple) : [], + sourceMap: minified.map + ? (0, packedMap_1.packDecodedMappings)({ mappings: minified.map.mappings, names: minified.map.names }) + : (0, packedMap_1.emptySourceMap)(), }; } catch (error) { @@ -380,12 +372,17 @@ async function transformJS(file, { config, options }) { sourceFileName: file.filename, sourceMaps: true, }, file.code); - // NOTE: incorrectly typed upstream - let map = result?.rawMappings.map(metro_source_map_1.toSegmentTuple) ?? []; + // `rawMappings` is omitted from `@types/babel__generator`'s + // `GeneratorResult`, but Babel emits it whenever `sourceMaps: true`. + const rawMappings = result?.rawMappings ?? []; let code = result.code; + let sourceMap; // NOTE: We might want to enable this on native + hermes when tree shaking is enabled. if (minify) { - ({ map, code } = await (0, exports.minifyCode)(config, file.filename, result.code, file.code, map, reserved)); + ({ sourceMap, code } = await (0, exports.minifyCode)(config, file.filename, result.code, file.code, rawMappings, reserved)); + } + else { + sourceMap = (0, packedMap_1.packRawMappings)(rawMappings); } const possibleReconcile = optimize && collectDependenciesOptions ? { @@ -409,7 +406,7 @@ async function transformJS(file, { config, options }) { } : undefined; let lineCount; - ({ lineCount, map } = (0, count_lines_1.countLinesAndTerminateMap)(code, map)); + ({ lineCount, sourceMap } = (0, packedMap_1.countLinesAndTerminateSourceMap)(code, sourceMap)); // Clean the AST for tree shaking by stripping non-serializable values (Symbols, functions, etc.) // that React Compiler and other Babel plugins may add. const output = [ @@ -417,7 +414,11 @@ async function transformJS(file, { config, options }) { data: { code, lineCount, - map, + // Reconcile re-runs Babel codegen and replaces `data.map` via + // `installPackedMap` before any reader sees it, so the sourceMap emitted + // here would be discarded — short-circuit to an empty Array to skip + // the work and avoid GC pressure on optimize builds. + map: possibleReconcile ? [] : sourceMap, functionMap: file.functionMap, hasCjsExports: file.hasCjsExports, reactServerReference: file.reactServerReference, @@ -518,10 +519,10 @@ async function transformJSON(file, { options, config }) { let code = config.unstable_disableModuleWrapping === true ? JsFileWrapping.jsonToCommonJS(file.code) : JsFileWrapping.wrapJson(file.code, config.globalPrefix); - let map = []; + let sourceMap = (0, packedMap_1.emptySourceMap)(); const minify = (0, resolveOptions_1.shouldMinify)(options); if (minify) { - ({ map, code } = await (0, exports.minifyCode)(config, file.filename, code, file.code, map)); + ({ sourceMap, code } = await (0, exports.minifyCode)(config, file.filename, code, file.code, [])); } let jsType; if (file.type === 'asset') { @@ -534,10 +535,10 @@ async function transformJSON(file, { options, config }) { jsType = 'js/module'; } let lineCount; - ({ lineCount, map } = (0, count_lines_1.countLinesAndTerminateMap)(code, map)); + ({ lineCount, sourceMap } = (0, packedMap_1.countLinesAndTerminateSourceMap)(code, sourceMap)); const output = [ { - data: { code, lineCount, map, functionMap: null }, + data: { code, lineCount, map: sourceMap, functionMap: null }, type: jsType, }, ]; @@ -612,6 +613,9 @@ async function transform(config, projectRoot, filename, data, options) { }; return transformJSWithBabel(file, context); } +// NOTE: Increment if cache becomes incompatible (original value would be '') +// 1. Added new packed source map format +const CACHE_VERSION = '1'; function getCacheKey(config, opts) { const { // The `expo_customTransformerPath` from `./supervising-transform-worker` should not participate be part of the cache key @@ -643,7 +647,12 @@ function getCacheKey(config, opts) { extendsBabelConfigPath: config.extendsBabelConfigPath, }) : ''; - return [filesKey, (0, metro_cache_1.stableHash)(remainingConfig).toString('hex'), babelTransformerCacheKey].join('$'); + const keyParts = []; + if (CACHE_VERSION) { + keyParts.push(CACHE_VERSION); + } + keyParts.push(filesKey, (0, metro_cache_1.stableHash)(remainingConfig).toString('hex'), babelTransformerCacheKey); + return keyParts.join('$'); } /** * Produces a Babel template that transforms an "import(...)" call into a diff --git a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js.map b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js.map index 35b6601c3edcff..dfa7feff8fa589 100644 --- a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js.map +++ b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js.map @@ -1 +1 @@ -{"version":3,"file":"metro-transform-worker.js","sourceRoot":"","sources":["../../src/transform-worker/metro-transform-worker.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"metro-transform-worker.js","sourceRoot":"","sources":["../../src/transform-worker/metro-transform-worker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2MA,gDAiGC;AAidD,8BA0DC;AAMD,kCAiDC;AAoCD,sEAcC;AAh6BD;;;;;;;;;GASG;AACH,sCAAgF;AAEhF,iEAAwC;AACxC,oGAAsF;AACtF,mHAA2F;AAC3F,sGAGoE;AAEpE,yDAAqD;AACrD,iEAA8E;AAC9E,mEAAsE;AAEtE,2FAA6E;AAM7E,8DAAiC;AAEjC,sEAAwD;AASxD,+EAEgC;AAChC,qDAAgD;AAEhD,uDAMiC;AACjC,uDAA8F;AAC9F,4DAA0F;AAC1F,qDAAmE;AA4CnE,MAAa,uBAAwB,SAAQ,KAAK;IAChD,UAAU,CAAkC;IAC5C,QAAQ,CAAS;IAEjB,YAAY,UAA2C,EAAE,QAAgB;QACvE,KAAK,CAAC,GAAG,QAAQ,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AATD,0DASC;AAED,SAAS,UAAU,CAAI,KAAQ;IAC7B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAmB,CAAuB,EAAE,OAAgB;IAC7E,IAAA,qBAAM,EAAC,CAAC,IAAI,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3B,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,sBAAsB,CAC7B,UAAmC,EACnC,QAAgB;IAEhB,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,gBAAgB;YACnB,OAAO,8BAA8B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC/E;YACE,MAAM,IAAI,KAAK,CAAC,8CAA8C,UAAU,IAAI,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAEM,MAAM,UAAU,GAAG,KAAK,EAC7B,MAAoE,EACpE,QAAgB,EAChB,IAAY,EACZ,MAAc,EACd,WAA6C,EAC7C,WAAqB,EAAE,EAItB,EAAE;IACH,MAAM,SAAS,GAAG,IAAA,mCAAuB,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IAE7E,MAAM,MAAM,GAAG,IAAA,yBAAW,EAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAEhD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC;YAC5B,IAAI;YACJ,GAAG,EAAE,SAAS;YACd,QAAQ;YACR,QAAQ;YACR,MAAM,EAAE,MAAM,CAAC,cAAc;SAC9B,CAAC,CAAC;QAEH,OAAO;YACL,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,SAAS,EAAE,QAAQ,CAAC,GAAG;gBACrB,CAAC,CAAC,IAAA,+BAAmB,EAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;gBACrF,CAAC,CAAC,IAAA,0BAAc,GAAE;SACrB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,CAAC,OAAO,YAAY,QAAQ,OAAO,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AArCW,QAAA,UAAU,cAqCrB;AAEF,SAAS,uBAAuB,CAAC,GAAW;IAC1C,6EAA6E;IAC7E,iBAAiB;IACjB,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;IAEnC,IACE,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,QAAQ;QACnC,UAAU,IAAI,IAAI;QAClB,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,YAAY,CAAC,KAAK,CAAC,CAAC,EAClE,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,YAAC,CAAC,SAAS,CAAC,YAAC,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,OAA2B,EAAE,GAAW;IAC9D,IACE,OAAO,CAAC,yBAAyB,KAAK,IAAI;QAC1C,OAAO,CAAC,sBAAsB,EAAE,YAAY,KAAK,OAAO,EACxD,CAAC;QACD,kFAAkF;QAClF,oHAAoH;QACpH,oDAAoD;QACpD,OAAO;YACL,SAAS,EAAE,gBAAgB;YAC3B,aAAa,EAAE,oBAAoB;SACpC,CAAC;IACJ,CAAC;IACD,iJAAiJ;IACjJ,OAAO,IAAA,6BAAmB,EAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,SAAgB,kBAAkB,CAChC,GAAU,EACV,EACE,QAAQ,EACR,OAAO,EACP,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,sBAAsB,GAevB;IAED,wEAAwE;IACxE,0DAA0D;IAC1D,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,eAAe,GAAG;QACtB,GAAG,OAAO;QACV,eAAe,EAAE,CAAC,aAAa,EAAE,SAAS,CAAC;QAC3C,aAAa;QACb,SAAS;KACV,CAAC;IAEF,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI;QACV,6CAA6C;QAC7C,6CAAqB,CACtB,CAAC;IACJ,CAAC;IAED,wGAAwG;IACxG,sGAAsG;IACtG,IAAI,OAAO,CAAC,yBAAyB,KAAK,IAAI,EAAE,CAAC;QAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,sBAAsB,EAAE,YAAY,KAAK,OAAO,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC;YACX,YAAY,CAAC,CAAC,CAAC,kDAA8B,CAAC,CAAC,CAAC,sCAAkB;YAClE,EAAE,GAAG,eAAe,EAAE,sBAAsB,EAAE;SAC/C,CAAC,CAAC;IACL,CAAC;IAED,0GAA0G;IAC1G,wGAAwG;IACxG,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC;YACX,qBAAqB,CAAC,oBAAoB;YAC1C;gBACE,GAAG,eAAe;gBAClB,eAAe,EAAE,OAAO,CAAC,kBAAkB;aAC5C;SACF,CAAC,CAAC;IACL,CAAC;IAED,iGAAiG;IACjG,uEAAuE;IAEvE,8GAA8G;IAC9G,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,UAAU,CACvB,IAAA,2BAAoB,EAAC,GAAG,EAAE,EAAE,EAAE;YAC5B,GAAG,EAAE,IAAI;YACT,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,KAAK;YACX,UAAU,EAAE,KAAK;YACjB,QAAQ,EAAE,IAAI;YACd,QAAQ;YACR,OAAO;YACP,UAAU,EAAE,KAAK;YAEjB,+GAA+G;YAC/G,0DAA0D;YAC1D,uBAAuB;YACvB,2FAA2F;YAC3F,+EAA+E;YAC/E,8JAA8J;YAC9J,+FAA+F;YAC/F,uFAAuF;YACvF,aAAa,EAAE,KAAK;SACrB,CAAC,CACH,CAAC;QACF,OAAO;YACL,GAAG,EAAE,MAAM,CAAC,GAAY;YACxB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC;AAED,SAAS,sBAAsB,CAAC,GAAyB,EAAE,EAAE,QAAQ,EAAwB;IAC3F,6GAA6G;IAC7G,4EAA4E;IAC5E,8GAA8G;IAC9G,mDAAmD;IACnD,MAAM,uBAAuB,GAAe;QAC1C,OAAO,EAAE;YACP,OAAO,EAAE;gBACP,KAAK,CAAC,IAAI;oBACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBACrB,CAAC;aACF;SACF;KACF,CAAC;IAEF,4EAA4E;IAC5E,wEAAwE;IACxE,cAAc;IACd,MAAM,MAAM,GAAG,IAAA,2BAAoB,EAAC,GAAG,EAAE,EAAE,EAAE;QAC3C,GAAG,EAAE,IAAI;QACT,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,KAAK;QACX,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,IAAI;QACd,QAAQ;QACR,OAAO,EAAE,CAAC,uBAAuB,EAAE,qBAAqB,CAAC,qBAAqB,CAAC;QAC/E,UAAU,EAAE,KAAK;QAEjB,wHAAwH;QACxH,sCAAsC;QACtC,+FAA+F;QAC/F,aAAa,EAAE,KAAK;KACrB,CAAC,EAAE,GAAG,CAAC;IAER,OAAO,UAAU,CAAC,MAAM,CAAgB,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,IAAY,EACZ,EAAE,MAAM,EAAE,OAAO,EAAyB;IAE1C,MAAM,SAAS,GAAG,OAAO,CAAC,sBAAsB,EAAE,WAAW,CAAC;IAC9D,MAAM,WAAW,GAAG,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,cAAc,CAAC;IAEzE,MAAM,QAAQ;IACZ,6DAA6D;IAC7D,IAAI,CAAC,IAAI,KAAK,WAAW;QACzB,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,QAAQ,CAAC,KAAK,MAAM;QAC3D,sCAAsC;QACtC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAE/C,MAAM,8BAA8B,GAAG,QAAQ,IAAI,MAAM,CAAC,8BAA8B,CAAC;IAEzF,IAAI,QAAQ,IAAI,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC;QACnD,uHAAuH;QACvH,MAAM,IAAI,KAAK,CACb,oFAAoF,CACrF,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,4DAA4D;IAC5D,IAAI,GAAG,GACL,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC,IAAA,YAAK,EAAC,IAAI,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IAE1E,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAElE,6EAA6E;IAC7E,iBAAiB;IACjB,uBAAuB,CAAC,GAAG,CAAC,CAAC;IAE7B,MAAM,sBAAsB,GAAG,MAAM,CAAC,sBAAsB,CAAC;IAE7D,4FAA4F;IAC5F,oFAAoF;IACpF,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAChD,GAAG,GAAG,sBAAsB,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,yFAAyF;IACzF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,GAAG,GAAG,kBAAkB,CAAC,GAAG,EAAE;YAC5B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,sBAAsB,EAAE,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC;YAC5D,OAAO;YACP,aAAa;YACb,SAAS;SACV,CAAC,CAAC,GAAG,CAAC;IACT,CAAC;IAED,IAAI,iBAAiB,GAAW,EAAE,CAAC;IACnC,IAAI,YAAmC,CAAC;IACxC,IAAI,UAAkB,CAAC;IAEvB,0EAA0E;IAC1E,8EAA8E;IAC9E,0EAA0E;IAC1E,0BAA0B;IAC1B,IAAI,0BAAkE,CAAC;IACvE,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAC9B,YAAY,GAAG,EAAE,CAAC;QAClB,UAAU,GAAG,cAAc,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,MAAM,qBAAqB,GAAG,IAAI,CAAC,8BAA8B,IAAI,IAAI,CAAC;YAE1E,mHAAmH;YACnH,0BAA0B,GAAG;gBAC3B,sBAAsB,EAAE,MAAM,CAAC,sBAAsB;gBACrD,qBAAqB,EACnB,MAAM,CAAC,8BAA8B,KAAK,IAAI;oBAC5C,CAAC,CAAC,6BAA6B;oBAC/B,CAAC,CAAC,SAAS;gBACf,eAAe,EAAE,WAAW;oBAC1B,CAAC,CAAC,mEAAmE;wBACnE,8CAA8C;wBAC9C,MAAM;oBACR,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,qBAAqB,EAAE,IAAI,CAAC,QAAQ,CAAC;gBACvE,eAAe,EAAE,CAAC,aAAa,EAAE,SAAS,CAAC;gBAC3C,gBAAgB,EAAE,OAAO,CAAC,GAAG;gBAC7B,yBAAyB,EAAE,MAAM,CAAC,yBAAyB;gBAC3D,iBAAiB,EAAE,MAAM,CAAC,kCAAkC;gBAC5D,4BAA4B,EAAE,MAAM,CAAC,4BAA4B;gBACjE,4BAA4B,EAAE,IAAI;gBAClC,wEAAwE;gBACxE,qDAAqD;gBACrD,WAAW,EAAE,QAAQ,KAAK,IAAI;aAC/B,CAAC;YAEF,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,iBAAiB,EAAE,GAAG,IAAA,8BAAmB,EAAC,GAAG,EAAE;gBACnE,GAAG,0BAA0B;gBAC7B,sEAAsE;gBACtE,qBAAqB,EACnB,8BAA8B,KAAK,IAAI,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,SAAS;gBACrF,4BAA4B,EAC1B,qBAAqB,IAAI,IAAI;oBAC3B,CAAC,CAAC,CAAC,GAAqB,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAA,gCAAQ,EAAC,GAAG,CAAC,CAAC;oBACrE,CAAC,CAAC,IAAI;aACX,CAAC,CAAC,CAAC;YAEJ,kGAAkG;YAClG,0BAA0B,GAAG;gBAC3B,GAAG,0BAA0B;gBAC7B,iBAAiB;aAClB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,8CAA+B,EAAE,CAAC;gBACrD,MAAM,IAAI,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,IAAI,8BAA8B,KAAK,IAAI,EAAE,CAAC;YAC5C,UAAU,GAAG,GAAG,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,wEAAwE;YACxE,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC,UAAU,CAC9C,GAAG,EACH,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,MAAM,CAAC,YAAY;YACnB,qEAAqE;YACrE,mEAAmE;YACnE,UAAU;YACV,sBAAsB,KAAK,KAAK,CACjC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,IAAA,6BAAY,EAAC,OAAO,CAAC,CAAC;IAErC,MAAM,4BAA4B,GAChC,MAAM;QACN,IAAI,CAAC,aAAa,IAAI,MAAM,CAAC,qBAAqB;QAClD,CAAC,MAAM,CAAC,sCAAsC,CAAC;IAEjD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,MAAM,CAAC,kCAAkC,IAAI,IAAI,EAAE,CAAC;QACtD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC;IAC3D,CAAC;IAED,IACE,4BAA4B;QAC5B,2HAA2H;QAC3H,CAAC,8BAA8B,EAC/B,CAAC;QACD,iHAAiH;QACjH,QAAQ,CAAC,IAAI,CACX,GAAG,qBAAqB,CAAC,sBAAsB,CAAC,UAAU,EAAE;YAC1D,aAAa,EAAE,QAAQ;SACxB,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,mBAAQ,EACrB,UAAU,EACV;QACE,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,MAAM,CAAC,sBAAsB;QACtC,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,WAAW,EAAE,KAAK;QAClB,cAAc,EAAE,IAAI,CAAC,QAAQ;QAC7B,UAAU,EAAE,IAAI;KACjB,EACD,IAAI,CAAC,IAAI,CACV,CAAC;IAEF,4DAA4D;IAC5D,qEAAqE;IACrE,MAAM,WAAW,GACd,MAA2D,EAAE,WAAW,IAAI,EAAE,CAAC;IAClF,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACvB,IAAI,SAAgC,CAAC;IAErC,sFAAsF;IACtF,IAAI,MAAM,EAAE,CAAC;QACX,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,kBAAU,EACrC,MAAM,EACN,IAAI,CAAC,QAAQ,EACb,MAAM,CAAC,IAAI,EACX,IAAI,CAAC,IAAI,EACT,WAAW,EACX,QAAQ,CACT,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,IAAA,2BAAe,EAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,iBAAiB,GACrB,QAAQ,IAAI,0BAA0B;QACpC,CAAC,CAAC;YACE,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,aAAa;YACb,SAAS;YACT,sBAAsB,EAAE,4BAA4B;YACpD,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,sBAAsB,EAAE,MAAM,CAAC,sBAAsB;YACrD,0BAA0B;YAC1B,MAAM,EAAE,MAAM;gBACZ,CAAC,CAAC;oBACE,YAAY,EAAE,MAAM,CAAC,YAAY;oBACjC,cAAc,EAAE,MAAM,CAAC,cAAc;iBACtC;gBACH,CAAC,CAAC,SAAS;YACb,kCAAkC,EAAE,MAAM,CAAC,kCAAkC;YAC7E,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;YACnD,sCAAsC,EAAE,MAAM,CAAC,sCAAsC;YACrF,sBAAsB;SACvB;QACH,CAAC,CAAC,SAAS,CAAC;IAEhB,IAAI,SAAS,CAAC;IACd,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,IAAA,2CAA+B,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAE9E,iGAAiG;IACjG,uDAAuD;IACvD,MAAM,MAAM,GAAmB;QAC7B;YACE,IAAI,EAAE;gBACJ,IAAI;gBACJ,SAAS;gBACT,8DAA8D;gBAC9D,yEAAyE;gBACzE,oEAAoE;gBACpE,qDAAqD;gBACrD,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;gBACvC,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;gBAC/C,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;gBAC/C,yBAAyB,EAAE,IAAI,CAAC,yBAAyB;gBACzD,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,GAAG,CAAC,iBAAiB;oBACnB,CAAC,CAAC;wBACE,GAAG,EAAE,UAAU;wBACf,2GAA2G;wBAC3G,iBAAiB;wBACjB,SAAS,EAAE,iBAAiB;qBAC7B;oBACH,CAAC,CAAC,EAAE,CAAC;aACR;YACD,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB;KACF,CAAC;IAEF,IAAI,iBAAiB,EAAE,CAAC;QACtB,yEAAyE;QACzE,MAAM,iBAAiB,GAAG,OAAO,CAAC,sBAAsB,EAAE,aAG7C,CAAC;QACd,IAAI,iBAAiB,KAAK,IAAI,IAAI,iBAAiB,KAAK,MAAM,EAAE,CAAC;YAC/D,IAAI,CAAC;gBACH,OAAO;oBACL,YAAY;oBACZ,qFAAqF;oBACrF,iFAAiF;oBACjF,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;iBAC3C,CAAC;YACJ,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,YAAY;QACZ,MAAM;KACP,CAAC;AACJ,CAAC;AAED,gCAAgC;AAChC,KAAK,UAAU,cAAc,CAC3B,IAAe,EACf,OAA8B;IAE9B,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAE3D,6CAA6C;IAC7C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAC7C,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,EACpC,iBAAiB,EACjB,YAAY,CACb,CAAC;IAEF,MAAM,MAAM,GAAW;QACrB,GAAG,IAAI;QACP,IAAI,EAAE,iBAAiB;QACvB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,WAAW,EAAE,IAAI;QACjB,aAAa,EAAE,IAAI;QACnB,oBAAoB,EAAE,MAAM,CAAC,oBAAoB;KAClD,CAAC;IAEF,OAAO,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,oBAAoB,CACjC,IAAY,EACZ,OAA8B;IAE9B,MAAM,EAAE,oBAAoB,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAChD,MAAM,WAAW,GAAqB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEpE,sGAAsG;IACtG,4GAA4G;IAC5G,yCAAyC;IACzC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC;QAC/C,yEAAyE;QACzE,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,sBAAsB,EAAE,aAGrD,CAAC;QACd,IAAI,iBAAiB,KAAK,IAAI,IAAI,iBAAiB,KAAK,MAAM,EAAE,CAAC;YAC/D,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,yBAAyB,GAAG,IAAI,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,8HAA8H;IAC9H,MAAM,eAAe,GAAG,MAAM,WAAW,CAAC,SAAS,CACjD,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE;QACnC,8DAA8D;QAC9D,yCAAsB;QACtB,gFAAgF;QAChF,6CAAqB;KACtB,CAAC,CACH,CAAC;IAEF,MAAM,MAAM,GAAW;QACrB,GAAG,IAAI;QACP,GAAG,EAAE,eAAe,CAAC,GAAG;QACxB,WAAW,EACT,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW;YAC5C,4DAA4D;YAC5D,eAAe,CAAC,WAAW;YAC3B,IAAI;QACN,8BAA8B,EAC5B,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,8BAA8B;QAClE,aAAa,EAAE,eAAe,CAAC,QAAQ,EAAE,aAAa;QACtD,oBAAoB,EAAE,eAAe,CAAC,QAAQ,EAAE,oBAAoB;QACpE,oBAAoB,EAAE,eAAe,CAAC,QAAQ,EAAE,oBAAoB;QACpE,yBAAyB,EAAE,eAAe,CAAC,QAAQ,EAAE,yBAAyB;QAC9E,eAAe,EAAE,eAAe,CAAC,QAAQ,EAAE,eAAe;QAC1D,sBAAsB,EAAE,eAAe,CAAC,QAAQ,EAAE,sBAAsB;KACzE,CAAC;IAEF,OAAO,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,IAAc,EACd,EAAE,OAAO,EAAE,MAAM,EAAyB;IAE1C,IAAI,IAAI,GACN,MAAM,CAAC,8BAA8B,KAAK,IAAI;QAC5C,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1C,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC9D,IAAI,SAAS,GAA0B,IAAA,0BAAc,GAAE,CAAC;IAExD,MAAM,MAAM,GAAG,IAAA,6BAAY,EAAC,OAAO,CAAC,CAAC;IAErC,IAAI,MAAM,EAAE,CAAC;QACX,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,kBAAU,EAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,MAAkB,CAAC;IAEvB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1B,MAAM,GAAG,iBAAiB,CAAC;IAC7B,CAAC;SAAM,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,GAAG,WAAW,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,WAAW,CAAC;IACvB,CAAC;IAED,IAAI,SAAS,CAAC;IACd,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,IAAA,2CAA+B,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAE9E,MAAM,MAAM,GAAmB;QAC7B;YACE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE;YAC5D,IAAI,EAAE,MAAM;SACb;KACF,CAAC;IAEF,OAAO;QACL,YAAY,EAAE,EAAE;QAChB,MAAM;KACP,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAAwC,EACxC,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAyB,EACvD,UAAwB,EAAE;IAE1B,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,GAAG,uBAAuB,EAAE,GAAG,OAAO,CAAC;IAClE,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,OAAO,EAAE;YACP,GAAG,uBAAuB;YAC1B,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;YAC/C,kFAAkF;YAClF,sBAAsB,EACpB,MAAM,CAAC,mBAAmB,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,SAAS;YAClF,0FAA0F;YAC1F,mGAAmG;YACnG,kBAAkB,EAAE,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB;YACjF,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,WAAW;YACX,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,QAAQ,EAAE,uBAAuB,CAAC,QAAQ,IAAI,IAAI;SACnD;QACD,OAAO;QACP,GAAG,EAAE,IAAI,CAAC,IAAI;KACf,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,SAAS,CAC7B,MAA2B,EAC3B,WAAmB,EACnB,QAAgB,EAChB,IAAY,EACZ,OAA2B;IAE3B,MAAM,OAAO,GAA0B;QACrC,MAAM;QACN,WAAW;QACX,OAAO;KACR,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEzC,MAAM,EAAE,kCAAkC,EAAE,GAAG,MAAM,CAAC;IACtD,IAAI,kCAAkC,IAAI,IAAI,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;QACxE,IAAI,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;YAClB,MAAM,IAAI,WAAW,CACnB,4CAA4C;gBAC1C,kCAAkC;gBAClC,wBAAwB;gBACxB,QAAQ,CACX,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAa;YACzB,QAAQ;YACR,aAAa,EAAE,IAAI,CAAC,MAAM;YAC1B,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC;QAEF,OAAO,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAc;YACtB,QAAQ;YACR,aAAa,EAAE,IAAI,CAAC,MAAM;YAC1B,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC;QAEF,OAAO,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,IAAI,GAAW;QACnB,QAAQ;QACR,aAAa,EAAE,IAAI,CAAC,MAAM;QAC1B,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW;QAC3D,WAAW,EAAE,IAAI;KAClB,CAAC;IAEF,OAAO,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED,6EAA6E;AAC7E,wCAAwC;AACxC,MAAM,aAAa,GAAG,GAAG,CAAC;AAE1B,SAAgB,WAAW,CACzB,MAA2B,EAC3B,IAAwC;IAExC,MAAM;IACJ,yHAAyH;IACzH,0BAA0B,EAAE,sBAAsB,EAClD,oBAAoB,EACpB,YAAY,EACZ,GAAG,eAAe,EACnB,GAAG,MAAM,CAAC;IAEX,gHAAgH;IAChH,MAAM,QAAQ,GAAG,IAAA,6BAAgB,EAAC;QAChC,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC;QACrC,IAAA,6BAAe,EAAC,YAAY,CAAC;QAC7B,OAAO,CAAC,OAAO,CAAC,sDAAsD,CAAC;QACvE,OAAO,CAAC,OAAO,CAAC,wBAAwB,CAAC;QACzC,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC;QACtC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC;QACnC,OAAO,CAAC,OAAO,CAAC,0DAA0D,CAAC;QAC3E,OAAO,CAAC,OAAO,CAAC,qDAAqD,CAAC;QACtE,GAAG,qBAAqB,CAAC,+BAA+B,EAAE;KAC3D,CAAC,CAAC;IAEH,IAAI,gBAAgB,GAAqB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEvE,uFAAuF;IACvF,yFAAyF;IACzF,mDAAmD;IACnD,IAAI,MAAM,CAAC,sBAAsB,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC;QACnE,gBAAgB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,wBAAwB,GAAG,gBAAgB,CAAC,WAAW;QAC3D,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC;YAC3B,WAAW,EAAE,IAAI,EAAE,WAAW;YAC9B,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;YAC/C,kHAAkH;YAClH,sBAAsB,EAAE,MAAM,CAAC,sBAAsB;SACtD,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,aAAa,EAAE,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC/B,CAAC;IACD,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAA,wBAAU,EAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,wBAAwB,CAAC,CAAC;IAC/F,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,4BAA4B,GAAG,eAAQ,CAAC,UAAU,CAAC,oCAAoC,CAAC,CAAC;AAI/F,MAAM,6BAA6B,GAA0B;IAC3D,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE,GAAE,CAAC;IAClC,4BAA4B,EAAE,GAAG,EAAE,GAAE,CAAC;IACtC,mBAAmB,EAAE,CAAC,IAAc,EAAE,UAA8B,EAAE,KAAY,EAAE,EAAE;QACpF,6EAA6E;QAC7E,+FAA+F;QAC/F,IAAI,SAAS,GAAmC,IAAI,CAAC;QACrD,OAAO,SAAS,CAAC,UAAU,EAAE,CAAC;YAC5B,SAAS,GAAG,SAAS,CAAC,UAAU,CAAC;QACnC,CAAC;QAED,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,WAAW,CACd,4BAA4B,CAAC;YAC3B,yBAAyB,EAAE,UAAU,CAAC,KAAK,CAAC,mCAAmC,CAAC;SACjF,CAAC,CACH,CAAC;QACF,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC5B,CAAC;IACD,iBAAiB,EAAE,GAAG,EAAE,GAAE,CAAC;IAC3B,8BAA8B,EAAE,GAAG,EAAE,GAAE,CAAC;CACzC,CAAC;AAEF,SAAgB,6BAA6B,CAAC,GAAW,EAAE,OAAmC;IAC5F,MAAM,0BAA0B,GAAG;QACjC,GAAG,OAAO;QAEV,wEAAwE;QACxE,qDAAqD;QACrD,WAAW,EAAE,IAAI;KAClB,CAAC;IAEF,OAAO,IAAA,8BAAmB,EAAC,GAAG,EAAE;QAC9B,GAAG,0BAA0B;QAC7B,sEAAsE;QACtE,qBAAqB,EAAE,6BAA6B;KACrD,CAAC,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/packages/@expo/metro-config/build/transform-worker/transform-worker.d.ts b/packages/@expo/metro-config/build/transform-worker/transform-worker.d.ts index 9190493972c6b1..458c479142f2ab 100644 --- a/packages/@expo/metro-config/build/transform-worker/transform-worker.d.ts +++ b/packages/@expo/metro-config/build/transform-worker/transform-worker.d.ts @@ -6,9 +6,10 @@ * LICENSE file in the root directory of this source tree. */ import type { TransformResultDependency } from '@expo/metro/metro/DeltaBundler'; -import type { JsTransformerConfig, JsTransformOptions, JsOutput } from '@expo/metro/metro-transform-worker'; +import type { JsTransformerConfig, JsTransformOptions } from '@expo/metro/metro-transform-worker'; +import type { ExpoJsOutput } from '../serializer/jsOutput'; export interface TransformResponse { readonly dependencies: readonly TransformResultDependency[]; - readonly output: readonly JsOutput[]; + readonly output: readonly ExpoJsOutput[]; } export declare function transform(config: JsTransformerConfig, projectRoot: string, filename: string, data: Buffer, options: JsTransformOptions): Promise; diff --git a/packages/@expo/metro-config/build/transform-worker/transform-worker.js.map b/packages/@expo/metro-config/build/transform-worker/transform-worker.js.map index 1eeacc41ba8350..07f4706fd2ae68 100644 --- a/packages/@expo/metro-config/build/transform-worker/transform-worker.js.map +++ b/packages/@expo/metro-config/build/transform-worker/transform-worker.js.map @@ -1 +1 @@ -{"version":3,"file":"transform-worker.js","sourceRoot":"","sources":["../../src/transform-worker/transform-worker.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDH,8BAuJC;AApMD,kFAA0D;AAM1D,yCAA8C;AAE9C,iDAAwD;AACxD,+BAA2C;AAC3C,+CAKuB;AACvB,+DAAqD;AACrD,iEAAmD;AACnD,uCAAmD;AACnD,iCAAgD;AAEhD,gDAAgD;AAOhD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,oCAAoC,CAAuB,CAAC;AAE3F,SAAS,cAAc,CAAC,KAAU;IAChC,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;AACrF,CAAC;AAEM,KAAK,UAAU,SAAS,CAC7B,MAA2B,EAC3B,WAAmB,EACnB,QAAgB,EAChB,IAAY,EACZ,OAA2B;IAE3B,MAAM,aAAa,GAAG,IAAA,sBAAW,EAAC,QAAQ,CAAC,CAAC;IAC5C,IACE,OAAO,OAAO,CAAC,sBAAsB,EAAE,GAAG,KAAK,QAAQ;QACvD,aAAa,CAAC,KAAK,CAAC,sBAAsB,CAAC,EAC3C,CAAC;QACD,qGAAqG;QACrG,yCAAyC;QACzC,MAAM,yBAAyB,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC;QAChG,MAAM,GAAG,GAAG,6DAA6D,yBAAyB,aAAa,CAAC;QAChH,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,aAAa,CAAC,KAAK,CAAC,8BAA8B,CAAC,EAAE,CAAC;QACxD,MAAM,WAAW,GAAG,OAAO,CAAC,sBAAsB,EAAE,WAAW,CAAC;QAChE,MAAM,QAAQ,GAAG,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,cAAc,CAAC;QAE1E,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,CAAC,sBAAsB,EAAE,gBAAgB,CAAC,CAAC;YAC1F,gFAAgF;YAChF,IAAI,gBAAgB,EAAE,CAAC;gBACrB,KAAK,CAAC,2BAA2B,EAAE,gBAAgB,CAAC,CAAC;gBAErD,gBAAgB;gBAChB,MAAM,GAAG,GACP,sBAAsB;oBACtB,gBAAgB;yBACb,GAAG,CAAC,CAAC,QAAgB,EAAE,EAAE;wBACxB,MAAM,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;wBACpD,OAAO,6BAA6B,kBAAkB,aAAa,QAAQ,oBAAoB,kBAAkB,IAAI,CAAC;oBACxH,CAAC,CAAC;yBACD,IAAI,CAAC,IAAI,CAAC;oBACb,MAAM,CAAC;gBAET,OAAO,MAAM,CAAC,SAAS,CACrB,MAAM,EACN,WAAW,EACX,QAAQ,EACR,MAAM,CAAC,IAAI,CAAC,+BAA+B,GAAG,GAAG,CAAC,EAClD,OAAO,CACR,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjE,OAAO,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACpE,CAAC;IAED,yDAAyD;IACzD,MAAM,WAAW,GAAG,OAAO,CAAC,sBAAsB,EAAE,WAAW,CAAC;IAChE,MAAM,mBAAmB,GAAG,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,cAAc,CAAC;IACrF,IACE,mBAAmB;QACnB,wCAAwC;QACxC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,mBAAmB,OAAO,CAAC,QAAQ,yBAAyB,CAAC,CAAC;YACvF,oBAAoB;YACpB,QAAQ,CAAC,KAAK,CAAC,8CAA8C,CAAC;YAC9D,2BAA2B;YAC3B,QAAQ,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,EAC3C,CAAC;QACD,2GAA2G;QAC3G,OAAO,MAAM,CAAC,SAAS,CACrB,MAAM,EACN,WAAW,EACX,QAAQ,EACR,CAAC,OAAO,CAAC,MAAM;YACb,CAAC,CAAC,MAAM,CAAC,IAAI;YACT,sEAAsE;YACtE,kBAAkB;YAClB,6EAA6E,CAC9E;YACH,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EACnB,OAAO,CACR,CAAC;IACJ,CAAC;IAED,IACE,mBAAmB;QACnB,CAAC,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC;QACnC,QAAQ,CAAC,KAAK,CAAC,8CAA8C,CAAC,EAC9D,CAAC;QACD,iEAAiE;QACjE,oFAAoF;QACpF,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;IACnF,CAAC;IAED,sHAAsH;IACtH,IAAI,QAAQ,CAAC,KAAK,CAAC,6DAA6D,CAAC,EAAE,CAAC;QAClF,MAAM,aAAa,GAAG,IAAA,kCAAY,EAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC,CAAC;QAChF,OAAO,MAAM,CAAC,SAAS,CACrB,MAAM,EACN,WAAW,EACX,QAAQ,EACR,MAAM,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,EAC/D,OAAO,CACR,CAAC;IACJ,CAAC;IAED;IACE,uDAAuD;IACvD,CAAC,mBAAmB;QACpB,QAAQ,CAAC,KAAK,CAAC,+BAA+B,CAAC,EAC/C,CAAC;QACD,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;IACnF,CAAC;IACD;IACE,uFAAuF;IACvF,mBAAmB;QACnB,sCAAsC;QACtC,QAAQ,CAAC,KAAK,CAAC,2BAA2B,CAAC,EAC3C,CAAC;QACD;QACE,sGAAsG;QACtG,OAAO,CAAC,GAAG,EACX,CAAC;YACD,MAAM,YAAY,GAAG,IAAA,oBAAQ,EAAC,IAAA,mBAAO,EAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAC;YAC9D,MAAM,SAAS,GAAG,IAAA,sBAAW,EAAC,YAAY,CAAC,CAAC;YAE5C,6HAA6H;YAC7H,4CAA4C;YAC5C,uHAAuH;YACvH,mFAAmF;YACnF,+HAA+H;YAC/H,mKAAmK;YACnK,MAAM,QAAQ,GAAG,yCAAyC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;;;;cAI3E,CAAC;YACT,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QACzF,CAAC;aAAM,CAAC;YACN,6IAA6I;YAE7I,uGAAuG;YACvG,MAAM,QAAQ,GAAG;;;;;WAKZ,CAAC;YACN,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,wBAAwB,CAAC,OAA2B;IAC3D,OAAO,OAAO,CAAC,sBAAsB,EAAE,WAAW,KAAK,cAAc,CAAC;AACxE,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,MAA2B,EAC3B,WAAmB,EACnB,QAAgB,EAChB,IAAY,EACZ,OAA2B;IAE3B,2DAA2D;IAC3D,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAA,4BAAc,EAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,yCAAyC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvF,OAAO,MAAM,CAAC,SAAS,CACrB,MAAM,EACN,WAAW,EACX,QAAQ;QACR,2BAA2B;QAC3B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EACjB,OAAO,CACR,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEjC,2BAA2B;IAC3B,MAAM,cAAc,GAAG,MAAM,IAAA,gCAAsB,EAAC,WAAW,EAAE;QAC/D,GAAG,EAAE,IAAI;QACT,QAAQ;KACT,CAAC,CAAC;IAEH,IAAI,cAAc,CAAC,UAAU,EAAE,CAAC;QAC9B,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC;IAC5B,CAAC;IAED,uEAAuE;IACvE,MAAM,MAAM,GAAG,IAAA,gBAAS,EAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,GAAG,IAAA,kBAAW,EAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC;IAC3E,CAAC;IAED,gEAAgE;IAChE,sDAAsD;IACtD,IAAI,IAAA,4BAAc,EAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,IAAA,mCAAqB,EAAC;YAC1C,oFAAoF;YACpF,4EAA4E;YAC5E,QAAQ,EAAE,IAAA,sBAAW,EAAC,QAAQ,CAAC;YAC/B,GAAG,EAAE,IAAI;YACT,OAAO,EAAE;gBACP,WAAW,EAAE,wBAAwB,CAAC,OAAO,CAAC;gBAC9C,WAAW;gBACX,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,SAAS,EAAE,KAAK;aACjB;SACF,CAAC,CAAC;QAEH,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,SAAS,CAC5C,MAAM,EACN,WAAW,EACX,QAAQ,EACR,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAC3B,OAAO,CACR,CAAC;QAEF,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,MAAM,GAAmB;YAC7B;gBACE,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE;oBACJ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,IAAI;oBAElC,wDAAwD;oBACxD,GAAG,EAAE;wBACH,IAAI,EAAE,OAAO;wBACb,SAAS,EAAE,IAAA,oBAAU,EAAC,OAAO,CAAC;wBAC9B,GAAG,EAAE,EAAE;wBACP,WAAW,EAAE,IAAI;wBACjB,sFAAsF;wBACtF,qEAAqE;wBACrE,SAAS,EAAE,cAAc,CAAC,UAAU;wBACpC,eAAe,EAAE,OAAO,CAAC,eAAe;qBACzC;iBACF;aACF;SACF,CAAC;QAEF,OAAO;YACL,YAAY,EAAE,eAAe,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;YACvE,MAAM;SACP,CAAC;IACJ,CAAC;IAED,cAAc;IAEd,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,cAAc,CAAkC,CAAC;IAE/E,iFAAiF;IACjF,gDAAgD;IAChD,MAAM,UAAU,GAAG,SAAS,CAAC;QAC3B,QAAQ;QACR,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QACvB,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,KAAK;QAChB,UAAU,EAAE,KAAK;QACjB,WAAW;QACX,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,mBAAmB,EAAE,IAAI;QACzB,OAAO,EAAE,MAAM,IAAA,qCAAsB,EAAC,WAAW,CAAC;QAClD,8BAA8B;QAC9B,mEAAmE;QACnE,QAAQ,EAAE,OAAO,CAAC,gBAAgB;QAClC,8CAA8C;QAC9C,OAAO,EAAE,CAAC,EAAE,UAAU;KACvB,CAAC,CAAC;IAEH,IAAA,8BAAgB,EAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEtD,MAAM,UAAU,GAAG,IAAA,+BAAiB,EAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,UAAU,CAAC,CAAC;IAC7F,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC;IAEhC,wDAAwD;IACxD,MAAM,SAAS,GAA0C;QACvD,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,IAAA,oBAAU,EAAC,OAAO,CAAC;QAC9B,GAAG,EAAE,EAAE;QACP,WAAW,EAAE,IAAI;QACjB,sFAAsF;QACtF,qEAAqE;QACrE,SAAS,EAAE,cAAc,CAAC,UAAU;QACpC,eAAe,EAAE,UAAU,CAAC,eAAe;KAC5C,CAAC;IAEF,MAAM,WAAW,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAEtD,wDAAwD;IACxD,kDAAkD;IAClD,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,SAAS,CAC5C,MAAM,EACN,WAAW,EACX,QAAQ,EACR,OAAO,CAAC,GAAG;QACT,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAA,wBAAkB,EAAC,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EACnB,OAAO,CACR,CAAC;IAEF,iFAAiF;IACjF,qFAAqF;IACrF,oCAAoC;IACpC,MAAM,MAAM,GAAmB;QAC7B;YACE,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE;gBACJ,GAAI,eAAe,CAAC,MAAM,CAAC,CAAC,CAAkB,CAAC,IAAI;gBACnD,GAAG,EAAE,SAAS;aACf;SACF;KACF,CAAC;IAEF,OAAO;QACL,YAAY,EAAE,eAAe,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC;QAC1E,MAAM;KACP,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,OAAO,GAAG;IACf,iDAAiD;IACjD,GAAG,MAAM;IACT,SAAS;CACV,CAAC"} \ No newline at end of file +{"version":3,"file":"transform-worker.js","sourceRoot":"","sources":["../../src/transform-worker/transform-worker.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/metro-config/package.json b/packages/@expo/metro-config/package.json index c8c4de89228a72..f4b30716da90cc 100644 --- a/packages/@expo/metro-config/package.json +++ b/packages/@expo/metro-config/package.json @@ -70,6 +70,9 @@ "@expo/json-file": "workspace:~10.1.0", "@expo/metro": "~56.0.0", "@expo/spawn-async": "^1.7.2", + "@jridgewell/gen-mapping": "^0.3.13", + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", "browserslist": "^4.25.0", "chalk": "^4.1.0", "debug": "^4.3.2", @@ -91,7 +94,7 @@ } }, "devDependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.31", "@types/babel__code-frame": "^7.0.1", "@types/babel__core": "^7.20.5", "@types/babel__generator": "^7.27.0", diff --git a/packages/@expo/metro-config/src/serializer/__tests__/packedMap.test.ts b/packages/@expo/metro-config/src/serializer/__tests__/packedMap.test.ts new file mode 100644 index 00000000000000..b67170861f29bf --- /dev/null +++ b/packages/@expo/metro-config/src/serializer/__tests__/packedMap.test.ts @@ -0,0 +1,692 @@ +import { encode } from '@jridgewell/sourcemap-codec'; + +import { + PackedMap, + countLinesAndTerminateSourceMap, + emptySourceMap, + installPackedMap, + isSerializableSourceMap, + makeProxy, + materializeMap, + packDecodedMappings, + packRawMappings, + patchTransformFileForPackedMaps, + tupleAt, + wrapTransformResultMaps, + type SerializableSourceMap, +} from '../packedMap'; + +const STRIDE = 5; +const SENTINEL = -1; + +// Build a wire object directly so byte-level tests have full control. +function wire(opts: { + segments: ( + | [number, number] + | [number, number, number, number] + | [number, number, number, number, string] + )[]; +}): SerializableSourceMap { + const names = new Map(); + const out: number[] = new Array(opts.segments.length * STRIDE); + let off = 0; + for (const seg of opts.segments) { + out[off] = seg[0]; + out[off + 1] = seg[1]; + if (seg.length === 2) { + out[off + 2] = SENTINEL; + out[off + 3] = SENTINEL; + out[off + 4] = SENTINEL; + } else { + out[off + 2] = seg[2]; + out[off + 3] = seg[3]; + if (seg.length === 5) { + let idx = names.get(seg[4]); + if (idx === undefined) { + idx = names.size; + names.set(seg[4], idx); + } + out[off + 4] = idx; + } else { + out[off + 4] = SENTINEL; + } + } + off += STRIDE; + } + return { + __version: 1, + __count: opts.segments.length, + __names: [...names.keys()], + __packed: out, + }; +} + +describe('isSerializableSourceMap', () => { + it('accepts a valid wire object', () => { + expect(isSerializableSourceMap(wire({ segments: [[1, 0]] }))).toBe(true); + }); + + it('rejects plain values', () => { + expect(isSerializableSourceMap(null)).toBe(false); + expect(isSerializableSourceMap(undefined)).toBe(false); + expect(isSerializableSourceMap('foo')).toBe(false); + expect(isSerializableSourceMap([])).toBe(false); + expect(isSerializableSourceMap([[1, 0]])).toBe(false); + }); + + it('rejects objects with the wrong version', () => { + const w = wire({ segments: [[1, 0]] }); + expect(isSerializableSourceMap({ ...w, __version: 0 })).toBe(false); + expect(isSerializableSourceMap({ ...w, __version: 2 })).toBe(false); + }); + + it('rejects malformed wire objects', () => { + const w = wire({ segments: [[1, 0]] }); + expect(isSerializableSourceMap({ ...w, __packed: 'not-array' })).toBe(false); + expect(isSerializableSourceMap({ ...w, __names: 'not-array' })).toBe(false); + expect(isSerializableSourceMap({ ...w, __count: 'not-number' })).toBe(false); + }); +}); + +describe('PackedMap', () => { + it('round-trips through the wire form', () => { + const original = wire({ + segments: [ + [1, 0], + [1, 5, 3, 2, 'foo'], + [2, 0, 4, 0], + ], + }); + const p = PackedMap.deserialize(original); + expect(p.serialize()).toEqual(original); + }); + + it('exposes the data as an Int32Array', () => { + const original = wire({ segments: [[1, 0, 1, 0]] }); + const p = PackedMap.deserialize(original); + expect(p.buf).toBeInstanceOf(Int32Array); + expect(p.buf).toBe(p.buf); + }); +}); + +describe('tupleAt', () => { + it('returns length-2 for sourceless segments', () => { + const p = PackedMap.deserialize(wire({ segments: [[7, 4]] })); + expect(tupleAt(p, 0)).toEqual([7, 4]); + expect(tupleAt(p, 0)!.length).toBe(2); + }); + + it('returns length-4 for sourced-without-name segments', () => { + const p = PackedMap.deserialize(wire({ segments: [[7, 4, 2, 0]] })); + expect(tupleAt(p, 0)).toEqual([7, 4, 2, 0]); + expect(tupleAt(p, 0)!.length).toBe(4); + }); + + it('returns length-5 for sourced+named segments', () => { + const p = PackedMap.deserialize(wire({ segments: [[7, 4, 2, 0, 'greet']] })); + expect(tupleAt(p, 0)).toEqual([7, 4, 2, 0, 'greet']); + expect(tupleAt(p, 0)!.length).toBe(5); + }); + + it('returns undefined for out-of-bounds indices (does not throw)', () => { + const p = PackedMap.deserialize(wire({ segments: [[1, 0]] })); + expect(tupleAt(p, -1)).toBeUndefined(); + expect(tupleAt(p, 1)).toBeUndefined(); + expect(tupleAt(p, 100)).toBeUndefined(); + }); + + it('throws a clear error for a corrupt name index (out-of-range)', () => { + // The packer would never produce this, but a corrupt cache entry could. + const corrupt: SerializableSourceMap = { + __version: 1, + __count: 1, + __names: ['only-name'], + __packed: [1, 0, 1, 0, 5], + }; + const p = PackedMap.deserialize(corrupt); + expect(() => tupleAt(p, 0)).toThrow(/wire entry is corrupt|name index/); + }); +}); + +describe('makeProxy', () => { + function buildProxy(segments: Parameters[0]['segments']) { + return makeProxy(PackedMap.deserialize(wire({ segments }))); + } + + it('Array.isArray returns true', () => { + expect(Array.isArray(buildProxy([[1, 0]]))).toBe(true); + }); + + it('length matches __count', () => { + expect(buildProxy([]).length).toBe(0); + expect(buildProxy([[1, 0]]).length).toBe(1); + expect( + buildProxy([ + [1, 0], + [2, 0], + [3, 0], + ]).length + ).toBe(3); + }); + + it('numeric indexing returns variable-length tuples', () => { + const p = buildProxy([ + [1, 0], + [1, 5, 3, 2], + [2, 0, 4, 0, 'foo'], + ]); + expect(p[0]).toEqual([1, 0]); + expect(p[1]).toEqual([1, 5, 3, 2]); + expect(p[2]).toEqual([2, 0, 4, 0, 'foo']); + }); + + it("symbolicate's `mapping.length < 4` check sees sourceless mappings correctly", () => { + const p = buildProxy([ + [1, 0], + [2, 0, 4, 0], + ]); + expect(p[0]!.length < 4).toBe(true); + expect(p[1]!.length < 4).toBe(false); + }); + + it('Symbol.iterator yields the same sequence as direct indexing', () => { + const p = buildProxy([ + [1, 0], + [2, 0, 4, 0], + [3, 0, 5, 1, 'x'], + ]); + expect([...p]).toEqual([p[0], p[1], p[2]]); + }); + + it('spread produces a plain Array of variable-length tuples', () => { + const p = buildProxy([ + [1, 0], + [2, 0, 4, 0], + ]); + const arr = [...p]; + expect(Array.isArray(arr)).toBe(true); + expect(arr).toEqual([ + [1, 0], + [2, 0, 4, 0], + ]); + }); + + it('Array.from produces the same plain Array', () => { + const p = buildProxy([ + [1, 0], + [2, 0, 4, 0], + ]); + expect(Array.from(p)).toEqual([ + [1, 0], + [2, 0, 4, 0], + ]); + }); + + it('JSON.stringify returns the wire shape, not materialized tuples', () => { + // A downstream consumer that stringifies and re-feeds through the + // wrapper must see the wire form, so the `__packed` detector fires + // on the round-trip rather than treating the materialized tuples as + // a fresh plain-tuple Array. + const original = wire({ + segments: [ + [1, 0], + [2, 0, 4, 0, 'foo'], + ], + }); + const p = makeProxy(PackedMap.deserialize(original)); + const json = JSON.stringify(p); + const parsed = JSON.parse(json); + expect(isSerializableSourceMap(parsed)).toBe(true); + expect(parsed).toEqual(original); + }); + + it('util.inspect.custom produces a friendly representation', () => { + const p = buildProxy([ + [1, 0], + [2, 0], + [3, 0], + ]); + const fn = (p as unknown as Record string>)[ + Symbol.for('nodejs.util.inspect.custom') + ]; + expect(typeof fn).toBe('function'); + expect(fn.call(p)).toBe('PackedMap(count=3)'); + }); + + it('write attempts throw', () => { + const p = buildProxy([[1, 0]]); + expect(() => { + (p as any)[0] = [9, 9]; + }).toThrow(/read-only/); + expect(() => { + (p as any).length = 0; + }).toThrow(/read-only/); + expect(() => { + (p as any).push([5, 5]); + }).toThrow(/read-only/); + }); + + it('Object.keys returns numeric-string keys with length === count', () => { + const p = buildProxy([ + [1, 0], + [2, 0], + [3, 0], + ]); + expect(Object.keys(p)).toEqual(['0', '1', '2']); + expect(Object.keys(p).length).toBe(p.length); + }); + + describe('edge cases', () => { + it('zero-segment module', () => { + const p = buildProxy([]); + expect(p.length).toBe(0); + expect([...p]).toEqual([]); + expect(Object.keys(p)).toEqual([]); + expect(JSON.parse(JSON.stringify(p)).__count).toBe(0); + }); + + it('single sourceless segment', () => { + const p = buildProxy([[1, 0]]); + expect(p.length).toBe(1); + expect(p[0]).toEqual([1, 0]); + expect([...p]).toEqual([[1, 0]]); + }); + }); +}); + +describe('emptySourceMap', () => { + it('returns a fresh empty wire object each call', () => { + const a = emptySourceMap(); + const b = emptySourceMap(); + expect(a).toEqual({ __version: 1, __count: 0, __names: [], __packed: [] }); + expect(a).not.toBe(b); + expect(a.__packed).not.toBe(b.__packed); + expect(a.__names).not.toBe(b.__names); + }); +}); + +describe('packRawMappings', () => { + it('packs Babel rawMappings directly to wire (sourceless / sourced / named)', () => { + const w = packRawMappings([ + { generated: { line: 1, column: 0 } }, + { generated: { line: 1, column: 5 }, original: { line: 3, column: 2 }, source: 'a.js' }, + { + generated: { line: 2, column: 0 }, + original: { line: 5, column: 0 }, + source: 'a.js', + name: 'foo', + }, + ]); + expect(w.__count).toBe(3); + expect(w.__names).toEqual(['foo']); + const p = PackedMap.deserialize(w); + expect(tupleAt(p, 0)).toEqual([1, 0]); + expect(tupleAt(p, 1)).toEqual([1, 5, 3, 2]); + expect(tupleAt(p, 2)).toEqual([2, 0, 5, 0, 'foo']); + }); + + it('treats a non-string name as no name (length-4 tuple)', () => { + const w = packRawMappings([ + // `name: null` shows up in some Babel paths for sourced-without-name. + { generated: { line: 1, column: 0 }, original: { line: 1, column: 0 }, name: null } as any, + ]); + const p = PackedMap.deserialize(w); + expect(tupleAt(p, 0)).toEqual([1, 0, 1, 0]); + expect(w.__names).toEqual([]); + }); + + it('returns an empty wire for empty input', () => { + const w = packRawMappings([]); + expect(w.__count).toBe(0); + expect(w.__names).toEqual([]); + expect(w.__packed).toEqual([]); + }); + + it('deduplicates names in the output array', () => { + const w = packRawMappings([ + { + generated: { line: 1, column: 0 }, + original: { line: 1, column: 0 }, + source: 'a', + name: 'foo', + }, + { + generated: { line: 2, column: 0 }, + original: { line: 2, column: 0 }, + source: 'a', + name: 'foo', + }, + { + generated: { line: 3, column: 0 }, + original: { line: 3, column: 0 }, + source: 'a', + name: 'bar', + }, + ]); + expect(w.__names).toEqual(['foo', 'bar']); + }); +}); + +describe('packDecodedMappings', () => { + it('decodes a VLQ mappings string straight to wire (1-based line conversion)', () => { + // Mappings authored at 0-based lines: line 0 col 0 -> src 0 / line 0 / col 0 + // line 1 col 0 -> src 0 / line 1 / col 0 / name 0 + const mappings = encode([[[0, 0, 0, 0]], [[0, 0, 1, 0, 0]]]); + const w = packDecodedMappings({ mappings, names: ['greet'] }); + expect(w.__count).toBe(2); + expect(w.__names).toEqual(['greet']); + const p = PackedMap.deserialize(w); + // Output is 1-based for source line/col + expect(tupleAt(p, 0)).toEqual([1, 0, 1, 0]); + expect(tupleAt(p, 1)).toEqual([2, 0, 2, 0, 'greet']); + }); + + it('handles sourceless segments (length-1 in decoded form → length-2 tuple)', () => { + const mappings = encode([[[0]]]); + const w = packDecodedMappings({ mappings, names: [] }); + expect(w.__count).toBe(1); + const p = PackedMap.deserialize(w); + expect(tupleAt(p, 0)).toEqual([1, 0]); + }); + + it('returns an empty wire for an empty mappings string', () => { + const w = packDecodedMappings({ mappings: '', names: [] }); + expect(w.__count).toBe(0); + expect(w.__packed).toEqual([]); + }); + + it('clones the names input rather than aliasing it', () => { + const names = ['foo']; + const w = packDecodedMappings({ mappings: '', names }); + expect(w.__names).not.toBe(names); + expect(w.__names).toEqual(['foo']); + }); +}); + +describe('countLinesAndTerminateSourceMap', () => { + it('returns lineCount=1 for an empty string', () => { + const w = emptySourceMap(); + const r = countLinesAndTerminateSourceMap('', w); + expect(r.lineCount).toBe(1); + expect(r.sourceMap.__count).toBe(1); + // Terminator at (line 1, col 0) + expect(r.sourceMap.__packed.slice(0, 5)).toEqual([1, 0, SENTINEL, SENTINEL, SENTINEL]); + }); + + it('counts \\n / \\r\\n / U+2028 / U+2029', () => { + expect(countLinesAndTerminateSourceMap('a\nb', emptySourceMap()).lineCount).toBe(2); + expect(countLinesAndTerminateSourceMap('a\r\nb\rc', emptySourceMap()).lineCount).toBe(3); + expect(countLinesAndTerminateSourceMap('a
b', emptySourceMap()).lineCount).toBe(2); + expect(countLinesAndTerminateSourceMap('a
b', emptySourceMap()).lineCount).toBe(2); + }); + + it('appends a terminator when the last segment is not at (lastLine, lastCol)', () => { + const w = packRawMappings([ + { generated: { line: 1, column: 0 }, original: { line: 1, column: 0 }, source: 'a' }, + ]); + const r = countLinesAndTerminateSourceMap('abc\nxyz', w); + expect(r.lineCount).toBe(2); + expect(r.sourceMap.__count).toBe(2); + // Terminator: line=2, col=3 (length of "xyz") + const off = STRIDE; // second segment starts at offset 5 + expect(r.sourceMap.__packed.slice(off, off + 5)).toEqual([2, 3, SENTINEL, SENTINEL, SENTINEL]); + }); + + it('does not append a redundant terminator when the last segment already ends at the position', () => { + // Last segment ends at (line 2, col 3); for "abc\nxyz" that's the end-of-file. + const w = packRawMappings([ + { generated: { line: 1, column: 0 }, original: { line: 1, column: 0 }, source: 'a' }, + { generated: { line: 2, column: 3 } }, + ]); + const r = countLinesAndTerminateSourceMap('abc\nxyz', w); + expect(r.lineCount).toBe(2); + expect(r.sourceMap.__count).toBe(2); + expect(r.sourceMap).toBe(w); + }); +}); + +describe('materializeMap', () => { + it('materializes wire to plain tuples', () => { + const w = wire({ + segments: [ + [1, 0], + [2, 0, 4, 0, 'foo'], + ], + }); + expect(materializeMap(w)).toEqual([ + [1, 0], + [2, 0, 4, 0, 'foo'], + ]); + }); + + it('materializes a Proxy to plain tuples (via Symbol.iterator)', () => { + const p = makeProxy(PackedMap.deserialize(wire({ segments: [[1, 0]] }))); + expect(materializeMap(p)).toEqual([[1, 0]]); + }); + + it('passes through plain tuple arrays', () => { + const tuples: any = [ + [1, 0], + [2, 0, 4, 0], + ]; + expect(materializeMap(tuples)).toEqual(tuples); + }); + + it('handles null/undefined gracefully', () => { + expect(materializeMap(null)).toEqual([]); + expect(materializeMap(undefined)).toEqual([]); + }); +}); + +describe('installPackedMap', () => { + it('installs from wire input', () => { + const data: any = {}; + installPackedMap(data, wire({ segments: [[1, 0, 1, 0]] })); + expect(Array.isArray(data.map)).toBe(true); + expect(data.map[0]).toEqual([1, 0, 1, 0]); + expect(data.__packedMap).toBeInstanceOf(PackedMap); + }); + + it('installs from tuple input (the reconcile path)', () => { + const data: any = {}; + installPackedMap(data, [ + [1, 0], + [2, 0, 4, 0, 'foo'], + ]); + expect(data.map.length).toBe(2); + expect(data.map[0]).toEqual([1, 0]); + expect(data.map[1]).toEqual([2, 0, 4, 0, 'foo']); + expect(data.__packedMap).toBeInstanceOf(PackedMap); + }); + + it('attaches __packedMap as non-enumerable', () => { + const data: any = {}; + installPackedMap(data, [[1, 0, 1, 0]]); + expect(Object.keys(data)).toEqual(['map']); + expect({ ...data }.__packedMap).toBeUndefined(); + }); + + it('is idempotent — replaces a previously-installed map cleanly', () => { + const data: any = {}; + installPackedMap(data, [[1, 0, 1, 0]]); + const firstPacked = data.__packedMap; + installPackedMap(data, [ + [1, 0], + [2, 0], + ]); + expect(data.map.length).toBe(2); + expect(data.__packedMap).not.toBe(firstPacked); + }); + + it('exposes `data.map` as a lazy accessor (Proxy not allocated until first read)', () => { + const data: any = {}; + installPackedMap(data, [[1, 0, 1, 0]]); + const descriptor = Object.getOwnPropertyDescriptor(data, 'map')!; + expect(typeof descriptor.get).toBe('function'); + expect('value' in descriptor).toBe(false); + expect(data.__packedMap).toBeInstanceOf(PackedMap); + }); + + it('caches the Proxy on first read so identity is stable', () => { + const data: any = {}; + installPackedMap(data, [[1, 0, 1, 0]]); + const first = data.map; + expect(data.map).toBe(first); + expect({ ...data }.map).toBe(first); + }); +}); + +describe('wrapTransformResultMaps', () => { + it('replaces wire `data.map` with a Proxy + non-enumerable __packedMap', () => { + const result = { + output: [ + { + type: 'js/module', + data: { + code: 'foo', + lineCount: 1, + map: wire({ segments: [[1, 0, 1, 0]] }), + functionMap: null, + }, + }, + ], + }; + const wrapped = wrapTransformResultMaps(result); + const data = wrapped.output[0]!.data as any; + expect(Array.isArray(data.map)).toBe(true); + expect(data.map.length).toBe(1); + expect(data.map[0]).toEqual([1, 0, 1, 0]); + + // __packedMap is attached non-enumerably, so spread/Object.keys ignore it. + expect(data.__packedMap).toBeInstanceOf(PackedMap); + expect(Object.keys(data)).not.toContain('__packedMap'); + expect({ ...data }.__packedMap).toBeUndefined(); + }); + + it('leaves non-wire `data.map` (legacy plain tuples) alone', () => { + const tuples: [number, number, number, number][] = [[1, 0, 1, 0]]; + const result = { + output: [ + { + type: 'js/module', + data: { code: 'foo', lineCount: 1, map: tuples, functionMap: null }, + }, + ], + }; + const wrapped = wrapTransformResultMaps(result); + const data = wrapped.output[0]!.data as any; + expect(data.map).toBe(tuples); + expect(data.__packedMap).toBeUndefined(); + }); + + it('handles results with no output gracefully', () => { + expect(wrapTransformResultMaps({ output: null as any })).toEqual({ output: null }); + expect(wrapTransformResultMaps({} as any)).toEqual({}); + }); + + it('short-circuits on already-wrapped data without invoking the lazy `data.map` getter', () => { + const result: any = { + output: [ + { + type: 'js/module', + data: { + code: '', + lineCount: 1, + map: wire({ segments: [[1, 0, 1, 0]] }), + functionMap: null, + }, + }, + ], + }; + wrapTransformResultMaps(result); + + const data = result.output[0].data; + let getInvocations = 0; + const originalDescriptor = Object.getOwnPropertyDescriptor(data, 'map')!; + Object.defineProperty(data, 'map', { + get() { + getInvocations++; + return originalDescriptor.get!.call(data); + }, + enumerable: true, + configurable: true, + }); + + wrapTransformResultMaps(result); + expect(getInvocations).toBe(0); + }); +}); + +describe('patchTransformFileForPackedMaps', () => { + it('wraps every result returned by the patched bundler', async () => { + const result1 = { + output: [ + { + type: 'js/module', + data: { + map: wire({ segments: [[1, 0, 1, 0]] }), + code: '', + lineCount: 1, + functionMap: null, + }, + }, + ], + }; + const result2 = { + output: [ + { + type: 'js/module', + data: { + map: wire({ segments: [[2, 0, 2, 0]] }), + code: '', + lineCount: 1, + functionMap: null, + }, + }, + ], + }; + const calls: any[] = []; + const bundler: any = { + async transformFile(...args: unknown[]) { + calls.push(args); + return calls.length === 1 ? result1 : result2; + }, + }; + patchTransformFileForPackedMaps(bundler); + + const r1 = await bundler.transformFile('/a.js'); + const r2 = await bundler.transformFile('/b.js'); + + expect(Array.isArray(r1.output[0].data.map)).toBe(true); + expect(r1.output[0].data.__packedMap).toBeInstanceOf(PackedMap); + expect(Array.isArray(r2.output[0].data.map)).toBe(true); + expect(r2.output[0].data.__packedMap).toBeInstanceOf(PackedMap); + expect(calls).toEqual([['/a.js'], ['/b.js']]); + }); + + it('chains cleanly with a pre-existing patch (no double-wrap on the second pass)', async () => { + const bundler: any = { + async transformFile() { + return { + output: [ + { + type: 'js/module', + data: { + map: wire({ segments: [[1, 0, 1, 0]] }), + code: '', + lineCount: 1, + functionMap: null, + }, + }, + ], + }; + }, + }; + patchTransformFileForPackedMaps(bundler); + patchTransformFileForPackedMaps(bundler); + + const r = await bundler.transformFile('/a.js'); + expect(r.output[0].data.__packedMap).toBeInstanceOf(PackedMap); + expect(r.output[0].data.map.length).toBe(1); + }); +}); diff --git a/packages/@expo/metro-config/src/serializer/__tests__/sourceMap.test.ts b/packages/@expo/metro-config/src/serializer/__tests__/sourceMap.test.ts new file mode 100644 index 00000000000000..1aa08310c3682f --- /dev/null +++ b/packages/@expo/metro-config/src/serializer/__tests__/sourceMap.test.ts @@ -0,0 +1,689 @@ +import { GenMapping, addMapping, toEncodedMap } from '@jridgewell/gen-mapping'; +import { TraceMap, originalPositionFor } from '@jridgewell/trace-mapping'; + +import { installPackedMap } from '../packedMap'; +import { + appendDebugIdToSourceMap, + composeSourceMaps, + patchMetroSourceMapStringForPackedMaps, + rawMappingsToEncodedMap, + sourceMapString, + sourceMapStringNonBlocking, + type BabelSourceMapSegment, + type ComposableSourceMap, + type MetroSourceMapSegmentTuple, +} from '../sourceMap'; + +function buildMap(opts: { + file?: string; + segments: { + generated: { line: number; column: number }; + original?: { line: number; column: number }; + source?: string; + name?: string; + }[]; +}): ComposableSourceMap { + const gen = new GenMapping({ file: opts.file }); + for (const s of opts.segments) { + addMapping(gen, { + generated: s.generated, + ...(s.source && s.original ? { source: s.source, original: s.original, name: s.name } : {}), + }); + } + const encoded = toEncodedMap(gen); + return { + version: encoded.version, + file: encoded.file ?? undefined, + mappings: encoded.mappings, + names: encoded.names as string[], + sources: encoded.sources as (string | null)[], + sourcesContent: encoded.sourcesContent as (string | null)[] | undefined, + }; +} + +describe('composeSourceMaps', () => { + it('throws on empty input', () => { + expect(() => composeSourceMaps([])).toThrow(/at least one map/); + }); + + it('composes a basic two-map chain so positions trace through', () => { + const bundler = buildMap({ + file: 'bundle.js', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'helloworld.js', + original: { line: 3, column: 0 }, + }, + { + generated: { line: 2, column: 0 }, + source: 'helloworld.js', + original: { line: 5, column: 0 }, + name: 'greet', + }, + ], + }); + + const hermes = buildMap({ + file: 'bundle.hbc', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'bundle.js', + original: { line: 1, column: 0 }, + }, + { + generated: { line: 2, column: 0 }, + source: 'bundle.js', + original: { line: 2, column: 0 }, + }, + ], + }); + + const composed = composeSourceMaps([bundler, hermes]); + const tracer = new TraceMap(composed as any); + + expect(originalPositionFor(tracer, { line: 1, column: 0 })).toMatchObject({ + source: 'helloworld.js', + line: 3, + column: 0, + }); + expect(originalPositionFor(tracer, { line: 2, column: 0 })).toMatchObject({ + source: 'helloworld.js', + line: 5, + column: 0, + name: 'greet', + }); + }); + + it('returns a single map unchanged in the trivial chain', () => { + const single = buildMap({ + file: 'a.js', + segments: [ + { generated: { line: 1, column: 0 }, source: 'src.js', original: { line: 1, column: 0 } }, + ], + }); + + const composed = composeSourceMaps([single]); + const tracer = new TraceMap(composed as any); + expect(originalPositionFor(tracer, { line: 1, column: 0 })).toMatchObject({ + source: 'src.js', + line: 1, + column: 0, + }); + }); + + describe('ignore list', () => { + it('translates x_google_ignoreList input-side and emits both keys on output', () => { + // The legacy alias is what Metro's Generator emits today. + const bundler: ComposableSourceMap = { + ...buildMap({ + file: 'bundle.js', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'user.js', + original: { line: 1, column: 0 }, + }, + { + generated: { line: 1, column: 5 }, + source: 'node_modules/lib.js', + original: { line: 2, column: 0 }, + }, + ], + }), + x_google_ignoreList: [1], // index of node_modules/lib.js in sources + }; + const hermes = buildMap({ + file: 'bundle.hbc', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'bundle.js', + original: { line: 1, column: 0 }, + }, + { + generated: { line: 1, column: 3 }, + source: 'bundle.js', + original: { line: 1, column: 5 }, + }, + ], + }); + + const composed = composeSourceMaps([bundler, hermes]); + + expect(composed.ignoreList).toBeDefined(); + expect(composed.x_google_ignoreList).toBeDefined(); + expect(composed.ignoreList).toEqual(composed.x_google_ignoreList); + + const ignoredSources = composed.ignoreList!.map((i) => composed.sources[i]); + expect(ignoredSources).toEqual(['node_modules/lib.js']); + }); + + it('does not emit ignoreList when input has no ignored sources', () => { + const bundler = buildMap({ + file: 'bundle.js', + segments: [ + { generated: { line: 1, column: 0 }, source: 'a.js', original: { line: 1, column: 0 } }, + ], + }); + const hermes = buildMap({ + file: 'bundle.hbc', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'bundle.js', + original: { line: 1, column: 0 }, + }, + ], + }); + + const composed = composeSourceMaps([bundler, hermes]); + expect(composed.ignoreList).toBeUndefined(); + expect(composed.x_google_ignoreList).toBeUndefined(); + }); + + it('honors a pre-translated ignoreList (no double-handling)', () => { + const bundler: ComposableSourceMap = { + ...buildMap({ + file: 'bundle.js', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'user.js', + original: { line: 1, column: 0 }, + }, + { + generated: { line: 1, column: 5 }, + source: 'lib.js', + original: { line: 2, column: 0 }, + }, + ], + }), + ignoreList: [1], + }; + const hermes = buildMap({ + file: 'bundle.hbc', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'bundle.js', + original: { line: 1, column: 0 }, + }, + { + generated: { line: 1, column: 3 }, + source: 'bundle.js', + original: { line: 1, column: 5 }, + }, + ], + }); + + const composed = composeSourceMaps([bundler, hermes]); + expect(composed.ignoreList).toEqual(composed.x_google_ignoreList); + const ignoredSources = composed.ignoreList!.map((i) => composed.sources[i]); + expect(ignoredSources).toEqual(['lib.js']); + }); + }); + + describe('Metro-specific extension fields', () => { + it('carries x_hermes_function_offsets through from the latest map', () => { + const bundler = buildMap({ + file: 'bundle.js', + segments: [ + { generated: { line: 1, column: 0 }, source: 'a.js', original: { line: 1, column: 0 } }, + { generated: { line: 5, column: 0 }, source: 'a.js', original: { line: 10, column: 0 } }, + ], + }); + // Fixture crosses a function boundary so dropping the field would + // observably break Hermes bytecode-frame symbolication. + const hermes: ComposableSourceMap = { + ...buildMap({ + file: 'bundle.hbc', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'bundle.js', + original: { line: 1, column: 0 }, + }, + { + generated: { line: 1, column: 100 }, + source: 'bundle.js', + original: { line: 5, column: 0 }, + }, + ], + }), + x_hermes_function_offsets: { 0: [0, 50], 1: [100, 200] }, + }; + + const composed = composeSourceMaps([bundler, hermes]); + expect(composed.x_hermes_function_offsets).toEqual({ 0: [0, 50], 1: [100, 200] }); + expect(composed.x_hermes_function_offsets).toBe(hermes.x_hermes_function_offsets); + }); + + it('drops x_facebook_sources deliberately (Expo does not ship to FB symbolicators)', () => { + const bundler: ComposableSourceMap & { x_facebook_sources?: unknown } = { + ...buildMap({ + file: 'bundle.js', + segments: [ + { generated: { line: 1, column: 0 }, source: 'a.js', original: { line: 1, column: 0 } }, + ], + }), + x_facebook_sources: [[{ names: [''], mappings: 'AAAA' }]], + }; + const hermes = buildMap({ + file: 'bundle.hbc', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'bundle.js', + original: { line: 1, column: 0 }, + }, + ], + }); + + const composed = composeSourceMaps([bundler, hermes]) as ComposableSourceMap & { + x_facebook_sources?: unknown; + }; + expect(composed.x_facebook_sources).toBeUndefined(); + }); + }); + + describe('parity vs Metro composeSourceMaps', () => { + function buildFixture() { + const bundler = buildMap({ + file: 'bundle.js', + segments: [ + { generated: { line: 1, column: 0 }, source: 'a.js', original: { line: 1, column: 0 } }, + { + generated: { line: 1, column: 10 }, + source: 'a.js', + original: { line: 1, column: 10 }, + name: 'foo', + }, + { generated: { line: 1, column: 20 }, source: 'b.js', original: { line: 5, column: 4 } }, + { generated: { line: 2, column: 0 }, source: 'b.js', original: { line: 6, column: 0 } }, + { + generated: { line: 2, column: 8 }, + source: 'c.js', + original: { line: 12, column: 0 }, + name: 'bar', + }, + { generated: { line: 3, column: 0 }, source: 'c.js', original: { line: 14, column: 0 } }, + ], + }); + + const hermes = buildMap({ + file: 'bundle.hbc', + segments: [ + { + generated: { line: 1, column: 0 }, + source: 'bundle.js', + original: { line: 1, column: 0 }, + }, + { + generated: { line: 1, column: 4 }, + source: 'bundle.js', + original: { line: 1, column: 10 }, + }, + { + generated: { line: 1, column: 9 }, + source: 'bundle.js', + original: { line: 1, column: 20 }, + }, + { + generated: { line: 1, column: 13 }, + source: 'bundle.js', + original: { line: 2, column: 0 }, + }, + { + generated: { line: 1, column: 18 }, + source: 'bundle.js', + original: { line: 2, column: 8 }, + }, + { + generated: { line: 1, column: 24 }, + source: 'bundle.js', + original: { line: 3, column: 0 }, + }, + ], + }); + + return { bundler, hermes }; + } + + it('resolves the same source positions as Metro for a multi-source fixture', () => { + const { bundler, hermes } = buildFixture(); + + const metroCompose: typeof import('@expo/metro/metro-source-map').composeSourceMaps = + require('@expo/metro/metro-source-map').composeSourceMaps; + + const ours = composeSourceMaps([bundler, hermes]); + const metro = metroCompose([bundler, hermes] as any); + + const oursTracer = new TraceMap(ours as any); + const metroTracer = new TraceMap(metro as any); + + const probes = [ + { line: 1, column: 0 }, + { line: 1, column: 4 }, + { line: 1, column: 7 }, + { line: 1, column: 9 }, + { line: 1, column: 13 }, + { line: 1, column: 18 }, + { line: 1, column: 24 }, + { line: 1, column: 30 }, + ]; + + for (const probe of probes) { + const oursPos = originalPositionFor(oursTracer, probe); + const metroPos = originalPositionFor(metroTracer, probe); + expect({ probe, ...oursPos }).toEqual({ probe, ...metroPos }); + } + }); + }); +}); + +describe('rawMappingsToEncodedMap', () => { + it('encodes Babel rawMappings so positions trace back through the encoded map', () => { + const rawMappings: BabelSourceMapSegment[] = [ + { + generated: { line: 1, column: 0 }, + original: { line: 3, column: 0 }, + source: 'helloworld.js', + }, + { + generated: { line: 1, column: 5 }, + original: { line: 3, column: 8 }, + source: 'helloworld.js', + name: 'greet', + }, + { + generated: { line: 2, column: 0 }, + original: { line: 5, column: 0 }, + source: 'helloworld.js', + }, + ]; + + const encoded = rawMappingsToEncodedMap({ + filename: 'helloworld.js', + source: 'console.log(1)\nconsole.log(2)\nconsole.log(3)\n', + rawMappings, + }); + + expect(encoded.version).toBe(3); + expect(encoded.sources).toEqual(['helloworld.js']); + expect(encoded.sourcesContent).toEqual(['console.log(1)\nconsole.log(2)\nconsole.log(3)\n']); + + const tracer = new TraceMap(encoded); + expect(originalPositionFor(tracer, { line: 1, column: 0 })).toMatchObject({ + source: 'helloworld.js', + line: 3, + column: 0, + }); + expect(originalPositionFor(tracer, { line: 1, column: 5 })).toMatchObject({ + source: 'helloworld.js', + line: 3, + column: 8, + name: 'greet', + }); + expect(originalPositionFor(tracer, { line: 2, column: 0 })).toMatchObject({ + source: 'helloworld.js', + line: 5, + column: 0, + }); + }); + + it('encodes sourceless rawMappings (no `original`) as sourceless mappings', () => { + const rawMappings: BabelSourceMapSegment[] = [ + { generated: { line: 1, column: 0 } }, + { generated: { line: 1, column: 4 }, original: { line: 1, column: 0 }, source: 'a.js' }, + ]; + const encoded = rawMappingsToEncodedMap({ + filename: 'a.js', + source: 'foo\n', + rawMappings, + }); + const tracer = new TraceMap(encoded); + expect(originalPositionFor(tracer, { line: 1, column: 0 })).toMatchObject({ + source: null, + line: null, + column: null, + }); + expect(originalPositionFor(tracer, { line: 1, column: 4 })).toMatchObject({ + source: 'a.js', + line: 1, + column: 0, + }); + }); + + it('returns a valid encoded map for empty input', () => { + const encoded = rawMappingsToEncodedMap({ + filename: 'a.js', + source: '', + rawMappings: [], + }); + expect(encoded.version).toBe(3); + expect(encoded.sources).toEqual(['a.js']); + expect(encoded.mappings).toBe(''); + }); +}); + +// Minimal `Module`-shaped fake: only the fields the encoder +// reads (`output[].data.{code,map,functionMap,lineCount}`, `path`, +// `getSource()`) are populated. +function fakeJsModule(opts: { + path: string; + code?: string; + source?: string; + map: MetroSourceMapSegmentTuple[]; + lineCount?: number; +}): any { + const code = opts.code ?? `// ${opts.path}\n`; + const source = opts.source ?? code; + return { + path: opts.path, + output: [ + { + type: 'js/module', + data: { + code, + lineCount: opts.lineCount ?? code.split(/\r\n?|\n/).length, + map: opts.map, + functionMap: null, + }, + }, + ], + dependencies: new Map(), + inverseDependencies: new Set(), + getSource: () => Buffer.from(source), + }; +} + +function defaultOptions() { + return { + excludeSource: true, + processModuleFilter: () => true, + shouldAddToIgnoreList: () => false, + }; +} + +describe('sourceMapString', () => { + it('does not fire the lazy `data.map` getter when `__packedMap` is present', () => { + // Reading `data.map` would allocate a Proxy per module per encode + // pass for nothing — the fast path goes through `__packedMap`. + const mod = fakeJsModule({ + path: '/foo.js', + map: [ + [1, 0, 1, 0], + [1, 5, 2, 0, 'foo'], + ], + }); + installPackedMap(mod.output[0].data, mod.output[0].data.map); + + let getCount = 0; + const descriptor = Object.getOwnPropertyDescriptor(mod.output[0].data, 'map')!; + Object.defineProperty(mod.output[0].data, 'map', { + get() { + getCount++; + return descriptor.get!.call(mod.output[0].data); + }, + enumerable: true, + configurable: true, + }); + + sourceMapString([mod], defaultOptions()); + expect(getCount).toBe(0); + }); + + it('produces a sourcemap byte-equivalent to Metros for the same input', () => { + // We feed Metro's `Generator` the same segments in the same order, + // so the serialized output should match byte-for-byte. Tests cover + // adjacents on the same line, sourceless mappings, named mappings, + // and module-boundary transitions. + const metroSourceMapString: typeof import('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString.js').sourceMapString = + require('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString.js').sourceMapString; + + const modules = [ + fakeJsModule({ + path: '/a.js', + code: 'A1\nA2\nA3\n', + map: [ + [1, 0, 1, 0], + [1, 4, 1, 0], + [2, 0, 2, 0, 'foo'], + [3, 0], + [3, 4, 3, 4], + ], + }), + fakeJsModule({ + path: '/b.js', + code: 'B1\n', + map: [[1, 0, 10, 0, 'bar']], + }), + ]; + + const ours = JSON.parse(sourceMapString(modules, defaultOptions())); + const theirs = JSON.parse(metroSourceMapString(modules, defaultOptions())); + expect(ours).toEqual(theirs); + }); + + it('sourceMapStringNonBlocking returns the same output as sourceMapString', async () => { + const modules = [ + fakeJsModule({ + path: '/a.js', + code: 'a\nb\nc\n', + map: [ + [1, 0, 1, 0], + [2, 0, 2, 0], + ], + }), + fakeJsModule({ + path: '/b.js', + code: 'd\n', + map: [[1, 0, 1, 0]], + }), + ]; + + const sync = sourceMapString(modules, defaultOptions()); + const async = await sourceMapStringNonBlocking(modules, defaultOptions()); + expect(async).toEqual(sync); + }); + + describe('debugId emission', () => { + const fixture = () => + fakeJsModule({ + path: '/foo.js', + code: 'a\n', + map: [[1, 0, 1, 0]], + }); + + it('emits debugId inline during build (no JSON.parse roundtrip needed)', () => { + const json = sourceMapString([fixture()], { ...defaultOptions(), debugId: 'abc-123' }); + const map = JSON.parse(json); + expect(map.debugId).toBe('abc-123'); + expect(typeof map.mappings).toBe('string'); + expect(Array.isArray(map.sources)).toBe(true); + }); + + it('omits debugId when option is not provided', () => { + const json = sourceMapString([fixture()], defaultOptions()); + const map = JSON.parse(json); + expect('debugId' in map).toBe(false); + }); + + it('escapes special characters in debugId via JSON.stringify', () => { + const id = 'has "quote" and \\ backslash'; + const json = sourceMapString([fixture()], { ...defaultOptions(), debugId: id }); + expect(JSON.parse(json).debugId).toBe(id); + }); + + it('produces output identical to a manual JSON.parse + add + JSON.stringify roundtrip', () => { + const baseline = sourceMapString([fixture()], defaultOptions()); + const baselineWithId = JSON.stringify({ ...JSON.parse(baseline), debugId: 'roundtrip' }); + const ours = sourceMapString([fixture()], { ...defaultOptions(), debugId: 'roundtrip' }); + expect(JSON.parse(ours)).toEqual(JSON.parse(baselineWithId)); + }); + + it('appendDebugIdToSourceMap injects without parsing', () => { + const baseline = sourceMapString([fixture()], defaultOptions()); + const injected = appendDebugIdToSourceMap(baseline, 'after-the-fact'); + const map = JSON.parse(injected); + expect(map.debugId).toBe('after-the-fact'); + expect(JSON.parse(baseline).debugId).toBeUndefined(); + }); + }); + + describe('CI guard: @expo/metro/metro-source-map/Generator import shape', () => { + it('exposes Generator via .default and the prototype methods we use', () => { + const Generator: any = require('@expo/metro/metro-source-map/Generator').default; + expect(typeof Generator).toBe('function'); + const proto = Generator.prototype; + for (const m of [ + 'addSimpleMapping', + 'addSourceMapping', + 'addNamedSourceMapping', + 'startFile', + 'endFile', + 'toString', + 'toMap', + ]) { + expect(typeof proto[m]).toBe('function'); + } + }); + }); + + describe('patchMetroSourceMapStringForPackedMaps', () => { + const STOCK_PATH = '@expo/metro/metro/DeltaBundler/Serializers/sourceMapString'; + + afterEach(() => { + // Repair the live module so other tests asserting against Metro's + // stock implementation don't see the patched references. + jest.resetModules(); + }); + + it('replaces both stock exports with Expo`s encoder', () => { + const stock = require(STOCK_PATH); + const originalSync = stock.sourceMapString; + const originalAsync = stock.sourceMapStringNonBlocking; + expect(originalSync).not.toBe(sourceMapString); + expect(originalAsync).not.toBe(sourceMapStringNonBlocking); + + patchMetroSourceMapStringForPackedMaps(); + + expect(stock.sourceMapString).toBe(sourceMapString); + expect(stock.sourceMapStringNonBlocking).toBe(sourceMapStringNonBlocking); + }); + + it('is idempotent — repeat calls leave the references unchanged', () => { + patchMetroSourceMapStringForPackedMaps(); + const after1 = require(STOCK_PATH); + const sync1 = after1.sourceMapString; + const async1 = after1.sourceMapStringNonBlocking; + + patchMetroSourceMapStringForPackedMaps(); + + expect(after1.sourceMapString).toBe(sync1); + expect(after1.sourceMapStringNonBlocking).toBe(async1); + }); + }); +}); diff --git a/packages/@expo/metro-config/src/serializer/exportHermes.ts b/packages/@expo/metro-config/src/serializer/exportHermes.ts index 17d23b6e850b09..d445eef0c06027 100644 --- a/packages/@expo/metro-config/src/serializer/exportHermes.ts +++ b/packages/@expo/metro-config/src/serializer/exportHermes.ts @@ -1,4 +1,3 @@ -import { composeSourceMaps } from '@expo/metro/metro-source-map'; import spawnAsync from '@expo/spawn-async'; import chalk from 'chalk'; import fs from 'fs'; @@ -7,6 +6,8 @@ import path from 'path'; import process from 'process'; import resolveFrom from 'resolve-from'; +import { composeSourceMaps } from './sourceMap'; + const debug = require('debug')('expo:metro:hermes') as typeof console.log; function importHermesCommandFromProject(projectRoot: string): string { diff --git a/packages/@expo/metro-config/src/serializer/fork/__tests__/mini-metro.test.ts b/packages/@expo/metro-config/src/serializer/fork/__tests__/mini-metro.test.ts index fec47ff70c3fa3..73e77bfea394af 100644 --- a/packages/@expo/metro-config/src/serializer/fork/__tests__/mini-metro.test.ts +++ b/packages/@expo/metro-config/src/serializer/fork/__tests__/mini-metro.test.ts @@ -72,121 +72,110 @@ it(`can create a micro Metro graph fixture`, async () => { "hasCjsExports": false, "lineCount": 6, "loaderReference": undefined, - "map": [ - [ + "map": { + "__count": 18, + "__names": [ + "_foo", + "_$$_REQUIRE", + "_dependencyMap", + "console", + "log", + "foo", + ], + "__packed": [ 4, 2, 2, 4, - ], - [ + -1, 4, 6, 2, 4, - "_foo", - ], - [ + 0, 4, 10, 2, 4, - ], - [ + -1, 4, 13, 2, 4, - "_$$_REQUIRE", - ], - [ + 1, 4, 24, 2, 4, - ], - [ + -1, 4, 25, 2, 4, - "_dependencyMap", - ], - [ + 2, 4, 39, 2, 4, - ], - [ + -1, 5, 2, 3, 4, - "console", - ], - [ + 3, 5, 9, 3, 11, - ], - [ + -1, 5, 10, 3, 12, - "log", - ], - [ + 4, 5, 13, 3, 15, - ], - [ + -1, 5, 14, 3, 16, - "foo", - ], - [ + 5, 5, 18, 3, 19, - ], - [ + -1, 5, 19, 3, 19, - "foo", - ], - [ + 5, 5, 22, 3, 19, - ], - [ + -1, 5, 23, 3, 20, - ], - [ + -1, 6, 0, 3, 21, - ], - [ + -1, 6, 3, + -1, + -1, + -1, ], - ], + "__version": 1, + }, "reactClientReference": undefined, "reactServerReference": undefined, }, @@ -228,158 +217,140 @@ it(`can create a micro Metro graph fixture`, async () => { "hasCjsExports": false, "lineCount": 14, "loaderReference": undefined, - "map": [ - [ + "map": { + "__count": 24, + "__names": [ + "Object", + "defineProperty", + "exports", + "enumerable", + "get", + "foo", + ], + "__packed": [ 7, 2, 2, 4, - "Object", - ], - [ + 0, 7, 8, 2, 4, - ], - [ + -1, 7, 9, 2, 4, - "defineProperty", - ], - [ + 1, 7, 23, 2, 4, - ], - [ + -1, 7, 24, 2, 4, - "exports", - ], - [ + 2, 7, 31, 2, 4, - ], - [ + -1, 8, 4, 2, 4, - "enumerable", - ], - [ + 3, 8, 14, 2, 4, - ], - [ + -1, 9, 4, 2, 4, - "get", - ], - [ + 4, 9, 7, 2, 4, - ], - [ + -1, 9, 18, 2, 4, - "get", - ], - [ + 4, 9, 19, 2, 4, - ], - [ + -1, 10, 6, 2, 4, - ], - [ + -1, 10, 13, 2, 4, - "foo", - ], - [ + 5, 10, 16, 2, 4, - ], - [ + -1, 11, 4, 2, 4, - ], - [ + -1, 12, 2, 2, 4, - ], - [ + -1, 13, 2, 2, 11, - ], - [ + -1, 13, 8, 2, 17, - "foo", - ], - [ + 5, 13, 11, 2, 20, - ], - [ + -1, 13, 14, 2, 23, - ], - [ + -1, 13, 19, 2, 28, - ], - [ + -1, 14, 0, 2, 29, - ], - [ + -1, 14, 3, + -1, + -1, + -1, ], - ], + "__version": 1, + }, "reactClientReference": undefined, "reactServerReference": undefined, }, diff --git a/packages/@expo/metro-config/src/serializer/fork/__tests__/mini-metro.ts b/packages/@expo/metro-config/src/serializer/fork/__tests__/mini-metro.ts index d2a40866f4d286..7572f67257bd64 100644 --- a/packages/@expo/metro-config/src/serializer/fork/__tests__/mini-metro.ts +++ b/packages/@expo/metro-config/src/serializer/fork/__tests__/mini-metro.ts @@ -11,6 +11,7 @@ import * as path from 'path'; import type { JsTransformOptions } from '../../../transform-worker/metro-transform-worker'; import * as expoMetroTransformWorker from '../../../transform-worker/transform-worker'; +import { wrapTransformResultMaps } from '../../packedMap'; export const projectRoot = '/app'; @@ -316,25 +317,29 @@ export async function parseModule( const absoluteFilePath = path.join(projectRoot, relativeFilePath); const codeBuffer = Buffer.from(code); - const { output, dependencies } = await expoMetroTransformWorker.transform( - // TODO: Maybe just pull from expo/metro-config to ensure correctness over time. - { - ...METRO_CONFIG_DEFAULTS.transformer, - asyncRequireModulePath: 'expo-mock/async-require', - unstable_allowRequireContext: true, - allowOptionalDependencies: true, - assetPlugins: [], - babelTransformerPath: '@expo/metro-config/build/babel-transformer', - ...transformConfig, - }, - projectRoot, - absoluteFilePath, - codeBuffer, - { - inlineRequires: false, - ...transformOptions, - inlinePlatform: true, - } + // Mirror the production `Bundler.transformFile` wrapper so test + // fixtures see the same `data.map` shape readers do. + const { output, dependencies } = wrapTransformResultMaps( + await expoMetroTransformWorker.transform( + // TODO: Maybe just pull from expo/metro-config to ensure correctness over time. + { + ...METRO_CONFIG_DEFAULTS.transformer, + asyncRequireModulePath: 'expo-mock/async-require', + unstable_allowRequireContext: true, + allowOptionalDependencies: true, + assetPlugins: [], + babelTransformerPath: '@expo/metro-config/build/babel-transformer', + ...transformConfig, + }, + projectRoot, + absoluteFilePath, + codeBuffer, + { + inlineRequires: false, + ...transformOptions, + inlinePlatform: true, + } + ) ); return { diff --git a/packages/@expo/metro-config/src/serializer/jsOutput.ts b/packages/@expo/metro-config/src/serializer/jsOutput.ts index 0e1796950e1607..9efd62d157f215 100644 --- a/packages/@expo/metro-config/src/serializer/jsOutput.ts +++ b/packages/@expo/metro-config/src/serializer/jsOutput.ts @@ -8,15 +8,28 @@ import type { types as t } from '@babel/core'; import type { FBSourceFunctionMap, MetroSourceMapSegmentTuple } from '@expo/metro/metro-source-map'; import type { JsTransformerConfig } from '@expo/metro/metro-transform-worker'; +import type { PackedMap, SerializableSourceMap } from './packedMap'; import type { Options as CollectDependenciesOptions } from '../transform-worker/collect-dependencies'; export type JSFileType = 'js/script' | 'js/module' | 'js/module/asset'; +// `data.map` is one of three shapes depending on the pipeline stage: +// - `SerializableSourceMap` from the worker / metro-cache. +// - The `Array.isArray`-true Proxy installed on the main thread by +// Expo's `Bundler.transformFile` wrapper — what every reader sees. +// - Plain `MetroSourceMapSegmentTuple[]` from custom transformers, or +// legacy cache entries written before `SerializableSourceMap` existed. +export type ModuleSourceMap = SerializableSourceMap | MetroSourceMapSegmentTuple[]; + export type JsOutput = { data: { code: string; lineCount: number; - map: MetroSourceMapSegmentTuple[]; + map: ModuleSourceMap; + // Non-enumerable so it doesn't survive `{...data}` spreads; the + // encoder fast path reads it off the original `data` object to + // iterate the underlying `Int32Array` directly. + readonly __packedMap?: PackedMap; functionMap: FBSourceFunctionMap | null; css?: { diff --git a/packages/@expo/metro-config/src/serializer/packedMap.ts b/packages/@expo/metro-config/src/serializer/packedMap.ts new file mode 100644 index 00000000000000..cb41811ea61833 --- /dev/null +++ b/packages/@expo/metro-config/src/serializer/packedMap.ts @@ -0,0 +1,455 @@ +/** + * Copyright © 2026 650 Industries. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// Compact, Array-compatible storage for a module's per-segment sourcemap +// data, replacing the per-segment heap-allocated tuple Array on +// `module.output[0].data.map`. The Proxy preserves every reader's access +// pattern (`Array.isArray`, `length`, numeric indices, iteration); the +// encoder fast path in `sourceMap.ts` reads the underlying `Int32Array` +// directly to avoid the per-segment tuple allocation that Proxy +// iteration would otherwise incur. +// +// `SerializableSourceMap` is the JSON-faithful sibling of the +// `PackedMap` class above — same logical shape, but storage is a plain +// `number[]` instead of an `Int32Array` so it round-trips through `JSON`. +// Workers emit it across IPC and `metro-cache` writes it to disk; +// `PackedMap.deserialize` rehydrates it on the main thread. + +import type { + BabelSourceMapSegment, + MetroSourceMapSegmentTuple, +} from '@expo/metro/metro-source-map'; + +// Layout per segment, starting at `i * STRIDE`. Fixed stride so segments +// are indexable in O(1); missing fields use sentinel `-1`. Lines are +// 1-based to match `MetroSourceMapSegmentTuple`. +// [0] generated line +// [1] generated column +// [2] source line (-1 if sourceless) +// [3] source column (-1 if sourceless) +// [4] name index (-1 if no name) +export const STRIDE = 5; +export const SENTINEL = -1; + +export interface SerializableSourceMap { + __packed: number[]; + __names: string[]; + __count: number; + __version: 1; +} + +export function isSerializableSourceMap(x: unknown): x is SerializableSourceMap { + if (x == null || typeof x !== 'object') return false; + const o = x as Partial; + return ( + o.__version === 1 && + Array.isArray(o.__packed) && + Array.isArray(o.__names) && + typeof o.__count === 'number' + ); +} + +export class PackedMap { + readonly count: number; + readonly names: string[]; + // `Int32Array` storage: 4 bytes/int off-heap vs 8 bytes/slot for the + // tagged `number[]` shape that `SerializableSourceMap` carries. + // Materialized eagerly so a `data.map` whose encoder never iterates + // (e.g. SSR-eval'd modules — the bundle is concatenated and + // `_compile`-ed without anyone calling `.buf`) doesn't strand a + // serialized-shape array on the JS heap. + readonly buf: Int32Array; + + private constructor(buf: Int32Array, names: string[], count: number) { + this.buf = buf; + this.names = names; + this.count = count; + } + + static deserialize(input: SerializableSourceMap): PackedMap { + return new PackedMap(Int32Array.from(input.__packed), input.__names, input.__count); + } + + static fromInts(buf: Int32Array, names: string[], count: number): PackedMap { + return new PackedMap(buf, names, count); + } + + serialize(): SerializableSourceMap { + const buf = this.buf; + const out: number[] = new Array(buf.length); + for (let i = 0; i < buf.length; i++) out[i] = buf[i]!; + return { + __version: 1, + __count: this.count, + __names: this.names.slice(), + __packed: out, + }; + } +} + +// Returns the variable-length form (2, 4, or 5) that matches Metro's +// tuple union. A fixed-length-5 tuple with `-1` sentinels would fool +// `symbolicate.js`'s `mapping.length < 4` sourceless-check and resolve to +// garbage source positions. +export function tupleAt(p: PackedMap, i: number): MetroSourceMapSegmentTuple | undefined { + if (i < 0 || i >= p.count) return undefined; + const buf = p.buf; + const off = i * STRIDE; + const genL = buf[off]!; + const genC = buf[off + 1]!; + const srcL = buf[off + 2]!; + if (srcL === SENTINEL) { + return [genL, genC]; + } + const srcC = buf[off + 3]!; + const nameIdx = buf[off + 4]!; + if (nameIdx === SENTINEL) { + return [genL, genC, srcL, srcC]; + } + // A `SerializableSourceMap` with `nameIdx >= __names.length` is malformed; throw a + // clear error rather than silently producing `[..., undefined]`, which + // would corrupt names through the encoder without any obvious symptom. + const name = p.names[nameIdx]; + if (name === undefined) { + throw new Error( + `[expo-metro-config] PackedMap segment ${i} references name index ${nameIdx}, ` + + `but only ${p.names.length} names exist. The serialized entry is corrupt; ` + + `clear the metro cache (\`expo start --clear\`) and rebuild.` + ); + } + return [genL, genC, srcL, srcC, name]; +} + +function* iterateTuples(p: PackedMap): IterableIterator { + for (let i = 0; i < p.count; i++) { + yield tupleAt(p, i)!; + } +} + +const NODE_INSPECT = Symbol.for('nodejs.util.inspect.custom'); + +// Replace `data.map` with the `Array.isArray`-true Proxy and attach the +// underlying `PackedMap` as non-enumerable `data.__packedMap` for the +// encoder fast path. Accepts either a `SerializableSourceMap` (worker output, +// cache hits) or plain tuples (reconcile-style serializer plugins). +// Idempotent: both fields are defined `configurable: true`, so re-running +// on a previously-installed `data` object is safe. +export function installPackedMap( + data: { map?: unknown; __packedMap?: PackedMap }, + source: SerializableSourceMap | readonly MetroSourceMapSegmentTuple[] +): void { + // Tuple input goes straight to a typed-array-backed `PackedMap` — going + // via `packTuples` would allocate a `number[]` that + // `PackedMap.deserialize` would then drop on first `.buf` access. + const packed = isSerializableSourceMap(source) + ? PackedMap.deserialize(source) + : packTuplesToPackedMap(source); + + // Lazy accessor for `data.map`: builds that never symbolicate (typical + // CI / quiet dev sessions) read `data.__packedMap` exclusively via the + // encoder fast path, so the Proxy is never allocated. Cached on first + // read so consumers that hold onto `data.map` (e.g. + // `getExplodedSourceMap`) see a stable identity. + let cachedProxy: MetroSourceMapSegmentTuple[] | undefined; + Object.defineProperty(data, 'map', { + get() { + if (!cachedProxy) cachedProxy = makeProxy(packed); + return cachedProxy; + }, + enumerable: true, + configurable: true, + }); + Object.defineProperty(data, '__packedMap', { + value: packed, + enumerable: false, + writable: false, + configurable: true, + }); +} + +// The single chokepoint between "worker emits SerializableSourceMap" and "main-thread +// readers expect array-shaped tuples". Used in production via the +// `Bundler.transformFile` patch and called directly in tests. +export function wrapTransformResultMaps( + result: T +): T { + if (!result || !Array.isArray(result.output)) return result; + for (const out of result.output) { + const data = (out as { data?: { map?: unknown; __packedMap?: PackedMap } } | null)?.data; + if (!data) continue; + // Skip without touching `data.map` — reading it would fire the lazy + // getter and materialize a Proxy we don't need. + if (data.__packedMap) continue; + if (isSerializableSourceMap(data.map)) { + installPackedMap(data, data.map); + } + } + return result; +} + +// Idempotent: chaining is safe because `installPackedMap` only fires +// when `data.map` is still a `SerializableSourceMap`. +export function patchTransformFileForPackedMaps(bundler: { + transformFile: (...args: any[]) => Promise; +}): void { + const originalTransformFile = bundler.transformFile.bind(bundler); + bundler.transformFile = async (...args: any[]) => { + return wrapTransformResultMaps((await originalTransformFile(...args)) as any); + }; +} + +// Materialize any `data.map` shape (serialized, Proxy, or plain tuples) into a +// plain `MetroSourceMapSegmentTuple[]`. NOT a hot path — allocates a +// fresh tuple per segment; production readers go through the Proxy or +// the encoder fast path. +export function materializeMap( + map: SerializableSourceMap | readonly MetroSourceMapSegmentTuple[] | null | undefined +): MetroSourceMapSegmentTuple[] { + if (map == null) return []; + if (isSerializableSourceMap(map)) { + const packed = PackedMap.deserialize(map); + const out: MetroSourceMapSegmentTuple[] = new Array(packed.count); + for (let i = 0; i < packed.count; i++) { + out[i] = tupleAt(packed, i)!; + } + return out; + } + // The Proxy is `Array.isArray`-true and iterates via `Symbol.iterator`. + return Array.isArray(map) ? Array.from(map) : []; +} + +function indexOrInsert(names: Map, name: string): number { + const existing = names.get(name); + if (existing !== undefined) return existing; + const idx = names.size; + names.set(name, idx); + return idx; +} + +export function emptySourceMap(): SerializableSourceMap { + return { __version: 1, __count: 0, __names: [], __packed: [] }; +} + +// Convert Babel’s `result.rawMappings` directly to a `SerializableSourceMap`. The +// worker's terminal storage is `SerializableSourceMap`, so going via an +// intermediate `MetroSourceMapSegmentTuple[]` (one heap-allocated Array +// per segment) is wasted work; for an N-module bundle averaging M +// segments per module that's N×M transient tuple allocations per +// transform pass. `BabelSourceMapSegment` lines are 1-based (matching +// the serialized shape). +export function packRawMappings( + rawMappings: readonly BabelSourceMapSegment[] +): SerializableSourceMap { + const names = new Map(); + const out: number[] = new Array(rawMappings.length * STRIDE); + let off = 0; + for (const m of rawMappings) { + out[off] = m.generated.line; + out[off + 1] = m.generated.column; + if (m.original == null) { + out[off + 2] = SENTINEL; + out[off + 3] = SENTINEL; + out[off + 4] = SENTINEL; + } else { + out[off + 2] = m.original.line; + out[off + 3] = m.original.column; + out[off + 4] = typeof m.name === 'string' ? indexOrInsert(names, m.name) : SENTINEL; + } + off += STRIDE; + } + return { + __version: 1, + __count: rawMappings.length, + __names: [...names.keys()], + __packed: out, + }; +} + +// Decode a minifier’s encoded sourcemap straight to a `SerializableSourceMap`. `decode` +// returns 0-based outer indices and 0-based source lines; the serialized form is +// 1-based for both — adjust at the boundary. The minifier already +// deduplicates names, so `input.names` becomes the output `__names` +// directly without re-interning. +export function packDecodedMappings(input: { + mappings: string; + names: readonly string[]; +}): SerializableSourceMap { + const decoded = loadSourceMapCodec().decode(input.mappings); + let total = 0; + for (const line of decoded) total += line.length; + const out: number[] = new Array(total * STRIDE); + let off = 0; + let count = 0; + for (let lineIdx = 0; lineIdx < decoded.length; lineIdx++) { + const genLine = lineIdx + 1; + for (const seg of decoded[lineIdx]!) { + out[off] = genLine; + out[off + 1] = seg[0]!; + if (seg.length === 1) { + out[off + 2] = SENTINEL; + out[off + 3] = SENTINEL; + out[off + 4] = SENTINEL; + } else { + out[off + 2] = (seg[2] as number) + 1; + out[off + 3] = seg[3] as number; + out[off + 4] = seg.length === 5 ? (seg[4] as number) : SENTINEL; + } + off += STRIDE; + count++; + } + } + return { + __version: 1, + __count: count, + __names: input.names.slice(), + __packed: out, + }; +} + +// Append the trailing `(lineCount+1, lastLineLength)` terminator to the +// `SerializableSourceMap`’s `__packed` if it isn’t already there. Without this, an +// out-of-bounds lookup at the tail of the bundle would alias to the +// last real mapping rather than resolving to nothing — same invariant +// as the legacy tuple-array form, but applied in place on the flat +// `number[]` storage. +// +// ASSUMPTION: Mappings are generated in order of increasing line and +// column. +export function countLinesAndTerminateSourceMap( + code: string, + sourceMap: SerializableSourceMap +): { lineCount: number; sourceMap: SerializableSourceMap } { + const NEWLINE = /\r\n?|\n|\u2028|\u2029/g; + let lineCount = 1; + let lastLineStart = 0; + for (const match of code.matchAll(NEWLINE)) { + if (match.index == null) continue; + lineCount++; + lastLineStart = match.index + match[0].length; + } + const lastLineLength = code.length - lastLineStart; + + const lastIdx = sourceMap.__count - 1; + if (lastIdx >= 0) { + const off = lastIdx * STRIDE; + if (sourceMap.__packed[off] === lineCount && sourceMap.__packed[off + 1] === lastLineLength) { + return { lineCount, sourceMap }; + } + } + return { + lineCount, + sourceMap: { + __version: 1, + __count: sourceMap.__count + 1, + __names: sourceMap.__names, + __packed: [...sourceMap.__packed, lineCount, lastLineLength, SENTINEL, SENTINEL, SENTINEL], + }, + }; +} + +type SourceMapCodecModule = typeof import('@jridgewell/sourcemap-codec'); +let _sourceMapCodec: SourceMapCodecModule | undefined; +function loadSourceMapCodec(): SourceMapCodecModule { + if (!_sourceMapCodec) { + _sourceMapCodec = require('@jridgewell/sourcemap-codec'); + } + return _sourceMapCodec!; +} + +// Pack tuples straight into an `Int32Array`-backed `PackedMap`, skipping +// a `SerializableSourceMap`. Used by `installPackedMap` when the caller already lives +// on the main thread (reconcile, in-memory refits) and never needs the +// JSON-faithful serialized shape for IPC. +function packTuplesToPackedMap(tuples: readonly MetroSourceMapSegmentTuple[]): PackedMap { + const names = new Map(); + const buf = new Int32Array(tuples.length * STRIDE); + let off = 0; + for (const tuple of tuples) { + buf[off] = tuple[0]; + buf[off + 1] = tuple[1]; + if (tuple.length === 2) { + buf[off + 2] = SENTINEL; + buf[off + 3] = SENTINEL; + buf[off + 4] = SENTINEL; + } else { + buf[off + 2] = tuple[2]; + buf[off + 3] = tuple[3]; + buf[off + 4] = tuple.length === 5 ? indexOrInsert(names, tuple[4]) : SENTINEL; + } + off += STRIDE; + } + return PackedMap.fromInts(buf, [...names.keys()], tuples.length); +} + +// Target is `[]` (a real Array) so `Array.isArray(proxy)` returns true +// per ECMA-262 §7.2.2 — required by Metro's `symbolicate`. +export function makeProxy(packed: PackedMap): MetroSourceMapSegmentTuple[] { + const target: MetroSourceMapSegmentTuple[] = []; + const handler: ProxyHandler = { + get(_t, prop) { + if (prop === 'length') return packed.count; + if (prop === Symbol.iterator) return () => iterateTuples(packed); + if (prop === 'toJSON') return () => packed.serialize(); + if (prop === NODE_INSPECT) { + return () => `PackedMap(count=${packed.count})`; + } + if (typeof prop === 'string') { + const n = +prop; + if (Number.isInteger(n) && String(n) === prop && n >= 0) { + return tupleAt(packed, n); + } + } + // Array.prototype methods (`forEach`, `map`, …) reach us back + // through numeric-index `get` and `length`, both covered above. + return Reflect.get(target, prop); + }, + has(_t, prop) { + if (prop === 'length' || prop === Symbol.iterator || prop === 'toJSON') return true; + if (typeof prop === 'string') { + const n = +prop; + if (Number.isInteger(n) && String(n) === prop && n >= 0 && n < packed.count) { + return true; + } + } + return Reflect.has(target, prop); + }, + ownKeys(t) { + const keys = new Array(packed.count); + for (let i = 0; i < packed.count; i++) keys[i] = String(i); + return keys.concat(Reflect.ownKeys(t) as string[]); + }, + getOwnPropertyDescriptor(t, prop) { + if (typeof prop === 'string') { + const n = +prop; + if (Number.isInteger(n) && String(n) === prop && n >= 0 && n < packed.count) { + return { + value: tupleAt(packed, n), + writable: false, + enumerable: true, + configurable: true, + }; + } + } + // Delegate `length` to the real Array target so the Proxy invariant + // for non-configurable own keys holds. + return Reflect.getOwnPropertyDescriptor(t, prop); + }, + set() { + throw new TypeError( + '[expo-metro-config] data.map is read-only — backed by a PackedMap. ' + + 'Modify the underlying source map or rebuild with a fresh transform instead.' + ); + }, + deleteProperty() { + throw new TypeError('[expo-metro-config] data.map is read-only — backed by a PackedMap.'); + }, + defineProperty() { + throw new TypeError('[expo-metro-config] data.map is read-only — backed by a PackedMap.'); + }, + }; + return new Proxy(target, handler); +} diff --git a/packages/@expo/metro-config/src/serializer/reconcileTransformSerializerPlugin.ts b/packages/@expo/metro-config/src/serializer/reconcileTransformSerializerPlugin.ts index 8e8d8d821e744a..cc2877825176e4 100644 --- a/packages/@expo/metro-config/src/serializer/reconcileTransformSerializerPlugin.ts +++ b/packages/@expo/metro-config/src/serializer/reconcileTransformSerializerPlugin.ts @@ -16,21 +16,26 @@ import * as JsFileWrapping from '@expo/metro/metro/ModuleGraph/worker/JsFileWrap import { locToKey } from '@expo/metro/metro/ModuleGraph/worker/importLocationsPlugin'; import { isResolvedDependency } from '@expo/metro/metro/lib/isResolvedDependency'; import type { SerializerConfigT } from '@expo/metro/metro-config'; -import { toSegmentTuple } from '@expo/metro/metro-source-map'; import { normalizePseudoGlobals } from '@expo/metro/metro-transform-plugins'; import assert from 'assert'; import util from 'node:util'; import type { ExpoJsOutput } from './jsOutput'; import { isExpoJsOutput } from './jsOutput'; +import { + countLinesAndTerminateSourceMap, + installPackedMap, + packRawMappings, + type SerializableSourceMap, +} from './packedMap'; import { hasSideEffectWithDebugTrace } from './sideEffects'; +import { type BabelSourceMapSegment } from './sourceMap'; import type { Dependency, DependencyData } from '../transform-worker/collect-dependencies'; import collectDependencies, { getKeyForDependency, hashKey, InvalidRequireCallError as InternalInvalidRequireCallError, } from '../transform-worker/collect-dependencies'; -import { countLinesAndTerminateMap } from '../transform-worker/count-lines'; import { applyImportSupport, InvalidRequireCallError, @@ -294,41 +299,47 @@ export async function reconcileTransformSerializerPlugin( outputItem.data.code ); - // @ts-expect-error: incorrectly typed upstream - let map = result.rawMappings ? result.rawMappings.map(toSegmentTuple) : []; + // `rawMappings` is omitted from `@types/babel__generator`'s + // `GeneratorResult`, but Babel emits it whenever `sourceMaps: true`. + const rawMappings = (result as { rawMappings?: BabelSourceMapSegment[] }).rawMappings ?? []; let code = result.code; + let sourceMap: SerializableSourceMap; if (reconcile.minify) { const source = value.getSource().toString('utf-8'); - ({ map, code } = await minifyCode( + ({ sourceMap, code } = await minifyCode( reconcile.minify, value.path, result.code, source, - map, + rawMappings, reserved )); + } else { + sourceMap = packRawMappings(rawMappings); } let lineCount; - ({ lineCount, map } = countLinesAndTerminateMap(code, map)); - - return { - ...outputItem, - data: { - ...outputItem.data, - code, - map, - lineCount, - functionMap: - // @ts-expect-error: https://github.com/facebook/metro/blob/6151e7eb241b15f3bb13b6302abeafc39d2ca3ad/packages/metro-transform-worker/src/index.js#L508-L512 - ast.metadata?.metro?.functionMap ?? - // @ts-expect-error: Fallback to deprecated explicitly-generated `functionMap` - ast.functionMap ?? - outputItem.data.functionMap ?? - null, - }, + ({ lineCount, sourceMap } = countLinesAndTerminateSourceMap(code, sourceMap)); + + const newData = { + ...outputItem.data, + code, + lineCount, + functionMap: + // @ts-expect-error: https://github.com/facebook/metro/blob/6151e7eb241b15f3bb13b6302abeafc39d2ca3ad/packages/metro-transform-worker/src/index.js#L508-L512 + ast.metadata?.metro?.functionMap ?? + // @ts-expect-error: Fallback to deprecated explicitly-generated `functionMap` + ast.functionMap ?? + outputItem.data.functionMap ?? + null, }; + // Reconcile runs post-graph-build, so it bypasses the + // `Bundler.transformFile` wrapper that normally installs the packed + // shape from worker output. Install it here directly so the encoder + // fast path stays live for reconciled modules. + installPackedMap(newData, sourceMap); + return { ...outputItem, data: newData }; } } diff --git a/packages/@expo/metro-config/src/serializer/serializeChunks.ts b/packages/@expo/metro-config/src/serializer/serializeChunks.ts index c24e10a6390a73..150d2325d57a51 100644 --- a/packages/@expo/metro-config/src/serializer/serializeChunks.ts +++ b/packages/@expo/metro-config/src/serializer/serializeChunks.ts @@ -22,6 +22,7 @@ import { getExportPathForDependencyWithOptions } from './exportPath'; import type { ExpoSerializerOptions } from './fork/baseJSBundle'; import { getCssSerialAssets } from './getCssDeps'; import type { SerialAsset } from './serializerAssets'; +import { appendDebugIdToSourceMap, sourceMapString } from './sourceMap'; import type { SerializerConfigOptions } from './withExpoSerializers'; import getMetroAssets from '../transform-worker/getAssets'; import { toPosixPath } from '../utils/filePath'; @@ -35,16 +36,6 @@ function getBuildHermesBundleAsync() { return _buildHermesBundleAsync; } -// Lazy-loaded to avoid pulling in metro's getAppendScripts -> sourceMapString -> @babel/traverse at startup -let _sourceMapString: typeof import('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString').sourceMapString; -function getSourceMapString() { - if (!_sourceMapString) { - _sourceMapString = - require('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString').sourceMapString; - } - return _sourceMapString; -} - let _baseJSBundleWithDependencies: typeof import('./fork/baseJSBundle').baseJSBundleWithDependencies; function getBaseJSBundleWithDependencies() { if (!_baseJSBundleWithDependencies) { @@ -424,20 +415,13 @@ export class Chunk { const assets: SerialAsset[] = [jsAsset]; - const mutateSourceMapWithDebugId = (sourceMap: string) => { - // TODO: Upstream this so we don't have to parse the source map back and forth. - if (!debugId) { - return sourceMap; - } - // NOTE: debugId isn't required for inline source maps because the source map is included in the same file, therefore - // we don't need to disambiguate between multiple source maps. - const sourceMapObject = JSON.parse(sourceMap); - sourceMapObject.debugId = debugId; - // NOTE: Sentry does this, but bun does not. - // sourceMapObject.debug_id = debugId; - return JSON.stringify(sourceMapObject); - }; - + // debugId is passed into `sourceMapString` so the bundler-map path + // emits it inline rather than a JSON.parse + JSON.stringify + // roundtrip; the Hermes branch below has to splice into a finished + // JSON string because `buildHermesBundleAsync` is opaque. + // NOTE: skipped for inline source maps since they don't need + // disambiguation. We only emit `debugId` (Sentry also reads + // `debug_id`, but bun doesn't). if ( // Only include the source map if the `options.sourceMapUrl` option is provided and we are exporting a static build. includeSourceMaps && @@ -466,13 +450,13 @@ export class Chunk { return module; }); - // TODO: We may not need to mutate the original source map with a `debugId` when hermes is enabled since we'll have different source maps. - const sourceMap = mutateSourceMapWithDebugId( - getSourceMapString()(modules, { - excludeSource: false, - ...this.options, - }) - ); + // TODO: We may not need to set `debugId` on the bundler sourcemap when + // Hermes is enabled, since we ship a separate `.hbc.map` for that case. + const sourceMap = sourceMapString(modules, { + excludeSource: false, + ...this.options, + debugId, + }); assets.push({ filename: this.options.dev ? jsAsset.filename + '.map' : outputFile + '.map', @@ -528,7 +512,9 @@ export class Chunk { } } if (assets[1] && hermesBundleOutput.sourcemap) { - assets[1].source = mutateSourceMapWithDebugId(hermesBundleOutput.sourcemap); + assets[1].source = debugId + ? appendDebugIdToSourceMap(hermesBundleOutput.sourcemap, debugId) + : hermesBundleOutput.sourcemap; assets[1].filename = assets[1].filename.replace(/\.js\.map$/, '.hbc.map'); } } diff --git a/packages/@expo/metro-config/src/serializer/sourceMap.ts b/packages/@expo/metro-config/src/serializer/sourceMap.ts new file mode 100644 index 00000000000000..ac122ba269d6ae --- /dev/null +++ b/packages/@expo/metro-config/src/serializer/sourceMap.ts @@ -0,0 +1,471 @@ +/** + * Copyright © 2026 650 Industries. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// Central indirection for sourcemap operations in `@expo/metro-config` +// and `@expo/cli`. Implementations are loaded lazily — `metro-source-map` +// (and its transitive `@babel/traverse`) at top level adds ~100ms to +// `@expo/cli` startup. +import type { SourceMapGeneratorOptions } from '@expo/metro/metro/DeltaBundler/Serializers/sourceMapGenerator'; +import type { Module } from '@expo/metro/metro/DeltaBundler/types'; +import type { + BabelSourceMapSegment, + BasicSourceMap, + FBSourceFunctionMap, + HermesFunctionOffsets, + MetroSourceMapSegmentTuple, + MixedSourceMap, +} from '@expo/metro/metro-source-map'; +import type GeneratorClass from '@expo/metro/metro-source-map/Generator'; + +import type { ModuleSourceMap } from './jsOutput'; +import { PackedMap, SENTINEL, STRIDE, isSerializableSourceMap } from './packedMap'; + +export type { + BabelSourceMapSegment, + BasicSourceMap, + FBSourceFunctionMap, + HermesFunctionOffsets, + MetroSourceMapSegmentTuple, + MixedSourceMap, + SourceMapGeneratorOptions, +}; + +// Metro's `BasicSourceMap` types `x_google_ignoreList` as `void`, which +// doesn't match the runtime data, so we define our own shape covering +// what `composeSourceMaps` actually reads and writes. +export interface ComposableSourceMap { + version: number; + file?: string; + mappings: string; + names: string[]; + sources: (string | null)[]; + sourcesContent?: (string | null)[]; + sourceRoot?: string; + ignoreList?: number[]; + x_google_ignoreList?: number[]; + x_hermes_function_offsets?: HermesFunctionOffsets; +} + +// `@jridgewell/remapping`'s CJS types use `export = function remapping(...)`, +// which TypeScript 6 rejects as a syntax error — load via `require()` and +// declare the function shape locally. +interface RemappingResult { + version: 3; + file?: string | null; + mappings: string; + names: string[]; + sources: (string | null)[]; + sourcesContent?: (string | null)[]; + sourceRoot?: string; + ignoreList?: number[]; +} + +type RemappingLoader = (file: string) => unknown; +type Remapping = (input: unknown, loader: RemappingLoader) => RemappingResult; + +let _remapping: Remapping | undefined; +function loadRemapping(): Remapping { + if (!_remapping) { + _remapping = require('@jridgewell/remapping'); + } + return _remapping!; +} + +// NOTE(@kitten): @jridgewell/gen-mapping has no streaming encoder — its +// `addSegment` buffers every segment into `_mappings` until +// `toEncodedMap` runs VLQ encoding at the end (~100 MB transient on a +// large bundle). Metro's own `Generator` is already a streaming VLQ +// encoder, so peak memory stays at roughly the size of the final +// `mappings` string. We use it directly here. + +type GeneratorCtor = new () => GeneratorClass; + +let _Generator: GeneratorCtor | undefined; +function loadGenerator(): GeneratorCtor { + if (!_Generator) { + _Generator = require('@expo/metro/metro-source-map/Generator').default; + } + return _Generator!; +} + +// `.js` suffix required for jest's resolver to find the file under +// `@expo/metro`'s `exports` map (see `getCssDeps.ts`/`getAssets.ts` for +// the same pattern). +type IsJsModule = typeof import('@expo/metro/metro/DeltaBundler/Serializers/helpers/js').isJsModule; + +let _isJsModule: IsJsModule | undefined; +function loadMetroSerializerHelpers(): { isJsModule: IsJsModule } { + if (!_isJsModule) { + _isJsModule = require('@expo/metro/metro/DeltaBundler/Serializers/helpers/js.js').isJsModule; + } + return { isJsModule: _isJsModule! }; +} + +function feedModuleSegments( + generator: GeneratorClass, + tuples: readonly MetroSourceMapSegmentTuple[], + carryOver: number +): void { + for (let i = 0, n = tuples.length; i < n; i++) { + const tuple = tuples[i]!; + const line = tuple[0] + carryOver; + const column = tuple[1]; + if (tuple.length === 2) { + generator.addSimpleMapping(line, column); + } else if (tuple.length === 4) { + generator.addSourceMapping(line, column, tuple[2], tuple[3]); + } else { + generator.addNamedSourceMapping(line, column, tuple[2], tuple[3], tuple[4]); + } + } +} + +// Encoder fast path: read the `Int32Array` directly, skipping the Proxy +// and the tuple-per-segment allocation that Proxy iteration would incur. +// Without this, encoding a large bundle would allocate millions of +// transient tuples per pass — defeating the in-memory storage win. +function feedModuleSegmentsPacked( + generator: GeneratorClass, + packed: PackedMap, + carryOver: number +): void { + const buf = packed.buf; + const names = packed.names; + const count = packed.count; + for (let i = 0; i < count; i++) { + const off = i * STRIDE; + const line = buf[off]! + carryOver; + const column = buf[off + 1]!; + const srcLine = buf[off + 2]!; + if (srcLine === SENTINEL) { + generator.addSimpleMapping(line, column); + continue; + } + const srcCol = buf[off + 3]!; + const nameIdx = buf[off + 4]!; + if (nameIdx === SENTINEL) { + generator.addSourceMapping(line, column, srcLine, srcCol); + } else { + generator.addNamedSourceMapping(line, column, srcLine, srcCol, names[nameIdx]!); + } + } +} + +// Inlined rather than going through Metro's `getSourceMapInfo` because +// it spreads `data` and drops the non-enumerable `__packedMap`, +// silently forcing the encoder onto the slow Proxy path. +function readSourceMapInfo( + module: Module, + options: SourceMapGeneratorOptions +): { + path: string; + source: string; + functionMap: FBSourceFunctionMap | null | undefined; + isIgnored: boolean; + map: ModuleSourceMap | null | undefined; + packed: PackedMap | undefined; + lineCount: number; +} { + const data = getModuleJsData(module); + // Don't read `data.map` when `__packedMap` is set — `data.map` is a + // lazy accessor that materializes the Proxy on first read, and the + // fast path below doesn't need it. + let packed = data.data.__packedMap; + let map: ModuleSourceMap | null | undefined; + if (!packed) { + map = data.data.map; + // Self-heal a `SerializableSourceMap` `data.map` that bypassed the wrapper. + if (isSerializableSourceMap(map)) { + packed = PackedMap.deserialize(map); + map = undefined; + } + } + return { + path: options.getSourceUrl?.(module) ?? module.path, + source: + options.excludeSource || data.type === 'js/module/asset' ? '' : module.getSource().toString(), + functionMap: data.data.functionMap, + isIgnored: options.shouldAddToIgnoreList(module), + map, + packed, + lineCount: data.data.lineCount, + }; +} + +function getModuleJsData(module: Module): { data: JsOutputData; type: string } { + for (const out of module.output) { + const type = (out as { type?: string }).type; + if (typeof type === 'string' && type.startsWith('js/')) { + return out as { data: JsOutputData; type: string }; + } + } + throw new Error( + `[expo-metro-config] Module "${module.path}" has no JS output. Cannot build a sourcemap entry.` + ); +} + +// Local shape rather than importing from `jsOutput.ts` to avoid a cycle +// through the transformer. +interface JsOutputData { + code: string; + lineCount: number; + map: ModuleSourceMap | null | undefined; + functionMap: FBSourceFunctionMap | null | undefined; + readonly __packedMap?: PackedMap; +} + +function processModuleIntoGenerator( + generator: GeneratorClass, + module: Module, + options: SourceMapGeneratorOptions, + carryOver: number +): number { + const info = readSourceMapInfo(module, options); + generator.startFile(info.path, info.source, info.functionMap ?? null, { + addToIgnoreList: info.isIgnored, + }); + if (info.packed) { + feedModuleSegmentsPacked(generator, info.packed, carryOver); + } else if (Array.isArray(info.map)) { + // Legacy plain-tuple path — hits for cache entries written before + // `data.map` switched to `SerializableSourceMap`, and for modules from custom + // transformers that don't emit packed format. + feedModuleSegments(generator, info.map, carryOver); + } + generator.endFile(); + return carryOver + info.lineCount; +} + +function filterModules( + modules: readonly Module[], + processModuleFilter: SourceMapGeneratorOptions['processModuleFilter'] +): Module[] { + const { isJsModule } = loadMetroSerializerHelpers(); + const out: Module[] = []; + for (const m of modules) { + if (isJsModule(m) && processModuleFilter(m)) { + out.push(m); + } + } + return out; +} + +// Adds `debugId`, which is emitted during JSON construction so callers +// don't pay for a parse + re-stringify roundtrip on a freshly-built +// sourcemap. +export interface ExpoSourceMapOptions extends SourceMapGeneratorOptions { + debugId?: string; +} + +// Splice `,"debugId":"..."` in front of the trailing `}` of an already +// JSON-encoded sourcemap. Used for Hermes output where we don't control +// the JSON producer. +export function appendDebugIdToSourceMap(sourceMap: string, debugId: string): string { + return sourceMap.slice(0, -1) + `,"debugId":${JSON.stringify(debugId)}}`; +} + +function emitGeneratorJson(generator: GeneratorClass, options: ExpoSourceMapOptions): string { + const json = generator.toString(undefined, { excludeSource: options.excludeSource }); + return options.debugId ? appendDebugIdToSourceMap(json, options.debugId) : json; +} + +export function sourceMapString(modules: readonly Module[], options: ExpoSourceMapOptions): string { + const Generator = loadGenerator(); + const generator = new Generator(); + const filtered = filterModules(modules, options.processModuleFilter); + let carryOver = 0; + for (const mod of filtered) { + carryOver = processModuleIntoGenerator(generator, mod, options, carryOver); + } + return emitGeneratorJson(generator, options); +} + +// Yields back to the event loop every ~50 ms so the node server stays +// responsive on very large bundles. Matches Metro's `getSourceMapInfosImpl` +// pacing. +export async function sourceMapStringNonBlocking( + modules: readonly Module[], + options: ExpoSourceMapOptions +): Promise { + const Generator = loadGenerator(); + const generator = new Generator(); + const filtered = filterModules(modules, options.processModuleFilter); + + const NS_IN_MS = 1_000_000; + const SLICE_NS = 50 * NS_IN_MS; + let carryOver = 0; + let i = 0; + + await new Promise((resolve) => { + const tick = () => { + const start = process.hrtime(); + while (i < filtered.length) { + carryOver = processModuleIntoGenerator(generator, filtered[i]!, options, carryOver); + i++; + const diff = process.hrtime(start); + if (diff[1] > SLICE_NS || diff[0] > 0) { + setImmediate(tick); + return; + } + } + resolve(); + }; + tick(); + }); + + return emitGeneratorJson(generator, options); +} + +// Metro's `Server._processSourceMapRequest` calls +// `sourceMapStringNonBlocking` directly, bypassing the `customSerializer` +// chain — so without rerouting it, every dev `.map` fetch iterates the +// `data.map` Proxy and the encoder fast path is unreachable. +export function patchMetroSourceMapStringForPackedMaps(): void { + const stock = require('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString'); + stock.sourceMapString = sourceMapString; + stock.sourceMapStringNonBlocking = sourceMapStringNonBlocking; +} + +// `maps[0]` is the original-most transform; `maps[maps.length - 1]` is +// the most recent. Built on `@jridgewell/remapping` instead of mozilla's +// `SourceMapConsumer`-based composer. +// +// Two shims around remapping: +// - Translate `x_google_ignoreList` to the standard `ignoreList` on +// each input. Metro's `Generator` emits only the legacy alias, but +// remapping's `TraceMap` reads only the standard field, so without +// this ignore-list info disappears across compose. +// - Carry over `x_hermes_function_offsets` (load-bearing for Hermes +// bytecode-frame symbolication) and re-emit the legacy +// `x_google_ignoreList` alias for devtools that haven't yet picked up +// the rename. +// +// `x_facebook_sources` is deliberately dropped — Expo doesn't ship to FB +// symbolicators. +export function composeSourceMaps(maps: readonly ComposableSourceMap[]): ComposableSourceMap { + if (maps.length < 1) { + throw new Error('composeSourceMaps: Expected at least one map'); + } + + const normalized = maps.map((map) => { + if (map.ignoreList || !map.x_google_ignoreList) { + return map; + } + return { ...map, ignoreList: map.x_google_ignoreList }; + }); + + // Metro convention is original-first; remapping is most-recent first. + const reversed = normalized.slice().reverse(); + + const composed = loadRemapping()(reversed, () => null); + + // Re-emit as a plain object — remapping returns a `SourceMap` class + // instance, which doesn't round-trip JSON cleanly. + const result: ComposableSourceMap = { + version: composed.version, + mappings: composed.mappings as string, + names: composed.names, + sources: composed.sources, + }; + if (composed.file != null) { + result.file = composed.file; + } + if (composed.sourceRoot != null) { + result.sourceRoot = composed.sourceRoot; + } + if (composed.sourcesContent) { + result.sourcesContent = composed.sourcesContent; + } + + // Required by Hermes for bytecode-frame symbolication. Lives on the + // most-recent map (the Hermes map) and passes through unchanged. + const last = maps[maps.length - 1]!; + if (last.x_hermes_function_offsets) { + result.x_hermes_function_offsets = last.x_hermes_function_offsets; + } + + // Emit both standard and legacy keys so devtools either side of the + // rename keep working. + if (composed.ignoreList && composed.ignoreList.length > 0) { + result.ignoreList = composed.ignoreList; + result.x_google_ignoreList = composed.ignoreList; + } + + return result; +} + +// Replaces the mozilla `source-map` round-trip the worker would +// otherwise do for the encoded sourcemap fed into a minifier. +type GenMappingModule = typeof import('@jridgewell/gen-mapping'); + +let _genMapping: GenMappingModule | undefined; +function loadGenMapping(): GenMappingModule { + if (!_genMapping) { + _genMapping = require('@jridgewell/gen-mapping'); + } + return _genMapping!; +} + +// Matches what `metro-minify-terser` (and equivalents) accept as their +// `map` input — nullable fields from `gen-mapping.toEncodedMap` are +// normalized away. +export interface EncodedTransformerSourceMap { + version: 3; + file?: string; + mappings: string; + names: string[]; + sources: string[]; + sourcesContent?: (string | null)[]; +} + +// Convert Babel's `result.rawMappings` directly to an encoded sourcemap +// for feeding into a minifier. `BabelSourceMapSegment` lines are +// 1-based; `gen-mapping`'s `addSegment` is 0-based — subtract 1 at the +// boundary. Skipping a tuple intermediate avoids one Array allocation +// per segment. +export function rawMappingsToEncodedMap(opts: { + filename: string; + source: string; + rawMappings: readonly BabelSourceMapSegment[]; +}): EncodedTransformerSourceMap { + const { GenMapping, addSegment, setSourceContent, toEncodedMap } = loadGenMapping(); + const map = new GenMapping({ file: opts.filename }); + setSourceContent(map, opts.filename, opts.source); + + for (const m of opts.rawMappings) { + const genLine = m.generated.line - 1; + const genCol = m.generated.column; + if (m.original == null) { + addSegment(map, genLine, genCol); + } else if (typeof m.name !== 'string') { + addSegment(map, genLine, genCol, opts.filename, m.original.line - 1, m.original.column); + } else { + addSegment( + map, + genLine, + genCol, + opts.filename, + m.original.line - 1, + m.original.column, + m.name + ); + } + } + + const encoded = toEncodedMap(map); + // gen-mapping always registers `opts.filename` as the single source, so + // hard-coding avoids a `.map(...)` allocation and a `(string | null)[]` + // narrowing. + return { + version: encoded.version, + file: encoded.file ?? undefined, + mappings: encoded.mappings, + names: encoded.names as string[], + sources: [opts.filename], + sourcesContent: encoded.sourcesContent as (string | null)[] | undefined, + }; +} diff --git a/packages/@expo/metro-config/src/serializer/withExpoSerializers.ts b/packages/@expo/metro-config/src/serializer/withExpoSerializers.ts index a80f9df7883a80..83a24a6f6d64e2 100644 --- a/packages/@expo/metro-config/src/serializer/withExpoSerializers.ts +++ b/packages/@expo/metro-config/src/serializer/withExpoSerializers.ts @@ -18,20 +18,11 @@ import { } from './environmentVariableSerializerPlugin'; import type { ExpoSerializerOptions } from './fork/baseJSBundle'; import { getSortedModules, graphToSerialAssetsAsync } from './serializeChunks'; +import { sourceMapString } from './sourceMap'; import { env } from '../env'; export type { SerialAsset } from './serializerAssets'; -// Lazy-loaded to avoid pulling in metro-source-map and @babel/traverse at startup (~100ms savings) -let _sourceMapString: typeof import('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString').sourceMapString; -function getSourceMapString() { - if (!_sourceMapString) { - _sourceMapString = - require('@expo/metro/metro/DeltaBundler/Serializers/sourceMapString').sourceMapString; - } - return _sourceMapString; -} - // Lazy-loaded to avoid pulling in @babel/generator, @babel/core at startup let _reconcileTransformSerializerPlugin: typeof import('./reconcileTransformSerializerPlugin').reconcileTransformSerializerPlugin; function getReconcileTransformSerializerPlugin() { @@ -50,7 +41,7 @@ function getTreeShakeSerializer() { return _treeShakeSerializer; } -// Lazy-loaded to avoid pulling in metro's getAppendScripts -> sourceMapString chain at startup +// Lazy-loaded to avoid pulling in metro's getAppendScripts at startup let _baseJSBundle: typeof import('./fork/baseJSBundle').baseJSBundle; function getBaseJSBundle() { if (!_baseJSBundle) { @@ -211,7 +202,7 @@ export function createDefaultExportCustomSerializer( } const getEnsuredMaps = () => { - bundleMap ??= getSourceMapString()( + bundleMap ??= sourceMapString( [...premodulesToBundle, ...getSortedModules([...graph.dependencies.values()], options)], { excludeSource: options.serializerOptions?.excludeSource ?? false, diff --git a/packages/@expo/metro-config/src/transform-worker/__tests__/metro-transform-worker.test.ts b/packages/@expo/metro-config/src/transform-worker/__tests__/metro-transform-worker.test.ts index 9b68d524d613da..b0f2d949179175 100644 --- a/packages/@expo/metro-config/src/transform-worker/__tests__/metro-transform-worker.test.ts +++ b/packages/@expo/metro-config/src/transform-worker/__tests__/metro-transform-worker.test.ts @@ -10,20 +10,21 @@ */ import { fromRawMappings } from '@expo/metro/metro-source-map'; -import type { - JsTransformerConfig, - JsTransformOptions, - JsOutput, -} from '@expo/metro/metro-transform-worker'; +import type { JsTransformerConfig, JsTransformOptions } from '@expo/metro/metro-transform-worker'; import { TraceMap, originalPositionFor, generatedPositionFor } from '@jridgewell/trace-mapping'; import { Buffer } from 'buffer'; import * as fs from 'fs'; import { vol } from 'memfs'; import * as path from 'path'; +import type { ExpoJsOutput } from '../../serializer/jsOutput'; +import { materializeMap } from '../../serializer/packedMap'; + /** Converts source mappings from Metro to a “TraceMap”, which is similar to source-map’s SourceMapConsumer */ -const toTraceMap = (output: JsOutput, contents: string) => { - const map = fromRawMappings([output.data]).toMap(); +const toTraceMap = (output: ExpoJsOutput, contents: string) => { + // `fromRawMappings` needs plain tuples; the worker emits the packed + // wire shape, so materialize at the boundary. + const map = fromRawMappings([{ ...output.data, map: materializeMap(output.data.map) }]).toMap(); return new TraceMap({ ...map, file: output.data.code, diff --git a/packages/@expo/metro-config/src/transform-worker/count-lines.ts b/packages/@expo/metro-config/src/transform-worker/count-lines.ts deleted file mode 100644 index b8395ff77550ad..00000000000000 --- a/packages/@expo/metro-config/src/transform-worker/count-lines.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright 2024-present 650 Industries (Expo). All rights reserved. - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * https://github.com/facebook/metro/blob/96c6b893eb77b5929b6050d7189905232ddf6d6d/packages/metro-transform-worker/src/index.js#L679 - */ - -import type { MetroSourceMapSegmentTuple } from '@expo/metro/metro-source-map'; - -export function countLinesAndTerminateMap( - code: string, - map: readonly MetroSourceMapSegmentTuple[] -): { - lineCount: number; - map: MetroSourceMapSegmentTuple[]; -} { - const NEWLINE = /\r\n?|\n|\u2028|\u2029/g; - let lineCount = 1; - let lastLineStart = 0; - - // Count lines and keep track of where the last line starts - for (const match of code.matchAll(NEWLINE)) { - if (match.index == null) continue; - lineCount++; - lastLineStart = match.index + match[0].length; - } - const lastLineLength = code.length - lastLineStart; - const lastLineIndex1Based = lineCount; - const lastLineNextColumn0Based = lastLineLength; - - // If there isn't a mapping at one-past-the-last column of the last line, - // add one that maps to nothing. This ensures out-of-bounds lookups hit the - // null mapping rather than aliasing to whichever mapping happens to be last. - // ASSUMPTION: Mappings are generated in order of increasing line and column. - const lastMapping = map[map.length - 1]; - const terminatingMapping: [number, number] = [lastLineIndex1Based, lastLineNextColumn0Based]; - if ( - !lastMapping || - lastMapping[0] !== terminatingMapping[0] || - lastMapping[1] !== terminatingMapping[1] - ) { - return { - lineCount, - map: map.concat([terminatingMapping]), - }; - } - return { lineCount, map: [...map] }; -} diff --git a/packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts b/packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts index 06af106b1f7e5a..4aab3652868de2 100644 --- a/packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts +++ b/packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts @@ -20,13 +20,8 @@ import { import type { BabelTransformer, BabelTransformerArgs } from '@expo/metro/metro-babel-transformer'; import { stableHash } from '@expo/metro/metro-cache'; import { getCacheKey as getMetroCacheKey } from '@expo/metro/metro-cache-key'; -import { - fromRawMappings, - functionMapBabelPlugin, - toBabelSegments, - toSegmentTuple, -} from '@expo/metro/metro-source-map'; -import type { FBSourceFunctionMap, MetroSourceMapSegmentTuple } from '@expo/metro/metro-source-map'; +import { functionMapBabelPlugin } from '@expo/metro/metro-source-map'; +import type { FBSourceFunctionMap } from '@expo/metro/metro-source-map'; import * as metroTransformPlugins from '@expo/metro/metro-transform-plugins'; import type { JsTransformerConfig, @@ -47,9 +42,16 @@ import type { import collectDependencies, { InvalidRequireCallError as InternalInvalidRequireCallError, } from './collect-dependencies'; -import { countLinesAndTerminateMap } from './count-lines'; import { shouldMinify } from './resolveOptions'; import type { ExpoJsOutput, ReconcileTransformSettings } from '../serializer/jsOutput'; +import { + countLinesAndTerminateSourceMap, + emptySourceMap, + packDecodedMappings, + packRawMappings, + type SerializableSourceMap, +} from '../serializer/packedMap'; +import { rawMappingsToEncodedMap, type BabelSourceMapSegment } from '../serializer/sourceMap'; import { importExportPlugin, importExportLiveBindingsPlugin } from '../transform-plugins'; import { getMinifier, resolveMinifier } from './utils/getMinifier'; @@ -134,24 +136,13 @@ export const minifyCode = async ( filename: string, code: string, source: string, - map: MetroSourceMapSegmentTuple[], + rawMappings: readonly BabelSourceMapSegment[], reserved: string[] = [] ): Promise<{ code: string; - map: MetroSourceMapSegmentTuple[]; + sourceMap: SerializableSourceMap; }> => { - const sourceMap = fromRawMappings([ - { - code, - source, - map, - // functionMap is overridden by the serializer - functionMap: null, - path: filename, - // isIgnored is overriden by the serializer - isIgnored: false, - }, - ]).toMap(undefined, {}); + const sourceMap = rawMappingsToEncodedMap({ filename, source, rawMappings }); const minify = getMinifier(config.minifierPath); @@ -166,7 +157,9 @@ export const minifyCode = async ( return { code: minified.code, - map: minified.map ? toBabelSegments(minified.map).map(toSegmentTuple) : [], + sourceMap: minified.map + ? packDecodedMappings({ mappings: minified.map.mappings, names: minified.map.names }) + : emptySourceMap(), }; } catch (error: any) { if (error.constructor.name === 'JS_Parse_Error') { @@ -514,20 +507,25 @@ async function transformJS( file.code ); - // NOTE: incorrectly typed upstream - let map = (result as any)?.rawMappings.map(toSegmentTuple) ?? []; + // `rawMappings` is omitted from `@types/babel__generator`'s + // `GeneratorResult`, but Babel emits it whenever `sourceMaps: true`. + const rawMappings = + (result as { rawMappings?: BabelSourceMapSegment[] } | null)?.rawMappings ?? []; let code = result.code; + let sourceMap: SerializableSourceMap; // NOTE: We might want to enable this on native + hermes when tree shaking is enabled. if (minify) { - ({ map, code } = await minifyCode( + ({ sourceMap, code } = await minifyCode( config, file.filename, result.code, file.code, - map, + rawMappings, reserved )); + } else { + sourceMap = packRawMappings(rawMappings); } const possibleReconcile: ReconcileTransformSettings | undefined = @@ -554,7 +552,7 @@ async function transformJS( : undefined; let lineCount; - ({ lineCount, map } = countLinesAndTerminateMap(code, map)); + ({ lineCount, sourceMap } = countLinesAndTerminateSourceMap(code, sourceMap)); // Clean the AST for tree shaking by stripping non-serializable values (Symbols, functions, etc.) // that React Compiler and other Babel plugins may add. @@ -563,7 +561,11 @@ async function transformJS( data: { code, lineCount, - map, + // Reconcile re-runs Babel codegen and replaces `data.map` via + // `installPackedMap` before any reader sees it, so the sourceMap emitted + // here would be discarded — short-circuit to an empty Array to skip + // the work and avoid GC pressure on optimize builds. + map: possibleReconcile ? [] : sourceMap, functionMap: file.functionMap, hasCjsExports: file.hasCjsExports, reactServerReference: file.reactServerReference, @@ -699,12 +701,12 @@ async function transformJSON( config.unstable_disableModuleWrapping === true ? JsFileWrapping.jsonToCommonJS(file.code) : JsFileWrapping.wrapJson(file.code, config.globalPrefix); - let map: MetroSourceMapSegmentTuple[] = []; + let sourceMap: SerializableSourceMap = emptySourceMap(); const minify = shouldMinify(options); if (minify) { - ({ map, code } = await minifyCode(config, file.filename, code, file.code, map)); + ({ sourceMap, code } = await minifyCode(config, file.filename, code, file.code, [])); } let jsType: JSFileType; @@ -718,11 +720,11 @@ async function transformJSON( } let lineCount; - ({ lineCount, map } = countLinesAndTerminateMap(code, map)); + ({ lineCount, sourceMap } = countLinesAndTerminateSourceMap(code, sourceMap)); const output: ExpoJsOutput[] = [ { - data: { code, lineCount, map, functionMap: null }, + data: { code, lineCount, map: sourceMap, functionMap: null }, type: jsType, }, ]; @@ -821,6 +823,10 @@ export async function transform( return transformJSWithBabel(file, context); } +// NOTE: Increment if cache becomes incompatible (original value would be '') +// 1. Added new packed source map format +const CACHE_VERSION = '1'; + export function getCacheKey( config: JsTransformerConfig, opts?: Readonly<{ projectRoot: string }> @@ -864,9 +870,12 @@ export function getCacheKey( }) : ''; - return [filesKey, stableHash(remainingConfig).toString('hex'), babelTransformerCacheKey].join( - '$' - ); + const keyParts: string[] = []; + if (CACHE_VERSION) { + keyParts.push(CACHE_VERSION); + } + keyParts.push(filesKey, stableHash(remainingConfig).toString('hex'), babelTransformerCacheKey); + return keyParts.join('$'); } /** diff --git a/packages/@expo/metro-config/src/transform-worker/transform-worker.ts b/packages/@expo/metro-config/src/transform-worker/transform-worker.ts index 1f36ad7d5b0282..2ac492a49f3068 100644 --- a/packages/@expo/metro-config/src/transform-worker/transform-worker.ts +++ b/packages/@expo/metro-config/src/transform-worker/transform-worker.ts @@ -8,11 +8,7 @@ import type { TransformResultDependency } from '@expo/metro/metro/DeltaBundler'; import countLines from '@expo/metro/metro/lib/countLines'; -import type { - JsTransformerConfig, - JsTransformOptions, - JsOutput, -} from '@expo/metro/metro-transform-worker'; +import type { JsTransformerConfig, JsTransformOptions } from '@expo/metro/metro-transform-worker'; import { relative, dirname } from 'node:path'; import { getBrowserslistTargets } from './browserslist'; @@ -32,7 +28,11 @@ import { toPosixPath } from '../utils/filePath'; export interface TransformResponse { readonly dependencies: readonly TransformResultDependency[]; - readonly output: readonly JsOutput[]; + // `ExpoJsOutput` widens `data.map` to `SerializableSourceMap | + // MetroSourceMapSegmentTuple[]`. Metro readers still see plain tuples + // because the `Bundler.transformFile` wrapper swaps the + // `SerializableSourceMap` for an `Array.isArray`-true Proxy first. + readonly output: readonly ExpoJsOutput[]; } const debug = require('debug')('expo:metro-config:transform-worker') as typeof console.log; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8a68832fe392cf..4c99549cc647a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2535,6 +2535,15 @@ importers: '@expo/spawn-async': specifier: ^1.7.2 version: 1.7.2 + '@jridgewell/gen-mapping': + specifier: ^0.3.13 + version: 0.3.13 + '@jridgewell/remapping': + specifier: ^2.3.5 + version: 2.3.5 + '@jridgewell/sourcemap-codec': + specifier: ^1.5.5 + version: 1.5.5 browserslist: specifier: ^4.25.0 version: 4.28.2 @@ -2570,7 +2579,7 @@ importers: version: 5.0.0 devDependencies: '@jridgewell/trace-mapping': - specifier: ^0.3.20 + specifier: ^0.3.31 version: 0.3.31 '@types/babel__code-frame': specifier: ^7.27.0 From c986f2824a9b41d9decc5d09c57b14906becd977 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 11 May 2026 18:20:13 +0100 Subject: [PATCH 04/15] chore(metro-config): Upgrade to `postcss@^8.5.14` and add missing postcss config caching (#45626) # Why Supersedes #45622 Supersedes #45076 We seemingly can safely upgrade to `postcss@^8.5.14`. We're not affected by the CVE, but this has a few parser performance fixes. We can also take this opportunity to in-memory cache the config and pipeline, and test this during the beta. # How - Upgrade to `postcss@^8.5.14` - Memoize the config and pipeline # Test Plan - CI tests should pass unchanged # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/@expo/metro-config/CHANGELOG.md | 2 + .../build/transform-worker/postcss.js | 56 ++++++++------ .../build/transform-worker/postcss.js.map | 2 +- packages/@expo/metro-config/package.json | 2 +- .../src/transform-worker/postcss.ts | 74 +++++++++++-------- pnpm-lock.yaml | 18 ++++- 6 files changed, 96 insertions(+), 58 deletions(-) diff --git a/packages/@expo/metro-config/CHANGELOG.md b/packages/@expo/metro-config/CHANGELOG.md index fbcc8d2ae6ea7a..4914fb46b1cf16 100644 --- a/packages/@expo/metro-config/CHANGELOG.md +++ b/packages/@expo/metro-config/CHANGELOG.md @@ -12,6 +12,8 @@ ### 💡 Others +- Bump to `postcss@^8.5.14` ([#45626](https://github.com/expo/expo/pull/45626) by [@kitten](https://github.com/kitten)) + ## 56.0.5 — 2026-05-08 ### 💡 Others diff --git a/packages/@expo/metro-config/build/transform-worker/postcss.js b/packages/@expo/metro-config/build/transform-worker/postcss.js index 4cecc6d5e9dd8e..802e717253a60f 100644 --- a/packages/@expo/metro-config/build/transform-worker/postcss.js +++ b/packages/@expo/metro-config/build/transform-worker/postcss.js @@ -20,32 +20,44 @@ const resolve_from_1 = __importDefault(require("resolve-from")); const require_1 = require("./utils/require"); const CONFIG_FILE_NAME = 'postcss.config'; const debug = require('debug')('expo:metro:transformer:postcss'); +const loadPostcssPipelineAsync = (function () { + let promise = null; + return function _loadPostcssPipelineAsync(projectRoot) { + if (promise == null) { + promise = (async () => { + const inputConfig = await resolvePostcssConfig(projectRoot); + if (!inputConfig) + return null; + const { plugins, processOptions } = await parsePostcssConfigAsync(projectRoot, { + config: inputConfig, + resourcePath: projectRoot, + }); + debug('options:', processOptions); + debug('plugins:', plugins); + const postcss = require('postcss'); + const { from: _from, to: _to, map: _map, ...baseOptions } = processOptions; + return { + processor: postcss.default(plugins), + baseOptions, + emitMap: inputConfig.map === true, + }; + })(); + } + return promise; + }; +})(); async function transformPostCssModule(projectRoot, { src, filename }) { - const inputConfig = await resolvePostcssConfig(projectRoot); - if (!inputConfig) { + const pipeline = await loadPostcssPipelineAsync(projectRoot); + if (!pipeline) { return { src, hasPostcss: false }; } - return { - src: await processWithPostcssInputConfigAsync(projectRoot, { - inputConfig, - src, - filename, - }), - hasPostcss: true, - }; -} -async function processWithPostcssInputConfigAsync(projectRoot, { src, filename, inputConfig }) { - const { plugins, processOptions } = await parsePostcssConfigAsync(projectRoot, { - config: inputConfig, - resourcePath: filename, + const { content } = await pipeline.processor.process(src, { + ...pipeline.baseOptions, + from: filename, + to: filename, + map: pipeline.emitMap ? { inline: true } : false, }); - debug('options:', processOptions); - debug('plugins:', plugins); - // TODO: Surely this can be cached... - const postcss = require('postcss'); - const processor = postcss.default(plugins); - const { content } = await processor.process(src, processOptions); - return content; + return { src: content, hasPostcss: true }; } async function parsePostcssConfigAsync(projectRoot, { resourcePath: file, config: { plugins: inputPlugins, map, parser, stringifier, syntax, ...config } = {}, }) { const factory = pluginFactory(); diff --git a/packages/@expo/metro-config/build/transform-worker/postcss.js.map b/packages/@expo/metro-config/build/transform-worker/postcss.js.map index 3b5401c321e8b7..b0f8036da9a1eb 100644 --- a/packages/@expo/metro-config/build/transform-worker/postcss.js.map +++ b/packages/@expo/metro-config/build/transform-worker/postcss.js.map @@ -1 +1 @@ -{"version":3,"file":"postcss.js","sourceRoot":"","sources":["../../src/transform-worker/postcss.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"postcss.js","sourceRoot":"","sources":["../../src/transform-worker/postcss.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/metro-config/package.json b/packages/@expo/metro-config/package.json index f4b30716da90cc..34e7a73f93a706 100644 --- a/packages/@expo/metro-config/package.json +++ b/packages/@expo/metro-config/package.json @@ -82,7 +82,7 @@ "jsc-safe-url": "^0.2.4", "lightningcss": "^1.30.1", "picomatch": "^4.0.3", - "postcss": "~8.4.32", + "postcss": "^8.5.14", "resolve-from": "^5.0.0" }, "peerDependencies": { diff --git a/packages/@expo/metro-config/src/transform-worker/postcss.ts b/packages/@expo/metro-config/src/transform-worker/postcss.ts index f490cb3d0d36a5..f538a8166d365a 100644 --- a/packages/@expo/metro-config/src/transform-worker/postcss.ts +++ b/packages/@expo/metro-config/src/transform-worker/postcss.ts @@ -7,7 +7,7 @@ import JsonFile from '@expo/json-file'; import fs from 'fs'; import path from 'path'; -import type { AcceptedPlugin, ProcessOptions } from 'postcss'; +import type { AcceptedPlugin, ProcessOptions, Processor } from 'postcss'; import resolveFrom from 'resolve-from'; import { tryRequireThenImport } from './utils/require'; @@ -26,44 +26,58 @@ const CONFIG_FILE_NAME = 'postcss.config'; const debug = require('debug')('expo:metro:transformer:postcss'); +interface LoadedPipeline { + processor: Processor; + baseOptions: Omit; + emitMap: boolean; +} + +const loadPostcssPipelineAsync = (function () { + let promise: Promise | null = null; + return function _loadPostcssPipelineAsync(projectRoot: string) { + if (promise == null) { + promise = (async () => { + const inputConfig = await resolvePostcssConfig(projectRoot); + if (!inputConfig) return null; + + const { plugins, processOptions } = await parsePostcssConfigAsync(projectRoot, { + config: inputConfig, + resourcePath: projectRoot, + }); + + debug('options:', processOptions); + debug('plugins:', plugins); + + const postcss = require('postcss') as typeof import('postcss'); + const { from: _from, to: _to, map: _map, ...baseOptions } = processOptions; + return { + processor: postcss.default(plugins), + baseOptions, + emitMap: inputConfig.map === true, + }; + })(); + } + return promise; + }; +})(); + export async function transformPostCssModule( projectRoot: string, { src, filename }: { src: string; filename: string } ): Promise<{ src: string; hasPostcss: boolean }> { - const inputConfig = await resolvePostcssConfig(projectRoot); - if (!inputConfig) { + const pipeline = await loadPostcssPipelineAsync(projectRoot); + if (!pipeline) { return { src, hasPostcss: false }; } - return { - src: await processWithPostcssInputConfigAsync(projectRoot, { - inputConfig, - src, - filename, - }), - hasPostcss: true, - }; -} - -async function processWithPostcssInputConfigAsync( - projectRoot: string, - { src, filename, inputConfig }: { src: string; filename: string; inputConfig: PostCSSInputConfig } -) { - const { plugins, processOptions } = await parsePostcssConfigAsync(projectRoot, { - config: inputConfig, - resourcePath: filename, + const { content } = await pipeline.processor.process(src, { + ...pipeline.baseOptions, + from: filename, + to: filename, + map: pipeline.emitMap ? { inline: true } : false, }); - debug('options:', processOptions); - debug('plugins:', plugins); - - // TODO: Surely this can be cached... - const postcss = require('postcss') as typeof import('postcss'); - - const processor = postcss.default(plugins); - const { content } = await processor.process(src, processOptions); - - return content; + return { src: content, hasPostcss: true }; } async function parsePostcssConfigAsync( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c99549cc647a2..b8fa697af8a1cd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2572,8 +2572,8 @@ importers: specifier: ^4.0.3 version: 4.0.3 postcss: - specifier: ~8.4.32 - version: 8.4.49 + specifier: ^8.5.14 + version: 8.5.14 resolve-from: specifier: ^5.0.0 version: 5.0.0 @@ -13924,6 +13924,10 @@ packages: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + engines: {node: ^10 || ^12 || >=14} + prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} @@ -19513,11 +19517,11 @@ snapshots: '@types/postcss-modules-local-by-default@4.0.2': dependencies: - postcss: 8.4.49 + postcss: 8.5.14 '@types/postcss-modules-scope@3.0.4': dependencies: - postcss: 8.4.49 + postcss: 8.5.14 '@types/probe-image-size@7.2.5': dependencies: @@ -24834,6 +24838,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.14: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prebuild-install@7.1.3: dependencies: detect-libc: 2.1.2 From d427a802b11d79c8e45be8ceb582ca10fae103af Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 11 May 2026 18:21:25 +0100 Subject: [PATCH 05/15] fix(babel-preset-expo): Fix three Hermes v1 (250829098) IR/compiler syntax bugs with fix-up transforms (#45601) # Why Resolves #45592 There's three fixes that have landed in Hermes v1 since the `250829098.x.x` branch cut that can reasonably be triggered by user code. In descending order of likelihood: - https://github.com/facebook/hermes/commit/68bfb3a48b31a19ac904ce6d3174ab2698ffc5e9 - https://github.com/facebook/hermes/commit/18a963465 - https://github.com/facebook/hermes/commit/1e94fbe0e The first issue is very easy to trigger, since it involves any complex parameters for any async arrow function. These commits have been identified in a full diff between `250829098.0.10` and the `static_h` branch on Hermes, and cross-checked against the `250829098.0.0-stable`. There's more fixes that this branch doesn't contain but they either: - aren't relevant for most codebases or are Hermes toolchain fixes - are runtime fixes (unfortunate, but not relevant for Babel) - cannot be fixed or are hard to hit - **apply only to async generators which are already transpiled by our preset** # How We apply three targeted fix-ups in Babel transforms that are targeted to these fixes. They swap out the problematic patterns with working ones. - Add test cases to `test-suite` for failing patterns - Add `fix-hermes-v1-async-arrow-non-simple-params` plugin for Hermes v1 preset - Add `fix-hermes-v1-class-in-finally` plugin for Hermes v1 preset - Add `fix-hermes-v1-super-in-object-accessor` plugin for Hermes v1 preset # Test Plan - Checked fixes against the `test-suite` and confirmed they avoid all three bugs - Added unit tests per Babel plugin with snapshots - Confirmed that transform performance isn't impacted significantly using `node scripts/profile-plugins.js --config hermes-v1` # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- apps/test-suite/TestModules.ts | 1 + apps/test-suite/package.json | 3 +- apps/test-suite/tests/JSAsync.js | 110 ++++++ apps/test-suite/tests/JSAsyncGenerator.js | 100 ++++++ apps/test-suite/tests/JSHermesMisc.js | 317 ++++++++++++++++++ packages/babel-preset-expo/CHANGELOG.md | 4 + .../build/configs/hermes-v1.js | 7 + .../build/configs/hermes-v1.js.map | 2 +- ...rmes-v1-async-arrow-non-simple-params.d.ts | 2 + ...hermes-v1-async-arrow-non-simple-params.js | 57 ++++ ...es-v1-async-arrow-non-simple-params.js.map | 1 + .../fix-hermes-v1-class-in-finally.d.ts | 2 + .../plugins/fix-hermes-v1-class-in-finally.js | 59 ++++ .../fix-hermes-v1-class-in-finally.js.map | 1 + ...ix-hermes-v1-super-in-object-accessor.d.ts | 2 + .../fix-hermes-v1-super-in-object-accessor.js | 58 ++++ ...-hermes-v1-super-in-object-accessor.js.map | 1 + .../src/__tests__/preset-config.test.ts | 6 + .../src/configs/hermes-v1.ts | 9 + ...s-v1-async-arrow-non-simple-params.test.ts | 190 +++++++++++ .../fix-hermes-v1-class-in-finally.test.ts | 160 +++++++++ ...hermes-v1-super-in-object-accessor.test.ts | 145 ++++++++ ...hermes-v1-async-arrow-non-simple-params.ts | 71 ++++ .../plugins/fix-hermes-v1-class-in-finally.ts | 70 ++++ .../fix-hermes-v1-super-in-object-accessor.ts | 57 ++++ pnpm-lock.yaml | 3 + 26 files changed, 1436 insertions(+), 2 deletions(-) create mode 100644 apps/test-suite/tests/JSHermesMisc.js create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.d.ts create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.js create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.js.map create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.d.ts create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.js create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.js.map create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.d.ts create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.js create mode 100644 packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.js.map create mode 100644 packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-async-arrow-non-simple-params.test.ts create mode 100644 packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-class-in-finally.test.ts create mode 100644 packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-super-in-object-accessor.test.ts create mode 100644 packages/babel-preset-expo/src/plugins/fix-hermes-v1-async-arrow-non-simple-params.ts create mode 100644 packages/babel-preset-expo/src/plugins/fix-hermes-v1-class-in-finally.ts create mode 100644 packages/babel-preset-expo/src/plugins/fix-hermes-v1-super-in-object-accessor.ts diff --git a/apps/test-suite/TestModules.ts b/apps/test-suite/TestModules.ts index e0342e8f031e4d..5ed6408390c327 100644 --- a/apps/test-suite/TestModules.ts +++ b/apps/test-suite/TestModules.ts @@ -51,6 +51,7 @@ export function getTestModules() { require('./tests/JSUnicodeRegexes'), require('./tests/JSNullishCoalescing'), require('./tests/JSOptionalChaining'), + require('./tests/JSHermesMisc'), ]; // Expo core modules should run everywhere diff --git a/apps/test-suite/package.json b/apps/test-suite/package.json index ea9d1c1ea06b14..5a2202784d62b6 100644 --- a/apps/test-suite/package.json +++ b/apps/test-suite/package.json @@ -16,6 +16,7 @@ "@expo/vector-icons": "^15.0.2", "@react-native-async-storage/async-storage": "^2.2.0", "@react-navigation/native": "^7.1.33", + "@react-navigation/native-stack": "^7.14.5", "@react-navigation/stack": "^7.8.5", "async-retry": "^1.1.4", "expo": "workspace:*", @@ -81,8 +82,8 @@ }, "devDependencies": { "@types/getenv": "^1.0.0", - "@types/jasmine": "^5.1.15", "@types/invariant": "^2.2.35", + "@types/jasmine": "^5.1.15", "@types/react": "~19.2.0", "@types/semver": "^7.7.1" }, diff --git a/apps/test-suite/tests/JSAsync.js b/apps/test-suite/tests/JSAsync.js index 7453bf22107d2a..c43c01f78cc2a3 100644 --- a/apps/test-suite/tests/JSAsync.js +++ b/apps/test-suite/tests/JSAsync.js @@ -785,5 +785,115 @@ export function test({ describe, it, xit, expect }) { expect(stack.indexOf('buildError') >= 0).toBe(true); }); }); + + describe('destructuring + state lifting', () => { + // See: https://github.com/expo/expo/issues/45592 + it('awaits after destructuring in arrow params', async () => { + const f = async ({ b: _ }) => 42; + const actual = await f({ b: 1 }); + expect(actual).toBe(42); + }); + + it('object destructure with rename', async () => { + const f = async ({ b: x }) => x; + expect(await f({ b: 42 })).toBe(42); + }); + + it('object destructure with default', async () => { + const f = async ({ b = 7 }) => b; + expect(await f({})).toBe(7); + }); + + it('object destructure with rest', async () => { + const f = async ({ a, ...rest }) => rest; + expect(await f({ a: 1, b: 2, c: 3 })).toEqual({ b: 2, c: 3 }); + }); + + it('nested object destructure', async () => { + const f = async ({ a: { b } }) => b; + expect(await f({ a: { b: 42 } })).toBe(42); + }); + + it('array destructure', async () => { + const f = async ([a, b]) => a + b; + expect(await f([1, 2])).toBe(3); + }); + + it('array destructure with rest', async () => { + const f = async ([a, ...rest]) => rest; + expect(await f([1, 2, 3, 4])).toEqual([2, 3, 4]); + }); + + it('async arrow with default-value param', async () => { + const f = async (x = 7) => x; + expect(await f()).toBe(7); + expect(await f(9)).toBe(9); + }); + + it('async arrow with rest param', async () => { + const f = async (...rest) => rest.length; + expect(await f(1, 2, 3)).toBe(3); + }); + + it('value visible through .then()', async () => { + const f = async ({ b: _ }) => 42; + const seen = await new Promise((resolve) => { + f({ b: 1 }).then((v) => resolve(v)); + }); + expect(seen).toBe(42); + }); + + it('value visible through Promise.all', async () => { + const f = async ({ b }) => b; + const results = await Promise.all([f({ b: 1 }), f({ b: 2 }), f({ b: 3 })]); + expect(results).toEqual([1, 2, 3]); + }); + + it('control: async arrow with plain (non-destructured) params', async () => { + const f = async (a, b) => 42; + expect(await f(1, 2)).toBe(42); + }); + + it('control: async function declaration with destructured param', async () => { + async function f({ b }) { + return 42; + } + expect(await f({ b: 1 })).toBe(42); + }); + + it('control: async function expression with destructured param', async () => { + const f = async function ({ b }) { + return 42; + }; + expect(await f({ b: 1 })).toBe(42); + }); + + it('control: class async method with destructured param', async () => { + class C { + async m({ b }) { + return 42; + } + } + expect(await new C().m({ b: 1 })).toBe(42); + }); + + it('control: object shorthand async method with destructured param', async () => { + const o = { + async m({ b }) { + return 42; + }, + }; + expect(await o.m({ b: 1 })).toBe(42); + }); + + it('control: arrow with body destructure (not in params)', async () => { + const f = async (x) => { + const { b } = x; + void b; + return 42; + }; + expect(await f({ b: 1 })).toBe(42); + }); + }); }); } diff --git a/apps/test-suite/tests/JSAsyncGenerator.js b/apps/test-suite/tests/JSAsyncGenerator.js index 34af607d86caf7..5c3514a26fcd69 100644 --- a/apps/test-suite/tests/JSAsyncGenerator.js +++ b/apps/test-suite/tests/JSAsyncGenerator.js @@ -1137,5 +1137,105 @@ export function test({ describe, it, xit, expect }) { } }); }); + + describe('destructuring + state lifting (generators)', () => { + // See: https://github.com/expo/expo/issues/45592 + it('async generator with destructured object param yields binding', async () => { + async function* gen({ b }) { + yield b; + yield b + 1; + } + const g = gen({ b: 41 }); + expect(await g.next()).toEqual({ value: 41, done: false }); + expect(await g.next()).toEqual({ value: 42, done: false }); + expect((await g.next()).done).toBe(true); + }); + + it('async generator with destructured array param', async () => { + async function* gen([a, b]) { + yield a; + yield b; + } + const g = gen([1, 2]); + expect(await g.next()).toEqual({ value: 1, done: false }); + expect(await g.next()).toEqual({ value: 2, done: false }); + }); + + it('async generator with destructured param + internal await', async () => { + async function* gen({ b }) { + const v = await Promise.resolve(b); + yield v; + return v + 1; + } + const g = gen({ b: 41 }); + expect(await g.next()).toEqual({ value: 41, done: false }); + expect(await g.next()).toEqual({ value: 42, done: true }); + }); + + it('async generator with destructured param iterates via for-await-of', async () => { + async function* gen({ b }) { + yield b; + yield b + 1; + } + const collected = []; + for await (const v of gen({ b: 10 })) { + collected.push(v); + } + expect(collected).toEqual([10, 11]); + }); + + it('class async generator method with destructured param', async () => { + class C { + async *gen({ b }) { + yield b; + return b + 1; + } + } + const g = new C().gen({ b: 41 }); + expect(await g.next()).toEqual({ value: 41, done: false }); + expect(await g.next()).toEqual({ value: 42, done: true }); + }); + + it('object shorthand async generator method with destructured param', async () => { + const o = { + async *gen({ b }) { + yield b; + return b + 1; + }, + }; + const g = o.gen({ b: 41 }); + expect(await g.next()).toEqual({ value: 41, done: false }); + expect(await g.next()).toEqual({ value: 42, done: true }); + }); + + it('sync generator with destructured object param yields binding', () => { + function* gen({ b }) { + yield b; + return b + 1; + } + const g = gen({ b: 41 }); + expect(g.next()).toEqual({ value: 41, done: false }); + expect(g.next()).toEqual({ value: 42, done: true }); + }); + + it('control: async generator with plain params', async () => { + async function* gen(a, b) { + yield a; + yield b; + } + const g = gen(1, 2); + expect(await g.next()).toEqual({ value: 1, done: false }); + expect(await g.next()).toEqual({ value: 2, done: false }); + }); + + it('control: async generator destructure in body (not in params)', async () => { + async function* gen(x) { + const { b } = x; + yield b; + } + const g = gen({ b: 42 }); + expect(await g.next()).toEqual({ value: 42, done: false }); + }); + }); }); } diff --git a/apps/test-suite/tests/JSHermesMisc.js b/apps/test-suite/tests/JSHermesMisc.js new file mode 100644 index 00000000000000..66cca92afa9c1f --- /dev/null +++ b/apps/test-suite/tests/JSHermesMisc.js @@ -0,0 +1,317 @@ +/* eslint-disable */ +'use strict'; + +// Regression tests for Hermes V1 IRGen bugs that babel-preset-expo's hermes-v1 profile +// works around with targeted Babel plugins. These cases all execute correctly on a fixed +// Hermes; on the unfixed Hermes shipping with RN 0.85.3 they crash, throw, or miscompile +// unless the workaround plugin is applied. Keep these even after the Hermes bump so a +// future regression in the same trigger surfaces here. + +export const name = 'JS Hermes Misc'; + +export function test({ describe, it, expect }) { + describe('JS Hermes Misc', () => { + describe('class declarations in finally blocks', () => { + // See: facebook/hermes 1e94fbe0e (legacy class internal Variable caching) + it('static field on a class declared in finally', () => { + function f() { + try { + throw 1; + } catch (_) { + } finally { + class C { + static x = 42; + } + return C.x; + } + } + expect(f()).toBe(42); + }); + + it('instance field on a class declared in finally', () => { + function f() { + try { + throw 1; + } catch (_) { + } finally { + class C { + y = 7; + } + return new C().y; + } + } + expect(f()).toBe(7); + }); + + it('private method on a class declared in finally', () => { + function f() { + try { + throw 1; + } catch (_) { + } finally { + class C { + #m() { + return 'private'; + } + call() { + return this.#m(); + } + } + return new C().call(); + } + } + expect(f()).toBe('private'); + }); + + it('class with computed key declared in finally', () => { + function f() { + const k = 'computed'; + try { + throw 1; + } catch (_) { + } finally { + class C { + [k] = 99; + } + return new C().computed; + } + } + expect(f()).toBe(99); + }); + + it('class with extends declared in finally', () => { + class Base { + base() { + return 'base'; + } + } + function f() { + try { + throw 1; + } catch (_) { + } finally { + class C extends Base { + child() { + return 'child'; + } + } + const c = new C(); + return c.base() + ':' + c.child(); + } + } + expect(f()).toBe('base:child'); + }); + + it('multiple classes declared in the same finally', () => { + function f() { + try { + throw 1; + } catch (_) { + } finally { + class A { + tag() { + return 'a'; + } + } + class B extends A { + tag() { + return super.tag() + 'b'; + } + } + return new B().tag(); + } + } + expect(f()).toBe('ab'); + }); + + it('class declared in a nested block inside finally', () => { + function f(cond) { + try { + throw 1; + } catch (_) { + } finally { + if (cond) { + class C { + static v = 'inner'; + } + return C.v; + } + return 'fallback'; + } + } + expect(f(true)).toBe('inner'); + expect(f(false)).toBe('fallback'); + }); + + it('class expression assigned in finally', () => { + function f() { + try { + throw 1; + } catch (_) { + } finally { + const C = class { + static v = 5; + }; + return C.v; + } + } + expect(f()).toBe(5); + }); + + it('control: class outside try/finally', () => { + class C { + static x = 42; + } + expect(C.x).toBe(42); + }); + + it('control: class inside try block (not finally)', () => { + function f() { + try { + class C { + static x = 42; + } + return C.x; + } catch (_) { + return -1; + } + } + expect(f()).toBe(42); + }); + + it('control: class inside catch block (not finally)', () => { + function f() { + try { + throw 1; + } catch (_) { + class C { + static x = 42; + } + return C.x; + } + } + expect(f()).toBe(42); + }); + }); + + describe('super in object literal accessors', () => { + // See: facebook/hermes 18a963465 (genFunctionExpression home object for accessors) + it('non-computed getter reads super', () => { + const o = { + get a() { + return super.m; + }, + }; + Object.setPrototypeOf(o, { m: 12 }); + expect(o.a).toBe(12); + }); + + it('non-computed setter writes super', () => { + const target = { _m: 0 }; + const o = { + set a(v) { + super.m = v; + }, + }; + Object.setPrototypeOf(o, { + set m(v) { + target._m = v; + }, + }); + o.a = 99; + expect(target._m).toBe(99); + }); + + it('non-computed getter with string-literal key reads super', () => { + const o = { + get 'weird key'() { + return super.m; + }, + }; + Object.setPrototypeOf(o, { m: 'ok' }); + expect(o['weird key']).toBe('ok'); + }); + + it('paired getter/setter on the same key', () => { + const store = { _v: 0 }; + const o = { + get a() { + return super.m; + }, + set a(v) { + super.m = v; + }, + }; + Object.setPrototypeOf(o, { + get m() { + return store._v; + }, + set m(v) { + store._v = v; + }, + }); + o.a = 5; + expect(o.a).toBe(5); + expect(store._v).toBe(5); + }); + + it('getter reaches super through a nested arrow', () => { + const o = { + get a() { + return (() => super.m)(); + }, + }; + Object.setPrototypeOf(o, { m: 7 }); + expect(o.a).toBe(7); + }); + + it('control: computed getter with super', () => { + const o = { + get ['a']() { + return super.m; + }, + }; + Object.setPrototypeOf(o, { m: 1 }); + expect(o.a).toBe(1); + }); + + it('control: getter without super', () => { + const o = { + get a() { + return 3; + }, + }; + expect(o.a).toBe(3); + }); + + it('control: class accessor with super', () => { + class Base { + get m() { + return 8; + } + } + class C extends Base { + get a() { + return super.m; + } + } + expect(new C().a).toBe(8); + }); + + it('control: nested object accessor owns its own super', () => { + const o = { + get a() { + return { + get b() { + return super.m; + }, + }; + }, + }; + const inner = o.a; + Object.setPrototypeOf(inner, { m: 4 }); + expect(inner.b).toBe(4); + }); + }); + }); +} diff --git a/packages/babel-preset-expo/CHANGELOG.md b/packages/babel-preset-expo/CHANGELOG.md index 378da1a86d13f0..244d05ebf76695 100644 --- a/packages/babel-preset-expo/CHANGELOG.md +++ b/packages/babel-preset-expo/CHANGELOG.md @@ -8,6 +8,10 @@ ### 🐛 Bug fixes +- Apply fix-up transform for Hermes v1 250829098 resolving undefined for async arrow functions with non-simple params ([#45601](https://github.com/expo/expo/pull/45601) by [@kitten](https://github.com/kitten)) +- Apply fix-up transform for Hermes v1 250829098 misdeclaring classes in finally blocks ([#45601](https://github.com/expo/expo/pull/45601) by [@kitten](https://github.com/kitten)) +- Apply fix-up transform for Hermes v1 250829098 mishandling super.prop accesses in computed object property methods ([#45601](https://github.com/expo/expo/pull/45601) by [@kitten](https://github.com/kitten)) + ### 💡 Others ## 56.0.5 — 2026-05-08 diff --git a/packages/babel-preset-expo/build/configs/hermes-v1.js b/packages/babel-preset-expo/build/configs/hermes-v1.js index c5ea3e2dc90256..f00ac17e58a521 100644 --- a/packages/babel-preset-expo/build/configs/hermes-v1.js +++ b/packages/babel-preset-expo/build/configs/hermes-v1.js @@ -11,11 +11,18 @@ * https://github.com/facebook/react-native/blob/main/packages/react-native-babel-preset/src/configs/main.js */ Object.defineProperty(exports, "__esModule", { value: true }); +const fix_hermes_v1_async_arrow_non_simple_params_1 = require("../plugins/fix-hermes-v1-async-arrow-non-simple-params"); +const fix_hermes_v1_class_in_finally_1 = require("../plugins/fix-hermes-v1-class-in-finally"); +const fix_hermes_v1_super_in_object_accessor_1 = require("../plugins/fix-hermes-v1-super-in-object-accessor"); // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` const loose = true; /** The JS syntax preset used with Hermes v1 (SDK 56+) */ module.exports = function (_api, _options) { const plugins = [ + // NOTE(@kitten): See individual plugins for which Hermes v1 fixes they correspond to + [fix_hermes_v1_async_arrow_non_simple_params_1.fixHermesV1AsyncArrowNonSimpleParams], + [fix_hermes_v1_super_in_object_accessor_1.fixHermesV1SuperInObjectAccessor], + [fix_hermes_v1_class_in_finally_1.fixHermesV1ClassInFinally], [require('@babel/plugin-transform-block-scoping')], [require('@babel/plugin-transform-class-static-block'), { loose }], [require('@babel/plugin-transform-async-generator-functions')], diff --git a/packages/babel-preset-expo/build/configs/hermes-v1.js.map b/packages/babel-preset-expo/build/configs/hermes-v1.js.map index 7ae9651c3a1131..c0f006c0c77a60 100644 --- a/packages/babel-preset-expo/build/configs/hermes-v1.js.map +++ b/packages/babel-preset-expo/build/configs/hermes-v1.js.map @@ -1 +1 @@ -{"version":3,"file":"hermes-v1.js","sourceRoot":"","sources":["../../src/configs/hermes-v1.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAIH,oEAAoE;AACpE,MAAM,KAAK,GAAG,IAAI,CAAC;AAMnB,yDAAyD;AACzD,MAAM,CAAC,OAAO,GAAG,UAAU,IAAe,EAAE,QAA+B;IACzE,MAAM,OAAO,GAAiB;QAC5B,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC;QAClD,CAAC,OAAO,CAAC,4CAA4C,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;QAClE,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC;KAC/D,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,IAAI;QACb,OAAO;KACR,CAAC;AACJ,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"hermes-v1.js","sourceRoot":"","sources":["../../src/configs/hermes-v1.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAIH,wHAA8G;AAC9G,8FAAsF;AACtF,8GAAqG;AAErG,oEAAoE;AACpE,MAAM,KAAK,GAAG,IAAI,CAAC;AAMnB,yDAAyD;AACzD,MAAM,CAAC,OAAO,GAAG,UAAU,IAAe,EAAE,QAA+B;IACzE,MAAM,OAAO,GAAiB;QAC5B,qFAAqF;QACrF,CAAC,kFAAoC,CAAC;QACtC,CAAC,yEAAgC,CAAC;QAClC,CAAC,0DAAyB,CAAC;QAE3B,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC;QAClD,CAAC,OAAO,CAAC,4CAA4C,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;QAClE,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC;KAC/D,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,IAAI;QACb,OAAO;KACR,CAAC;AACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.d.ts b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.d.ts new file mode 100644 index 00000000000000..80cb84c0405dd0 --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.d.ts @@ -0,0 +1,2 @@ +import type { ConfigAPI, PluginObj } from '@babel/core'; +export declare function fixHermesV1AsyncArrowNonSimpleParams({ types: t, }: ConfigAPI & typeof import('@babel/core')): PluginObj; diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.js b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.js new file mode 100644 index 00000000000000..1e00a994f07e0a --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.js @@ -0,0 +1,57 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fixHermesV1AsyncArrowNonSimpleParams = fixHermesV1AsyncArrowNonSimpleParams; +// TODO(@kitten): Workaround for facebook/hermes#1761 +// Remove when fix is incorporated into RN's Hermes v1 version: https://github.com/facebook/hermes/commit/68bfb3a48b31a19ac904ce6d3174ab2698ffc5e9 +// 2026-05-09: Currently, Hermes v1 is up to date to 2025-08-29. Fix is from 2025-09-11 +function fixHermesV1AsyncArrowNonSimpleParams({ types: t, }) { + return { + name: 'fix-hermes-v1-async-arrow-non-simple-params', + visitor: { + ArrowFunctionExpression(path) { + const { node } = path; + if (!node.async || node.params.every((p) => t.isIdentifier(p))) { + return; + } + // Hermes v1 rejects any rest param on async arrows + // Bail with wrapping sync arrow function closing over async arrow function + if (node.params.some((p) => t.isRestElement(p))) { + const body = !t.isBlockStatement(node.body) + ? t.blockStatement([t.returnStatement(node.body)]) + : node.body; + const innerAsync = t.arrowFunctionExpression([], body, true); + node.async = false; + node.body = t.callExpression(innerAsync, []); + return; + } + const newParams = []; + const init = []; + for (let idx = 0; idx < node.params.length; idx++) { + const param = node.params[idx]; + if (t.isIdentifier(param)) { + newParams.push(param); + continue; + } + const sym = path.scope.generateUidIdentifier('p'); + if (t.isAssignmentPattern(param)) { + newParams.push(sym); + init.push(t.variableDeclaration('var', [ + t.variableDeclarator(param.left, t.conditionalExpression(t.binaryExpression('===', t.cloneNode(sym), t.identifier('undefined')), param.right, t.cloneNode(sym))), + ])); + } + else { + newParams.push(sym); + init.push(t.variableDeclaration('var', [t.variableDeclarator(param, t.cloneNode(sym))])); + } + } + const body = !t.isBlockStatement(node.body) + ? t.blockStatement([t.returnStatement(node.body)]) + : node.body; + body.body.unshift(...init); + node.params = newParams; + node.body = body; + }, + }, + }; +} +//# sourceMappingURL=fix-hermes-v1-async-arrow-non-simple-params.js.map \ No newline at end of file diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.js.map b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.js.map new file mode 100644 index 00000000000000..245887c2b2112f --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-async-arrow-non-simple-params.js.map @@ -0,0 +1 @@ +{"version":3,"file":"fix-hermes-v1-async-arrow-non-simple-params.js","sourceRoot":"","sources":["../../src/plugins/fix-hermes-v1-async-arrow-non-simple-params.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.d.ts b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.d.ts new file mode 100644 index 00000000000000..43c8eea587ca66 --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.d.ts @@ -0,0 +1,2 @@ +import type { ConfigAPI, PluginObj } from '@babel/core'; +export declare function fixHermesV1ClassInFinally({ types: t, }: ConfigAPI & typeof import('@babel/core')): PluginObj; diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.js b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.js new file mode 100644 index 00000000000000..5f61cc06678499 --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.js @@ -0,0 +1,59 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fixHermesV1ClassInFinally = fixHermesV1ClassInFinally; +// TODO(@kitten): Workaround for facebook/hermes 1e94fbe0e (Variable caching for legacy classes +// Remove when fix is incorporated into RN's Hermes v1 version: https://github.com/facebook/hermes/commit/1e94fbe0e +// 2026-05-09: Currently, Hermes v1 is up to date to 2025-08-29. Fix is from 2026-02-12 +function fixHermesV1ClassInFinally({ types: t, }) { + return { + name: 'fix-hermes-v1-class-in-finally', + visitor: { + ClassDeclaration(path) { + const id = path.node.id; + if (path.node.decorators?.length || !id || !isInFinalizerScope(path)) { + return; + } + const inner = t.classDeclaration(t.cloneNode(id), path.node.superClass, path.node.body, []); + const arrow = t.arrowFunctionExpression([], t.blockStatement([inner, t.returnStatement(t.cloneNode(id))])); + path.replaceWith(t.variableDeclaration('var', [ + t.variableDeclarator(t.cloneNode(id), t.callExpression(arrow, [])), + ])); + path.skip(); + }, + ClassExpression(path) { + if (path.node.decorators?.length || !isInFinalizerScope(path)) { + return; + } + const arrow = t.arrowFunctionExpression([], path.node); + path.replaceWith(t.callExpression(arrow, [])); + path.skip(); + }, + }, + }; +} +function isInFinalizerScope(path) { + let inner = path; + let parentPath = path.parentPath; + while (parentPath) { + const type = parentPath.node.type; + switch (type) { + case 'FunctionExpression': + case 'FunctionDeclaration': + case 'ArrowFunctionExpression': + case 'ObjectMethod': + case 'ClassMethod': + case 'ClassPrivateMethod': + case 'StaticBlock': + return false; + case 'TryStatement': + if (inner.key === 'finalizer') { + return true; + } + break; + } + inner = parentPath; + parentPath = parentPath.parentPath; + } + return false; +} +//# sourceMappingURL=fix-hermes-v1-class-in-finally.js.map \ No newline at end of file diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.js.map b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.js.map new file mode 100644 index 00000000000000..ad29e86381a261 --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-class-in-finally.js.map @@ -0,0 +1 @@ +{"version":3,"file":"fix-hermes-v1-class-in-finally.js","sourceRoot":"","sources":["../../src/plugins/fix-hermes-v1-class-in-finally.ts"],"names":[],"mappings":";;AAKA,8DAsCC;AAzCD,+FAA+F;AAC/F,mHAAmH;AACnH,uFAAuF;AACvF,SAAgB,yBAAyB,CAAC,EACxC,KAAK,EAAE,CAAC,GACiC;IACzC,OAAO;QACL,IAAI,EAAE,gCAAgC;QACtC,OAAO,EAAE;YACP,gBAAgB,CAAC,IAAI;gBACnB,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrE,OAAO;gBACT,CAAC;gBAED,MAAM,KAAK,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAE5F,MAAM,KAAK,GAAG,CAAC,CAAC,uBAAuB,CACrC,EAAE,EACF,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAC9D,CAAC;gBAEF,IAAI,CAAC,WAAW,CACd,CAAC,CAAC,mBAAmB,CAAC,KAAK,EAAE;oBAC3B,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;iBACnE,CAAC,CACH,CAAC;gBACF,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,CAAC;YAED,eAAe,CAAC,IAAI;gBAClB,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC9D,OAAO;gBACT,CAAC;gBAED,MAAM,KAAK,GAAG,CAAC,CAAC,uBAAuB,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;gBAC9C,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,CAAC;SACF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAc;IACxC,IAAI,KAAK,GAAG,IAAI,CAAC;IACjB,IAAI,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,OAAO,UAAU,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAClC,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,oBAAoB,CAAC;YAC1B,KAAK,qBAAqB,CAAC;YAC3B,KAAK,yBAAyB,CAAC;YAC/B,KAAK,cAAc,CAAC;YACpB,KAAK,aAAa,CAAC;YACnB,KAAK,oBAAoB,CAAC;YAC1B,KAAK,aAAa;gBAChB,OAAO,KAAK,CAAC;YACf,KAAK,cAAc;gBACjB,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;oBAC9B,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,MAAM;QACV,CAAC;QACD,KAAK,GAAG,UAAU,CAAC;QACnB,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;IACrC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"} \ No newline at end of file diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.d.ts b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.d.ts new file mode 100644 index 00000000000000..8d416f0b0666bb --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.d.ts @@ -0,0 +1,2 @@ +import type { ConfigAPI, PluginObj } from '@babel/core'; +export declare function fixHermesV1SuperInObjectAccessor({ types: t, }: ConfigAPI & typeof import('@babel/core')): PluginObj; diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.js b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.js new file mode 100644 index 00000000000000..cbf88645434c9c --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.js @@ -0,0 +1,58 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fixHermesV1SuperInObjectAccessor = fixHermesV1SuperInObjectAccessor; +// TODO(@kitten): Workaround for facebook/hermes 18a963465 (genFunctionExpression for a +// Remove when fix is incorporated into RN's Hermes v1 version: https://github.com/facebook/hermes/commit/18a963465 +// 2026-05-09: Currently, Hermes v1 is up to date to 2025-08-29. Fix is from 2025-11-04 +function fixHermesV1SuperInObjectAccessor({ types: t, }) { + return { + name: 'fix-hermes-v1-super-in-object-accessor', + visitor: { + Super(path) { + // Only super.x / super[expr] reaches the buggy home-object path. super() lives + // only in derived class constructors and takes a different codepath. + const parent = path.parent; + if (parent.type !== 'MemberExpression' || parent.object !== path.node) + return; + const accessor = findEnclosingNonComputedObjectAccessor(path); + if (accessor) { + const key = accessor.key; + if (key.type === 'Identifier') { + accessor.key = t.stringLiteral(key.name); + } + else if (key.type !== 'StringLiteral') { + return; + } + accessor.computed = true; + } + }, + }, + }; +} +function findEnclosingNonComputedObjectAccessor(path) { + let parentPath = path.parentPath; + while (parentPath) { + const node = parentPath.node; + const type = node.type; + switch (type) { + case 'ClassMethod': + case 'ClassPrivateMethod': + case 'FunctionExpression': + case 'FunctionDeclaration': + case 'StaticBlock': + case 'ClassProperty': + case 'ClassPrivateProperty': + return null; + case 'ObjectMethod': + if (!node.computed && (node.kind === 'get' || node.kind === 'set')) { + return node; + } + else { + return null; + } + } + parentPath = parentPath.parentPath; + } + return null; +} +//# sourceMappingURL=fix-hermes-v1-super-in-object-accessor.js.map \ No newline at end of file diff --git a/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.js.map b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.js.map new file mode 100644 index 00000000000000..bdf6fd47c98975 --- /dev/null +++ b/packages/babel-preset-expo/build/plugins/fix-hermes-v1-super-in-object-accessor.js.map @@ -0,0 +1 @@ +{"version":3,"file":"fix-hermes-v1-super-in-object-accessor.js","sourceRoot":"","sources":["../../src/plugins/fix-hermes-v1-super-in-object-accessor.ts"],"names":[],"mappings":";;AAKA,4EAyBC;AA5BD,uFAAuF;AACvF,mHAAmH;AACnH,uFAAuF;AACvF,SAAgB,gCAAgC,CAAC,EAC/C,KAAK,EAAE,CAAC,GACiC;IACzC,OAAO;QACL,IAAI,EAAE,wCAAwC;QAC9C,OAAO,EAAE;YACP,KAAK,CAAC,IAAI;gBACR,+EAA+E;gBAC/E,qEAAqE;gBACrE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC3B,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAE9E,MAAM,QAAQ,GAAG,sCAAsC,CAAC,IAAI,CAAC,CAAC;gBAC9D,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC;oBACzB,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBAC9B,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAC3C,CAAC;yBAAM,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;wBACxC,OAAO;oBACT,CAAC;oBACD,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAC3B,CAAC;YACH,CAAC;SACF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,sCAAsC,CAAC,IAAc;IAC5D,IAAI,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,OAAO,UAAU,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,aAAa,CAAC;YACnB,KAAK,oBAAoB,CAAC;YAC1B,KAAK,oBAAoB,CAAC;YAC1B,KAAK,qBAAqB,CAAC;YAC3B,KAAK,aAAa,CAAC;YACnB,KAAK,eAAe,CAAC;YACrB,KAAK,sBAAsB;gBACzB,OAAO,IAAI,CAAC;YACd,KAAK,cAAc;gBACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;oBACnE,OAAO,IAAI,CAAC;gBACd,CAAC;qBAAM,CAAC;oBACN,OAAO,IAAI,CAAC;gBACd,CAAC;QACL,CAAC;QACD,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"} \ No newline at end of file diff --git a/packages/babel-preset-expo/src/__tests__/preset-config.test.ts b/packages/babel-preset-expo/src/__tests__/preset-config.test.ts index 55340a15c14411..1125807eb7fec8 100644 --- a/packages/babel-preset-expo/src/__tests__/preset-config.test.ts +++ b/packages/babel-preset-expo/src/__tests__/preset-config.test.ts @@ -132,6 +132,9 @@ describe('plugin list snapshots', () => { "expo-ui", "warn-on-deep-imports", "transform-react-jsx", + "fix-hermes-v1-async-arrow-non-simple-params", + "fix-hermes-v1-super-in-object-accessor", + "fix-hermes-v1-class-in-finally", "transform-block-scoping", "transform-class-static-block", "transform-async-generator-functions", @@ -178,6 +181,9 @@ describe('plugin list snapshots', () => { "expo-ui", "transform-react-jsx", "transform-react-pure-annotations", + "fix-hermes-v1-async-arrow-non-simple-params", + "fix-hermes-v1-super-in-object-accessor", + "fix-hermes-v1-class-in-finally", "transform-block-scoping", "transform-class-static-block", "transform-async-generator-functions", diff --git a/packages/babel-preset-expo/src/configs/hermes-v1.ts b/packages/babel-preset-expo/src/configs/hermes-v1.ts index 5683e6f7993bd1..14a1af38f17ed6 100644 --- a/packages/babel-preset-expo/src/configs/hermes-v1.ts +++ b/packages/babel-preset-expo/src/configs/hermes-v1.ts @@ -12,6 +12,10 @@ import type { ConfigAPI, PluginItem } from '@babel/core'; +import { fixHermesV1AsyncArrowNonSimpleParams } from '../plugins/fix-hermes-v1-async-arrow-non-simple-params'; +import { fixHermesV1ClassInFinally } from '../plugins/fix-hermes-v1-class-in-finally'; +import { fixHermesV1SuperInObjectAccessor } from '../plugins/fix-hermes-v1-super-in-object-accessor'; + // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` const loose = true; @@ -22,6 +26,11 @@ export interface HermesV1ConfigOptions { /** The JS syntax preset used with Hermes v1 (SDK 56+) */ module.exports = function (_api: ConfigAPI, _options: HermesV1ConfigOptions) { const plugins: PluginItem[] = [ + // NOTE(@kitten): See individual plugins for which Hermes v1 fixes they correspond to + [fixHermesV1AsyncArrowNonSimpleParams], + [fixHermesV1SuperInObjectAccessor], + [fixHermesV1ClassInFinally], + [require('@babel/plugin-transform-block-scoping')], [require('@babel/plugin-transform-class-static-block'), { loose }], [require('@babel/plugin-transform-async-generator-functions')], diff --git a/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-async-arrow-non-simple-params.test.ts b/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-async-arrow-non-simple-params.test.ts new file mode 100644 index 00000000000000..098a7939473a27 --- /dev/null +++ b/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-async-arrow-non-simple-params.test.ts @@ -0,0 +1,190 @@ +import { transformSync } from '@babel/core'; + +import { fixHermesV1AsyncArrowNonSimpleParams } from '../fix-hermes-v1-async-arrow-non-simple-params'; + +function transform(code: string) { + const result = transformSync(code, { + plugins: [fixHermesV1AsyncArrowNonSimpleParams], + configFile: false, + babelrc: false, + compact: false, + }); + return result!.code!; +} + +describe('non-simple async arrows', () => { + it('rewrites object destructure', () => { + expect(transform(`const f = async ({ b }) => 42;`)).toMatchInlineSnapshot(` + "const f = async _p => { + var { + b + } = _p; + return 42; + };" + `); + }); + + it('rewrites rest params ', () => { + expect(transform(`const f = async (...rest) => 42;`)).toMatchInlineSnapshot(` + "const f = (...rest) => (async () => { + return 42; + })();" + `); + }); + + it('rewrites object destructure with rename and default', () => { + expect(transform(`const f = async ({ a: x = 7 }) => x;`)).toMatchInlineSnapshot(` + "const f = async _p => { + var { + a: x = 7 + } = _p; + return x; + };" + `); + }); + + it('rewrites array destructure', () => { + expect(transform(`const f = async ([a, b]) => a + b;`)).toMatchInlineSnapshot(` + "const f = async _p => { + var [a, b] = _p; + return a + b; + };" + `); + }); + + it('rewrites array destructure with rest', () => { + expect(transform(`const f = async ([a, ...rest]) => rest;`)).toMatchInlineSnapshot(` + "const f = async _p => { + var [a, ...rest] = _p; + return rest; + };" + `); + }); + + it('rewrites default value param', () => { + expect(transform(`const f = async (x = 7) => x;`)).toMatchInlineSnapshot(` + "const f = async _p => { + var x = _p === undefined ? 7 : _p; + return x; + };" + `); + }); + + it('rewrites default value param with side-effecting expression', () => { + expect(transform(`const f = async (x = compute()) => x;`)).toMatchInlineSnapshot(` + "const f = async _p => { + var x = _p === undefined ? compute() : _p; + return x; + };" + `); + }); + + it('rewrites rest param', () => { + expect(transform(`const f = async (...rest) => rest.length;`)).toMatchInlineSnapshot(` + "const f = (...rest) => (async () => { + return rest.length; + })();" + `); + }); + + it('rewrites mixed simple, destructure, default, and rest params', () => { + expect(transform(`const f = async (a, { b }, c = 1, ...rest) => [a, b, c, rest];`)) + .toMatchInlineSnapshot(` + "const f = (a, { + b + }, c = 1, ...rest) => (async () => { + return [a, b, c, rest]; + })();" + `); + }); + + it('promotes concise body to block with return', () => { + expect(transform(`const f = async ({ b }) => await b;`)).toMatchInlineSnapshot(` + "const f = async _p => { + var { + b + } = _p; + return await b; + };" + `); + }); + + it('preserves block body and prepends inits', () => { + expect(transform(`const f = async ({ b }) => { const c = b + 1; return c; };`)) + .toMatchInlineSnapshot(` + "const f = async _p => { + var { + b + } = _p; + const c = b + 1; + return c; + };" + `); + }); +}); + +describe('untouched', () => { + it('leaves async arrow with simple params alone', () => { + expect(transform(`const f = async (a, b) => a + b;`)).toMatchInlineSnapshot( + `"const f = async (a, b) => a + b;"` + ); + }); + + it('leaves async arrow with no params alone', () => { + expect(transform(`const f = async () => 42;`)).toMatchInlineSnapshot( + `"const f = async () => 42;"` + ); + }); + + it('leaves sync arrow with destructured params alone', () => { + expect(transform(`const f = ({ b }) => b;`)).toMatchInlineSnapshot(` + "const f = ({ + b + }) => b;" + `); + }); + + it('leaves async function declaration with destructured params alone', () => { + expect(transform(`async function f({ b }) { return b; }`)).toMatchInlineSnapshot(` + "async function f({ + b + }) { + return b; + }" + `); + }); + + it('leaves async function expression with destructured params alone', () => { + expect(transform(`const f = async function ({ b }) { return b; };`)).toMatchInlineSnapshot(` + "const f = async function ({ + b + }) { + return b; + };" + `); + }); + + it('leaves class async method with destructured params alone', () => { + expect(transform(`class C { async m({ b }) { return b; } }`)).toMatchInlineSnapshot(` + "class C { + async m({ + b + }) { + return b; + } + }" + `); + }); + + it('leaves object shorthand async method with destructured params alone', () => { + expect(transform(`const o = { async m({ b }) { return b; } };`)).toMatchInlineSnapshot(` + "const o = { + async m({ + b + }) { + return b; + } + };" + `); + }); +}); diff --git a/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-class-in-finally.test.ts b/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-class-in-finally.test.ts new file mode 100644 index 00000000000000..d0c592b9ee301a --- /dev/null +++ b/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-class-in-finally.test.ts @@ -0,0 +1,160 @@ +import { transformSync } from '@babel/core'; + +import { fixHermesV1ClassInFinally } from '../fix-hermes-v1-class-in-finally'; + +function transform(code: string) { + const result = transformSync(code, { + plugins: [fixHermesV1ClassInFinally], + configFile: false, + babelrc: false, + compact: false, + }); + return result!.code!; +} + +describe('classes inside finally', () => { + it('wraps a class declaration', () => { + expect( + transform( + `function f() { try { throw 1; } finally { class C { static x = 42; } return C.x; } }` + ) + ).toMatchInlineSnapshot(` +"function f() { + try { + throw 1; + } finally { + var C = (() => { + class C { + static x = 42; + } + return C; + })(); + return C.x; + } +}" +`); + }); + + it('wraps multiple class declarations', () => { + expect(transform(`try {} finally { class A {} class B extends A {} use(A, B); }`)) + .toMatchInlineSnapshot(` +"try {} finally { + var A = (() => { + class A {} + return A; + })(); + var B = (() => { + class B extends A {} + return B; + })(); + use(A, B); +}" +`); + }); + + it('wraps a class expression', () => { + expect(transform(`try {} finally { use(class { method() {} }); }`)).toMatchInlineSnapshot(` +"try {} finally { + use((() => class { + method() {} + })()); +}" +`); + }); + + it('wraps classes nested in blocks inside finally', () => { + expect(transform(`try {} finally { if (cond) { class C {} use(C); } }`)).toMatchInlineSnapshot(` +"try {} finally { + if (cond) { + var C = (() => { + class C {} + return C; + })(); + use(C); + } +}" +`); + }); + + it('preserves extends, methods, and static/private fields', () => { + expect( + transform( + `try {} finally { class C extends Base { #priv = 1; static s = 2; m() { return this.#priv; } } }` + ) + ).toMatchInlineSnapshot(` +"try {} finally { + var C = (() => { + class C extends Base { + #priv = 1; + static s = 2; + m() { + return this.#priv; + } + } + return C; + })(); +}" +`); + }); +}); + +describe('untouched', () => { + it('leaves a class outside any try/finally alone', () => { + expect(transform(`class C {}`)).toMatchInlineSnapshot(`"class C {}"`); + }); + + it('leaves a class in a try block alone', () => { + expect(transform(`try { class C {} } catch (e) {}`)).toMatchInlineSnapshot(` +"try { + class C {} +} catch (e) {}" +`); + }); + + it('leaves a class in a catch block alone', () => { + expect(transform(`try {} catch (e) { class C {} }`)).toMatchInlineSnapshot(` +"try {} catch (e) { + class C {} +}" +`); + }); + + it('leaves a class behind a function boundary inside finally alone', () => { + expect(transform(`try {} finally { (() => { class C {} return C; })(); }`)) + .toMatchInlineSnapshot(` +"try {} finally { + (() => { + class C {} + return C; + })(); +}" +`); + }); + + it('leaves a class inside a method body inside finally alone', () => { + expect(transform(`try {} finally { class Outer { m() { class Inner {} return Inner; } } }`)) + .toMatchInlineSnapshot(` +"try {} finally { + var Outer = (() => { + class Outer { + m() { + class Inner {} + return Inner; + } + } + return Outer; + })(); +}" +`); + }); + + it('leaves a try/finally with no class inside alone', () => { + expect(transform(`try { a(); } finally { b(); }`)).toMatchInlineSnapshot(` +"try { + a(); +} finally { + b(); +}" +`); + }); +}); diff --git a/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-super-in-object-accessor.test.ts b/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-super-in-object-accessor.test.ts new file mode 100644 index 00000000000000..7da4937dd3dca7 --- /dev/null +++ b/packages/babel-preset-expo/src/plugins/__tests__/fix-hermes-v1-super-in-object-accessor.test.ts @@ -0,0 +1,145 @@ +import { transformSync } from '@babel/core'; + +import { fixHermesV1SuperInObjectAccessor } from '../fix-hermes-v1-super-in-object-accessor'; + +function transform(code: string) { + const result = transformSync(code, { + plugins: [fixHermesV1SuperInObjectAccessor], + configFile: false, + babelrc: false, + compact: false, + }); + return result!.code!; +} + +describe('object literal accessors with super', () => { + it('rewrites a non-computed identifier-keyed getter with super', () => { + expect(transform(`const o = { get a() { return super.m; } };`)).toMatchInlineSnapshot(` +"const o = { + get ["a"]() { + return super.m; + } +};" +`); + }); + + it('rewrites a non-computed identifier-keyed setter with super', () => { + expect(transform(`const o = { set a(v) { super.m = v; } };`)).toMatchInlineSnapshot(` +"const o = { + set ["a"](v) { + super.m = v; + } +};" +`); + }); + + it('rewrites a string-literal-keyed getter with super', () => { + expect(transform(`const o = { get "weird key"() { return super.m; } };`)) + .toMatchInlineSnapshot(` +"const o = { + get ["weird key"]() { + return super.m; + } +};" +`); + }); + + it('detects super reachable through a nested arrow', () => { + expect(transform(`const o = { get a() { return (() => super.m)(); } };`)) + .toMatchInlineSnapshot(` +"const o = { + get ["a"]() { + return (() => super.m)(); + } +};" +`); + }); +}); + +describe('untouched', () => { + it('leaves an accessor without super alone', () => { + expect(transform(`const o = { get a() { return 1; } };`)).toMatchInlineSnapshot(` +"const o = { + get a() { + return 1; + } +};" +`); + }); + + it('leaves an already-computed accessor alone', () => { + expect(transform(`const o = { get ['a']() { return super.m; } };`)).toMatchInlineSnapshot(` +"const o = { + get ['a']() { + return super.m; + } +};" +`); + }); + + it('leaves a regular method (kind: method) alone', () => { + expect(transform(`const o = { m() { return super.m; } };`)).toMatchInlineSnapshot(` +"const o = { + m() { + return super.m; + } +};" +`); + }); + + it('leaves a class method with super alone', () => { + expect(transform(`class C extends B { get a() { return super.m; } }`)).toMatchInlineSnapshot(` +"class C extends B { + get a() { + return super.m; + } +}" +`); + }); + + it('does not flip when super only appears in a nested class static block', () => { + expect( + transform(`const o = { get a() { class C extends B { static { super.m; } } return C; } };`) + ).toMatchInlineSnapshot(` +"const o = { + get a() { + class C extends B { + static { + super.m; + } + } + return C; + } +};" +`); + }); + + it('does not flip when super only appears in a nested class field initializer', () => { + expect(transform(`const o = { get a() { class C extends B { x = super.m; } return C; } };`)) + .toMatchInlineSnapshot(` +"const o = { + get a() { + class C extends B { + x = super.m; + } + return C; + } +};" +`); + }); + + it('does not flip when super only appears in a nested object accessor', () => { + expect(transform(`const o = { get a() { return { get b() { return super.m; } }.b; } };`)) + .toMatchInlineSnapshot(` +"const o = { + get a() { + return { + get ["b"]() { + return super.m; + } + }.b; + } +};" +`); + }); +}); diff --git a/packages/babel-preset-expo/src/plugins/fix-hermes-v1-async-arrow-non-simple-params.ts b/packages/babel-preset-expo/src/plugins/fix-hermes-v1-async-arrow-non-simple-params.ts new file mode 100644 index 00000000000000..c5b15cd79588c3 --- /dev/null +++ b/packages/babel-preset-expo/src/plugins/fix-hermes-v1-async-arrow-non-simple-params.ts @@ -0,0 +1,71 @@ +import type { ConfigAPI, PluginObj } from '@babel/core'; + +// TODO(@kitten): Workaround for facebook/hermes#1761 +// Remove when fix is incorporated into RN's Hermes v1 version: https://github.com/facebook/hermes/commit/68bfb3a48b31a19ac904ce6d3174ab2698ffc5e9 +// 2026-05-09: Currently, Hermes v1 is up to date to 2025-08-29. Fix is from 2025-09-11 +export function fixHermesV1AsyncArrowNonSimpleParams({ + types: t, +}: ConfigAPI & typeof import('@babel/core')): PluginObj { + return { + name: 'fix-hermes-v1-async-arrow-non-simple-params', + visitor: { + ArrowFunctionExpression(path) { + const { node } = path; + if (!node.async || node.params.every((p) => t.isIdentifier(p))) { + return; + } + + // Hermes v1 rejects any rest param on async arrows + // Bail with wrapping sync arrow function closing over async arrow function + if (node.params.some((p) => t.isRestElement(p))) { + const body = !t.isBlockStatement(node.body) + ? t.blockStatement([t.returnStatement(node.body)]) + : node.body; + const innerAsync = t.arrowFunctionExpression([], body, true); + node.async = false; + node.body = t.callExpression(innerAsync, []); + return; + } + + const newParams = []; + const init = []; + for (let idx = 0; idx < node.params.length; idx++) { + const param = node.params[idx]!; + if (t.isIdentifier(param)) { + newParams.push(param); + continue; + } + + const sym = path.scope.generateUidIdentifier('p'); + if (t.isAssignmentPattern(param)) { + newParams.push(sym); + init.push( + t.variableDeclaration('var', [ + t.variableDeclarator( + param.left, + t.conditionalExpression( + t.binaryExpression('===', t.cloneNode(sym), t.identifier('undefined')), + param.right, + t.cloneNode(sym) + ) + ), + ]) + ); + } else { + newParams.push(sym); + init.push( + t.variableDeclaration('var', [t.variableDeclarator(param, t.cloneNode(sym))]) + ); + } + } + + const body = !t.isBlockStatement(node.body) + ? t.blockStatement([t.returnStatement(node.body)]) + : node.body; + body.body.unshift(...init); + node.params = newParams; + node.body = body; + }, + }, + }; +} diff --git a/packages/babel-preset-expo/src/plugins/fix-hermes-v1-class-in-finally.ts b/packages/babel-preset-expo/src/plugins/fix-hermes-v1-class-in-finally.ts new file mode 100644 index 00000000000000..91c7f613fcbde6 --- /dev/null +++ b/packages/babel-preset-expo/src/plugins/fix-hermes-v1-class-in-finally.ts @@ -0,0 +1,70 @@ +import type { ConfigAPI, NodePath, PluginObj } from '@babel/core'; + +// TODO(@kitten): Workaround for facebook/hermes 1e94fbe0e (Variable caching for legacy classes +// Remove when fix is incorporated into RN's Hermes v1 version: https://github.com/facebook/hermes/commit/1e94fbe0e +// 2026-05-09: Currently, Hermes v1 is up to date to 2025-08-29. Fix is from 2026-02-12 +export function fixHermesV1ClassInFinally({ + types: t, +}: ConfigAPI & typeof import('@babel/core')): PluginObj { + return { + name: 'fix-hermes-v1-class-in-finally', + visitor: { + ClassDeclaration(path) { + const id = path.node.id; + if (path.node.decorators?.length || !id || !isInFinalizerScope(path)) { + return; + } + + const inner = t.classDeclaration(t.cloneNode(id), path.node.superClass, path.node.body, []); + + const arrow = t.arrowFunctionExpression( + [], + t.blockStatement([inner, t.returnStatement(t.cloneNode(id))]) + ); + + path.replaceWith( + t.variableDeclaration('var', [ + t.variableDeclarator(t.cloneNode(id), t.callExpression(arrow, [])), + ]) + ); + path.skip(); + }, + + ClassExpression(path) { + if (path.node.decorators?.length || !isInFinalizerScope(path)) { + return; + } + + const arrow = t.arrowFunctionExpression([], path.node); + path.replaceWith(t.callExpression(arrow, [])); + path.skip(); + }, + }, + }; +} + +function isInFinalizerScope(path: NodePath): boolean { + let inner = path; + let parentPath = path.parentPath; + while (parentPath) { + const type = parentPath.node.type; + switch (type) { + case 'FunctionExpression': + case 'FunctionDeclaration': + case 'ArrowFunctionExpression': + case 'ObjectMethod': + case 'ClassMethod': + case 'ClassPrivateMethod': + case 'StaticBlock': + return false; + case 'TryStatement': + if (inner.key === 'finalizer') { + return true; + } + break; + } + inner = parentPath; + parentPath = parentPath.parentPath; + } + return false; +} diff --git a/packages/babel-preset-expo/src/plugins/fix-hermes-v1-super-in-object-accessor.ts b/packages/babel-preset-expo/src/plugins/fix-hermes-v1-super-in-object-accessor.ts new file mode 100644 index 00000000000000..5fb3289b6ad695 --- /dev/null +++ b/packages/babel-preset-expo/src/plugins/fix-hermes-v1-super-in-object-accessor.ts @@ -0,0 +1,57 @@ +import type { ConfigAPI, NodePath, PluginObj, types as t } from '@babel/core'; + +// TODO(@kitten): Workaround for facebook/hermes 18a963465 (genFunctionExpression for a +// Remove when fix is incorporated into RN's Hermes v1 version: https://github.com/facebook/hermes/commit/18a963465 +// 2026-05-09: Currently, Hermes v1 is up to date to 2025-08-29. Fix is from 2025-11-04 +export function fixHermesV1SuperInObjectAccessor({ + types: t, +}: ConfigAPI & typeof import('@babel/core')): PluginObj { + return { + name: 'fix-hermes-v1-super-in-object-accessor', + visitor: { + Super(path) { + // Only super.x / super[expr] reaches the buggy home-object path. super() lives + // only in derived class constructors and takes a different codepath. + const parent = path.parent; + if (parent.type !== 'MemberExpression' || parent.object !== path.node) return; + + const accessor = findEnclosingNonComputedObjectAccessor(path); + if (accessor) { + const key = accessor.key; + if (key.type === 'Identifier') { + accessor.key = t.stringLiteral(key.name); + } else if (key.type !== 'StringLiteral') { + return; + } + accessor.computed = true; + } + }, + }, + }; +} + +function findEnclosingNonComputedObjectAccessor(path: NodePath): t.ObjectMethod | null { + let parentPath = path.parentPath; + while (parentPath) { + const node = parentPath.node; + const type = node.type; + switch (type) { + case 'ClassMethod': + case 'ClassPrivateMethod': + case 'FunctionExpression': + case 'FunctionDeclaration': + case 'StaticBlock': + case 'ClassProperty': + case 'ClassPrivateProperty': + return null; + case 'ObjectMethod': + if (!node.computed && (node.kind === 'get' || node.kind === 'set')) { + return node; + } else { + return null; + } + } + parentPath = parentPath.parentPath; + } + return null; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8fa697af8a1cd..ecea23926b6624 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1571,6 +1571,9 @@ importers: '@react-navigation/native': specifier: ^7.1.33 version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + '@react-navigation/native-stack': + specifier: ^7.14.5 + version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) '@react-navigation/stack': specifier: ^7.8.5 version: 7.8.5(5f603fd5b7fdee282854d7921c603411) From b9b6c721bac8dd17559d08c7c6cb1d0816e91a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kosmaty?= Date: Mon, 11 May 2026 19:21:45 +0200 Subject: [PATCH 06/15] [expo] Add `ccache` setup to `CONTRIBUTING.md` (#45639) --- CONTRIBUTING.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 301927caeaaef2..98011d824607ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,6 +63,23 @@ export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home `ANDROID_SDK_ROOT` environmental variable should be set or configured via `local.properties` file in `android` folder of the native project you're working with. +### (Optional) Speed up Android native builds with ccache + +[ccache](https://ccache.dev/) caches C/C++ compilation results so rebuilds of native code are nearly instant when source files haven't changed. + +1. Install ccache: `brew install ccache` +2. Add to your `~/.zshrc` (or `~/.bashrc`): + ```sh + export CMAKE_C_COMPILER_LAUNCHER="ccache" + export CMAKE_CXX_COMPILER_LAUNCHER="ccache" + ``` +3. Enable precompiled header support (required by some modules like `expo-modules-core`): + ```sh + ccache -o sloppiness=pch_defines,time_macros + ``` + +The repo's `.envrc` automatically sets `CCACHE_BASEDIR` via direnv, so cache is shared across git worktrees with no extra setup. + ### Set up iOS If you will be working with the iOS project, ensure **ruby 3.3** is installed on your machine. macOS comes with ruby 2.6, which is not supported in this repository; if you use Homebrew you can just run `brew install ruby@3.3`. You will also need to have the latest stable version of Xcode installed, along with Xcode command line tools. From 157716ce0c8e61ccf4ec142fe76d45edb8a55406 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 11 May 2026 18:25:20 +0100 Subject: [PATCH 07/15] fix(metro-file-map): Fix Windows cross-device path resolution (#45648) # Why Reported at https://github.com/facebook/metro/pull/1696. This PR is being upstreamed at: https://github.com/facebook/metro/pull/1711 The intention in Metro is that cross-device paths are represented as relative normal paths. If the root dir is at `C:\project` then a cross-device normal path at `D:\temp` is represented as `..\..\D:\temp`. This assumption is broken in several places, like `normalToAbsolute` printing, leading to `C:\D:\` paths that are invalid. # How - Fix `normalToAbsolute` not cutting off cross-device absolute paths - Fix `resolveSymlinkToNormal` cutting off trailing slash for absolute Windows device paths - Prevent double slash when appending normal path to root `C:\` path - Prevent `TreeFS#remove` from re-normalizing internally built paths, which can lead to excessively clamped paths - Adjust relative root maximum depth for Windows (remove `-1` adjustment for Windows) # Test Plan - Represented in unit test changes - **Note:** Invalid unit tests have been removed for paths that rise above the filesystem root # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/@expo/metro-file-map/CHANGELOG.md | 2 + .../metro-file-map/build/lib/RootPathUtils.js | 31 ++- .../@expo/metro-file-map/build/lib/TreeFS.js | 7 +- .../metro-file-map/src/lib/RootPathUtils.ts | 32 ++- .../@expo/metro-file-map/src/lib/TreeFS.ts | 8 +- .../src/lib/__tests__/RootPathUtils.test.ts | 182 ++++++++++++++---- .../src/lib/__tests__/TreeFS.test.ts | 81 +++++++- 7 files changed, 280 insertions(+), 63 deletions(-) diff --git a/packages/@expo/metro-file-map/CHANGELOG.md b/packages/@expo/metro-file-map/CHANGELOG.md index f45d014e09ae00..87916cd70fc03c 100644 --- a/packages/@expo/metro-file-map/CHANGELOG.md +++ b/packages/@expo/metro-file-map/CHANGELOG.md @@ -8,6 +8,8 @@ ### 🐛 Bug fixes +- Fix Windows path resolution for cross-device resolved paths ([#45648](https://github.com/expo/expo/pull/45648) by [@kitten](https://github.com/kitten)) + ### 💡 Others ## 56.0.0 — 2026-05-08 diff --git a/packages/@expo/metro-file-map/build/lib/RootPathUtils.js b/packages/@expo/metro-file-map/build/lib/RootPathUtils.js index ad76b0330b39bf..5200382cb58081 100644 --- a/packages/@expo/metro-file-map/build/lib/RootPathUtils.js +++ b/packages/@expo/metro-file-map/build/lib/RootPathUtils.js @@ -48,6 +48,15 @@ const UP_FRAGMENT_SEP = '..' + path_1.default.sep; const SEP_UP_FRAGMENT = path_1.default.sep + '..'; const UP_FRAGMENT_SEP_LENGTH = UP_FRAGMENT_SEP.length; const CURRENT_FRAGMENT = '.' + path_1.default.sep; +const IS_WIN32 = path_1.default.sep === '\\'; +const ROOT_BASE_IDX = IS_WIN32 ? 0 : 1; +function startsWithDriveLetter(str) { + if (!IS_WIN32 || str.charCodeAt(1) !== 58 /* ':' */) { + return false; + } + const c = str.charCodeAt(0); + return (c >= 65 && c <= 90) /* A-Z */ || (c >= 97 && c <= 122) /* a-z */; +} class RootPathUtils { #rootDir; #rootDirnames; @@ -121,6 +130,12 @@ class RootPathUtils { if (right.length === 0) { return left; } + else if (pos > this.#rootDepth * UP_FRAGMENT_SEP_LENGTH) { + // When we walk above the filesystem root, we emit the remaining path as is. + // This is important on Windows, since we're canonicalizing cross-device paths + // as relative paths from rootDir + return right; + } // left may already end in a path separator only if it is a filesystem root, // '/' or 'X:\'. if (i === this.#rootDepth) { @@ -135,8 +150,11 @@ class RootPathUtils { resolveSymlinkToNormal(symlinkNormalPath, readlinkResult) { let target = (0, normalizePathSeparatorsToSystem_1.default)(readlinkResult); // WARN: This only applies to Windows + Node 20 case, where the value is completely - // unnormalized and a trailing slash may be returned - if (target[target.length - 1] === path_1.default.sep) { + // unnormalized and a trailing slash may be returned. Skip the strip when the target + // is a filesystem root: POSIX '/' or Windows 'X:\' + const len = target.length; + const isFsRoot = len === 1 || (len === 3 && startsWithDriveLetter(target)); + if (!isFsRoot && target[len - 1] === path_1.default.sep) { target = target.slice(0, -1); } if (path_1.default.isAbsolute(target)) { @@ -176,7 +194,7 @@ class RootPathUtils { if (relativePath === '') { return { collapsedSegments: 0, normalPath }; } - const left = normalPath + path_1.default.sep; + const left = normalPath.endsWith(path_1.default.sep) ? normalPath : normalPath + path_1.default.sep; const rawPath = left + relativePath; if (normalPath === '..' || normalPath.endsWith(SEP_UP_FRAGMENT)) { const collapsed = this.#tryCollapseIndirectionsInSuffix(rawPath, 0, 0); @@ -262,9 +280,10 @@ class RootPathUtils { collapsedSegments, }; } - // Cap the number of indirections at the total number of root segments. - // File systems treat '..' at the root as '.'. - if (totalUpIndirections < this.#rootParts.length - 1) { + // Cap the number of indirections at the total number of root parts. + // File systems treat '..' at the root as '.'. For Windows, cross-device + // paths need to survive this + if (totalUpIndirections < this.#rootParts.length - ROOT_BASE_IDX) { totalUpIndirections++; } if (nextIndirection !== pos + 1 || // Fallback when ./ later in the path, or leading diff --git a/packages/@expo/metro-file-map/build/lib/TreeFS.js b/packages/@expo/metro-file-map/build/lib/TreeFS.js index dc67fc74ab943d..f6072673c499bb 100644 --- a/packages/@expo/metro-file-map/build/lib/TreeFS.js +++ b/packages/@expo/metro-file-map/build/lib/TreeFS.js @@ -379,6 +379,9 @@ class TreeFS { } remove(mixedPath, changeListener) { const normalPath = this.#normalizePath(mixedPath); + this.#removeNormalPath(normalPath, changeListener); + } + #removeNormalPath(normalPath, changeListener) { const result = this.#lookupByNormalPath(normalPath, { followLeaf: false }); if (!result.exists) { return; @@ -386,7 +389,7 @@ class TreeFS { const { parentNode, canonicalPath, node } = result; if (isDirectory(node) && node.size > 0) { for (const basename of node.keys()) { - this.remove(canonicalPath + path_1.default.sep + basename, changeListener); + this.#removeNormalPath(canonicalPath + path_1.default.sep + basename, changeListener); } // Removing the last file will delete this directory return; @@ -407,7 +410,7 @@ class TreeFS { // that's not expected to be a case common enough to justify // implementation complexity, or slowing down more common uses of // _lookupByNormalPath. - this.remove(path_1.default.dirname(canonicalPath), changeListener); + this.#removeNormalPath(path_1.default.dirname(canonicalPath), changeListener); } } } diff --git a/packages/@expo/metro-file-map/src/lib/RootPathUtils.ts b/packages/@expo/metro-file-map/src/lib/RootPathUtils.ts index a1edbe58a6c183..3157f644fce3e6 100644 --- a/packages/@expo/metro-file-map/src/lib/RootPathUtils.ts +++ b/packages/@expo/metro-file-map/src/lib/RootPathUtils.ts @@ -45,6 +45,17 @@ const SEP_UP_FRAGMENT = path.sep + '..'; const UP_FRAGMENT_SEP_LENGTH = UP_FRAGMENT_SEP.length; const CURRENT_FRAGMENT = '.' + path.sep; +const IS_WIN32 = path.sep === '\\'; +const ROOT_BASE_IDX = IS_WIN32 ? 0 : 1; + +function startsWithDriveLetter(str: string): boolean { + if (!IS_WIN32 || str.charCodeAt(1) !== 58 /* ':' */) { + return false; + } + const c = str.charCodeAt(0); + return (c >= 65 && c <= 90) /* A-Z */ || (c >= 97 && c <= 122) /* a-z */; +} + export class RootPathUtils { #rootDir: string; #rootDirnames: readonly string[]; @@ -145,6 +156,11 @@ export class RootPathUtils { const right = pos === 0 ? normalPath : normalPath.slice(pos); if (right.length === 0) { return left; + } else if (pos > this.#rootDepth * UP_FRAGMENT_SEP_LENGTH) { + // When we walk above the filesystem root, we emit the remaining path as is. + // This is important on Windows, since we're canonicalizing cross-device paths + // as relative paths from rootDir + return right; } // left may already end in a path separator only if it is a filesystem root, // '/' or 'X:\'. @@ -164,8 +180,11 @@ export class RootPathUtils { resolveSymlinkToNormal(symlinkNormalPath: string, readlinkResult: string): string { let target = normalizePathSeparatorsToSystem(readlinkResult); // WARN: This only applies to Windows + Node 20 case, where the value is completely - // unnormalized and a trailing slash may be returned - if (target[target.length - 1] === path.sep) { + // unnormalized and a trailing slash may be returned. Skip the strip when the target + // is a filesystem root: POSIX '/' or Windows 'X:\' + const len = target.length; + const isFsRoot = len === 1 || (len === 3 && startsWithDriveLetter(target)); + if (!isFsRoot && target[len - 1] === path.sep) { target = target.slice(0, -1); } if (path.isAbsolute(target)) { @@ -211,7 +230,7 @@ export class RootPathUtils { if (relativePath === '') { return { collapsedSegments: 0, normalPath }; } - const left = normalPath + path.sep; + const left = normalPath.endsWith(path.sep) ? normalPath : normalPath + path.sep; const rawPath = left + relativePath; if (normalPath === '..' || normalPath.endsWith(SEP_UP_FRAGMENT)) { const collapsed = this.#tryCollapseIndirectionsInSuffix(rawPath, 0, 0); @@ -304,9 +323,10 @@ export class RootPathUtils { }; } - // Cap the number of indirections at the total number of root segments. - // File systems treat '..' at the root as '.'. - if (totalUpIndirections < this.#rootParts.length - 1) { + // Cap the number of indirections at the total number of root parts. + // File systems treat '..' at the root as '.'. For Windows, cross-device + // paths need to survive this + if (totalUpIndirections < this.#rootParts.length - ROOT_BASE_IDX) { totalUpIndirections++; } diff --git a/packages/@expo/metro-file-map/src/lib/TreeFS.ts b/packages/@expo/metro-file-map/src/lib/TreeFS.ts index 93c50f202df8c4..32bad8b56f3264 100644 --- a/packages/@expo/metro-file-map/src/lib/TreeFS.ts +++ b/packages/@expo/metro-file-map/src/lib/TreeFS.ts @@ -527,6 +527,10 @@ export default class TreeFS implements MutableFileSystem { remove(mixedPath: Path, changeListener?: FileSystemListener): void { const normalPath = this.#normalizePath(mixedPath); + this.#removeNormalPath(normalPath, changeListener); + } + + #removeNormalPath(normalPath: string, changeListener?: FileSystemListener): void { const result = this.#lookupByNormalPath(normalPath, { followLeaf: false }); if (!result.exists) { return; @@ -535,7 +539,7 @@ export default class TreeFS implements MutableFileSystem { if (isDirectory(node) && node.size > 0) { for (const basename of node.keys()) { - this.remove(canonicalPath + path.sep + basename, changeListener); + this.#removeNormalPath(canonicalPath + path.sep + basename, changeListener); } // Removing the last file will delete this directory return; @@ -555,7 +559,7 @@ export default class TreeFS implements MutableFileSystem { // that's not expected to be a case common enough to justify // implementation complexity, or slowing down more common uses of // _lookupByNormalPath. - this.remove(path.dirname(canonicalPath), changeListener); + this.#removeNormalPath(path.dirname(canonicalPath), changeListener); } } } diff --git a/packages/@expo/metro-file-map/src/lib/__tests__/RootPathUtils.test.ts b/packages/@expo/metro-file-map/src/lib/__tests__/RootPathUtils.test.ts index ee5664af861ba5..5cc739655a6114 100644 --- a/packages/@expo/metro-file-map/src/lib/__tests__/RootPathUtils.test.ts +++ b/packages/@expo/metro-file-map/src/lib/__tests__/RootPathUtils.test.ts @@ -85,48 +85,66 @@ describe.each([['win32'], ['posix']] as const)('RootPathUtils on %s', (platform) expect(pathRelative).toHaveBeenCalled(); }); - test.each([ - p('..'), - p('../..'), - p('../../'), - p('normal/path'), - p('normal/path/'), - p('../normal/path'), - p('../normal/path/'), - p('../../normal/path'), - p('../../../normal/path'), - ])(`normalToAbsolute('%s') matches path.resolve`, (normalPath) => { - let expected = mockPathModule.resolve(rootDir, normalPath); - // Unlike path.resolve, we expect to preserve trailing separators. - if (normalPath.endsWith(sep) && !expected.endsWith(sep)) { - expected += sep; + // normalToAbsolute is documented to take normal (root-relative, no + // redundant indirections) paths; inputs with more '..'s than rootDepth + // are non-canonical and out of contract. + const normalToAbsoluteInputs = + rootDir === p('/project/root') + ? [ + p('..'), + p('../..'), + p('../../'), + p('normal/path'), + p('normal/path/'), + p('../normal/path'), + p('../normal/path/'), + p('../../normal/path'), + ] + : [p('..'), p('../..'), p('../../'), p('normal/path'), p('normal/path/')]; + + test.each(normalToAbsoluteInputs)( + `normalToAbsolute('%s') matches path.resolve`, + (normalPath) => { + let expected = mockPathModule.resolve(rootDir, normalPath); + // Unlike path.resolve, we expect to preserve trailing separators. + if (normalPath.endsWith(sep) && !expected.endsWith(sep)) { + expected += sep; + } + expect(pathUtils.normalToAbsolute(normalPath)).toEqual(expected); } - expect(pathUtils.normalToAbsolute(normalPath)).toEqual(expected); - }); + ); - test.each([ - p('..'), - p('../root'), - p('../root/path'), - p('../project'), - p('../project/'), - p('../../project/root'), - p('../../project/root/'), - p('../../../normal/path'), - p('../../../normal/path/'), - p('../../..'), - ])(`relativeToNormal('%s') matches path.resolve + path.relative`, (relativePath) => { - let expected = mockPathModule.relative( - rootDir, - mockPathModule.resolve(rootDir, relativePath) - ); - // Unlike native path.resolve + path.relative, we expect to preserve - // trailing separators. (Consistent with path.normalize.) - if (relativePath.endsWith(sep) && !expected.endsWith(sep) && expected !== '') { - expected += sep; + // relativeToNormal no longer collapses non-canonical leading '..' chains + // (no in-function clip); inputs are expected to be canonical for rootDir. + const relativeToNormalInputs = + rootDir === p('/project/root') + ? [ + p('..'), + p('../root'), + p('../root/path'), + p('../project'), + p('../project/'), + p('../../project/root'), + p('../../project/root/'), + p('../../..'), + ] + : [p('..')]; + + test.each(relativeToNormalInputs)( + `relativeToNormal('%s') matches path.resolve + path.relative`, + (relativePath) => { + let expected = mockPathModule.relative( + rootDir, + mockPathModule.resolve(rootDir, relativePath) + ); + // Unlike native path.resolve + path.relative, we expect to preserve + // trailing separators. (Consistent with path.normalize.) + if (relativePath.endsWith(sep) && !expected.endsWith(sep) && expected !== '') { + expected += sep; + } + expect(pathUtils.relativeToNormal(relativePath)).toEqual(expected); } - expect(pathUtils.relativeToNormal(relativePath)).toEqual(expected); - }); + ); }); test.each([ @@ -258,4 +276,90 @@ describe.each([['win32'], ['posix']] as const)('RootPathUtils on %s', (platform) expect(pattern.test(p('src/foo.js'))).toBe(false); }); }); + + // See: https://github.com/facebook/metro/pull/1696 + // When a path and rootDir differ in drives on Windows, we expect the resulting + // path to have an anchor (D:) on the new drive + if (platform === 'win32') { + describe('cross-drive absolute paths (Windows)', () => { + test.each(['C:\\project\\root', 'C:\\'])( + 'path.relative returns cross-drive target as-is from rootDir=%s', + (rootDir) => { + expect(mockPathModule.relative(rootDir, 'D:\\some\\file.js')).toEqual( + 'D:\\some\\file.js' + ); + } + ); + + // Pin the ..-chain encoding so we keep the "normal paths are root- + // relative" invariant; only normalToAbsolute observes the cross-drive + // case and returns the absolute remainder. + test.each([ + ['C:\\project\\root', 'D:\\some\\file.js', '..\\..\\..\\D:\\some\\file.js'], + ['C:\\project\\root', 'D:\\some\\', '..\\..\\..\\D:\\some\\'], + ['C:\\project\\root', 'D:\\', '..\\..\\..\\D:\\'], + ['C:\\', 'D:\\some\\file.js', '..\\D:\\some\\file.js'], + ['C:\\', 'D:\\', '..\\D:\\'], + ['D:\\project\\root', 'C:\\file.js', '..\\..\\..\\C:\\file.js'], + ])( + 'absoluteToNormal emits a ..-chain (rootDir=%s, X=%s -> %s)', + (rootDir, absolutePath, expectedNormal) => { + pathUtils = new RootPathUtils(rootDir); + expect(pathUtils.absoluteToNormal(absolutePath)).toEqual(expectedNormal); + } + ); + + test.each([ + ['C:\\project\\root', 'D:\\some\\file.js'], + ['C:\\project\\root', 'D:\\some\\'], + ['C:\\project\\root', 'D:\\'], + ['C:\\', 'D:\\some\\file.js'], + ['C:\\', 'D:\\some\\'], + ['C:\\', 'D:\\'], + ['D:\\project\\root', 'C:\\file.js'], + ['D:\\project\\root', 'C:\\'], + ])( + 'normalToAbsolute(absoluteToNormal(X)) === X for rootDir=%s, X=%s', + (rootDir, absolutePath) => { + pathUtils = new RootPathUtils(rootDir); + const normal = pathUtils.absoluteToNormal(absolutePath); + expect(pathUtils.normalToAbsolute(normal)).toEqual(absolutePath); + } + ); + + test.each([ + ['C:\\project\\root', 'D:\\dir\\sub', 'extra\\file.js'], + ['C:\\project\\root', 'D:\\', 'foo.js'], + ['C:\\', 'D:\\dir', 'sub\\file.js'], + ])( + 'joinNormalToRelative round-trips cross-drive (rootDir=%s, base=%s, rel=%s)', + (rootDir, baseAbsolute, relativePath) => { + pathUtils = new RootPathUtils(rootDir); + const baseNormal = pathUtils.absoluteToNormal(baseAbsolute); + const { normalPath } = pathUtils.joinNormalToRelative(baseNormal, relativePath); + expect(pathUtils.normalToAbsolute(normalPath)).toEqual( + mockPathModule.join(baseAbsolute, relativePath) + ); + } + ); + + test.each([ + ['C:\\project\\root', 'link', 'D:\\target.js'], + ['C:\\project\\root', 'a\\b\\link', 'D:\\sub\\target.js'], + // 'D:\\' hits a distinct path: the leading trailing-separator strip + // turns it into 'D:', which path.win32.isAbsolute rejects, so this + // falls through to the relative branch instead of absoluteToNormal. + ['C:\\project\\root', 'link', 'D:\\'], + ['C:\\', 'link', 'D:\\target.js'], + ['C:\\', 'link', 'D:\\'], + ])( + 'resolveSymlinkToNormal round-trips a cross-drive target (rootDir=%s, %s -> %s)', + (rootDir, symlinkNormalPath, readlinkResult) => { + pathUtils = new RootPathUtils(rootDir); + const normal = pathUtils.resolveSymlinkToNormal(symlinkNormalPath, readlinkResult); + expect(pathUtils.normalToAbsolute(normal)).toEqual(readlinkResult); + } + ); + }); + } }); diff --git a/packages/@expo/metro-file-map/src/lib/__tests__/TreeFS.test.ts b/packages/@expo/metro-file-map/src/lib/__tests__/TreeFS.test.ts index dce3538ed1cae2..2f706dfd5a1461 100644 --- a/packages/@expo/metro-file-map/src/lib/__tests__/TreeFS.test.ts +++ b/packages/@expo/metro-file-map/src/lib/__tests__/TreeFS.test.ts @@ -1973,23 +1973,22 @@ describe.each([['win32'], ['posix']] as const)('TreeFS on %s', (platform) => { const fbTfs = makeFallbackTfs({ serverRoot: p('/project'), files: new Map([ - [p('node_modules/react'), [0, 0, 0, null, '../../.bun-cache/react', null] as any], + // Canonical normal target for /.bun-cache/react under rootDir + // /project is '../.bun-cache/react' (rootDepth=1). + [p('node_modules/react'), [0, 0, 0, null, '../.bun-cache/react', null] as any], ]), }); mockFallback.readdir.mockImplementation( (normalPath: string, _absolutePath: string, dirNode: any) => { const result = dirNode ?? new Map(); - if (normalPath === p('../..')) { + if (normalPath === p('..')) { if (!result.has('.bun-cache')) { result.set('.bun-cache', markFallbackDir(new Map())); } return markFallbackDir(result, 1); } - if ( - normalPath === p('../../.bun-cache/react') || - normalPath === p('node_modules/react') - ) { + if (normalPath === p('../.bun-cache/react') || normalPath === p('node_modules/react')) { result.set('package.json', [100, 5, 0, null, 0, null]); result.set('index.js', [100, 5, 0, null, 0, null]); return markFallbackDir(result, 1); @@ -1998,7 +1997,7 @@ describe.each([['win32'], ['posix']] as const)('TreeFS on %s', (platform) => { } ); mockFallback.lookup.mockImplementation((normalPath: string) => { - if (normalPath === p('../../.bun-cache/react')) { + if (normalPath === p('../.bun-cache/react')) { return markFallbackDir(new Map()); } return null; @@ -2013,7 +2012,7 @@ describe.each([['win32'], ['posix']] as const)('TreeFS on %s', (platform) => { ); expect(found).not.toBeNull(); expect(found?.absolutePath).toBe( - mockPathModule.resolve(p('/project'), p('../../.bun-cache/react/package.json')) + mockPathModule.resolve(p('/project'), p('../.bun-cache/react/package.json')) ); }); @@ -2497,4 +2496,70 @@ describe.each([['win32'], ['posix']] as const)('TreeFS on %s', (platform) => { }); }); }); + + if (platform === 'win32') { + describe('cross-drive paths (Windows)', () => { + let tfsCD: TreeFSType; + const externalMeta: FileMetadata = [123, 4, 0, null, 0, 'external']; + + beforeEach(() => { + tfsCD = new TreeFS({ + rootDir: 'C:\\project', + files: new Map([ + ['bar.js', [234, 3, 0, null, 0, 'bar']], + // Canonical form of 'D:\\external\\file.js' for rootDepth=1. + ['..\\..\\D:\\external\\file.js', externalMeta], + ]), + processFile: async () => { + throw new Error('Not implemented'); + }, + }); + }); + + test('exists() finds a seeded cross-drive file', () => { + expect(tfsCD.exists('D:\\external\\file.js')).toBe(true); + }); + + test('lookup() returns the absolute drive-prefixed path as realPath', () => { + expect(tfsCD.lookup('D:\\external\\file.js')).toMatchObject({ + exists: true, + type: 'f', + realPath: 'D:\\external\\file.js', + }); + }); + + test('getAllFiles() enumerates cross-drive and in-tree files side by side', () => { + expect(tfsCD.getAllFiles().sort()).toEqual([ + 'C:\\project\\bar.js', + 'D:\\external\\file.js', + ]); + }); + + test('addOrModify() accepts a new cross-drive absolute path', () => { + tfsCD.addOrModify('D:\\added\\later.js', [1, 1, 0, null, 0, 'later']); + expect(tfsCD.exists('D:\\added\\later.js')).toBe(true); + expect(tfsCD.lookup('D:\\added\\later.js')).toMatchObject({ + exists: true, + type: 'f', + realPath: 'D:\\added\\later.js', + }); + }); + + test('remove() deletes a cross-drive entry and prunes empty ancestor dirs', () => { + tfsCD.remove('D:\\external\\file.js'); + expect(tfsCD.exists('D:\\external\\file.js')).toBe(false); + // Intermediate 'D:' / 'external' directory nodes pruned. + expect(tfsCD.lookup('D:\\external').exists).toBe(false); + expect(tfsCD.exists('C:\\project\\bar.js')).toBe(true); + }); + + test('lookup() reports missing for non-existent cross-drive path', () => { + expect(tfsCD.lookup('D:\\external\\missing.js')).toMatchObject({ + exists: false, + }); + // A different drive (E:) was never seeded — also missing. + expect(tfsCD.exists('E:\\anywhere.js')).toBe(false); + }); + }); + } }); From 49e3f69e4c93754664d3ffa7df8dea9a5074e990 Mon Sep 17 00:00:00 2001 From: Jakub Tkacz <32908614+Ubax@users.noreply.github.com> Date: Mon, 11 May 2026 19:26:09 +0200 Subject: [PATCH 08/15] Upgrade react-native-screens to 4.25.0 (#45644) # Why # How # Test Plan 1. Expo Go 2. Router e2e # Checklist - [ ] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- apps/bare-expo/package.json | 2 +- apps/brownfield-tester/expo-app/package.json | 2 +- apps/expo-go/ios/Podfile.lock | 12 +-- apps/expo-go/package.json | 2 +- apps/native-component-list/package.json | 2 +- apps/notification-tester/package.json | 2 +- apps/observe-tester/package.json | 2 +- apps/router-e2e/package.json | 2 +- .../with-monorepo/apps/app-a/package.json | 2 +- .../with-monorepo/apps/app-b/package.json | 2 +- .../with-router-typed-routes/package.json | 2 +- .../cli/e2e/fixtures/with-router/package.json | 2 +- packages/expo-router/CHANGELOG.md | 1 + packages/expo-router/package.json | 6 +- packages/expo/bundledNativeModules.json | 2 +- pnpm-lock.yaml | 76 +++++++++---------- templates/expo-template-default/package.json | 2 +- templates/expo-template-tabs/package.json | 2 +- 18 files changed, 62 insertions(+), 61 deletions(-) diff --git a/apps/bare-expo/package.json b/apps/bare-expo/package.json index a78d4d8e2d6db9..af8d10d981d377 100644 --- a/apps/bare-expo/package.json +++ b/apps/bare-expo/package.json @@ -89,7 +89,7 @@ "react-native-pager-view": "6.9.1", "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "4.25.0", "react-native-svg": "15.15.4", "react-native-view-shot": "4.0.3", "react-native-webview": "13.16.1", diff --git a/apps/brownfield-tester/expo-app/package.json b/apps/brownfield-tester/expo-app/package.json index 24e667c4092078..7d6c8119a2e2d9 100644 --- a/apps/brownfield-tester/expo-app/package.json +++ b/apps/brownfield-tester/expo-app/package.json @@ -35,7 +35,7 @@ "react-native-worklets": "0.8.3", "react-native-reanimated": "~4.3.1", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.3", + "react-native-screens": "~4.25.0", "react-native-web": "~0.21.0" }, "devDependencies": { diff --git a/apps/expo-go/ios/Podfile.lock b/apps/expo-go/ios/Podfile.lock index f8320a10f0bb9e..1b4499d0d409f1 100644 --- a/apps/expo-go/ios/Podfile.lock +++ b/apps/expo-go/ios/Podfile.lock @@ -3694,7 +3694,7 @@ PODS: - RNWorklets - SocketRocket - Yoga - - RNScreens (4.25.0-beta.3): + - RNScreens (4.25.0): - boost - DoubleConversion - fast_float @@ -3721,10 +3721,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNScreens/common (= 4.25.0-beta.3) + - RNScreens/common (= 4.25.0) - SocketRocket - Yoga - - RNScreens/common (4.25.0-beta.3): + - RNScreens/common (4.25.0): - boost - DoubleConversion - fast_float @@ -4242,7 +4242,7 @@ DEPENDENCIES: - "RNDateTimePicker (from `../../../node_modules/.pnpm/@react-native-community+datetimepicker@9.1.0_expo@packages+expo_react-native@0.85.3_@ba_4da8b598fd3fe2232b688159ab685884/node_modules/@react-native-community/datetimepicker`)" - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.31.1_react-native@0.85.3_@babel+core@7.29.0_@react-nativ_e5f24f573130d9ef91edaa3a7b5d2446/node_modules/react-native-gesture-handler`)" - "RNReanimated (from `../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_1a5e3d09dfc1ab41347a1ceaceaf61bc/node_modules/react-native-reanimated`)" - - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.3_react-native@0.85.3_@babel+core@7.29.0_@react-native_d946f5d10f696c25c0f95066694ac89d/node_modules/react-native-screens`)" + - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.0_react-native@0.85.3_@babel+core@7.29.0_@react-native+jest-p_27bafc37770a4b472b96129a8e818eae/node_modules/react-native-screens`)" - "RNSVG (from `../../../node_modules/.pnpm/react-native-svg@15.15.4_react-native@0.85.3_@babel+core@7.29.0_@react-native+jest-pres_492c03827e778ae24445fe49da301b55/node_modules/react-native-svg`)" - "RNWorklets (from `../../../node_modules/.pnpm/react-native-worklets@0.8.3_patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89_42b4111e02dad0db2c0db5ed881424fc/node_modules/react-native-worklets`)" - SocketRocket (~> 0.7.1) @@ -4624,7 +4624,7 @@ EXTERNAL SOURCES: RNReanimated: :path: "../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_1a5e3d09dfc1ab41347a1ceaceaf61bc/node_modules/react-native-reanimated" RNScreens: - :path: "../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.3_react-native@0.85.3_@babel+core@7.29.0_@react-native_d946f5d10f696c25c0f95066694ac89d/node_modules/react-native-screens" + :path: "../../../node_modules/.pnpm/react-native-screens@4.25.0_react-native@0.85.3_@babel+core@7.29.0_@react-native+jest-p_27bafc37770a4b472b96129a8e818eae/node_modules/react-native-screens" RNSVG: :path: "../../../node_modules/.pnpm/react-native-svg@15.15.4_react-native@0.85.3_@babel+core@7.29.0_@react-native+jest-pres_492c03827e778ae24445fe49da301b55/node_modules/react-native-svg" RNWorklets: @@ -4824,7 +4824,7 @@ SPEC CHECKSUMS: RNDateTimePicker: 73ffdd45f0ce1d00ff981031679a05206e619fdc RNGestureHandler: f0d7f370292ab1ff422eac5a6cbae6feef14bb98 RNReanimated: cde3c8091894bc33108f57ee08f05a63760f7a96 - RNScreens: 4e2c5f6f16b001928717ed8e508f929544137a4f + RNScreens: 82303e628dc897156e686705597f2bbcbfa027c3 RNSVG: c9d7c940ad9655eba72c5b9ca7b017c95bb58083 RNWorklets: 057f16d520cd6d64f85e0dcd7565ed3f673ae9dc SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf diff --git a/apps/expo-go/package.json b/apps/expo-go/package.json index c34d0bcd95256e..3ca3412df1252f 100644 --- a/apps/expo-go/package.json +++ b/apps/expo-go/package.json @@ -84,7 +84,7 @@ "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "5.7.0", "react-native-svg": "15.15.4", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "4.25.0", "react-native-view-shot": "4.0.3", "react-native-webview": "13.16.1", "react-native-worklets": "0.8.3" diff --git a/apps/native-component-list/package.json b/apps/native-component-list/package.json index 85a757d3caf22e..ef8e1669b4f4c6 100644 --- a/apps/native-component-list/package.json +++ b/apps/native-component-list/package.json @@ -153,7 +153,7 @@ "react-native-paper": "^5.12.5", "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "4.25.0", "react-native-svg": "15.15.4", "react-native-view-shot": "4.0.3", "react-native-web": "~0.21.0", diff --git a/apps/notification-tester/package.json b/apps/notification-tester/package.json index 3a14eb7e6682f3..096524a4060f25 100644 --- a/apps/notification-tester/package.json +++ b/apps/notification-tester/package.json @@ -41,7 +41,7 @@ "react": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.3" + "react-native-screens": "4.25.0" }, "devDependencies": { "@types/jest": "^29.5.12", diff --git a/apps/observe-tester/package.json b/apps/observe-tester/package.json index cbea9345ca0509..7cc0b7dd3347ed 100644 --- a/apps/observe-tester/package.json +++ b/apps/observe-tester/package.json @@ -43,7 +43,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.3" + "react-native-screens": "4.25.0" }, "devDependencies": { "@expo/config": "workspace:*", diff --git a/apps/router-e2e/package.json b/apps/router-e2e/package.json index d2a7dc20fe0cf7..e97826b2a2ded6 100644 --- a/apps/router-e2e/package.json +++ b/apps/router-e2e/package.json @@ -78,7 +78,7 @@ "react-native": "0.85.3", "react-native-gesture-handler": "~2.30.0", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "4.25.0", "react-native-web": "^0.21.0", "react-native-webview": "13.16.1" }, diff --git a/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-a/package.json b/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-a/package.json index 4a4be8d398e25e..601c2d1493d90d 100644 --- a/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-a/package.json +++ b/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-a/package.json @@ -13,7 +13,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.3", + "react-native-screens": "~4.25.0", "react-native-web": "~0.21.0" } } diff --git a/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-b/package.json b/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-b/package.json index b2b3f0a8276a04..e9a1363663508e 100644 --- a/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-b/package.json +++ b/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-b/package.json @@ -13,7 +13,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.3", + "react-native-screens": "~4.25.0", "react-native-web": "~0.21.0" } } diff --git a/packages/@expo/cli/e2e/fixtures/with-router-typed-routes/package.json b/packages/@expo/cli/e2e/fixtures/with-router-typed-routes/package.json index 365012c3b753aa..2bf26bc7978859 100644 --- a/packages/@expo/cli/e2e/fixtures/with-router-typed-routes/package.json +++ b/packages/@expo/cli/e2e/fixtures/with-router-typed-routes/package.json @@ -13,7 +13,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.3", + "react-native-screens": "~4.25.0", "react-native-web": "~0.21.0" } } diff --git a/packages/@expo/cli/e2e/fixtures/with-router/package.json b/packages/@expo/cli/e2e/fixtures/with-router/package.json index 4cf0c88b385c27..e7bf8fd36d1092 100644 --- a/packages/@expo/cli/e2e/fixtures/with-router/package.json +++ b/packages/@expo/cli/e2e/fixtures/with-router/package.json @@ -12,7 +12,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.3", + "react-native-screens": "~4.25.0", "react-native-web": "~0.21.0" } } diff --git a/packages/expo-router/CHANGELOG.md b/packages/expo-router/CHANGELOG.md index 757b6c24ef953a..680b0663fd6fa4 100644 --- a/packages/expo-router/CHANGELOG.md +++ b/packages/expo-router/CHANGELOG.md @@ -7,6 +7,7 @@ ### 🎉 New features - export new useCurrentRouteInfo hook ([#45566](https://github.com/expo/expo/pull/45566) by [@Ubax](https://github.com/Ubax)) +- Upgrade react-native-screens to 4.25.0 ([#45644](https://github.com/expo/expo/pull/45644) by [@Ubax](https://github.com/Ubax)) ### 🐛 Bug fixes diff --git a/packages/expo-router/package.json b/packages/expo-router/package.json index 0b678e160bbf23..3c8a323bd6c7b5 100644 --- a/packages/expo-router/package.json +++ b/packages/expo-router/package.json @@ -100,7 +100,7 @@ "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "^4.25.0", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, @@ -143,7 +143,7 @@ "react-native-gesture-handler": "~2.30.0", "react-native-reanimated": "~4.3.1", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "^4.25.0", "react-native-web": "~0.21.0", "react-server-dom-webpack": "~19.0.4", "tsd": "^0.33.0" @@ -173,7 +173,7 @@ "react-fast-compare": "^3.2.2", "react-is": "^19.1.0", "react-native-drawer-layout": "^4.2.2", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "^4.25.0", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", diff --git a/packages/expo/bundledNativeModules.json b/packages/expo/bundledNativeModules.json index 5f0a6eaff9b637..56438d5ca991ee 100644 --- a/packages/expo/bundledNativeModules.json +++ b/packages/expo/bundledNativeModules.json @@ -107,7 +107,7 @@ "react-native-pager-view": "8.0.1", "react-native-worklets": "0.8.3", "react-native-reanimated": "4.3.1", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "4.25.0", "react-native-safe-area-context": "~5.7.0", "react-native-svg": "15.15.4", "react-native-view-shot": "4.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ecea23926b6624..956d1538e93007 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -120,13 +120,13 @@ importers: version: 2.5.7(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.15.5(4cf81f97ae4861b2ec2ba3fb0b222013) '@react-navigation/native': specifier: ^7.1.33 version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native-stack': specifier: ^7.14.5 - version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.14.5(4cf81f97ae4861b2ec2ba3fb0b222013) '@shopify/flash-list': specifier: 2.0.2 version: 2.0.2(@babel/runtime@7.29.2)(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -233,8 +233,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.3 - version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0 + version: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-svg: specifier: 15.15.4 version: 15.15.4(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -323,7 +323,7 @@ importers: version: 15.1.1(expo-font@packages+expo-font)(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.15.5(4cf81f97ae4861b2ec2ba3fb0b222013) '@react-navigation/elements': specifier: ^2.9.10 version: 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -394,8 +394,8 @@ importers: specifier: ~5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: ~4.25.0-beta.3 - version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~4.25.0 + version: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-web: specifier: ~0.21.0 version: 0.21.2(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -663,8 +663,8 @@ importers: specifier: 5.7.0 version: 5.7.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.3 - version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0 + version: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-svg: specifier: 15.15.4 version: 15.15.4(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -811,10 +811,10 @@ importers: version: 2.5.7(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.15.5(4cf81f97ae4861b2ec2ba3fb0b222013) '@react-navigation/drawer': specifier: ^7.9.4 - version: 7.9.4(4baeb4b8b805b845dcda02e750a2f352) + version: 7.9.4(95132758d8004dd66bf72ef620b9fd08) '@react-navigation/elements': specifier: ^2.9.10 version: 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -823,10 +823,10 @@ importers: version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native-stack': specifier: ^7.14.5 - version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.14.5(4cf81f97ae4861b2ec2ba3fb0b222013) '@react-navigation/stack': specifier: ^7.8.5 - version: 7.8.5(5f603fd5b7fdee282854d7921c603411) + version: 7.8.5(12bc826df429feb25958fa59e16a7d42) '@shopify/flash-list': specifier: 2.0.2 version: 2.0.2(@babel/runtime@7.29.2)(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1122,8 +1122,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.3 - version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0 + version: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-svg: specifier: 15.15.4 version: 15.15.4(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1245,7 +1245,7 @@ importers: version: link:../../packages/expo-ui '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.15.5(4cf81f97ae4861b2ec2ba3fb0b222013) '@react-navigation/native': specifier: ^7.1.33 version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1304,8 +1304,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.3 - version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0 + version: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) test-suite: specifier: workspace:* version: link:../test-suite @@ -1330,13 +1330,13 @@ importers: version: 15.1.1(expo-font@packages+expo-font)(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.15.5(4cf81f97ae4861b2ec2ba3fb0b222013) '@react-navigation/native': specifier: ^7.1.33 version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native-stack': specifier: ^7.14.5 - version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.14.5(4cf81f97ae4861b2ec2ba3fb0b222013) expo: specifier: workspace:* version: link:../../packages/expo @@ -1407,8 +1407,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.3 - version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0 + version: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) devDependencies: '@expo/config': specifier: workspace:* @@ -1477,8 +1477,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.3 - version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0 + version: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-web: specifier: ^0.21.0 version: 0.21.2(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -1576,7 +1576,7 @@ importers: version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) '@react-navigation/stack': specifier: ^7.8.5 - version: 7.8.5(5f603fd5b7fdee282854d7921c603411) + version: 7.8.5(12bc826df429feb25958fa59e16a7d42) async-retry: specifier: ^1.1.4 version: 1.3.3 @@ -5168,8 +5168,8 @@ importers: specifier: ^4.2.2 version: 4.2.2(7ddf79089c35e29e6117a946c4322c39) react-native-screens: - specifier: 4.25.0-beta.3 - version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ^4.25.0 + version: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) server-only: specifier: ^0.0.1 version: 0.0.1 @@ -14243,8 +14243,8 @@ packages: react: 19.2.3 react-native: 0.85.3 - react-native-screens@4.25.0-beta.3: - resolution: {integrity: sha512-LU5e8hlXvzQI3Ps8OGsG9pm/+FOY3XnNB2IKAsEkBgpJOyiZdVwkCogF/kM7XSzW6rG21Hib9CLMri6J4SpXCA==} + react-native-screens@4.25.0: + resolution: {integrity: sha512-CoE6W0perui0W4WK9fZFJfikUql/AYQFSJjnOGoXcPeteFb5Tursfmkot3vPOSu9lKWQMO6tlCIBQTC1CgbVRw==} peerDependencies: react: 19.2.3 react-native: 0.85.3 @@ -18896,7 +18896,7 @@ snapshots: transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@react-navigation/bottom-tabs@7.15.5(e6b77e6971707d55b305242378ff9e6b)': + '@react-navigation/bottom-tabs@7.15.5(4cf81f97ae4861b2ec2ba3fb0b222013)': dependencies: '@react-navigation/elements': 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native': 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -18904,7 +18904,7 @@ snapshots: react: 19.2.3 react-native: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - react-native-screens: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-screens: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) sf-symbols-typescript: 2.2.0 transitivePeerDependencies: - '@react-native-masked-view/masked-view' @@ -18921,7 +18921,7 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.3) use-sync-external-store: 1.6.0(react@19.2.3) - '@react-navigation/drawer@7.9.4(4baeb4b8b805b845dcda02e750a2f352)': + '@react-navigation/drawer@7.9.4(95132758d8004dd66bf72ef620b9fd08)': dependencies: '@react-navigation/elements': 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native': 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -18932,7 +18932,7 @@ snapshots: react-native-gesture-handler: 2.30.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-reanimated: 4.3.1(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - react-native-screens: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-screens: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) use-latest-callback: 0.2.6(react@19.2.3) transitivePeerDependencies: - '@react-native-masked-view/masked-view' @@ -18949,7 +18949,7 @@ snapshots: optionalDependencies: '@react-native-masked-view/masked-view': 0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - '@react-navigation/native-stack@7.14.5(e6b77e6971707d55b305242378ff9e6b)': + '@react-navigation/native-stack@7.14.5(4cf81f97ae4861b2ec2ba3fb0b222013)': dependencies: '@react-navigation/elements': 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native': 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -18957,7 +18957,7 @@ snapshots: react: 19.2.3 react-native: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - react-native-screens: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-screens: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) sf-symbols-typescript: 2.2.0 warn-once: 0.1.1 transitivePeerDependencies: @@ -18977,7 +18977,7 @@ snapshots: dependencies: nanoid: 3.3.11 - '@react-navigation/stack@7.8.5(5f603fd5b7fdee282854d7921c603411)': + '@react-navigation/stack@7.8.5(12bc826df429feb25958fa59e16a7d42)': dependencies: '@react-navigation/elements': 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native': 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -18986,7 +18986,7 @@ snapshots: react-native: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-gesture-handler: 2.30.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - react-native-screens: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-screens: 4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) use-latest-callback: 0.2.6(react@19.2.3) transitivePeerDependencies: - '@react-native-masked-view/masked-view' @@ -25192,7 +25192,7 @@ snapshots: react-native: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) warn-once: 0.1.1 - react-native-screens@4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3): + react-native-screens@4.25.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3): dependencies: react: 19.2.3 react-freeze: 1.0.4(react@19.2.3) diff --git a/templates/expo-template-default/package.json b/templates/expo-template-default/package.json index 653da7cbd8e3f5..0a61c04f96b8b3 100644 --- a/templates/expo-template-default/package.json +++ b/templates/expo-template-default/package.json @@ -33,7 +33,7 @@ "react-native-worklets": "0.8.3", "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "4.25.0", "react-native-web": "~0.21.0" }, "devDependencies": { diff --git a/templates/expo-template-tabs/package.json b/templates/expo-template-tabs/package.json index 0a96d9fcc35680..90bb61adbdf5d4 100644 --- a/templates/expo-template-tabs/package.json +++ b/templates/expo-template-tabs/package.json @@ -26,7 +26,7 @@ "react-native-worklets": "0.8.3", "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "4.25.0-beta.3", + "react-native-screens": "4.25.0", "react-native-web": "~0.21.0" }, "devDependencies": { From 840bcec717516658a964e71e3376e96b81a3ae51 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 11 May 2026 18:27:04 +0100 Subject: [PATCH 09/15] perf(metro-file-map): Add fast path to `TreeFS.#checkCandidateHasSubpath` (#45650) # Why The `TreeFS.hierarchicalLookup` code path is exercised quite often by Metro. It's called on each `getPackageForModule` lookup, effectively searching for `./package.json` at each parent hierarchically until the `node_modules` boundary. This is a special case that makes the `TreeFS.#checkCandidateHasSubpath` check trivial, which means it can be sped up. An improvement here (which is about 20%) yields an outsized improvement on resolution performance. # How - Add fast-path to `TreeFS.#checkCandidateHasSubpath` for simple sub-paths # Test Plan - Tests pass unchanged - New tests cover uncovered code paths # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/@expo/metro-file-map/CHANGELOG.md | 2 + .../@expo/metro-file-map/build/lib/TreeFS.js | 54 ++++++++++++- .../@expo/metro-file-map/src/lib/TreeFS.ts | 60 +++++++++++++- .../src/lib/__tests__/TreeFS.test.ts | 78 +++++++++++++++++++ 4 files changed, 190 insertions(+), 4 deletions(-) diff --git a/packages/@expo/metro-file-map/CHANGELOG.md b/packages/@expo/metro-file-map/CHANGELOG.md index 87916cd70fc03c..42c8d50c1e8620 100644 --- a/packages/@expo/metro-file-map/CHANGELOG.md +++ b/packages/@expo/metro-file-map/CHANGELOG.md @@ -12,6 +12,8 @@ ### 💡 Others +- Add hints and start node for `TreeFS.hierarchicalLookup` improving performance for metro's `getClosestPackage` lookups ([#45650](https://github.com/expo/expo/pull/45650) by [@kitten](https://github.com/kitten)) + ## 56.0.0 — 2026-05-08 ### 💡 Others diff --git a/packages/@expo/metro-file-map/build/lib/TreeFS.js b/packages/@expo/metro-file-map/build/lib/TreeFS.js index f6072673c499bb..60d39a614888cc 100644 --- a/packages/@expo/metro-file-map/build/lib/TreeFS.js +++ b/packages/@expo/metro-file-map/build/lib/TreeFS.js @@ -672,7 +672,11 @@ class TreeFS { collectLinkPaths: invalidatedBy, }); if (closestLookup.exists && isDirectory(closestLookup.node)) { - const maybeAbsolutePathMatch = this.#checkCandidateHasSubpath(closestLookup.canonicalPath, subpath, opts.subpathType, invalidatedBy, null); + const maybeAbsolutePathMatch = this.#checkCandidateHasSubpath(closestLookup.canonicalPath, subpath, opts.subpathType, invalidatedBy, { + ancestorOfRootIdx: closestLookup.ancestorOfRootIdx, + node: closestLookup.node, + pathIdx: closestLookup.canonicalPath.length > 0 ? closestLookup.canonicalPath.length + 1 : 0, + }); if (maybeAbsolutePathMatch != null) { return { absolutePath: maybeAbsolutePathMatch, @@ -755,7 +759,11 @@ class TreeFS { let nextNode = commonRoot; let depthBelowCommonRoot = 0; while (isDirectory(nextNode)) { - const maybeAbsolutePathMatch = this.#checkCandidateHasSubpath(candidateNormalPath, subpath, opts.subpathType, invalidatedBy, null); + const maybeAbsolutePathMatch = this.#checkCandidateHasSubpath(candidateNormalPath, subpath, opts.subpathType, invalidatedBy, { + ancestorOfRootIdx: commonRootDepth + depthBelowCommonRoot, + node: nextNode, + pathIdx: candidateNormalPath.length > 0 ? candidateNormalPath.length + 1 : 0, + }); if (maybeAbsolutePathMatch != null) { const rootDirParts = this.#pathUtils.getParts(); const relativeParts = depthBelowCommonRoot > 0 @@ -777,8 +785,50 @@ class TreeFS { return null; } #checkCandidateHasSubpath(normalCandidatePath, subpath, subpathType, invalidatedBy, start) { + // NOTE(@kitten): The most common call for package.json only needs a simple map + // lookup, and can skip traversal entirely + if (start != null && + subpath.length > 0 && + subpath !== '.' && + subpath !== '..' && + subpath.indexOf(path_1.default.sep) === -1) { + const child = start.node.get(subpath); + if (child == null) { + if (this.#fallbackFilesystem != null) { + // noop: fall through to slow-path + } + else { + if (invalidatedBy) { + invalidatedBy.add(this.#pathUtils.normalToAbsolute(normalCandidatePath === '' ? subpath : normalCandidatePath + path_1.default.sep + subpath)); + } + return null; + } + } + else { + const childIsDirectory = isDirectory(child); + if (!childIsDirectory && !isRegularFile(child)) { + // noop: Handle symlinks in the slow path, since it needs state tracking + } + else { + const absolutePath = this.#pathUtils.normalToAbsolute(normalCandidatePath === '' ? subpath : normalCandidatePath + path_1.default.sep + subpath); + if (childIsDirectory === (subpathType === 'd')) { + return absolutePath; + } + else { + if (invalidatedBy) + invalidatedBy.add(absolutePath); + return null; + } + } + } + } + // NOTE(@kitten): We can forward `start` if there's no indirection in the candidate path + const canForwardStart = start != null && + normalCandidatePath !== '..' && + !normalCandidatePath.endsWith(path_1.default.sep + '..'); const lookupResult = this.#lookupByNormalPath(this.#pathUtils.joinNormalToRelative(normalCandidatePath, subpath).normalPath, { collectLinkPaths: invalidatedBy, + start: canForwardStart ? start : undefined, }); if (lookupResult.exists && // Should be a Map iff subpathType is directory diff --git a/packages/@expo/metro-file-map/src/lib/TreeFS.ts b/packages/@expo/metro-file-map/src/lib/TreeFS.ts index 32bad8b56f3264..7495c731d8d743 100644 --- a/packages/@expo/metro-file-map/src/lib/TreeFS.ts +++ b/packages/@expo/metro-file-map/src/lib/TreeFS.ts @@ -939,7 +939,12 @@ export default class TreeFS implements MutableFileSystem { subpath, opts.subpathType, invalidatedBy, - null + { + ancestorOfRootIdx: closestLookup.ancestorOfRootIdx, + node: closestLookup.node, + pathIdx: + closestLookup.canonicalPath.length > 0 ? closestLookup.canonicalPath.length + 1 : 0, + } ); if (maybeAbsolutePathMatch != null) { return { @@ -1050,7 +1055,11 @@ export default class TreeFS implements MutableFileSystem { subpath, opts.subpathType, invalidatedBy, - null + { + ancestorOfRootIdx: commonRootDepth + depthBelowCommonRoot, + node: nextNode, + pathIdx: candidateNormalPath.length > 0 ? candidateNormalPath.length + 1 : 0, + } ); if (maybeAbsolutePathMatch != null) { const rootDirParts = this.#pathUtils.getParts(); @@ -1091,10 +1100,57 @@ export default class TreeFS implements MutableFileSystem { | null | undefined ): string | null { + // NOTE(@kitten): The most common call for package.json only needs a simple map + // lookup, and can skip traversal entirely + if ( + start != null && + subpath.length > 0 && + subpath !== '.' && + subpath !== '..' && + subpath.indexOf(path.sep) === -1 + ) { + const child = start.node.get(subpath); + if (child == null) { + if (this.#fallbackFilesystem != null) { + // noop: fall through to slow-path + } else { + if (invalidatedBy) { + invalidatedBy.add( + this.#pathUtils.normalToAbsolute( + normalCandidatePath === '' ? subpath : normalCandidatePath + path.sep + subpath + ) + ); + } + return null; + } + } else { + const childIsDirectory = isDirectory(child); + if (!childIsDirectory && !isRegularFile(child)) { + // noop: Handle symlinks in the slow path, since it needs state tracking + } else { + const absolutePath = this.#pathUtils.normalToAbsolute( + normalCandidatePath === '' ? subpath : normalCandidatePath + path.sep + subpath + ); + if (childIsDirectory === (subpathType === 'd')) { + return absolutePath; + } else { + if (invalidatedBy) invalidatedBy.add(absolutePath); + return null; + } + } + } + } + + // NOTE(@kitten): We can forward `start` if there's no indirection in the candidate path + const canForwardStart = + start != null && + normalCandidatePath !== '..' && + !normalCandidatePath.endsWith(path.sep + '..'); const lookupResult = this.#lookupByNormalPath( this.#pathUtils.joinNormalToRelative(normalCandidatePath, subpath).normalPath, { collectLinkPaths: invalidatedBy, + start: canForwardStart ? start! : undefined, } ); if ( diff --git a/packages/@expo/metro-file-map/src/lib/__tests__/TreeFS.test.ts b/packages/@expo/metro-file-map/src/lib/__tests__/TreeFS.test.ts index 2f706dfd5a1461..a988cbc24a92ea 100644 --- a/packages/@expo/metro-file-map/src/lib/__tests__/TreeFS.test.ts +++ b/packages/@expo/metro-file-map/src/lib/__tests__/TreeFS.test.ts @@ -845,6 +845,84 @@ describe.each([['win32'], ['posix']] as const)('TreeFS on %s', (platform) => { expect(invalidatedBy).toEqual(new Set(expectedInvalidatedBy.map(p))); } ); + + test('subpathType "d": matches directory child', () => { + const invalidatedBy = new Set(); + expect( + hlTfs.hierarchicalLookup(p('/A/B/C/a'), 'b', { + breakOnSegment: 'n_m', + invalidatedBy, + subpathType: 'd', + }) + ).toEqual({ absolutePath: p('/A/B/C/a/b'), containerRelativePath: '' }); + expect(invalidatedBy).toEqual(new Set()); + }); + + test('subpathType "d": skips file ancestor, matches directory ancestor', () => { + const invalidatedBy = new Set(); + expect( + hlTfs.hierarchicalLookup(p('/A/B/C/a/b/c/d/foo.js'), 'package.json', { + breakOnSegment: 'n_m', + invalidatedBy, + subpathType: 'd', + }) + ).toEqual({ + absolutePath: p('/A/B/C/a/b/package.json'), + containerRelativePath: p('c/d/foo.js'), + }); + expect(invalidatedBy).toEqual( + new Set([ + p('/A/B/C/a/b/c/d/foo.js'), + p('/A/B/C/a/b/c/d/package.json'), + p('/A/B/C/a/b/c/package.json'), + ]) + ); + }); + + test('multi-segment subpath resolves against Phase 1 candidate', () => { + const invalidatedBy = new Set(); + expect( + hlTfs.hierarchicalLookup(p('/A/B/C/a/n_m/pkg/foo.js'), p('subpath/package.json'), { + breakOnSegment: 'n_m', + invalidatedBy, + subpathType: 'f', + }) + ).toEqual({ + absolutePath: p('/A/B/C/a/n_m/pkg/subpath/package.json'), + containerRelativePath: 'foo.js', + }); + }); + + test('multi-segment subpath resolves against Phase 2 candidate above root', () => { + // Phase 2 candidate ends in `..`, so `start` is not forwarded to the + // slow path — joinNormalToRelative would otherwise collapse the suffix. + const invalidatedBy = new Set(); + expect( + hlTfs.hierarchicalLookup(p('/A/B/foo'), p('C/a/package.json'), { + breakOnSegment: 'n_m', + invalidatedBy, + subpathType: 'f', + }) + ).toEqual({ + absolutePath: p('/A/B/C/a/package.json'), + containerRelativePath: 'foo', + }); + expect(invalidatedBy).toEqual(new Set([p('/A/B/foo')])); + }); + + test('symlink at subpath resolves via slow path', () => { + const invalidatedBy = new Set(); + expect( + hlTfs.hierarchicalLookup(p('/A/B/C/a/1/foo.js'), 'package.json', { + breakOnSegment: 'n_m', + invalidatedBy, + subpathType: 'f', + }) + ).toEqual({ + absolutePath: p('/A/B/C/a/1/real-package.json'), + containerRelativePath: 'foo.js', + }); + }); }); describe('matchFiles', () => { From 34ef2f08b68d2e0b6ffd3d1ecf9f62ddc7256b0f Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 11 May 2026 18:27:58 +0100 Subject: [PATCH 10/15] fix(cli): Fix `LogRespectingTerminal` regressing on stderr on exit (#45641) # Why Fix regression in #45523 Because we use `console.*` methods, and these are buffered, output might be lost if we're logging just before we call `process.exit`. Similarly, other output in our CLI is lost when we're fatally crashing. # How - Add an `on('exit')` handler to `LogRespectingTerminal` that manually flushes - Guard with `isExiting` in `log.ts` that manually writes to `stdout`/`stderr` instead # Test Plan - Manually tested to restore fatal stderr output # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/@expo/cli/CHANGELOG.md | 2 ++ packages/@expo/cli/src/log.ts | 27 +++++++++++++++---- .../start/server/metro/instantiateMetro.ts | 10 +++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/packages/@expo/cli/CHANGELOG.md b/packages/@expo/cli/CHANGELOG.md index 7dff547eccdd92..3938996b3ff153 100644 --- a/packages/@expo/cli/CHANGELOG.md +++ b/packages/@expo/cli/CHANGELOG.md @@ -8,6 +8,8 @@ ### 🐛 Bug fixes +- Fix regression hiding stderr output on fatal exit ([#45641](https://github.com/expo/expo/pull/45641) by [@kitten](https://github.com/kitten)) + ### 💡 Others - Deserialize new `@expo/metro-config` packed source-map format and update to use new source-map representation internally ([#45594](https://github.com/expo/expo/pull/45594) by [@kitten](https://github.com/kitten)) diff --git a/packages/@expo/cli/src/log.ts b/packages/@expo/cli/src/log.ts index 4c1764f63c4552..ad4564ee2feb3a 100644 --- a/packages/@expo/cli/src/log.ts +++ b/packages/@expo/cli/src/log.ts @@ -1,5 +1,9 @@ import chalk from 'chalk'; +// NOTE(@kitten): LogRespectingTerminal in instantiateMetro regressed on fatal errors and +// logs may be swallowed before exiting. We redirect them to a direct write when we're about to exit +let isExiting = false; + export function time(label?: string): void { console.time(label); } @@ -9,6 +13,14 @@ export function timeEnd(label?: string): void { } export function error(...message: string[]): void { + if (isExiting) { + // `console.error` may be patched to route through an async stderr queue + // (see LogRespectingTerminal in instantiateMetro.ts). On the exit path + // that queue has no chance to drain before `process.exit`, so write + // synchronously to bypass it. + process.stderr.write(message.join(' ') + '\n'); + return; + } console.error(...message); } @@ -19,10 +31,18 @@ export function exception(e: Error): void { } export function warn(...message: string[]): void { + if (isExiting) { + process.stderr.write(message.map((value) => chalk.yellow(value)).join(' ') + '\n'); + return; + } console.warn(...message.map((value) => chalk.yellow(value))); } export function log(...message: string[]): void { + if (isExiting) { + process.stdout.write(message.join(' ') + '\n'); + return; + } console.log(...message); } @@ -38,19 +58,16 @@ export function clear(): void { /** Log a message and exit the current process. If the `code` is non-zero then `console.error` will be used instead of `console.log`. */ export function exit(message: string | Error, code: number = 1): never { + isExiting = true; if (message instanceof Error) { exception(message); - process.exit(code); - } - - if (message) { + } else if (message) { if (code === 0) { log(message); } else { error(message); } } - process.exit(code); } diff --git a/packages/@expo/cli/src/start/server/metro/instantiateMetro.ts b/packages/@expo/cli/src/start/server/metro/instantiateMetro.ts index 4b315bb60af1f0..b3992a994f026e 100644 --- a/packages/@expo/cli/src/start/server/metro/instantiateMetro.ts +++ b/packages/@expo/cli/src/start/server/metro/instantiateMetro.ts @@ -127,6 +127,16 @@ class LogRespectingTerminal extends Terminal { console.info = sendLog; console.warn = sendStderr; console.error = sendStderr; + + // NOTE(@kitten): We flush the stderr queue immediately when we're about to exit + process.on('exit', () => { + if (!this.#drainingStderr && this.#stderrQueue.length) { + this.#drainingStderr = true; + this.status(''); + const lines = this.#stderrQueue.splice(0); + process.stderr.write(lines.join('\n') + '\n'); + } + }); } /** Write to stderr without corrupting Terminal's cursor tracking. */ From c97bd328f03cb684226f8bec277d9297942a395f Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 11 May 2026 18:35:30 +0100 Subject: [PATCH 11/15] chore: Fix pnpm lockfile post merge conflict (#45652) # Why # How # Test Plan # Checklist - [ ] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 956d1538e93007..f081c5b877006f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1573,7 +1573,7 @@ importers: version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native-stack': specifier: ^7.14.5 - version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) + version: 7.14.5(4cf81f97ae4861b2ec2ba3fb0b222013) '@react-navigation/stack': specifier: ^7.8.5 version: 7.8.5(12bc826df429feb25958fa59e16a7d42) From b180ac37de435a0ec7251d0cdb30e4e4e5d63d31 Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Mon, 11 May 2026 19:43:41 +0200 Subject: [PATCH 12/15] [ui] add scrollIndicators modifier (#45649) --- .../src/screens/UI/ScrollViewScreen.ios.tsx | 94 +++++++++++++++---- .../expo-ui/swift-ui/modifiers.json | 2 +- packages/expo-ui/CHANGELOG.md | 4 + .../build/swift-ui/ScrollView/index.d.ts | 5 +- .../build/swift-ui/ScrollView/index.d.ts.map | 2 +- .../build/swift-ui/modifiers/index.d.ts | 16 +++- .../build/swift-ui/modifiers/index.d.ts.map | 2 +- .../ios/Convertibles/AxisOptions.swift | 19 ++++ .../ScrollIndicatorVisibilityOptions.swift | 22 +++++ .../ContainerRelativeFrameModifier.swift | 19 +--- .../Modifiers/ScrollIndicatorsModifier.swift | 13 +++ .../ios/Modifiers/ViewModifierRegistry.swift | 21 +---- .../expo-ui/src/swift-ui/ScrollView/index.tsx | 5 +- .../expo-ui/src/swift-ui/modifiers/index.ts | 19 ++++ 14 files changed, 181 insertions(+), 62 deletions(-) create mode 100644 packages/expo-ui/ios/Convertibles/AxisOptions.swift create mode 100644 packages/expo-ui/ios/Convertibles/ScrollIndicatorVisibilityOptions.swift create mode 100644 packages/expo-ui/ios/Modifiers/ScrollIndicatorsModifier.swift diff --git a/apps/native-component-list/src/screens/UI/ScrollViewScreen.ios.tsx b/apps/native-component-list/src/screens/UI/ScrollViewScreen.ios.tsx index 0e4c1d6ffc6b76..7be7bd0499fc09 100644 --- a/apps/native-component-list/src/screens/UI/ScrollViewScreen.ios.tsx +++ b/apps/native-component-list/src/screens/UI/ScrollViewScreen.ios.tsx @@ -1,9 +1,17 @@ -import { Host, ScrollView, VStack, Text, RoundedRectangle } from '@expo/ui/swift-ui'; -import { frame, foregroundStyle, padding, font } from '@expo/ui/swift-ui/modifiers'; +import { HStack, Host, ScrollView, VStack, Text, RoundedRectangle } from '@expo/ui/swift-ui'; +import { + frame, + foregroundStyle, + padding, + font, + scrollIndicators, +} from '@expo/ui/swift-ui/modifiers'; -export default function ScrollViewScreen() { +import { ScrollPage, Section } from '../../components/Page'; + +function VerticalExample() { return ( - + {Array.from({ length: 20 }, (_, i) => ( @@ -23,29 +31,58 @@ export default function ScrollViewScreen() { ); } -export function ScrollViewHorizontalScreen() { +function HorizontalExample() { return ( - + - {Array.from({ length: 20 }, (_, i) => ( - - ))} + + {Array.from({ length: 20 }, (_, i) => ( + + ))} + ); } -export function ScrollViewHideIndicatorsScreen() { +function BothAxesExample() { + const rows = 12; + const cols = 12; return ( - - + + + + {Array.from({ length: rows }, (_, r) => ( + + {Array.from({ length: cols }, (_, c) => ( + + ))} + + ))} + + + + ); +} + +function HideIndicatorsExample() { + return ( + + {Array.from({ length: 30 }, (_, i) => ( @@ -58,6 +95,25 @@ export function ScrollViewHideIndicatorsScreen() { ); } +export default function ScrollViewScreen() { + return ( + +
+ +
+
+ +
+
+ +
+
+ +
+
+ ); +} + ScrollViewScreen.navigationOptions = { title: 'ScrollView', }; diff --git a/docs/public/static/data/unversioned/expo-ui/swift-ui/modifiers.json b/docs/public/static/data/unversioned/expo-ui/swift-ui/modifiers.json index 68e998f44f0078..42fcf5e994cb3b 100644 --- a/docs/public/static/data/unversioned/expo-ui/swift-ui/modifiers.json +++ b/docs/public/static/data/unversioned/expo-ui/swift-ui/modifiers.json @@ -1 +1 @@ -{"schemaVersion":"2.0","name":"expo-ui/swift-ui/modifiers","variant":"project","kind":1,"children":[{"name":"ModifierConfig","variant":"declaration","kind":256,"comment":{"summary":[{"kind":"text","text":"Base interface for all view modifiers.\nAll modifiers must have a type field and can include arbitrary parameters."}]},"children":[{"name":"$type","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"eventListener","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"args","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"indexSignatures":[{"name":"__index","variant":"signature","kind":8192,"parameters":[{"name":"key","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"any"}}]},{"name":"ChainableAnimationType","variant":"declaration","kind":2097152,"children":[{"name":"[VALUE_SYMBOL]","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/swift-ui/modifiers/animation/types.ts","qualifiedName":"AnimationObject"},"name":"AnimationObject","package":"@expo/ui"}}]}}},{"name":"delay","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Adds a delay before the animation starts (in seconds)."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"delay","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}}},{"name":"repeat","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Repeats the animation the given number of times."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"autoreverses","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"repeatCount","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}}}]},{"name":"Color","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reference","target":{"packageName":"react-native","packagePath":"Libraries/StyleSheet/StyleSheet.d.ts","qualifiedName":"ColorValue"},"name":"ColorValue","package":"react-native"},{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/swift-ui/modifiers/types.ts","qualifiedName":"NamedColor"},"name":"NamedColor","package":"@expo/ui"}]}},{"name":"ContainerBackgroundPlacement","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"widget"},{"type":"literal","value":"navigation"},{"type":"literal","value":"navigationSplitView"}]}},{"name":"DatePickerStyleType","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"compact"},{"type":"literal","value":"graphical"},{"type":"literal","value":"wheel"}]}},{"name":"EnvironmentConfig","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"key","variant":"declaration","kind":1024,"type":{"type":"literal","value":"editMode"}},{"name":"value","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"active"},{"type":"literal","value":"inactive"},{"type":"literal","value":"transient"}]}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"key","variant":"declaration","kind":1024,"type":{"type":"literal","value":"colorScheme"}},{"name":"value","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"light"},{"type":"literal","value":"dark"}]}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"key","variant":"declaration","kind":1024,"type":{"type":"literal","value":"locale"}},{"name":"value","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"key","variant":"declaration","kind":1024,"type":{"type":"literal","value":"timeZone"}},{"name":"value","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}}]}}]}},{"name":"GaugeStyleType","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"circular"},{"type":"literal","value":"circularCapacity"},{"type":"literal","value":"linear"},{"type":"literal","value":"linearCapacity"}]}},{"name":"GlobalEvent","variant":"declaration","kind":2097152,"children":[{"name":"onGlobalEvent","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"event","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"nativeEvent","variant":"declaration","kind":1024,"type":{"type":"reference","name":"GlobalEventPayload","package":"@expo/ui"}}]}}}],"type":{"type":"intrinsic","name":"void"}}]}}}]},{"name":"GlobalEventPayload","variant":"declaration","kind":2097152,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"indexSignatures":[{"name":"__index","variant":"signature","kind":8192,"parameters":[{"name":"eventName","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Record"},"typeArguments":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"any"}],"name":"Record","package":"typescript"}}]}}},{"name":"IndexViewStyleConfig","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Configuration for the "},{"kind":"code","text":"`indexViewStyle`"},{"kind":"text","text":" modifier."}]},"children":[{"name":"backgroundDisplayMode","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Translucent background behind the page indicator dots. Useful when the\ndots sit on top of dark or busy content."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"'automatic'"}]}]},"type":{"type":"reference","name":"PageIndexBackgroundDisplayMode","package":"@expo/ui"}}]},{"name":"InterpolatingSpringAnimationParams","variant":"declaration","kind":2097152,"children":[{"name":"bounce","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Extra bounce to apply to the spring animation."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"damping","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The damping applied to the spring."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"duration","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Total animation duration (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"initialVelocity","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The initial velocity of the animation."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"mass","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The mass attached to the spring."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"stiffness","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The stiffness of the spring."}]},"type":{"type":"intrinsic","name":"number"}}]},{"name":"ListStyle","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"plain"},{"type":"literal","value":"inset"},{"type":"literal","value":"insetGrouped"},{"type":"literal","value":"grouped"},{"type":"literal","value":"sidebar"}]}},{"name":"PageIndexBackgroundDisplayMode","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"always"},{"type":"literal","value":"never"},{"type":"literal","value":"interactive"}]}},{"name":"PageIndexDisplayMode","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"always"},{"type":"literal","value":"never"}]}},{"name":"PickerStyleType","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"inline"},{"type":"literal","value":"menu"},{"type":"literal","value":"navigationLink"},{"type":"literal","value":"palette"},{"type":"literal","value":"segmented"},{"type":"literal","value":"wheel"}]}},{"name":"PresentationBackgroundInteractionType","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Presentation background interaction type."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"enabled"},{"type":"literal","value":"disabled"},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"detent","variant":"declaration","kind":1024,"type":{"type":"reference","name":"PresentationDetent","package":"@expo/ui"}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"enabledUpThrough"}}]}}]}},{"name":"PresentationDetent","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Presentation detent type for controlling sheet heights.\n- "},{"kind":"code","text":"`'medium'`"},{"kind":"text","text":": System medium height (approximately half screen)\n- "},{"kind":"code","text":"`'large'`"},{"kind":"text","text":": System large height (full screen)\n- "},{"kind":"code","text":"`{ fraction: number }`"},{"kind":"text","text":": Fraction of screen height (0-1, for example, 0.4 equals to 40% of screen)\n- "},{"kind":"code","text":"`{ height: number }`"},{"kind":"text","text":": Fixed height in points"}]},"type":{"type":"union","types":[{"type":"literal","value":"medium"},{"type":"literal","value":"large"},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"fraction","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}]}},{"name":"ProgressViewStyleType","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"linear"},{"type":"literal","value":"circular"}]}},{"name":"Shape","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.roundedRectangle","package":"@expo/ui","qualifiedName":"__object.roundedRectangle"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.capsule","package":"@expo/ui","qualifiedName":"__object.capsule"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.rectangle","package":"@expo/ui","qualifiedName":"__object.rectangle"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.ellipse","package":"@expo/ui","qualifiedName":"__object.ellipse"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.circle","package":"@expo/ui","qualifiedName":"__object.circle"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.containerRelativeShape","package":"@expo/ui","qualifiedName":"__object.containerRelativeShape"}}],"name":"ReturnType","package":"typescript"}]}},{"name":"SpringAnimationParams","variant":"declaration","kind":2097152,"children":[{"name":"blendDuration","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The duration over which to blend between animations (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"bounce","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Extra bounce to apply to the spring animation."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"dampingFraction","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The amount of damping applied to the spring's motion."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"duration","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Total animation duration (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"response","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The spring's response time (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}}]},{"name":"TabViewStyleConfig","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Configuration for the "},{"kind":"code","text":"`tabViewStyle`"},{"kind":"text","text":" modifier.\n\n - "},{"kind":"code","text":"`'page'`"},{"kind":"text","text":" — swipeable horizontal pager with optional dot indicators.\n - "},{"kind":"code","text":"`'automatic'`"},{"kind":"text","text":" — SwiftUI's default tab-bar style.\n - "},{"kind":"code","text":"`'sidebarAdaptable'`"},{"kind":"text","text":" — iOS 18+. Sidebar on iPad/Mac, bottom bar on\n iPhone."}]},"type":{"type":"union","types":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"indexDisplayMode","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Visibility of the page indicator dots. Only meaningful for the page style."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"'automatic'"}]}]},"type":{"type":"reference","name":"PageIndexDisplayMode","package":"@expo/ui"}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"page"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"automatic"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"sidebarAdaptable"}}]}}]}},{"name":"TimingAnimationParams","variant":"declaration","kind":2097152,"children":[{"name":"duration","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Total animation duration (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}}]},{"name":"UnitPointValue","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"zero"},{"type":"literal","value":"topLeading"},{"type":"literal","value":"top"},{"type":"literal","value":"topTrailing"},{"type":"literal","value":"leading"},{"type":"literal","value":"center"},{"type":"literal","value":"trailing"},{"type":"literal","value":"bottomLeading"},{"type":"literal","value":"bottom"},{"type":"literal","value":"bottomTrailing"}]}},{"name":"Animation","variant":"declaration","kind":32,"flags":{"isConst":true},"comment":{"summary":[{"kind":"text","text":"Built-in animation presets for the "},{"kind":"code","text":"`animation`"},{"kind":"text","text":" modifier.\nPresets:\n- Timing presets ("},{"kind":"code","text":"`easeInOut`"},{"kind":"text","text":", "},{"kind":"code","text":"`easeIn`"},{"kind":"text","text":", "},{"kind":"code","text":"`easeOut`"},{"kind":"text","text":", "},{"kind":"code","text":"`linear`"},{"kind":"text","text":") accept\n["},{"kind":"code","text":"`TimingAnimationParams`"},{"kind":"text","text":"](#timinganimationparams).\n- "},{"kind":"code","text":"`spring`"},{"kind":"text","text":" accepts ["},{"kind":"code","text":"`SpringAnimationParams`"},{"kind":"text","text":"](#springanimationparams).\n- "},{"kind":"code","text":"`interpolatingSpring`"},{"kind":"text","text":" accepts\n["},{"kind":"code","text":"`InterpolatingSpringAnimationParams`"},{"kind":"text","text":"](#interpolatingspringanimationparams).\n- Chaining returns ["},{"kind":"code","text":"`ChainableAnimationType`"},{"kind":"text","text":"](#chainableanimationtype)."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\nimport { Host, VStack } from '@expo/ui/swift-ui';\nimport { animation, Animation } from '@expo/ui/swift-ui/modifiers';\n\nfunction Example() {\n const [isExpanded, setIsExpanded] = useState(false);\n\n return (\n \n \n //...\n \n \n );\n}\n```"}]},{"tag":"@hideType","content":[]}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"default","variant":"declaration","kind":1024,"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"},"defaultValue":"..."},{"name":"easeIn","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"TimingAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"easeInOut","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"TimingAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"easeOut","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"TimingAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"interpolatingSpring","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"InterpolatingSpringAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"linear","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"TimingAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"spring","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"SpringAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."}]}},"defaultValue":"..."},{"name":"shapes","variant":"declaration","kind":32,"flags":{"isConst":true},"comment":{"summary":[{"kind":"text","text":"Shape builders for modifiers that accept shapes, such as "},{"kind":"code","text":"`background`"},{"kind":"text","text":" and "},{"kind":"code","text":"`containerShape`"},{"kind":"text","text":".\n\nShapes: "},{"kind":"code","text":"`roundedRectangle`"},{"kind":"text","text":", "},{"kind":"code","text":"`capsule`"},{"kind":"text","text":", "},{"kind":"code","text":"`rectangle`"},{"kind":"text","text":", "},{"kind":"code","text":"`ellipse`"},{"kind":"text","text":", "},{"kind":"code","text":"`circle`"},{"kind":"text","text":", "},{"kind":"code","text":"`containerRelativeShape`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\nimport { background, shapes } from '@expo/ui/swift-ui/modifiers';\nimport { Text, Host } from '@expo/ui/swift-ui';\n\nfunction Example() {\n return (\n \n \n Hello, world!\n
\n
\n );\n}\n```"}]},{"tag":"@hideType","content":[]}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"capsule","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"roundedCornerStyle","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"continuous"},{"type":"literal","value":"circular"}]}}]}}}],"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"roundedCornerStyle","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"continuous"},{"type":"literal","value":"circular"},{"type":"intrinsic","name":"undefined"}]},"defaultValue":"params.roundedCornerStyle"},{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'capsule'"}]}}}]}},"defaultValue":"..."},{"name":"circle","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'circle'"}]}}}]}},"defaultValue":"..."},{"name":"containerRelativeShape","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'containerRelativeShape'"}]}}}]}},"defaultValue":"..."},{"name":"ellipse","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'ellipse'"}]}}}]}},"defaultValue":"..."},{"name":"rectangle","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'rectangle'"}]}}}]}},"defaultValue":"..."},{"name":"roundedRectangle","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"cornerRadius","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"cornerSize","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"roundedCornerStyle","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"continuous"},{"type":"literal","value":"circular"}]}}]}}}],"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"cornerRadius","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"undefined"}]},"defaultValue":"params.cornerRadius"},{"name":"cornerSize","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}},{"type":"intrinsic","name":"undefined"}]},"defaultValue":"params.cornerSize"},{"name":"roundedCornerStyle","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"continuous"},{"type":"literal","value":"circular"},{"type":"intrinsic","name":"undefined"}]},"defaultValue":"params.roundedCornerStyle"},{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'roundedRectangle'"}]}}}]}},"defaultValue":"..."}]}},"defaultValue":"..."},{"name":"accessibilityHint","variant":"declaration","kind":64,"signatures":[{"name":"accessibilityHint","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets accessibility hint for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/accessibilityhint(_:))."}]}]},"parameters":[{"name":"hint","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The accessibility hint."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"accessibilityLabel","variant":"declaration","kind":64,"signatures":[{"name":"accessibilityLabel","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets accessibility label for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/accessibilitylabel(_:))."}]}]},"parameters":[{"name":"label","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The accessibility label."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"accessibilityValue","variant":"declaration","kind":64,"signatures":[{"name":"accessibilityValue","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets accessibility value for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/accessibilityvalue(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The accessibility value."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"allowsTightening","variant":"declaration","kind":64,"signatures":[{"name":"allowsTightening","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets whether text in this view can compress the space between characters when necessary to fit text in a line"}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"true"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/allowstightening(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"animation","variant":"declaration","kind":64,"signatures":[{"name":"animation","variant":"signature","kind":4096,"parameters":[{"name":"animationObject","variant":"param","kind":32768,"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}},{"name":"animatedValue","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"boolean"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"aspectRatio","variant":"declaration","kind":64,"signatures":[{"name":"aspectRatio","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets aspect ratio constraint."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/aspectratio(_:contentmode:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Optional width/height aspect ratio and content mode."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"contentMode","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"fill"},{"type":"literal","value":"fit"}]}},{"name":"ratio","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"autocorrectionDisabled","variant":"declaration","kind":64,"signatures":[{"name":"autocorrectionDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables autocorrection for text input views."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/autocorrectiondisabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether autocorrection is disabled. Defaults to "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"background","variant":"declaration","kind":64,"signatures":[{"name":"background","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the background of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/background(_:alignment:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The background color (hex string). For example, "},{"kind":"code","text":"`#FF0000`"},{"kind":"text","text":"."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"shape","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional shape to clip the background. If not provided, the background will fill the entire view."}]},"type":{"type":"reference","name":"Shape","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"backgroundOverlay","variant":"declaration","kind":64,"signatures":[{"name":"backgroundOverlay","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a background behind the view."}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Background color and alignment."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"alignment","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"}]}},{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"badge","variant":"declaration","kind":64,"signatures":[{"name":"badge","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Generates a badge for the view from a localized string key."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/badge(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Text view to display as a badge. Set the value to nil to hide the badge."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"badgeProminence","variant":"declaration","kind":64,"signatures":[{"name":"badgeProminence","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"The prominence to apply to badges associated with this environment."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/badgeprominence(_:))."}]}]},"parameters":[{"name":"badgeType","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Select the type of badge"}]},"type":{"type":"union","types":[{"type":"literal","value":"standard"},{"type":"literal","value":"increased"},{"type":"literal","value":"decreased"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"blur","variant":"declaration","kind":64,"signatures":[{"name":"blur","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies blur to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/blur(radius:opaque:))."}]}]},"parameters":[{"name":"radius","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The blur radius."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"bold","variant":"declaration","kind":64,"signatures":[{"name":"bold","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Makes text bold.\nWhen applied to "},{"kind":"code","text":"`Text`"},{"kind":"text","text":", it works on all iOS/tvOS versions. When used on regular views, it requires iOS 16.0+/tvOS 16.0+."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/text/bold())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"border","variant":"declaration","kind":64,"signatures":[{"name":"border","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a border to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/border(_:width:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The border parameters. Color and width."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"width","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"brightness","variant":"declaration","kind":64,"signatures":[{"name":"brightness","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adjusts the brightness of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/brightness(_:))."}]}]},"parameters":[{"name":"amount","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Brightness adjustment (-1 to 1)."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"buttonStyle","variant":"declaration","kind":64,"signatures":[{"name":"buttonStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the button style for button views."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/buttonstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The button style. "},{"kind":"code","text":"`'glass'`"},{"kind":"text","text":" and "},{"kind":"code","text":"`'glassProminent'`"},{"kind":"text","text":" are available on iOS 26+ and tvOS 26+ only."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"bordered"},{"type":"literal","value":"borderedProminent"},{"type":"literal","value":"borderless"},{"type":"literal","value":"glass"},{"type":"literal","value":"glassProminent"},{"type":"literal","value":"plain"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"clipped","variant":"declaration","kind":64,"signatures":[{"name":"clipped","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Clips content to bounds."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/clipped(antialiased:))."}]}]},"parameters":[{"name":"clipped","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to clip content."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"clipShape","variant":"declaration","kind":64,"signatures":[{"name":"clipShape","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Clips the view to a specific shape."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/clipshape(_:style:))."}]}]},"parameters":[{"name":"shape","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The clipping shape."}]},"type":{"type":"union","types":[{"type":"literal","value":"roundedRectangle"},{"type":"literal","value":"capsule"},{"type":"literal","value":"rectangle"},{"type":"literal","value":"ellipse"},{"type":"literal","value":"circle"},{"type":"literal","value":"containerRelativeShape"}]}},{"name":"cornerRadius","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Corner radius for rounded rectangle (default: 8)"}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"colorInvert","variant":"declaration","kind":64,"signatures":[{"name":"colorInvert","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Inverts the colors of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/colorinvert())."}]}]},"parameters":[{"name":"inverted","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to invert colors."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"containerBackground","variant":"declaration","kind":64,"signatures":[{"name":"containerBackground","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the container background of the enclosing container using a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/containerbackground(_:for:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The color to set as the background of the container."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"container","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The type of container to apply the background to."}]},"type":{"type":"reference","name":"ContainerBackgroundPlacement","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"containerRelativeFrame","variant":"declaration","kind":64,"signatures":[{"name":"containerRelativeFrame","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Positions this view within an invisible frame with a size relative to the nearest container."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/containerRelativeFrame(_:alignment:))."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 17.0+"}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The content relative frame parameters: "},{"kind":"code","text":"`axes`"},{"kind":"text","text":", "},{"kind":"code","text":"`count`"},{"kind":"text","text":", "},{"kind":"code","text":"`span`"},{"kind":"text","text":", "},{"kind":"code","text":"`spacing`"},{"kind":"text","text":" and "},{"kind":"code","text":"`alignment`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"alignment","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"topLeading"},{"type":"literal","value":"topTrailing"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"bottomLeading"},{"type":"literal","value":"bottomTrailing"}]}},{"name":"axes","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"},{"type":"literal","value":"both"}]}},{"name":"count","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"spacing","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"span","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"containerShape","variant":"declaration","kind":64,"signatures":[{"name":"containerShape","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the container shape for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/containershape(_:))."}]}]},"parameters":[{"name":"shape","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A shape configuration from the shapes API"}]},"type":{"type":"reference","name":"Shape","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"contentShape","variant":"declaration","kind":64,"signatures":[{"name":"contentShape","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Defines the content shape for hit-testing purposes.\n\nThis modifier is essential for making entire view areas (including "},{"kind":"code","text":"`Spacer`"},{"kind":"text","text":" or empty space)\ninteractive. Without it, only visible elements like "},{"kind":"code","text":"`Text`"},{"kind":"text","text":" or "},{"kind":"code","text":"`Image`"},{"kind":"text","text":" respond to tap gestures."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\nimport { HStack, List, Section, Spacer, Text } from \"@expo/ui/swift-ui\";\nimport { contentShape, onTapGesture } from \"@expo/ui/swift-ui/modifiers\";\nimport { shapes } from \"@expo/ui/swift-ui/modifiers\";\n\nfunction InteractiveRow() {\n return (\n \n
\n console.log(\"Row tapped!\"))\n ]}\n >\n Label\n \n Value\n \n
\n
\n );\n}\n```"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/contentshape(_:eofill:))."}]}]},"parameters":[{"name":"shape","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A shape configuration from the shapes API (rectangle, circle, capsule, ellipse, roundedRectangle)."}]},"type":{"type":"reference","name":"Shape","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"contentTransition","variant":"declaration","kind":64,"signatures":[{"name":"contentTransition","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the content transition type for a view.\nUseful for animating changes in text content, especially numeric text.\nUse with the ["},{"kind":"code","text":"`animation`"},{"kind":"text","text":"](#animationanimationobject-animatedvalue) modifier to animate the transition when the content changes."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\n\n {count.toString()}\n\n```"}]},{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/contenttransition(_:))."}]}]},"parameters":[{"name":"transitionType","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The type of content transition."}]},"type":{"type":"union","types":[{"type":"literal","value":"identity"},{"type":"literal","value":"numericText"},{"type":"literal","value":"opacity"},{"type":"literal","value":"interpolate"}]}},{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional parameters."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"countsDown","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Whether the numeric text counts down."}]},"type":{"type":"intrinsic","name":"boolean"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"contrast","variant":"declaration","kind":64,"signatures":[{"name":"contrast","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adjusts the contrast of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/contrast(_:))."}]}]},"parameters":[{"name":"amount","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Contrast multiplier (0 to infinity, 1 = normal)."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"controlSize","variant":"declaration","kind":64,"signatures":[{"name":"controlSize","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the size of controls within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/controlsize(_:))."}]}]},"parameters":[{"name":"size","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The control size."}]},"type":{"type":"union","types":[{"type":"literal","value":"small"},{"type":"literal","value":"large"},{"type":"literal","value":"mini"},{"type":"literal","value":"regular"},{"type":"literal","value":"extraLarge"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"cornerRadius","variant":"declaration","kind":64,"signatures":[{"name":"cornerRadius","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies corner radius to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/cornerradius(_:antialiased:))."}]}]},"parameters":[{"name":"radius","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The corner radius value."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"createModifier","variant":"declaration","kind":64,"signatures":[{"name":"createModifier","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Factory function to create modifier configuration objects.\nThis is used by all built-in modifier functions and can be used by 3rd party libraries to create custom modifiers."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A "},{"kind":"code","text":"`ModifierConfig`"},{"kind":"text","text":" object that can be passed in the "},{"kind":"code","text":"`modifiers`"},{"kind":"text","text":" prop array."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\n// In a 3rd party package\nimport { createModifier } from '@expo/ui/swift-ui/modifiers';\n\nexport const blurEffect = (params: { radius: number; style?: string }) =>\n createModifier('blurEffect', params);\n```"}]}]},"parameters":[{"name":"type","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The modifier type string that maps to a registered native modifier."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Additional parameters to pass to the modifier."}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Record"},"typeArguments":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"any"}],"name":"Record","package":"typescript"},"defaultValue":"{}"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"createModifierWithEventListener","variant":"declaration","kind":64,"signatures":[{"name":"createModifierWithEventListener","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Creates a modifier with an event listener."}]},"parameters":[{"name":"type","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"eventListener","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"args","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"params","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Record"},"typeArguments":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"any"}],"name":"Record","package":"typescript"},"defaultValue":"{}"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"createViewModifierEventListener","variant":"declaration","kind":64,"signatures":[{"name":"createViewModifierEventListener","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Create an event listener for a view modifier."}]},"parameters":[{"name":"modifiers","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of modifier configs to extract event listeners from."}]},"type":{"type":"array","elementType":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}}],"type":{"type":"reference","name":"GlobalEvent","package":"@expo/ui"}}]},{"name":"datePickerStyle","variant":"declaration","kind":64,"signatures":[{"name":"datePickerStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the date picker."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/datepickerstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The style for the date picker."}]},"type":{"type":"reference","name":"DatePickerStyleType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"defaultScrollAnchor","variant":"declaration","kind":64,"signatures":[{"name":"defaultScrollAnchor","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the default anchor point for a scroll view's content."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"macos 14.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/defaultscrollanchor(_:))."}]}]},"parameters":[{"name":"anchor","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The anchor point for initial scroll position and content size changes, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" to reset."}]},"type":{"type":"union","types":[{"type":"reference","name":"UnitPointValue","package":"@expo/ui"},{"type":"literal","value":null}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"defaultScrollAnchorForRole","variant":"declaration","kind":64,"signatures":[{"name":"defaultScrollAnchorForRole","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the default anchor point for a scroll view for a specific role.\nPass "},{"kind":"code","text":"`null`"},{"kind":"text","text":" to opt out of a specific role while keeping anchors for other roles."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 18.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 18.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"macos 15.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/defaultscrollanchor(_:for:))."}]}]},"parameters":[{"name":"anchor","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The anchor point, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" to opt out of this role."}]},"type":{"type":"union","types":[{"type":"reference","name":"UnitPointValue","package":"@expo/ui"},{"type":"literal","value":null}]}},{"name":"role","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The scroll anchor role: "},{"kind":"code","text":"`'initialOffset'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'sizeChanges'`"},{"kind":"text","text":", or "},{"kind":"code","text":"`'alignment'`"},{"kind":"text","text":"."}]},"type":{"type":"union","types":[{"type":"literal","value":"initialOffset"},{"type":"literal","value":"sizeChanges"},{"type":"literal","value":"alignment"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"deleteDisabled","variant":"declaration","kind":64,"signatures":[{"name":"deleteDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables the delete action for a view in a list.\nApply to items within a "},{"kind":"code","text":"`ForEach`"},{"kind":"text","text":" to prevent them from being deleted."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"true"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/deletedisabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether deletion should be disabled"}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"disabled","variant":"declaration","kind":64,"signatures":[{"name":"disabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables or enables a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/disabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether the view should be disabled."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"environment","variant":"declaration","kind":64,"signatures":[{"name":"environment","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets a SwiftUI environment value."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/environment(_:_:))."}]}]},"parameters":[{"name":"config","variant":"param","kind":32768,"type":{"type":"reference","name":"EnvironmentConfig","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}},{"name":"environment","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets a SwiftUI environment value."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/environment(_:_:))."}]}]},"parameters":[{"name":"key","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"literal","value":"colorScheme"},{"type":"literal","value":"editMode"},{"type":"literal","value":"locale"},{"type":"literal","value":"timeZone"}]}},{"name":"value","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"fixedSize","variant":"declaration","kind":64,"signatures":[{"name":"fixedSize","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls fixed size behavior."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/fixedsize())."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Whether the view should use its ideal width or height."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"horizontal","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"vertical","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"font","variant":"declaration","kind":64,"signatures":[{"name":"font","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the font properties of a view.\nSupports both custom font families and system fonts with weight and design options."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\n// Custom font family\nCustom Font Text\n\n// System font with weight and design\nSystem Font Text\n```"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation for "},{"kind":"code","text":"`custom(_:size:)`"},{"kind":"text","text":"](https://developer.apple.com/documentation/swiftui/font/custom(_:size:)) and Official [SwiftUI documentation for "},{"kind":"code","text":"`system(size:weight:design:)`"},{"kind":"text","text":"](https://developer.apple.com/documentation/swiftui/font/system(size:weight:design:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The font configuration. When "},{"kind":"code","text":"`family`"},{"kind":"text","text":" is provided, it uses Font.custom().\nWhen "},{"kind":"code","text":"`family`"},{"kind":"text","text":" is not provided, it uses Font.system() with the specified weight and design."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"design","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Font design for system fonts"}]},"type":{"type":"union","types":[{"type":"literal","value":"default"},{"type":"literal","value":"rounded"},{"type":"literal","value":"serif"},{"type":"literal","value":"monospaced"}]}},{"name":"family","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Custom font family name.\nIf provided, uses "},{"kind":"code","text":"`Font.custom()`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"size","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Font size in points."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"weight","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Font weight for system fonts."}]},"type":{"type":"union","types":[{"type":"literal","value":"light"},{"type":"literal","value":"bold"},{"type":"literal","value":"black"},{"type":"literal","value":"medium"},{"type":"literal","value":"regular"},{"type":"literal","value":"ultraLight"},{"type":"literal","value":"thin"},{"type":"literal","value":"semibold"},{"type":"literal","value":"heavy"}]}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"foregroundColor","variant":"declaration","kind":64,"signatures":[{"name":"foregroundColor","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the foreground color/tint of a view."}],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`foregroundStyle`"},{"kind":"text","text":" instead."}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/foregroundcolor(_:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The foreground color (hex string)."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"foregroundStyle","variant":"declaration","kind":64,"signatures":[{"name":"foregroundStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the foreground style of a view with comprehensive styling options.\n\nReplaces the deprecated "},{"kind":"code","text":"`foregroundColor`"},{"kind":"text","text":" modifier with enhanced capabilities including\ncolors, gradients, and semantic hierarchical styles that adapt to system appearance."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\n// Simple usage\nRed Text\n\n// Adaptive hierarchical styling\n\n Supporting Text\n\n\n// Linear gradient\n\n Gradient Text\n\n```"}]},{"tag":"@returns","content":[{"kind":"text","text":"A view modifier that applies the specified foreground style"}]},{"tag":"@since","content":[{"kind":"text","text":"iOS 15.0+ (hierarchical quinary requires iOS 16.0+)"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/foregroundstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The foreground style configuration. Can be:\n\n**Simple Color ("},{"kind":"code","text":"`Color`"},{"kind":"text","text":"):**\n- Hex colors: "},{"kind":"code","text":"`'#FF0000'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'#RGB'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'#RRGGBB'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'#AARRGGBB'`"},{"kind":"text","text":"\n- Named colors: "},{"kind":"code","text":"`'red'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'blue'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'green'`"},{"kind":"text","text":", and so on.\n- React Native color values like "},{"kind":"code","text":"`PlatformColor('label')`"},{"kind":"text","text":"\n\n**Explicit Color Object:**\n"},{"kind":"code","text":"```ts\n{ type: 'color', color: PlatformColor('label') }\n```"},{"kind":"text","text":"\n\n**Hierarchical Styles (Semantic):**\nAuto-adapting semantic styles that respond to light/dark mode and accessibility settings:\n"},{"kind":"code","text":"```ts\n{ type: 'hierarchical', style: 'primary' } // Most prominent (main content, headlines)\n{ type: 'hierarchical', style: 'secondary' } // Supporting text, subheadlines\n{ type: 'hierarchical', style: 'tertiary' } // Less important text, captions\n{ type: 'hierarchical', style: 'quaternary' } // Subtle text, disabled states\n{ type: 'hierarchical', style: 'quinary' } // Most subtle (iOS 16+, fallback to quaternary)\n```"},{"kind":"text","text":"\n\n**Linear Gradient:**\n"},{"kind":"code","text":"```ts\n{\n type: 'linearGradient',\n colors: [PlatformColor('systemPink'), '#0000FF', '#00FF00'],\n startPoint: { x: 0, y: 0 }, // Top-left\n endPoint: { x: 1, y: 1 } // Bottom-right\n}\n```"},{"kind":"text","text":"\n\n**Radial Gradient:**\n"},{"kind":"code","text":"```ts\n{\n type: 'radialGradient',\n colors: [PlatformColor('systemPink'), '#0000FF'],\n center: { x: 0.5, y: 0.5 }, // Center of view\n startRadius: 0, // Inner radius\n endRadius: 100 // Outer radius\n}\n```"},{"kind":"text","text":"\n\n**Angular Gradient (Conic):**\n"},{"kind":"code","text":"```ts\n{\n type: 'angularGradient',\n colors: [PlatformColor('systemPink'), '#00FF00', '#0000FF'],\n center: { x: 0.5, y: 0.5 } // Rotation center\n}\n```"}]},"type":{"type":"union","types":[{"type":"reference","name":"Color","package":"@expo/ui"},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"color"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"style","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"primary"},{"type":"literal","value":"secondary"},{"type":"literal","value":"tertiary"},{"type":"literal","value":"quaternary"},{"type":"literal","value":"quinary"}]}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"hierarchical"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"colors","variant":"declaration","kind":1024,"type":{"type":"array","elementType":{"type":"reference","name":"Color","package":"@expo/ui"}}},{"name":"endPoint","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"startPoint","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"linearGradient"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"center","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"colors","variant":"declaration","kind":1024,"type":{"type":"array","elementType":{"type":"reference","name":"Color","package":"@expo/ui"}}},{"name":"endRadius","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"startRadius","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"radialGradient"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"center","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"colors","variant":"declaration","kind":1024,"type":{"type":"array","elementType":{"type":"reference","name":"Color","package":"@expo/ui"}}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"angularGradient"}}]}}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"frame","variant":"declaration","kind":64,"signatures":[{"name":"frame","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the frame properties of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/frame(width:height:alignment:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The frame parameters. Width, height, minWidth, maxWidth, minHeight, maxHeight, idealWidth, idealHeight and alignment."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"alignment","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"topLeading"},{"type":"literal","value":"topTrailing"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"bottomLeading"},{"type":"literal","value":"bottomTrailing"}]}},{"name":"height","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"idealHeight","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"idealWidth","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"maxHeight","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"maxWidth","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"minHeight","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"minWidth","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gaugeStyle","variant":"declaration","kind":64,"signatures":[{"name":"gaugeStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the gauge."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/gaugestyle)."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The style for the gauge."}]},"type":{"type":"reference","name":"GaugeStyleType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"glassEffect","variant":"declaration","kind":64,"signatures":[{"name":"glassEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a glass effect to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/glasseffect(_:in:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The glass effect parameters. Variant, interactive, tint and shape."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"cornerRadius","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"glass","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"interactive","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"tint","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"variant","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"clear"},{"type":"literal","value":"regular"},{"type":"literal","value":"identity"}]}}]}}},{"name":"shape","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"roundedRectangle"},{"type":"literal","value":"capsule"},{"type":"literal","value":"rectangle"},{"type":"literal","value":"ellipse"},{"type":"literal","value":"circle"},{"type":"literal","value":"containerRelativeShape"}]}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"glassEffectId","variant":"declaration","kind":64,"signatures":[{"name":"glassEffectId","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Associates an identity value to Liquid Glass effects defined within a "},{"kind":"code","text":"`GlassEffectContainer`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/glasseffectid(_:in:))."}]}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The id of the glass effect."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"namespaceId","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The namespace id of the glass effect. Use Namespace component to create a namespace."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"grayscale","variant":"declaration","kind":64,"signatures":[{"name":"grayscale","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Makes a view grayscale."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/grayscale(_:))."}]}]},"parameters":[{"name":"amount","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Grayscale amount (0 to 1)."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gridCellAnchor","variant":"declaration","kind":64,"signatures":[{"name":"gridCellAnchor","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Specifies a custom alignment anchor for a view that acts as a grid cell."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that uses the specified anchor point to align its content."}]},{"tag":"@platform","content":[{"kind":"text","text":"iOS 16+"}]},{"tag":"@example","content":[{"kind":"code","text":"```tsx\n// Using a preset anchor\n\n\n// Using a custom anchor point\n\n```"}]}]},"parameters":[{"name":"anchor","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The unit point that defines how to align the view within the bounds of its grid cell."}]},"type":{"type":"union","types":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"anchor","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"zero"},{"type":"literal","value":"topLeading"},{"type":"literal","value":"topTrailing"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"bottomLeading"},{"type":"literal","value":"bottomTrailing"}]}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"preset"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"points","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"custom"}}]}}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gridCellColumns","variant":"declaration","kind":64,"signatures":[{"name":"gridCellColumns","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Tells a view that acts as a cell in a grid to span the specified number of columns."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that occupies the specified number of columns in a grid row."}]}]},"parameters":[{"name":"count","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The number of columns that the view should consume when placed in a grid row."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gridCellUnsizedAxes","variant":"declaration","kind":64,"signatures":[{"name":"gridCellUnsizedAxes","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Asks grid layouts not to offer the view extra size in the specified axes."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that doesn’t ask an enclosing grid for extra size in one or more axes."}]}]},"parameters":[{"name":"axes","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The dimensions in which the grid shouldn’t offer the view a share of any available space. This prevents a flexible view like a Spacer, Divider, or Color from defining the size of a row or column."}]},"type":{"type":"union","types":[{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gridColumnAlignment","variant":"declaration","kind":64,"signatures":[{"name":"gridColumnAlignment","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Overrides the default horizontal alignment of the grid column that the view appears in."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that uses the specified horizontal alignment, and that causes all cells in the same column of a grid to use the same alignment."}]},{"tag":"@platform","content":[{"kind":"text","text":"iOS 16+"}]}]},"parameters":[{"name":"alignment","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The HorizontalAlignment guide to use for the grid column that the view appears in."}]},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"headerProminence","variant":"declaration","kind":64,"signatures":[{"name":"headerProminence","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the header prominence for this view."}]},"parameters":[{"name":"prominence","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The prominence to apply."}]},"type":{"type":"union","types":[{"type":"literal","value":"standard"},{"type":"literal","value":"increased"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"hidden","variant":"declaration","kind":64,"signatures":[{"name":"hidden","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Hides or shows a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/hidden(_:))."}]}]},"parameters":[{"name":"hidden","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether the view should be hidden."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"hueRotation","variant":"declaration","kind":64,"signatures":[{"name":"hueRotation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a hue rotation to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/huerotation(_:))."}]}]},"parameters":[{"name":"angle","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Hue rotation angle in degrees."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"id","variant":"declaration","kind":64,"signatures":[{"name":"id","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Attaches a stable identifier to a view so it can be referenced by scroll target bindings.\nUse with "},{"kind":"code","text":"`scrollTargetLayout()`"},{"kind":"text","text":" on the containing stack and the "},{"kind":"code","text":"`scrollPosition`"},{"kind":"text","text":" modifier on a scrollable container."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/id(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"String identifier matched by "},{"kind":"code","text":"`scrollPosition`"},{"kind":"text","text":"'s observable state."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"ignoreSafeArea","variant":"declaration","kind":64,"signatures":[{"name":"ignoreSafeArea","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Allows a view to ignore safe area constraints."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ignoressafearea(_:edges:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The safe area regions to ignore and the edges to expand into."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"edges","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"},{"type":"literal","value":"all"}]}},{"name":"regions","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"container"},{"type":"literal","value":"all"},{"type":"literal","value":"keyboard"}]}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"indexViewStyle","variant":"declaration","kind":64,"signatures":[{"name":"indexViewStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the page index view inside a "},{"kind":"code","text":"`TabView`"},{"kind":"text","text":". SwiftUI only\nships a "},{"kind":"code","text":"`.page`"},{"kind":"text","text":" index view style, so no style selector is exposed."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/indexviewstyle(_:))."}]}]},"parameters":[{"name":"config","variant":"param","kind":32768,"type":{"type":"reference","name":"IndexViewStyleConfig","package":"@expo/ui"},"defaultValue":"{}"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"interactiveDismissDisabled","variant":"declaration","kind":64,"signatures":[{"name":"interactiveDismissDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables interactive dismissal of a sheet."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/interactivedismissdisabled(_:))."}]}]},"parameters":[{"name":"isDisabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether interactive dismiss is disabled (default: true)."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"italic","variant":"declaration","kind":64,"signatures":[{"name":"italic","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Makes text italic.\nWhen applied to "},{"kind":"code","text":"`Text`"},{"kind":"text","text":", it works on all iOS/tvOS versions. When used on regular views, it requires iOS 16.0+/tvOS 16.0+."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/text/italic())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"kerning","variant":"declaration","kind":64,"signatures":[{"name":"kerning","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the spacing, or kerning, between characters for the text in this view."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"0"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/kerning(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"keyboardType","variant":"declaration","kind":64,"signatures":[{"name":"keyboardType","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the keyboard type for text input views."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/keyboardtype(_:))."}]}]},"parameters":[{"name":"keyboardType","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The type of keyboard to display."}]},"type":{"type":"union","types":[{"type":"literal","value":"default"},{"type":"literal","value":"url"},{"type":"literal","value":"email-address"},{"type":"literal","value":"numeric"},{"type":"literal","value":"phone-pad"},{"type":"literal","value":"ascii-capable"},{"type":"literal","value":"numbers-and-punctuation"},{"type":"literal","value":"name-phone-pad"},{"type":"literal","value":"decimal-pad"},{"type":"literal","value":"twitter"},{"type":"literal","value":"web-search"},{"type":"literal","value":"ascii-capable-number-pad"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"labelsHidden","variant":"declaration","kind":64,"signatures":[{"name":"labelsHidden","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Hides the labels of any controls contained within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/labelshidden())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"labelStyle","variant":"declaration","kind":64,"signatures":[{"name":"labelStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for labels within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/labelstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The label style."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"iconOnly"},{"type":"literal","value":"titleAndIcon"},{"type":"literal","value":"titleOnly"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"layoutPriority","variant":"declaration","kind":64,"signatures":[{"name":"layoutPriority","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets layout priority for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/layoutpriority(_:))."}]}]},"parameters":[{"name":"priority","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Layout priority value."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"lineHeight","variant":"declaration","kind":64,"signatures":[{"name":"lineHeight","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the total line height for text in this view."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 26.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"macos 26.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 26.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/lineheight(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The line height in points."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"lineLimit","variant":"declaration","kind":64,"signatures":[{"name":"lineLimit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the line limit for text in the view.\n\nFour variants matching SwiftUI:\n- "},{"kind":"code","text":"`lineLimit()`"},{"kind":"text","text":" — no line limit (unlimited lines)\n- "},{"kind":"code","text":"`lineLimit(5)`"},{"kind":"text","text":" — max 5 lines\n- "},{"kind":"code","text":"`lineLimit(5, { reservesSpace: true })`"},{"kind":"text","text":" — max 5 lines, reserves height even when empty (iOS 16+, tvOS 16+)\n- "},{"kind":"code","text":"`lineLimit({ min: 3, max: 8 })`"},{"kind":"text","text":" — range of 3 to 8 lines (iOS 16+, tvOS 16+)"}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/linelimit(_:))."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}},{"name":"lineLimit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the line limit for text in the view.\n\nFour variants matching SwiftUI:\n- "},{"kind":"code","text":"`lineLimit()`"},{"kind":"text","text":" — no line limit (unlimited lines)\n- "},{"kind":"code","text":"`lineLimit(5)`"},{"kind":"text","text":" — max 5 lines\n- "},{"kind":"code","text":"`lineLimit(5, { reservesSpace: true })`"},{"kind":"text","text":" — max 5 lines, reserves height even when empty (iOS 16+, tvOS 16+)\n- "},{"kind":"code","text":"`lineLimit({ min: 3, max: 8 })`"},{"kind":"text","text":" — range of 3 to 8 lines (iOS 16+, tvOS 16+)"}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/linelimit(_:))."}]}]},"parameters":[{"name":"limit","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"number"}},{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"reservesSpace","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}},{"name":"lineLimit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the line limit for text in the view.\n\nFour variants matching SwiftUI:\n- "},{"kind":"code","text":"`lineLimit()`"},{"kind":"text","text":" — no line limit (unlimited lines)\n- "},{"kind":"code","text":"`lineLimit(5)`"},{"kind":"text","text":" — max 5 lines\n- "},{"kind":"code","text":"`lineLimit(5, { reservesSpace: true })`"},{"kind":"text","text":" — max 5 lines, reserves height even when empty (iOS 16+, tvOS 16+)\n- "},{"kind":"code","text":"`lineLimit({ min: 3, max: 8 })`"},{"kind":"text","text":" — range of 3 to 8 lines (iOS 16+, tvOS 16+)"}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/linelimit(_:))."}]}]},"parameters":[{"name":"range","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"max","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"min","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"lineSpacing","variant":"declaration","kind":64,"signatures":[{"name":"lineSpacing","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"The distance in points between the bottom of one line fragment and the top of the next."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/linespacing(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The amount of space between the bottom of one line and the top of the next line in points. This value is always nonnegative. Otherwise, the default value will be used."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listRowBackground","variant":"declaration","kind":64,"signatures":[{"name":"listRowBackground","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the background of a row."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/listrowbackground(_:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The row color (hex string). For example, "},{"kind":"code","text":"`#FF0000`"},{"kind":"text","text":"."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listRowInsets","variant":"declaration","kind":64,"signatures":[{"name":"listRowInsets","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies an inset to the rows in a list."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/listrowinsets(_:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The inset to apply to the rows in a list."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"bottom","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"leading","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"top","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"trailing","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listRowSeparator","variant":"declaration","kind":64,"signatures":[{"name":"listRowSeparator","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls the visibility of the separator for a list row."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/listrowseparator(_:edges:))."}]}]},"parameters":[{"name":"visibility","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The visibility to apply."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"visible"},{"type":"literal","value":"hidden"}]}},{"name":"edges","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The edges where the separator visibility applies."}]},"type":{"type":"union","types":[{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"all"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listSectionMargins","variant":"declaration","kind":64,"signatures":[{"name":"listSectionMargins","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Allows a view to ignore safe area constraints."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"iOS 26+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/listsectionmargins(_:_:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The margins to apply to the section in a list."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"edges","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"},{"type":"literal","value":"all"}]}},{"name":"length","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listSectionSpacing","variant":"declaration","kind":64,"signatures":[{"name":"listSectionSpacing","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the spacing between adjacent sections."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]}]},"parameters":[{"name":"spacing","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The spacing to apply."}]},"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":"default"},{"type":"literal","value":"compact"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listStyle","variant":"declaration","kind":64,"signatures":[{"name":"listStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for a List view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/liststyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The list style to apply."}]},"type":{"type":"reference","name":"ListStyle","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"luminanceToAlpha","variant":"declaration","kind":64,"signatures":[{"name":"luminanceToAlpha","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a luminance to alpha effect to this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/luminanceToAlpha())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"mask","variant":"declaration","kind":64,"signatures":[{"name":"mask","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a mask to the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/mask(_:))."}]}]},"parameters":[{"name":"shape","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The masking shape."}]},"type":{"type":"union","types":[{"type":"literal","value":"roundedRectangle"},{"type":"literal","value":"capsule"},{"type":"literal","value":"rectangle"},{"type":"literal","value":"ellipse"},{"type":"literal","value":"circle"},{"type":"literal","value":"containerRelativeShape"}]}},{"name":"cornerRadius","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Corner radius for rounded rectangle (default: "},{"kind":"code","text":"`8`"},{"kind":"text","text":")."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"matchedGeometryEffect","variant":"declaration","kind":64,"signatures":[{"name":"matchedGeometryEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a matched geometry effect to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/matchedgeometryeffect(id:in:properties:anchor:issource:))."}]}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The id of the view."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"namespaceId","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The namespace id of the view. Use Namespace component to create a namespace."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"menuActionDismissBehavior","variant":"declaration","kind":64,"signatures":[{"name":"menuActionDismissBehavior","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls the dismissal behavior of menu actions."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.4+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 17.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/menuactiondismissbehavior(_:))."}]}]},"parameters":[{"name":"behavior","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The menu action dismiss behavior."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"enabled"},{"type":"literal","value":"disabled"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"monospacedDigit","variant":"declaration","kind":64,"signatures":[{"name":"monospacedDigit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Modifies the fonts of all child views to use fixed-width digits, if possible, while leaving other characters proportionally spaced.\nWhen applied to "},{"kind":"code","text":"`Text`"},{"kind":"text","text":", modifies the text view's font to use fixed-width digits, while leaving other characters proportionally spaced."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/monospaceddigit())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"moveDisabled","variant":"declaration","kind":64,"signatures":[{"name":"moveDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables the move action for a view in a list.\nApply to items within a "},{"kind":"code","text":"`ForEach`"},{"kind":"text","text":" to prevent them from being moved."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"true"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/movedisabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether moving should be disabled"}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"multilineTextAlignment","variant":"declaration","kind":64,"signatures":[{"name":"multilineTextAlignment","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"An alignment position for text along the horizontal axis."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/multilinetextalignment(_:))."}]}]},"parameters":[{"name":"alignment","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A value that you use to align multiple lines of text within a view."}]},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"offset","variant":"declaration","kind":64,"signatures":[{"name":"offset","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies an offset (translation) to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/offset(x:y:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The offset parameters: "},{"kind":"code","text":"`x`"},{"kind":"text","text":" and "},{"kind":"code","text":"`y`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onAppear","variant":"declaration","kind":64,"signatures":[{"name":"onAppear","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds an onAppear modifier that calls a function when the view appears."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/onappear(perform:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call when the view appears."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onDisappear","variant":"declaration","kind":64,"signatures":[{"name":"onDisappear","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds an onDisappear modifier that calls a function when the view disappears."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ondisappear(perform:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call when the view disappears."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onGeometryChange","variant":"declaration","kind":64,"signatures":[{"name":"onGeometryChange","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Calls the handler whenever the view's geometry changes. Sizes are in points."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ongeometrychange(for:of:action:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function called with the new size."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"size","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onLongPressGesture","variant":"declaration","kind":64,"signatures":[{"name":"onLongPressGesture","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a long press gesture recognizer."}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call when long pressed."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"minimumDuration","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Minimum duration for long press (default: 0.5s)"}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onSubmit","variant":"declaration","kind":64,"signatures":[{"name":"onSubmit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds an action to perform when the user submits a value to this view (e.g. pressing return in a text field)."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/onsubmit(of:_:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call on submit."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onTapGesture","variant":"declaration","kind":64,"signatures":[{"name":"onTapGesture","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a tap gesture recognizer."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ontapgesture(count:perform:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call when tapped."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"opacity","variant":"declaration","kind":64,"signatures":[{"name":"opacity","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the opacity of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/opacity(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Opacity value between 0 and 1."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"overlay","variant":"declaration","kind":64,"signatures":[{"name":"overlay","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Overlays another view on top."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/overlay(_:alignment:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Overlay color and alignment."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"alignment","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"}]}},{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"padding","variant":"declaration","kind":64,"signatures":[{"name":"padding","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets padding on a view.\nSupports individual edges or shorthand properties."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/padding(_:_:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The padding parameters: "},{"kind":"code","text":"`top`"},{"kind":"text","text":", "},{"kind":"code","text":"`bottom`"},{"kind":"text","text":", "},{"kind":"code","text":"`leading`"},{"kind":"text","text":", "},{"kind":"code","text":"`trailing`"},{"kind":"text","text":", "},{"kind":"code","text":"`horizontal`"},{"kind":"text","text":", "},{"kind":"code","text":"`vertical`"},{"kind":"text","text":" and "},{"kind":"code","text":"`all`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"all","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"bottom","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"horizontal","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"leading","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"top","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"trailing","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"vertical","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"pickerStyle","variant":"declaration","kind":64,"signatures":[{"name":"pickerStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the picker."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/pickerstyle)."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The style for the picker."}]},"type":{"type":"reference","name":"PickerStyleType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"presentationBackgroundInteraction","variant":"declaration","kind":64,"signatures":[{"name":"presentationBackgroundInteraction","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls interaction with the content behind a sheet."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.4+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.4+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/presentationbackgroundinteraction(_:))."}]}]},"parameters":[{"name":"interaction","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The background interaction behavior."}]},"type":{"type":"reference","name":"PresentationBackgroundInteractionType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"presentationDetents","variant":"declaration","kind":64,"signatures":[{"name":"presentationDetents","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the available heights for a sheet presentation."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/presentationdetents(_:selection:))."}]}]},"parameters":[{"name":"detents","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Array of detents the sheet can snap to."}]},"type":{"type":"array","elementType":{"type":"reference","name":"PresentationDetent","package":"@expo/ui"}}},{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional settings for tracking the selected detent."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"onSelectionChange","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Callback fired when the user changes the active detent by dragging."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"detent","variant":"param","kind":32768,"type":{"type":"reference","name":"PresentationDetent","package":"@expo/ui"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"selection","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The currently selected detent."}]},"type":{"type":"reference","name":"PresentationDetent","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"presentationDragIndicator","variant":"declaration","kind":64,"signatures":[{"name":"presentationDragIndicator","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls the visibility of the drag indicator on a sheet."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/presentationdragindicator(_:))."}]}]},"parameters":[{"name":"visibility","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The visibility of the drag indicator."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"visible"},{"type":"literal","value":"hidden"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"progressViewStyle","variant":"declaration","kind":64,"signatures":[{"name":"progressViewStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the progress view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/progressviewstyle)."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The style for the progress view."}]},"type":{"type":"reference","name":"ProgressViewStyleType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"refreshable","variant":"declaration","kind":64,"signatures":[{"name":"refreshable","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Marks a view as refreshable. Adds pull-to-refresh functionality."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/refreshable(action:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Async function to call when refresh is triggered."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"resizable","variant":"declaration","kind":64,"signatures":[{"name":"resizable","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the mode by which SwiftUI resizes an image to fit its space."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/image/resizable(capinsets:resizingmode:))."}]}]},"parameters":[{"name":"capInsets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Inset values that indicate a portion of the image that SwiftUI doesn’t resize."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"bottom","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"leading","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"top","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"trailing","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"resizingMode","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The mode by which SwiftUI resizes the image."}]},"type":{"type":"union","types":[{"type":"literal","value":"stretch"},{"type":"literal","value":"tile"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"rotation3DEffect","variant":"declaration","kind":64,"signatures":[{"name":"rotation3DEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a 3D rotation transformation."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/rotation3deffect(_:axis:anchor:anchorz:perspective:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The rotation parameters: "},{"kind":"code","text":"`angle`"},{"kind":"text","text":" (in degrees), "},{"kind":"code","text":"`axis`"},{"kind":"text","text":" (x, y, z), and "},{"kind":"code","text":"`perspective`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"angle","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"axis","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"z","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"perspective","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"rotationEffect","variant":"declaration","kind":64,"signatures":[{"name":"rotationEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies rotation transformation."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/rotationeffect(_:anchor:))."}]}]},"parameters":[{"name":"angle","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Rotation angle in degrees."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"saturation","variant":"declaration","kind":64,"signatures":[{"name":"saturation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adjusts the saturation of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/saturation(_:))."}]}]},"parameters":[{"name":"amount","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Saturation multiplier (0 to infinity, 1 = normal)."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scaleEffect","variant":"declaration","kind":64,"signatures":[{"name":"scaleEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies scaling transformation."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scaleeffect(_:anchor:))."}]}]},"parameters":[{"name":"scale","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Uniform scale factor (1.0 = normal size), or an object with separate "},{"kind":"code","text":"`x`"},{"kind":"text","text":" and "},{"kind":"code","text":"`y`"},{"kind":"text","text":" scale factors."}]},"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollContentBackground","variant":"declaration","kind":64,"signatures":[{"name":"scrollContentBackground","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Specifies the visibility of the background for scrollable views within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrollcontentbackground(_:))."}]}]},"parameters":[{"name":"visible","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The visibility of the background."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"visible"},{"type":"literal","value":"hidden"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollDisabled","variant":"declaration","kind":64,"signatures":[{"name":"scrollDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables or enables scrolling in scrollable views."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolldisabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether scrolling should be disabled (default: true)."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollDismissesKeyboard","variant":"declaration","kind":64,"signatures":[{"name":"scrollDismissesKeyboard","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls how the keyboard is dismissed when scrolling."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolldismisseskeyboard(_:))."}]}]},"parameters":[{"name":"mode","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The keyboard dismiss mode."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"never"},{"type":"literal","value":"interactively"},{"type":"literal","value":"immediately"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollPosition","variant":"declaration","kind":64,"signatures":[{"name":"scrollPosition","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Binds the leading scroll target of a scrollable container to an observable native state.\n\nReading "},{"kind":"code","text":"`state.value`"},{"kind":"text","text":" returns the id of the leading scroll target. Writing to it scrolls\nthe container to the matching view. Pair with "},{"kind":"code","text":"`scrollTargetLayout()`"},{"kind":"text","text":" on the content\ncontainer and "},{"kind":"code","text":"`id()`"},{"kind":"text","text":" on each target. Works on "},{"kind":"code","text":"`ScrollView`"},{"kind":"text","text":", "},{"kind":"code","text":"`LazyVStack`"},{"kind":"text","text":", "},{"kind":"code","text":"`LazyHStack`"},{"kind":"text","text":",\nand other scrollable containers.\n\nOn iOS below 17.0, the modifier is a no-op."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"macos 14.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrollposition(id:anchor:))."}]},{"tag":"@example","content":[{"kind":"code","text":"```tsx\nconst activeID = useNativeState(null);\n\n console.log('leading target:', newID),\n }),\n ]}>\n \n {items.map((item) => (\n {item.text}\n ))}\n \n
\n```"}]}]},"parameters":[{"name":"state","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An "},{"kind":"code","text":"`ObservableState`"},{"kind":"text","text":" created with "},{"kind":"code","text":"`useNativeState`"},{"kind":"text","text":"."}]},"type":{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/State/useNativeState.ts","qualifiedName":"ObservableState"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"literal","value":null}]}],"name":"ObservableState","package":"@expo/ui"}},{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"anchor","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Anchor used to pick which view drives the binding and to align\n programmatic scrolls. Maps to the "},{"kind":"code","text":"`anchor:`"},{"kind":"text","text":" parameter of SwiftUI's "},{"kind":"code","text":"`.scrollPosition(id:anchor:)`"},{"kind":"text","text":"."}]},"type":{"type":"reference","name":"UnitPointValue","package":"@expo/ui"}},{"name":"onChange","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Fires on the JS thread whenever the leading scroll target changes."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"id","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"literal","value":null}]}}],"type":{"type":"intrinsic","name":"void"}}]}}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollTargetBehavior","variant":"declaration","kind":64,"signatures":[{"name":"scrollTargetBehavior","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the scroll snapping behavior for scrollable views.\nUse with "},{"kind":"code","text":"`scrollTargetLayout`"},{"kind":"text","text":" on the content container."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolltargetbehavior(_:))."}]}]},"parameters":[{"name":"behavior","variant":"param","kind":32768,"comment":{"summary":[{"kind":"code","text":"`'paging'`"},{"kind":"text","text":" for container-aligned snapping, "},{"kind":"code","text":"`'viewAligned'`"},{"kind":"text","text":" for view-aligned snapping."}]},"type":{"type":"union","types":[{"type":"literal","value":"paging"},{"type":"literal","value":"viewAligned"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollTargetLayout","variant":"declaration","kind":64,"signatures":[{"name":"scrollTargetLayout","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Configures a layout container as a scroll target layout for view-aligned snapping.\nApply to "},{"kind":"code","text":"`VStack`"},{"kind":"text","text":" or "},{"kind":"code","text":"`HStack`"},{"kind":"text","text":" inside a "},{"kind":"code","text":"`ScrollView`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolltargetlayout(isenabled:))."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"shadow","variant":"declaration","kind":64,"signatures":[{"name":"shadow","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a shadow to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/shadow(color:radius:x:y:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The shadow parameters: "},{"kind":"code","text":"`radius`"},{"kind":"text","text":", offset ("},{"kind":"code","text":"`x`"},{"kind":"text","text":", "},{"kind":"code","text":"`y`"},{"kind":"text","text":") and "},{"kind":"code","text":"`color`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"radius","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"x","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"strikethrough","variant":"declaration","kind":64,"signatures":[{"name":"strikethrough","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a strikethrough to the text."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/text/strikethrough(_:color:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Controls whether the strikethrough is visible ("},{"kind":"code","text":"`true`"},{"kind":"text","text":" to show, "},{"kind":"code","text":"`false`"},{"kind":"text","text":" to hide)."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"isActive","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"boolean"}},{"name":"pattern","variant":"declaration","kind":1024,"type":{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/swift-ui/modifiers/index.ts","qualifiedName":"LinePattern"},"name":"LinePattern","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"submitLabel","variant":"declaration","kind":64,"signatures":[{"name":"submitLabel","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Specifies the label to display in the keyboard's return key. For example, "},{"kind":"code","text":"`'done'`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that uses the specified submit label."}]},{"tag":"@platform","content":[{"kind":"text","text":"iOS 15+"}]},{"tag":"@example","content":[{"kind":"code","text":"```tsx\n\n```"}]}]},"parameters":[{"name":"submitLabel","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The label to display in the keyboard's return key."}]},"type":{"type":"union","types":[{"type":"literal","value":"join"},{"type":"literal","value":"search"},{"type":"literal","value":"done"},{"type":"literal","value":"continue"},{"type":"literal","value":"go"},{"type":"literal","value":"next"},{"type":"literal","value":"return"},{"type":"literal","value":"route"},{"type":"literal","value":"send"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"tabViewStyle","variant":"declaration","kind":64,"signatures":[{"name":"tabViewStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for a "},{"kind":"code","text":"`TabView`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/tabviewstyle(_:))."}]}]},"parameters":[{"name":"config","variant":"param","kind":32768,"type":{"type":"reference","name":"TabViewStyleConfig","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"tag","variant":"declaration","kind":64,"signatures":[{"name":"tag","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets a tag on a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/tag(_:includeoptional:))."}]}]},"parameters":[{"name":"tag","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The tag to set on the view."}]},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textCase","variant":"declaration","kind":64,"signatures":[{"name":"textCase","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets a transform for the case of the text contained in this view when displayed."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"\"lowercase\""}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textcase(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"literal","value":"lowercase"},{"type":"literal","value":"uppercase"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textContentType","variant":"declaration","kind":64,"signatures":[{"name":"textContentType","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the text content type for input text, which the system uses to offer\nsuggestions (like autofill) while the user enters text."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 13.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textcontenttype(_:)-ufdv)."}]}]},"parameters":[{"name":"textContentType","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The semantic meaning of the text input area."}]},"type":{"type":"union","types":[{"type":"literal","value":"URL"},{"type":"literal","value":"namePrefix"},{"type":"literal","value":"name"},{"type":"literal","value":"nameSuffix"},{"type":"literal","value":"givenName"},{"type":"literal","value":"middleName"},{"type":"literal","value":"familyName"},{"type":"literal","value":"nickname"},{"type":"literal","value":"organizationName"},{"type":"literal","value":"jobTitle"},{"type":"literal","value":"location"},{"type":"literal","value":"fullStreetAddress"},{"type":"literal","value":"streetAddressLine1"},{"type":"literal","value":"streetAddressLine2"},{"type":"literal","value":"addressCity"},{"type":"literal","value":"addressCityAndState"},{"type":"literal","value":"addressState"},{"type":"literal","value":"postalCode"},{"type":"literal","value":"sublocality"},{"type":"literal","value":"countryName"},{"type":"literal","value":"username"},{"type":"literal","value":"password"},{"type":"literal","value":"newPassword"},{"type":"literal","value":"oneTimeCode"},{"type":"literal","value":"emailAddress"},{"type":"literal","value":"telephoneNumber"},{"type":"literal","value":"cellularEID"},{"type":"literal","value":"cellularIMEI"},{"type":"literal","value":"creditCardNumber"},{"type":"literal","value":"creditCardExpiration"},{"type":"literal","value":"creditCardExpirationMonth"},{"type":"literal","value":"creditCardExpirationYear"},{"type":"literal","value":"creditCardSecurityCode"},{"type":"literal","value":"creditCardType"},{"type":"literal","value":"creditCardName"},{"type":"literal","value":"creditCardGivenName"},{"type":"literal","value":"creditCardMiddleName"},{"type":"literal","value":"creditCardFamilyName"},{"type":"literal","value":"birthdate"},{"type":"literal","value":"birthdateDay"},{"type":"literal","value":"birthdateMonth"},{"type":"literal","value":"birthdateYear"},{"type":"literal","value":"dateTime"},{"type":"literal","value":"flightNumber"},{"type":"literal","value":"shipmentTrackingNumber"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textFieldStyle","variant":"declaration","kind":64,"signatures":[{"name":"textFieldStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the text field style for text field views."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textfieldstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The text field style."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"plain"},{"type":"literal","value":"roundedBorder"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textInputAutocapitalization","variant":"declaration","kind":64,"signatures":[{"name":"textInputAutocapitalization","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets how often the shift key in the keyboard is automatically enabled."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 15.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textinputautocapitalization(_:))."}]}]},"parameters":[{"name":"autocapitalization","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The autocapitalization behavior."}]},"type":{"type":"union","types":[{"type":"literal","value":"never"},{"type":"literal","value":"words"},{"type":"literal","value":"sentences"},{"type":"literal","value":"characters"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textSelection","variant":"declaration","kind":64,"signatures":[{"name":"textSelection","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls whether people can select text within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textselection(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Enable selection"}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"tint","variant":"declaration","kind":64,"signatures":[{"name":"tint","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the tint color of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/tint(_:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The tint color (hex string). For example, "},{"kind":"code","text":"`#FF0000`"},{"kind":"text","text":"."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"toggleStyle","variant":"declaration","kind":64,"signatures":[{"name":"toggleStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for toggles within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/togglestyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The toggle style."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"switch"},{"type":"literal","value":"button"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"truncationMode","variant":"declaration","kind":64,"signatures":[{"name":"truncationMode","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the truncation mode for lines of text that are too long to fit in the available space."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/truncationmode(_:))."}]}]},"parameters":[{"name":"mode","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The truncation mode that specifies where to truncate the text within the text view, if needed.\nYou can truncate at the beginning, middle, or end of the text view."}]},"type":{"type":"union","types":[{"type":"literal","value":"head"},{"type":"literal","value":"middle"},{"type":"literal","value":"tail"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"underline","variant":"declaration","kind":64,"signatures":[{"name":"underline","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies an underline to the text."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/underline(_:pattern:color:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Controls whether the underline is visible ("},{"kind":"code","text":"`true`"},{"kind":"text","text":" to show, "},{"kind":"code","text":"`false`"},{"kind":"text","text":" to hide)."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"isActive","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"boolean"}},{"name":"pattern","variant":"declaration","kind":1024,"type":{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/swift-ui/modifiers/index.ts","qualifiedName":"LinePattern"},"name":"LinePattern","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"widgetAccentedRenderingMode","variant":"declaration","kind":64,"signatures":[{"name":"widgetAccentedRenderingMode","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Specifies the how to render an Image when using the WidgetKit/WidgetRenderingMode/accented mode."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/image/widgetaccentedrenderingmode(_:))."}]}]},"parameters":[{"name":"renderingMode","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A constant describing how the Image should be rendered."}]},"type":{"type":"union","types":[{"type":"literal","value":"fullColor"},{"type":"literal","value":"accented"},{"type":"literal","value":"desaturated"},{"type":"literal","value":"accentedDesaturated"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"widgetURL","variant":"declaration","kind":64,"signatures":[{"name":"widgetURL","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the URL to open in the containing app when the user clicks the widget.\nWidgets support one widgetURL modifier in their view hierarchy. If multiple views have widgetURL modifiers, the behavior is undefined."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/widgetURL(_:))."}]}]},"parameters":[{"name":"url","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The URL to open in the containing app."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"zIndex","variant":"declaration","kind":64,"signatures":[{"name":"zIndex","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the z-index (display order) of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/zindex(_:))."}]}]},"parameters":[{"name":"index","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The z-index value."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]}],"packageName":"@expo/ui"} \ No newline at end of file +{"schemaVersion":"2.0","name":"expo-ui/swift-ui/modifiers","variant":"project","kind":1,"children":[{"name":"ModifierConfig","variant":"declaration","kind":256,"comment":{"summary":[{"kind":"text","text":"Base interface for all view modifiers.\nAll modifiers must have a type field and can include arbitrary parameters."}]},"children":[{"name":"$type","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"eventListener","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"args","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"indexSignatures":[{"name":"__index","variant":"signature","kind":8192,"parameters":[{"name":"key","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"any"}}]},{"name":"ChainableAnimationType","variant":"declaration","kind":2097152,"children":[{"name":"[VALUE_SYMBOL]","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/swift-ui/modifiers/animation/types.ts","qualifiedName":"AnimationObject"},"name":"AnimationObject","package":"@expo/ui"}}]}}},{"name":"delay","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Adds a delay before the animation starts (in seconds)."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"delay","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}}},{"name":"repeat","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Repeats the animation the given number of times."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"autoreverses","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"repeatCount","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}}}]},{"name":"Color","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reference","target":{"packageName":"react-native","packagePath":"Libraries/StyleSheet/StyleSheet.d.ts","qualifiedName":"ColorValue"},"name":"ColorValue","package":"react-native"},{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/swift-ui/modifiers/types.ts","qualifiedName":"NamedColor"},"name":"NamedColor","package":"@expo/ui"}]}},{"name":"ContainerBackgroundPlacement","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"widget"},{"type":"literal","value":"navigation"},{"type":"literal","value":"navigationSplitView"}]}},{"name":"DatePickerStyleType","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"compact"},{"type":"literal","value":"graphical"},{"type":"literal","value":"wheel"}]}},{"name":"EnvironmentConfig","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"key","variant":"declaration","kind":1024,"type":{"type":"literal","value":"editMode"}},{"name":"value","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"active"},{"type":"literal","value":"inactive"},{"type":"literal","value":"transient"}]}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"key","variant":"declaration","kind":1024,"type":{"type":"literal","value":"colorScheme"}},{"name":"value","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"light"},{"type":"literal","value":"dark"}]}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"key","variant":"declaration","kind":1024,"type":{"type":"literal","value":"locale"}},{"name":"value","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"key","variant":"declaration","kind":1024,"type":{"type":"literal","value":"timeZone"}},{"name":"value","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}}]}}]}},{"name":"GaugeStyleType","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"circular"},{"type":"literal","value":"circularCapacity"},{"type":"literal","value":"linear"},{"type":"literal","value":"linearCapacity"}]}},{"name":"GlobalEvent","variant":"declaration","kind":2097152,"children":[{"name":"onGlobalEvent","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"event","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"nativeEvent","variant":"declaration","kind":1024,"type":{"type":"reference","name":"GlobalEventPayload","package":"@expo/ui"}}]}}}],"type":{"type":"intrinsic","name":"void"}}]}}}]},{"name":"GlobalEventPayload","variant":"declaration","kind":2097152,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"indexSignatures":[{"name":"__index","variant":"signature","kind":8192,"parameters":[{"name":"eventName","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Record"},"typeArguments":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"any"}],"name":"Record","package":"typescript"}}]}}},{"name":"IndexViewStyleConfig","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Configuration for the "},{"kind":"code","text":"`indexViewStyle`"},{"kind":"text","text":" modifier."}]},"children":[{"name":"backgroundDisplayMode","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Translucent background behind the page indicator dots. Useful when the\ndots sit on top of dark or busy content."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"'automatic'"}]}]},"type":{"type":"reference","name":"PageIndexBackgroundDisplayMode","package":"@expo/ui"}}]},{"name":"InterpolatingSpringAnimationParams","variant":"declaration","kind":2097152,"children":[{"name":"bounce","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Extra bounce to apply to the spring animation."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"damping","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The damping applied to the spring."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"duration","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Total animation duration (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"initialVelocity","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The initial velocity of the animation."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"mass","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The mass attached to the spring."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"stiffness","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The stiffness of the spring."}]},"type":{"type":"intrinsic","name":"number"}}]},{"name":"ListStyle","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"plain"},{"type":"literal","value":"inset"},{"type":"literal","value":"insetGrouped"},{"type":"literal","value":"grouped"},{"type":"literal","value":"sidebar"}]}},{"name":"PageIndexBackgroundDisplayMode","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"always"},{"type":"literal","value":"never"},{"type":"literal","value":"interactive"}]}},{"name":"PageIndexDisplayMode","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"always"},{"type":"literal","value":"never"}]}},{"name":"PickerStyleType","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"inline"},{"type":"literal","value":"menu"},{"type":"literal","value":"navigationLink"},{"type":"literal","value":"palette"},{"type":"literal","value":"segmented"},{"type":"literal","value":"wheel"}]}},{"name":"PresentationBackgroundInteractionType","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Presentation background interaction type."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"enabled"},{"type":"literal","value":"disabled"},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"detent","variant":"declaration","kind":1024,"type":{"type":"reference","name":"PresentationDetent","package":"@expo/ui"}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"enabledUpThrough"}}]}}]}},{"name":"PresentationDetent","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Presentation detent type for controlling sheet heights.\n- "},{"kind":"code","text":"`'medium'`"},{"kind":"text","text":": System medium height (approximately half screen)\n- "},{"kind":"code","text":"`'large'`"},{"kind":"text","text":": System large height (full screen)\n- "},{"kind":"code","text":"`{ fraction: number }`"},{"kind":"text","text":": Fraction of screen height (0-1, for example, 0.4 equals to 40% of screen)\n- "},{"kind":"code","text":"`{ height: number }`"},{"kind":"text","text":": Fixed height in points"}]},"type":{"type":"union","types":[{"type":"literal","value":"medium"},{"type":"literal","value":"large"},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"fraction","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}]}},{"name":"ProgressViewStyleType","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"linear"},{"type":"literal","value":"circular"}]}},{"name":"Shape","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.roundedRectangle","package":"@expo/ui","qualifiedName":"__object.roundedRectangle"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.capsule","package":"@expo/ui","qualifiedName":"__object.capsule"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.rectangle","package":"@expo/ui","qualifiedName":"__object.rectangle"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.ellipse","package":"@expo/ui","qualifiedName":"__object.ellipse"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.circle","package":"@expo/ui","qualifiedName":"__object.circle"}}],"name":"ReturnType","package":"typescript"},{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"ReturnType"},"typeArguments":[{"type":"query","queryType":{"type":"reference","name":"shapes.containerRelativeShape","package":"@expo/ui","qualifiedName":"__object.containerRelativeShape"}}],"name":"ReturnType","package":"typescript"}]}},{"name":"SpringAnimationParams","variant":"declaration","kind":2097152,"children":[{"name":"blendDuration","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The duration over which to blend between animations (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"bounce","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Extra bounce to apply to the spring animation."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"dampingFraction","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The amount of damping applied to the spring's motion."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"duration","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Total animation duration (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"response","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The spring's response time (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}}]},{"name":"TabViewStyleConfig","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Configuration for the "},{"kind":"code","text":"`tabViewStyle`"},{"kind":"text","text":" modifier.\n\n - "},{"kind":"code","text":"`'page'`"},{"kind":"text","text":" — swipeable horizontal pager with optional dot indicators.\n - "},{"kind":"code","text":"`'automatic'`"},{"kind":"text","text":" — SwiftUI's default tab-bar style.\n - "},{"kind":"code","text":"`'sidebarAdaptable'`"},{"kind":"text","text":" — iOS 18+. Sidebar on iPad/Mac, bottom bar on\n iPhone."}]},"type":{"type":"union","types":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"indexDisplayMode","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Visibility of the page indicator dots. Only meaningful for the page style."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"'automatic'"}]}]},"type":{"type":"reference","name":"PageIndexDisplayMode","package":"@expo/ui"}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"page"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"automatic"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"sidebarAdaptable"}}]}}]}},{"name":"TimingAnimationParams","variant":"declaration","kind":2097152,"children":[{"name":"duration","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Total animation duration (in seconds)."}]},"type":{"type":"intrinsic","name":"number"}}]},{"name":"UnitPointValue","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"zero"},{"type":"literal","value":"topLeading"},{"type":"literal","value":"top"},{"type":"literal","value":"topTrailing"},{"type":"literal","value":"leading"},{"type":"literal","value":"center"},{"type":"literal","value":"trailing"},{"type":"literal","value":"bottomLeading"},{"type":"literal","value":"bottom"},{"type":"literal","value":"bottomTrailing"}]}},{"name":"Animation","variant":"declaration","kind":32,"flags":{"isConst":true},"comment":{"summary":[{"kind":"text","text":"Built-in animation presets for the "},{"kind":"code","text":"`animation`"},{"kind":"text","text":" modifier.\nPresets:\n- Timing presets ("},{"kind":"code","text":"`easeInOut`"},{"kind":"text","text":", "},{"kind":"code","text":"`easeIn`"},{"kind":"text","text":", "},{"kind":"code","text":"`easeOut`"},{"kind":"text","text":", "},{"kind":"code","text":"`linear`"},{"kind":"text","text":") accept\n["},{"kind":"code","text":"`TimingAnimationParams`"},{"kind":"text","text":"](#timinganimationparams).\n- "},{"kind":"code","text":"`spring`"},{"kind":"text","text":" accepts ["},{"kind":"code","text":"`SpringAnimationParams`"},{"kind":"text","text":"](#springanimationparams).\n- "},{"kind":"code","text":"`interpolatingSpring`"},{"kind":"text","text":" accepts\n["},{"kind":"code","text":"`InterpolatingSpringAnimationParams`"},{"kind":"text","text":"](#interpolatingspringanimationparams).\n- Chaining returns ["},{"kind":"code","text":"`ChainableAnimationType`"},{"kind":"text","text":"](#chainableanimationtype)."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\nimport { Host, VStack } from '@expo/ui/swift-ui';\nimport { animation, Animation } from '@expo/ui/swift-ui/modifiers';\n\nfunction Example() {\n const [isExpanded, setIsExpanded] = useState(false);\n\n return (\n \n \n //...\n \n \n );\n}\n```"}]},{"tag":"@hideType","content":[]}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"default","variant":"declaration","kind":1024,"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"},"defaultValue":"..."},{"name":"easeIn","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"TimingAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"easeInOut","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"TimingAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"easeOut","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"TimingAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"interpolatingSpring","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"InterpolatingSpringAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"linear","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"TimingAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."},{"name":"spring","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","name":"SpringAnimationParams","package":"@expo/ui"}}],"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}}]}},"defaultValue":"..."}]}},"defaultValue":"..."},{"name":"shapes","variant":"declaration","kind":32,"flags":{"isConst":true},"comment":{"summary":[{"kind":"text","text":"Shape builders for modifiers that accept shapes, such as "},{"kind":"code","text":"`background`"},{"kind":"text","text":" and "},{"kind":"code","text":"`containerShape`"},{"kind":"text","text":".\n\nShapes: "},{"kind":"code","text":"`roundedRectangle`"},{"kind":"text","text":", "},{"kind":"code","text":"`capsule`"},{"kind":"text","text":", "},{"kind":"code","text":"`rectangle`"},{"kind":"text","text":", "},{"kind":"code","text":"`ellipse`"},{"kind":"text","text":", "},{"kind":"code","text":"`circle`"},{"kind":"text","text":", "},{"kind":"code","text":"`containerRelativeShape`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\nimport { background, shapes } from '@expo/ui/swift-ui/modifiers';\nimport { Text, Host } from '@expo/ui/swift-ui';\n\nfunction Example() {\n return (\n \n \n Hello, world!\n \n \n );\n}\n```"}]},{"tag":"@hideType","content":[]}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"capsule","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"roundedCornerStyle","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"continuous"},{"type":"literal","value":"circular"}]}}]}}}],"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"roundedCornerStyle","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"continuous"},{"type":"literal","value":"circular"},{"type":"intrinsic","name":"undefined"}]},"defaultValue":"params.roundedCornerStyle"},{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'capsule'"}]}}}]}},"defaultValue":"..."},{"name":"circle","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'circle'"}]}}}]}},"defaultValue":"..."},{"name":"containerRelativeShape","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'containerRelativeShape'"}]}}}]}},"defaultValue":"..."},{"name":"ellipse","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'ellipse'"}]}}}]}},"defaultValue":"..."},{"name":"rectangle","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'rectangle'"}]}}}]}},"defaultValue":"..."},{"name":"roundedRectangle","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"params","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"cornerRadius","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"cornerSize","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"roundedCornerStyle","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"continuous"},{"type":"literal","value":"circular"}]}}]}}}],"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"cornerRadius","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"undefined"}]},"defaultValue":"params.cornerRadius"},{"name":"cornerSize","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}},{"type":"intrinsic","name":"undefined"}]},"defaultValue":"params.cornerSize"},{"name":"roundedCornerStyle","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"continuous"},{"type":"literal","value":"circular"},{"type":"intrinsic","name":"undefined"}]},"defaultValue":"params.roundedCornerStyle"},{"name":"shape","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"},"defaultValue":"'roundedRectangle'"}]}}}]}},"defaultValue":"..."}]}},"defaultValue":"..."},{"name":"accessibilityHint","variant":"declaration","kind":64,"signatures":[{"name":"accessibilityHint","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets accessibility hint for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/accessibilityhint(_:))."}]}]},"parameters":[{"name":"hint","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The accessibility hint."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"accessibilityLabel","variant":"declaration","kind":64,"signatures":[{"name":"accessibilityLabel","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets accessibility label for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/accessibilitylabel(_:))."}]}]},"parameters":[{"name":"label","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The accessibility label."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"accessibilityValue","variant":"declaration","kind":64,"signatures":[{"name":"accessibilityValue","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets accessibility value for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/accessibilityvalue(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The accessibility value."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"allowsTightening","variant":"declaration","kind":64,"signatures":[{"name":"allowsTightening","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets whether text in this view can compress the space between characters when necessary to fit text in a line"}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"true"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/allowstightening(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"animation","variant":"declaration","kind":64,"signatures":[{"name":"animation","variant":"signature","kind":4096,"parameters":[{"name":"animationObject","variant":"param","kind":32768,"type":{"type":"reference","name":"ChainableAnimationType","package":"@expo/ui"}},{"name":"animatedValue","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"boolean"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"aspectRatio","variant":"declaration","kind":64,"signatures":[{"name":"aspectRatio","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets aspect ratio constraint."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/aspectratio(_:contentmode:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Optional width/height aspect ratio and content mode."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"contentMode","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"fill"},{"type":"literal","value":"fit"}]}},{"name":"ratio","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"autocorrectionDisabled","variant":"declaration","kind":64,"signatures":[{"name":"autocorrectionDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables autocorrection for text input views."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/autocorrectiondisabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether autocorrection is disabled. Defaults to "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"background","variant":"declaration","kind":64,"signatures":[{"name":"background","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the background of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/background(_:alignment:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The background color (hex string). For example, "},{"kind":"code","text":"`#FF0000`"},{"kind":"text","text":"."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"shape","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional shape to clip the background. If not provided, the background will fill the entire view."}]},"type":{"type":"reference","name":"Shape","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"backgroundOverlay","variant":"declaration","kind":64,"signatures":[{"name":"backgroundOverlay","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a background behind the view."}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Background color and alignment."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"alignment","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"}]}},{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"badge","variant":"declaration","kind":64,"signatures":[{"name":"badge","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Generates a badge for the view from a localized string key."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/badge(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Text view to display as a badge. Set the value to nil to hide the badge."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"badgeProminence","variant":"declaration","kind":64,"signatures":[{"name":"badgeProminence","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"The prominence to apply to badges associated with this environment."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/badgeprominence(_:))."}]}]},"parameters":[{"name":"badgeType","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Select the type of badge"}]},"type":{"type":"union","types":[{"type":"literal","value":"standard"},{"type":"literal","value":"increased"},{"type":"literal","value":"decreased"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"blur","variant":"declaration","kind":64,"signatures":[{"name":"blur","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies blur to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/blur(radius:opaque:))."}]}]},"parameters":[{"name":"radius","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The blur radius."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"bold","variant":"declaration","kind":64,"signatures":[{"name":"bold","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Makes text bold.\nWhen applied to "},{"kind":"code","text":"`Text`"},{"kind":"text","text":", it works on all iOS/tvOS versions. When used on regular views, it requires iOS 16.0+/tvOS 16.0+."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/text/bold())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"border","variant":"declaration","kind":64,"signatures":[{"name":"border","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a border to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/border(_:width:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The border parameters. Color and width."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"width","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"brightness","variant":"declaration","kind":64,"signatures":[{"name":"brightness","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adjusts the brightness of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/brightness(_:))."}]}]},"parameters":[{"name":"amount","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Brightness adjustment (-1 to 1)."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"buttonStyle","variant":"declaration","kind":64,"signatures":[{"name":"buttonStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the button style for button views."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/buttonstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The button style. "},{"kind":"code","text":"`'glass'`"},{"kind":"text","text":" and "},{"kind":"code","text":"`'glassProminent'`"},{"kind":"text","text":" are available on iOS 26+ and tvOS 26+ only."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"bordered"},{"type":"literal","value":"borderedProminent"},{"type":"literal","value":"borderless"},{"type":"literal","value":"glass"},{"type":"literal","value":"glassProminent"},{"type":"literal","value":"plain"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"clipped","variant":"declaration","kind":64,"signatures":[{"name":"clipped","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Clips content to bounds."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/clipped(antialiased:))."}]}]},"parameters":[{"name":"clipped","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to clip content."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"clipShape","variant":"declaration","kind":64,"signatures":[{"name":"clipShape","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Clips the view to a specific shape."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/clipshape(_:style:))."}]}]},"parameters":[{"name":"shape","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The clipping shape."}]},"type":{"type":"union","types":[{"type":"literal","value":"roundedRectangle"},{"type":"literal","value":"capsule"},{"type":"literal","value":"rectangle"},{"type":"literal","value":"ellipse"},{"type":"literal","value":"circle"},{"type":"literal","value":"containerRelativeShape"}]}},{"name":"cornerRadius","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Corner radius for rounded rectangle (default: 8)"}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"colorInvert","variant":"declaration","kind":64,"signatures":[{"name":"colorInvert","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Inverts the colors of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/colorinvert())."}]}]},"parameters":[{"name":"inverted","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to invert colors."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"containerBackground","variant":"declaration","kind":64,"signatures":[{"name":"containerBackground","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the container background of the enclosing container using a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/containerbackground(_:for:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The color to set as the background of the container."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"container","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The type of container to apply the background to."}]},"type":{"type":"reference","name":"ContainerBackgroundPlacement","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"containerRelativeFrame","variant":"declaration","kind":64,"signatures":[{"name":"containerRelativeFrame","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Positions this view within an invisible frame with a size relative to the nearest container."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/containerRelativeFrame(_:alignment:))."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 17.0+"}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The content relative frame parameters: "},{"kind":"code","text":"`axes`"},{"kind":"text","text":", "},{"kind":"code","text":"`count`"},{"kind":"text","text":", "},{"kind":"code","text":"`span`"},{"kind":"text","text":", "},{"kind":"code","text":"`spacing`"},{"kind":"text","text":" and "},{"kind":"code","text":"`alignment`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"alignment","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"topLeading"},{"type":"literal","value":"topTrailing"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"bottomLeading"},{"type":"literal","value":"bottomTrailing"}]}},{"name":"axes","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"},{"type":"literal","value":"both"}]}},{"name":"count","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"spacing","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"span","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"containerShape","variant":"declaration","kind":64,"signatures":[{"name":"containerShape","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the container shape for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/containershape(_:))."}]}]},"parameters":[{"name":"shape","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A shape configuration from the shapes API"}]},"type":{"type":"reference","name":"Shape","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"contentShape","variant":"declaration","kind":64,"signatures":[{"name":"contentShape","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Defines the content shape for hit-testing purposes.\n\nThis modifier is essential for making entire view areas (including "},{"kind":"code","text":"`Spacer`"},{"kind":"text","text":" or empty space)\ninteractive. Without it, only visible elements like "},{"kind":"code","text":"`Text`"},{"kind":"text","text":" or "},{"kind":"code","text":"`Image`"},{"kind":"text","text":" respond to tap gestures."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\nimport { HStack, List, Section, Spacer, Text } from \"@expo/ui/swift-ui\";\nimport { contentShape, onTapGesture } from \"@expo/ui/swift-ui/modifiers\";\nimport { shapes } from \"@expo/ui/swift-ui/modifiers\";\n\nfunction InteractiveRow() {\n return (\n \n
\n console.log(\"Row tapped!\"))\n ]}\n >\n Label\n \n Value\n \n
\n
\n );\n}\n```"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/contentshape(_:eofill:))."}]}]},"parameters":[{"name":"shape","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A shape configuration from the shapes API (rectangle, circle, capsule, ellipse, roundedRectangle)."}]},"type":{"type":"reference","name":"Shape","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"contentTransition","variant":"declaration","kind":64,"signatures":[{"name":"contentTransition","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the content transition type for a view.\nUseful for animating changes in text content, especially numeric text.\nUse with the ["},{"kind":"code","text":"`animation`"},{"kind":"text","text":"](#animationanimationobject-animatedvalue) modifier to animate the transition when the content changes."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\n\n {count.toString()}\n\n```"}]},{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/contenttransition(_:))."}]}]},"parameters":[{"name":"transitionType","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The type of content transition."}]},"type":{"type":"union","types":[{"type":"literal","value":"identity"},{"type":"literal","value":"numericText"},{"type":"literal","value":"opacity"},{"type":"literal","value":"interpolate"}]}},{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional parameters."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"countsDown","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Whether the numeric text counts down."}]},"type":{"type":"intrinsic","name":"boolean"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"contrast","variant":"declaration","kind":64,"signatures":[{"name":"contrast","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adjusts the contrast of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/contrast(_:))."}]}]},"parameters":[{"name":"amount","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Contrast multiplier (0 to infinity, 1 = normal)."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"controlSize","variant":"declaration","kind":64,"signatures":[{"name":"controlSize","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the size of controls within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/controlsize(_:))."}]}]},"parameters":[{"name":"size","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The control size."}]},"type":{"type":"union","types":[{"type":"literal","value":"small"},{"type":"literal","value":"large"},{"type":"literal","value":"mini"},{"type":"literal","value":"regular"},{"type":"literal","value":"extraLarge"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"cornerRadius","variant":"declaration","kind":64,"signatures":[{"name":"cornerRadius","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies corner radius to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/cornerradius(_:antialiased:))."}]}]},"parameters":[{"name":"radius","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The corner radius value."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"createModifier","variant":"declaration","kind":64,"signatures":[{"name":"createModifier","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Factory function to create modifier configuration objects.\nThis is used by all built-in modifier functions and can be used by 3rd party libraries to create custom modifiers."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A "},{"kind":"code","text":"`ModifierConfig`"},{"kind":"text","text":" object that can be passed in the "},{"kind":"code","text":"`modifiers`"},{"kind":"text","text":" prop array."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\n// In a 3rd party package\nimport { createModifier } from '@expo/ui/swift-ui/modifiers';\n\nexport const blurEffect = (params: { radius: number; style?: string }) =>\n createModifier('blurEffect', params);\n```"}]}]},"parameters":[{"name":"type","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The modifier type string that maps to a registered native modifier."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Additional parameters to pass to the modifier."}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Record"},"typeArguments":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"any"}],"name":"Record","package":"typescript"},"defaultValue":"{}"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"createModifierWithEventListener","variant":"declaration","kind":64,"signatures":[{"name":"createModifierWithEventListener","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Creates a modifier with an event listener."}]},"parameters":[{"name":"type","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"eventListener","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"args","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"params","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Record"},"typeArguments":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"any"}],"name":"Record","package":"typescript"},"defaultValue":"{}"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"createViewModifierEventListener","variant":"declaration","kind":64,"signatures":[{"name":"createViewModifierEventListener","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Create an event listener for a view modifier."}]},"parameters":[{"name":"modifiers","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of modifier configs to extract event listeners from."}]},"type":{"type":"array","elementType":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}}],"type":{"type":"reference","name":"GlobalEvent","package":"@expo/ui"}}]},{"name":"datePickerStyle","variant":"declaration","kind":64,"signatures":[{"name":"datePickerStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the date picker."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/datepickerstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The style for the date picker."}]},"type":{"type":"reference","name":"DatePickerStyleType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"defaultScrollAnchor","variant":"declaration","kind":64,"signatures":[{"name":"defaultScrollAnchor","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the default anchor point for a scroll view's content."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"macos 14.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/defaultscrollanchor(_:))."}]}]},"parameters":[{"name":"anchor","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The anchor point for initial scroll position and content size changes, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" to reset."}]},"type":{"type":"union","types":[{"type":"reference","name":"UnitPointValue","package":"@expo/ui"},{"type":"literal","value":null}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"defaultScrollAnchorForRole","variant":"declaration","kind":64,"signatures":[{"name":"defaultScrollAnchorForRole","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the default anchor point for a scroll view for a specific role.\nPass "},{"kind":"code","text":"`null`"},{"kind":"text","text":" to opt out of a specific role while keeping anchors for other roles."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 18.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 18.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"macos 15.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/defaultscrollanchor(_:for:))."}]}]},"parameters":[{"name":"anchor","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The anchor point, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" to opt out of this role."}]},"type":{"type":"union","types":[{"type":"reference","name":"UnitPointValue","package":"@expo/ui"},{"type":"literal","value":null}]}},{"name":"role","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The scroll anchor role: "},{"kind":"code","text":"`'initialOffset'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'sizeChanges'`"},{"kind":"text","text":", or "},{"kind":"code","text":"`'alignment'`"},{"kind":"text","text":"."}]},"type":{"type":"union","types":[{"type":"literal","value":"initialOffset"},{"type":"literal","value":"sizeChanges"},{"type":"literal","value":"alignment"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"deleteDisabled","variant":"declaration","kind":64,"signatures":[{"name":"deleteDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables the delete action for a view in a list.\nApply to items within a "},{"kind":"code","text":"`ForEach`"},{"kind":"text","text":" to prevent them from being deleted."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"true"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/deletedisabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether deletion should be disabled"}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"disabled","variant":"declaration","kind":64,"signatures":[{"name":"disabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables or enables a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/disabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether the view should be disabled."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"environment","variant":"declaration","kind":64,"signatures":[{"name":"environment","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets a SwiftUI environment value."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/environment(_:_:))."}]}]},"parameters":[{"name":"config","variant":"param","kind":32768,"type":{"type":"reference","name":"EnvironmentConfig","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}},{"name":"environment","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets a SwiftUI environment value."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/environment(_:_:))."}]}]},"parameters":[{"name":"key","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"literal","value":"colorScheme"},{"type":"literal","value":"editMode"},{"type":"literal","value":"locale"},{"type":"literal","value":"timeZone"}]}},{"name":"value","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"fixedSize","variant":"declaration","kind":64,"signatures":[{"name":"fixedSize","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls fixed size behavior."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/fixedsize())."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Whether the view should use its ideal width or height."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"horizontal","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"vertical","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"font","variant":"declaration","kind":64,"signatures":[{"name":"font","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the font properties of a view.\nSupports both custom font families and system fonts with weight and design options."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\n// Custom font family\nCustom Font Text\n\n// System font with weight and design\nSystem Font Text\n```"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation for "},{"kind":"code","text":"`custom(_:size:)`"},{"kind":"text","text":"](https://developer.apple.com/documentation/swiftui/font/custom(_:size:)) and Official [SwiftUI documentation for "},{"kind":"code","text":"`system(size:weight:design:)`"},{"kind":"text","text":"](https://developer.apple.com/documentation/swiftui/font/system(size:weight:design:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The font configuration. When "},{"kind":"code","text":"`family`"},{"kind":"text","text":" is provided, it uses Font.custom().\nWhen "},{"kind":"code","text":"`family`"},{"kind":"text","text":" is not provided, it uses Font.system() with the specified weight and design."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"design","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Font design for system fonts"}]},"type":{"type":"union","types":[{"type":"literal","value":"default"},{"type":"literal","value":"rounded"},{"type":"literal","value":"serif"},{"type":"literal","value":"monospaced"}]}},{"name":"family","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Custom font family name.\nIf provided, uses "},{"kind":"code","text":"`Font.custom()`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"size","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Font size in points."}]},"type":{"type":"intrinsic","name":"number"}},{"name":"weight","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Font weight for system fonts."}]},"type":{"type":"union","types":[{"type":"literal","value":"light"},{"type":"literal","value":"bold"},{"type":"literal","value":"black"},{"type":"literal","value":"medium"},{"type":"literal","value":"regular"},{"type":"literal","value":"ultraLight"},{"type":"literal","value":"thin"},{"type":"literal","value":"semibold"},{"type":"literal","value":"heavy"}]}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"foregroundColor","variant":"declaration","kind":64,"signatures":[{"name":"foregroundColor","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the foreground color/tint of a view."}],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`foregroundStyle`"},{"kind":"text","text":" instead."}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/foregroundcolor(_:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The foreground color (hex string)."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"foregroundStyle","variant":"declaration","kind":64,"signatures":[{"name":"foregroundStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the foreground style of a view with comprehensive styling options.\n\nReplaces the deprecated "},{"kind":"code","text":"`foregroundColor`"},{"kind":"text","text":" modifier with enhanced capabilities including\ncolors, gradients, and semantic hierarchical styles that adapt to system appearance."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```tsx\n// Simple usage\nRed Text\n\n// Adaptive hierarchical styling\n\n Supporting Text\n\n\n// Linear gradient\n\n Gradient Text\n\n```"}]},{"tag":"@returns","content":[{"kind":"text","text":"A view modifier that applies the specified foreground style"}]},{"tag":"@since","content":[{"kind":"text","text":"iOS 15.0+ (hierarchical quinary requires iOS 16.0+)"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/foregroundstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The foreground style configuration. Can be:\n\n**Simple Color ("},{"kind":"code","text":"`Color`"},{"kind":"text","text":"):**\n- Hex colors: "},{"kind":"code","text":"`'#FF0000'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'#RGB'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'#RRGGBB'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'#AARRGGBB'`"},{"kind":"text","text":"\n- Named colors: "},{"kind":"code","text":"`'red'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'blue'`"},{"kind":"text","text":", "},{"kind":"code","text":"`'green'`"},{"kind":"text","text":", and so on.\n- React Native color values like "},{"kind":"code","text":"`PlatformColor('label')`"},{"kind":"text","text":"\n\n**Explicit Color Object:**\n"},{"kind":"code","text":"```ts\n{ type: 'color', color: PlatformColor('label') }\n```"},{"kind":"text","text":"\n\n**Hierarchical Styles (Semantic):**\nAuto-adapting semantic styles that respond to light/dark mode and accessibility settings:\n"},{"kind":"code","text":"```ts\n{ type: 'hierarchical', style: 'primary' } // Most prominent (main content, headlines)\n{ type: 'hierarchical', style: 'secondary' } // Supporting text, subheadlines\n{ type: 'hierarchical', style: 'tertiary' } // Less important text, captions\n{ type: 'hierarchical', style: 'quaternary' } // Subtle text, disabled states\n{ type: 'hierarchical', style: 'quinary' } // Most subtle (iOS 16+, fallback to quaternary)\n```"},{"kind":"text","text":"\n\n**Linear Gradient:**\n"},{"kind":"code","text":"```ts\n{\n type: 'linearGradient',\n colors: [PlatformColor('systemPink'), '#0000FF', '#00FF00'],\n startPoint: { x: 0, y: 0 }, // Top-left\n endPoint: { x: 1, y: 1 } // Bottom-right\n}\n```"},{"kind":"text","text":"\n\n**Radial Gradient:**\n"},{"kind":"code","text":"```ts\n{\n type: 'radialGradient',\n colors: [PlatformColor('systemPink'), '#0000FF'],\n center: { x: 0.5, y: 0.5 }, // Center of view\n startRadius: 0, // Inner radius\n endRadius: 100 // Outer radius\n}\n```"},{"kind":"text","text":"\n\n**Angular Gradient (Conic):**\n"},{"kind":"code","text":"```ts\n{\n type: 'angularGradient',\n colors: [PlatformColor('systemPink'), '#00FF00', '#0000FF'],\n center: { x: 0.5, y: 0.5 } // Rotation center\n}\n```"}]},"type":{"type":"union","types":[{"type":"reference","name":"Color","package":"@expo/ui"},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"color"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"style","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"primary"},{"type":"literal","value":"secondary"},{"type":"literal","value":"tertiary"},{"type":"literal","value":"quaternary"},{"type":"literal","value":"quinary"}]}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"hierarchical"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"colors","variant":"declaration","kind":1024,"type":{"type":"array","elementType":{"type":"reference","name":"Color","package":"@expo/ui"}}},{"name":"endPoint","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"startPoint","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"linearGradient"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"center","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"colors","variant":"declaration","kind":1024,"type":{"type":"array","elementType":{"type":"reference","name":"Color","package":"@expo/ui"}}},{"name":"endRadius","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"startRadius","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"radialGradient"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"center","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"colors","variant":"declaration","kind":1024,"type":{"type":"array","elementType":{"type":"reference","name":"Color","package":"@expo/ui"}}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"angularGradient"}}]}}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"frame","variant":"declaration","kind":64,"signatures":[{"name":"frame","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the frame properties of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/frame(width:height:alignment:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The frame parameters. Width, height, minWidth, maxWidth, minHeight, maxHeight, idealWidth, idealHeight and alignment."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"alignment","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"topLeading"},{"type":"literal","value":"topTrailing"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"bottomLeading"},{"type":"literal","value":"bottomTrailing"}]}},{"name":"height","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"idealHeight","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"idealWidth","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"maxHeight","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"maxWidth","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"minHeight","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"minWidth","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gaugeStyle","variant":"declaration","kind":64,"signatures":[{"name":"gaugeStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the gauge."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/gaugestyle)."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The style for the gauge."}]},"type":{"type":"reference","name":"GaugeStyleType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"glassEffect","variant":"declaration","kind":64,"signatures":[{"name":"glassEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a glass effect to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/glasseffect(_:in:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The glass effect parameters. Variant, interactive, tint and shape."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"cornerRadius","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"glass","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"interactive","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"tint","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"variant","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"clear"},{"type":"literal","value":"regular"},{"type":"literal","value":"identity"}]}}]}}},{"name":"shape","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"roundedRectangle"},{"type":"literal","value":"capsule"},{"type":"literal","value":"rectangle"},{"type":"literal","value":"ellipse"},{"type":"literal","value":"circle"},{"type":"literal","value":"containerRelativeShape"}]}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"glassEffectId","variant":"declaration","kind":64,"signatures":[{"name":"glassEffectId","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Associates an identity value to Liquid Glass effects defined within a "},{"kind":"code","text":"`GlassEffectContainer`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/glasseffectid(_:in:))."}]}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The id of the glass effect."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"namespaceId","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The namespace id of the glass effect. Use Namespace component to create a namespace."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"grayscale","variant":"declaration","kind":64,"signatures":[{"name":"grayscale","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Makes a view grayscale."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/grayscale(_:))."}]}]},"parameters":[{"name":"amount","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Grayscale amount (0 to 1)."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gridCellAnchor","variant":"declaration","kind":64,"signatures":[{"name":"gridCellAnchor","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Specifies a custom alignment anchor for a view that acts as a grid cell."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that uses the specified anchor point to align its content."}]},{"tag":"@platform","content":[{"kind":"text","text":"iOS 16+"}]},{"tag":"@example","content":[{"kind":"code","text":"```tsx\n// Using a preset anchor\n\n\n// Using a custom anchor point\n\n```"}]}]},"parameters":[{"name":"anchor","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The unit point that defines how to align the view within the bounds of its grid cell."}]},"type":{"type":"union","types":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"anchor","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"zero"},{"type":"literal","value":"topLeading"},{"type":"literal","value":"topTrailing"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"bottomLeading"},{"type":"literal","value":"bottomTrailing"}]}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"preset"}}]}},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"points","variant":"declaration","kind":1024,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"type","variant":"declaration","kind":1024,"type":{"type":"literal","value":"custom"}}]}}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gridCellColumns","variant":"declaration","kind":64,"signatures":[{"name":"gridCellColumns","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Tells a view that acts as a cell in a grid to span the specified number of columns."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that occupies the specified number of columns in a grid row."}]}]},"parameters":[{"name":"count","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The number of columns that the view should consume when placed in a grid row."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gridCellUnsizedAxes","variant":"declaration","kind":64,"signatures":[{"name":"gridCellUnsizedAxes","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Asks grid layouts not to offer the view extra size in the specified axes."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that doesn’t ask an enclosing grid for extra size in one or more axes."}]}]},"parameters":[{"name":"axes","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The dimensions in which the grid shouldn’t offer the view a share of any available space. This prevents a flexible view like a Spacer, Divider, or Color from defining the size of a row or column."}]},"type":{"type":"union","types":[{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"gridColumnAlignment","variant":"declaration","kind":64,"signatures":[{"name":"gridColumnAlignment","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Overrides the default horizontal alignment of the grid column that the view appears in."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that uses the specified horizontal alignment, and that causes all cells in the same column of a grid to use the same alignment."}]},{"tag":"@platform","content":[{"kind":"text","text":"iOS 16+"}]}]},"parameters":[{"name":"alignment","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The HorizontalAlignment guide to use for the grid column that the view appears in."}]},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"headerProminence","variant":"declaration","kind":64,"signatures":[{"name":"headerProminence","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the header prominence for this view."}]},"parameters":[{"name":"prominence","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The prominence to apply."}]},"type":{"type":"union","types":[{"type":"literal","value":"standard"},{"type":"literal","value":"increased"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"hidden","variant":"declaration","kind":64,"signatures":[{"name":"hidden","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Hides or shows a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/hidden(_:))."}]}]},"parameters":[{"name":"hidden","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether the view should be hidden."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"hueRotation","variant":"declaration","kind":64,"signatures":[{"name":"hueRotation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a hue rotation to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/huerotation(_:))."}]}]},"parameters":[{"name":"angle","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Hue rotation angle in degrees."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"id","variant":"declaration","kind":64,"signatures":[{"name":"id","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Attaches a stable identifier to a view so it can be referenced by scroll target bindings.\nUse with "},{"kind":"code","text":"`scrollTargetLayout()`"},{"kind":"text","text":" on the containing stack and the "},{"kind":"code","text":"`scrollPosition`"},{"kind":"text","text":" modifier on a scrollable container."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/id(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"String identifier matched by "},{"kind":"code","text":"`scrollPosition`"},{"kind":"text","text":"'s observable state."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"ignoreSafeArea","variant":"declaration","kind":64,"signatures":[{"name":"ignoreSafeArea","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Allows a view to ignore safe area constraints."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ignoressafearea(_:edges:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The safe area regions to ignore and the edges to expand into."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"edges","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"},{"type":"literal","value":"all"}]}},{"name":"regions","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"container"},{"type":"literal","value":"all"},{"type":"literal","value":"keyboard"}]}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"indexViewStyle","variant":"declaration","kind":64,"signatures":[{"name":"indexViewStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the page index view inside a "},{"kind":"code","text":"`TabView`"},{"kind":"text","text":". SwiftUI only\nships a "},{"kind":"code","text":"`.page`"},{"kind":"text","text":" index view style, so no style selector is exposed."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/indexviewstyle(_:))."}]}]},"parameters":[{"name":"config","variant":"param","kind":32768,"type":{"type":"reference","name":"IndexViewStyleConfig","package":"@expo/ui"},"defaultValue":"{}"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"interactiveDismissDisabled","variant":"declaration","kind":64,"signatures":[{"name":"interactiveDismissDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables interactive dismissal of a sheet."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/interactivedismissdisabled(_:))."}]}]},"parameters":[{"name":"isDisabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether interactive dismiss is disabled (default: true)."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"italic","variant":"declaration","kind":64,"signatures":[{"name":"italic","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Makes text italic.\nWhen applied to "},{"kind":"code","text":"`Text`"},{"kind":"text","text":", it works on all iOS/tvOS versions. When used on regular views, it requires iOS 16.0+/tvOS 16.0+."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/text/italic())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"kerning","variant":"declaration","kind":64,"signatures":[{"name":"kerning","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the spacing, or kerning, between characters for the text in this view."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"0"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/kerning(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"keyboardType","variant":"declaration","kind":64,"signatures":[{"name":"keyboardType","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the keyboard type for text input views."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/keyboardtype(_:))."}]}]},"parameters":[{"name":"keyboardType","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The type of keyboard to display."}]},"type":{"type":"union","types":[{"type":"literal","value":"default"},{"type":"literal","value":"url"},{"type":"literal","value":"email-address"},{"type":"literal","value":"numeric"},{"type":"literal","value":"phone-pad"},{"type":"literal","value":"ascii-capable"},{"type":"literal","value":"numbers-and-punctuation"},{"type":"literal","value":"name-phone-pad"},{"type":"literal","value":"decimal-pad"},{"type":"literal","value":"twitter"},{"type":"literal","value":"web-search"},{"type":"literal","value":"ascii-capable-number-pad"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"labelsHidden","variant":"declaration","kind":64,"signatures":[{"name":"labelsHidden","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Hides the labels of any controls contained within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/labelshidden())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"labelStyle","variant":"declaration","kind":64,"signatures":[{"name":"labelStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for labels within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/labelstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The label style."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"iconOnly"},{"type":"literal","value":"titleAndIcon"},{"type":"literal","value":"titleOnly"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"layoutPriority","variant":"declaration","kind":64,"signatures":[{"name":"layoutPriority","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets layout priority for the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/layoutpriority(_:))."}]}]},"parameters":[{"name":"priority","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Layout priority value."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"lineHeight","variant":"declaration","kind":64,"signatures":[{"name":"lineHeight","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the total line height for text in this view."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 26.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"macos 26.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 26.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/lineheight(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The line height in points."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"lineLimit","variant":"declaration","kind":64,"signatures":[{"name":"lineLimit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the line limit for text in the view.\n\nFour variants matching SwiftUI:\n- "},{"kind":"code","text":"`lineLimit()`"},{"kind":"text","text":" — no line limit (unlimited lines)\n- "},{"kind":"code","text":"`lineLimit(5)`"},{"kind":"text","text":" — max 5 lines\n- "},{"kind":"code","text":"`lineLimit(5, { reservesSpace: true })`"},{"kind":"text","text":" — max 5 lines, reserves height even when empty (iOS 16+, tvOS 16+)\n- "},{"kind":"code","text":"`lineLimit({ min: 3, max: 8 })`"},{"kind":"text","text":" — range of 3 to 8 lines (iOS 16+, tvOS 16+)"}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/linelimit(_:))."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}},{"name":"lineLimit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the line limit for text in the view.\n\nFour variants matching SwiftUI:\n- "},{"kind":"code","text":"`lineLimit()`"},{"kind":"text","text":" — no line limit (unlimited lines)\n- "},{"kind":"code","text":"`lineLimit(5)`"},{"kind":"text","text":" — max 5 lines\n- "},{"kind":"code","text":"`lineLimit(5, { reservesSpace: true })`"},{"kind":"text","text":" — max 5 lines, reserves height even when empty (iOS 16+, tvOS 16+)\n- "},{"kind":"code","text":"`lineLimit({ min: 3, max: 8 })`"},{"kind":"text","text":" — range of 3 to 8 lines (iOS 16+, tvOS 16+)"}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/linelimit(_:))."}]}]},"parameters":[{"name":"limit","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"number"}},{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"reservesSpace","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}},{"name":"lineLimit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the line limit for text in the view.\n\nFour variants matching SwiftUI:\n- "},{"kind":"code","text":"`lineLimit()`"},{"kind":"text","text":" — no line limit (unlimited lines)\n- "},{"kind":"code","text":"`lineLimit(5)`"},{"kind":"text","text":" — max 5 lines\n- "},{"kind":"code","text":"`lineLimit(5, { reservesSpace: true })`"},{"kind":"text","text":" — max 5 lines, reserves height even when empty (iOS 16+, tvOS 16+)\n- "},{"kind":"code","text":"`lineLimit({ min: 3, max: 8 })`"},{"kind":"text","text":" — range of 3 to 8 lines (iOS 16+, tvOS 16+)"}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/linelimit(_:))."}]}]},"parameters":[{"name":"range","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"max","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"min","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"lineSpacing","variant":"declaration","kind":64,"signatures":[{"name":"lineSpacing","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"The distance in points between the bottom of one line fragment and the top of the next."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/linespacing(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The amount of space between the bottom of one line and the top of the next line in points. This value is always nonnegative. Otherwise, the default value will be used."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listRowBackground","variant":"declaration","kind":64,"signatures":[{"name":"listRowBackground","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the background of a row."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/listrowbackground(_:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The row color (hex string). For example, "},{"kind":"code","text":"`#FF0000`"},{"kind":"text","text":"."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listRowInsets","variant":"declaration","kind":64,"signatures":[{"name":"listRowInsets","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies an inset to the rows in a list."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/listrowinsets(_:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The inset to apply to the rows in a list."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"bottom","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"leading","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"top","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"trailing","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listRowSeparator","variant":"declaration","kind":64,"signatures":[{"name":"listRowSeparator","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls the visibility of the separator for a list row."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/listrowseparator(_:edges:))."}]}]},"parameters":[{"name":"visibility","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The visibility to apply."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"visible"},{"type":"literal","value":"hidden"}]}},{"name":"edges","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The edges where the separator visibility applies."}]},"type":{"type":"union","types":[{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"all"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listSectionMargins","variant":"declaration","kind":64,"signatures":[{"name":"listSectionMargins","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Allows a view to ignore safe area constraints."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"iOS 26+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/listsectionmargins(_:_:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The margins to apply to the section in a list."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"edges","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"},{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"},{"type":"literal","value":"all"}]}},{"name":"length","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listSectionSpacing","variant":"declaration","kind":64,"signatures":[{"name":"listSectionSpacing","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the spacing between adjacent sections."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]}]},"parameters":[{"name":"spacing","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The spacing to apply."}]},"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":"default"},{"type":"literal","value":"compact"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"listStyle","variant":"declaration","kind":64,"signatures":[{"name":"listStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for a List view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/liststyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The list style to apply."}]},"type":{"type":"reference","name":"ListStyle","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"luminanceToAlpha","variant":"declaration","kind":64,"signatures":[{"name":"luminanceToAlpha","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a luminance to alpha effect to this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/luminanceToAlpha())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"mask","variant":"declaration","kind":64,"signatures":[{"name":"mask","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a mask to the view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/mask(_:))."}]}]},"parameters":[{"name":"shape","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The masking shape."}]},"type":{"type":"union","types":[{"type":"literal","value":"roundedRectangle"},{"type":"literal","value":"capsule"},{"type":"literal","value":"rectangle"},{"type":"literal","value":"ellipse"},{"type":"literal","value":"circle"},{"type":"literal","value":"containerRelativeShape"}]}},{"name":"cornerRadius","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Corner radius for rounded rectangle (default: "},{"kind":"code","text":"`8`"},{"kind":"text","text":")."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"matchedGeometryEffect","variant":"declaration","kind":64,"signatures":[{"name":"matchedGeometryEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a matched geometry effect to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/matchedgeometryeffect(id:in:properties:anchor:issource:))."}]}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The id of the view."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"namespaceId","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The namespace id of the view. Use Namespace component to create a namespace."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"menuActionDismissBehavior","variant":"declaration","kind":64,"signatures":[{"name":"menuActionDismissBehavior","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls the dismissal behavior of menu actions."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.4+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 17.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/menuactiondismissbehavior(_:))."}]}]},"parameters":[{"name":"behavior","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The menu action dismiss behavior."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"enabled"},{"type":"literal","value":"disabled"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"monospacedDigit","variant":"declaration","kind":64,"signatures":[{"name":"monospacedDigit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Modifies the fonts of all child views to use fixed-width digits, if possible, while leaving other characters proportionally spaced.\nWhen applied to "},{"kind":"code","text":"`Text`"},{"kind":"text","text":", modifies the text view's font to use fixed-width digits, while leaving other characters proportionally spaced."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/monospaceddigit())."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"moveDisabled","variant":"declaration","kind":64,"signatures":[{"name":"moveDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables the move action for a view in a list.\nApply to items within a "},{"kind":"code","text":"`ForEach`"},{"kind":"text","text":" to prevent them from being moved."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"true"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/movedisabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether moving should be disabled"}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"multilineTextAlignment","variant":"declaration","kind":64,"signatures":[{"name":"multilineTextAlignment","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"An alignment position for text along the horizontal axis."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/multilinetextalignment(_:))."}]}]},"parameters":[{"name":"alignment","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A value that you use to align multiple lines of text within a view."}]},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"offset","variant":"declaration","kind":64,"signatures":[{"name":"offset","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies an offset (translation) to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/offset(x:y:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The offset parameters: "},{"kind":"code","text":"`x`"},{"kind":"text","text":" and "},{"kind":"code","text":"`y`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onAppear","variant":"declaration","kind":64,"signatures":[{"name":"onAppear","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds an onAppear modifier that calls a function when the view appears."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/onappear(perform:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call when the view appears."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onDisappear","variant":"declaration","kind":64,"signatures":[{"name":"onDisappear","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds an onDisappear modifier that calls a function when the view disappears."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ondisappear(perform:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call when the view disappears."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onGeometryChange","variant":"declaration","kind":64,"signatures":[{"name":"onGeometryChange","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Calls the handler whenever the view's geometry changes. Sizes are in points."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ongeometrychange(for:of:action:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function called with the new size."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"size","variant":"param","kind":32768,"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onLongPressGesture","variant":"declaration","kind":64,"signatures":[{"name":"onLongPressGesture","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a long press gesture recognizer."}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call when long pressed."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"minimumDuration","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Minimum duration for long press (default: 0.5s)"}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onSubmit","variant":"declaration","kind":64,"signatures":[{"name":"onSubmit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds an action to perform when the user submits a value to this view (e.g. pressing return in a text field)."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/onsubmit(of:_:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call on submit."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"onTapGesture","variant":"declaration","kind":64,"signatures":[{"name":"onTapGesture","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a tap gesture recognizer."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ontapgesture(count:perform:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Function to call when tapped."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"opacity","variant":"declaration","kind":64,"signatures":[{"name":"opacity","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the opacity of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/opacity(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Opacity value between 0 and 1."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"overlay","variant":"declaration","kind":64,"signatures":[{"name":"overlay","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Overlays another view on top."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/overlay(_:alignment:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Overlay color and alignment."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"alignment","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"literal","value":"center"},{"type":"literal","value":"top"},{"type":"literal","value":"bottom"},{"type":"literal","value":"leading"},{"type":"literal","value":"trailing"}]}},{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"padding","variant":"declaration","kind":64,"signatures":[{"name":"padding","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets padding on a view.\nSupports individual edges or shorthand properties."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/padding(_:_:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The padding parameters: "},{"kind":"code","text":"`top`"},{"kind":"text","text":", "},{"kind":"code","text":"`bottom`"},{"kind":"text","text":", "},{"kind":"code","text":"`leading`"},{"kind":"text","text":", "},{"kind":"code","text":"`trailing`"},{"kind":"text","text":", "},{"kind":"code","text":"`horizontal`"},{"kind":"text","text":", "},{"kind":"code","text":"`vertical`"},{"kind":"text","text":" and "},{"kind":"code","text":"`all`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"all","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"bottom","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"horizontal","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"leading","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"top","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"trailing","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"vertical","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"pickerStyle","variant":"declaration","kind":64,"signatures":[{"name":"pickerStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the picker."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/pickerstyle)."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The style for the picker."}]},"type":{"type":"reference","name":"PickerStyleType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"presentationBackgroundInteraction","variant":"declaration","kind":64,"signatures":[{"name":"presentationBackgroundInteraction","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls interaction with the content behind a sheet."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.4+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.4+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/presentationbackgroundinteraction(_:))."}]}]},"parameters":[{"name":"interaction","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The background interaction behavior."}]},"type":{"type":"reference","name":"PresentationBackgroundInteractionType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"presentationDetents","variant":"declaration","kind":64,"signatures":[{"name":"presentationDetents","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the available heights for a sheet presentation."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/presentationdetents(_:selection:))."}]}]},"parameters":[{"name":"detents","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Array of detents the sheet can snap to."}]},"type":{"type":"array","elementType":{"type":"reference","name":"PresentationDetent","package":"@expo/ui"}}},{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional settings for tracking the selected detent."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"onSelectionChange","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Callback fired when the user changes the active detent by dragging."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"detent","variant":"param","kind":32768,"type":{"type":"reference","name":"PresentationDetent","package":"@expo/ui"}}],"type":{"type":"intrinsic","name":"void"}}]}}},{"name":"selection","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The currently selected detent."}]},"type":{"type":"reference","name":"PresentationDetent","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"presentationDragIndicator","variant":"declaration","kind":64,"signatures":[{"name":"presentationDragIndicator","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls the visibility of the drag indicator on a sheet."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/presentationdragindicator(_:))."}]}]},"parameters":[{"name":"visibility","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The visibility of the drag indicator."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"visible"},{"type":"literal","value":"hidden"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"progressViewStyle","variant":"declaration","kind":64,"signatures":[{"name":"progressViewStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for the progress view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/progressviewstyle)."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The style for the progress view."}]},"type":{"type":"reference","name":"ProgressViewStyleType","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"refreshable","variant":"declaration","kind":64,"signatures":[{"name":"refreshable","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Marks a view as refreshable. Adds pull-to-refresh functionality."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/refreshable(action:))."}]}]},"parameters":[{"name":"handler","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Async function to call when refresh is triggered."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"resizable","variant":"declaration","kind":64,"signatures":[{"name":"resizable","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the mode by which SwiftUI resizes an image to fit its space."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/image/resizable(capinsets:resizingmode:))."}]}]},"parameters":[{"name":"capInsets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Inset values that indicate a portion of the image that SwiftUI doesn’t resize."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"bottom","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"leading","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"top","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"trailing","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"resizingMode","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"The mode by which SwiftUI resizes the image."}]},"type":{"type":"union","types":[{"type":"literal","value":"stretch"},{"type":"literal","value":"tile"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"rotation3DEffect","variant":"declaration","kind":64,"signatures":[{"name":"rotation3DEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a 3D rotation transformation."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/rotation3deffect(_:axis:anchor:anchorz:perspective:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The rotation parameters: "},{"kind":"code","text":"`angle`"},{"kind":"text","text":" (in degrees), "},{"kind":"code","text":"`axis`"},{"kind":"text","text":" (x, y, z), and "},{"kind":"code","text":"`perspective`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"angle","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"axis","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"z","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}},{"name":"perspective","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"rotationEffect","variant":"declaration","kind":64,"signatures":[{"name":"rotationEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies rotation transformation."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/rotationeffect(_:anchor:))."}]}]},"parameters":[{"name":"angle","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Rotation angle in degrees."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"saturation","variant":"declaration","kind":64,"signatures":[{"name":"saturation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adjusts the saturation of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/saturation(_:))."}]}]},"parameters":[{"name":"amount","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Saturation multiplier (0 to infinity, 1 = normal)."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scaleEffect","variant":"declaration","kind":64,"signatures":[{"name":"scaleEffect","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies scaling transformation."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scaleeffect(_:anchor:))."}]}]},"parameters":[{"name":"scale","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Uniform scale factor (1.0 = normal size), or an object with separate "},{"kind":"code","text":"`x`"},{"kind":"text","text":" and "},{"kind":"code","text":"`y`"},{"kind":"text","text":" scale factors."}]},"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"x","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]}}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollContentBackground","variant":"declaration","kind":64,"signatures":[{"name":"scrollContentBackground","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Specifies the visibility of the background for scrollable views within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrollcontentbackground(_:))."}]}]},"parameters":[{"name":"visible","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The visibility of the background."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"visible"},{"type":"literal","value":"hidden"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollDisabled","variant":"declaration","kind":64,"signatures":[{"name":"scrollDisabled","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Disables or enables scrolling in scrollable views."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolldisabled(_:))."}]}]},"parameters":[{"name":"disabled","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether scrolling should be disabled (default: true)."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"true"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollDismissesKeyboard","variant":"declaration","kind":64,"signatures":[{"name":"scrollDismissesKeyboard","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls how the keyboard is dismissed when scrolling."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolldismisseskeyboard(_:))."}]}]},"parameters":[{"name":"mode","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The keyboard dismiss mode."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"never"},{"type":"literal","value":"interactively"},{"type":"literal","value":"immediately"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollIndicators","variant":"declaration","kind":64,"signatures":[{"name":"scrollIndicators","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls the visibility of scroll indicators for scrollable views.\nMirrors SwiftUI's "},{"kind":"code","text":"`scrollIndicators(_:axes:)`"},{"kind":"text","text":" modifier."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 16.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 16.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrollindicators(_:axes:))."}]}]},"parameters":[{"name":"visibility","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Indicator visibility:\n- "},{"kind":"code","text":"`'automatic'`"},{"kind":"text","text":": platform-default behavior.\n- "},{"kind":"code","text":"`'visible'`"},{"kind":"text","text":": prefer showing indicators (may still be hidden by the system).\n- "},{"kind":"code","text":"`'hidden'`"},{"kind":"text","text":": prefer hiding indicators (may still be shown by the system).\n- "},{"kind":"code","text":"`'never'`"},{"kind":"text","text":": never show indicators."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"never"},{"type":"literal","value":"visible"},{"type":"literal","value":"hidden"}]}},{"name":"axes","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Axes to apply the visibility to. Defaults to "},{"kind":"code","text":"`'both'`"},{"kind":"text","text":"."}]},"type":{"type":"union","types":[{"type":"literal","value":"horizontal"},{"type":"literal","value":"vertical"},{"type":"literal","value":"both"}]},"defaultValue":"'both'"}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollPosition","variant":"declaration","kind":64,"signatures":[{"name":"scrollPosition","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Binds the leading scroll target of a scrollable container to an observable native state.\n\nReading "},{"kind":"code","text":"`state.value`"},{"kind":"text","text":" returns the id of the leading scroll target. Writing to it scrolls\nthe container to the matching view. Pair with "},{"kind":"code","text":"`scrollTargetLayout()`"},{"kind":"text","text":" on the content\ncontainer and "},{"kind":"code","text":"`id()`"},{"kind":"text","text":" on each target. Works on "},{"kind":"code","text":"`ScrollView`"},{"kind":"text","text":", "},{"kind":"code","text":"`LazyVStack`"},{"kind":"text","text":", "},{"kind":"code","text":"`LazyHStack`"},{"kind":"text","text":",\nand other scrollable containers.\n\nOn iOS below 17.0, the modifier is a no-op."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"tvos 17.0+"}]},{"tag":"@platform","content":[{"kind":"text","text":"macos 14.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrollposition(id:anchor:))."}]},{"tag":"@example","content":[{"kind":"code","text":"```tsx\nconst activeID = useNativeState(null);\n\n console.log('leading target:', newID),\n }),\n ]}>\n \n {items.map((item) => (\n {item.text}\n ))}\n \n
\n```"}]}]},"parameters":[{"name":"state","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An "},{"kind":"code","text":"`ObservableState`"},{"kind":"text","text":" created with "},{"kind":"code","text":"`useNativeState`"},{"kind":"text","text":"."}]},"type":{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/State/useNativeState.ts","qualifiedName":"ObservableState"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"literal","value":null}]}],"name":"ObservableState","package":"@expo/ui"}},{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"anchor","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Anchor used to pick which view drives the binding and to align\n programmatic scrolls. Maps to the "},{"kind":"code","text":"`anchor:`"},{"kind":"text","text":" parameter of SwiftUI's "},{"kind":"code","text":"`.scrollPosition(id:anchor:)`"},{"kind":"text","text":"."}]},"type":{"type":"reference","name":"UnitPointValue","package":"@expo/ui"}},{"name":"onChange","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Fires on the JS thread whenever the leading scroll target changes."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"id","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"literal","value":null}]}}],"type":{"type":"intrinsic","name":"void"}}]}}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollTargetBehavior","variant":"declaration","kind":64,"signatures":[{"name":"scrollTargetBehavior","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the scroll snapping behavior for scrollable views.\nUse with "},{"kind":"code","text":"`scrollTargetLayout`"},{"kind":"text","text":" on the content container."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolltargetbehavior(_:))."}]}]},"parameters":[{"name":"behavior","variant":"param","kind":32768,"comment":{"summary":[{"kind":"code","text":"`'paging'`"},{"kind":"text","text":" for container-aligned snapping, "},{"kind":"code","text":"`'viewAligned'`"},{"kind":"text","text":" for view-aligned snapping."}]},"type":{"type":"union","types":[{"type":"literal","value":"paging"},{"type":"literal","value":"viewAligned"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"scrollTargetLayout","variant":"declaration","kind":64,"signatures":[{"name":"scrollTargetLayout","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Configures a layout container as a scroll target layout for view-aligned snapping.\nApply to "},{"kind":"code","text":"`VStack`"},{"kind":"text","text":" or "},{"kind":"code","text":"`HStack`"},{"kind":"text","text":" inside a "},{"kind":"code","text":"`ScrollView`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 17.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolltargetlayout(isenabled:))."}]}]},"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"shadow","variant":"declaration","kind":64,"signatures":[{"name":"shadow","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds a shadow to a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/shadow(color:radius:x:y:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The shadow parameters: "},{"kind":"code","text":"`radius`"},{"kind":"text","text":", offset ("},{"kind":"code","text":"`x`"},{"kind":"text","text":", "},{"kind":"code","text":"`y`"},{"kind":"text","text":") and "},{"kind":"code","text":"`color`"},{"kind":"text","text":"."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"radius","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"x","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}},{"name":"y","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"number"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"strikethrough","variant":"declaration","kind":64,"signatures":[{"name":"strikethrough","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies a strikethrough to the text."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/text/strikethrough(_:color:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Controls whether the strikethrough is visible ("},{"kind":"code","text":"`true`"},{"kind":"text","text":" to show, "},{"kind":"code","text":"`false`"},{"kind":"text","text":" to hide)."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"isActive","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"boolean"}},{"name":"pattern","variant":"declaration","kind":1024,"type":{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/swift-ui/modifiers/index.ts","qualifiedName":"LinePattern"},"name":"LinePattern","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"submitLabel","variant":"declaration","kind":64,"signatures":[{"name":"submitLabel","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Specifies the label to display in the keyboard's return key. For example, "},{"kind":"code","text":"`'done'`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A view that uses the specified submit label."}]},{"tag":"@platform","content":[{"kind":"text","text":"iOS 15+"}]},{"tag":"@example","content":[{"kind":"code","text":"```tsx\n\n```"}]}]},"parameters":[{"name":"submitLabel","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The label to display in the keyboard's return key."}]},"type":{"type":"union","types":[{"type":"literal","value":"join"},{"type":"literal","value":"search"},{"type":"literal","value":"done"},{"type":"literal","value":"continue"},{"type":"literal","value":"go"},{"type":"literal","value":"next"},{"type":"literal","value":"return"},{"type":"literal","value":"route"},{"type":"literal","value":"send"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"tabViewStyle","variant":"declaration","kind":64,"signatures":[{"name":"tabViewStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for a "},{"kind":"code","text":"`TabView`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/tabviewstyle(_:))."}]}]},"parameters":[{"name":"config","variant":"param","kind":32768,"type":{"type":"reference","name":"TabViewStyleConfig","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"tag","variant":"declaration","kind":64,"signatures":[{"name":"tag","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets a tag on a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/tag(_:includeoptional:))."}]}]},"parameters":[{"name":"tag","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The tag to set on the view."}]},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textCase","variant":"declaration","kind":64,"signatures":[{"name":"textCase","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets a transform for the case of the text contained in this view when displayed."}],"blockTags":[{"tag":"@default","content":[{"kind":"text","text":"\"lowercase\""}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textcase(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"literal","value":"lowercase"},{"type":"literal","value":"uppercase"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textContentType","variant":"declaration","kind":64,"signatures":[{"name":"textContentType","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the text content type for input text, which the system uses to offer\nsuggestions (like autofill) while the user enters text."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 13.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textcontenttype(_:)-ufdv)."}]}]},"parameters":[{"name":"textContentType","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The semantic meaning of the text input area."}]},"type":{"type":"union","types":[{"type":"literal","value":"URL"},{"type":"literal","value":"namePrefix"},{"type":"literal","value":"name"},{"type":"literal","value":"nameSuffix"},{"type":"literal","value":"givenName"},{"type":"literal","value":"middleName"},{"type":"literal","value":"familyName"},{"type":"literal","value":"nickname"},{"type":"literal","value":"organizationName"},{"type":"literal","value":"jobTitle"},{"type":"literal","value":"location"},{"type":"literal","value":"fullStreetAddress"},{"type":"literal","value":"streetAddressLine1"},{"type":"literal","value":"streetAddressLine2"},{"type":"literal","value":"addressCity"},{"type":"literal","value":"addressCityAndState"},{"type":"literal","value":"addressState"},{"type":"literal","value":"postalCode"},{"type":"literal","value":"sublocality"},{"type":"literal","value":"countryName"},{"type":"literal","value":"username"},{"type":"literal","value":"password"},{"type":"literal","value":"newPassword"},{"type":"literal","value":"oneTimeCode"},{"type":"literal","value":"emailAddress"},{"type":"literal","value":"telephoneNumber"},{"type":"literal","value":"cellularEID"},{"type":"literal","value":"cellularIMEI"},{"type":"literal","value":"creditCardNumber"},{"type":"literal","value":"creditCardExpiration"},{"type":"literal","value":"creditCardExpirationMonth"},{"type":"literal","value":"creditCardExpirationYear"},{"type":"literal","value":"creditCardSecurityCode"},{"type":"literal","value":"creditCardType"},{"type":"literal","value":"creditCardName"},{"type":"literal","value":"creditCardGivenName"},{"type":"literal","value":"creditCardMiddleName"},{"type":"literal","value":"creditCardFamilyName"},{"type":"literal","value":"birthdate"},{"type":"literal","value":"birthdateDay"},{"type":"literal","value":"birthdateMonth"},{"type":"literal","value":"birthdateYear"},{"type":"literal","value":"dateTime"},{"type":"literal","value":"flightNumber"},{"type":"literal","value":"shipmentTrackingNumber"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textFieldStyle","variant":"declaration","kind":64,"signatures":[{"name":"textFieldStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the text field style for text field views."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textfieldstyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The text field style."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"plain"},{"type":"literal","value":"roundedBorder"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textInputAutocapitalization","variant":"declaration","kind":64,"signatures":[{"name":"textInputAutocapitalization","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets how often the shift key in the keyboard is automatically enabled."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios 15.0+"}]},{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textinputautocapitalization(_:))."}]}]},"parameters":[{"name":"autocapitalization","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The autocapitalization behavior."}]},"type":{"type":"union","types":[{"type":"literal","value":"never"},{"type":"literal","value":"words"},{"type":"literal","value":"sentences"},{"type":"literal","value":"characters"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"textSelection","variant":"declaration","kind":64,"signatures":[{"name":"textSelection","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Controls whether people can select text within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/textselection(_:))."}]}]},"parameters":[{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Enable selection"}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"tint","variant":"declaration","kind":64,"signatures":[{"name":"tint","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the tint color of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/tint(_:))."}]}]},"parameters":[{"name":"color","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The tint color (hex string). For example, "},{"kind":"code","text":"`#FF0000`"},{"kind":"text","text":"."}]},"type":{"type":"reference","name":"Color","package":"@expo/ui"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"toggleStyle","variant":"declaration","kind":64,"signatures":[{"name":"toggleStyle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the style for toggles within this view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/togglestyle(_:))."}]}]},"parameters":[{"name":"style","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The toggle style."}]},"type":{"type":"union","types":[{"type":"literal","value":"automatic"},{"type":"literal","value":"switch"},{"type":"literal","value":"button"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"truncationMode","variant":"declaration","kind":64,"signatures":[{"name":"truncationMode","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the truncation mode for lines of text that are too long to fit in the available space."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/truncationmode(_:))."}]}]},"parameters":[{"name":"mode","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The truncation mode that specifies where to truncate the text within the text view, if needed.\nYou can truncate at the beginning, middle, or end of the text view."}]},"type":{"type":"union","types":[{"type":"literal","value":"head"},{"type":"literal","value":"middle"},{"type":"literal","value":"tail"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"underline","variant":"declaration","kind":64,"signatures":[{"name":"underline","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Applies an underline to the text."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/underline(_:pattern:color:))."}]}]},"parameters":[{"name":"params","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Controls whether the underline is visible ("},{"kind":"code","text":"`true`"},{"kind":"text","text":" to show, "},{"kind":"code","text":"`false`"},{"kind":"text","text":" to hide)."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"color","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"reference","name":"Color","package":"@expo/ui"}},{"name":"isActive","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"boolean"}},{"name":"pattern","variant":"declaration","kind":1024,"type":{"type":"reference","target":{"packageName":"@expo/ui","packagePath":"src/swift-ui/modifiers/index.ts","qualifiedName":"LinePattern"},"name":"LinePattern","package":"@expo/ui"}}]}}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"widgetAccentedRenderingMode","variant":"declaration","kind":64,"signatures":[{"name":"widgetAccentedRenderingMode","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Specifies the how to render an Image when using the WidgetKit/WidgetRenderingMode/accented mode."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/image/widgetaccentedrenderingmode(_:))."}]}]},"parameters":[{"name":"renderingMode","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A constant describing how the Image should be rendered."}]},"type":{"type":"union","types":[{"type":"literal","value":"fullColor"},{"type":"literal","value":"accented"},{"type":"literal","value":"desaturated"},{"type":"literal","value":"accentedDesaturated"}]}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"widgetURL","variant":"declaration","kind":64,"signatures":[{"name":"widgetURL","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the URL to open in the containing app when the user clicks the widget.\nWidgets support one widgetURL modifier in their view hierarchy. If multiple views have widgetURL modifiers, the behavior is undefined."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/widgetURL(_:))."}]}]},"parameters":[{"name":"url","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The URL to open in the containing app."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]},{"name":"zIndex","variant":"declaration","kind":64,"signatures":[{"name":"zIndex","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Sets the z-index (display order) of a view."}],"blockTags":[{"tag":"@see","content":[{"kind":"text","text":"Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/zindex(_:))."}]}]},"parameters":[{"name":"index","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The z-index value."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"ModifierConfig","package":"@expo/ui"}}]}],"packageName":"@expo/ui"} \ No newline at end of file diff --git a/packages/expo-ui/CHANGELOG.md b/packages/expo-ui/CHANGELOG.md index 4b5148fe462662..db9e12c666c567 100644 --- a/packages/expo-ui/CHANGELOG.md +++ b/packages/expo-ui/CHANGELOG.md @@ -6,10 +6,14 @@ ### 🎉 New features +- [iOS] Added the `scrollIndicators(visibility, axes?)` SwiftUI modifier in `@expo/ui/swift-ui/modifiers`, wrapping SwiftUI's `scrollIndicators(_:axes:)`. ([#45649](https://github.com/expo/expo/pull/45649) by [@vonovak](https://github.com/vonovak)) + ### 🐛 Bug fixes ### 💡 Others +- [iOS] Consolidated the duplicate `AxisOptions` / `AxisSetType` enums into a single `AxisOptions` in `Convertibles/AxisOptions.swift`. ([#45649](https://github.com/expo/expo/pull/45649) by [@vonovak](https://github.com/vonovak)) + ## 56.0.4 — 2026-05-08 ### 💡 Others diff --git a/packages/expo-ui/build/swift-ui/ScrollView/index.d.ts b/packages/expo-ui/build/swift-ui/ScrollView/index.d.ts index 9d493e29ad2125..343e6d7959f86c 100644 --- a/packages/expo-ui/build/swift-ui/ScrollView/index.d.ts +++ b/packages/expo-ui/build/swift-ui/ScrollView/index.d.ts @@ -2,12 +2,13 @@ import { type CommonViewModifierProps } from '../types'; export type ScrollViewProps = { children: React.ReactNode; /** - * The scrollable axes. + * The scrollable axes. Pass `'both'` to enable 2D (horizontal + vertical) scrolling. * @default 'vertical' */ axes?: 'vertical' | 'horizontal' | 'both'; /** - * Whether to show scroll indicators. + * Whether to show scroll indicators. For richer visibility control (e.g. `'never'`) + * or per-axis control, use the `scrollIndicators(...)` modifier instead. * @default true */ showsIndicators?: boolean; diff --git a/packages/expo-ui/build/swift-ui/ScrollView/index.d.ts.map b/packages/expo-ui/build/swift-ui/ScrollView/index.d.ts.map index 6cb13708fd6a83..118c7627a5dbc5 100644 --- a/packages/expo-ui/build/swift-ui/ScrollView/index.d.ts.map +++ b/packages/expo-ui/build/swift-ui/ScrollView/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/swift-ui/ScrollView/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IAC1C;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,uBAAuB,CAAC;AAO5B,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,2CAShD"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/swift-ui/ScrollView/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IAC1C;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,uBAAuB,CAAC;AAO5B,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,2CAShD"} \ No newline at end of file diff --git a/packages/expo-ui/build/swift-ui/modifiers/index.d.ts b/packages/expo-ui/build/swift-ui/modifiers/index.d.ts index dc723c3d213a4e..e01c7be9a2d00f 100644 --- a/packages/expo-ui/build/swift-ui/modifiers/index.d.ts +++ b/packages/expo-ui/build/swift-ui/modifiers/index.d.ts @@ -466,6 +466,20 @@ export declare const scrollDismissesKeyboard: (mode: "automatic" | "never" | "in * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrolldisabled(_:)). */ export declare const scrollDisabled: (disabled?: boolean) => ModifierConfig; +/** + * Controls the visibility of scroll indicators for scrollable views. + * Mirrors SwiftUI's `scrollIndicators(_:axes:)` modifier. + * @param visibility - Indicator visibility: + * - `'automatic'`: platform-default behavior. + * - `'visible'`: prefer showing indicators (may still be hidden by the system). + * - `'hidden'`: prefer hiding indicators (may still be shown by the system). + * - `'never'`: never show indicators. + * @param axes - Axes to apply the visibility to. Defaults to `'both'`. + * @platform ios 16.0+ + * @platform tvos 16.0+ + * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/scrollindicators(_:axes:)). + */ +export declare const scrollIndicators: (visibility: "automatic" | "visible" | "hidden" | "never", axes?: "vertical" | "horizontal" | "both") => ModifierConfig; export type UnitPointValue = 'zero' | 'topLeading' | 'top' | 'topTrailing' | 'leading' | 'center' | 'trailing' | 'bottomLeading' | 'bottom' | 'bottomTrailing'; /** * Sets the default anchor point for a scroll view's content. @@ -945,7 +959,7 @@ export declare const resizable: (capInsets?: { * This provides type safety for the modifiers array. * @hidden */ -export type BuiltInModifier = ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType