@alchemy.run/node-utils 2.0.0-beta.76 → 2.0.0-beta.78

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 (37) hide show
  1. package/THIRD_PARTY_LICENSES.md +11 -11
  2. package/lib/dependency-watcher.d.ts +28 -0
  3. package/lib/dependency-watcher.d.ts.map +1 -0
  4. package/lib/dependency-watcher.js +114 -0
  5. package/lib/dependency-watcher.js.map +1 -0
  6. package/lib/register-oxc.d.ts +61 -0
  7. package/lib/register-oxc.d.ts.map +1 -0
  8. package/lib/register-oxc.js +220 -0
  9. package/lib/register-oxc.js.map +1 -0
  10. package/lib/resolve-specifier.d.ts +46 -0
  11. package/lib/resolve-specifier.d.ts.map +1 -0
  12. package/lib/resolve-specifier.js +123 -0
  13. package/lib/resolve-specifier.js.map +1 -0
  14. package/lib/transform-cache.d.ts +63 -0
  15. package/lib/transform-cache.d.ts.map +1 -0
  16. package/lib/transform-cache.js +193 -0
  17. package/lib/transform-cache.js.map +1 -0
  18. package/lib/transform-source.d.ts +19 -0
  19. package/lib/transform-source.d.ts.map +1 -0
  20. package/lib/transform-source.js +213 -0
  21. package/lib/transform-source.js.map +1 -0
  22. package/lib/watch-import-bun.d.ts +30 -0
  23. package/lib/watch-import-bun.d.ts.map +1 -0
  24. package/lib/watch-import-bun.js +73 -0
  25. package/lib/watch-import-bun.js.map +1 -0
  26. package/lib/watch-import.d.ts +27 -0
  27. package/lib/watch-import.d.ts.map +1 -0
  28. package/lib/watch-import.js +79 -0
  29. package/lib/watch-import.js.map +1 -0
  30. package/package.json +21 -2
  31. package/src/dependency-watcher.ts +130 -0
  32. package/src/register-oxc.ts +337 -0
  33. package/src/resolve-specifier.ts +157 -0
  34. package/src/transform-cache.ts +226 -0
  35. package/src/transform-source.ts +254 -0
  36. package/src/watch-import-bun.ts +99 -0
  37. package/src/watch-import.ts +106 -0
@@ -0,0 +1,123 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { ResolverFactory } from "rolldown/experimental";
4
+ export const nodeModulesSegment = `${path.sep}node_modules${path.sep}`;
5
+ /** Local project code: a file path outside every `node_modules` directory. */
6
+ export const isProjectPath = (filePath) => !filePath.includes(nodeModulesSegment);
7
+ const typeScriptExtensions = /\.(?:[cm]?ts|[tj]sx)$/;
8
+ /** Whether TypeScript's extension substitution applies to this importer. */
9
+ export const isTypeScriptPath = (filePath) => typeScriptExtensions.test(filePath);
10
+ export const isFileLikeSpecifier = (specifier) => specifier.startsWith("./") ||
11
+ specifier.startsWith("../") ||
12
+ specifier === "." ||
13
+ specifier === ".." ||
14
+ specifier.startsWith("file:") ||
15
+ path.isAbsolute(specifier);
16
+ /**
17
+ * Splits `?query#fragment` metadata off a specifier. Bare specifiers never
18
+ * carry fragments in Node, so only `?` is honoured there.
19
+ */
20
+ export const splitSpecifierMetadata = (specifier) => {
21
+ const index = isFileLikeSpecifier(specifier)
22
+ ? specifier.search(/[?#]/)
23
+ : specifier.indexOf("?");
24
+ return index === -1
25
+ ? { specifier, metadata: "" }
26
+ : {
27
+ specifier: specifier.slice(0, index),
28
+ metadata: specifier.slice(index),
29
+ };
30
+ };
31
+ export const filePathOfUrl = (url) => {
32
+ if (url === undefined || !url.startsWith("file:"))
33
+ return undefined;
34
+ try {
35
+ return fileURLToPath(new URL(url));
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ };
41
+ export class SpecifierResolver {
42
+ #options;
43
+ #base;
44
+ #byConditions = new Map();
45
+ constructor(options) {
46
+ this.#options = {
47
+ tsconfig: options.tsconfig ? "auto" : undefined,
48
+ // TypeScript source first, then Node's implicit extensions.
49
+ extensions: [
50
+ ".ts",
51
+ ".tsx",
52
+ ".mts",
53
+ ".cts",
54
+ ".jsx",
55
+ ".js",
56
+ ".mjs",
57
+ ".cjs",
58
+ ".json",
59
+ ".node",
60
+ ],
61
+ // TypeScript's emitted-extension substitution: `./x.js` may point at
62
+ // `x.ts` (source) or `x.js` (emitted); source wins when both exist.
63
+ extensionAlias: {
64
+ ".js": [".ts", ".tsx", ".js"],
65
+ ".jsx": [".tsx", ".jsx"],
66
+ ".mjs": [".mts", ".mjs"],
67
+ ".cjs": [".cts", ".cjs"],
68
+ },
69
+ mainFiles: ["index"],
70
+ builtinModules: true,
71
+ moduleType: true,
72
+ };
73
+ this.#base = new ResolverFactory(this.#options);
74
+ }
75
+ /**
76
+ * Bare specifiers are probed without following symlinks: a workspace
77
+ * package linked into `node_modules` must still read as a package (and be
78
+ * left to Node), not as the project file its real path points at.
79
+ */
80
+ #resolver(conditions, symlinks) {
81
+ const key = `${symlinks} ${conditions.join(" ")}`;
82
+ let resolver = this.#byConditions.get(key);
83
+ if (resolver === undefined) {
84
+ // `cloneWithOptions` replaces the option set (sharing only the cache),
85
+ // so each conditions variant restates the base options.
86
+ resolver = this.#base.cloneWithOptions({
87
+ ...this.#options,
88
+ symlinks,
89
+ conditionNames: [...conditions],
90
+ });
91
+ this.#byConditions.set(key, resolver);
92
+ }
93
+ return resolver;
94
+ }
95
+ /**
96
+ * Resolves `specifier` as imported from `parentPath` to an absolute file
97
+ * path, or `undefined` when Oxc cannot resolve it (Node then reports the
98
+ * error), when it is a builtin, or when a bare specifier lands inside
99
+ * `node_modules` — packages are Node's business, only `paths` aliases
100
+ * that map onto project files are ours.
101
+ */
102
+ resolve(parentPath, specifier, conditions) {
103
+ const request = specifier.startsWith("file:")
104
+ ? filePathOfUrl(specifier)
105
+ : specifier;
106
+ if (request === undefined)
107
+ return undefined;
108
+ let result;
109
+ try {
110
+ result = this.#resolver(conditions, isFileLikeSpecifier(request)).resolveFileSync(parentPath, request);
111
+ }
112
+ catch {
113
+ return undefined;
114
+ }
115
+ if (result.path === undefined)
116
+ return undefined;
117
+ if (!isFileLikeSpecifier(request) && !isProjectPath(result.path)) {
118
+ return undefined;
119
+ }
120
+ return result.path;
121
+ }
122
+ }
123
+ //# sourceMappingURL=resolve-specifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-specifier.js","sourceRoot":"","sources":["../src/resolve-specifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ export declare const TRANSFORM_CACHE_ENV = "ALCHEMY_TRANSFORM_CACHE";
2
+ /**
3
+ * The directory to use for the given option, or `undefined` when caching is
4
+ * off. `cache: false` and `ALCHEMY_TRANSFORM_CACHE=0` disable it; a string
5
+ * (option or env) names the directory; otherwise the per-user default.
6
+ */
7
+ export declare const resolveCacheDirectory: (option: boolean | string | undefined) => string | undefined;
8
+ /** One transform's output as handed to {@link TransformCache.set}. */
9
+ export interface TransformCacheEntry {
10
+ readonly format: "module" | "commonjs";
11
+ readonly code: string;
12
+ /** Source map JSON, or `undefined` when the transform produced none. */
13
+ readonly map: string | undefined;
14
+ }
15
+ /** A cache hit: the code, and where its source map lives on disk. */
16
+ export interface CachedTransform {
17
+ readonly format: "module" | "commonjs";
18
+ readonly code: string;
19
+ /** Absolute path of the entry's `.map` file, present when it has one. */
20
+ readonly mapFile: string | undefined;
21
+ }
22
+ /**
23
+ * On-disk cache of Oxc transform output shared by every process on the
24
+ * machine — the `alchemy` CLI, its dev exec child, the local-provider
25
+ * sidecars and dev-server runners all load the same source files, and
26
+ * without this each of them transpiles the whole graph again.
27
+ *
28
+ * Modelled on tsx's file cache: entries are keyed by a hash of the source
29
+ * file's path, size and mtime, the transform options and the resolved
30
+ * tsconfig, so a change to any input is simply a different key; nothing is
31
+ * ever invalidated in place. Size plus nanosecond mtime stands in for the
32
+ * contents so a hit never reads the source.
33
+ *
34
+ * An entry is two files: `<key>.json` with the code, and `<key>.map` with
35
+ * the source map. The map stays on disk and is referenced from the module
36
+ * by path rather than inlined — an inline `data:` map is part of the
37
+ * script's source text, which V8 keeps for the process lifetime; for a
38
+ * graph the size of alchemy's that is hundreds of megabytes per process.
39
+ * Node reads the referenced file synchronously as it compiles the module,
40
+ * so the map is written (atomically) before `set` returns; the code entry
41
+ * is a fire-and-forget write, because a missing one is only a slower
42
+ * cache. Reads are synchronous (the loader hook is). Stale entries are
43
+ * swept by age once per process.
44
+ */
45
+ export declare class TransformCache {
46
+ #private;
47
+ constructor(directory: string);
48
+ /** The entry key for these transform inputs. */
49
+ key(parts: ReadonlyArray<string>): string;
50
+ /**
51
+ * The cached transform, or `undefined` on a miss. An entry whose map file
52
+ * has gone (swept, or never landed) is a miss too: the module would
53
+ * otherwise reference a map that is not there.
54
+ */
55
+ get(key: string): CachedTransform | undefined;
56
+ /**
57
+ * Stores one transform. Returns the map file's path once it is on disk,
58
+ * or `undefined` when there is no map or it could not be written — the
59
+ * caller then falls back to inlining it.
60
+ */
61
+ set(key: string, entry: TransformCacheEntry): string | undefined;
62
+ }
63
+ //# sourceMappingURL=transform-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-cache.d.ts","sourceRoot":"","sources":["../src/transform-cache.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,mBAAmB,4BAA4B,CAAC;AAW7D;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,WACxB,OAAO,GAAG,MAAM,GAAG,SAAS,KACnC,MAAM,GAAG,SAOX,CAAC;AAEF,sEAAsE;AACtE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,cAAc;;IAKzB,YAAY,SAAS,EAAE,MAAM,EAE5B;IAED,gDAAgD;IAChD,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CASxC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CA4B5C;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAqB/D;CAoDF"}
@@ -0,0 +1,193 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, mkdirSync, promises as fs, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import rolldown from "rolldown/package.json" with { type: "json" };
6
+ import self from "../package.json" with { type: "json" };
7
+ /**
8
+ * Anything that changes Oxc's output for identical input invalidates every
9
+ * entry: the transformer itself (rolldown), this package's transform
10
+ * pipeline, and the on-disk entry layout.
11
+ */
12
+ const CACHE_VERSION = ["1", self.version, rolldown.version].join("-");
13
+ /** Entries untouched for this long are swept on the first disk access. */
14
+ const MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
15
+ export const TRANSFORM_CACHE_ENV = "ALCHEMY_TRANSFORM_CACHE";
16
+ /**
17
+ * Per-user directory, like tsx's `tsx-<uid>`: `tmpdir()` is shared on
18
+ * multi-user machines, and entries are written with the owner's umask.
19
+ */
20
+ const defaultDirectory = () => {
21
+ const user = process.geteuid?.() ?? os.userInfo().username;
22
+ return path.join(os.tmpdir(), `alchemy-oxc-${user}`);
23
+ };
24
+ /**
25
+ * The directory to use for the given option, or `undefined` when caching is
26
+ * off. `cache: false` and `ALCHEMY_TRANSFORM_CACHE=0` disable it; a string
27
+ * (option or env) names the directory; otherwise the per-user default.
28
+ */
29
+ export const resolveCacheDirectory = (option) => {
30
+ if (option === false)
31
+ return undefined;
32
+ if (typeof option === "string")
33
+ return option;
34
+ const env = process.env[TRANSFORM_CACHE_ENV];
35
+ if (env === "0" || env === "false")
36
+ return undefined;
37
+ if (env !== undefined && env !== "")
38
+ return env;
39
+ return defaultDirectory();
40
+ };
41
+ /**
42
+ * On-disk cache of Oxc transform output shared by every process on the
43
+ * machine — the `alchemy` CLI, its dev exec child, the local-provider
44
+ * sidecars and dev-server runners all load the same source files, and
45
+ * without this each of them transpiles the whole graph again.
46
+ *
47
+ * Modelled on tsx's file cache: entries are keyed by a hash of the source
48
+ * file's path, size and mtime, the transform options and the resolved
49
+ * tsconfig, so a change to any input is simply a different key; nothing is
50
+ * ever invalidated in place. Size plus nanosecond mtime stands in for the
51
+ * contents so a hit never reads the source.
52
+ *
53
+ * An entry is two files: `<key>.json` with the code, and `<key>.map` with
54
+ * the source map. The map stays on disk and is referenced from the module
55
+ * by path rather than inlined — an inline `data:` map is part of the
56
+ * script's source text, which V8 keeps for the process lifetime; for a
57
+ * graph the size of alchemy's that is hundreds of megabytes per process.
58
+ * Node reads the referenced file synchronously as it compiles the module,
59
+ * so the map is written (atomically) before `set` returns; the code entry
60
+ * is a fire-and-forget write, because a missing one is only a slower
61
+ * cache. Reads are synchronous (the loader hook is). Stale entries are
62
+ * swept by age once per process.
63
+ */
64
+ export class TransformCache {
65
+ #directory;
66
+ #ready = false;
67
+ #sequence = 0;
68
+ constructor(directory) {
69
+ this.#directory = directory;
70
+ }
71
+ /** The entry key for these transform inputs. */
72
+ key(parts) {
73
+ const hash = createHash("sha1");
74
+ hash.update(CACHE_VERSION);
75
+ for (const part of parts) {
76
+ // Length-prefixed so adjacent parts cannot run into each other.
77
+ hash.update(`\0${part.length}\0`);
78
+ hash.update(part);
79
+ }
80
+ return hash.digest("hex");
81
+ }
82
+ /**
83
+ * The cached transform, or `undefined` on a miss. An entry whose map file
84
+ * has gone (swept, or never landed) is a miss too: the module would
85
+ * otherwise reference a map that is not there.
86
+ */
87
+ get(key) {
88
+ this.#prepare();
89
+ let raw;
90
+ try {
91
+ raw = readFileSync(this.#file(key, "json"), "utf8");
92
+ }
93
+ catch {
94
+ return undefined;
95
+ }
96
+ let entry;
97
+ try {
98
+ entry = JSON.parse(raw);
99
+ }
100
+ catch {
101
+ return undefined;
102
+ }
103
+ if ((entry.format !== "module" && entry.format !== "commonjs") ||
104
+ typeof entry.code !== "string" ||
105
+ typeof entry.map !== "boolean") {
106
+ return undefined;
107
+ }
108
+ const mapFile = this.#file(key, "map");
109
+ if (entry.map && !existsSync(mapFile))
110
+ return undefined;
111
+ return {
112
+ format: entry.format,
113
+ code: entry.code,
114
+ mapFile: entry.map ? mapFile : undefined,
115
+ };
116
+ }
117
+ /**
118
+ * Stores one transform. Returns the map file's path once it is on disk,
119
+ * or `undefined` when there is no map or it could not be written — the
120
+ * caller then falls back to inlining it.
121
+ */
122
+ set(key, entry) {
123
+ this.#prepare();
124
+ let mapFile;
125
+ if (entry.map !== undefined) {
126
+ mapFile = this.#file(key, "map");
127
+ if (!this.#writeAtomically(mapFile, entry.map))
128
+ return undefined;
129
+ }
130
+ const file = this.#file(key, "json");
131
+ const temporary = this.#temporary(file);
132
+ // Best effort: a cache that cannot be written is only a slower cache.
133
+ fs.writeFile(temporary, JSON.stringify({
134
+ format: entry.format,
135
+ code: entry.code,
136
+ map: mapFile !== undefined,
137
+ }))
138
+ .then(() => fs.rename(temporary, file))
139
+ .catch(() => fs.unlink(temporary).catch(() => { }));
140
+ return mapFile;
141
+ }
142
+ #file(key, extension) {
143
+ return path.join(this.#directory, `${key}.${extension}`);
144
+ }
145
+ #temporary(file) {
146
+ return `${file}.${process.pid}.${this.#sequence++}.tmp`;
147
+ }
148
+ /** Temp file plus rename: concurrent readers never see a partial file. */
149
+ #writeAtomically(file, content) {
150
+ const temporary = this.#temporary(file);
151
+ try {
152
+ writeFileSync(temporary, content);
153
+ renameSync(temporary, file);
154
+ return true;
155
+ }
156
+ catch {
157
+ try {
158
+ unlinkSync(temporary);
159
+ }
160
+ catch { }
161
+ return false;
162
+ }
163
+ }
164
+ #prepare() {
165
+ if (this.#ready)
166
+ return;
167
+ this.#ready = true;
168
+ try {
169
+ mkdirSync(this.#directory, { recursive: true });
170
+ }
171
+ catch {
172
+ return;
173
+ }
174
+ // Off the hot path: the loader hook that got us here is synchronous.
175
+ setImmediate(() => {
176
+ this.#sweep().catch(() => { });
177
+ });
178
+ }
179
+ async #sweep() {
180
+ const cutoff = Date.now() - MAX_AGE_MS;
181
+ const names = await fs.readdir(this.#directory);
182
+ await Promise.all(names.map(async (name) => {
183
+ const file = path.join(this.#directory, name);
184
+ try {
185
+ const { mtimeMs } = await fs.stat(file);
186
+ if (mtimeMs < cutoff)
187
+ await fs.unlink(file);
188
+ }
189
+ catch { }
190
+ }));
191
+ }
192
+ }
193
+ //# sourceMappingURL=transform-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-cache.js","sourceRoot":"","sources":["../src/transform-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { OxcLoaderOptions } from "./register-oxc.ts";
2
+ /** Extensions Oxc transpiles; everything else is JavaScript Node can run. */
3
+ export declare const transformExtensions: Set<string>;
4
+ export type ModuleFormat = "module" | "commonjs";
5
+ export interface TransformedSource {
6
+ readonly format: ModuleFormat;
7
+ readonly source: string;
8
+ }
9
+ export declare class SourceTransformer {
10
+ #private;
11
+ constructor(options: OxcLoaderOptions);
12
+ /**
13
+ * Transpiles `filePath` for Node, or returns `undefined` when the file is
14
+ * JavaScript that needs no work. `format` is what Node's `load` hook was
15
+ * told; it decides `sourceType` and the format handed back.
16
+ */
17
+ transform(filePath: string, format: string | null | undefined): TransformedSource | undefined;
18
+ }
19
+ //# sourceMappingURL=transform-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-source.d.ts","sourceRoot":"","sources":["../src/transform-source.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,aAM9B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,CAAC;AA0FjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,iBAAiB;;IAK5B,YAAY,OAAO,EAAE,gBAAgB,EAKpC;IA4CD;;;;OAIG;IACH,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAChC,iBAAiB,GAAG,SAAS,CAyE/B;CACF"}
@@ -0,0 +1,213 @@
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { resolveTsconfig } from "rolldown/experimental";
5
+ import { parseSync, transformSync, TsconfigCache, } from "rolldown/utils";
6
+ import { resolveCacheDirectory, TransformCache } from "./transform-cache.js";
7
+ /** Extensions Oxc transpiles; everything else is JavaScript Node can run. */
8
+ export const transformExtensions = new Set([
9
+ ".ts",
10
+ ".tsx",
11
+ ".mts",
12
+ ".cts",
13
+ ".jsx",
14
+ ]);
15
+ /**
16
+ * Module format from Node's `load` hook context. Node derives these from the
17
+ * extension and the nearest `package.json#type`; `*-typescript` variants are
18
+ * its TypeScript-aware spellings and mean the same thing.
19
+ */
20
+ const nodeFormat = (format) => {
21
+ switch (format) {
22
+ case "module":
23
+ case "module-typescript":
24
+ return "module";
25
+ case "commonjs":
26
+ case "commonjs-typescript":
27
+ return "commonjs";
28
+ default:
29
+ return undefined;
30
+ }
31
+ };
32
+ /** Fallback for older Nodes that pass no format: extension, then package type. */
33
+ const inferFormat = (filePath) => {
34
+ const extension = path.extname(filePath);
35
+ if (extension === ".mts" || extension === ".mjs")
36
+ return "module";
37
+ if (extension === ".cts" || extension === ".cjs")
38
+ return "commonjs";
39
+ let directory = path.dirname(filePath);
40
+ while (true) {
41
+ const packageJson = path.join(directory, "package.json");
42
+ if (existsSync(packageJson)) {
43
+ try {
44
+ return JSON.parse(readFileSync(packageJson, "utf8")).type === "module"
45
+ ? "module"
46
+ : "commonjs";
47
+ }
48
+ catch {
49
+ return "commonjs";
50
+ }
51
+ }
52
+ const parent = path.dirname(directory);
53
+ if (parent === directory)
54
+ return "commonjs";
55
+ directory = parent;
56
+ }
57
+ };
58
+ const language = (filePath) => {
59
+ switch (path.extname(filePath)) {
60
+ case ".tsx":
61
+ return "tsx";
62
+ case ".ts":
63
+ case ".mts":
64
+ case ".cts":
65
+ return "ts";
66
+ case ".jsx":
67
+ return "jsx";
68
+ default:
69
+ return "js";
70
+ }
71
+ };
72
+ /**
73
+ * Inline map, for when there is no cache file to point at. Only the
74
+ * fallback: the base64 becomes part of the script source V8 retains, and
75
+ * for a non-ASCII source it is stored two bytes per character on top.
76
+ */
77
+ const inlineSourceMapComment = (map) => {
78
+ const json = typeof map === "string" ? map : JSON.stringify(map);
79
+ return `\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(json).toString("base64")}`;
80
+ };
81
+ /**
82
+ * Map by reference. Node's source-map support only understands `data:`
83
+ * URLs and scheme-less paths (it resolves the latter against the module
84
+ * URL and reads the file), so this is the file URL's path component —
85
+ * `/var/…/x.map` on POSIX, `/C:/…/x.map` on Windows — never a `file:` URL.
86
+ */
87
+ const fileSourceMapComment = (mapFile) => `\n//# sourceMappingURL=${pathToFileURL(mapFile).pathname}`;
88
+ /**
89
+ * The transform's map without `sourcesContent`. Every source is a file on
90
+ * this machine, named by the map's `sources`, so embedding its text only
91
+ * makes the map larger than the code it describes and every process that
92
+ * loads the module pay for it.
93
+ */
94
+ const withoutSourcesContent = ({ sourcesContent: _, ...map }) => map;
95
+ export class SourceTransformer {
96
+ #options;
97
+ #tsconfigCache = new TsconfigCache();
98
+ #cache;
99
+ constructor(options) {
100
+ this.#options = options;
101
+ const directory = resolveCacheDirectory(options.cache);
102
+ this.#cache =
103
+ directory === undefined ? undefined : new TransformCache(directory);
104
+ }
105
+ /**
106
+ * Cache key for one transform, or `undefined` when the result must not be
107
+ * cached. Every input Oxc's output depends on is part of it: the file's
108
+ * path (source maps name it), its size and mtime standing in for its
109
+ * contents — a stat instead of a read plus a hash per module on the warm
110
+ * path — the effective transform options, Node's module format, and the
111
+ * tsconfig that would be discovered for the file, resolved through the
112
+ * same cache `transformSync` uses with the `extends` chain already
113
+ * merged, so editing any tsconfig in the chain is a new key.
114
+ */
115
+ #cacheKey(filePath, options, format) {
116
+ if (this.#cache === undefined)
117
+ return undefined;
118
+ let stat;
119
+ try {
120
+ stat = statSync(filePath, { bigint: true });
121
+ }
122
+ catch {
123
+ return undefined;
124
+ }
125
+ let tsconfig = null;
126
+ try {
127
+ if (options.tsconfig === true) {
128
+ tsconfig = resolveTsconfig(filePath, this.#tsconfigCache)?.tsconfig;
129
+ }
130
+ else if (typeof options.tsconfig === "string") {
131
+ tsconfig = readFileSync(options.tsconfig, "utf8");
132
+ }
133
+ }
134
+ catch {
135
+ // A broken tsconfig is the transform's error to report; don't cache.
136
+ return undefined;
137
+ }
138
+ return this.#cache.key([
139
+ filePath,
140
+ `${stat.size}:${stat.mtimeNs}`,
141
+ JSON.stringify(options),
142
+ JSON.stringify(tsconfig ?? null),
143
+ format,
144
+ ]);
145
+ }
146
+ /**
147
+ * Transpiles `filePath` for Node, or returns `undefined` when the file is
148
+ * JavaScript that needs no work. `format` is what Node's `load` hook was
149
+ * told; it decides `sourceType` and the format handed back.
150
+ */
151
+ transform(filePath, format) {
152
+ const extension = path.extname(filePath);
153
+ if (!transformExtensions.has(extension))
154
+ return undefined;
155
+ let moduleFormat = nodeFormat(format) ?? inferFormat(filePath);
156
+ const lang = language(filePath);
157
+ const options = {
158
+ tsconfig: this.#options.tsconfig ?? true,
159
+ sourcemap: true,
160
+ lang,
161
+ };
162
+ // The key is taken before the source is read so a hit costs one stat
163
+ // and one cache read, never the source itself.
164
+ const key = this.#cacheKey(filePath, options, moduleFormat);
165
+ const cached = key === undefined ? undefined : this.#cache?.get(key);
166
+ if (cached !== undefined) {
167
+ return {
168
+ format: cached.format,
169
+ source: cached.mapFile === undefined
170
+ ? cached.code
171
+ : cached.code + fileSourceMapComment(cached.mapFile),
172
+ };
173
+ }
174
+ const source = readFileSync(filePath, "utf8");
175
+ // A `.ts` file in a CommonJS package that uses `import`/`export` runs
176
+ // as ESM — the same call Node's own module-syntax detection makes for
177
+ // `.js`. Explicit `.cts` stays CommonJS regardless.
178
+ if (moduleFormat === "commonjs" &&
179
+ extension !== ".cts" &&
180
+ parseSync(filePath, source, { lang, sourceType: "unambiguous" }).module
181
+ .hasModuleSyntax) {
182
+ moduleFormat = "module";
183
+ }
184
+ const transformed = transformSync(filePath, source, { ...options, sourceType: moduleFormat }, this.#tsconfigCache);
185
+ if (transformed.errors.length > 0) {
186
+ const [error] = transformed.errors;
187
+ throw error instanceof Error
188
+ ? error
189
+ : new SyntaxError(`${filePath}: ${error.message ?? String(error)}`);
190
+ }
191
+ const map = transformed.map === undefined
192
+ ? undefined
193
+ : JSON.stringify(withoutSourcesContent(transformed.map));
194
+ // The map ends up in the module exactly one way: on disk next to the
195
+ // cache entry and referenced by path, or (cache off) inlined.
196
+ const mapFile = key === undefined || map === undefined
197
+ ? undefined
198
+ : this.#cache?.set(key, {
199
+ format: moduleFormat,
200
+ code: transformed.code,
201
+ map,
202
+ });
203
+ return {
204
+ format: moduleFormat,
205
+ source: mapFile !== undefined
206
+ ? transformed.code + fileSourceMapComment(mapFile)
207
+ : map !== undefined
208
+ ? transformed.code + inlineSourceMapComment(map)
209
+ : transformed.code,
210
+ };
211
+ }
212
+ }
213
+ //# sourceMappingURL=transform-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-source.js","sourceRoot":"","sources":["../src/transform-source.ts"],"names":[],"mappings":"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"}