@nola-lang/compiler 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/ambient-stub.d.ts +8 -0
- package/dist/ambient-stub.d.ts.map +1 -0
- package/dist/ambient-stub.js +71 -0
- package/dist/ambient-stub.js.map +1 -0
- package/dist/companion-name.d.ts +22 -0
- package/dist/companion-name.d.ts.map +1 -0
- package/dist/companion-name.js +48 -0
- package/dist/companion-name.js.map +1 -0
- package/dist/companion.d.ts +22 -0
- package/dist/companion.d.ts.map +1 -0
- package/dist/companion.js +90 -0
- package/dist/companion.js.map +1 -0
- package/dist/compile.d.ts +3 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +33 -0
- package/dist/compile.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/lower/Lowerer.d.ts +56 -0
- package/dist/lower/Lowerer.d.ts.map +1 -0
- package/dist/lower/Lowerer.js +353 -0
- package/dist/lower/Lowerer.js.map +1 -0
- package/dist/lower/index.d.ts +8 -0
- package/dist/lower/index.d.ts.map +1 -0
- package/dist/lower/index.js +5 -0
- package/dist/lower/index.js.map +1 -0
- package/dist/lower/lower.d.ts +2 -0
- package/dist/lower/lower.d.ts.map +1 -0
- package/dist/lower/lower.js +319 -0
- package/dist/lower/lower.js.map +1 -0
- package/dist/lower/templates.d.ts +61 -0
- package/dist/lower/templates.d.ts.map +1 -0
- package/dist/lower/templates.js +70 -0
- package/dist/lower/templates.js.map +1 -0
- package/dist/lower.d.ts +4 -0
- package/dist/lower.d.ts.map +1 -0
- package/dist/lower.js +322 -0
- package/dist/lower.js.map +1 -0
- package/dist/path.d.ts +16 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +28 -0
- package/dist/path.js.map +1 -0
- package/dist/schema-expr.d.ts +61 -0
- package/dist/schema-expr.d.ts.map +1 -0
- package/dist/schema-expr.js +211 -0
- package/dist/schema-expr.js.map +1 -0
- package/dist/schema.d.ts +16 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +152 -0
- package/dist/schema.js.map +1 -0
- package/dist/spans.d.ts +73 -0
- package/dist/spans.d.ts.map +1 -0
- package/dist/spans.js +169 -0
- package/dist/spans.js.map +1 -0
- package/dist/static-config.d.ts +15 -0
- package/dist/static-config.d.ts.map +1 -0
- package/dist/static-config.js +93 -0
- package/dist/static-config.js.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { programBody, } from "@nola-lang/ast";
|
|
2
|
+
import { moduleIdFor } from "./companion-name.js";
|
|
3
|
+
import { jsdocDescription } from "./schema.js";
|
|
4
|
+
export function accessorNameFor(typeName) {
|
|
5
|
+
return `__nola_type_${typeName}`;
|
|
6
|
+
}
|
|
7
|
+
const IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
8
|
+
/**
|
|
9
|
+
* Emit-5/6 companion of deriveSchema: same supported surface, but produces a
|
|
10
|
+
* `__nola.types.*` combinator expression instead of inline JSON. Named
|
|
11
|
+
* registry references become ref() calls — which is what makes recursion
|
|
12
|
+
* legal (toJsonSchema resolves cycles to $defs/$ref at run time) — and named
|
|
13
|
+
* IMPORTS become module-qualified refs bound to companion accessors.
|
|
14
|
+
*/
|
|
15
|
+
export function deriveTypeExpr(t, ctx) {
|
|
16
|
+
const refs = new Set();
|
|
17
|
+
const companions = new Map();
|
|
18
|
+
const result = walk(t, ctx, refs, companions);
|
|
19
|
+
return result.ok ? { ok: true, expr: result.expr, refs, companions } : result;
|
|
20
|
+
}
|
|
21
|
+
/** All named ImportSpecifier bindings (type or value; default/namespace skipped). */
|
|
22
|
+
export function collectTypeImports(ast) {
|
|
23
|
+
const out = new Map();
|
|
24
|
+
const importDecls = programBody(ast).filter((n) => n.type === "ImportDeclaration");
|
|
25
|
+
for (const decl of importDecls) {
|
|
26
|
+
const specifier = decl.source?.value;
|
|
27
|
+
if (!specifier)
|
|
28
|
+
continue;
|
|
29
|
+
const specs = decl.specifiers?.filter((s) => s.type === "ImportSpecifier");
|
|
30
|
+
for (const spec of specs ?? []) {
|
|
31
|
+
const imported = spec.imported;
|
|
32
|
+
const local = spec.local?.name;
|
|
33
|
+
const importedName = imported?.type === "StringLiteral" ? imported.value : imported?.name;
|
|
34
|
+
if (importedName && local)
|
|
35
|
+
out.set(local, { specifier, importedName });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/** Transitively derive accessor bodies for named local types (worklist). */
|
|
41
|
+
export function buildAccessorPlan(entryRefs, ctx) {
|
|
42
|
+
const plan = { accessors: new Map(), companions: new Map(), errors: [] };
|
|
43
|
+
const queue = [...entryRefs];
|
|
44
|
+
while (queue.length > 0) {
|
|
45
|
+
const name = queue.shift();
|
|
46
|
+
if (plan.accessors.has(name))
|
|
47
|
+
continue;
|
|
48
|
+
const decl = ctx.registry.get(name);
|
|
49
|
+
if (!decl)
|
|
50
|
+
continue; // the reference itself was already diagnosed
|
|
51
|
+
plan.accessors.set(name, ""); // reserve slot to break cycles
|
|
52
|
+
const derived = deriveTypeExpr(decl, ctx);
|
|
53
|
+
if (derived.ok) {
|
|
54
|
+
plan.accessors.set(name, derived.expr);
|
|
55
|
+
queue.push(...derived.refs);
|
|
56
|
+
for (const [local, imp] of derived.companions)
|
|
57
|
+
plan.companions.set(local, imp);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
plan.accessors.delete(name);
|
|
61
|
+
plan.errors.push({ name, message: derived.message, node: derived.node });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return plan;
|
|
65
|
+
}
|
|
66
|
+
function walk(t, ctx, refs, companions) {
|
|
67
|
+
switch (t.type) {
|
|
68
|
+
case "TSStringKeyword":
|
|
69
|
+
return { ok: true, expr: "__nola.types.string()" };
|
|
70
|
+
case "TSNumberKeyword":
|
|
71
|
+
return { ok: true, expr: "__nola.types.number()" };
|
|
72
|
+
case "TSBooleanKeyword":
|
|
73
|
+
return { ok: true, expr: "__nola.types.boolean()" };
|
|
74
|
+
case "TSArrayType": {
|
|
75
|
+
const inner = walk(t.elementType, ctx, refs, companions);
|
|
76
|
+
return inner.ok ? { ok: true, expr: `__nola.types.array(${inner.expr})` } : inner;
|
|
77
|
+
}
|
|
78
|
+
case "TSTypeLiteral":
|
|
79
|
+
return walkObject(t.members ?? [], ctx, refs, companions, t);
|
|
80
|
+
case "TSInterfaceDeclaration": {
|
|
81
|
+
const bodyMembers = t.body?.body ?? [];
|
|
82
|
+
return walkObject(bodyMembers, ctx, refs, companions, t);
|
|
83
|
+
}
|
|
84
|
+
case "TSUnionType": {
|
|
85
|
+
const labels = [];
|
|
86
|
+
for (const member of t.types ?? []) {
|
|
87
|
+
const literal = member.type === "TSLiteralType" ? member.literal : undefined;
|
|
88
|
+
if (literal?.type !== "StringLiteral") {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
message: "only unions of string literals are supported in intent schemas",
|
|
92
|
+
node: member,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const value = literal.value ?? "";
|
|
96
|
+
if (!labels.includes(value))
|
|
97
|
+
labels.push(value);
|
|
98
|
+
}
|
|
99
|
+
return { ok: true, expr: `__nola.types.enum([${labels.map((l) => JSON.stringify(l)).join(",")}])` };
|
|
100
|
+
}
|
|
101
|
+
case "TSEnumDeclaration": {
|
|
102
|
+
const decl = t;
|
|
103
|
+
const members = decl.body?.members ?? decl.members ?? [];
|
|
104
|
+
const labels = [];
|
|
105
|
+
for (const member of members) {
|
|
106
|
+
const init = member.initializer;
|
|
107
|
+
if (init?.type !== "StringLiteral") {
|
|
108
|
+
return { ok: false, message: "only string-valued enums are supported in intent schemas", node: member };
|
|
109
|
+
}
|
|
110
|
+
const value = init.value ?? "";
|
|
111
|
+
if (!labels.includes(value))
|
|
112
|
+
labels.push(value);
|
|
113
|
+
}
|
|
114
|
+
return { ok: true, expr: `__nola.types.enum([${labels.map((l) => JSON.stringify(l)).join(",")}])` };
|
|
115
|
+
}
|
|
116
|
+
case "TSTypeReference": {
|
|
117
|
+
const ref = t;
|
|
118
|
+
const typeName = ref.typeName;
|
|
119
|
+
const hasParams = Boolean(ref.typeParameters ?? ref.typeArguments);
|
|
120
|
+
if (typeName?.type !== "Identifier" || hasParams) {
|
|
121
|
+
return {
|
|
122
|
+
ok: false,
|
|
123
|
+
message: `unsupported type for intent schema: ${ctx.source.slice(t.start, t.end)}`,
|
|
124
|
+
node: t,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const name = typeName.name ?? "";
|
|
128
|
+
// Checked before the registry: a dead name must not re-enter refs (that
|
|
129
|
+
// is what makes the prune loop's dead-ref set monotone and terminating).
|
|
130
|
+
if (ctx.lossy && ctx.deadRefs?.has(name)) {
|
|
131
|
+
return { ok: false, message: `type '${name}' has no derivable members`, node: t };
|
|
132
|
+
}
|
|
133
|
+
if (ctx.registry.has(name)) {
|
|
134
|
+
refs.add(name);
|
|
135
|
+
return {
|
|
136
|
+
ok: true,
|
|
137
|
+
expr: `__nola.types.ref(${JSON.stringify(ctx.refQualifier + name)}, ${accessorNameFor(name)})`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const imp = ctx.imports.get(name);
|
|
141
|
+
if (imp) {
|
|
142
|
+
if (!imp.specifier.startsWith("./") && !imp.specifier.startsWith("../")) {
|
|
143
|
+
return {
|
|
144
|
+
ok: false,
|
|
145
|
+
message: `type '${name}' is imported from a package ("${imp.specifier}") — intent schema types must come from project files`,
|
|
146
|
+
node: t,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
companions.set(name, imp);
|
|
150
|
+
const id = moduleIdFor(ctx.importerDisplayFile, imp.specifier);
|
|
151
|
+
return {
|
|
152
|
+
ok: true,
|
|
153
|
+
expr: `__nola.types.ref(${JSON.stringify(`${id}#${imp.importedName}`)}, ${accessorNameFor(name)})`,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// Built-in Date (only when no local declaration or import shadows it):
|
|
157
|
+
// wire format is an ISO 8601 string; the runtime revives it to a Date.
|
|
158
|
+
if (name === "Date")
|
|
159
|
+
return { ok: true, expr: "__nola.types.date()" };
|
|
160
|
+
return {
|
|
161
|
+
ok: false,
|
|
162
|
+
message: `type '${name}' must be a non-generic type alias, interface, or enum declared in this file or imported with a named import`,
|
|
163
|
+
node: t,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
default:
|
|
167
|
+
return { ok: false, message: `unsupported type for intent schema: ${t.type}`, node: t };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function walkObject(members, ctx, refs, companions, owner) {
|
|
171
|
+
const parts = [];
|
|
172
|
+
for (const member of members) {
|
|
173
|
+
if (member.type !== "TSPropertySignature") {
|
|
174
|
+
if (ctx.lossy)
|
|
175
|
+
continue; // prune: methods, index signatures, ... just vanish from the description
|
|
176
|
+
return { ok: false, message: `unsupported member '${member.type}' in intent schema object`, node: member };
|
|
177
|
+
}
|
|
178
|
+
const prop = member;
|
|
179
|
+
const key = prop.key;
|
|
180
|
+
const name = key?.type === "Identifier" ? key.name : key?.type === "StringLiteral" ? key.value : undefined;
|
|
181
|
+
if (!name) {
|
|
182
|
+
if (ctx.lossy)
|
|
183
|
+
continue;
|
|
184
|
+
return { ok: false, message: "unsupported property key in intent schema object", node: member };
|
|
185
|
+
}
|
|
186
|
+
const annotation = prop.typeAnnotation?.typeAnnotation;
|
|
187
|
+
if (!annotation) {
|
|
188
|
+
if (ctx.lossy)
|
|
189
|
+
continue;
|
|
190
|
+
return { ok: false, message: `property '${name}' needs a type annotation`, node: member };
|
|
191
|
+
}
|
|
192
|
+
const inner = walk(annotation, ctx, refs, companions);
|
|
193
|
+
if (!inner.ok) {
|
|
194
|
+
if (ctx.lossy)
|
|
195
|
+
continue;
|
|
196
|
+
return inner;
|
|
197
|
+
}
|
|
198
|
+
let expr = inner.expr;
|
|
199
|
+
if (prop.optional)
|
|
200
|
+
expr = `__nola.types.optional(${expr})`;
|
|
201
|
+
const description = jsdocDescription(member);
|
|
202
|
+
if (description)
|
|
203
|
+
expr = `${expr}.describe(${JSON.stringify(description)})`;
|
|
204
|
+
parts.push(`${IDENT.test(name) ? name : JSON.stringify(name)}: ${expr}`);
|
|
205
|
+
}
|
|
206
|
+
if (parts.length === 0) {
|
|
207
|
+
return { ok: false, message: "empty object types are not useful as intent schemas", node: owner };
|
|
208
|
+
}
|
|
209
|
+
return { ok: true, expr: `__nola.types.object({ ${parts.join(", ")} })` };
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=schema-expr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-expr.js","sourceRoot":"","sources":["../src/schema-expr.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type BaseNode } from "@nola-lang/ast";
|
|
2
|
+
import type { JsonSchema } from "@nola-lang/core";
|
|
3
|
+
export type SchemaResult = {
|
|
4
|
+
ok: true;
|
|
5
|
+
schema: JsonSchema;
|
|
6
|
+
} | {
|
|
7
|
+
ok: false;
|
|
8
|
+
message: string;
|
|
9
|
+
node: BaseNode;
|
|
10
|
+
};
|
|
11
|
+
/** Top-level non-generic `type X = {…}` / `interface X {…}` by name. */
|
|
12
|
+
export declare function collectTypeRegistry(ast: BaseNode): Map<string, BaseNode>;
|
|
13
|
+
/** First JSDoc block (slash-star-star … star-slash) in leadingComments → collapsed description. */
|
|
14
|
+
export declare function jsdocDescription(member: BaseNode): string | undefined;
|
|
15
|
+
export declare function deriveSchema(t: BaseNode, source: string, registry: Map<string, BaseNode>, seen?: Set<string>): SchemaResult;
|
|
16
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAcd,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE7G,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAgBxE;AAED,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAerE;AAED,wBAAgB,YAAY,CAC1B,CAAC,EAAE,QAAQ,EACX,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAC/B,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAC5B,YAAY,CA6Ed"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { programBody, } from "@nola-lang/ast";
|
|
2
|
+
/** Top-level non-generic `type X = {…}` / `interface X {…}` by name. */
|
|
3
|
+
export function collectTypeRegistry(ast) {
|
|
4
|
+
const registry = new Map();
|
|
5
|
+
for (const raw of programBody(ast)) {
|
|
6
|
+
const stmt = (raw.type === "ExportNamedDeclaration" ? raw.declaration : raw) ?? raw;
|
|
7
|
+
if (stmt.type === "TSTypeAliasDeclaration") {
|
|
8
|
+
const alias = stmt;
|
|
9
|
+
if (!alias.typeParameters)
|
|
10
|
+
registry.set(alias.id?.name ?? "", alias.typeAnnotation);
|
|
11
|
+
}
|
|
12
|
+
else if (stmt.type === "TSInterfaceDeclaration") {
|
|
13
|
+
const iface = stmt;
|
|
14
|
+
if (!iface.typeParameters && !iface.extends?.length)
|
|
15
|
+
registry.set(iface.id?.name ?? "", iface);
|
|
16
|
+
}
|
|
17
|
+
else if (stmt.type === "TSEnumDeclaration") {
|
|
18
|
+
registry.set(stmt.id?.name ?? "", stmt);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
registry.delete("");
|
|
22
|
+
return registry;
|
|
23
|
+
}
|
|
24
|
+
/** First JSDoc block (slash-star-star … star-slash) in leadingComments → collapsed description. */
|
|
25
|
+
export function jsdocDescription(member) {
|
|
26
|
+
const comments = member.leadingComments;
|
|
27
|
+
if (!comments)
|
|
28
|
+
return undefined;
|
|
29
|
+
for (const c of comments) {
|
|
30
|
+
if (c.type === "CommentBlock" && c.value.startsWith("*")) {
|
|
31
|
+
const text = c.value
|
|
32
|
+
.split("\n")
|
|
33
|
+
.map((l) => l.replace(/^\s*\*+\s?/, "").trim())
|
|
34
|
+
.filter((l) => l.length > 0)
|
|
35
|
+
.join(" ")
|
|
36
|
+
.trim();
|
|
37
|
+
if (text)
|
|
38
|
+
return text;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
export function deriveSchema(t, source, registry, seen = new Set()) {
|
|
44
|
+
switch (t.type) {
|
|
45
|
+
case "TSStringKeyword":
|
|
46
|
+
return { ok: true, schema: { type: "string" } };
|
|
47
|
+
case "TSNumberKeyword":
|
|
48
|
+
return { ok: true, schema: { type: "number" } };
|
|
49
|
+
case "TSBooleanKeyword":
|
|
50
|
+
return { ok: true, schema: { type: "boolean" } };
|
|
51
|
+
case "TSArrayType": {
|
|
52
|
+
const inner = deriveSchema(t.elementType, source, registry, seen);
|
|
53
|
+
return inner.ok ? { ok: true, schema: { type: "array", items: inner.schema } } : inner;
|
|
54
|
+
}
|
|
55
|
+
case "TSTypeLiteral":
|
|
56
|
+
return deriveObject(t.members ?? [], source, registry, seen, t);
|
|
57
|
+
case "TSInterfaceDeclaration": {
|
|
58
|
+
const bodyMembers = t.body?.body ?? [];
|
|
59
|
+
return deriveObject(bodyMembers, source, registry, seen, t);
|
|
60
|
+
}
|
|
61
|
+
case "TSUnionType": {
|
|
62
|
+
const labels = [];
|
|
63
|
+
for (const member of t.types ?? []) {
|
|
64
|
+
const literal = member.type === "TSLiteralType" ? member.literal : undefined;
|
|
65
|
+
if (literal?.type !== "StringLiteral") {
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
message: "only unions of string literals are supported in intent schemas",
|
|
69
|
+
node: member,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const value = literal.value ?? "";
|
|
73
|
+
if (!labels.includes(value))
|
|
74
|
+
labels.push(value);
|
|
75
|
+
}
|
|
76
|
+
return { ok: true, schema: { type: "string", enum: labels } };
|
|
77
|
+
}
|
|
78
|
+
case "TSEnumDeclaration": {
|
|
79
|
+
const decl = t;
|
|
80
|
+
const members = decl.body?.members ?? decl.members ?? [];
|
|
81
|
+
const labels = [];
|
|
82
|
+
for (const member of members) {
|
|
83
|
+
const init = member.initializer;
|
|
84
|
+
if (init?.type !== "StringLiteral") {
|
|
85
|
+
return { ok: false, message: "only string-valued enums are supported in intent schemas", node: member };
|
|
86
|
+
}
|
|
87
|
+
const value = init.value ?? "";
|
|
88
|
+
if (!labels.includes(value))
|
|
89
|
+
labels.push(value);
|
|
90
|
+
}
|
|
91
|
+
return { ok: true, schema: { type: "string", enum: labels } };
|
|
92
|
+
}
|
|
93
|
+
case "TSTypeReference": {
|
|
94
|
+
const ref = t;
|
|
95
|
+
const typeName = ref.typeName;
|
|
96
|
+
const hasParams = Boolean(ref.typeParameters ?? ref.typeArguments);
|
|
97
|
+
if (typeName?.type !== "Identifier" || hasParams) {
|
|
98
|
+
return { ok: false, message: `unsupported type for intent schema: ${source.slice(t.start, t.end)}`, node: t };
|
|
99
|
+
}
|
|
100
|
+
const name = typeName.name ?? "";
|
|
101
|
+
if (seen.has(name)) {
|
|
102
|
+
return { ok: false, message: `recursive type '${name}' is not supported in intent schemas`, node: t };
|
|
103
|
+
}
|
|
104
|
+
const target = registry.get(name);
|
|
105
|
+
if (!target) {
|
|
106
|
+
// Built-in Date (unshadowed): ISO 8601 string on the wire, revived by
|
|
107
|
+
// the runtime — keep in lockstep with deriveTypeExpr/inferTypes.date.
|
|
108
|
+
if (name === "Date")
|
|
109
|
+
return { ok: true, schema: { type: "string", format: "date-time" } };
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
message: `type '${name}' must be a non-generic type alias or interface declared in the same file`,
|
|
113
|
+
node: t,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const nextSeen = new Set(seen);
|
|
117
|
+
nextSeen.add(name);
|
|
118
|
+
return deriveSchema(target, source, registry, nextSeen);
|
|
119
|
+
}
|
|
120
|
+
default:
|
|
121
|
+
return { ok: false, message: `unsupported type for intent schema: ${t.type}`, node: t };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function deriveObject(members, source, registry, seen, owner) {
|
|
125
|
+
const properties = {};
|
|
126
|
+
const required = [];
|
|
127
|
+
for (const member of members) {
|
|
128
|
+
if (member.type !== "TSPropertySignature") {
|
|
129
|
+
return { ok: false, message: `unsupported member '${member.type}' in intent schema object`, node: member };
|
|
130
|
+
}
|
|
131
|
+
const prop = member;
|
|
132
|
+
const key = prop.key;
|
|
133
|
+
const name = key?.type === "Identifier" ? key.name : key?.type === "StringLiteral" ? key.value : undefined;
|
|
134
|
+
if (!name)
|
|
135
|
+
return { ok: false, message: "unsupported property key in intent schema object", node: member };
|
|
136
|
+
const annotation = prop.typeAnnotation?.typeAnnotation;
|
|
137
|
+
if (!annotation)
|
|
138
|
+
return { ok: false, message: `property '${name}' needs a type annotation`, node: member };
|
|
139
|
+
const inner = deriveSchema(annotation, source, registry, seen);
|
|
140
|
+
if (!inner.ok)
|
|
141
|
+
return inner;
|
|
142
|
+
const description = jsdocDescription(member);
|
|
143
|
+
properties[name] = description ? { ...inner.schema, description } : inner.schema;
|
|
144
|
+
if (!prop.optional)
|
|
145
|
+
required.push(name);
|
|
146
|
+
}
|
|
147
|
+
if (Object.keys(properties).length === 0) {
|
|
148
|
+
return { ok: false, message: "empty object types are not useful as intent schemas", node: owner };
|
|
149
|
+
}
|
|
150
|
+
return { ok: true, schema: { type: "object", properties, required, additionalProperties: false } };
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/spans.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { SourceMap } from "magic-string";
|
|
2
|
+
import MagicString from "magic-string";
|
|
3
|
+
export type SpanKind = "verbatim" | "replaced" | "appendix";
|
|
4
|
+
export interface Span {
|
|
5
|
+
sourceStart: number;
|
|
6
|
+
sourceEnd: number;
|
|
7
|
+
generatedStart: number;
|
|
8
|
+
generatedEnd: number;
|
|
9
|
+
kind: SpanKind;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A source fragment copied byte-identically into replacement text (e.g. the
|
|
13
|
+
* extractor's `<T>` type text re-emitted inside `ExtractIntent<T>`). Anchors
|
|
14
|
+
* ride on top of the span tiling: the source range also belongs to a replaced
|
|
15
|
+
* span (which keeps diagnostics), while the anchor gives the fragment
|
|
16
|
+
* full-feature editor mappings (navigation, hover, completion).
|
|
17
|
+
*/
|
|
18
|
+
export interface Anchor {
|
|
19
|
+
sourceStart: number;
|
|
20
|
+
sourceEnd: number;
|
|
21
|
+
generatedStart: number;
|
|
22
|
+
generatedEnd: number;
|
|
23
|
+
}
|
|
24
|
+
/** A copied fragment declared at edit time: where its bytes came from, and where they sit in `text`. */
|
|
25
|
+
export interface EditAnchor {
|
|
26
|
+
sourceStart: number;
|
|
27
|
+
sourceEnd: number;
|
|
28
|
+
/** offset of the copied bytes within the edit's replacement text */
|
|
29
|
+
textOffset: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Records every MagicString mutation lower() performs so finalize() can
|
|
33
|
+
* reconstruct the generated file as a tiling of spans. meta.spans is the
|
|
34
|
+
* ground truth for editor mappings (spec §4c); the v3 source map stays as
|
|
35
|
+
* derived output for the loader and `nola check`.
|
|
36
|
+
*
|
|
37
|
+
* Only the mutations lower() actually uses are exposed. The correctness
|
|
38
|
+
* anchor is the byte-equality invariant test, not this class: if MagicString
|
|
39
|
+
* ordering ever disagrees with finalize()'s model, spans.test.ts fails.
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* Debugger hygiene for the v3 map: every generated line that BEGINS inside
|
|
43
|
+
* replaced/inserted text gets a line-start segment anchored at the edit's
|
|
44
|
+
* source position. magic-string emits no mappings for inserted text, which
|
|
45
|
+
* leaves whole wrapper lines (the infer-function opener and closer) unmapped;
|
|
46
|
+
* the loader's esbuild merge then attributes such a line to the previous
|
|
47
|
+
* mapped token via esbuild's line-start carry segment — observed as F11 into
|
|
48
|
+
* an infer function displaying the body's LAST line while actually paused in
|
|
49
|
+
* intent construction. With the anchor, the opener pauses display the
|
|
50
|
+
* function header and the closer (including the arrow's return position)
|
|
51
|
+
* displays the close-brace line. The appendix keeps its unmapped contract.
|
|
52
|
+
*/
|
|
53
|
+
export declare function anchorInsertedLines(map: SourceMap, spans: Span[], generated: string, source: string): void;
|
|
54
|
+
export declare class SpanRecorder {
|
|
55
|
+
private readonly s;
|
|
56
|
+
private readonly edits;
|
|
57
|
+
private appendixText;
|
|
58
|
+
private seq;
|
|
59
|
+
constructor(source: string);
|
|
60
|
+
overwrite(start: number, end: number, text: string, anchors?: EditAnchor[]): void;
|
|
61
|
+
remove(start: number, end: number): void;
|
|
62
|
+
appendLeft(pos: number, text: string): void;
|
|
63
|
+
appendRight(pos: number, text: string): void;
|
|
64
|
+
/** The EOF insert (runtime import + accessors). Always the last content. */
|
|
65
|
+
appendix(text: string): void;
|
|
66
|
+
toString(): string;
|
|
67
|
+
generateMap(options: Parameters<MagicString["generateMap"]>[0]): SourceMap;
|
|
68
|
+
finalize(sourceLength: number): {
|
|
69
|
+
spans: Span[];
|
|
70
|
+
anchors: Anchor[];
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=spans.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spans.d.ts","sourceRoot":"","sources":["../src/spans.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAE5D,MAAM,WAAW,IAAI;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wGAAwG;AACxG,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;CACpB;AAYD;;;;;;;;;GASG;AACH;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAoC1G;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAc;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,GAAG,CAAK;gBAEJ,MAAM,EAAE,MAAM;IAI1B,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI;IAKjF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKxC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAK3C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAK5C,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK5B,QAAQ,IAAI,MAAM;IAIlB,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS;IAI1E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE;CA8DrE"}
|
package/dist/spans.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { decode, encode } from "@jridgewell/sourcemap-codec";
|
|
2
|
+
import MagicString from "magic-string";
|
|
3
|
+
/**
|
|
4
|
+
* Records every MagicString mutation lower() performs so finalize() can
|
|
5
|
+
* reconstruct the generated file as a tiling of spans. meta.spans is the
|
|
6
|
+
* ground truth for editor mappings (spec §4c); the v3 source map stays as
|
|
7
|
+
* derived output for the loader and `nola check`.
|
|
8
|
+
*
|
|
9
|
+
* Only the mutations lower() actually uses are exposed. The correctness
|
|
10
|
+
* anchor is the byte-equality invariant test, not this class: if MagicString
|
|
11
|
+
* ordering ever disagrees with finalize()'s model, spans.test.ts fails.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Debugger hygiene for the v3 map: every generated line that BEGINS inside
|
|
15
|
+
* replaced/inserted text gets a line-start segment anchored at the edit's
|
|
16
|
+
* source position. magic-string emits no mappings for inserted text, which
|
|
17
|
+
* leaves whole wrapper lines (the infer-function opener and closer) unmapped;
|
|
18
|
+
* the loader's esbuild merge then attributes such a line to the previous
|
|
19
|
+
* mapped token via esbuild's line-start carry segment — observed as F11 into
|
|
20
|
+
* an infer function displaying the body's LAST line while actually paused in
|
|
21
|
+
* intent construction. With the anchor, the opener pauses display the
|
|
22
|
+
* function header and the closer (including the arrow's return position)
|
|
23
|
+
* displays the close-brace line. The appendix keeps its unmapped contract.
|
|
24
|
+
*/
|
|
25
|
+
export function anchorInsertedLines(map, spans, generated, source) {
|
|
26
|
+
const lineStartsOf = (text) => {
|
|
27
|
+
const starts = [0];
|
|
28
|
+
for (let i = 0; i < text.length; i++)
|
|
29
|
+
if (text[i] === "\n")
|
|
30
|
+
starts.push(i + 1);
|
|
31
|
+
return starts;
|
|
32
|
+
};
|
|
33
|
+
const lineOf = (starts, offset) => {
|
|
34
|
+
let lo = 0;
|
|
35
|
+
let hi = starts.length - 1;
|
|
36
|
+
while (lo < hi) {
|
|
37
|
+
const mid = (lo + hi + 1) >> 1;
|
|
38
|
+
if (starts[mid] <= offset)
|
|
39
|
+
lo = mid;
|
|
40
|
+
else
|
|
41
|
+
hi = mid - 1;
|
|
42
|
+
}
|
|
43
|
+
return lo;
|
|
44
|
+
};
|
|
45
|
+
const genStarts = lineStartsOf(generated);
|
|
46
|
+
const srcStarts = lineStartsOf(source);
|
|
47
|
+
const decoded = decode(map.mappings);
|
|
48
|
+
let changed = false;
|
|
49
|
+
for (const sp of spans) {
|
|
50
|
+
if (sp.kind !== "replaced")
|
|
51
|
+
continue;
|
|
52
|
+
const srcLine = lineOf(srcStarts, sp.sourceStart);
|
|
53
|
+
const srcCol = sp.sourceStart - srcStarts[srcLine];
|
|
54
|
+
let line = lineOf(genStarts, sp.generatedStart);
|
|
55
|
+
if (genStarts[line] < sp.generatedStart)
|
|
56
|
+
line += 1;
|
|
57
|
+
for (; line < genStarts.length && genStarts[line] < sp.generatedEnd; line++) {
|
|
58
|
+
while (decoded.length <= line)
|
|
59
|
+
decoded.push([]);
|
|
60
|
+
const segs = decoded[line];
|
|
61
|
+
if (segs.length === 0 || segs[0][0] > 0) {
|
|
62
|
+
segs.unshift([0, 0, srcLine, srcCol]);
|
|
63
|
+
changed = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (changed)
|
|
68
|
+
map.mappings = encode(decoded);
|
|
69
|
+
}
|
|
70
|
+
export class SpanRecorder {
|
|
71
|
+
s;
|
|
72
|
+
edits = [];
|
|
73
|
+
appendixText = "";
|
|
74
|
+
seq = 0;
|
|
75
|
+
constructor(source) {
|
|
76
|
+
this.s = new MagicString(source);
|
|
77
|
+
}
|
|
78
|
+
overwrite(start, end, text, anchors) {
|
|
79
|
+
this.s.overwrite(start, end, text);
|
|
80
|
+
this.edits.push({ sourceStart: start, sourceEnd: end, text, side: 0, seq: this.seq++, anchors });
|
|
81
|
+
}
|
|
82
|
+
remove(start, end) {
|
|
83
|
+
this.s.remove(start, end);
|
|
84
|
+
this.edits.push({ sourceStart: start, sourceEnd: end, text: "", side: 0, seq: this.seq++ });
|
|
85
|
+
}
|
|
86
|
+
appendLeft(pos, text) {
|
|
87
|
+
this.s.appendLeft(pos, text);
|
|
88
|
+
this.edits.push({ sourceStart: pos, sourceEnd: pos, text, side: 0, seq: this.seq++ });
|
|
89
|
+
}
|
|
90
|
+
appendRight(pos, text) {
|
|
91
|
+
this.s.appendRight(pos, text);
|
|
92
|
+
this.edits.push({ sourceStart: pos, sourceEnd: pos, text, side: 1, seq: this.seq++ });
|
|
93
|
+
}
|
|
94
|
+
/** The EOF insert (runtime import + accessors). Always the last content. */
|
|
95
|
+
appendix(text) {
|
|
96
|
+
this.s.append(text);
|
|
97
|
+
this.appendixText += text;
|
|
98
|
+
}
|
|
99
|
+
toString() {
|
|
100
|
+
return this.s.toString();
|
|
101
|
+
}
|
|
102
|
+
generateMap(options) {
|
|
103
|
+
return this.s.generateMap(options);
|
|
104
|
+
}
|
|
105
|
+
finalize(sourceLength) {
|
|
106
|
+
// MagicString emission order at a shared position: appendLeft content
|
|
107
|
+
// precedes appendRight content; same-side calls emit in call order.
|
|
108
|
+
// Sorting by (sourceStart, side, seq) reproduces that order.
|
|
109
|
+
const edits = [...this.edits].sort((a, b) => a.sourceStart - b.sourceStart || a.side - b.side || a.seq - b.seq);
|
|
110
|
+
const spans = [];
|
|
111
|
+
const anchors = [];
|
|
112
|
+
let src = 0;
|
|
113
|
+
let gen = 0;
|
|
114
|
+
const pushVerbatim = (to) => {
|
|
115
|
+
if (to > src) {
|
|
116
|
+
spans.push({
|
|
117
|
+
sourceStart: src,
|
|
118
|
+
sourceEnd: to,
|
|
119
|
+
generatedStart: gen,
|
|
120
|
+
generatedEnd: gen + (to - src),
|
|
121
|
+
kind: "verbatim",
|
|
122
|
+
});
|
|
123
|
+
gen += to - src;
|
|
124
|
+
src = to;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
for (const e of edits) {
|
|
128
|
+
pushVerbatim(e.sourceStart);
|
|
129
|
+
for (const a of e.anchors ?? []) {
|
|
130
|
+
anchors.push({
|
|
131
|
+
sourceStart: a.sourceStart,
|
|
132
|
+
sourceEnd: a.sourceEnd,
|
|
133
|
+
generatedStart: gen + a.textOffset,
|
|
134
|
+
generatedEnd: gen + a.textOffset + (a.sourceEnd - a.sourceStart),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const prev = spans[spans.length - 1];
|
|
138
|
+
if (prev && prev.kind === "replaced" && prev.sourceEnd === e.sourceStart && prev.generatedEnd === gen) {
|
|
139
|
+
// Coalesce adjacent replacements (e.g. an extract suffix appendLeft
|
|
140
|
+
// and the enclosing ask's appendRight at the same position).
|
|
141
|
+
prev.sourceEnd = e.sourceEnd;
|
|
142
|
+
prev.generatedEnd += e.text.length;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
spans.push({
|
|
146
|
+
sourceStart: e.sourceStart,
|
|
147
|
+
sourceEnd: e.sourceEnd,
|
|
148
|
+
generatedStart: gen,
|
|
149
|
+
generatedEnd: gen + e.text.length,
|
|
150
|
+
kind: "replaced",
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
gen += e.text.length;
|
|
154
|
+
src = Math.max(src, e.sourceEnd);
|
|
155
|
+
}
|
|
156
|
+
pushVerbatim(sourceLength);
|
|
157
|
+
if (this.appendixText.length > 0) {
|
|
158
|
+
spans.push({
|
|
159
|
+
sourceStart: sourceLength,
|
|
160
|
+
sourceEnd: sourceLength,
|
|
161
|
+
generatedStart: gen,
|
|
162
|
+
generatedEnd: gen + this.appendixText.length,
|
|
163
|
+
kind: "appendix",
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return { spans, anchors };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=spans.js.map
|