@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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -0
  3. package/dist/ambient-stub.d.ts +8 -0
  4. package/dist/ambient-stub.d.ts.map +1 -0
  5. package/dist/ambient-stub.js +71 -0
  6. package/dist/ambient-stub.js.map +1 -0
  7. package/dist/companion-name.d.ts +22 -0
  8. package/dist/companion-name.d.ts.map +1 -0
  9. package/dist/companion-name.js +48 -0
  10. package/dist/companion-name.js.map +1 -0
  11. package/dist/companion.d.ts +22 -0
  12. package/dist/companion.d.ts.map +1 -0
  13. package/dist/companion.js +90 -0
  14. package/dist/companion.js.map +1 -0
  15. package/dist/compile.d.ts +3 -0
  16. package/dist/compile.d.ts.map +1 -0
  17. package/dist/compile.js +33 -0
  18. package/dist/compile.js.map +1 -0
  19. package/dist/index.d.ts +12 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +10 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/lower/Lowerer.d.ts +56 -0
  24. package/dist/lower/Lowerer.d.ts.map +1 -0
  25. package/dist/lower/Lowerer.js +353 -0
  26. package/dist/lower/Lowerer.js.map +1 -0
  27. package/dist/lower/index.d.ts +8 -0
  28. package/dist/lower/index.d.ts.map +1 -0
  29. package/dist/lower/index.js +5 -0
  30. package/dist/lower/index.js.map +1 -0
  31. package/dist/lower/lower.d.ts +2 -0
  32. package/dist/lower/lower.d.ts.map +1 -0
  33. package/dist/lower/lower.js +319 -0
  34. package/dist/lower/lower.js.map +1 -0
  35. package/dist/lower/templates.d.ts +61 -0
  36. package/dist/lower/templates.d.ts.map +1 -0
  37. package/dist/lower/templates.js +70 -0
  38. package/dist/lower/templates.js.map +1 -0
  39. package/dist/lower.d.ts +4 -0
  40. package/dist/lower.d.ts.map +1 -0
  41. package/dist/lower.js +322 -0
  42. package/dist/lower.js.map +1 -0
  43. package/dist/path.d.ts +16 -0
  44. package/dist/path.d.ts.map +1 -0
  45. package/dist/path.js +28 -0
  46. package/dist/path.js.map +1 -0
  47. package/dist/schema-expr.d.ts +61 -0
  48. package/dist/schema-expr.d.ts.map +1 -0
  49. package/dist/schema-expr.js +211 -0
  50. package/dist/schema-expr.js.map +1 -0
  51. package/dist/schema.d.ts +16 -0
  52. package/dist/schema.d.ts.map +1 -0
  53. package/dist/schema.js +152 -0
  54. package/dist/schema.js.map +1 -0
  55. package/dist/spans.d.ts +73 -0
  56. package/dist/spans.d.ts.map +1 -0
  57. package/dist/spans.js +169 -0
  58. package/dist/spans.js.map +1 -0
  59. package/dist/static-config.d.ts +15 -0
  60. package/dist/static-config.d.ts.map +1 -0
  61. package/dist/static-config.js +93 -0
  62. package/dist/static-config.js.map +1 -0
  63. package/dist/types.d.ts +37 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +2 -0
  66. package/dist/types.js.map +1 -0
  67. 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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"}
@@ -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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"}
@@ -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