@chanmeng666/archlang 0.1.0 → 0.2.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/dist/{chunk-J5DEA2KQ.js → chunk-ICYNEDSM.js} +237 -108
- package/dist/chunk-ICYNEDSM.js.map +1 -0
- package/dist/cli.js +13 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +69 -9
- package/dist/index.js +7 -3
- package/package.json +65 -64
- package/dist/chunk-J5DEA2KQ.js.map +0 -1
|
@@ -19,11 +19,12 @@ function lex(src) {
|
|
|
19
19
|
}
|
|
20
20
|
return c;
|
|
21
21
|
};
|
|
22
|
-
const push = (type, value, startLine, startCol, extra) => tokens.push({ type, value, line: startLine, col: startCol, ...extra });
|
|
22
|
+
const push = (type, value, startLine, startCol, startIdx, extra) => tokens.push({ type, value, line: startLine, col: startCol, ...extra, start: startIdx, end: i });
|
|
23
23
|
while (i < src.length) {
|
|
24
24
|
const c = peek();
|
|
25
25
|
const startLine = line;
|
|
26
26
|
const startCol = col;
|
|
27
|
+
const startIdx = i;
|
|
27
28
|
if (c === " " || c === " " || c === "\r" || c === "\n") {
|
|
28
29
|
advance();
|
|
29
30
|
continue;
|
|
@@ -53,50 +54,50 @@ function lex(src) {
|
|
|
53
54
|
value += advance();
|
|
54
55
|
}
|
|
55
56
|
if (!terminated) {
|
|
56
|
-
errors.push({ message: "Unterminated string literal",
|
|
57
|
+
errors.push({ message: "Unterminated string literal", span: { start: startIdx, end: i } });
|
|
57
58
|
}
|
|
58
|
-
push("string", value, startLine, startCol);
|
|
59
|
+
push("string", value, startLine, startCol, startIdx);
|
|
59
60
|
continue;
|
|
60
61
|
}
|
|
61
62
|
if (c === "(") {
|
|
62
63
|
advance();
|
|
63
|
-
push("lparen", "(", startLine, startCol);
|
|
64
|
+
push("lparen", "(", startLine, startCol, startIdx);
|
|
64
65
|
continue;
|
|
65
66
|
}
|
|
66
67
|
if (c === ")") {
|
|
67
68
|
advance();
|
|
68
|
-
push("rparen", ")", startLine, startCol);
|
|
69
|
+
push("rparen", ")", startLine, startCol, startIdx);
|
|
69
70
|
continue;
|
|
70
71
|
}
|
|
71
72
|
if (c === "{") {
|
|
72
73
|
advance();
|
|
73
|
-
push("lcurly", "{", startLine, startCol);
|
|
74
|
+
push("lcurly", "{", startLine, startCol, startIdx);
|
|
74
75
|
continue;
|
|
75
76
|
}
|
|
76
77
|
if (c === "}") {
|
|
77
78
|
advance();
|
|
78
|
-
push("rcurly", "}", startLine, startCol);
|
|
79
|
+
push("rcurly", "}", startLine, startCol, startIdx);
|
|
79
80
|
continue;
|
|
80
81
|
}
|
|
81
82
|
if (c === ",") {
|
|
82
83
|
advance();
|
|
83
|
-
push("comma", ",", startLine, startCol);
|
|
84
|
+
push("comma", ",", startLine, startCol, startIdx);
|
|
84
85
|
continue;
|
|
85
86
|
}
|
|
86
87
|
if (c === "=") {
|
|
87
88
|
advance();
|
|
88
|
-
push("equals", "=", startLine, startCol);
|
|
89
|
+
push("equals", "=", startLine, startCol, startIdx);
|
|
89
90
|
continue;
|
|
90
91
|
}
|
|
91
92
|
if (c === ":") {
|
|
92
93
|
advance();
|
|
93
|
-
push("colon", ":", startLine, startCol);
|
|
94
|
+
push("colon", ":", startLine, startCol, startIdx);
|
|
94
95
|
continue;
|
|
95
96
|
}
|
|
96
97
|
if (c === "-" && peek(1) === ">") {
|
|
97
98
|
advance();
|
|
98
99
|
advance();
|
|
99
|
-
push("arrow", "->", startLine, startCol);
|
|
100
|
+
push("arrow", "->", startLine, startCol, startIdx);
|
|
100
101
|
continue;
|
|
101
102
|
}
|
|
102
103
|
if (isDigit(c) || c === "-" && isDigit(peek(1)) || c === "." && isDigit(peek(1))) {
|
|
@@ -118,52 +119,67 @@ function lex(src) {
|
|
|
118
119
|
while (isDigit(peek())) raw2 += advance();
|
|
119
120
|
}
|
|
120
121
|
const second = parseFloat(raw2);
|
|
121
|
-
push("dimension", `${raw}x${raw2}`, startLine, startCol, { num: first, num2: second });
|
|
122
|
+
push("dimension", `${raw}x${raw2}`, startLine, startCol, startIdx, { num: first, num2: second });
|
|
122
123
|
continue;
|
|
123
124
|
}
|
|
124
|
-
push("number", raw, startLine, startCol, { num: first });
|
|
125
|
+
push("number", raw, startLine, startCol, startIdx, { num: first });
|
|
125
126
|
continue;
|
|
126
127
|
}
|
|
127
128
|
if (isIdentStart(c)) {
|
|
128
129
|
let value = "";
|
|
129
130
|
while (i < src.length && isIdentPart(peek())) value += advance();
|
|
130
|
-
push("ident", value, startLine, startCol);
|
|
131
|
+
push("ident", value, startLine, startCol, startIdx);
|
|
131
132
|
continue;
|
|
132
133
|
}
|
|
133
|
-
errors.push({ message: `Unexpected character ${JSON.stringify(c)}`,
|
|
134
|
+
errors.push({ message: `Unexpected character ${JSON.stringify(c)}`, span: { start: startIdx, end: startIdx + 1 } });
|
|
134
135
|
advance();
|
|
135
136
|
}
|
|
136
|
-
push("eof", "", line, col);
|
|
137
|
+
push("eof", "", line, col, i);
|
|
137
138
|
return { tokens, errors };
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
// src/parser.ts
|
|
142
|
+
var STATEMENT_STARTS = /* @__PURE__ */ new Set([
|
|
143
|
+
"units",
|
|
144
|
+
"grid",
|
|
145
|
+
"scale",
|
|
146
|
+
"north",
|
|
147
|
+
"wall",
|
|
148
|
+
"room",
|
|
149
|
+
"door",
|
|
150
|
+
"window",
|
|
151
|
+
"furniture",
|
|
152
|
+
"dim",
|
|
153
|
+
"title"
|
|
154
|
+
]);
|
|
141
155
|
var ParseError = class extends Error {
|
|
142
|
-
constructor(message,
|
|
156
|
+
constructor(message, span) {
|
|
143
157
|
super(message);
|
|
144
158
|
this.message = message;
|
|
145
|
-
this.
|
|
146
|
-
this.col = col;
|
|
159
|
+
this.span = span;
|
|
147
160
|
}
|
|
148
161
|
message;
|
|
149
|
-
|
|
150
|
-
col;
|
|
162
|
+
span;
|
|
151
163
|
};
|
|
152
164
|
function parse(src) {
|
|
153
165
|
const { tokens, errors: lexErrors } = lex(src);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
166
|
+
const lexDiags = lexErrors.map((e) => ({
|
|
167
|
+
severity: "error",
|
|
168
|
+
message: e.message,
|
|
169
|
+
span: e.span
|
|
170
|
+
}));
|
|
171
|
+
const p = new Parser(tokens);
|
|
172
|
+
let plan;
|
|
157
173
|
try {
|
|
158
|
-
|
|
159
|
-
const plan = p.parsePlan();
|
|
160
|
-
return { plan, errors: [] };
|
|
174
|
+
plan = p.parsePlan();
|
|
161
175
|
} catch (e) {
|
|
162
176
|
if (e instanceof ParseError) {
|
|
163
|
-
|
|
177
|
+
p.diagnostics.push({ severity: "error", message: e.message, span: e.span });
|
|
178
|
+
} else {
|
|
179
|
+
throw e;
|
|
164
180
|
}
|
|
165
|
-
throw e;
|
|
166
181
|
}
|
|
182
|
+
return { plan, diagnostics: [...lexDiags, ...p.diagnostics] };
|
|
167
183
|
}
|
|
168
184
|
var Parser = class {
|
|
169
185
|
constructor(toks) {
|
|
@@ -171,6 +187,7 @@ var Parser = class {
|
|
|
171
187
|
}
|
|
172
188
|
toks;
|
|
173
189
|
pos = 0;
|
|
190
|
+
diagnostics = [];
|
|
174
191
|
peek(o = 0) {
|
|
175
192
|
return this.toks[Math.min(this.pos + o, this.toks.length - 1)];
|
|
176
193
|
}
|
|
@@ -178,7 +195,21 @@ var Parser = class {
|
|
|
178
195
|
return this.toks[Math.min(this.pos++, this.toks.length - 1)];
|
|
179
196
|
}
|
|
180
197
|
fail(msg, t = this.peek()) {
|
|
181
|
-
throw new ParseError(msg, t.
|
|
198
|
+
throw new ParseError(msg, { start: t.start, end: t.end });
|
|
199
|
+
}
|
|
200
|
+
/** Span from a start offset to the end of the last consumed token. */
|
|
201
|
+
spanFrom(start) {
|
|
202
|
+
const last = this.toks[Math.max(0, Math.min(this.pos - 1, this.toks.length - 1))];
|
|
203
|
+
return { start, end: last.end };
|
|
204
|
+
}
|
|
205
|
+
/** Recover after a statement error: skip to the next statement start or block end. */
|
|
206
|
+
synchronize() {
|
|
207
|
+
if (!this.isType("rcurly") && !this.isType("eof")) this.next();
|
|
208
|
+
while (!this.isType("rcurly") && !this.isType("eof")) {
|
|
209
|
+
const t = this.peek();
|
|
210
|
+
if (t.type === "ident" && STATEMENT_STARTS.has(t.value)) return;
|
|
211
|
+
this.next();
|
|
212
|
+
}
|
|
182
213
|
}
|
|
183
214
|
isKeyword(kw, o = 0) {
|
|
184
215
|
const t = this.peek(o);
|
|
@@ -222,57 +253,96 @@ var Parser = class {
|
|
|
222
253
|
};
|
|
223
254
|
while (!this.isType("rcurly") && !this.isType("eof")) {
|
|
224
255
|
const t = this.peek();
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
256
|
+
const start = t.start;
|
|
257
|
+
try {
|
|
258
|
+
if (t.type !== "ident") this.fail(`Expected a statement but found ${describe(t)}`);
|
|
259
|
+
switch (t.value) {
|
|
260
|
+
case "units": {
|
|
261
|
+
this.next();
|
|
262
|
+
const u = this.eatIdent().value;
|
|
263
|
+
if (u !== "mm") this.fail(`Unsupported units "${u}" (only "mm" is supported)`, t);
|
|
264
|
+
plan.units = "mm";
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
case "grid":
|
|
268
|
+
this.next();
|
|
269
|
+
plan.grid = this.eatNumber();
|
|
270
|
+
break;
|
|
271
|
+
case "scale": {
|
|
272
|
+
this.next();
|
|
273
|
+
const a = this.eatNumber();
|
|
274
|
+
this.eat("colon");
|
|
275
|
+
const b = this.eatNumber();
|
|
276
|
+
plan.scale = `${a}:${b}`;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
case "north":
|
|
280
|
+
this.next();
|
|
281
|
+
plan.north = this.parseNorth();
|
|
282
|
+
break;
|
|
283
|
+
case "wall": {
|
|
284
|
+
const n = this.parseWall();
|
|
285
|
+
n.span = this.spanFrom(start);
|
|
286
|
+
plan.walls.push(n);
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
case "room": {
|
|
290
|
+
const n = this.parseRoom();
|
|
291
|
+
n.span = this.spanFrom(start);
|
|
292
|
+
plan.rooms.push(n);
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
case "door": {
|
|
296
|
+
const n = this.parseDoor();
|
|
297
|
+
n.span = this.spanFrom(start);
|
|
298
|
+
plan.doors.push(n);
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case "window": {
|
|
302
|
+
const n = this.parseWindow();
|
|
303
|
+
n.span = this.spanFrom(start);
|
|
304
|
+
plan.windows.push(n);
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
case "furniture": {
|
|
308
|
+
const n = this.parseFurniture();
|
|
309
|
+
n.span = this.spanFrom(start);
|
|
310
|
+
plan.furniture.push(n);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
case "dim": {
|
|
314
|
+
const n = this.parseDim();
|
|
315
|
+
n.span = this.spanFrom(start);
|
|
316
|
+
plan.dims.push(n);
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
case "title": {
|
|
320
|
+
const n = this.parseTitle();
|
|
321
|
+
n.span = this.spanFrom(start);
|
|
322
|
+
plan.title = n;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
default:
|
|
326
|
+
this.fail(`Unknown statement "${t.value}"`, t);
|
|
233
327
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const a = this.eatNumber();
|
|
241
|
-
this.eat("colon");
|
|
242
|
-
const b = this.eatNumber();
|
|
243
|
-
plan.scale = `${a}:${b}`;
|
|
244
|
-
break;
|
|
328
|
+
} catch (e) {
|
|
329
|
+
if (e instanceof ParseError) {
|
|
330
|
+
this.diagnostics.push({ severity: "error", message: e.message, span: e.span });
|
|
331
|
+
this.synchronize();
|
|
332
|
+
} else {
|
|
333
|
+
throw e;
|
|
245
334
|
}
|
|
246
|
-
case "north":
|
|
247
|
-
this.next();
|
|
248
|
-
plan.north = this.parseNorth();
|
|
249
|
-
break;
|
|
250
|
-
case "wall":
|
|
251
|
-
plan.walls.push(this.parseWall());
|
|
252
|
-
break;
|
|
253
|
-
case "room":
|
|
254
|
-
plan.rooms.push(this.parseRoom());
|
|
255
|
-
break;
|
|
256
|
-
case "door":
|
|
257
|
-
plan.doors.push(this.parseDoor());
|
|
258
|
-
break;
|
|
259
|
-
case "window":
|
|
260
|
-
plan.windows.push(this.parseWindow());
|
|
261
|
-
break;
|
|
262
|
-
case "furniture":
|
|
263
|
-
plan.furniture.push(this.parseFurniture());
|
|
264
|
-
break;
|
|
265
|
-
case "dim":
|
|
266
|
-
plan.dims.push(this.parseDim());
|
|
267
|
-
break;
|
|
268
|
-
case "title":
|
|
269
|
-
plan.title = this.parseTitle();
|
|
270
|
-
break;
|
|
271
|
-
default:
|
|
272
|
-
this.fail(`Unknown statement "${t.value}"`, t);
|
|
273
335
|
}
|
|
274
336
|
}
|
|
275
|
-
|
|
337
|
+
try {
|
|
338
|
+
this.eat("rcurly");
|
|
339
|
+
} catch (e) {
|
|
340
|
+
if (e instanceof ParseError) {
|
|
341
|
+
this.diagnostics.push({ severity: "error", message: e.message, span: e.span });
|
|
342
|
+
} else {
|
|
343
|
+
throw e;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
276
346
|
return plan;
|
|
277
347
|
}
|
|
278
348
|
isType(type) {
|
|
@@ -561,8 +631,9 @@ function planBounds(plan) {
|
|
|
561
631
|
|
|
562
632
|
// src/validate.ts
|
|
563
633
|
function validate(plan) {
|
|
564
|
-
const
|
|
565
|
-
const
|
|
634
|
+
const diags = [];
|
|
635
|
+
const error = (message, code, span) => diags.push({ severity: "error", message, code, span });
|
|
636
|
+
const warn = (message, code, span) => diags.push({ severity: "warning", message, code, span });
|
|
566
637
|
const g = plan.grid;
|
|
567
638
|
const snap = (v) => g > 0 ? Math.round(v / g) * g : v;
|
|
568
639
|
const snapPt = (p) => ({ x: snap(p.x), y: snap(p.y) });
|
|
@@ -591,10 +662,10 @@ function validate(plan) {
|
|
|
591
662
|
dm.to = snapPt(dm.to);
|
|
592
663
|
}
|
|
593
664
|
const seen = /* @__PURE__ */ new Set();
|
|
594
|
-
const assign = (provided, prefix, idx,
|
|
665
|
+
const assign = (provided, prefix, idx, span) => {
|
|
595
666
|
if (provided) {
|
|
596
667
|
if (seen.has(provided)) {
|
|
597
|
-
|
|
668
|
+
error(`Duplicate id "${provided}"`, "E_DUP_ID", span);
|
|
598
669
|
}
|
|
599
670
|
seen.add(provided);
|
|
600
671
|
return provided;
|
|
@@ -604,32 +675,32 @@ function validate(plan) {
|
|
|
604
675
|
seen.add(auto);
|
|
605
676
|
return auto;
|
|
606
677
|
};
|
|
607
|
-
plan.walls.forEach((w, i) => w.id = assign(w.id, w.kind || "wall", i + 1, w.
|
|
608
|
-
plan.rooms.forEach((r, i) => r.id = assign(r.id, "room", i + 1, r.
|
|
609
|
-
plan.doors.forEach((d, i) => d.id = assign(d.id, "door", i + 1, d.
|
|
610
|
-
plan.windows.forEach((w, i) => w.id = assign(w.id, "window", i + 1, w.
|
|
611
|
-
plan.furniture.forEach((f, i) => f.id = assign(f.id, f.kind || "furniture", i + 1, f.
|
|
612
|
-
plan.dims.forEach((d, i) => d.id = assign(d.id, "dim", i + 1, d.
|
|
678
|
+
plan.walls.forEach((w, i) => w.id = assign(w.id, w.kind || "wall", i + 1, w.span));
|
|
679
|
+
plan.rooms.forEach((r, i) => r.id = assign(r.id, "room", i + 1, r.span));
|
|
680
|
+
plan.doors.forEach((d, i) => d.id = assign(d.id, "door", i + 1, d.span));
|
|
681
|
+
plan.windows.forEach((w, i) => w.id = assign(w.id, "window", i + 1, w.span));
|
|
682
|
+
plan.furniture.forEach((f, i) => f.id = assign(f.id, f.kind || "furniture", i + 1, f.span));
|
|
683
|
+
plan.dims.forEach((d, i) => d.id = assign(d.id, "dim", i + 1, d.span));
|
|
613
684
|
for (const r of plan.rooms) {
|
|
614
685
|
if (r.size.w <= 0 || r.size.h <= 0)
|
|
615
|
-
|
|
686
|
+
error(`Room "${r.id}" must have a positive size`, "E_ROOM_SIZE", r.span);
|
|
616
687
|
}
|
|
617
688
|
for (const f of plan.furniture) {
|
|
618
689
|
if (f.size.w <= 0 || f.size.h <= 0)
|
|
619
|
-
|
|
690
|
+
error(`Furniture "${f.id}" must have a positive size`, "E_FURN_SIZE", f.span);
|
|
620
691
|
}
|
|
621
692
|
for (const d of plan.doors) {
|
|
622
|
-
if (d.width <= 0)
|
|
693
|
+
if (d.width <= 0) error(`Door "${d.id}" must have a positive width`, "E_DOOR_WIDTH", d.span);
|
|
623
694
|
}
|
|
624
695
|
for (const w of plan.windows) {
|
|
625
|
-
if (w.width <= 0)
|
|
696
|
+
if (w.width <= 0) error(`Window "${w.id}" must have a positive width`, "E_WINDOW_WIDTH", w.span);
|
|
626
697
|
}
|
|
627
698
|
for (const w of plan.walls) {
|
|
628
699
|
if (w.thickness <= 0)
|
|
629
|
-
|
|
700
|
+
error(`Wall "${w.id}" must have a positive thickness`, "E_WALL_THICKNESS", w.span);
|
|
630
701
|
}
|
|
631
702
|
if (plan.walls.length === 0 && plan.rooms.length === 0 && plan.furniture.length === 0) {
|
|
632
|
-
|
|
703
|
+
warn("Plan has no walls, rooms, or furniture \u2014 nothing to draw", "W_EMPTY_PLAN");
|
|
633
704
|
}
|
|
634
705
|
const onSomeWall = (at, wallRef) => {
|
|
635
706
|
const candidates = wallRef ? plan.walls.filter((w) => w.id === wallRef || w.kind === wallRef) : plan.walls;
|
|
@@ -646,11 +717,11 @@ function validate(plan) {
|
|
|
646
717
|
};
|
|
647
718
|
for (const d of plan.doors) {
|
|
648
719
|
if (plan.walls.length > 0 && !onSomeWall(d.at, d.wall))
|
|
649
|
-
|
|
720
|
+
warn(`Door "${d.id}" does not lie on any wall`, "W_DOOR_OFF_WALL", d.span);
|
|
650
721
|
}
|
|
651
722
|
for (const w of plan.windows) {
|
|
652
723
|
if (plan.walls.length > 0 && !onSomeWall(w.at, w.wall))
|
|
653
|
-
|
|
724
|
+
warn(`Window "${w.id}" does not lie on any wall`, "W_WINDOW_OFF_WALL", w.span);
|
|
654
725
|
}
|
|
655
726
|
for (let a = 0; a < plan.rooms.length; a++) {
|
|
656
727
|
for (let b = a + 1; b < plan.rooms.length; b++) {
|
|
@@ -659,11 +730,11 @@ function validate(plan) {
|
|
|
659
730
|
const ox = Math.max(0, Math.min(r1.at.x + r1.size.w, r2.at.x + r2.size.w) - Math.max(r1.at.x, r2.at.x));
|
|
660
731
|
const oy = Math.max(0, Math.min(r1.at.y + r1.size.h, r2.at.y + r2.size.h) - Math.max(r1.at.y, r2.at.y));
|
|
661
732
|
if (ox > 1 && oy > 1) {
|
|
662
|
-
|
|
733
|
+
warn(`Rooms "${r1.id}" and "${r2.id}" overlap`, "W_ROOM_OVERLAP", r2.span);
|
|
663
734
|
}
|
|
664
735
|
}
|
|
665
736
|
}
|
|
666
|
-
return
|
|
737
|
+
return diags;
|
|
667
738
|
}
|
|
668
739
|
|
|
669
740
|
// src/render.ts
|
|
@@ -955,6 +1026,60 @@ function titleBlock(plan, b, margin, refDim, thin) {
|
|
|
955
1026
|
return `<g>${parts.join("")}</g>`;
|
|
956
1027
|
}
|
|
957
1028
|
|
|
1029
|
+
// src/diagnostics.ts
|
|
1030
|
+
function offsetToLineCol(source, offset) {
|
|
1031
|
+
const o = Math.max(0, Math.min(offset, source.length));
|
|
1032
|
+
let line = 1;
|
|
1033
|
+
let col = 1;
|
|
1034
|
+
for (let k = 0; k < o; k++) {
|
|
1035
|
+
if (source[k] === "\n") {
|
|
1036
|
+
line++;
|
|
1037
|
+
col = 1;
|
|
1038
|
+
} else {
|
|
1039
|
+
col++;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
return { line, col };
|
|
1043
|
+
}
|
|
1044
|
+
function lineStart(source, offset) {
|
|
1045
|
+
let k = Math.max(0, Math.min(offset, source.length));
|
|
1046
|
+
while (k > 0 && source[k - 1] !== "\n") k--;
|
|
1047
|
+
return k;
|
|
1048
|
+
}
|
|
1049
|
+
function lineEnd(source, offset) {
|
|
1050
|
+
let k = Math.max(0, Math.min(offset, source.length));
|
|
1051
|
+
while (k < source.length && source[k] !== "\n") k++;
|
|
1052
|
+
return k;
|
|
1053
|
+
}
|
|
1054
|
+
function formatDiagnostic(source, d) {
|
|
1055
|
+
const codeTag = d.code ? `[${d.code}]` : "";
|
|
1056
|
+
const header = `${d.severity}${codeTag}: ${d.message}`;
|
|
1057
|
+
const lines = [header];
|
|
1058
|
+
if (d.span) {
|
|
1059
|
+
const { line, col } = offsetToLineCol(source, d.span.start);
|
|
1060
|
+
const ls = lineStart(source, d.span.start);
|
|
1061
|
+
const le = lineEnd(source, d.span.start);
|
|
1062
|
+
const srcLine = source.slice(ls, le);
|
|
1063
|
+
const caretStart = d.span.start - ls;
|
|
1064
|
+
const caretEnd = Math.min(d.span.end, le) - ls;
|
|
1065
|
+
const caretLen = Math.max(1, caretEnd - caretStart);
|
|
1066
|
+
const gutter = String(line);
|
|
1067
|
+
const pad = " ".repeat(gutter.length);
|
|
1068
|
+
lines.push(`${pad} --> ${line}:${col}`);
|
|
1069
|
+
lines.push(`${pad} |`);
|
|
1070
|
+
lines.push(`${gutter} | ${srcLine}`);
|
|
1071
|
+
lines.push(`${pad} | ${" ".repeat(caretStart)}${"^".repeat(caretLen)}`);
|
|
1072
|
+
for (const hint of d.hints ?? []) {
|
|
1073
|
+
lines.push(`${pad} = help: ${hint}`);
|
|
1074
|
+
}
|
|
1075
|
+
} else {
|
|
1076
|
+
for (const hint of d.hints ?? []) {
|
|
1077
|
+
lines.push(` = help: ${hint}`);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
return lines.join("\n");
|
|
1081
|
+
}
|
|
1082
|
+
|
|
958
1083
|
// src/index.ts
|
|
959
1084
|
var cache = /* @__PURE__ */ new Map();
|
|
960
1085
|
var CACHE_MAX = 64;
|
|
@@ -974,24 +1099,28 @@ function compile(source, opts = {}) {
|
|
|
974
1099
|
}
|
|
975
1100
|
return result;
|
|
976
1101
|
}
|
|
1102
|
+
function toLegacy(source, d) {
|
|
1103
|
+
if (!d.span) return { message: d.message };
|
|
1104
|
+
const { line, col } = offsetToLineCol(source, d.span.start);
|
|
1105
|
+
return { message: d.message, line, col };
|
|
1106
|
+
}
|
|
977
1107
|
function compileUncached(source, opts) {
|
|
978
|
-
const { plan,
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
const
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
}
|
|
986
|
-
const svg = render(plan, opts);
|
|
987
|
-
return { svg, errors: [], warnings, ast: plan };
|
|
1108
|
+
const { plan, diagnostics: parseDiags } = parse(source);
|
|
1109
|
+
const diagnostics = plan ? [...parseDiags, ...validate(plan)] : [...parseDiags];
|
|
1110
|
+
const errs = diagnostics.filter((d) => d.severity === "error");
|
|
1111
|
+
const errors = errs.map((d) => toLegacy(source, d));
|
|
1112
|
+
const warnings = diagnostics.filter((d) => d.severity === "warning").map((d) => toLegacy(source, d));
|
|
1113
|
+
const svg = plan && errs.length === 0 ? render(plan, opts) : "";
|
|
1114
|
+
return { svg, errors, warnings, diagnostics, ast: plan };
|
|
988
1115
|
}
|
|
989
1116
|
function clearCache() {
|
|
990
1117
|
cache.clear();
|
|
991
1118
|
}
|
|
992
1119
|
|
|
993
1120
|
export {
|
|
1121
|
+
offsetToLineCol,
|
|
1122
|
+
formatDiagnostic,
|
|
994
1123
|
compile,
|
|
995
1124
|
clearCache
|
|
996
1125
|
};
|
|
997
|
-
//# sourceMappingURL=chunk-
|
|
1126
|
+
//# sourceMappingURL=chunk-ICYNEDSM.js.map
|