@ttsc/metro 0.16.3

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/lib/index.mjs ADDED
@@ -0,0 +1,70 @@
1
+ import { join, dirname } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { ENV_KEY, serializeOptions } from './core/options.mjs';
4
+
5
+ /**
6
+ * `@ttsc/metro` — Metro (React Native / Expo) adapter for ttsc plugins.
7
+ *
8
+ * Metro bundles with Babel, which strips TypeScript types and never runs ttsc
9
+ * plugins, so neither the `ttsc` CLI nor `@ttsc/unplugin` can reach an RN/Expo
10
+ * build. {@link withTtsc} wires a Metro custom transformer that runs the ttsc
11
+ * plugin pass on each TypeScript file before handing the result to the
12
+ * project's existing Expo/React-Native Babel transformer.
13
+ *
14
+ * @example
15
+ * Expo```js
16
+ * // metro.config.js
17
+ * const { getDefaultConfig } = require("expo/metro-config");
18
+ * const { withTtsc } = require("@ttsc/metro");
19
+ *
20
+ * module.exports = withTtsc(getDefaultConfig(__dirname));
21
+ * ```;
22
+ *
23
+ * @example
24
+ * Bare React Native
25
+ * ```js
26
+ * // metro.config.js
27
+ * const { getDefaultConfig } = require("@react-native/metro-config");
28
+ * const { withTtsc } = require("@ttsc/metro");
29
+ *
30
+ * module.exports = withTtsc(getDefaultConfig(__dirname));
31
+ * ```
32
+ */
33
+ /**
34
+ * Wrap a Metro config so ttsc plugins run on every TypeScript file.
35
+ *
36
+ * Sets `transformer.babelTransformerPath` to this package's transformer and
37
+ * publishes the resolved options to Metro's worker processes via the
38
+ * {@link ENV_KEY} environment variable (the workers never see this call, so env
39
+ * is the transport — see `core/options.ts`). Compatible with Expo's
40
+ * `getDefaultConfig()` and bare React Native alike.
41
+ *
42
+ * With no `options`, the transformer auto-discovers `tsconfig.json` and runs
43
+ * the plugins configured there — the standard ttsc model. Pass `options` only
44
+ * to override the project path, plugin list, or include/exclude filters.
45
+ */
46
+ function withTtsc(config, options = {}) {
47
+ process.env[ENV_KEY] = serializeOptions(options);
48
+ return {
49
+ ...config,
50
+ transformer: {
51
+ ...config.transformer,
52
+ babelTransformerPath: transformerModulePath(),
53
+ },
54
+ };
55
+ }
56
+ /**
57
+ * Absolute path to the built transformer module Metro will `require`.
58
+ *
59
+ * Always the CommonJS build (`transformer.js`) next to this module: Metro
60
+ * resolves `babelTransformerPath` with `require`, and `metro.config.js` is a
61
+ * CommonJS module. Rollup rewrites `import.meta.url` for both the CJS and ESM
62
+ * builds, so this resolves correctly regardless of how the config loaded this
63
+ * entry.
64
+ */
65
+ function transformerModulePath() {
66
+ return join(dirname(fileURLToPath(import.meta.url)), "transformer.js");
67
+ }
68
+
69
+ export { withTtsc };
70
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BG;AAyBH;;;;;;;;;;;;AAYG;SACa,QAAQ,CACtB,MAAS,EACT,UAA4B,EAAE,EAAA;IAE9B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,gBAAgB,CAAC,OAAO,CAAC;IAChD,OAAO;AACL,QAAA,GAAG,MAAM;AACT,QAAA,WAAW,EAAE;YACX,GAAG,MAAM,CAAC,WAAW;YACrB,oBAAoB,EAAE,qBAAqB,EAAE;AAC9C,SAAA;KACG;AACR;AAEA;;;;;;;;AAQG;AACH,SAAS,qBAAqB,GAAA;AAC5B,IAAA,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC;AACxE;;;;"}
@@ -0,0 +1,52 @@
1
+ import type { ResolvedTtscMetroOptions } from "./core/options";
2
+ /**
3
+ * Resolve Metro's per-file `filename` to an absolute path.
4
+ *
5
+ * Metro hands the babel transformer a path **relative to `projectRoot`** (it
6
+ * reads the file via `fs.readFileSync(path.resolve(projectRoot, filename))`)
7
+ * and passes `projectRoot` inside `options`. The ttsc pass needs an absolute
8
+ * path that matches a key in the compiled program, so resolve against
9
+ * `projectRoot` — never `process.cwd()`, which differs from `projectRoot` in
10
+ * monorepos and when Metro is launched from a parent directory. Getting this
11
+ * wrong makes every file look "outside the project" and silently skips the
12
+ * plugin pass.
13
+ */
14
+ export declare function resolveAbsoluteFilename(filename: string, options?: Record<string, unknown>): string;
15
+ /**
16
+ * Metro transform entry point.
17
+ *
18
+ * Runs the ttsc plugin pass on TypeScript files, then delegates to the upstream
19
+ * Expo/React-Native Babel transformer to produce the AST Metro expects. The
20
+ * upstream call receives Metro's original params (notably the project-relative
21
+ * `filename`, which Babel expects); only `src` is replaced with the
22
+ * ttsc-transformed source.
23
+ */
24
+ export declare function transform(params: {
25
+ src: string;
26
+ filename: string;
27
+ options: Record<string, unknown>;
28
+ [key: string]: unknown;
29
+ }): Promise<{
30
+ ast: object;
31
+ }>;
32
+ /**
33
+ * Metro transform-cache key.
34
+ *
35
+ * Metro already content-hashes each file, so this only has to invalidate when
36
+ * the transformer itself changes: package version + resolved options + the
37
+ * upstream transformer's own key (forwarded Metro's args, e.g. `projectRoot`,
38
+ * so a `babel.config.js` change still busts the cache). Resolving the upstream
39
+ * is deliberately non-fatal here — a missing peer must not crash cache-key
40
+ * computation. NOTE: this does not encode the tsconfig / plugin configuration
41
+ * or cross-file type dependencies, so after editing those (or a depended-upon
42
+ * type) run Metro with `--reset-cache`. See the README "Caveats" and
43
+ * samchon/ttsc#255.
44
+ */
45
+ export declare function getCacheKey(...args: unknown[]): string;
46
+ /**
47
+ * Decide whether a file should run through the ttsc pass. Only TypeScript
48
+ * sources (`.ts`/`.tsx`/`.cts`/`.mts`, excluding `.d.ts`) qualify; `exclude`
49
+ * substrings win over `include`, and an empty `include` means "all TypeScript".
50
+ * Exported for unit testing.
51
+ */
52
+ export declare function shouldTransform(filename: string, opts: ResolvedTtscMetroOptions): boolean;
@@ -0,0 +1,217 @@
1
+ 'use strict';
2
+
3
+ var api = require('@ttsc/unplugin/api');
4
+ var node_crypto = require('node:crypto');
5
+ var node_module = require('node:module');
6
+ var path = require('node:path');
7
+ var options$1 = require('./core/options.js');
8
+ var upstream = require('./core/upstream.js');
9
+
10
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
11
+ /**
12
+ * Metro custom transformer for ttsc.
13
+ *
14
+ * Metro loads this module via `transformer.babelTransformerPath` (wired by
15
+ * {@link withTtsc}) and calls {@link transform} once per file. The flow is:
16
+ *
17
+ * TypeScript source -> ttsc plugin pass (typia, nestia, …) via @ttsc/unplugin's
18
+ * core -> transformed TypeScript source -> upstream Expo/RN Babel transformer
19
+ * (strips types, RN transforms) -> Babel AST (what Metro consumes)
20
+ *
21
+ * The ttsc pass reuses `@ttsc/unplugin`'s `transformTtsc`, so the plugin
22
+ * contract, tsconfig discovery, and per-build cache are identical to every
23
+ * other bundler integration. See the package README for the v1 cost model and
24
+ * the cross-file cache-invalidation caveat.
25
+ */
26
+ const nodeRequire = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('transformer.js', document.baseURI).href)));
27
+ /**
28
+ * Matches the TypeScript source extensions the ttsc pass handles (`.ts`,
29
+ * `.tsx`, `.cts`, `.mts`). JavaScript and declaration files are passed straight
30
+ * through to the upstream transformer.
31
+ */
32
+ const TS_EXTENSION = /\.[cm]?tsx?$/;
33
+ const DECLARATION = /\.d\.[cm]?ts$/;
34
+ /**
35
+ * Per-worker singletons. Metro loads this module once per worker process and
36
+ * reuses it across every file that worker handles, so the resolved options, the
37
+ * transform cache, and the memoised `@ttsc/unplugin` options are all scoped to
38
+ * the worker.
39
+ */
40
+ let resolved;
41
+ let unpluginOptions;
42
+ const cache = api.createTtscTransformCache();
43
+ /** Lazily resolve the worker-side options (from {@link resolveOptionsFromEnv}). */
44
+ function options() {
45
+ return (resolved ??= options$1.resolveOptionsFromEnv());
46
+ }
47
+ /**
48
+ * Resolve Metro's per-file `filename` to an absolute path.
49
+ *
50
+ * Metro hands the babel transformer a path **relative to `projectRoot`** (it
51
+ * reads the file via `fs.readFileSync(path.resolve(projectRoot, filename))`)
52
+ * and passes `projectRoot` inside `options`. The ttsc pass needs an absolute
53
+ * path that matches a key in the compiled program, so resolve against
54
+ * `projectRoot` — never `process.cwd()`, which differs from `projectRoot` in
55
+ * monorepos and when Metro is launched from a parent directory. Getting this
56
+ * wrong makes every file look "outside the project" and silently skips the
57
+ * plugin pass.
58
+ */
59
+ function resolveAbsoluteFilename(filename, options) {
60
+ if (path.isAbsolute(filename)) {
61
+ return filename;
62
+ }
63
+ const projectRoot = options !== undefined && typeof options.projectRoot === "string"
64
+ ? options.projectRoot
65
+ : process.cwd();
66
+ return path.resolve(projectRoot, filename);
67
+ }
68
+ /**
69
+ * Metro transform entry point.
70
+ *
71
+ * Runs the ttsc plugin pass on TypeScript files, then delegates to the upstream
72
+ * Expo/React-Native Babel transformer to produce the AST Metro expects. The
73
+ * upstream call receives Metro's original params (notably the project-relative
74
+ * `filename`, which Babel expects); only `src` is replaced with the
75
+ * ttsc-transformed source.
76
+ */
77
+ async function transform(params) {
78
+ const opts = options();
79
+ const upstream$1 = upstream.resolveUpstreamTransformer(opts.upstreamTransformer);
80
+ // Gate on the project-relative path Metro supplies, so include/exclude
81
+ // substrings match what the user writes (e.g. "src/generated") and never
82
+ // collide with an absolute ancestor directory name. The absolute path is used
83
+ // only to address the file inside the compiled program.
84
+ if (!shouldTransform(params.filename, opts)) {
85
+ return upstream$1.transform(params);
86
+ }
87
+ let transformedSrc = params.src;
88
+ try {
89
+ unpluginOptions ??= api.resolveOptions(opts.ttsc);
90
+ const result = await api.transformTtsc(resolveAbsoluteFilename(params.filename, params.options), params.src, unpluginOptions, undefined, cache);
91
+ if (result !== undefined && typeof result.code === "string") {
92
+ transformedSrc = result.code;
93
+ }
94
+ }
95
+ catch (error) {
96
+ // A file that is not part of the tsconfig program is not a build error —
97
+ // pass it through untransformed. Genuine compile/type failures propagate so
98
+ // Metro surfaces them, matching the other ttsc bundler integrations.
99
+ if (!isFileOutsideProject(error)) {
100
+ throw error;
101
+ }
102
+ }
103
+ return upstream$1.transform({ ...params, src: transformedSrc });
104
+ }
105
+ /**
106
+ * Metro transform-cache key.
107
+ *
108
+ * Metro already content-hashes each file, so this only has to invalidate when
109
+ * the transformer itself changes: package version + resolved options + the
110
+ * upstream transformer's own key (forwarded Metro's args, e.g. `projectRoot`,
111
+ * so a `babel.config.js` change still busts the cache). Resolving the upstream
112
+ * is deliberately non-fatal here — a missing peer must not crash cache-key
113
+ * computation. NOTE: this does not encode the tsconfig / plugin configuration
114
+ * or cross-file type dependencies, so after editing those (or a depended-upon
115
+ * type) run Metro with `--reset-cache`. See the README "Caveats" and
116
+ * samchon/ttsc#255.
117
+ */
118
+ function getCacheKey(...args) {
119
+ const opts = options();
120
+ const hash = node_crypto.createHash("sha256");
121
+ hash.update(`@ttsc/metro:${packageVersion()}`);
122
+ hash.update(stableStringify({
123
+ ttsc: opts.ttsc,
124
+ include: opts.include,
125
+ exclude: opts.exclude,
126
+ upstreamTransformer: opts.upstreamTransformer ?? null,
127
+ }));
128
+ const upstreamKey = upstreamCacheKey(opts.upstreamTransformer, args);
129
+ if (upstreamKey.length !== 0) {
130
+ hash.update(upstreamKey);
131
+ }
132
+ return hash.digest("hex");
133
+ }
134
+ /**
135
+ * Fold the upstream transformer's cache key in, defensively. Forwards Metro's
136
+ * own `getCacheKey` arguments so the upstream's babelrc-derived key is
137
+ * preserved, and never throws: a missing peer or a throwing upstream
138
+ * `getCacheKey` yields an empty contribution rather than failing the whole
139
+ * build's cache keying.
140
+ */
141
+ function upstreamCacheKey(upstreamTransformer, args) {
142
+ let upstream$1;
143
+ try {
144
+ upstream$1 = upstream.resolveUpstreamTransformer(upstreamTransformer);
145
+ }
146
+ catch {
147
+ return "";
148
+ }
149
+ if (upstream$1.getCacheKey === undefined) {
150
+ return "";
151
+ }
152
+ try {
153
+ return String(upstream$1.getCacheKey(...args) ?? "");
154
+ }
155
+ catch {
156
+ return "";
157
+ }
158
+ }
159
+ /**
160
+ * Decide whether a file should run through the ttsc pass. Only TypeScript
161
+ * sources (`.ts`/`.tsx`/`.cts`/`.mts`, excluding `.d.ts`) qualify; `exclude`
162
+ * substrings win over `include`, and an empty `include` means "all TypeScript".
163
+ * Exported for unit testing.
164
+ */
165
+ function shouldTransform(filename, opts) {
166
+ if (!TS_EXTENSION.test(filename) || DECLARATION.test(filename)) {
167
+ return false;
168
+ }
169
+ if (opts.exclude.some((pattern) => filename.includes(pattern))) {
170
+ return false;
171
+ }
172
+ if (opts.include.length !== 0 &&
173
+ !opts.include.some((pattern) => filename.includes(pattern))) {
174
+ return false;
175
+ }
176
+ return true;
177
+ }
178
+ /**
179
+ * `transformTtsc` throws `"ttsc transform did not return output for <file>"`
180
+ * when the requested file is not part of the compiled program (e.g. excluded
181
+ * from the tsconfig). That case is non-fatal — the file should pass through.
182
+ */
183
+ function isFileOutsideProject(error) {
184
+ const message = error instanceof Error ? error.message : String(error);
185
+ return message.includes("did not return output");
186
+ }
187
+ function packageVersion() {
188
+ try {
189
+ const pkg = nodeRequire("@ttsc/metro/package.json");
190
+ return pkg.version ?? "0";
191
+ }
192
+ catch {
193
+ return "0";
194
+ }
195
+ }
196
+ /**
197
+ * JSON-serialise with object keys sorted recursively, so two semantically equal
198
+ * option sets always hash to the same cache key regardless of property order.
199
+ */
200
+ function stableStringify(value) {
201
+ if (Array.isArray(value)) {
202
+ return `[${value.map(stableStringify).join(",")}]`;
203
+ }
204
+ if (value !== null && typeof value === "object") {
205
+ return `{${Object.entries(value)
206
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
207
+ .map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`)
208
+ .join(",")}}`;
209
+ }
210
+ return JSON.stringify(value);
211
+ }
212
+
213
+ exports.getCacheKey = getCacheKey;
214
+ exports.resolveAbsoluteFilename = resolveAbsoluteFilename;
215
+ exports.shouldTransform = shouldTransform;
216
+ exports.transform = transform;
217
+ //# sourceMappingURL=transformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer.js","sources":["../src/transformer.ts"],"sourcesContent":[null],"names":["createRequire","createTtscTransformCache","resolveOptionsFromEnv","upstream","resolveUpstreamTransformer","resolveOptions","transformTtsc","createHash"],"mappings":"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"}
@@ -0,0 +1,211 @@
1
+ import { createTtscTransformCache, resolveOptions, transformTtsc } from '@ttsc/unplugin/api';
2
+ import { createHash } from 'node:crypto';
3
+ import { createRequire } from 'node:module';
4
+ import path from 'node:path';
5
+ import { resolveOptionsFromEnv } from './core/options.mjs';
6
+ import { resolveUpstreamTransformer } from './core/upstream.mjs';
7
+
8
+ /**
9
+ * Metro custom transformer for ttsc.
10
+ *
11
+ * Metro loads this module via `transformer.babelTransformerPath` (wired by
12
+ * {@link withTtsc}) and calls {@link transform} once per file. The flow is:
13
+ *
14
+ * TypeScript source -> ttsc plugin pass (typia, nestia, …) via @ttsc/unplugin's
15
+ * core -> transformed TypeScript source -> upstream Expo/RN Babel transformer
16
+ * (strips types, RN transforms) -> Babel AST (what Metro consumes)
17
+ *
18
+ * The ttsc pass reuses `@ttsc/unplugin`'s `transformTtsc`, so the plugin
19
+ * contract, tsconfig discovery, and per-build cache are identical to every
20
+ * other bundler integration. See the package README for the v1 cost model and
21
+ * the cross-file cache-invalidation caveat.
22
+ */
23
+ const nodeRequire = createRequire(import.meta.url);
24
+ /**
25
+ * Matches the TypeScript source extensions the ttsc pass handles (`.ts`,
26
+ * `.tsx`, `.cts`, `.mts`). JavaScript and declaration files are passed straight
27
+ * through to the upstream transformer.
28
+ */
29
+ const TS_EXTENSION = /\.[cm]?tsx?$/;
30
+ const DECLARATION = /\.d\.[cm]?ts$/;
31
+ /**
32
+ * Per-worker singletons. Metro loads this module once per worker process and
33
+ * reuses it across every file that worker handles, so the resolved options, the
34
+ * transform cache, and the memoised `@ttsc/unplugin` options are all scoped to
35
+ * the worker.
36
+ */
37
+ let resolved;
38
+ let unpluginOptions;
39
+ const cache = createTtscTransformCache();
40
+ /** Lazily resolve the worker-side options (from {@link resolveOptionsFromEnv}). */
41
+ function options() {
42
+ return (resolved ??= resolveOptionsFromEnv());
43
+ }
44
+ /**
45
+ * Resolve Metro's per-file `filename` to an absolute path.
46
+ *
47
+ * Metro hands the babel transformer a path **relative to `projectRoot`** (it
48
+ * reads the file via `fs.readFileSync(path.resolve(projectRoot, filename))`)
49
+ * and passes `projectRoot` inside `options`. The ttsc pass needs an absolute
50
+ * path that matches a key in the compiled program, so resolve against
51
+ * `projectRoot` — never `process.cwd()`, which differs from `projectRoot` in
52
+ * monorepos and when Metro is launched from a parent directory. Getting this
53
+ * wrong makes every file look "outside the project" and silently skips the
54
+ * plugin pass.
55
+ */
56
+ function resolveAbsoluteFilename(filename, options) {
57
+ if (path.isAbsolute(filename)) {
58
+ return filename;
59
+ }
60
+ const projectRoot = options !== undefined && typeof options.projectRoot === "string"
61
+ ? options.projectRoot
62
+ : process.cwd();
63
+ return path.resolve(projectRoot, filename);
64
+ }
65
+ /**
66
+ * Metro transform entry point.
67
+ *
68
+ * Runs the ttsc plugin pass on TypeScript files, then delegates to the upstream
69
+ * Expo/React-Native Babel transformer to produce the AST Metro expects. The
70
+ * upstream call receives Metro's original params (notably the project-relative
71
+ * `filename`, which Babel expects); only `src` is replaced with the
72
+ * ttsc-transformed source.
73
+ */
74
+ async function transform(params) {
75
+ const opts = options();
76
+ const upstream = resolveUpstreamTransformer(opts.upstreamTransformer);
77
+ // Gate on the project-relative path Metro supplies, so include/exclude
78
+ // substrings match what the user writes (e.g. "src/generated") and never
79
+ // collide with an absolute ancestor directory name. The absolute path is used
80
+ // only to address the file inside the compiled program.
81
+ if (!shouldTransform(params.filename, opts)) {
82
+ return upstream.transform(params);
83
+ }
84
+ let transformedSrc = params.src;
85
+ try {
86
+ unpluginOptions ??= resolveOptions(opts.ttsc);
87
+ const result = await transformTtsc(resolveAbsoluteFilename(params.filename, params.options), params.src, unpluginOptions, undefined, cache);
88
+ if (result !== undefined && typeof result.code === "string") {
89
+ transformedSrc = result.code;
90
+ }
91
+ }
92
+ catch (error) {
93
+ // A file that is not part of the tsconfig program is not a build error —
94
+ // pass it through untransformed. Genuine compile/type failures propagate so
95
+ // Metro surfaces them, matching the other ttsc bundler integrations.
96
+ if (!isFileOutsideProject(error)) {
97
+ throw error;
98
+ }
99
+ }
100
+ return upstream.transform({ ...params, src: transformedSrc });
101
+ }
102
+ /**
103
+ * Metro transform-cache key.
104
+ *
105
+ * Metro already content-hashes each file, so this only has to invalidate when
106
+ * the transformer itself changes: package version + resolved options + the
107
+ * upstream transformer's own key (forwarded Metro's args, e.g. `projectRoot`,
108
+ * so a `babel.config.js` change still busts the cache). Resolving the upstream
109
+ * is deliberately non-fatal here — a missing peer must not crash cache-key
110
+ * computation. NOTE: this does not encode the tsconfig / plugin configuration
111
+ * or cross-file type dependencies, so after editing those (or a depended-upon
112
+ * type) run Metro with `--reset-cache`. See the README "Caveats" and
113
+ * samchon/ttsc#255.
114
+ */
115
+ function getCacheKey(...args) {
116
+ const opts = options();
117
+ const hash = createHash("sha256");
118
+ hash.update(`@ttsc/metro:${packageVersion()}`);
119
+ hash.update(stableStringify({
120
+ ttsc: opts.ttsc,
121
+ include: opts.include,
122
+ exclude: opts.exclude,
123
+ upstreamTransformer: opts.upstreamTransformer ?? null,
124
+ }));
125
+ const upstreamKey = upstreamCacheKey(opts.upstreamTransformer, args);
126
+ if (upstreamKey.length !== 0) {
127
+ hash.update(upstreamKey);
128
+ }
129
+ return hash.digest("hex");
130
+ }
131
+ /**
132
+ * Fold the upstream transformer's cache key in, defensively. Forwards Metro's
133
+ * own `getCacheKey` arguments so the upstream's babelrc-derived key is
134
+ * preserved, and never throws: a missing peer or a throwing upstream
135
+ * `getCacheKey` yields an empty contribution rather than failing the whole
136
+ * build's cache keying.
137
+ */
138
+ function upstreamCacheKey(upstreamTransformer, args) {
139
+ let upstream;
140
+ try {
141
+ upstream = resolveUpstreamTransformer(upstreamTransformer);
142
+ }
143
+ catch {
144
+ return "";
145
+ }
146
+ if (upstream.getCacheKey === undefined) {
147
+ return "";
148
+ }
149
+ try {
150
+ return String(upstream.getCacheKey(...args) ?? "");
151
+ }
152
+ catch {
153
+ return "";
154
+ }
155
+ }
156
+ /**
157
+ * Decide whether a file should run through the ttsc pass. Only TypeScript
158
+ * sources (`.ts`/`.tsx`/`.cts`/`.mts`, excluding `.d.ts`) qualify; `exclude`
159
+ * substrings win over `include`, and an empty `include` means "all TypeScript".
160
+ * Exported for unit testing.
161
+ */
162
+ function shouldTransform(filename, opts) {
163
+ if (!TS_EXTENSION.test(filename) || DECLARATION.test(filename)) {
164
+ return false;
165
+ }
166
+ if (opts.exclude.some((pattern) => filename.includes(pattern))) {
167
+ return false;
168
+ }
169
+ if (opts.include.length !== 0 &&
170
+ !opts.include.some((pattern) => filename.includes(pattern))) {
171
+ return false;
172
+ }
173
+ return true;
174
+ }
175
+ /**
176
+ * `transformTtsc` throws `"ttsc transform did not return output for <file>"`
177
+ * when the requested file is not part of the compiled program (e.g. excluded
178
+ * from the tsconfig). That case is non-fatal — the file should pass through.
179
+ */
180
+ function isFileOutsideProject(error) {
181
+ const message = error instanceof Error ? error.message : String(error);
182
+ return message.includes("did not return output");
183
+ }
184
+ function packageVersion() {
185
+ try {
186
+ const pkg = nodeRequire("@ttsc/metro/package.json");
187
+ return pkg.version ?? "0";
188
+ }
189
+ catch {
190
+ return "0";
191
+ }
192
+ }
193
+ /**
194
+ * JSON-serialise with object keys sorted recursively, so two semantically equal
195
+ * option sets always hash to the same cache key regardless of property order.
196
+ */
197
+ function stableStringify(value) {
198
+ if (Array.isArray(value)) {
199
+ return `[${value.map(stableStringify).join(",")}]`;
200
+ }
201
+ if (value !== null && typeof value === "object") {
202
+ return `{${Object.entries(value)
203
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
204
+ .map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`)
205
+ .join(",")}}`;
206
+ }
207
+ return JSON.stringify(value);
208
+ }
209
+
210
+ export { getCacheKey, resolveAbsoluteFilename, shouldTransform, transform };
211
+ //# sourceMappingURL=transformer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer.mjs","sources":["../src/transformer.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@ttsc/metro",
3
+ "version": "0.16.3",
4
+ "description": "Metro (React Native / Expo) adapter for ttsc plugins.",
5
+ "main": "lib/index.js",
6
+ "module": "lib/index.mjs",
7
+ "types": "lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "import": "./lib/index.mjs",
12
+ "default": "./lib/index.js"
13
+ },
14
+ "./transformer": {
15
+ "types": "./lib/transformer.d.ts",
16
+ "import": "./lib/transformer.mjs",
17
+ "default": "./lib/transformer.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "keywords": [
25
+ "ttsc",
26
+ "metro",
27
+ "react-native",
28
+ "expo",
29
+ "typescript",
30
+ "tsgo"
31
+ ],
32
+ "files": [
33
+ "README.md",
34
+ "lib",
35
+ "src"
36
+ ],
37
+ "dependencies": {
38
+ "@ttsc/unplugin": "0.16.3"
39
+ },
40
+ "peerDependencies": {
41
+ "@expo/metro-config": "*",
42
+ "@react-native/metro-babel-transformer": "*",
43
+ "metro-react-native-babel-transformer": "*"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "@expo/metro-config": {
47
+ "optional": true
48
+ },
49
+ "@react-native/metro-babel-transformer": {
50
+ "optional": true
51
+ },
52
+ "metro-react-native-babel-transformer": {
53
+ "optional": true
54
+ }
55
+ },
56
+ "devDependencies": {
57
+ "@rollup/plugin-commonjs": "^29.0.2",
58
+ "@rollup/plugin-node-resolve": "^16.0.3",
59
+ "@types/node": "^25.3.0",
60
+ "rimraf": "^6.1.2",
61
+ "rollup": "^4.60.3",
62
+ "rollup-plugin-auto-external": "^2.0.0",
63
+ "rollup-plugin-node-externals": "^9.0.1",
64
+ "tinyglobby": "^0.2.16",
65
+ "tslib": "^2.8.1",
66
+ "typescript": "7.0.1-rc",
67
+ "ttsc": "0.16.3"
68
+ },
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "https://github.com/samchon/ttsc"
72
+ },
73
+ "author": "Jeongho Nam",
74
+ "license": "MIT",
75
+ "bugs": {
76
+ "url": "https://github.com/samchon/ttsc/issues"
77
+ },
78
+ "homepage": "https://ttsc.dev",
79
+ "sideEffects": false,
80
+ "scripts": {
81
+ "build": "rimraf lib && tsc --emitDeclarationOnly && rollup -c"
82
+ }
83
+ }