@ttsc/metro 0.28.5 → 0.28.6
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 +9 -7
- package/lib/core/fingerprint.d.ts +62 -41
- package/lib/core/fingerprint.js +666 -180
- package/lib/core/fingerprint.js.map +1 -1
- package/lib/core/fingerprint.mjs +668 -182
- package/lib/core/fingerprint.mjs.map +1 -1
- package/lib/core/options.d.ts +3 -1
- package/lib/core/options.js +9 -2
- package/lib/core/options.js.map +1 -1
- package/lib/core/options.mjs +9 -2
- package/lib/core/options.mjs.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +2 -2
- package/lib/index.mjs.map +1 -1
- package/lib/transformer.d.ts +11 -12
- package/lib/transformer.js +35 -24
- package/lib/transformer.js.map +1 -1
- package/lib/transformer.mjs +37 -26
- package/lib/transformer.mjs.map +1 -1
- package/package.json +3 -3
- package/src/core/fingerprint.ts +906 -223
- package/src/core/options.ts +18 -4
- package/src/index.ts +5 -4
- package/src/transformer.ts +39 -26
package/src/core/options.ts
CHANGED
|
@@ -53,6 +53,8 @@ export interface ResolvedTtscMetroOptions {
|
|
|
53
53
|
include: string[];
|
|
54
54
|
/** Resolved exclude patterns (never `undefined`). */
|
|
55
55
|
exclude: string[];
|
|
56
|
+
/** Private run identity shared by `getCacheKey` and Metro workers. */
|
|
57
|
+
snapshotRunId?: string;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
/**
|
|
@@ -71,8 +73,14 @@ export const ENV_KEY = "TTSC_METRO_OPTIONS";
|
|
|
71
73
|
* Serialise user options for transport to the worker processes via
|
|
72
74
|
* {@link ENV_KEY}.
|
|
73
75
|
*/
|
|
74
|
-
export function serializeOptions(
|
|
75
|
-
|
|
76
|
+
export function serializeOptions(
|
|
77
|
+
options: TtscMetroOptions,
|
|
78
|
+
snapshotRunId?: string,
|
|
79
|
+
): string {
|
|
80
|
+
return JSON.stringify({
|
|
81
|
+
...(options ?? {}),
|
|
82
|
+
...(snapshotRunId === undefined ? {} : { __snapshotRunId: snapshotRunId }),
|
|
83
|
+
});
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
/**
|
|
@@ -98,10 +106,16 @@ export function resolveOptionsFromEnv(): ResolvedTtscMetroOptions {
|
|
|
98
106
|
: undefined,
|
|
99
107
|
include: toStringArray(parsed.include),
|
|
100
108
|
exclude: toStringArray(parsed.exclude),
|
|
109
|
+
...(typeof parsed.__snapshotRunId === "string" &&
|
|
110
|
+
parsed.__snapshotRunId.length !== 0
|
|
111
|
+
? { snapshotRunId: parsed.__snapshotRunId }
|
|
112
|
+
: {}),
|
|
101
113
|
};
|
|
102
114
|
}
|
|
103
115
|
|
|
104
|
-
function parse(
|
|
116
|
+
function parse(
|
|
117
|
+
raw: string | undefined,
|
|
118
|
+
): TtscMetroOptions & { __snapshotRunId?: unknown } {
|
|
105
119
|
if (raw === undefined || raw.length === 0) {
|
|
106
120
|
return {};
|
|
107
121
|
}
|
|
@@ -111,7 +125,7 @@ function parse(raw: string | undefined): TtscMetroOptions {
|
|
|
111
125
|
// and booleans (all valid JSON) degrade to defaults rather than leaking a
|
|
112
126
|
// wrong-shaped value downstream.
|
|
113
127
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
114
|
-
? (value as TtscMetroOptions)
|
|
128
|
+
? (value as TtscMetroOptions & { __snapshotRunId?: unknown })
|
|
115
129
|
: {};
|
|
116
130
|
} catch {
|
|
117
131
|
return {};
|
package/src/index.ts
CHANGED
|
@@ -79,16 +79,17 @@ export function withTtsc<T extends MetroConfigLike>(
|
|
|
79
79
|
config: T,
|
|
80
80
|
options: TtscMetroOptions = {},
|
|
81
81
|
): T {
|
|
82
|
-
process.env[ENV_KEY] = serializeOptions(
|
|
83
|
-
inheritConfiguredTransformer(config, options),
|
|
84
|
-
);
|
|
85
82
|
// Prepare the reference-graph snapshot backing the transformer's cache-key
|
|
86
83
|
// fingerprint (see `core/fingerprint.ts`). This runs in the single Metro
|
|
87
84
|
// config process before any worker exists, so it is the race-free moment to
|
|
88
85
|
// mint the snapshot epoch and compact the previous run's worker files.
|
|
89
|
-
prepareSnapshot(
|
|
86
|
+
const snapshotRunId = prepareSnapshot(
|
|
90
87
|
typeof config.projectRoot === "string" ? config.projectRoot : undefined,
|
|
91
88
|
);
|
|
89
|
+
process.env[ENV_KEY] = serializeOptions(
|
|
90
|
+
inheritConfiguredTransformer(config, options),
|
|
91
|
+
snapshotRunId,
|
|
92
|
+
);
|
|
92
93
|
return {
|
|
93
94
|
...config,
|
|
94
95
|
transformer: {
|
package/src/transformer.ts
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import {
|
|
19
19
|
createTtscTransformCache,
|
|
20
|
+
isTransformTarget,
|
|
20
21
|
resolveOptions,
|
|
21
22
|
transformTtsc,
|
|
22
23
|
} from "@ttsc/unplugin/api";
|
|
@@ -36,14 +37,6 @@ import { resolveUpstreamTransformer } from "./core/upstream";
|
|
|
36
37
|
|
|
37
38
|
const nodeRequire = createRequire(import.meta.url);
|
|
38
39
|
|
|
39
|
-
/**
|
|
40
|
-
* Matches the TypeScript source extensions the ttsc pass handles (`.ts`,
|
|
41
|
-
* `.tsx`, `.cts`, `.mts`). JavaScript and declaration files are passed straight
|
|
42
|
-
* through to the upstream transformer.
|
|
43
|
-
*/
|
|
44
|
-
const TS_EXTENSION = /\.[cm]?tsx?$/;
|
|
45
|
-
const DECLARATION = /\.d\.[cm]?ts$/;
|
|
46
|
-
|
|
47
40
|
/**
|
|
48
41
|
* Per-worker singletons. Metro loads this module once per worker process and
|
|
49
42
|
* reuses it across every file that worker handles, so the resolved options, the
|
|
@@ -53,13 +46,19 @@ const DECLARATION = /\.d\.[cm]?ts$/;
|
|
|
53
46
|
let resolved: ResolvedTtscMetroOptions | undefined;
|
|
54
47
|
let unpluginOptions: ReturnType<typeof resolveOptions> | undefined;
|
|
55
48
|
const cache = createTtscTransformCache();
|
|
56
|
-
|
|
49
|
+
let snapshotRecorder: ReturnType<typeof createSnapshotRecorder> | undefined;
|
|
57
50
|
|
|
58
51
|
/** Lazily resolve the worker-side options (from {@link resolveOptionsFromEnv}). */
|
|
59
52
|
function options(): ResolvedTtscMetroOptions {
|
|
60
53
|
return (resolved ??= resolveOptionsFromEnv());
|
|
61
54
|
}
|
|
62
55
|
|
|
56
|
+
/** The recorder bound to the private run identity inherited by this worker. */
|
|
57
|
+
function recorder(): ReturnType<typeof createSnapshotRecorder> {
|
|
58
|
+
const opts = options();
|
|
59
|
+
return (snapshotRecorder ??= createSnapshotRecorder(opts.snapshotRunId));
|
|
60
|
+
}
|
|
61
|
+
|
|
63
62
|
/**
|
|
64
63
|
* Resolve Metro's per-file `filename` to an absolute path.
|
|
65
64
|
*
|
|
@@ -121,15 +120,25 @@ export async function transform(params: {
|
|
|
121
120
|
: undefined;
|
|
122
121
|
const explicitProject =
|
|
123
122
|
typeof opts.ttsc.project === "string" ? opts.ttsc.project : undefined;
|
|
123
|
+
const filename = resolveAbsoluteFilename(params.filename, params.options);
|
|
124
124
|
const project = resolveProjectView({
|
|
125
125
|
compilerOptions: opts.ttsc.compilerOptions,
|
|
126
126
|
explicitProject,
|
|
127
|
+
filename,
|
|
127
128
|
projectRoot,
|
|
128
129
|
});
|
|
130
|
+
// Freeze the implicit selection made above into this call. Re-running
|
|
131
|
+
// discovery inside the transform after a config candidate changes would
|
|
132
|
+
// attach one project's recorder evidence to another project's compiler
|
|
133
|
+
// output.
|
|
134
|
+
const transformOptions = {
|
|
135
|
+
...unpluginOptions,
|
|
136
|
+
project: project.tsconfig,
|
|
137
|
+
};
|
|
129
138
|
const result = await transformTtsc(
|
|
130
|
-
|
|
139
|
+
filename,
|
|
131
140
|
params.src,
|
|
132
|
-
|
|
141
|
+
transformOptions,
|
|
133
142
|
undefined,
|
|
134
143
|
cache,
|
|
135
144
|
{
|
|
@@ -144,11 +153,15 @@ export async function transform(params: {
|
|
|
144
153
|
// memo means stat-ing the whole `extends` chain, which is an answer
|
|
145
154
|
// that cannot change between two inputs of one file
|
|
146
155
|
// (samchon/ttsc#1316).
|
|
147
|
-
|
|
156
|
+
addWatchFiles: (inputs) =>
|
|
157
|
+
recorder().recordMany({
|
|
158
|
+
inputs: [...project.discoveryInputs, ...inputs],
|
|
159
|
+
project,
|
|
160
|
+
}),
|
|
148
161
|
// A volatile declaration means the output depends on non-file inputs
|
|
149
162
|
// that no file fingerprint can represent; the snapshot marks it and
|
|
150
163
|
// getCacheKey degrades to a per-run nonce (no cross-run reuse).
|
|
151
|
-
markVolatile: () =>
|
|
164
|
+
markVolatile: () => recorder().recordVolatile({ project }),
|
|
152
165
|
},
|
|
153
166
|
);
|
|
154
167
|
// A file the program does not contain comes back as `undefined` from the
|
|
@@ -179,16 +192,15 @@ export async function transform(params: {
|
|
|
179
192
|
* transformer's own key (forwarded Metro's args, e.g. `projectRoot`, so a
|
|
180
193
|
* `babel.config.js` change still busts the cache);
|
|
181
194
|
* - The project fingerprint (see `core/fingerprint.ts`): every input file under
|
|
182
|
-
* the project
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* ancestry).
|
|
195
|
+
* the routed project walks, every effective config source, the previous
|
|
196
|
+
* transforms' derived inputs, and the epoch that isolates a worker state
|
|
197
|
+
* differing from this run's exact main-process baseline.
|
|
186
198
|
*
|
|
187
|
-
* A change to any fingerprinted input re-keys every transformed file
|
|
188
|
-
* project-level granularity, forced by Metro's single static key
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
199
|
+
* A change to any fingerprinted input re-keys every transformed file at
|
|
200
|
+
* project-level granularity, forced by Metro's single static key, replacing the
|
|
201
|
+
* former manual `--reset-cache` step. Resolving the upstream is deliberately
|
|
202
|
+
* non-fatal here: a missing peer must not crash cache-key computation. See the
|
|
203
|
+
* README "Caveats" and samchon/ttsc#721.
|
|
192
204
|
*/
|
|
193
205
|
export function getCacheKey(...args: unknown[]): string {
|
|
194
206
|
const opts = options();
|
|
@@ -215,6 +227,7 @@ export function getCacheKey(...args: unknown[]): string {
|
|
|
215
227
|
explicitProject:
|
|
216
228
|
typeof opts.ttsc.project === "string" ? opts.ttsc.project : undefined,
|
|
217
229
|
projectRoot: cacheKeyProjectRoot(args),
|
|
230
|
+
runId: opts.snapshotRunId,
|
|
218
231
|
}),
|
|
219
232
|
);
|
|
220
233
|
return hash.digest("hex");
|
|
@@ -267,15 +280,15 @@ function upstreamCacheKey(
|
|
|
267
280
|
|
|
268
281
|
/**
|
|
269
282
|
* Decide whether a file should run through the ttsc pass. Only TypeScript
|
|
270
|
-
* sources (`.ts`/`.tsx`/`.cts
|
|
271
|
-
* substrings win over `include`, and an empty `include`
|
|
272
|
-
* Exported for unit testing.
|
|
283
|
+
* sources (`.ts`/`.tsx`/`.mts`/`.cts`, excluding every declaration form)
|
|
284
|
+
* qualify; `exclude` substrings win over `include`, and an empty `include`
|
|
285
|
+
* means "all TypeScript". Exported for unit testing.
|
|
273
286
|
*/
|
|
274
287
|
export function shouldTransform(
|
|
275
288
|
filename: string,
|
|
276
289
|
opts: ResolvedTtscMetroOptions,
|
|
277
290
|
): boolean {
|
|
278
|
-
if (!
|
|
291
|
+
if (!isTransformTarget(filename)) {
|
|
279
292
|
return false;
|
|
280
293
|
}
|
|
281
294
|
if (opts.exclude.some((pattern) => filename.includes(pattern))) {
|