@alchemy.run/node-utils 2.0.0-beta.75 → 2.0.0-beta.77

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/import-loader.d.ts +54 -0
  7. package/lib/import-loader.d.ts.map +1 -0
  8. package/lib/import-loader.js +9 -0
  9. package/lib/import-loader.js.map +1 -0
  10. package/lib/register-oxc.d.ts +16 -0
  11. package/lib/register-oxc.d.ts.map +1 -0
  12. package/lib/register-oxc.js +257 -0
  13. package/lib/register-oxc.js.map +1 -0
  14. package/lib/resolve-specifier.d.ts +52 -0
  15. package/lib/resolve-specifier.d.ts.map +1 -0
  16. package/lib/resolve-specifier.js +139 -0
  17. package/lib/resolve-specifier.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 +140 -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 +68 -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 +77 -0
  29. package/lib/watch-import.js.map +1 -0
  30. package/package.json +26 -2
  31. package/src/dependency-watcher.ts +130 -0
  32. package/src/import-loader.ts +75 -0
  33. package/src/register-oxc.ts +342 -0
  34. package/src/resolve-specifier.ts +179 -0
  35. package/src/transform-source.ts +170 -0
  36. package/src/watch-import-bun.ts +94 -0
  37. package/src/watch-import.ts +107 -0
@@ -0,0 +1,139 @@
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
+ * Given a file path Node failed to find (typically an `exports`/`main`
124
+ * target that names emitted JavaScript that was never built), finds the
125
+ * TypeScript source it was emitted from via extension substitution.
126
+ */
127
+ resolveMissing(missingPath, conditions) {
128
+ const directory = path.dirname(missingPath);
129
+ const base = path.basename(missingPath);
130
+ try {
131
+ const result = this.#resolver(conditions, true).sync(directory, `./${base}`);
132
+ return result.path;
133
+ }
134
+ catch {
135
+ return undefined;
136
+ }
137
+ }
138
+ }
139
+ //# 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,19 @@
1
+ import type { ImportLoaderOptions } from "./import-loader.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: ImportLoaderOptions);
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, url: 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":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAoB,MAAM,oBAAoB,CAAC;AAEhF,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,aAM9B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,CAAC;AAiEjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,iBAAiB;;IAI5B,YAAY,OAAO,EAAE,mBAAmB,EAEvC;IAED;;;;OAIG;IACH,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAChC,iBAAiB,GAAG,SAAS,CA8D/B;CACF"}
@@ -0,0 +1,140 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { parseSync, transformSync, TsconfigCache, } from "rolldown/utils";
4
+ /** Extensions Oxc transpiles; everything else is JavaScript Node can run. */
5
+ export const transformExtensions = new Set([
6
+ ".ts",
7
+ ".tsx",
8
+ ".mts",
9
+ ".cts",
10
+ ".jsx",
11
+ ]);
12
+ /**
13
+ * Module format from Node's `load` hook context. Node derives these from the
14
+ * extension and the nearest `package.json#type`; `*-typescript` variants are
15
+ * its TypeScript-aware spellings and mean the same thing.
16
+ */
17
+ const nodeFormat = (format) => {
18
+ switch (format) {
19
+ case "module":
20
+ case "module-typescript":
21
+ return "module";
22
+ case "commonjs":
23
+ case "commonjs-typescript":
24
+ return "commonjs";
25
+ default:
26
+ return undefined;
27
+ }
28
+ };
29
+ /** Fallback for older Nodes that pass no format: extension, then package type. */
30
+ const inferFormat = (filePath) => {
31
+ const extension = path.extname(filePath);
32
+ if (extension === ".mts" || extension === ".mjs")
33
+ return "module";
34
+ if (extension === ".cts" || extension === ".cjs")
35
+ return "commonjs";
36
+ let directory = path.dirname(filePath);
37
+ while (true) {
38
+ const packageJson = path.join(directory, "package.json");
39
+ if (existsSync(packageJson)) {
40
+ try {
41
+ return JSON.parse(readFileSync(packageJson, "utf8")).type === "module"
42
+ ? "module"
43
+ : "commonjs";
44
+ }
45
+ catch {
46
+ return "commonjs";
47
+ }
48
+ }
49
+ const parent = path.dirname(directory);
50
+ if (parent === directory)
51
+ return "commonjs";
52
+ directory = parent;
53
+ }
54
+ };
55
+ const language = (filePath) => {
56
+ switch (path.extname(filePath)) {
57
+ case ".tsx":
58
+ return "tsx";
59
+ case ".ts":
60
+ case ".mts":
61
+ case ".cts":
62
+ return "ts";
63
+ case ".jsx":
64
+ return "jsx";
65
+ default:
66
+ return "js";
67
+ }
68
+ };
69
+ const sourceMapComment = (map) => {
70
+ const json = typeof map === "string" ? map : JSON.stringify(map);
71
+ return `\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(json).toString("base64")}`;
72
+ };
73
+ export class SourceTransformer {
74
+ #options;
75
+ #tsconfigCache = new TsconfigCache();
76
+ constructor(options) {
77
+ this.#options = options;
78
+ }
79
+ /**
80
+ * Transpiles `filePath` for Node, or returns `undefined` when the file is
81
+ * JavaScript that needs no work. `format` is what Node's `load` hook was
82
+ * told; it decides `sourceType` and the format handed back.
83
+ */
84
+ transform(filePath, url, format) {
85
+ const extension = path.extname(filePath);
86
+ const transpile = transformExtensions.has(extension);
87
+ if (!transpile && this.#options.transforms === undefined)
88
+ return undefined;
89
+ let moduleFormat = nodeFormat(format) ?? inferFormat(filePath);
90
+ let source = readFileSync(filePath, "utf8");
91
+ let map;
92
+ if (transpile) {
93
+ const lang = this.#options.transform?.lang ?? language(filePath);
94
+ // A `.ts` file in a CommonJS package that uses `import`/`export` runs
95
+ // as ESM — the same call Node's own module-syntax detection makes for
96
+ // `.js`. Explicit `.cts` stays CommonJS regardless.
97
+ if (moduleFormat === "commonjs" &&
98
+ extension !== ".cts" &&
99
+ parseSync(filePath, source, { lang, sourceType: "unambiguous" }).module
100
+ .hasModuleSyntax) {
101
+ moduleFormat = "module";
102
+ }
103
+ const transformed = transformSync(filePath, source, {
104
+ tsconfig: this.#options.tsconfig ?? true,
105
+ sourcemap: true,
106
+ ...this.#options.transform,
107
+ lang,
108
+ sourceType: this.#options.transform?.sourceType ?? moduleFormat,
109
+ }, this.#tsconfigCache);
110
+ if (transformed.errors.length > 0) {
111
+ const [error] = transformed.errors;
112
+ throw error instanceof Error
113
+ ? error
114
+ : new SyntaxError(`${filePath}: ${error.message ?? String(error)}`);
115
+ }
116
+ source = transformed.code;
117
+ map = transformed.map;
118
+ }
119
+ const context = {
120
+ url,
121
+ path: filePath,
122
+ format: moduleFormat,
123
+ };
124
+ for (const transform of this.#options.transforms ?? []) {
125
+ const result = transform(source, context);
126
+ if (typeof result === "string") {
127
+ source = result;
128
+ map = undefined;
129
+ }
130
+ else if (result !== undefined) {
131
+ source = result.code;
132
+ map = result.map;
133
+ }
134
+ }
135
+ if (map !== undefined)
136
+ source += sourceMapComment(map);
137
+ return { format: moduleFormat, source };
138
+ }
139
+ }
140
+ //# 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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"}
@@ -0,0 +1,30 @@
1
+ import { type DependencyChangeListener, type DependencyWatcherOptions } from "./dependency-watcher.ts";
2
+ export interface BunImportTrackerOptions extends DependencyWatcherOptions {
3
+ /**
4
+ * Directory whose modules belong to the tracked graph. Files outside it and
5
+ * anything under a `node_modules` directory load untouched.
6
+ */
7
+ readonly root: string;
8
+ }
9
+ /**
10
+ * Records every project-local module Bun loads after registration and watches
11
+ * those files for changes.
12
+ *
13
+ * Bun has no loader hooks that can evict or re-namespace an evaluated module,
14
+ * so unlike Node's {@link ImportWatcher} this cannot import a fresh
15
+ * generation in-process. A runtime `Bun.plugin` `onLoad` hook is used purely
16
+ * as a dependency probe: it hands the source back unchanged with the loader
17
+ * Bun would have picked itself. Callers react to a change by exiting so a
18
+ * supervisor can start a fresh process.
19
+ */
20
+ export declare class BunImportTracker {
21
+ #private;
22
+ constructor(options: BunImportTrackerOptions);
23
+ get dependencies(): ReadonlySet<string>;
24
+ subscribe(listener: DependencyChangeListener): () => void;
25
+ /** Stops watching. The load hook stays registered but only echoes sources. */
26
+ close(): Promise<void>;
27
+ [Symbol.asyncDispose](): Promise<void>;
28
+ }
29
+ export declare const trackBunImports: (options: BunImportTrackerOptions) => BunImportTracker;
30
+ //# sourceMappingURL=watch-import-bun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-import-bun.d.ts","sourceRoot":"","sources":["../src/watch-import-bun.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC9B,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAgBD;;;;;;;;;;GAUG;AACH,qBAAa,gBAAgB;;IAI3B,YAAY,OAAO,EAAE,uBAAuB,EA2B3C;IAED,IAAI,YAAY,IAAI,WAAW,CAAC,MAAM,CAAC,CAEtC;IAED,SAAS,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,IAAI,CAExD;IAED,8EAA8E;IAC9E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAErB;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3C;CACF;AAED,eAAO,MAAM,eAAe,YAAa,uBAAuB,qBACjC,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { realpathSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { DependencyWatcher, } from "./dependency-watcher.js";
4
+ const loaders = {
5
+ ".js": "js",
6
+ ".mjs": "js",
7
+ ".cjs": "js",
8
+ ".jsx": "jsx",
9
+ ".ts": "ts",
10
+ ".mts": "ts",
11
+ ".cts": "ts",
12
+ ".tsx": "tsx",
13
+ };
14
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15
+ /**
16
+ * Records every project-local module Bun loads after registration and watches
17
+ * those files for changes.
18
+ *
19
+ * Bun has no loader hooks that can evict or re-namespace an evaluated module,
20
+ * so unlike Node's {@link ImportWatcher} this cannot import a fresh
21
+ * generation in-process. A runtime `Bun.plugin` `onLoad` hook is used purely
22
+ * as a dependency probe: it hands the source back unchanged with the loader
23
+ * Bun would have picked itself. Callers react to a change by exiting so a
24
+ * supervisor can start a fresh process.
25
+ */
26
+ export class BunImportTracker {
27
+ #watcher;
28
+ #dependencies = new Set();
29
+ constructor(options) {
30
+ if (process.versions.bun === undefined) {
31
+ throw new Error("BunImportTracker requires Bun; Node callers should use watchImport.");
32
+ }
33
+ this.#watcher = new DependencyWatcher(options);
34
+ // Bun reports real paths (`/private/tmp/...` for `/tmp/...` on macOS);
35
+ // match them against the root's real path too.
36
+ const root = realpathSync.native(path.resolve(options.root)) + path.sep;
37
+ const nodeModules = `${path.sep}node_modules${path.sep}`;
38
+ const filter = new RegExp(`^${escapeRegExp(root)}(?!.*${escapeRegExp(nodeModules)}).*\\.[cm]?[jt]sx?$`);
39
+ Bun.plugin({
40
+ name: "@alchemy.run/node-utils/watch-import-bun",
41
+ setup: (build) => {
42
+ build.onLoad({ filter }, async (args) => {
43
+ this.#dependencies.add(args.path);
44
+ this.#watcher.set(new Set(this.#dependencies));
45
+ return {
46
+ contents: await Bun.file(args.path).text(),
47
+ loader: loaders[path.extname(args.path)] ?? "js",
48
+ };
49
+ });
50
+ },
51
+ });
52
+ }
53
+ get dependencies() {
54
+ return this.#watcher.dependencies;
55
+ }
56
+ subscribe(listener) {
57
+ return this.#watcher.subscribe(listener);
58
+ }
59
+ /** Stops watching. The load hook stays registered but only echoes sources. */
60
+ close() {
61
+ return this.#watcher.close();
62
+ }
63
+ async [Symbol.asyncDispose]() {
64
+ await this.close();
65
+ }
66
+ }
67
+ export const trackBunImports = (options) => new BunImportTracker(options);
68
+ //# sourceMappingURL=watch-import-bun.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-import-bun.js","sourceRoot":"","sources":["../src/watch-import-bun.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,iBAAiB,GAGlB,MAAM,yBAAyB,CAAC;AAUjC,MAAM,OAAO,GAAgD;IAC3D,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,KAAK;CACd,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAE,CACrC,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,MAAM,OAAO,gBAAgB;IAClB,QAAQ,CAAoB;IAC5B,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IAE3C,YAAY,OAAgC;QAC1C,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,qEAAqE,CACtE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC/C,uEAAuE;QACvE,+CAA+C;QAC/C,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;QACxE,MAAM,WAAW,GAAG,GAAG,IAAI,CAAC,GAAG,eAAe,IAAI,CAAC,GAAG,EAAE,CAAC;QACzD,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,YAAY,CAAC,WAAW,CAAC,qBAAqB,CAC7E,CAAC;QACF,GAAG,CAAC,MAAM,CAAC;YACT,IAAI,EAAE,0CAA0C;YAChD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;gBACf,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;oBACtC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAClC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;oBAC/C,OAAO;wBACL,QAAQ,EAAE,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;wBAC1C,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI;qBACjD,CAAC;gBACJ,CAAC,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;IACpC,CAAC;IAED,SAAS,CAAC,QAAkC;QAC1C,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,8EAA8E;IAC9E,KAAK;QACH,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAgC,EAAE,EAAE,CAClE,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { type DependencyChangeListener, type DependencyWatcherOptions } from "./dependency-watcher.ts";
2
+ import { type ImportLoaderOptions } from "./import-loader.ts";
3
+ export interface ImportGeneration<T> {
4
+ readonly value: T;
5
+ readonly namespace: string;
6
+ readonly dependencies: ReadonlySet<string>;
7
+ }
8
+ export interface ImportWatcherOptions extends ImportLoaderOptions, DependencyWatcherOptions {
9
+ readonly parentURL: string;
10
+ }
11
+ /**
12
+ * Imports fresh Node module generations and watches the exact files loaded by
13
+ * the current generation. Bun callers should use `BunImportTracker` from
14
+ * `./watch-import-bun.ts`: Bun cannot evict evaluated modules, so a change
15
+ * there restarts the process instead of importing a new generation.
16
+ */
17
+ export declare class ImportWatcher<T = unknown> {
18
+ #private;
19
+ constructor(specifier: string, options: ImportWatcherOptions);
20
+ get dependencies(): ReadonlySet<string>;
21
+ subscribe(listener: DependencyChangeListener): () => void;
22
+ import(): Promise<ImportGeneration<T>>;
23
+ close(): Promise<void>;
24
+ [Symbol.asyncDispose](): Promise<void>;
25
+ }
26
+ export declare const watchImport: <T = unknown>(specifier: string, options: ImportWatcherOptions) => ImportWatcher<T>;
27
+ //# sourceMappingURL=watch-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-import.d.ts","sourceRoot":"","sources":["../src/watch-import.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,oBACf,SAAQ,mBAAmB,EAAE,wBAAwB;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,qBAAa,aAAa,CAAC,CAAC,GAAG,OAAO;;IAQpC,YAAY,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAI3D;IAED,IAAI,YAAY,IAAI,WAAW,CAAC,MAAM,CAAC,CAEtC;IAED,SAAS,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,IAAI,CAExD;IAEK,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAqC3C;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3B;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3C;CACF;AAED,eAAO,MAAM,WAAW,GAAI,CAAC,GAAG,OAAO,aAC1B,MAAM,WACR,oBAAoB,qBACc,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { fileURLToPath } from "node:url";
3
+ import { DependencyWatcher, } from "./dependency-watcher.js";
4
+ import { createImportLoader, } from "./import-loader.js";
5
+ /**
6
+ * Imports fresh Node module generations and watches the exact files loaded by
7
+ * the current generation. Bun callers should use `BunImportTracker` from
8
+ * `./watch-import-bun.ts`: Bun cannot evict evaluated modules, so a change
9
+ * there restarts the process instead of importing a new generation.
10
+ */
11
+ export class ImportWatcher {
12
+ #specifier;
13
+ #options;
14
+ #watcher;
15
+ #registration;
16
+ #dependencies = new Set();
17
+ #closed = false;
18
+ constructor(specifier, options) {
19
+ this.#specifier = specifier;
20
+ this.#options = options;
21
+ this.#watcher = new DependencyWatcher(options);
22
+ }
23
+ get dependencies() {
24
+ return this.#dependencies;
25
+ }
26
+ subscribe(listener) {
27
+ return this.#watcher.subscribe(listener);
28
+ }
29
+ async import() {
30
+ if (this.#closed)
31
+ throw new Error("ImportWatcher is closed");
32
+ const namespace = randomUUID();
33
+ const dependencies = new Set();
34
+ const { debounceMs: _, parentURL, watch: _watch, ...registerOptions } = this.#options;
35
+ const registration = await createImportLoader({
36
+ ...registerOptions,
37
+ namespace,
38
+ onImport: (url) => {
39
+ if (!url.startsWith("file:"))
40
+ return;
41
+ dependencies.add(fileURLToPath(url));
42
+ // A lazy import evaluated after this generation became current
43
+ // extends the watched set immediately.
44
+ if (this.#dependencies === dependencies)
45
+ this.#watcher.set(dependencies);
46
+ },
47
+ });
48
+ try {
49
+ const value = await registration.import(this.#specifier, parentURL);
50
+ await this.#registration?.unregister();
51
+ this.#registration = registration;
52
+ this.#dependencies = dependencies;
53
+ this.#watcher.set(dependencies);
54
+ return { value, namespace, dependencies };
55
+ }
56
+ catch (error) {
57
+ await registration.unregister();
58
+ // Keep watching everything the failed import touched so the next save
59
+ // of any of those files retries.
60
+ this.#dependencies = new Set([...this.#dependencies, ...dependencies]);
61
+ this.#watcher.set(this.#dependencies);
62
+ throw error;
63
+ }
64
+ }
65
+ async close() {
66
+ if (this.#closed)
67
+ return;
68
+ this.#closed = true;
69
+ await this.#registration?.unregister();
70
+ await this.#watcher.close();
71
+ }
72
+ async [Symbol.asyncDispose]() {
73
+ await this.close();
74
+ }
75
+ }
76
+ export const watchImport = (specifier, options) => new ImportWatcher(specifier, options);
77
+ //# sourceMappingURL=watch-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-import.js","sourceRoot":"","sources":["../src/watch-import.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alchemy.run/node-utils",
3
- "version": "2.0.0-beta.75",
4
- "description": "Gitignore-compatible path matching for Alchemy packages.",
3
+ "version": "2.0.0-beta.77",
4
+ "description": "Runtime utilities for Alchemy packages.",
5
5
  "homepage": "https://alchemy.run",
6
6
  "author": "Sam Goodwin <sam@alchemy.run>",
7
7
  "keywords": [
@@ -33,8 +33,32 @@
33
33
  "types": "./lib/ignore.d.ts",
34
34
  "bun": "./src/ignore.ts",
35
35
  "import": "./lib/ignore.js"
36
+ },
37
+ "./import-loader": {
38
+ "types": "./lib/import-loader.d.ts",
39
+ "bun": "./src/import-loader.ts",
40
+ "import": "./lib/import-loader.js"
41
+ },
42
+ "./register-oxc": {
43
+ "types": "./lib/register-oxc.d.ts",
44
+ "bun": "./src/register-oxc.ts",
45
+ "import": "./lib/register-oxc.js"
46
+ },
47
+ "./watch-import": {
48
+ "types": "./lib/watch-import.d.ts",
49
+ "bun": "./src/watch-import.ts",
50
+ "import": "./lib/watch-import.js"
51
+ },
52
+ "./watch-import-bun": {
53
+ "types": "./lib/watch-import-bun.d.ts",
54
+ "bun": "./src/watch-import-bun.ts",
55
+ "import": "./lib/watch-import-bun.js"
36
56
  }
37
57
  },
58
+ "dependencies": {
59
+ "chokidar": "^5.0.0",
60
+ "rolldown": "1.2.5"
61
+ },
38
62
  "publishConfig": {
39
63
  "access": "public"
40
64
  },