@nola-lang/node-loader 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +82 -0
- package/dist/config.js.map +1 -0
- package/dist/debug-prewarm.d.ts +13 -0
- package/dist/debug-prewarm.d.ts.map +1 -0
- package/dist/debug-prewarm.js +33 -0
- package/dist/debug-prewarm.js.map +1 -0
- package/dist/hooks.d.ts +37 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +76 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/register.d.ts +10 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +16 -0
- package/dist/register.js.map +1 -0
- package/dist/transform.d.ts +13 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/transform.js +107 -0
- package/dist/transform.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Evgen Mykhailenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Part of [Nola](https://github.com/nola-lang/nola), a TypeScript superset (`.tsi`) where `infer` functions and `ask` extractors turn prompts into typed values.
|
|
2
|
+
|
|
3
|
+
**Internal package** — you probably want [`nola-lang`](https://www.npmjs.com/package/nola-lang) (the dev tool) or [`@nola-lang/runtime`](https://www.npmjs.com/package/@nola-lang/runtime) (the app dependency).
|
|
4
|
+
|
|
5
|
+
This package registers Node module hooks that lower `.tsi` in memory — the engine behind `nola run` and `node --import nola-lang/register`, including inline source maps for debugging.
|
|
6
|
+
|
|
7
|
+
Versioned in lockstep with the whole toolchain; internal APIs may change in any release.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ResolvedCompilerConfig, type ResolvedNolaConfig } from "@nola-lang/runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The project root: the directory holding the nearest `nola.config.ts`, else `startDir`.
|
|
4
|
+
* Used to relativize the paths baked into lowered output, so `dist/` never carries the
|
|
5
|
+
* build machine's directory layout.
|
|
6
|
+
*
|
|
7
|
+
* Always absolute — `displayPathFor` prefix-matches this against an absolute file path,
|
|
8
|
+
* and a relative root would match nothing and silently fall back to emitting the
|
|
9
|
+
* absolute path.
|
|
10
|
+
*/
|
|
11
|
+
export declare function findProjectRoot(startDir?: string): string;
|
|
12
|
+
export declare function loadNolaConfig(startDir?: string): Promise<ResolvedNolaConfig | null>;
|
|
13
|
+
/**
|
|
14
|
+
* The `compiler` section alone, for `nola build`/`check`: validates ONLY that
|
|
15
|
+
* section, so a project without a runtime-valid config (no providers yet)
|
|
16
|
+
* still compiles. Defaults apply when there is no config file at all.
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadCompilerOptions(startDir?: string): Promise<ResolvedCompilerConfig>;
|
|
19
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EAGxB,MAAM,oBAAoB,CAAC;AA2B5B;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,QAAQ,SAAgB,GAAG,MAAM,CAIhE;AAiBD,wBAAsB,cAAc,CAAC,QAAQ,SAAgB,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAIjG;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,SAAgB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAMnG"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { parseEnv } from "node:util";
|
|
6
|
+
import { resolveCompilerConfig, resolveNolaConfig, } from "@nola-lang/runtime";
|
|
7
|
+
import { transformSync } from "esbuild";
|
|
8
|
+
// Apply a project-root `.env` into process.env before the config is evaluated, so
|
|
9
|
+
// `nola.config.ts` (and anything it reads, e.g. OPENAI_API_KEY) sees it. Precedence
|
|
10
|
+
// follows dotenv convention: an entry already set in the real environment wins, so
|
|
11
|
+
// shell/launch vars are never clobbered by the file.
|
|
12
|
+
async function applyDotEnv(dir) {
|
|
13
|
+
const envPath = join(dir, ".env");
|
|
14
|
+
if (!existsSync(envPath))
|
|
15
|
+
return;
|
|
16
|
+
const parsed = parseEnv(await readFile(envPath, "utf8"));
|
|
17
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
18
|
+
if (process.env[key] === undefined)
|
|
19
|
+
process.env[key] = value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function findUp(startDir, name) {
|
|
23
|
+
let dir = startDir;
|
|
24
|
+
for (;;) {
|
|
25
|
+
const candidate = join(dir, name);
|
|
26
|
+
if (existsSync(candidate))
|
|
27
|
+
return candidate;
|
|
28
|
+
const parent = dirname(dir);
|
|
29
|
+
if (parent === dir)
|
|
30
|
+
return null;
|
|
31
|
+
dir = parent;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The project root: the directory holding the nearest `nola.config.ts`, else `startDir`.
|
|
36
|
+
* Used to relativize the paths baked into lowered output, so `dist/` never carries the
|
|
37
|
+
* build machine's directory layout.
|
|
38
|
+
*
|
|
39
|
+
* Always absolute — `displayPathFor` prefix-matches this against an absolute file path,
|
|
40
|
+
* and a relative root would match nothing and silently fall back to emitting the
|
|
41
|
+
* absolute path.
|
|
42
|
+
*/
|
|
43
|
+
export function findProjectRoot(startDir = process.cwd()) {
|
|
44
|
+
const from = resolve(startDir);
|
|
45
|
+
const configPath = findUp(from, "nola.config.ts");
|
|
46
|
+
return configPath ? dirname(configPath) : from;
|
|
47
|
+
}
|
|
48
|
+
/** Evaluate nola.config.ts (esbuild type-strip + temp-module import) and return its default export raw. */
|
|
49
|
+
async function evalConfigModule(configPath) {
|
|
50
|
+
await applyDotEnv(dirname(configPath));
|
|
51
|
+
const source = await readFile(configPath, "utf8");
|
|
52
|
+
const { code } = transformSync(source, { loader: "ts", format: "esm" });
|
|
53
|
+
const tmp = join(dirname(configPath), `nola.config.${Date.now()}.${process.pid}.mjs`);
|
|
54
|
+
await writeFile(tmp, code);
|
|
55
|
+
try {
|
|
56
|
+
const mod = (await import(pathToFileURL(tmp).href));
|
|
57
|
+
return mod.default;
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
await rm(tmp, { force: true });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export async function loadNolaConfig(startDir = process.cwd()) {
|
|
64
|
+
const configPath = findUp(startDir, "nola.config.ts");
|
|
65
|
+
if (!configPath)
|
|
66
|
+
return null;
|
|
67
|
+
return resolveNolaConfig(await evalConfigModule(configPath), { source: configPath });
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The `compiler` section alone, for `nola build`/`check`: validates ONLY that
|
|
71
|
+
* section, so a project without a runtime-valid config (no providers yet)
|
|
72
|
+
* still compiles. Defaults apply when there is no config file at all.
|
|
73
|
+
*/
|
|
74
|
+
export async function loadCompilerOptions(startDir = process.cwd()) {
|
|
75
|
+
const configPath = findUp(startDir, "nola.config.ts");
|
|
76
|
+
if (!configPath)
|
|
77
|
+
return resolveCompilerConfig(undefined);
|
|
78
|
+
const raw = await evalConfigModule(configPath);
|
|
79
|
+
const section = raw !== null && typeof raw === "object" ? raw.compiler : undefined;
|
|
80
|
+
return resolveCompilerConfig(section, configPath);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debugger-only: force undici's one-time llhttp WebAssembly compile BEFORE
|
|
3
|
+
* user code runs. js-debug wraps WebAssembly.compile with an injected
|
|
4
|
+
* `debugger;` statement (its WASM instrumentation), and when that pause fires
|
|
5
|
+
* MID-STEP — which is exactly what happens when F10 crosses the process's
|
|
6
|
+
* first `ask` and fetch lazily compiles llhttp — js-debug auto-resumes its
|
|
7
|
+
* own pause and V8's pending step dies with it: the step turns into a
|
|
8
|
+
* continue. One loopback round-trip (~2ms, no external network) moves the
|
|
9
|
+
* compile to startup, where the instrumentation pause is harmless.
|
|
10
|
+
* No-op unless an inspector is attached.
|
|
11
|
+
*/
|
|
12
|
+
export declare function prewarmDebuggerHttpStack(): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=debug-prewarm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-prewarm.d.ts","sourceRoot":"","sources":["../src/debug-prewarm.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAgB9D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import inspector from "node:inspector";
|
|
2
|
+
import net from "node:net";
|
|
3
|
+
/**
|
|
4
|
+
* Debugger-only: force undici's one-time llhttp WebAssembly compile BEFORE
|
|
5
|
+
* user code runs. js-debug wraps WebAssembly.compile with an injected
|
|
6
|
+
* `debugger;` statement (its WASM instrumentation), and when that pause fires
|
|
7
|
+
* MID-STEP — which is exactly what happens when F10 crosses the process's
|
|
8
|
+
* first `ask` and fetch lazily compiles llhttp — js-debug auto-resumes its
|
|
9
|
+
* own pause and V8's pending step dies with it: the step turns into a
|
|
10
|
+
* continue. One loopback round-trip (~2ms, no external network) moves the
|
|
11
|
+
* compile to startup, where the instrumentation pause is harmless.
|
|
12
|
+
* No-op unless an inspector is attached.
|
|
13
|
+
*/
|
|
14
|
+
export async function prewarmDebuggerHttpStack() {
|
|
15
|
+
if (inspector.url() === undefined)
|
|
16
|
+
return;
|
|
17
|
+
try {
|
|
18
|
+
const server = net.createServer((sock) => {
|
|
19
|
+
sock.end("HTTP/1.1 204 No Content\r\nconnection: close\r\n\r\n");
|
|
20
|
+
});
|
|
21
|
+
await new Promise((resolve, reject) => {
|
|
22
|
+
server.once("error", reject);
|
|
23
|
+
server.listen(0, "127.0.0.1", resolve);
|
|
24
|
+
});
|
|
25
|
+
const address = server.address();
|
|
26
|
+
await fetch(`http://127.0.0.1:${address.port}/`).then((r) => r.arrayBuffer());
|
|
27
|
+
server.close();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// best-effort: a failed prewarm only means stepping may lose the race once
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=debug-prewarm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-prewarm.js","sourceRoot":"","sources":["../src/debug-prewarm.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,IAAI,SAAS,CAAC,GAAG,EAAE,KAAK,SAAS;QAAE,OAAO;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE;YACvC,IAAI,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAqB,CAAC;QACpD,MAAM,KAAK,CAAC,oBAAoB,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9E,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;IAC7E,CAAC;AACH,CAAC"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare function initialize(data?: {
|
|
2
|
+
compiler?: {
|
|
3
|
+
underivableContextType?: "error" | "prune" | "omit";
|
|
4
|
+
};
|
|
5
|
+
}): void;
|
|
6
|
+
interface ResolveContext {
|
|
7
|
+
parentURL?: string;
|
|
8
|
+
}
|
|
9
|
+
type NextResolve = (specifier: string, context: ResolveContext) => Promise<{
|
|
10
|
+
url: string;
|
|
11
|
+
shortCircuit?: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Companion specifiers name modules that never exist on disk — default
|
|
15
|
+
* resolution would throw ERR_MODULE_NOT_FOUND before `load` ran. Recognize the
|
|
16
|
+
* reserved suffix, probe the type-source candidates next to the importer, and
|
|
17
|
+
* short-circuit to a marked URL the `load` hook synthesizes from.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolve(specifier: string, context: ResolveContext, nextResolve: NextResolve): Promise<{
|
|
20
|
+
url: string;
|
|
21
|
+
shortCircuit?: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
interface LoadContext {
|
|
24
|
+
format?: string | null;
|
|
25
|
+
}
|
|
26
|
+
type NextLoad = (url: string, context: LoadContext) => Promise<{
|
|
27
|
+
format: string;
|
|
28
|
+
source: unknown;
|
|
29
|
+
shortCircuit?: boolean;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function load(url: string, context: LoadContext, nextLoad: NextLoad): Promise<{
|
|
32
|
+
format: string;
|
|
33
|
+
source: unknown;
|
|
34
|
+
shortCircuit?: boolean;
|
|
35
|
+
}>;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AA+BA,wBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE;QAAE,sBAAsB,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,CAE9G;AAED,UAAU,cAAc;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AACD,KAAK,WAAW,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEpH;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW;SARhB,MAAM;mBAAiB,OAAO;GA2B/G;AAED,UAAU,WAAW;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AACD,KAAK,QAAQ,GAAG,CACd,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAE1E,wBAAsB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ;YAFzD,MAAM;YAAU,OAAO;mBAAiB,OAAO;GAqBrE"}
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, resolve as resolvePath } from "node:path";
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
+
import { companionSourceCandidates, compileCompanion, isCompanionSpecifier } from "@nola-lang/compiler";
|
|
6
|
+
import { transform } from "esbuild";
|
|
7
|
+
import { findProjectRoot } from "./config.js";
|
|
8
|
+
import { NolaTransformError, transformNola } from "./transform.js";
|
|
9
|
+
// The hooks run in Node's module-hooks worker, which `register()` gives no project
|
|
10
|
+
// context. Walk up for the root here, memoized per directory — a `.tsi` import graph
|
|
11
|
+
// is many files across few directories.
|
|
12
|
+
const roots = new Map();
|
|
13
|
+
function rootFor(file) {
|
|
14
|
+
const dir = dirname(file);
|
|
15
|
+
let root = roots.get(dir);
|
|
16
|
+
if (root === undefined) {
|
|
17
|
+
root = findProjectRoot(dir);
|
|
18
|
+
roots.set(dir, root);
|
|
19
|
+
}
|
|
20
|
+
return root;
|
|
21
|
+
}
|
|
22
|
+
const COMPANION_QUERY = "?nola-companion";
|
|
23
|
+
// Compile-time config, delivered by registerNola through `register` data (the
|
|
24
|
+
// hooks worker cannot see the main thread's config object). Absent data —
|
|
25
|
+
// e.g. hooks registered without registerNola — falls back to the compiler
|
|
26
|
+
// default, which matches an unconfigured project.
|
|
27
|
+
let underivableContextType;
|
|
28
|
+
export function initialize(data) {
|
|
29
|
+
underivableContextType = data?.compiler?.underivableContextType;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Companion specifiers name modules that never exist on disk — default
|
|
33
|
+
* resolution would throw ERR_MODULE_NOT_FOUND before `load` ran. Recognize the
|
|
34
|
+
* reserved suffix, probe the type-source candidates next to the importer, and
|
|
35
|
+
* short-circuit to a marked URL the `load` hook synthesizes from.
|
|
36
|
+
*/
|
|
37
|
+
export async function resolve(specifier, context, nextResolve) {
|
|
38
|
+
if (!isCompanionSpecifier(specifier) || !specifier.startsWith(".") || !context.parentURL?.startsWith("file:")) {
|
|
39
|
+
return nextResolve(specifier, context);
|
|
40
|
+
}
|
|
41
|
+
const importerDir = dirname(fileURLToPath(context.parentURL));
|
|
42
|
+
const literal = resolvePath(importerDir, specifier);
|
|
43
|
+
if (existsSync(literal)) {
|
|
44
|
+
// Never silently shadow: a real on-disk *.nola.* file is a reserved-namespace violation.
|
|
45
|
+
throw new Error(`NOLA2006: ${literal} matches the reserved *.nola.* companion namespace — rename the file.`);
|
|
46
|
+
}
|
|
47
|
+
for (const candidate of companionSourceCandidates(specifier)) {
|
|
48
|
+
const p = resolvePath(importerDir, candidate);
|
|
49
|
+
if (existsSync(p)) {
|
|
50
|
+
return { url: pathToFileURL(p).href + COMPANION_QUERY, shortCircuit: true };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`NOLA2007: cannot locate the type source for "${specifier}" imported from ${fileURLToPath(context.parentURL)}`);
|
|
54
|
+
}
|
|
55
|
+
export async function load(url, context, nextLoad) {
|
|
56
|
+
if (url.endsWith(COMPANION_QUERY)) {
|
|
57
|
+
const file = fileURLToPath(url.slice(0, -COMPANION_QUERY.length));
|
|
58
|
+
const source = await readFile(file, "utf8");
|
|
59
|
+
const companion = compileCompanion(source, file, { sourceRoot: rootFor(file) });
|
|
60
|
+
if (companion.code === "" || companion.diagnostics.length > 0) {
|
|
61
|
+
throw new NolaTransformError(companion.diagnostics);
|
|
62
|
+
}
|
|
63
|
+
// Plain TS with no meaningful original positions — strip types, skip the map.
|
|
64
|
+
// Async `transform` for the same worker-thread reason documented in transform.ts.
|
|
65
|
+
const js = await transform(companion.code, { loader: "ts", format: "esm" });
|
|
66
|
+
return { format: "module", source: js.code, shortCircuit: true };
|
|
67
|
+
}
|
|
68
|
+
if (!url.endsWith(".tsi"))
|
|
69
|
+
return nextLoad(url, context);
|
|
70
|
+
const file = fileURLToPath(url);
|
|
71
|
+
const source = await readFile(file, "utf8");
|
|
72
|
+
const { code, map } = await transformNola(source, file, { sourceRoot: rootFor(file), underivableContextType });
|
|
73
|
+
const withMap = `${code}\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(map).toString("base64")}\n`;
|
|
74
|
+
return { format: "module", source: withMap, shortCircuit: true };
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config loads BEFORE the hooks register: the hooks worker gets no project
|
|
3
|
+
* context of its own, so the compiler section rides in as `register` data —
|
|
4
|
+
* the one channel into the worker — keeping a single config evaluation.
|
|
5
|
+
* (Consequence: nola.config.ts itself cannot import `.tsi` modules.)
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerNola(opts?: {
|
|
8
|
+
dir?: string;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7E"}
|
package/dist/register.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { register } from "node:module";
|
|
2
|
+
import { nolaRuntime } from "@nola-lang/runtime";
|
|
3
|
+
import { loadNolaConfig } from "./config.js";
|
|
4
|
+
/**
|
|
5
|
+
* Config loads BEFORE the hooks register: the hooks worker gets no project
|
|
6
|
+
* context of its own, so the compiler section rides in as `register` data —
|
|
7
|
+
* the one channel into the worker — keeping a single config evaluation.
|
|
8
|
+
* (Consequence: nola.config.ts itself cannot import `.tsi` modules.)
|
|
9
|
+
*/
|
|
10
|
+
export async function registerNola(opts = {}) {
|
|
11
|
+
const config = await loadNolaConfig(opts.dir ?? process.cwd());
|
|
12
|
+
register("./hooks.js", { parentURL: import.meta.url, data: { compiler: config?.compiler } });
|
|
13
|
+
if (config)
|
|
14
|
+
nolaRuntime.configure(config);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAyB,EAAE;IAC5D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/D,QAAQ,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC7F,IAAI,MAAM;QAAE,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Diagnostic } from "@nola-lang/ast";
|
|
2
|
+
import { type CompileOptions } from "@nola-lang/compiler";
|
|
3
|
+
export declare function formatDiagnostics(diagnostics: Diagnostic[]): string;
|
|
4
|
+
export declare class NolaTransformError extends Error {
|
|
5
|
+
readonly diagnostics: Diagnostic[];
|
|
6
|
+
name: string;
|
|
7
|
+
constructor(diagnostics: Diagnostic[]);
|
|
8
|
+
}
|
|
9
|
+
export declare function transformNola(source: string, file: string, options?: CompileOptions): Promise<{
|
|
10
|
+
code: string;
|
|
11
|
+
map: string;
|
|
12
|
+
}>;
|
|
13
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,KAAK,cAAc,EAAmC,MAAM,qBAAqB,CAAC;AAS3F,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAInE;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAE/B,QAAQ,CAAC,WAAW,EAAE,UAAU,EAAE;IADrC,IAAI,SAAwB;gBAChB,WAAW,EAAE,UAAU,EAAE;CAG/C;AAkED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAcxC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import remappingImport from "@ampproject/remapping";
|
|
2
|
+
import { decode, encode } from "@jridgewell/sourcemap-codec";
|
|
3
|
+
import { compileNola } from "@nola-lang/compiler";
|
|
4
|
+
import { transform } from "esbuild";
|
|
5
|
+
const remapping = remappingImport;
|
|
6
|
+
export function formatDiagnostics(diagnostics) {
|
|
7
|
+
return diagnostics
|
|
8
|
+
.map((d) => `${d.file}:${d.loc.start.line}:${d.loc.start.column + 1} ${d.code}: ${d.message}`)
|
|
9
|
+
.join("\n");
|
|
10
|
+
}
|
|
11
|
+
export class NolaTransformError extends Error {
|
|
12
|
+
diagnostics;
|
|
13
|
+
name = "NolaTransformError";
|
|
14
|
+
constructor(diagnostics) {
|
|
15
|
+
super(formatDiagnostics(diagnostics));
|
|
16
|
+
this.diagnostics = diagnostics;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Debugger-facing map hygiene, applied to esbuild's map BEFORE the merge.
|
|
21
|
+
*
|
|
22
|
+
* The loader's merged map is what js-debug steps by, and stepping should walk
|
|
23
|
+
* STRAIGHT THROUGH intent construction: F11 on `ask fn(...)` must land in the
|
|
24
|
+
* callee's body, not tour the lowered wrapper. js-debug's smart-stepping does
|
|
25
|
+
* exactly that for UNMAPPED positions, so here the wrapper lines (generated
|
|
26
|
+
* lines that begin inside replaced text — the infer opener/closer; identified
|
|
27
|
+
* via meta.spans in LOWERED space, where they are still distinguishable) lose
|
|
28
|
+
* their segments. Two segment classes must go:
|
|
29
|
+
*
|
|
30
|
+
* - segments whose lowered position sits on a wrapper line (the compiler's
|
|
31
|
+
* `anchorInsertedLines` anchors — kept in the compiler map for `nola build`
|
|
32
|
+
* dist maps and `nola check`, deliberately absent from the debug map);
|
|
33
|
+
* - esbuild's line-start CARRY segments: esbuild opens each output line by
|
|
34
|
+
* re-emitting the previous token run's position, so a wrapper output line
|
|
35
|
+
* would otherwise inherit the BODY'S LAST TOKEN and the debugger displays
|
|
36
|
+
* the body's last line while paused in construction (the F11
|
|
37
|
+
* `return valid;` bug). A carry is precise to detect: a column-0 segment
|
|
38
|
+
* whose original position equals the previous line's last segment's.
|
|
39
|
+
*/
|
|
40
|
+
function stripWrapperSegments(jsMap, lowered) {
|
|
41
|
+
const map = JSON.parse(jsMap);
|
|
42
|
+
const decoded = decode(map.mappings);
|
|
43
|
+
const generated = lowered.code;
|
|
44
|
+
const lineStarts = [0];
|
|
45
|
+
for (let i = 0; i < generated.length; i++)
|
|
46
|
+
if (generated[i] === "\n")
|
|
47
|
+
lineStarts.push(i + 1);
|
|
48
|
+
const lineOf = (offset) => {
|
|
49
|
+
let lo = 0;
|
|
50
|
+
let hi = lineStarts.length - 1;
|
|
51
|
+
while (lo < hi) {
|
|
52
|
+
const mid = (lo + hi + 1) >> 1;
|
|
53
|
+
if (lineStarts[mid] <= offset)
|
|
54
|
+
lo = mid;
|
|
55
|
+
else
|
|
56
|
+
hi = mid - 1;
|
|
57
|
+
}
|
|
58
|
+
return lo;
|
|
59
|
+
};
|
|
60
|
+
const wrapperLines = new Set();
|
|
61
|
+
for (const sp of lowered.meta.spans) {
|
|
62
|
+
if (sp.kind !== "replaced")
|
|
63
|
+
continue;
|
|
64
|
+
let line = lineOf(sp.generatedStart);
|
|
65
|
+
if (lineStarts[line] < sp.generatedStart)
|
|
66
|
+
line += 1;
|
|
67
|
+
for (; line < lineStarts.length && lineStarts[line] < sp.generatedEnd; line++)
|
|
68
|
+
wrapperLines.add(line);
|
|
69
|
+
}
|
|
70
|
+
let prevLast;
|
|
71
|
+
for (let l = 0; l < decoded.length; l++) {
|
|
72
|
+
const original = decoded[l];
|
|
73
|
+
let segments = original.filter((s) => s.length >= 4 && !wrapperLines.has(s[2]));
|
|
74
|
+
const first = segments[0];
|
|
75
|
+
if (first && first[0] === 0 && prevLast && first[2] === prevLast[2] && first[3] === prevLast[3]) {
|
|
76
|
+
segments = segments.slice(1);
|
|
77
|
+
}
|
|
78
|
+
if (original.length > 0)
|
|
79
|
+
prevLast = original[original.length - 1];
|
|
80
|
+
decoded[l] = segments;
|
|
81
|
+
}
|
|
82
|
+
map.mappings = encode(decoded);
|
|
83
|
+
return JSON.stringify(map);
|
|
84
|
+
}
|
|
85
|
+
// Async `transform` (esbuild's child-process service), NOT `transformSync`. The loader
|
|
86
|
+
// runs inside Node's module-hooks worker thread, and `transformSync` there spawns a
|
|
87
|
+
// nested worker_threads Worker (startWorkerThreadService) that the VS Code debugger's
|
|
88
|
+
// worker instrumentation intermittently breaks ("Worker is not a constructor"). The
|
|
89
|
+
// async API uses a child process instead, so it is safe under a debugger. Keep it async.
|
|
90
|
+
export async function transformNola(source, file, options = {}) {
|
|
91
|
+
const lowered = compileNola(source, file, options);
|
|
92
|
+
if (lowered.diagnostics.length > 0)
|
|
93
|
+
throw new NolaTransformError(lowered.diagnostics);
|
|
94
|
+
const js = await transform(lowered.code, { loader: "ts", format: "esm", sourcemap: "external", sourcefile: file });
|
|
95
|
+
const stripped = stripWrapperSegments(js.map, lowered);
|
|
96
|
+
// One-shot loader: the esbuild map's single source resolves to the compiler map;
|
|
97
|
+
// the compiler map's own source (same file name) is the original leaf → null.
|
|
98
|
+
let consumed = false;
|
|
99
|
+
const merged = remapping(stripped, () => {
|
|
100
|
+
if (consumed)
|
|
101
|
+
return null;
|
|
102
|
+
consumed = true;
|
|
103
|
+
return lowered.map;
|
|
104
|
+
});
|
|
105
|
+
return { code: js.code, map: merged.toString() };
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nola-lang/node-loader",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "Node module hooks that compile .tsi on the fly (internal; powers nola run and nola-lang/register)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"nola"
|
|
7
|
+
],
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "Evgen Mykhailenko",
|
|
10
|
+
"homepage": "https://github.com/nola-lang/nola#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/nola-lang/nola.git",
|
|
14
|
+
"directory": "packages/node-loader"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/nola-lang/nola/issues"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./hooks": "./dist/hooks.js",
|
|
29
|
+
"./register": "./dist/register.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@nola-lang/ast": "0.1.0-alpha.0",
|
|
36
|
+
"@nola-lang/compiler": "0.1.0-alpha.0",
|
|
37
|
+
"@nola-lang/parser": "0.1.0-alpha.0",
|
|
38
|
+
"@nola-lang/runtime": "0.1.0-alpha.0",
|
|
39
|
+
"@ampproject/remapping": "^2.3.0",
|
|
40
|
+
"@jridgewell/sourcemap-codec": "^1.5.0",
|
|
41
|
+
"esbuild": "^0.25.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@jridgewell/trace-mapping": "^0.3.25"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=22"
|
|
48
|
+
}
|
|
49
|
+
}
|