@ttsc/metro 0.30.4 → 0.31.0
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.
- package/README.md +11 -6
- package/lib/core/SnapshotReadOperations.d.ts +119 -0
- package/lib/core/SnapshotReadOperations.js +3 -0
- package/lib/core/SnapshotReadOperations.js.map +1 -0
- package/lib/core/SnapshotReadOperations.mjs +2 -0
- package/lib/core/SnapshotReadOperations.mjs.map +1 -0
- package/lib/core/TtscMetroOptions.d.ts +119 -0
- package/lib/core/TtscMetroOptions.js +3 -0
- package/lib/core/TtscMetroOptions.js.map +1 -0
- package/lib/core/TtscMetroOptions.mjs +2 -0
- package/lib/core/TtscMetroOptions.mjs.map +1 -0
- package/lib/core/TtscMetroProjectView.d.ts +64 -0
- package/lib/core/TtscMetroProjectView.js +3 -0
- package/lib/core/TtscMetroProjectView.js.map +1 -0
- package/lib/core/TtscMetroProjectView.mjs +2 -0
- package/lib/core/TtscMetroProjectView.mjs.map +1 -0
- package/lib/core/UpstreamTransformer.d.ts +127 -0
- package/lib/core/UpstreamTransformer.js +3 -0
- package/lib/core/UpstreamTransformer.js.map +1 -0
- package/lib/core/UpstreamTransformer.mjs +2 -0
- package/lib/core/UpstreamTransformer.mjs.map +1 -0
- package/lib/core/fingerprint.d.ts +442 -97
- package/lib/core/fingerprint.js +838 -83
- package/lib/core/fingerprint.js.map +1 -1
- package/lib/core/fingerprint.mjs +839 -84
- package/lib/core/fingerprint.mjs.map +1 -1
- package/lib/core/options.d.ts +81 -58
- package/lib/core/options.js +81 -4
- package/lib/core/options.js.map +1 -1
- package/lib/core/options.mjs +81 -4
- package/lib/core/options.mjs.map +1 -1
- package/lib/core/remapAstLocations.d.ts +76 -0
- package/lib/core/remapAstLocations.js +205 -0
- package/lib/core/remapAstLocations.js.map +1 -0
- package/lib/core/remapAstLocations.mjs +203 -0
- package/lib/core/remapAstLocations.mjs.map +1 -0
- package/lib/core/upstream.d.ts +97 -27
- package/lib/core/upstream.js +109 -8
- package/lib/core/upstream.js.map +1 -1
- package/lib/core/upstream.mjs +109 -9
- package/lib/core/upstream.mjs.map +1 -1
- package/lib/index.d.ts +50 -2
- package/lib/index.js +88 -24
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +89 -25
- package/lib/index.mjs.map +1 -1
- package/lib/transformer.d.ts +183 -6
- package/lib/transformer.js +209 -14
- package/lib/transformer.js.map +1 -1
- package/lib/transformer.mjs +211 -16
- package/lib/transformer.mjs.map +1 -1
- package/package.json +7 -18
- package/src/core/SnapshotReadOperations.ts +121 -0
- package/src/core/TtscMetroOptions.ts +127 -0
- package/src/core/TtscMetroProjectView.ts +74 -0
- package/src/core/UpstreamTransformer.ts +126 -0
- package/src/core/fingerprint.ts +987 -109
- package/src/core/options.ts +85 -62
- package/src/core/remapAstLocations.ts +219 -0
- package/src/core/upstream.ts +110 -26
- package/src/index.ts +99 -28
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"SnapshotReadOperations.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"TtscMetroOptions.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"TtscMetroProjectView.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"UpstreamTransformer.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UpstreamTransformer.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|