nola-lang 0.1.7 → 0.1.9
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/dist/build.d.ts +2 -0
- package/dist/build.js +77 -81
- package/dist/check.d.ts +1 -0
- package/dist/check.js +52 -51
- package/dist/commands.d.ts +1 -0
- package/dist/commands.js +5 -2
- package/dist/declarations.d.ts +7 -4
- package/dist/declarations.js +37 -25
- package/dist/derive.d.ts +21 -0
- package/dist/derive.js +27 -0
- package/dist/skill.d.ts +1 -1
- package/dist/skill.js +2 -2
- package/dist/style.js +1 -1
- package/dist/tshost-declarations.d.ts +11 -5
- package/dist/tshost-declarations.js +28 -18
- package/dist/tshost.d.ts +12 -1
- package/dist/tshost.js +23 -15
- package/dist/views.d.ts +7 -0
- package/dist/views.js +20 -0
- package/dist/walk.d.ts +8 -1
- package/dist/walk.js +16 -9
- package/package.json +12 -10
- package/dist/account.d.ts.map +0 -1
- package/dist/account.js.map +0 -1
- package/dist/build.d.ts.map +0 -1
- package/dist/build.js.map +0 -1
- package/dist/check.d.ts.map +0 -1
- package/dist/check.js.map +0 -1
- package/dist/commands.d.ts.map +0 -1
- package/dist/commands.js.map +0 -1
- package/dist/companions.d.ts +0 -18
- package/dist/companions.d.ts.map +0 -1
- package/dist/companions.js +0 -44
- package/dist/companions.js.map +0 -1
- package/dist/console.d.ts.map +0 -1
- package/dist/console.js.map +0 -1
- package/dist/declarations.d.ts.map +0 -1
- package/dist/declarations.js.map +0 -1
- package/dist/diag.d.ts.map +0 -1
- package/dist/diag.js.map +0 -1
- package/dist/frame.d.ts.map +0 -1
- package/dist/frame.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init.d.ts.map +0 -1
- package/dist/init.js.map +0 -1
- package/dist/key.d.ts.map +0 -1
- package/dist/key.js.map +0 -1
- package/dist/login.d.ts.map +0 -1
- package/dist/login.js.map +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/open-url.d.ts.map +0 -1
- package/dist/open-url.js.map +0 -1
- package/dist/register.d.ts.map +0 -1
- package/dist/register.js.map +0 -1
- package/dist/run.d.ts.map +0 -1
- package/dist/run.js.map +0 -1
- package/dist/skill.d.ts.map +0 -1
- package/dist/skill.js.map +0 -1
- package/dist/style.d.ts.map +0 -1
- package/dist/style.js.map +0 -1
- package/dist/tshost-declarations.d.ts.map +0 -1
- package/dist/tshost-declarations.js.map +0 -1
- package/dist/tshost.d.ts.map +0 -1
- package/dist/tshost.js.map +0 -1
- package/dist/walk.d.ts.map +0 -1
- package/dist/walk.js.map +0 -1
package/dist/build.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export interface BuildResult {
|
|
2
2
|
written: string[];
|
|
3
3
|
errors: string[];
|
|
4
|
+
/** non-fatal: same-basename .ts + .tsi pairs (spec decision 5) */
|
|
5
|
+
warnings: string[];
|
|
4
6
|
}
|
|
5
7
|
export declare function cmdBuild(dirArg?: string, outArg?: string): Promise<BuildResult>;
|
|
6
8
|
//# sourceMappingURL=build.d.ts.map
|
package/dist/build.js
CHANGED
|
@@ -2,13 +2,13 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
4
4
|
import remappingImport from "@ampproject/remapping";
|
|
5
|
-
import { Codes } from "@nola-lang/ast";
|
|
6
|
-
import { companionSourceCandidates, companionSpecifierFor, compileCompanion, compileNola } from "@nola-lang/compiler";
|
|
7
5
|
import { bundleSelfConfiguringConfig, findProjectRoot, loadBuildOptions, loadCompilerOptions, } from "@nola-lang/node-loader";
|
|
8
6
|
import { transformSync } from "esbuild";
|
|
7
|
+
import { createProjectDeriver } from "./derive.js";
|
|
9
8
|
import { printDiagnostics } from "./diag.js";
|
|
10
9
|
import { emitDeclarationTexts } from "./tshost-declarations.js";
|
|
11
|
-
import {
|
|
10
|
+
import { danglingViewErrors } from "./views.js";
|
|
11
|
+
import { siblingWarning, walkProject } from "./walk.js";
|
|
12
12
|
const remapping = remappingImport;
|
|
13
13
|
/** First line of the emitted config bundle; the overwrite guard keys on it. */
|
|
14
14
|
const CONFIG_BUNDLE_MARKER = "// generated by nola build — self-configuring Nola config bundle";
|
|
@@ -23,20 +23,15 @@ export async function cmdBuild(dirArg = ".", outArg = "dist") {
|
|
|
23
23
|
const written = [];
|
|
24
24
|
const errors = [];
|
|
25
25
|
const lowered = [];
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
for (const file of reserved) {
|
|
29
|
-
errors.push(`${file} ${Codes.ReservedCompanionPath}: the *.nola.* filename namespace is reserved for generated companion modules — rename this file`);
|
|
30
|
-
}
|
|
31
|
-
if (errors.length > 0)
|
|
32
|
-
return { written, errors };
|
|
26
|
+
const { tsi, siblings } = await walkProject(dir);
|
|
27
|
+
const warnings = siblings.map(siblingWarning);
|
|
33
28
|
// App builds ship the config: bundle nola.config.ts (relative imports
|
|
34
29
|
// inlined, packages external) with a self-configuring wrapper, emitted
|
|
35
30
|
// first so a bad config fails the build before any compilation.
|
|
36
31
|
if (wireConfig) {
|
|
37
32
|
if (existsSync(configOutPath) && !(await readFile(configOutPath, "utf8")).startsWith(CONFIG_BUNDLE_MARKER)) {
|
|
38
33
|
errors.push(`${configOutPath}: exists and was not generated by nola build — refusing to overwrite. Is another toolchain compiling nola.config.ts into --out?`);
|
|
39
|
-
return { written, errors };
|
|
34
|
+
return { written, errors, warnings };
|
|
40
35
|
}
|
|
41
36
|
try {
|
|
42
37
|
const bundled = await bundleSelfConfiguringConfig(configPath);
|
|
@@ -46,81 +41,82 @@ export async function cmdBuild(dirArg = ".", outArg = "dist") {
|
|
|
46
41
|
}
|
|
47
42
|
catch (err) {
|
|
48
43
|
errors.push(err instanceof Error ? err.message : String(err));
|
|
49
|
-
return { written, errors };
|
|
44
|
+
return { written, errors, warnings };
|
|
50
45
|
}
|
|
51
46
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (result.diagnostics.length > 0) {
|
|
56
|
-
errors.push(printDiagnostics(result.diagnostics, () => source));
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
lowered.push({ file, loweredCode: result.code });
|
|
60
|
-
metas.push(result.meta.companions);
|
|
61
|
-
// The wiring import is appended to the TRANSFORM INPUT only — the
|
|
62
|
-
// declarations pass reuses result.code and must never see it. EOF keeps
|
|
63
|
-
// positions intact; the appended line has no counterpart in result.map,
|
|
64
|
-
// so it stays unmapped after the merge.
|
|
65
|
-
const outPath = `${join(out, relative(dir, file))}.js`;
|
|
66
|
-
let emitCode = result.code;
|
|
67
|
-
if (wireConfig) {
|
|
68
|
-
const rel = relative(dirname(outPath), configOutPath).replace(/\\/g, "/");
|
|
69
|
-
emitCode = `${result.code}\nimport ${JSON.stringify(rel.startsWith(".") ? rel : `./${rel}`)};\n`;
|
|
70
|
-
}
|
|
71
|
-
const js = transformSync(emitCode, { loader: "ts", format: "esm", sourcemap: "external", sourcefile: file });
|
|
72
|
-
let consumed = false;
|
|
73
|
-
const merged = remapping(js.map, () => {
|
|
74
|
-
if (consumed)
|
|
75
|
-
return null;
|
|
76
|
-
consumed = true;
|
|
77
|
-
return result.map;
|
|
78
|
-
});
|
|
79
|
-
await mkdir(dirname(outPath), { recursive: true });
|
|
80
|
-
await writeFile(outPath, `${js.code}\n//# sourceMappingURL=${basename(outPath)}.map\n`);
|
|
81
|
-
await writeFile(`${outPath}.map`, merged.toString());
|
|
82
|
-
written.push(outPath, `${outPath}.map`);
|
|
47
|
+
const deriver = createProjectDeriver(dir, sourceRoot, underivableContextType);
|
|
48
|
+
try {
|
|
49
|
+
return await buildWith(deriver);
|
|
83
50
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
51
|
+
finally {
|
|
52
|
+
deriver.dispose();
|
|
53
|
+
}
|
|
54
|
+
async function buildWith(deriver) {
|
|
55
|
+
for (const file of tsi) {
|
|
56
|
+
const source = await readFile(file, "utf8");
|
|
57
|
+
// phase 1 + the checker pass (emit 15): the appendix accessors carry real bodies from here on
|
|
58
|
+
const result = deriver.lower(file, source);
|
|
59
|
+
if (result.diagnostics.length > 0) {
|
|
60
|
+
errors.push(printDiagnostics(result.diagnostics, () => source));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
lowered.push({ file, loweredCode: result.code });
|
|
64
|
+
errors.push(...danglingViewErrors(file, result.meta.views));
|
|
65
|
+
// The wiring import is appended to the TRANSFORM INPUT only — the
|
|
66
|
+
// declarations pass reuses result.code and must never see it. EOF keeps
|
|
67
|
+
// positions intact; the appended line has no counterpart in result.map,
|
|
68
|
+
// so it stays unmapped after the merge.
|
|
69
|
+
const outPath = `${join(out, relative(dir, file))}.js`;
|
|
70
|
+
let emitCode = result.code;
|
|
71
|
+
if (wireConfig) {
|
|
72
|
+
const rel = relative(dirname(outPath), configOutPath).replace(/\\/g, "/");
|
|
73
|
+
emitCode = `${result.code}\nimport ${JSON.stringify(rel.startsWith(".") ? rel : `./${rel}`)};\n`;
|
|
74
|
+
}
|
|
75
|
+
const js = transformSync(emitCode, { loader: "ts", format: "esm", sourcemap: "external", sourcefile: file });
|
|
76
|
+
let consumed = false;
|
|
77
|
+
const merged = remapping(js.map, () => {
|
|
78
|
+
if (consumed)
|
|
79
|
+
return null;
|
|
80
|
+
consumed = true;
|
|
81
|
+
return result.map;
|
|
82
|
+
});
|
|
83
|
+
await mkdir(dirname(outPath), { recursive: true });
|
|
84
|
+
await writeFile(outPath, `${js.code}\n//# sourceMappingURL=${basename(outPath)}.map\n`);
|
|
85
|
+
await writeFile(`${outPath}.map`, merged.toString());
|
|
86
|
+
written.push(outPath, `${outPath}.map`);
|
|
97
87
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
88
|
+
const decl = await emitDeclarationTexts(lowered, sourceRoot, dir, { deriveView: deriver.viewCode });
|
|
89
|
+
for (const [file, declarationText] of decl.tsi) {
|
|
90
|
+
// Next to the built .js in --out (report.tsi.js + report.tsi.d.ts pair
|
|
91
|
+
// under NodeNext), NEVER adjacent to the source: the editor serves
|
|
92
|
+
// .tsi virtually, and an on-disk declaration would only shadow it.
|
|
93
|
+
const dtsPath = `${join(out, relative(dir, file))}.d.ts`;
|
|
94
|
+
await mkdir(dirname(dtsPath), { recursive: true });
|
|
95
|
+
await writeFile(dtsPath, declarationText);
|
|
96
|
+
written.push(dtsPath);
|
|
105
97
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
98
|
+
// Every VIEW the program reached becomes a real `<base>.tsi.js` +
|
|
99
|
+
// `<base>.tsi.d.ts` pair beside the lowered output — the NodeNext pair real
|
|
100
|
+
// .tsi files get — so production output needs no loader at all. The view
|
|
101
|
+
// re-exports `./<base>.js`, so the plain module compiles into the same tree.
|
|
102
|
+
for (const [viewSource, declarationText] of decl.views) {
|
|
103
|
+
const src = resolve(viewSource); // tshost keys views by posix path; `written` stays platform-native
|
|
104
|
+
const base = basename(src).replace(/\.d\.ts$|\.ts$/, "");
|
|
105
|
+
const outDir = join(out, relative(dir, dirname(src)));
|
|
106
|
+
const viewCode = deriver.viewCode(src);
|
|
107
|
+
if (viewCode === undefined) {
|
|
108
|
+
errors.push(`${src}: the view of this module could not be derived (see the diagnostics above)`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const js = transformSync(viewCode, { loader: "ts", format: "esm" });
|
|
112
|
+
await mkdir(outDir, { recursive: true });
|
|
113
|
+
const jsPath = join(outDir, `${base}.tsi.js`);
|
|
114
|
+
const dtsPath = join(outDir, `${base}.tsi.d.ts`);
|
|
115
|
+
await writeFile(jsPath, js.code);
|
|
116
|
+
await writeFile(dtsPath, declarationText);
|
|
117
|
+
written.push(jsPath, dtsPath);
|
|
118
|
+
}
|
|
119
|
+
return { written, errors, warnings };
|
|
123
120
|
}
|
|
124
|
-
return { written, errors };
|
|
125
121
|
}
|
|
126
122
|
//# sourceMappingURL=build.js.map
|
package/dist/check.d.ts
CHANGED
package/dist/check.js
CHANGED
|
@@ -1,71 +1,72 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { originalPositionFor, TraceMap } from "@jridgewell/trace-mapping";
|
|
4
|
-
import { Codes } from "@nola-lang/ast";
|
|
5
|
-
import { compileNola } from "@nola-lang/compiler";
|
|
6
4
|
import { findProjectRoot, loadCompilerOptions } from "@nola-lang/node-loader";
|
|
7
5
|
import ts from "typescript";
|
|
8
|
-
import {
|
|
6
|
+
import { createProjectDeriver } from "./derive.js";
|
|
9
7
|
import { printDiagnostics } from "./diag.js";
|
|
10
8
|
import { createLoweredProgram } from "./tshost.js";
|
|
11
|
-
import {
|
|
9
|
+
import { danglingViewErrors } from "./views.js";
|
|
10
|
+
import { siblingWarning, walkProject } from "./walk.js";
|
|
12
11
|
export async function cmdCheck(dirArg = ".") {
|
|
13
12
|
const dir = resolve(dirArg);
|
|
14
13
|
// Check the same text `nola build` emits, so the two can't drift.
|
|
15
14
|
const sourceRoot = findProjectRoot(dir);
|
|
16
15
|
const { underivableContextType } = await loadCompilerOptions(dir);
|
|
17
16
|
const errors = [];
|
|
18
|
-
const { tsi,
|
|
19
|
-
|
|
20
|
-
errors.push(`${file} ${Codes.ReservedCompanionPath}: the *.nola.* filename namespace is reserved for generated companion modules — rename this file`);
|
|
21
|
-
}
|
|
22
|
-
if (errors.length > 0)
|
|
23
|
-
return { errors };
|
|
17
|
+
const { tsi, siblings } = await walkProject(dir);
|
|
18
|
+
const warnings = siblings.map(siblingWarning);
|
|
24
19
|
const entries = [];
|
|
25
20
|
const maps = new Map();
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return { errors };
|
|
40
|
-
const companionEntries = await collectCompanionEntries(seeds, sourceRoot);
|
|
41
|
-
errors.push(...companionEntries.errors);
|
|
42
|
-
const { program, virtualName } = createLoweredProgram(entries, dir, "check", companionEntries.virtual);
|
|
43
|
-
const virtualToFile = new Map(entries.map((e) => [virtualName(e.file).replace(/\\/g, "/"), e.file]));
|
|
44
|
-
for (const d of ts.getPreEmitDiagnostics(program)) {
|
|
45
|
-
if (!d.file || d.start === undefined)
|
|
46
|
-
continue;
|
|
47
|
-
const fileName = d.file.fileName.replace(/\\/g, "/");
|
|
48
|
-
const message = ts.flattenDiagnosticMessageText(d.messageText, " ");
|
|
49
|
-
const companionSource = companionEntries.sources.get(fileName);
|
|
50
|
-
if (companionSource) {
|
|
51
|
-
// Diagnostics policy: never report into a file the user cannot open.
|
|
52
|
-
errors.push(`${companionSource}:1:1 TS${d.code}: in derived type module: ${message}`);
|
|
53
|
-
continue;
|
|
21
|
+
const deriver = createProjectDeriver(dir, sourceRoot, underivableContextType);
|
|
22
|
+
try {
|
|
23
|
+
for (const file of tsi) {
|
|
24
|
+
const source = await readFile(file, "utf8");
|
|
25
|
+
// phase 1 + the checker pass: NOLA2002 / NOLA2008 arrive with the lowering diagnostics
|
|
26
|
+
const result = deriver.lower(file, source);
|
|
27
|
+
if (result.diagnostics.length > 0) {
|
|
28
|
+
errors.push(printDiagnostics(result.diagnostics, () => source));
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
entries.push({ file, loweredCode: result.code });
|
|
32
|
+
maps.set(file, result.map);
|
|
33
|
+
errors.push(...danglingViewErrors(file, result.meta.views));
|
|
54
34
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
35
|
+
if (entries.length === 0)
|
|
36
|
+
return { errors, warnings };
|
|
37
|
+
const { program, virtualName, views } = createLoweredProgram(entries, dir, "check", sourceRoot, {
|
|
38
|
+
deriveView: deriver.viewCode,
|
|
39
|
+
});
|
|
40
|
+
const virtualToFile = new Map(entries.map((e) => [virtualName(e.file).replace(/\\/g, "/"), e.file]));
|
|
41
|
+
for (const d of ts.getPreEmitDiagnostics(program)) {
|
|
42
|
+
if (!d.file || d.start === undefined)
|
|
43
|
+
continue;
|
|
44
|
+
const fileName = d.file.fileName.replace(/\\/g, "/");
|
|
45
|
+
const message = ts.flattenDiagnosticMessageText(d.messageText, " ");
|
|
46
|
+
const viewSource = views.get(fileName);
|
|
47
|
+
if (viewSource) {
|
|
48
|
+
// Diagnostics policy: never report into a file the user cannot open.
|
|
49
|
+
errors.push(`${viewSource}:1:1 TS${d.code}: in derived type module: ${message}`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const original = virtualToFile.get(fileName);
|
|
53
|
+
if (!original) {
|
|
54
|
+
// A real on-disk file (a plain .ts project root): position it directly.
|
|
55
|
+
const pos = d.file.getLineAndCharacterOfPosition(d.start);
|
|
56
|
+
errors.push(`${d.file.fileName}:${pos.line + 1}:${pos.character + 1} TS${d.code}: ${message}`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const generated = d.file.getLineAndCharacterOfPosition(d.start);
|
|
60
|
+
const tracer = new TraceMap(maps.get(original));
|
|
61
|
+
const pos = originalPositionFor(tracer, { line: generated.line + 1, column: generated.character });
|
|
62
|
+
const line = pos.line ?? generated.line + 1;
|
|
63
|
+
const column = (pos.column ?? generated.character) + 1;
|
|
64
|
+
errors.push(`${original}:${line}:${column} TS${d.code}: ${message}`);
|
|
61
65
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const column = (pos.column ?? generated.character) + 1;
|
|
67
|
-
errors.push(`${original}:${line}:${column} TS${d.code}: ${message}`);
|
|
66
|
+
return { errors, warnings };
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
deriver.dispose();
|
|
68
70
|
}
|
|
69
|
-
return { errors };
|
|
70
71
|
}
|
|
71
72
|
//# sourceMappingURL=check.js.map
|
package/dist/commands.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { type CliIo, type CommandSpec, type Palette } from "create-nola-lang";
|
|
|
6
6
|
export declare function report(label: string, result: {
|
|
7
7
|
written?: string[];
|
|
8
8
|
errors: string[];
|
|
9
|
+
warnings?: string[];
|
|
9
10
|
}, separator: string, io?: CliIo, p?: Palette): number;
|
|
10
11
|
export declare const COMMANDS: readonly CommandSpec[];
|
|
11
12
|
//# sourceMappingURL=commands.d.ts.map
|
package/dist/commands.js
CHANGED
|
@@ -18,6 +18,9 @@ const consoleIo = { log: (m) => console.log(m), error: (m) => console.error(m) }
|
|
|
18
18
|
* summary (exit 0): the file count when it writes, "no errors" otherwise.
|
|
19
19
|
*/
|
|
20
20
|
export function report(label, result, separator, io = consoleIo, p = ansi) {
|
|
21
|
+
// Non-fatal (a same-basename .ts + .tsi pair): stderr, no exit-code change.
|
|
22
|
+
for (const warning of result.warnings ?? [])
|
|
23
|
+
io.error(`warning: ${warning}`);
|
|
21
24
|
if (result.errors.length > 0) {
|
|
22
25
|
io.error(styleDiagnostics(result.errors.join(separator), p));
|
|
23
26
|
return 1;
|
|
@@ -53,10 +56,10 @@ export const COMMANDS = [
|
|
|
53
56
|
}),
|
|
54
57
|
defineCommand({
|
|
55
58
|
name: "skill",
|
|
56
|
-
summary: "write agent skill
|
|
59
|
+
summary: "write the Nola agent skill (.claude/skills, .agents/skills) and/or AGENTS.md into the project",
|
|
57
60
|
args: "install",
|
|
58
61
|
options: {
|
|
59
|
-
agents: { type: "string", description: "claude,
|
|
62
|
+
agents: { type: "string", description: "claude,universal,agents-md | all | none" },
|
|
60
63
|
force: { type: "boolean", description: "replace files stamped by another Nola version" },
|
|
61
64
|
},
|
|
62
65
|
run: ({ positionals: [sub], values }) => cmdSkill(sub, { agents: values.agents, force: values.force }),
|
package/dist/declarations.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/** report.tsi → report.d.tsi.ts, adjacent — TS allowArbitraryExtensions resolves it. */
|
|
2
2
|
export declare function adjacentDeclarationPath(tsiFile: string): string;
|
|
3
|
+
/** models.ts / api.d.ts → models.d.tsi.ts / api.d.tsi.ts: the declaration of the module's VIEW. */
|
|
4
|
+
export declare function adjacentViewDeclarationPath(viewSourceFile: string): string;
|
|
3
5
|
/**
|
|
4
|
-
* Emit <base>.d.tsi.ts next to each .tsi
|
|
5
|
-
* like `next build`)
|
|
6
|
-
*
|
|
7
|
-
* them from roots.
|
|
6
|
+
* Emit <base>.d.tsi.ts next to each .tsi — and next to each plain module
|
|
7
|
+
* reached as a VIEW — so PLAIN tsc (and framework builds like `next build`)
|
|
8
|
+
* resolve `.tsi` imports via allowArbitraryExtensions. The editor hides these
|
|
9
|
+
* when the sibling .tsi exists; `nola check` excludes them from roots.
|
|
8
10
|
*/
|
|
9
11
|
export declare function emitAdjacentDeclarations(dirArg?: string): Promise<{
|
|
10
12
|
written: string[];
|
|
11
13
|
errors: string[];
|
|
14
|
+
warnings: string[];
|
|
12
15
|
}>;
|
|
13
16
|
//# sourceMappingURL=declarations.d.ts.map
|
package/dist/declarations.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { Codes } from "@nola-lang/ast";
|
|
4
|
-
import { compileNola } from "@nola-lang/compiler";
|
|
5
3
|
import { findProjectRoot, loadCompilerOptions } from "@nola-lang/node-loader";
|
|
4
|
+
import { createProjectDeriver } from "./derive.js";
|
|
6
5
|
import { printDiagnostics } from "./diag.js";
|
|
7
6
|
import { emitDeclarationTexts } from "./tshost-declarations.js";
|
|
8
|
-
import {
|
|
7
|
+
import { danglingViewErrors } from "./views.js";
|
|
8
|
+
import { siblingWarning, walkProject } from "./walk.js";
|
|
9
9
|
/** report.tsi → report.d.tsi.ts, adjacent — TS allowArbitraryExtensions resolves it. */
|
|
10
10
|
export function adjacentDeclarationPath(tsiFile) {
|
|
11
11
|
return `${tsiFile.slice(0, -".tsi".length)}.d.tsi.ts`;
|
|
12
12
|
}
|
|
13
|
+
/** models.ts / api.d.ts → models.d.tsi.ts / api.d.tsi.ts: the declaration of the module's VIEW. */
|
|
14
|
+
export function adjacentViewDeclarationPath(viewSourceFile) {
|
|
15
|
+
return `${viewSourceFile.replace(/\.d\.ts$|\.ts$/, "")}.d.tsi.ts`;
|
|
16
|
+
}
|
|
13
17
|
/**
|
|
14
|
-
* Emit <base>.d.tsi.ts next to each .tsi
|
|
15
|
-
* like `next build`)
|
|
16
|
-
*
|
|
17
|
-
* them from roots.
|
|
18
|
+
* Emit <base>.d.tsi.ts next to each .tsi — and next to each plain module
|
|
19
|
+
* reached as a VIEW — so PLAIN tsc (and framework builds like `next build`)
|
|
20
|
+
* resolve `.tsi` imports via allowArbitraryExtensions. The editor hides these
|
|
21
|
+
* when the sibling .tsi exists; `nola check` excludes them from roots.
|
|
18
22
|
*/
|
|
19
23
|
export async function emitAdjacentDeclarations(dirArg = ".") {
|
|
20
24
|
const dir = resolve(dirArg);
|
|
@@ -22,30 +26,38 @@ export async function emitAdjacentDeclarations(dirArg = ".") {
|
|
|
22
26
|
const { underivableContextType } = await loadCompilerOptions(dir);
|
|
23
27
|
const written = [];
|
|
24
28
|
const errors = [];
|
|
25
|
-
const { tsi,
|
|
26
|
-
|
|
27
|
-
errors.push(`${file} ${Codes.ReservedCompanionPath}: the *.nola.* filename namespace is reserved for generated companion modules — rename this file`);
|
|
28
|
-
}
|
|
29
|
-
if (errors.length > 0)
|
|
30
|
-
return { written, errors };
|
|
29
|
+
const { tsi, siblings } = await walkProject(dir);
|
|
30
|
+
const warnings = siblings.map(siblingWarning);
|
|
31
31
|
const lowered = [];
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
const deriver = createProjectDeriver(dir, sourceRoot, underivableContextType);
|
|
33
|
+
let decl;
|
|
34
|
+
try {
|
|
35
|
+
for (const file of tsi) {
|
|
36
|
+
const source = await readFile(file, "utf8");
|
|
37
|
+
const result = deriver.lower(file, source);
|
|
38
|
+
if (result.diagnostics.length > 0) {
|
|
39
|
+
errors.push(printDiagnostics(result.diagnostics, () => source));
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
lowered.push({ file, loweredCode: result.code });
|
|
43
|
+
errors.push(...danglingViewErrors(file, result.meta.views));
|
|
39
44
|
}
|
|
40
|
-
lowered
|
|
41
|
-
|
|
45
|
+
decl = await emitDeclarationTexts(lowered, sourceRoot, dir, { deriveView: deriver.viewCode });
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
deriver.dispose();
|
|
42
49
|
}
|
|
43
|
-
|
|
44
|
-
for (const [file, text] of texts) {
|
|
50
|
+
for (const [file, text] of decl.tsi) {
|
|
45
51
|
const dtsPath = adjacentDeclarationPath(file);
|
|
46
52
|
await writeFile(dtsPath, text);
|
|
47
53
|
written.push(dtsPath);
|
|
48
54
|
}
|
|
49
|
-
|
|
55
|
+
for (const [src, text] of decl.views) {
|
|
56
|
+
// tshost keys views by posix path; `resolve` restores the platform form for `written`
|
|
57
|
+
const dtsPath = adjacentViewDeclarationPath(resolve(src));
|
|
58
|
+
await writeFile(dtsPath, text);
|
|
59
|
+
written.push(dtsPath);
|
|
60
|
+
}
|
|
61
|
+
return { written, errors, warnings };
|
|
50
62
|
}
|
|
51
63
|
//# sourceMappingURL=declarations.js.map
|
package/dist/derive.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type CompileResult } from "@nola-lang/compiler";
|
|
2
|
+
import type { UnderivableContextTypeMode } from "@nola-lang/core";
|
|
3
|
+
import { type DerivationService } from "@nola-lang/derive";
|
|
4
|
+
/**
|
|
5
|
+
* The checker-backed derivation seam of `nola build` / `nola check` /
|
|
6
|
+
* `nola declarations` (emit 15): one DerivationService per command, phase 1
|
|
7
|
+
* → answers → finalize for every `.tsi`, and the finalized view of every plain
|
|
8
|
+
* module the lowered program reaches (fed to tshost through its `deriveView`
|
|
9
|
+
* hook, so the program type-checks the REAL bodies — the UnsupportedType
|
|
10
|
+
* elaboration included — and the emitted `.tsi.js` of a view is complete).
|
|
11
|
+
*/
|
|
12
|
+
export interface ProjectDeriver {
|
|
13
|
+
readonly service: DerivationService;
|
|
14
|
+
/** phase 1 + derive + finalize; `diagnostics` carries NOLA2002 / NOLA2008 next to the parse/lower ones */
|
|
15
|
+
lower(file: string, source: string): CompileResult;
|
|
16
|
+
/** finalized code of the view of `source` (x.ts / x.d.ts), memoized; undefined when the source does not parse */
|
|
17
|
+
viewCode(source: string): string | undefined;
|
|
18
|
+
dispose(): void;
|
|
19
|
+
}
|
|
20
|
+
export declare function createProjectDeriver(projectDir: string, sourceRoot: string, underivableContextType: UnderivableContextTypeMode): ProjectDeriver;
|
|
21
|
+
//# sourceMappingURL=derive.d.ts.map
|
package/dist/derive.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { compileNola, finalizeDerivations } from "@nola-lang/compiler";
|
|
2
|
+
import { createDerivationService } from "@nola-lang/derive";
|
|
3
|
+
export function createProjectDeriver(projectDir, sourceRoot, underivableContextType) {
|
|
4
|
+
const service = createDerivationService({ projectRoot: projectDir, sourceRoot, underivableContextType });
|
|
5
|
+
const views = new Map();
|
|
6
|
+
return {
|
|
7
|
+
service,
|
|
8
|
+
lower(file, source) {
|
|
9
|
+
const phase1 = compileNola(source, file, { sourceRoot, underivableContextType });
|
|
10
|
+
if (phase1.diagnostics.length > 0)
|
|
11
|
+
return phase1;
|
|
12
|
+
return finalizeDerivations(phase1, service.derive(file, phase1).answers, file);
|
|
13
|
+
},
|
|
14
|
+
viewCode(source) {
|
|
15
|
+
const key = source.replace(/\\/g, "/");
|
|
16
|
+
if (!views.has(key)) {
|
|
17
|
+
const view = service.deriveView(source);
|
|
18
|
+
views.set(key, view.code === "" || view.diagnostics.length > 0 ? undefined : view.code);
|
|
19
|
+
}
|
|
20
|
+
return views.get(key);
|
|
21
|
+
},
|
|
22
|
+
dispose() {
|
|
23
|
+
service.dispose();
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=derive.js.map
|
package/dist/skill.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** `nola skill install` — write agent skill
|
|
1
|
+
/** `nola skill install` — write the agent skill (.claude/skills, .agents/skills) and/or AGENTS.md into the current project. */
|
|
2
2
|
export declare function cmdSkill(sub: string | undefined, opts: {
|
|
3
3
|
agents?: string;
|
|
4
4
|
force?: boolean;
|
package/dist/skill.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { runSkillInstall } from "create-nola-lang";
|
|
2
|
-
const USAGE = "nola skill install [--agents claude,
|
|
3
|
-
/** `nola skill install` — write agent skill
|
|
2
|
+
const USAGE = "nola skill install [--agents claude,universal,agents-md | all | none] [--force]";
|
|
3
|
+
/** `nola skill install` — write the agent skill (.claude/skills, .agents/skills) and/or AGENTS.md into the current project. */
|
|
4
4
|
export async function cmdSkill(sub, opts) {
|
|
5
5
|
if (sub !== "install") {
|
|
6
6
|
console.log(USAGE);
|
package/dist/style.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// `path:line:col CODE: message` (build/check/declarations), or `path CODE: message`
|
|
2
|
-
// for
|
|
2
|
+
// for a position-less refusal such as a dangling view import (NOLA2007). The path is everything
|
|
3
3
|
// before the last `:line:col` — a Windows drive letter carries its own colon.
|
|
4
4
|
const HEAD = /^(.+?)(:\d+:\d+)? ((?:NOLA|TS)\d+): /;
|
|
5
5
|
const GUTTER = /^(\d+ \|)( .*)?$/;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { type LoweredEntry } from "./tshost.js";
|
|
1
|
+
import { type LoweredEntry, type LoweredProgramHooks } from "./tshost.js";
|
|
2
|
+
export interface DeclarationTexts {
|
|
3
|
+
/** .tsi source path -> its declaration text */
|
|
4
|
+
tsi: Map<string, string>;
|
|
5
|
+
/** viewed plain-module source path (x.ts / x.d.ts) -> the view's declaration text */
|
|
6
|
+
views: Map<string, string>;
|
|
7
|
+
}
|
|
2
8
|
/**
|
|
3
|
-
* Declaration text per lowered .tsi
|
|
4
|
-
* extracted from cmdBuild so `nola build`
|
|
5
|
-
* `nola declarations` (adjacent d.tsi.ts) cannot drift.
|
|
9
|
+
* Declaration text per lowered .tsi — and per VIEW the program reached —
|
|
10
|
+
* from one shared lowered program, extracted from cmdBuild so `nola build`
|
|
11
|
+
* (--out pairs) and `nola declarations` (adjacent d.tsi.ts) cannot drift.
|
|
6
12
|
*/
|
|
7
|
-
export declare function emitDeclarationTexts(lowered: LoweredEntry[],
|
|
13
|
+
export declare function emitDeclarationTexts(lowered: LoweredEntry[], sourceRoot: string, projectDir: string, hooks?: LoweredProgramHooks): Promise<DeclarationTexts>;
|
|
8
14
|
//# sourceMappingURL=tshost-declarations.d.ts.map
|