@ttsc/metro 0.30.4 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +11 -6
  2. package/lib/core/SnapshotReadOperations.d.ts +119 -0
  3. package/lib/core/SnapshotReadOperations.js +3 -0
  4. package/lib/core/SnapshotReadOperations.js.map +1 -0
  5. package/lib/core/SnapshotReadOperations.mjs +2 -0
  6. package/lib/core/SnapshotReadOperations.mjs.map +1 -0
  7. package/lib/core/TtscMetroOptions.d.ts +119 -0
  8. package/lib/core/TtscMetroOptions.js +3 -0
  9. package/lib/core/TtscMetroOptions.js.map +1 -0
  10. package/lib/core/TtscMetroOptions.mjs +2 -0
  11. package/lib/core/TtscMetroOptions.mjs.map +1 -0
  12. package/lib/core/TtscMetroProjectView.d.ts +64 -0
  13. package/lib/core/TtscMetroProjectView.js +3 -0
  14. package/lib/core/TtscMetroProjectView.js.map +1 -0
  15. package/lib/core/TtscMetroProjectView.mjs +2 -0
  16. package/lib/core/TtscMetroProjectView.mjs.map +1 -0
  17. package/lib/core/UpstreamTransformer.d.ts +127 -0
  18. package/lib/core/UpstreamTransformer.js +3 -0
  19. package/lib/core/UpstreamTransformer.js.map +1 -0
  20. package/lib/core/UpstreamTransformer.mjs +2 -0
  21. package/lib/core/UpstreamTransformer.mjs.map +1 -0
  22. package/lib/core/fingerprint.d.ts +442 -97
  23. package/lib/core/fingerprint.js +838 -83
  24. package/lib/core/fingerprint.js.map +1 -1
  25. package/lib/core/fingerprint.mjs +839 -84
  26. package/lib/core/fingerprint.mjs.map +1 -1
  27. package/lib/core/options.d.ts +81 -58
  28. package/lib/core/options.js +81 -4
  29. package/lib/core/options.js.map +1 -1
  30. package/lib/core/options.mjs +81 -4
  31. package/lib/core/options.mjs.map +1 -1
  32. package/lib/core/remapAstLocations.d.ts +76 -0
  33. package/lib/core/remapAstLocations.js +205 -0
  34. package/lib/core/remapAstLocations.js.map +1 -0
  35. package/lib/core/remapAstLocations.mjs +203 -0
  36. package/lib/core/remapAstLocations.mjs.map +1 -0
  37. package/lib/core/upstream.d.ts +97 -27
  38. package/lib/core/upstream.js +109 -8
  39. package/lib/core/upstream.js.map +1 -1
  40. package/lib/core/upstream.mjs +109 -9
  41. package/lib/core/upstream.mjs.map +1 -1
  42. package/lib/index.d.ts +50 -2
  43. package/lib/index.js +88 -24
  44. package/lib/index.js.map +1 -1
  45. package/lib/index.mjs +89 -25
  46. package/lib/index.mjs.map +1 -1
  47. package/lib/transformer.d.ts +183 -6
  48. package/lib/transformer.js +209 -14
  49. package/lib/transformer.js.map +1 -1
  50. package/lib/transformer.mjs +211 -16
  51. package/lib/transformer.mjs.map +1 -1
  52. package/package.json +7 -18
  53. package/src/core/SnapshotReadOperations.ts +121 -0
  54. package/src/core/TtscMetroOptions.ts +127 -0
  55. package/src/core/TtscMetroProjectView.ts +74 -0
  56. package/src/core/UpstreamTransformer.ts +126 -0
  57. package/src/core/fingerprint.ts +987 -109
  58. package/src/core/options.ts +85 -62
  59. package/src/core/remapAstLocations.ts +219 -0
  60. package/src/core/upstream.ts +110 -26
  61. package/src/index.ts +99 -28
  62. package/src/transformer.ts +214 -17
package/README.md CHANGED
@@ -39,11 +39,11 @@ const { withTtsc } = require("@ttsc/metro");
39
39
  module.exports = withTtsc(getDefaultConfig(__dirname));
40
40
  ```
41
41
 
42
- `withTtsc` sets `transformer.babelTransformerPath` and leaves the rest of your config untouched. It auto-detects the upstream transformer to delegate to (`@expo/metro-config/babel-transformer` for Expo, then `@react-native/metro-babel-transformer`, then the legacy `metro-react-native-babel-transformer`).
42
+ `withTtsc` sets `transformer.babelTransformerPath` and leaves the rest of your config untouched. It auto-detects the upstream transformer to delegate to (`@expo/metro-config/babel-transformer` for Expo, then `@react-native/metro-babel-transformer`, then the legacy `metro-react-native-babel-transformer`). Those candidates, and a package name passed as `upstreamTransformer`, resolve from your project (`projectRoot`), so a transformer only the app installed is found even when the adapter itself lives outside the app's `node_modules`, as it does under pnpm or a linked workspace.
43
43
 
44
44
  If your config already set `transformer.babelTransformerPath`, that transformer is **chained rather than replaced**: the `ttsc` pass runs first and then delegates to it, so wrapping a working config keeps what it configured. This is what makes `react-native-svg-transformer`, whose entire installation is that one assignment, keep working after you adopt `@ttsc/metro`. Pass `upstreamTransformer` explicitly to override both that and auto-detection.
45
45
 
46
- The value is resolved from your `projectRoot`, exactly as Metro resolves it, so a relative `"./metro-svg.cjs"` and a bare `"react-native-svg-transformer"` both mean what they mean in your project rather than inside this package. A path that names `@ttsc/metro`'s own transformer is never chained in any spelling, including a second copy installed elsewhere in your tree, because delegating this transformer into itself would recurse on every file.
46
+ The value is resolved from your `projectRoot`, exactly as Metro resolves it, so a relative `"./metro-svg.cjs"` and a bare `"react-native-svg-transformer"` both mean what they mean in your project rather than inside this package. A `babelTransformerPath` that names `@ttsc/metro`'s own transformer is never adopted as the upstream in any spelling, including a second copy installed elsewhere in your tree, because delegating this transformer into itself would recurse on every file. An explicit `upstreamTransformer` is taken as written, so it must not name this package.
47
47
 
48
48
  Auto-detection only skips a candidate whose entry point is genuinely **not available**: the package is not installed, or it is installed but the requested subpath is not exported (Expo/React Native version skew). A candidate that _does_ resolve but fails while loading, whether from a top-level throw, an incompatible runtime ABI, or a missing peer or transitive dependency, surfaces its original error (as the `cause` of a `@ttsc/metro` wrapper) instead of being treated as absent. This stops a broken Expo/React Native install from silently falling through to the wrong transformer, and stops an explicit `upstreamTransformer` failure from being reported as if the module did not exist.
49
49
 
@@ -65,7 +65,7 @@ module.exports = withTtsc(getDefaultConfig(__dirname), {
65
65
  - `compilerOptions`: a temporary overlay layered on the selected project config.
66
66
  - `plugins`: an explicit `ttsc` plugin list override, or `false` to disable project plugins.
67
67
  - `upstreamTransformer`: an explicit module path for the Babel transformer to delegate to, when neither the config's own transformer nor auto-detection is what you want.
68
- - `include` / `exclude`: substring patterns matched against the project-relative file path, selecting which files run through the `ttsc` pass (`.ts`/`.tsx`/`.cts`/`.mts` only; declaration and JavaScript files always pass straight through).
68
+ - `include` / `exclude`: substring patterns matched against the project-relative file path, selecting which files run through the `ttsc` pass (`.ts`/`.tsx`/`.cts`/`.mts` only; declaration files, JavaScript files and anything below a `node_modules` directory always pass straight through).
69
69
 
70
70
  Options are forwarded from the Metro **config** process to Metro's **worker** processes through the `TTSC_METRO_OPTIONS` environment variable, so they must stay JSON-serialisable (hence substring patterns rather than `RegExp`).
71
71
 
@@ -75,6 +75,7 @@ For each TypeScript file Metro asks to transform:
75
75
 
76
76
  1. `@ttsc/metro` runs the `ttsc` plugin pass (reusing `@ttsc/unplugin`'s transform core) → transformed **TypeScript** source.
77
77
  2. The transformed source is handed to the upstream Expo/React-Native Babel transformer, which strips types, applies the RN transforms, and returns the Babel AST Metro consumes.
78
+ 3. The pass also returns a source map back to your text, and `@ttsc/metro` moves the returned AST's locations through it, so the map Metro builds from that AST, and every stack trace and breakpoint, points at the lines you wrote rather than at the transformed text.
78
79
 
79
80
  The plugin contract and `tsconfig` discovery match the Unplugin integrations. Metro's worker has no build-start callback, so its shared transform cache validates the complete project snapshot on every hit instead of using a build-scoped first-delivery shortcut.
80
81
 
@@ -90,16 +91,18 @@ should apply to it.
90
91
 
91
92
  This is not a build error. The file is simply not this project's to transform, and the usual cause is a Metro graph reaching past the `tsconfig`'s `include`, such as a source beside `src` rather than inside it or one in a sibling workspace folder. Add it to that project's `include` if `ttsc` plugins should apply to it.
92
93
 
93
- The report matters because passing through is not the same as leaving alone: a file that skips the `ttsc` pass keeps whatever plugin-driven syntax it carries, which fails at runtime rather than at build time. Declaration and JavaScript files never reach the pass at all, so they are not reported; they are filtered before it, as `include` / `exclude` above describes.
94
+ The report matters because passing through is not the same as leaving alone: a file that skips the `ttsc` pass keeps whatever plugin-driven syntax it carries, which fails at runtime rather than at build time. Declaration files, JavaScript files and files below `node_modules` never reach the pass at all, so they are not reported; they are filtered before it, as `include` / `exclude` above describes.
94
95
 
95
96
  This is the shared core's answer rather than Metro's own, so every `@ttsc/unplugin` adapter gives the identical one. `@ttsc/metro` used to be alone in treating it as non-fatal while every adapter failed the build.
96
97
 
97
98
  ## Cache invalidation
98
99
 
99
- Metro keys its transform cache on each file's own content plus one static transformer key, and its babel-transformer contract has no per-file dependency registration. A `ttsc` transform can depend on a _type_ in another file, so `@ttsc/metro` folds a project fingerprint into that static key: every regular file reached by the project walk, every effective config source, and transform inputs recorded under `node_modules/.cache/ttsc-metro`. In a workspace with nested or directory-linked `tsconfig.json` projects, each lexical subtree is walked under the nearest config that transformed files use; the project-map traversal follows symlinks and Windows junctions while a physical ancestor set cuts cycles without collapsing independent aliases. The project map itself is hashed so adding or removing a nested or linked project config also changes the key. Worker discovery retains the exact candidate predicates that selected its project instead of reconstructing them after selection. A module passed through because its Program has no output still records those candidates and the universal config inputs that can later admit it. `withTtsc` gives each run a private identity, `getCacheKey` records the exact file state and static coverage that identity hashed, and workers compare every derived input's compiler-generation hash, realpath, or resolution predicate with that baseline. Inputs outside proven static coverage stay in one batched worker snapshot. A missing input, an out-of-root `watchFolders` project, a symlink or Windows junction transition, an `extends` change, or any A-to-B-to-A change between static keying and transformation taints the observation and rotates the next snapshot epoch, so it cannot collide with the earlier A key. Editing any fingerprinted input re-keys the next run, so `metro bundle` and dev-server starts pick up cross-file type changes without `--reset-cache`.
100
+ Metro keys its transform cache on each file's own content plus one static transformer key, and its babel-transformer contract has no per-file dependency registration. A `ttsc` transform can depend on a _type_ in another file, so `@ttsc/metro` folds a project fingerprint into that static key: every file the project walk admits under the project's membership policy, every effective config source, and transform inputs recorded under `node_modules/.cache/ttsc-metro`. In a workspace with nested or directory-linked `tsconfig.json` projects, each lexical subtree is walked under the nearest config that transformed files use; the project-map traversal follows symlinks and Windows junctions while a physical ancestor set cuts cycles without collapsing independent aliases. The project map itself is hashed so adding or removing a nested or linked project config also changes the key. Worker discovery retains the exact candidate predicates that selected its project instead of reconstructing them after selection. A module passed through because its Program has no output still records those candidates and the universal config inputs that can later admit it. `withTtsc` gives each run a private identity, `getCacheKey` records the exact file state and static coverage that identity hashed, and workers compare every derived input's compiler-generation hash, realpath, or resolution predicate with that baseline. Inputs outside proven static coverage stay in one batched worker snapshot. A missing input, an out-of-root `watchFolders` project, a symlink or Windows junction transition, an `extends` change, or any A-to-B-to-A change between static keying and transformation taints the observation and rotates the next snapshot epoch, so it cannot collide with the earlier A key. Editing any fingerprinted input re-keys the next run, so `metro bundle` and dev-server starts pick up cross-file type changes without `--reset-cache`.
100
101
 
101
102
  Snapshot compaction is serialized across Metro config processes. If two builds prepare the same project cache at once, one compacts the shared worker documents and the contender uses a private non-reusable key for that run instead of racing the main snapshot rewrite.
102
103
 
104
+ Upstream loading and cache-key errors remain nonfatal during key computation. They disable cross-run reuse through a nonce because the upstream contribution is unknown. An upstream without an optional `getCacheKey` callback still contributes no additional key. Loading failures propagate when Metro actually transforms a file.
105
+
103
106
  The granularity is project-level by necessity: Metro evaluates the transformer key once per run, so any fingerprinted change re-transforms every file on the next run. What remains outside the mechanism's reach:
104
107
 
105
108
  - **Within a running dev server**, Metro re-transforms only files its watcher reports changed. Editing a type in file B updates a dependent file A on A's next transform: save A, or restart the dev server (no `--reset-cache` needed).
@@ -108,7 +111,9 @@ The granularity is project-level by necessity: Metro evaluates the transformer k
108
111
 
109
112
  ## Caveats (v1)
110
113
 
111
- - **Cost model.** This release reuses `@ttsc/unplugin`'s transform core, which type-checks the whole `tsconfig` project and caches the result per process. Metro runs transforms in a multi-process worker pool, so the project is compiled once per worker (on that worker's first file). A resident, incremental, per-file compiler shared across workers is the planned optimization, tracked in [samchon/ttsc#255](https://github.com/samchon/ttsc/issues/255).
114
+ - **Cost model.** This release reuses `@ttsc/unplugin`'s transform core, which type-checks the whole `tsconfig` project. Metro runs transforms in a multi-process worker pool, and the workers share each compile: `withTtsc` opens a session in the Metro process, and the first worker to need a project state compiles it while the others wait and adopt it, after proving it against their own filesystem. So a cold build and each edit compile the project once, not once per worker. The session's store lives under the system temporary directory, one per user, and outlives Metro: a restarted Metro's workers adopt what the last one compiled, after the same proof, and a compile is named by the ttsc, TypeScript-Go, and adapter versions it ran under. A resident, incremental, per-file compiler is the next step, tracked in [samchon/ttsc#255](https://github.com/samchon/ttsc/issues/255).
115
+ - **Unobservable plugin inputs fail the build.** `@ttsc/metro` does not tell the shared core whether Metro is watching, so a compile whose plugin input observation is unavailable on the host fails the transform with an error naming that, rather than being cached.
116
+ - **A stale compaction lock keeps the cache cold.** If the process that held `node_modules/.cache/ttsc-metro/snapshot-compaction.lock` died and its process id now belongs to a live process, every run takes a non-reusable key until that process exits or you delete the lock directory.
112
117
  - **Type errors fail the build.** The `ttsc` pass type-checks; a project type error surfaces as a Metro build error, matching the other `ttsc` bundler integrations.
113
118
 
114
119
  ## Sponsors
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The filesystem reads the snapshot reader performs, injectable so a test can
3
+ * drive the interleaving of a listing with a concurrent compaction. Production
4
+ * passes nothing and reads the real filesystem.
5
+ *
6
+ * @evidence contracts/common.md#principled-implementation
7
+ * A structural record of the three Node filesystem reads the snapshot reader
8
+ * makes; the default delegates to node:fs unchanged.
9
+ *
10
+ * @evidence contracts/common.md#clear-and-simple-design
11
+ * One optional parameter carries the read boundary instead of a test mode
12
+ * flag, mirroring the repository's injectable filesystem operations.
13
+ *
14
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
15
+ * Production code never branches on the injection; no fs method is patched.
16
+ *
17
+ * @evidence contracts/common.md#meaningful-documentation
18
+ * The native JSDoc states why the boundary exists and that production uses
19
+ * the real filesystem.
20
+ *
21
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
22
+ * Declares a shape only; it holds no state, handle or buffer.
23
+ *
24
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
25
+ * Declares a shape only; there is no loop or processing in it.
26
+ *
27
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
28
+ * Declares a shape only; it computes nothing to share.
29
+ *
30
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
31
+ * Declares three call signatures; the host filesystem interprets every path it is given.
32
+ */
33
+ export interface SnapshotReadOperations {
34
+ /**
35
+ * Whether a path exists, as `fs.existsSync`.
36
+ *
37
+ * @evidence contracts/common.md#principled-implementation
38
+ * Signature of the Node call it replaces; the default delegates to it.
39
+ *
40
+ * @evidence contracts/common.md#clear-and-simple-design
41
+ * One call per member, no behavior of its own.
42
+ *
43
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
44
+ * The reader never branches on whether it was injected.
45
+ *
46
+ * @evidence contracts/common.md#meaningful-documentation
47
+ * States which read this member stands for.
48
+ *
49
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
50
+ * Declares a shape only; it holds no state, handle or buffer.
51
+ *
52
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
53
+ * Declares a shape only; there is no loop or processing in it.
54
+ *
55
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
56
+ * Declares a shape only; it computes nothing to share.
57
+ *
58
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
59
+ * Forwards its path to the host call unchanged; no path is interpreted here.
60
+ */
61
+ existsSync: (file: string) => boolean;
62
+ /**
63
+ * Text of a file, as `fs.readFileSync`; throws a missing-file error when
64
+ * absent.
65
+ *
66
+ * @evidence contracts/common.md#principled-implementation
67
+ * Signature of the Node call it replaces; the default delegates to it.
68
+ *
69
+ * @evidence contracts/common.md#clear-and-simple-design
70
+ * One call per member, no behavior of its own.
71
+ *
72
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
73
+ * The reader never branches on whether it was injected.
74
+ *
75
+ * @evidence contracts/common.md#meaningful-documentation
76
+ * States which read this member stands for.
77
+ *
78
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
79
+ * Declares a shape only; it holds no state, handle or buffer.
80
+ *
81
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
82
+ * Declares a shape only; there is no loop or processing in it.
83
+ *
84
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
85
+ * Declares a shape only; it computes nothing to share.
86
+ *
87
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
88
+ * Forwards its path to the host call unchanged; no path is interpreted here.
89
+ */
90
+ readFileSync: (file: string, encoding: "utf8") => string;
91
+ /**
92
+ * Entry names of a directory, as `fs.readdirSync`.
93
+ *
94
+ * @evidence contracts/common.md#principled-implementation
95
+ * Signature of the Node call it replaces; the default delegates to it.
96
+ *
97
+ * @evidence contracts/common.md#clear-and-simple-design
98
+ * One call per member, no behavior of its own.
99
+ *
100
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
101
+ * The reader never branches on whether it was injected.
102
+ *
103
+ * @evidence contracts/common.md#meaningful-documentation
104
+ * States which read this member stands for.
105
+ *
106
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
107
+ * Declares a shape only; it holds no state, handle or buffer.
108
+ *
109
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
110
+ * Declares a shape only; there is no loop or processing in it.
111
+ *
112
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
113
+ * Declares a shape only; it computes nothing to share.
114
+ *
115
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
116
+ * Forwards its directory to the host call unchanged; no path is interpreted here.
117
+ */
118
+ readdirSync: (directory: string) => string[];
119
+ }
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ //# sourceMappingURL=SnapshotReadOperations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SnapshotReadOperations.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=SnapshotReadOperations.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SnapshotReadOperations.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,119 @@
1
+ import type { TtscUnpluginOptions } from "@ttsc/unplugin/api";
2
+ /**
3
+ * Options accepted by {@link withTtsc} and the Metro transformer.
4
+ *
5
+ * The `project` / `compilerOptions` / `plugins` fields are inherited from
6
+ * `@ttsc/unplugin` so the Metro adapter speaks the exact same configuration
7
+ * language as every other bundler integration. The remaining fields are
8
+ * Metro-specific.
9
+ *
10
+ * Every field is JSON-serialisable on purpose: `withTtsc` runs in the Metro
11
+ * **config** process, but the transformer runs in Metro's **worker** processes,
12
+ * so the resolved options have to survive a JSON / env round-trip to reach them
13
+ * (see {@link serializeOptions}). That is why `include`/`exclude` are plain
14
+ * substring patterns rather than `RegExp`.
15
+ *
16
+ * @evidence contracts/common.md#principled-implementation
17
+ * This interface extends the documented Unplugin option contract rather than
18
+ * defining another plugin protocol. Metro adds JSON-compatible upstream and
19
+ * substring filters for its config-to-worker transport.
20
+ *
21
+ * @evidence contracts/common.md#clear-and-simple-design
22
+ * Inheritance keeps shared compiler options with Unplugin; this interface
23
+ * adds only upstream selection and the two Metro substring filters.
24
+ *
25
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
26
+ * The representation follows the documented consumer contract; its fields do
27
+ * not introduce fixture-selected variants.
28
+ *
29
+ * @evidence contracts/common.md#meaningful-documentation
30
+ * The native JSDoc explains inherited options, JSON transport, upstream
31
+ * precedence and the include/exclude relationship. Checked against the
32
+ * documentation skill: separate paragraphs state the contract and why its
33
+ * nonobvious boundary matters; field comments retain their own useful
34
+ * facts.
35
+ *
36
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
37
+ * Declares a shape only; it holds no state, handle or buffer.
38
+ *
39
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
40
+ * Declares a shape only; there is no loop or processing in it.
41
+ *
42
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
43
+ * Declares a shape only; it computes nothing to share.
44
+ *
45
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
46
+ * Carries project and upstream paths as strings; every path is resolved by the code that consumes it.
47
+ */
48
+ export interface TtscMetroOptions extends TtscUnpluginOptions {
49
+ /**
50
+ * Explicit module path of the upstream Metro Babel transformer to delegate to
51
+ * after the ttsc pass.
52
+ *
53
+ * When omitted, `withTtsc` inherits the config's existing transformer unless
54
+ * it names this adapter. Without one it detects
55
+ * `@expo/metro-config/babel-transformer` first (Expo), then
56
+ * `@react-native/metro-babel-transformer`, then the legacy
57
+ * `metro-react-native-babel-transformer`.
58
+ */
59
+ upstreamTransformer?: string;
60
+ /**
61
+ * Substring patterns; when non-empty only files whose path contains one of
62
+ * them are run through the ttsc pass. Non-matching files are passed straight
63
+ * to the upstream transformer.
64
+ */
65
+ include?: string[];
66
+ /**
67
+ * Substring patterns; files whose path contains one of them skip the ttsc
68
+ * pass and go straight to the upstream transformer. Applied after
69
+ * {@link include}.
70
+ */
71
+ exclude?: string[];
72
+ }
73
+ /**
74
+ * Fully-resolved options, split into the ttsc-side overlay and Metro-side
75
+ * knobs.
76
+ *
77
+ * @evidence contracts/common.md#principled-implementation
78
+ * A structural interface separates the existing Unplugin overlay from
79
+ * resolved Metro filters and the private run handshake.
80
+ *
81
+ * @evidence contracts/common.md#clear-and-simple-design
82
+ * The ttsc member groups the forwarded overlay, while always-present filter
83
+ * arrays remove optional-array handling from every worker delivery.
84
+ *
85
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
86
+ * Its optional upstream/run identity and always-present arrays describe
87
+ * worker state without executable branches or mutation.
88
+ *
89
+ * @evidence contracts/common.md#meaningful-documentation
90
+ * The native JSDoc explains the forwarded overlay, empty filter arrays,
91
+ * optional upstream and private snapshot identity. Checked against the
92
+ * documentation skill: separate paragraphs state the contract and why its
93
+ * nonobvious boundary matters; field comments retain their own useful
94
+ * facts.
95
+ *
96
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
97
+ * Declares a shape only; it holds no state, handle or buffer.
98
+ *
99
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
100
+ * Declares a shape only; there is no loop or processing in it.
101
+ *
102
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
103
+ * Declares a shape only; it computes nothing to share.
104
+ *
105
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
106
+ * Carries project and upstream paths as strings; every path is resolved by the code that consumes it.
107
+ */
108
+ export interface ResolvedTtscMetroOptions {
109
+ /** Options forwarded verbatim to the `@ttsc/unplugin` transform core. */
110
+ ttsc: TtscUnpluginOptions;
111
+ /** Explicit upstream transformer module path, or `undefined` to auto-detect. */
112
+ upstreamTransformer?: string;
113
+ /** Resolved include patterns (never `undefined`). */
114
+ include: string[];
115
+ /** Resolved exclude patterns (never `undefined`). */
116
+ exclude: string[];
117
+ /** Private run identity shared by `getCacheKey` and Metro workers. */
118
+ snapshotRunId?: string;
119
+ }
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ //# sourceMappingURL=TtscMetroOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TtscMetroOptions.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=TtscMetroOptions.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TtscMetroOptions.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,64 @@
1
+ import type { TtscWatchInput, readProjectMembershipPolicy } from "@ttsc/unplugin/api";
2
+ /**
3
+ * One project, and the membership policy that describes it.
4
+ *
5
+ * The recorder's question is whether the project walk already covers an input,
6
+ * so it needs both the walk's roots and the policy that walk used, and it is
7
+ * wrong exactly when those two describe different projects. Passing them
8
+ * separately made that mismatch expressible — the policy for one project
9
+ * alongside the root of another — and passing the policy alone made it
10
+ * expressible in a quieter way still, since a recorder that resolved its own
11
+ * could describe a different program than the walk hashed. Both halves travel
12
+ * together so neither can be supplied without the other (samchon/ttsc#1316).
13
+ *
14
+ * @evidence contracts/common.md#principled-implementation
15
+ * A readonly structural interface carries the selected config, discovery
16
+ * observations, membership policy and walk roots as one view.
17
+ * resolveProjectView supplies that coherent view to the recorder instead of
18
+ * independently resolving its parts.
19
+ *
20
+ * @evidence contracts/common.md#clear-and-simple-design
21
+ * The view groups config, policy, roots and discovery observations so a
22
+ * recorder receives one selected project rather than independently chosen
23
+ * pieces. Readonly members prevent replacement through this interface.
24
+ *
25
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
26
+ * The type does not structurally prohibit an inconsistent manually
27
+ * constructed value; it introduces no executable branches, consumer
28
+ * exceptions or foreign mutation.
29
+ *
30
+ * @evidence contracts/common.md#meaningful-documentation
31
+ * The native JSDoc explains each readonly field, one selected project and
32
+ * the reason policy and roots travel together. Checked against the
33
+ * documentation skill: separate paragraphs state the contract and why its
34
+ * nonobvious boundary matters; field comments retain their own useful
35
+ * facts.
36
+ *
37
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
38
+ * Declares a shape only; it holds no state, handle or buffer.
39
+ *
40
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
41
+ * Declares a shape only; there is no loop or processing in it.
42
+ *
43
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
44
+ * Declares a shape only; it computes nothing to share.
45
+ *
46
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
47
+ * Carries absolute paths chosen by the project resolver; it compares or normalizes none.
48
+ */
49
+ export interface TtscMetroProjectView {
50
+ /** The base directory both fingerprint sides agree on. */
51
+ readonly base: string;
52
+ /** Config candidates observed while selecting this transform's project. */
53
+ readonly discoveryInputs: readonly TtscWatchInput[];
54
+ /** The caller's explicit `project`, if any. */
55
+ readonly explicitProject: string | undefined;
56
+ /** The membership policy resolved for that project. */
57
+ readonly policy: ReturnType<typeof readProjectMembershipPolicy>;
58
+ /** The policy used by the routed static walk. */
59
+ readonly walkPolicy: ReturnType<typeof readProjectMembershipPolicy>;
60
+ /** Lexical roots whose fingerprint uses this project's policy. */
61
+ readonly roots: readonly string[];
62
+ /** The exact config selected for this project. */
63
+ readonly tsconfig: string;
64
+ }
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ //# sourceMappingURL=TtscMetroProjectView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TtscMetroProjectView.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=TtscMetroProjectView.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TtscMetroProjectView.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * The subset of the Metro Babel-transformer contract this adapter relies on.
3
+ *
4
+ * Metro loads the module named by `transformer.babelTransformerPath` and calls
5
+ * its `transform` once per file, expecting a Babel AST back. `getCacheKey` is
6
+ * an optional export Metro folds into its transform-cache key; Metro invokes it
7
+ * with arguments (e.g. `{ projectRoot, enableBabelRCLookup }`), so it is typed
8
+ * variadic.
9
+ *
10
+ * @evidence contracts/common.md#principled-implementation
11
+ * This structural interface describes Metro's Babel-transformer extension:
12
+ * one transform operation and an optional variadic cache key. It does not
13
+ * implement Babel, install peers or alter their exports. Concrete modules
14
+ * supply the callbacks through normal Node loading.
15
+ *
16
+ * @evidence contracts/common.md#clear-and-simple-design
17
+ * This peer-independent interface exposes only the transform and cache-key
18
+ * callbacks the adapter invokes, avoiding a dependency on Metro's full API.
19
+ *
20
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
21
+ * The representation follows the documented consumer contract; its fields do
22
+ * not introduce fixture-selected variants.
23
+ *
24
+ * @evidence contracts/common.md#meaningful-documentation
25
+ * The native JSDoc explains the awaited AST result and optional cache-key
26
+ * callback including forwarded arguments. Checked against the documentation
27
+ * skill: separate paragraphs state the contract and why its nonobvious
28
+ * boundary matters; field comments retain their own useful facts.
29
+ *
30
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
31
+ * Declares a shape only; it holds no state, handle or buffer.
32
+ *
33
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
34
+ * Declares a shape only; there is no loop or processing in it.
35
+ *
36
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
37
+ * Declares a shape only; it computes nothing to share.
38
+ *
39
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
40
+ * Describes the callbacks of a Babel transformer; it names no path or process.
41
+ */
42
+ export interface UpstreamTransformer {
43
+ /**
44
+ * Parse the supplied source and return the Babel AST Metro consumes.
45
+ *
46
+ * The adapter preserves Metro's filename, options and additional parameters;
47
+ * only `src` may hold successfully transformed TypeScript. The returned AST
48
+ * may have its locations remapped by the adapter before Metro receives it.
49
+ *
50
+ * @evidence contracts/common.md#principled-implementation
51
+ * This method signature represents the upstream transformer that Metro
52
+ * selected.
53
+ *
54
+ * @evidence contracts/common.md#clear-and-simple-design
55
+ * One parameter record preserves Metro's extensible delivery shape and
56
+ * the result exposes only the AST this adapter needs.
57
+ *
58
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
59
+ * It accepts the original Metro parameter record, with src replaced only by
60
+ * the owning adapter after a successful compiler pass; the type declares no
61
+ * implementation or test-specific branch.
62
+ *
63
+ * @evidence contracts/common.md#meaningful-documentation
64
+ * The native JSDoc explains source, filename, extra Metro parameters and
65
+ * the awaited Babel AST result. Checked against the documentation skill:
66
+ * separate paragraphs state the contract and why its nonobvious boundary
67
+ * matters; field comments retain their own useful facts.
68
+ *
69
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
70
+ * Declares a shape only; it holds no state, handle or buffer.
71
+ *
72
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
73
+ * Declares a shape only; there is no loop or processing in it.
74
+ *
75
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
76
+ * Declares a shape only; it computes nothing to share.
77
+ *
78
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
79
+ * The filename is Metro's own string, passed through to Babel unchanged.
80
+ */
81
+ transform(params: {
82
+ src: string;
83
+ filename: string;
84
+ options: Record<string, unknown>;
85
+ [key: string]: unknown;
86
+ }): Promise<{
87
+ ast: object;
88
+ }>;
89
+ /**
90
+ * Optional upstream contribution to Metro's static transformer key.
91
+ *
92
+ * Metro's arguments are forwarded unchanged. Absence contributes no upstream
93
+ * key; the adapter treats a throwing key as nonfatal and disables reuse,
94
+ * while transformer loading failures still fail actual transformation.
95
+ *
96
+ * @evidence contracts/common.md#principled-implementation
97
+ * The optional callback follows Metro's upstream transformer contract.
98
+ * Arguments are variadic because Metro supplies its own key options; absence
99
+ * is handled by the adapter.
100
+ *
101
+ * @evidence contracts/common.md#clear-and-simple-design
102
+ * An optional variadic callback expresses the one upstream contribution
103
+ * without adapter-specific copies of Metro's cache-key options.
104
+ *
105
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
106
+ * This signature executes nothing and never replaces a foreign callback.
107
+ *
108
+ * @evidence contracts/common.md#meaningful-documentation
109
+ * The native JSDoc explains optional absence, forwarded Metro arguments and
110
+ * the upstream key contribution. Checked against the documentation skill:
111
+ * separate paragraphs state the contract and why its nonobvious boundary
112
+ * matters; field comments retain their own useful facts.
113
+ *
114
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources
115
+ * Declares a shape only; it holds no state, handle or buffer.
116
+ *
117
+ * @evidenceExclude contracts/performance.md#efficient-algorithms
118
+ * Declares a shape only; there is no loop or processing in it.
119
+ *
120
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work
121
+ * Declares a shape only; it computes nothing to share.
122
+ *
123
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation
124
+ * Metro's arguments are forwarded unchanged; no path is interpreted here.
125
+ */
126
+ getCacheKey?: (...args: unknown[]) => string;
127
+ }
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ //# sourceMappingURL=UpstreamTransformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpstreamTransformer.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=UpstreamTransformer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpstreamTransformer.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}