@nubjs/loader 0.9.0-canary.20260908.508 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -9
- package/preload-async-hooks.mjs +1 -6
- package/preload-common.cjs +9 -61
- package/transform-core.mjs +4 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nubjs/loader",
|
|
3
|
-
"version": "0.9.0
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Standalone TypeScript loader for Node.js from the Nub project — TypeScript, JSX, tsconfig paths, and data-format imports through a native transform, registered the way tsx and ts-node are",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "https://github.com/nubjs/nub",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
"@oxc-project/runtime": "0.140.0"
|
|
50
50
|
},
|
|
51
51
|
"optionalDependencies": {
|
|
52
|
-
"@nubjs/loader-darwin-arm64": "0.9.0
|
|
53
|
-
"@nubjs/loader-darwin-x64": "0.9.0
|
|
54
|
-
"@nubjs/loader-linux-x64": "0.9.0
|
|
55
|
-
"@nubjs/loader-linux-x64-musl": "0.9.0
|
|
56
|
-
"@nubjs/loader-linux-arm64": "0.9.0
|
|
57
|
-
"@nubjs/loader-linux-arm64-musl": "0.9.0
|
|
58
|
-
"@nubjs/loader-win32-x64": "0.9.0
|
|
59
|
-
"@nubjs/loader-win32-arm64": "0.9.0
|
|
52
|
+
"@nubjs/loader-darwin-arm64": "0.9.0",
|
|
53
|
+
"@nubjs/loader-darwin-x64": "0.9.0",
|
|
54
|
+
"@nubjs/loader-linux-x64": "0.9.0",
|
|
55
|
+
"@nubjs/loader-linux-x64-musl": "0.9.0",
|
|
56
|
+
"@nubjs/loader-linux-arm64": "0.9.0",
|
|
57
|
+
"@nubjs/loader-linux-arm64-musl": "0.9.0",
|
|
58
|
+
"@nubjs/loader-win32-x64": "0.9.0",
|
|
59
|
+
"@nubjs/loader-win32-arm64": "0.9.0"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/preload-async-hooks.mjs
CHANGED
|
@@ -30,7 +30,7 @@ import "./floor-builtin.mjs";
|
|
|
30
30
|
import {
|
|
31
31
|
TRANSPILE_EXTS, PLAIN_JS_EXTS, CLOBBER_MAP, dataExtsFor,
|
|
32
32
|
extname, isFileUrl, resolveSpec, loadTranspile, maybeTranspilePlainJs, loadData, loadTextImport, isDependency,
|
|
33
|
-
noteRuntimeV8FlagSource,
|
|
33
|
+
noteRuntimeV8FlagSource,
|
|
34
34
|
} from "./transform-core.mjs";
|
|
35
35
|
import { createRequire, isBuiltin } from "node:module";
|
|
36
36
|
import { existsSync } from "node:fs";
|
|
@@ -114,11 +114,6 @@ async function loadInner(url, context, nextLoad) {
|
|
|
114
114
|
// fast-tier hook.
|
|
115
115
|
if (context?.importAttributes?.type === "text" && isFileUrl(url)) return loadTextImport(url);
|
|
116
116
|
const ext = extname(url);
|
|
117
|
-
// A user loader above nub's assigned this TypeScript file a bare module format
|
|
118
|
-
// and will transform it itself from the raw source (tsx's pattern; see
|
|
119
|
-
// `outerHookOwnsFormat`). This tier has no registration counter like the fast
|
|
120
|
-
// tier's and needs none: nothing but such a hook produces the bare form here.
|
|
121
|
-
if (outerHookOwnsFormat(context?.format, ext) && !isDependency(url)) return nextLoad(url, context);
|
|
122
117
|
// node_modules deps are NEVER transpiled (the byte-parity boundary). This guard is
|
|
123
118
|
// make-or-break now that TRANSPILE_EXTS includes `.js`/`.mjs`/`.cjs`: without it,
|
|
124
119
|
// the compat tier would route every dependency `.js` through oxc. (loadTranspile's
|
package/preload-common.cjs
CHANGED
|
@@ -231,10 +231,6 @@ function installWatchReporting(core) {
|
|
|
231
231
|
// `type` (transpile — there is no user hook to do it, and Node's strip-only mode
|
|
232
232
|
// can't handle enums/namespaces). See makeHooks().load.
|
|
233
233
|
let __userHooksRegistered = false;
|
|
234
|
-
// Narrower: a user registration that brought a `load` hook, so it can transform
|
|
235
|
-
// what nub hands back. A resolve-only user hook that labels a `.ts` file with a
|
|
236
|
-
// bare `commonjs`/`module` still relies on nub as the transformer.
|
|
237
|
-
let __userLoadHookRegistered = false;
|
|
238
234
|
function installUserHookDetector() {
|
|
239
235
|
if (typeof module_.registerHooks !== "function") return;
|
|
240
236
|
const orig = module_.registerHooks;
|
|
@@ -242,10 +238,7 @@ function installUserHookDetector() {
|
|
|
242
238
|
let seen = 0;
|
|
243
239
|
const wrapped = function (...args) {
|
|
244
240
|
// Call #1 is nub's own preload registration; #2+ are user hooks.
|
|
245
|
-
if (seen >= 1)
|
|
246
|
-
__userHooksRegistered = true;
|
|
247
|
-
if (args[0] && typeof args[0].load === "function") __userLoadHookRegistered = true;
|
|
248
|
-
}
|
|
241
|
+
if (seen >= 1) __userHooksRegistered = true;
|
|
249
242
|
seen += 1;
|
|
250
243
|
return orig.apply(this, args);
|
|
251
244
|
};
|
|
@@ -705,8 +698,8 @@ function makeHooks(core, watchReporting, foreignLoaderFlagPresent = foreignAsync
|
|
|
705
698
|
const source = readFileSync(path);
|
|
706
699
|
const pkgType = core.getPackageType(dirname(path));
|
|
707
700
|
const format = core.moduleFormatFor(ext, pkgType, path, source.toString("utf8"));
|
|
708
|
-
if (format === "commonjs") return { format: "commonjs", source: null,
|
|
709
|
-
return { format, source,
|
|
701
|
+
if (format === "commonjs") return { format: "commonjs", source: null, shortCircuit: true };
|
|
702
|
+
return { format, source, shortCircuit: true };
|
|
710
703
|
} catch {
|
|
711
704
|
return null;
|
|
712
705
|
}
|
|
@@ -780,22 +773,7 @@ function makeHooks(core, watchReporting, foreignLoaderFlagPresent = foreignAsync
|
|
|
780
773
|
// user's outer hook, which does the real ESM->CJS conversion, matching Node.
|
|
781
774
|
// Native 'module-typescript'/'commonjs-typescript' formats still fall through to
|
|
782
775
|
// nub's transpile below, so normal augmentation is unchanged.
|
|
783
|
-
|
|
784
|
-
// tsx 4.2x writes the bare `commonjs`/`module` form instead of 'typescript'
|
|
785
|
-
// (`outerHookOwnsFormat`), and the hook that wrote it must also be able to
|
|
786
|
-
// transform what it gets back: a user registration WITH a load hook
|
|
787
|
-
// (`__userLoadHookRegistered`), or a loader registered through
|
|
788
|
-
// `module.register` (`userAsyncLoaderActive`), which the registerHooks counter
|
|
789
|
-
// cannot see and which nub has no way to inspect. A resolve-only user hook
|
|
790
|
-
// that labels a `.ts` file keeps nub as its transformer. The 'typescript'
|
|
791
|
-
// branch keeps its own narrower gate: a non-transpiling async loader (a
|
|
792
|
-
// telemetry `--import`) must not turn a bare 'typescript' from Node's own
|
|
793
|
-
// CJS loader into a step-aside.
|
|
794
|
-
if (context && (
|
|
795
|
-
(__userHooksRegistered && context.format === "typescript") ||
|
|
796
|
-
((__userLoadHookRegistered || userAsyncLoaderActive(foreignLoaderFlagPresent)) &&
|
|
797
|
-
core.outerHookOwnsFormat(context.format, ext) && !core.isDependency(url))
|
|
798
|
-
)) {
|
|
776
|
+
if (__userHooksRegistered && context && context.format === "typescript") {
|
|
799
777
|
return nextLoad(url, context);
|
|
800
778
|
}
|
|
801
779
|
|
|
@@ -1049,36 +1027,10 @@ function installCjsRequireHooks(core, withClassicTranspile) {
|
|
|
1049
1027
|
// missing. An explicit `require("dep/x/sub.cjs")` is unaffected either way — an
|
|
1050
1028
|
// exact path is found by stat, without consulting the extension list at all.
|
|
1051
1029
|
const NUB_ADDED_EXTS = [".ts", ".cts", ".mts", ".tsx", ".jsx", ".cjs"];
|
|
1052
|
-
// A `require.extensions` handler that is ALREADY registered for one of these
|
|
1053
|
-
// when this runs belongs to a transpiler the user chose, and it stays in charge
|
|
1054
|
-
// of that extension: nub's classic shim neither replaces it nor pre-judges its
|
|
1055
|
-
// files as ES modules at resolve time. Every `--require` runs before any `--import`, so on
|
|
1056
|
-
// the compat tier — where nub's own preload is an `--import` — tsx's
|
|
1057
|
-
// `--require`d preflight installs its `.ts` handler FIRST; nub then overwrote
|
|
1058
|
-
// it, and a file tsx would have compiled to CJS (mixed `import` + `require`,
|
|
1059
|
-
// the shape its ESM hook hands to the CJS loader) died in nub's handler as
|
|
1060
|
-
// "Cannot require() this file — it is an ES module". Node itself registers only
|
|
1061
|
-
// `.js`/`.json`/`.node`, so nothing but a user transpiler holds one of these
|
|
1062
|
-
// keys here.
|
|
1063
|
-
const foreignExts = new Set(
|
|
1064
|
-
[...core.TRANSPILE_EXTS, ...core.allDataExts(), ...NUB_ADDED_EXTS].filter((ext) =>
|
|
1065
|
-
ext !== ".js" && ext !== ".json" && ext !== ".node" && Object.hasOwn(module_._extensions, ext)),
|
|
1066
|
-
);
|
|
1067
|
-
// Ownership of a key is decided per lookup, never frozen at start-up: user code
|
|
1068
|
-
// may install or replace a handler after nub's preload (`--import tsx` runs
|
|
1069
|
-
// after every `--require`), and from then on that key is the user's own
|
|
1070
|
-
// widening of LOAD_AS_FILE, exactly as under plain Node plus their handler —
|
|
1071
|
-
// `require("dep/sub")` finding a dependency's `sub.ts` through it is the answer
|
|
1072
|
-
// to preserve. A key is nub's only while BOTH hold: nub introduced it (it was
|
|
1073
|
-
// not in `foreignExts` — a user's `.cjs` handler that nub merely wraps still
|
|
1074
|
-
// counts as theirs) and it still holds a function nub registered below
|
|
1075
|
-
// (`nubHandlers`). Anything else is not nub's to strip, nor to pre-judge.
|
|
1076
|
-
const nubHandlers = new Set();
|
|
1077
|
-
const nubOwnsExt = (ext) => !foreignExts.has(ext) && nubHandlers.has(module_._extensions[ext]);
|
|
1078
1030
|
const withoutNubAddedExtensions = (fn) => {
|
|
1079
1031
|
const saved = [];
|
|
1080
1032
|
for (const ext of NUB_ADDED_EXTS) {
|
|
1081
|
-
if (
|
|
1033
|
+
if (Object.hasOwn(module_._extensions, ext)) {
|
|
1082
1034
|
saved.push([ext, module_._extensions[ext]]);
|
|
1083
1035
|
delete module_._extensions[ext];
|
|
1084
1036
|
}
|
|
@@ -1091,7 +1043,7 @@ function installCjsRequireHooks(core, withClassicTranspile) {
|
|
|
1091
1043
|
};
|
|
1092
1044
|
const isDepAddedExtHit = (filename) =>
|
|
1093
1045
|
typeof filename === "string" &&
|
|
1094
|
-
|
|
1046
|
+
NUB_ADDED_EXTS.includes(pathExtname(filename)) &&
|
|
1095
1047
|
core.isDependency(pathToFileURL(filename).href);
|
|
1096
1048
|
|
|
1097
1049
|
module_._resolveFilename = function (request, parent, isMain, options) {
|
|
@@ -1114,8 +1066,7 @@ function installCjsRequireHooks(core, withClassicTranspile) {
|
|
|
1114
1066
|
// and 4 from `require.resolve` up to 22.14, but 22.15 and 22.16 pass 4 for both
|
|
1115
1067
|
// while still lacking native TS — and the translator crash is present on
|
|
1116
1068
|
// exactly those versions. A clean error beats an opaque crash, so this stays.
|
|
1117
|
-
if (withClassicTranspile &&
|
|
1118
|
-
core.requireTargetIsEsm(resolved, pathExtname(resolved))) {
|
|
1069
|
+
if (withClassicTranspile && core.requireTargetIsEsm(resolved, pathExtname(resolved))) {
|
|
1119
1070
|
throw requireEsmError(resolved);
|
|
1120
1071
|
}
|
|
1121
1072
|
return resolved;
|
|
@@ -1244,7 +1195,6 @@ function installCjsRequireHooks(core, withClassicTranspile) {
|
|
|
1244
1195
|
if (core.TRANSPILE_EXTS.has(ext)) return transpileExtension(mod, filename);
|
|
1245
1196
|
return nativeJs.call(module_._extensions, mod, filename);
|
|
1246
1197
|
};
|
|
1247
|
-
nubHandlers.add(nubExtension);
|
|
1248
1198
|
|
|
1249
1199
|
// Registered for every extension either path may claim, so the dispatcher is
|
|
1250
1200
|
// reached at all; `nubExtension` then decides. Node's own `.js`/`.json`/`.node`
|
|
@@ -1265,7 +1215,7 @@ function installCjsRequireHooks(core, withClassicTranspile) {
|
|
|
1265
1215
|
// resolution identical across tiers.
|
|
1266
1216
|
const CODE_EXTS = new Set([".ts", ".cts", ".mts", ".tsx", ".jsx"]);
|
|
1267
1217
|
for (const ext of new Set([...core.TRANSPILE_EXTS, ...core.allDataExts()])) {
|
|
1268
|
-
if (ext === ".js" || ext === ".json" || ext === ".node"
|
|
1218
|
+
if (ext === ".js" || ext === ".json" || ext === ".node") continue;
|
|
1269
1219
|
Object.defineProperty(module_._extensions, ext, {
|
|
1270
1220
|
value: nubExtension,
|
|
1271
1221
|
enumerable: CODE_EXTS.has(ext),
|
|
@@ -1293,7 +1243,7 @@ function installCjsRequireHooks(core, withClassicTranspile) {
|
|
|
1293
1243
|
// (`nativeJs` is captured above, before the TS handlers are registered.)
|
|
1294
1244
|
for (const ext of [".js", ".cjs"]) {
|
|
1295
1245
|
const origExtension = module_._extensions[ext] || nativeJs;
|
|
1296
|
-
|
|
1246
|
+
module_._extensions[ext] = (mod, filename) => {
|
|
1297
1247
|
// (0) The project pointed this extension at a data loader (`{".js":"text"}`),
|
|
1298
1248
|
// which the ESM path honors. These two extensions are skipped by the
|
|
1299
1249
|
// registration loop above because THIS wrapper owns them and runs after it,
|
|
@@ -1316,8 +1266,6 @@ function installCjsRequireHooks(core, withClassicTranspile) {
|
|
|
1316
1266
|
}
|
|
1317
1267
|
return origExtension.call(module_._extensions, mod, filename); // (3)
|
|
1318
1268
|
};
|
|
1319
|
-
module_._extensions[ext] = plainJsExtension;
|
|
1320
|
-
nubHandlers.add(plainJsExtension);
|
|
1321
1269
|
}
|
|
1322
1270
|
}
|
|
1323
1271
|
|
package/transform-core.mjs
CHANGED
|
@@ -207,20 +207,6 @@ export const TRANSPILE_EXTS = new Set([".ts", ".tsx", ".mts", ".cts", ".jsx"]);
|
|
|
207
207
|
// `maybeTranspilePlainJs` gate); a no-op plain-JS file falls through to Node's
|
|
208
208
|
// native loader untouched, byte-identical. node_modules is excluded at the gate.
|
|
209
209
|
export const PLAIN_JS_EXTS = new Set([".js", ".mjs", ".cjs"]);
|
|
210
|
-
// A bare `commonjs`/`module` format on a file nub would transpile can only have
|
|
211
|
-
// been assigned by a hook layered ABOVE nub's. Node's resolver labels a `.ts` file
|
|
212
|
-
// `commonjs-typescript`/`module-typescript` (or `typescript` when the package has
|
|
213
|
-
// no `type`) and leaves `.jsx` unlabelled, and nub's own resolve returns no format;
|
|
214
|
-
// the bare form is what tsx's resolve hook writes (getFormatFromFileUrl), and its
|
|
215
|
-
// load hook then expects the RAW source back from `nextLoad` so it can run its own
|
|
216
|
-
// module-format transform — a mixed `import` + `require` file becomes CJS there,
|
|
217
|
-
// where nub's syntax detection would make it ESM and `require` undefined. Both
|
|
218
|
-
// tiers step aside on this signal, the fast tier only once the user registration
|
|
219
|
-
// is known to carry a load hook (preload-common.cjs). Plain JS is excluded: Node
|
|
220
|
-
// assigns those the bare form itself.
|
|
221
|
-
export function outerHookOwnsFormat(format, ext) {
|
|
222
|
-
return (format === "commonjs" || format === "module") && TRANSPILE_EXTS.has(ext) && !PLAIN_JS_EXTS.has(ext);
|
|
223
|
-
}
|
|
224
210
|
// The data loaders nub SHIPS — a runtime feature, not a project setting, so they stay
|
|
225
211
|
// in force inside node_modules too (see dataExtsFor).
|
|
226
212
|
const BUILTIN_DATA_EXTS = { ".jsonc": "jsonc", ".json5": "json5", ".toml": "toml", ".yaml": "yaml", ".yml": "yaml", ".txt": "txt" };
|
|
@@ -1021,15 +1007,7 @@ export function loadTranspile(url, ext, source) {
|
|
|
1021
1007
|
const details = result.errors.map((e) => e.codeframe || e.message).join("\n\n");
|
|
1022
1008
|
throw new Error(`Transpile error in ${filePath}:\n${details}`);
|
|
1023
1009
|
}
|
|
1024
|
-
|
|
1025
|
-
// to the file URL, and tsx's load hook takes its CommonJS branch only when the
|
|
1026
|
-
// result `nextLoad` hands back carries a `file:` responseURL — without it, tsx
|
|
1027
|
-
// re-transformed a `.ts` file nub had already emitted as CJS in its ESM branch,
|
|
1028
|
-
// and `require` was undefined at run time (`tsx script.ts` under `nub run`).
|
|
1029
|
-
// Node itself defaults a missing responseURL to the URL, so only a hook layered
|
|
1030
|
-
// above nub's can observe the difference; every file-URL result nub
|
|
1031
|
-
// short-circuits carries it for that reason.
|
|
1032
|
-
return { format: result.format, source: result.code, responseURL: url, shortCircuit: true };
|
|
1010
|
+
return { format: result.format, source: result.code, shortCircuit: true };
|
|
1033
1011
|
}
|
|
1034
1012
|
|
|
1035
1013
|
// Project-source plain JS (`.js`/`.mjs`/`.cjs`) gate. Returns a transpiled load
|
|
@@ -1148,7 +1126,7 @@ export function loadData(url, ext) {
|
|
|
1148
1126
|
const parsed = dataValue(url, ext);
|
|
1149
1127
|
|
|
1150
1128
|
if (parsed == null) {
|
|
1151
|
-
return { format: "module", source: "export default undefined;\n",
|
|
1129
|
+
return { format: "module", source: "export default undefined;\n", shortCircuit: true };
|
|
1152
1130
|
}
|
|
1153
1131
|
|
|
1154
1132
|
// Default export only. Data modules deliberately do NOT emit per-key named
|
|
@@ -1158,7 +1136,7 @@ export function loadData(url, ext) {
|
|
|
1158
1136
|
// default — `import cfg from "./c.yaml"; const { host } = cfg;` — which the
|
|
1159
1137
|
// `@nubjs/types` `Record<string, unknown>` default type makes sound.
|
|
1160
1138
|
const code = `export default ${JSON.stringify(parsed)};\n`;
|
|
1161
|
-
return { format: "module", source: code,
|
|
1139
|
+
return { format: "module", source: code, shortCircuit: true };
|
|
1162
1140
|
}
|
|
1163
1141
|
|
|
1164
1142
|
// Import Text: `import s from "./any.file" with { type: "text" }` → the raw file
|
|
@@ -1174,5 +1152,5 @@ export function loadData(url, ext) {
|
|
|
1174
1152
|
const __textDecoder = new TextDecoder();
|
|
1175
1153
|
export function loadTextImport(url) {
|
|
1176
1154
|
const text = __textDecoder.decode(readFileSync(fileURLToPath(url)));
|
|
1177
|
-
return { format: "module", source: `export default ${JSON.stringify(text)};\n`,
|
|
1155
|
+
return { format: "module", source: `export default ${JSON.stringify(text)};\n`, shortCircuit: true };
|
|
1178
1156
|
}
|