topodraft-cli 0.1.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 (5) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +28 -0
  4. package/dist/cli.js +1692 -0
  5. package/package.json +34 -0
package/dist/cli.js ADDED
@@ -0,0 +1,1692 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // src/cli.ts
5
+ var import_node_fs = require("node:fs");
6
+
7
+ // ../../node_modules/jsonc-parser/lib/esm/impl/scanner.js
8
+ function createScanner(text, ignoreTrivia = false) {
9
+ const len = text.length;
10
+ let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
11
+ function scanHexDigits(count, exact) {
12
+ let digits = 0;
13
+ let value2 = 0;
14
+ while (digits < count || !exact) {
15
+ let ch = text.charCodeAt(pos);
16
+ if (ch >= 48 && ch <= 57) {
17
+ value2 = value2 * 16 + ch - 48;
18
+ } else if (ch >= 65 && ch <= 70) {
19
+ value2 = value2 * 16 + ch - 65 + 10;
20
+ } else if (ch >= 97 && ch <= 102) {
21
+ value2 = value2 * 16 + ch - 97 + 10;
22
+ } else {
23
+ break;
24
+ }
25
+ pos++;
26
+ digits++;
27
+ }
28
+ if (digits < count) {
29
+ value2 = -1;
30
+ }
31
+ return value2;
32
+ }
33
+ function setPosition(newPosition) {
34
+ pos = newPosition;
35
+ value = "";
36
+ tokenOffset = 0;
37
+ token = 16;
38
+ scanError = 0;
39
+ }
40
+ function scanNumber() {
41
+ let start = pos;
42
+ if (text.charCodeAt(pos) === 48) {
43
+ pos++;
44
+ } else {
45
+ pos++;
46
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
47
+ pos++;
48
+ }
49
+ }
50
+ if (pos < text.length && text.charCodeAt(pos) === 46) {
51
+ pos++;
52
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
53
+ pos++;
54
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
55
+ pos++;
56
+ }
57
+ } else {
58
+ scanError = 3;
59
+ return text.substring(start, pos);
60
+ }
61
+ }
62
+ let end = pos;
63
+ if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
64
+ pos++;
65
+ if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
66
+ pos++;
67
+ }
68
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
69
+ pos++;
70
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
71
+ pos++;
72
+ }
73
+ end = pos;
74
+ } else {
75
+ scanError = 3;
76
+ }
77
+ }
78
+ return text.substring(start, end);
79
+ }
80
+ function scanString() {
81
+ let result = "", start = pos;
82
+ while (true) {
83
+ if (pos >= len) {
84
+ result += text.substring(start, pos);
85
+ scanError = 2;
86
+ break;
87
+ }
88
+ const ch = text.charCodeAt(pos);
89
+ if (ch === 34) {
90
+ result += text.substring(start, pos);
91
+ pos++;
92
+ break;
93
+ }
94
+ if (ch === 92) {
95
+ result += text.substring(start, pos);
96
+ pos++;
97
+ if (pos >= len) {
98
+ scanError = 2;
99
+ break;
100
+ }
101
+ const ch2 = text.charCodeAt(pos++);
102
+ switch (ch2) {
103
+ case 34:
104
+ result += '"';
105
+ break;
106
+ case 92:
107
+ result += "\\";
108
+ break;
109
+ case 47:
110
+ result += "/";
111
+ break;
112
+ case 98:
113
+ result += "\b";
114
+ break;
115
+ case 102:
116
+ result += "\f";
117
+ break;
118
+ case 110:
119
+ result += "\n";
120
+ break;
121
+ case 114:
122
+ result += "\r";
123
+ break;
124
+ case 116:
125
+ result += " ";
126
+ break;
127
+ case 117:
128
+ const ch3 = scanHexDigits(4, true);
129
+ if (ch3 >= 0) {
130
+ result += String.fromCharCode(ch3);
131
+ } else {
132
+ scanError = 4;
133
+ }
134
+ break;
135
+ default:
136
+ scanError = 5;
137
+ }
138
+ start = pos;
139
+ continue;
140
+ }
141
+ if (ch >= 0 && ch <= 31) {
142
+ if (isLineBreak(ch)) {
143
+ result += text.substring(start, pos);
144
+ scanError = 2;
145
+ break;
146
+ } else {
147
+ scanError = 6;
148
+ }
149
+ }
150
+ pos++;
151
+ }
152
+ return result;
153
+ }
154
+ function scanNext() {
155
+ value = "";
156
+ scanError = 0;
157
+ tokenOffset = pos;
158
+ lineStartOffset = lineNumber;
159
+ prevTokenLineStartOffset = tokenLineStartOffset;
160
+ if (pos >= len) {
161
+ tokenOffset = len;
162
+ return token = 17;
163
+ }
164
+ let code = text.charCodeAt(pos);
165
+ if (isWhiteSpace(code)) {
166
+ do {
167
+ pos++;
168
+ value += String.fromCharCode(code);
169
+ code = text.charCodeAt(pos);
170
+ } while (isWhiteSpace(code));
171
+ return token = 15;
172
+ }
173
+ if (isLineBreak(code)) {
174
+ pos++;
175
+ value += String.fromCharCode(code);
176
+ if (code === 13 && text.charCodeAt(pos) === 10) {
177
+ pos++;
178
+ value += "\n";
179
+ }
180
+ lineNumber++;
181
+ tokenLineStartOffset = pos;
182
+ return token = 14;
183
+ }
184
+ switch (code) {
185
+ // tokens: []{}:,
186
+ case 123:
187
+ pos++;
188
+ return token = 1;
189
+ case 125:
190
+ pos++;
191
+ return token = 2;
192
+ case 91:
193
+ pos++;
194
+ return token = 3;
195
+ case 93:
196
+ pos++;
197
+ return token = 4;
198
+ case 58:
199
+ pos++;
200
+ return token = 6;
201
+ case 44:
202
+ pos++;
203
+ return token = 5;
204
+ // strings
205
+ case 34:
206
+ pos++;
207
+ value = scanString();
208
+ return token = 10;
209
+ // comments
210
+ case 47:
211
+ const start = pos - 1;
212
+ if (text.charCodeAt(pos + 1) === 47) {
213
+ pos += 2;
214
+ while (pos < len) {
215
+ if (isLineBreak(text.charCodeAt(pos))) {
216
+ break;
217
+ }
218
+ pos++;
219
+ }
220
+ value = text.substring(start, pos);
221
+ return token = 12;
222
+ }
223
+ if (text.charCodeAt(pos + 1) === 42) {
224
+ pos += 2;
225
+ const safeLength = len - 1;
226
+ let commentClosed = false;
227
+ while (pos < safeLength) {
228
+ const ch = text.charCodeAt(pos);
229
+ if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
230
+ pos += 2;
231
+ commentClosed = true;
232
+ break;
233
+ }
234
+ pos++;
235
+ if (isLineBreak(ch)) {
236
+ if (ch === 13 && text.charCodeAt(pos) === 10) {
237
+ pos++;
238
+ }
239
+ lineNumber++;
240
+ tokenLineStartOffset = pos;
241
+ }
242
+ }
243
+ if (!commentClosed) {
244
+ pos++;
245
+ scanError = 1;
246
+ }
247
+ value = text.substring(start, pos);
248
+ return token = 13;
249
+ }
250
+ value += String.fromCharCode(code);
251
+ pos++;
252
+ return token = 16;
253
+ // numbers
254
+ case 45:
255
+ value += String.fromCharCode(code);
256
+ pos++;
257
+ if (pos === len || !isDigit(text.charCodeAt(pos))) {
258
+ return token = 16;
259
+ }
260
+ // found a minus, followed by a number so
261
+ // we fall through to proceed with scanning
262
+ // numbers
263
+ case 48:
264
+ case 49:
265
+ case 50:
266
+ case 51:
267
+ case 52:
268
+ case 53:
269
+ case 54:
270
+ case 55:
271
+ case 56:
272
+ case 57:
273
+ value += scanNumber();
274
+ return token = 11;
275
+ // literals and unknown symbols
276
+ default:
277
+ while (pos < len && isUnknownContentCharacter(code)) {
278
+ pos++;
279
+ code = text.charCodeAt(pos);
280
+ }
281
+ if (tokenOffset !== pos) {
282
+ value = text.substring(tokenOffset, pos);
283
+ switch (value) {
284
+ case "true":
285
+ return token = 8;
286
+ case "false":
287
+ return token = 9;
288
+ case "null":
289
+ return token = 7;
290
+ }
291
+ return token = 16;
292
+ }
293
+ value += String.fromCharCode(code);
294
+ pos++;
295
+ return token = 16;
296
+ }
297
+ }
298
+ function isUnknownContentCharacter(code) {
299
+ if (isWhiteSpace(code) || isLineBreak(code)) {
300
+ return false;
301
+ }
302
+ switch (code) {
303
+ case 125:
304
+ case 93:
305
+ case 123:
306
+ case 91:
307
+ case 34:
308
+ case 58:
309
+ case 44:
310
+ case 47:
311
+ return false;
312
+ }
313
+ return true;
314
+ }
315
+ function scanNextNonTrivia() {
316
+ let result;
317
+ do {
318
+ result = scanNext();
319
+ } while (result >= 12 && result <= 15);
320
+ return result;
321
+ }
322
+ return {
323
+ setPosition,
324
+ getPosition: () => pos,
325
+ scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
326
+ getToken: () => token,
327
+ getTokenValue: () => value,
328
+ getTokenOffset: () => tokenOffset,
329
+ getTokenLength: () => pos - tokenOffset,
330
+ getTokenStartLine: () => lineStartOffset,
331
+ getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
332
+ getTokenError: () => scanError
333
+ };
334
+ }
335
+ function isWhiteSpace(ch) {
336
+ return ch === 32 || ch === 9;
337
+ }
338
+ function isLineBreak(ch) {
339
+ return ch === 10 || ch === 13;
340
+ }
341
+ function isDigit(ch) {
342
+ return ch >= 48 && ch <= 57;
343
+ }
344
+ var CharacterCodes;
345
+ (function(CharacterCodes2) {
346
+ CharacterCodes2[CharacterCodes2["lineFeed"] = 10] = "lineFeed";
347
+ CharacterCodes2[CharacterCodes2["carriageReturn"] = 13] = "carriageReturn";
348
+ CharacterCodes2[CharacterCodes2["space"] = 32] = "space";
349
+ CharacterCodes2[CharacterCodes2["_0"] = 48] = "_0";
350
+ CharacterCodes2[CharacterCodes2["_1"] = 49] = "_1";
351
+ CharacterCodes2[CharacterCodes2["_2"] = 50] = "_2";
352
+ CharacterCodes2[CharacterCodes2["_3"] = 51] = "_3";
353
+ CharacterCodes2[CharacterCodes2["_4"] = 52] = "_4";
354
+ CharacterCodes2[CharacterCodes2["_5"] = 53] = "_5";
355
+ CharacterCodes2[CharacterCodes2["_6"] = 54] = "_6";
356
+ CharacterCodes2[CharacterCodes2["_7"] = 55] = "_7";
357
+ CharacterCodes2[CharacterCodes2["_8"] = 56] = "_8";
358
+ CharacterCodes2[CharacterCodes2["_9"] = 57] = "_9";
359
+ CharacterCodes2[CharacterCodes2["a"] = 97] = "a";
360
+ CharacterCodes2[CharacterCodes2["b"] = 98] = "b";
361
+ CharacterCodes2[CharacterCodes2["c"] = 99] = "c";
362
+ CharacterCodes2[CharacterCodes2["d"] = 100] = "d";
363
+ CharacterCodes2[CharacterCodes2["e"] = 101] = "e";
364
+ CharacterCodes2[CharacterCodes2["f"] = 102] = "f";
365
+ CharacterCodes2[CharacterCodes2["g"] = 103] = "g";
366
+ CharacterCodes2[CharacterCodes2["h"] = 104] = "h";
367
+ CharacterCodes2[CharacterCodes2["i"] = 105] = "i";
368
+ CharacterCodes2[CharacterCodes2["j"] = 106] = "j";
369
+ CharacterCodes2[CharacterCodes2["k"] = 107] = "k";
370
+ CharacterCodes2[CharacterCodes2["l"] = 108] = "l";
371
+ CharacterCodes2[CharacterCodes2["m"] = 109] = "m";
372
+ CharacterCodes2[CharacterCodes2["n"] = 110] = "n";
373
+ CharacterCodes2[CharacterCodes2["o"] = 111] = "o";
374
+ CharacterCodes2[CharacterCodes2["p"] = 112] = "p";
375
+ CharacterCodes2[CharacterCodes2["q"] = 113] = "q";
376
+ CharacterCodes2[CharacterCodes2["r"] = 114] = "r";
377
+ CharacterCodes2[CharacterCodes2["s"] = 115] = "s";
378
+ CharacterCodes2[CharacterCodes2["t"] = 116] = "t";
379
+ CharacterCodes2[CharacterCodes2["u"] = 117] = "u";
380
+ CharacterCodes2[CharacterCodes2["v"] = 118] = "v";
381
+ CharacterCodes2[CharacterCodes2["w"] = 119] = "w";
382
+ CharacterCodes2[CharacterCodes2["x"] = 120] = "x";
383
+ CharacterCodes2[CharacterCodes2["y"] = 121] = "y";
384
+ CharacterCodes2[CharacterCodes2["z"] = 122] = "z";
385
+ CharacterCodes2[CharacterCodes2["A"] = 65] = "A";
386
+ CharacterCodes2[CharacterCodes2["B"] = 66] = "B";
387
+ CharacterCodes2[CharacterCodes2["C"] = 67] = "C";
388
+ CharacterCodes2[CharacterCodes2["D"] = 68] = "D";
389
+ CharacterCodes2[CharacterCodes2["E"] = 69] = "E";
390
+ CharacterCodes2[CharacterCodes2["F"] = 70] = "F";
391
+ CharacterCodes2[CharacterCodes2["G"] = 71] = "G";
392
+ CharacterCodes2[CharacterCodes2["H"] = 72] = "H";
393
+ CharacterCodes2[CharacterCodes2["I"] = 73] = "I";
394
+ CharacterCodes2[CharacterCodes2["J"] = 74] = "J";
395
+ CharacterCodes2[CharacterCodes2["K"] = 75] = "K";
396
+ CharacterCodes2[CharacterCodes2["L"] = 76] = "L";
397
+ CharacterCodes2[CharacterCodes2["M"] = 77] = "M";
398
+ CharacterCodes2[CharacterCodes2["N"] = 78] = "N";
399
+ CharacterCodes2[CharacterCodes2["O"] = 79] = "O";
400
+ CharacterCodes2[CharacterCodes2["P"] = 80] = "P";
401
+ CharacterCodes2[CharacterCodes2["Q"] = 81] = "Q";
402
+ CharacterCodes2[CharacterCodes2["R"] = 82] = "R";
403
+ CharacterCodes2[CharacterCodes2["S"] = 83] = "S";
404
+ CharacterCodes2[CharacterCodes2["T"] = 84] = "T";
405
+ CharacterCodes2[CharacterCodes2["U"] = 85] = "U";
406
+ CharacterCodes2[CharacterCodes2["V"] = 86] = "V";
407
+ CharacterCodes2[CharacterCodes2["W"] = 87] = "W";
408
+ CharacterCodes2[CharacterCodes2["X"] = 88] = "X";
409
+ CharacterCodes2[CharacterCodes2["Y"] = 89] = "Y";
410
+ CharacterCodes2[CharacterCodes2["Z"] = 90] = "Z";
411
+ CharacterCodes2[CharacterCodes2["asterisk"] = 42] = "asterisk";
412
+ CharacterCodes2[CharacterCodes2["backslash"] = 92] = "backslash";
413
+ CharacterCodes2[CharacterCodes2["closeBrace"] = 125] = "closeBrace";
414
+ CharacterCodes2[CharacterCodes2["closeBracket"] = 93] = "closeBracket";
415
+ CharacterCodes2[CharacterCodes2["colon"] = 58] = "colon";
416
+ CharacterCodes2[CharacterCodes2["comma"] = 44] = "comma";
417
+ CharacterCodes2[CharacterCodes2["dot"] = 46] = "dot";
418
+ CharacterCodes2[CharacterCodes2["doubleQuote"] = 34] = "doubleQuote";
419
+ CharacterCodes2[CharacterCodes2["minus"] = 45] = "minus";
420
+ CharacterCodes2[CharacterCodes2["openBrace"] = 123] = "openBrace";
421
+ CharacterCodes2[CharacterCodes2["openBracket"] = 91] = "openBracket";
422
+ CharacterCodes2[CharacterCodes2["plus"] = 43] = "plus";
423
+ CharacterCodes2[CharacterCodes2["slash"] = 47] = "slash";
424
+ CharacterCodes2[CharacterCodes2["formFeed"] = 12] = "formFeed";
425
+ CharacterCodes2[CharacterCodes2["tab"] = 9] = "tab";
426
+ })(CharacterCodes || (CharacterCodes = {}));
427
+
428
+ // ../../node_modules/jsonc-parser/lib/esm/impl/string-intern.js
429
+ var cachedSpaces = new Array(20).fill(0).map((_, index) => {
430
+ return " ".repeat(index);
431
+ });
432
+ var maxCachedValues = 200;
433
+ var cachedBreakLinesWithSpaces = {
434
+ " ": {
435
+ "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
436
+ return "\n" + " ".repeat(index);
437
+ }),
438
+ "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
439
+ return "\r" + " ".repeat(index);
440
+ }),
441
+ "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
442
+ return "\r\n" + " ".repeat(index);
443
+ })
444
+ },
445
+ " ": {
446
+ "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
447
+ return "\n" + " ".repeat(index);
448
+ }),
449
+ "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
450
+ return "\r" + " ".repeat(index);
451
+ }),
452
+ "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
453
+ return "\r\n" + " ".repeat(index);
454
+ })
455
+ }
456
+ };
457
+
458
+ // ../../node_modules/jsonc-parser/lib/esm/impl/parser.js
459
+ var ParseOptions;
460
+ (function(ParseOptions2) {
461
+ ParseOptions2.DEFAULT = {
462
+ allowTrailingComma: false
463
+ };
464
+ })(ParseOptions || (ParseOptions = {}));
465
+ function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
466
+ let currentParent = { type: "array", offset: -1, length: -1, children: [], parent: void 0 };
467
+ function ensurePropertyComplete(endOffset) {
468
+ if (currentParent.type === "property") {
469
+ currentParent.length = endOffset - currentParent.offset;
470
+ currentParent = currentParent.parent;
471
+ }
472
+ }
473
+ function onValue(valueNode) {
474
+ currentParent.children.push(valueNode);
475
+ return valueNode;
476
+ }
477
+ const visitor = {
478
+ onObjectBegin: (offset) => {
479
+ currentParent = onValue({ type: "object", offset, length: -1, parent: currentParent, children: [] });
480
+ },
481
+ onObjectProperty: (name, offset, length) => {
482
+ currentParent = onValue({ type: "property", offset, length: -1, parent: currentParent, children: [] });
483
+ currentParent.children.push({ type: "string", value: name, offset, length, parent: currentParent });
484
+ },
485
+ onObjectEnd: (offset, length) => {
486
+ ensurePropertyComplete(offset + length);
487
+ currentParent.length = offset + length - currentParent.offset;
488
+ currentParent = currentParent.parent;
489
+ ensurePropertyComplete(offset + length);
490
+ },
491
+ onArrayBegin: (offset, length) => {
492
+ currentParent = onValue({ type: "array", offset, length: -1, parent: currentParent, children: [] });
493
+ },
494
+ onArrayEnd: (offset, length) => {
495
+ currentParent.length = offset + length - currentParent.offset;
496
+ currentParent = currentParent.parent;
497
+ ensurePropertyComplete(offset + length);
498
+ },
499
+ onLiteralValue: (value, offset, length) => {
500
+ onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });
501
+ ensurePropertyComplete(offset + length);
502
+ },
503
+ onSeparator: (sep, offset, length) => {
504
+ if (currentParent.type === "property") {
505
+ if (sep === ":") {
506
+ currentParent.colonOffset = offset;
507
+ } else if (sep === ",") {
508
+ ensurePropertyComplete(offset);
509
+ }
510
+ }
511
+ },
512
+ onError: (error, offset, length) => {
513
+ errors.push({ error, offset, length });
514
+ }
515
+ };
516
+ visit(text, visitor, options);
517
+ const result = currentParent.children[0];
518
+ if (result) {
519
+ delete result.parent;
520
+ }
521
+ return result;
522
+ }
523
+ function findNodeAtLocation(root, path) {
524
+ if (!root) {
525
+ return void 0;
526
+ }
527
+ let node = root;
528
+ for (let segment of path) {
529
+ if (typeof segment === "string") {
530
+ if (node.type !== "object" || !Array.isArray(node.children)) {
531
+ return void 0;
532
+ }
533
+ let found = false;
534
+ for (const propertyNode of node.children) {
535
+ if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {
536
+ node = propertyNode.children[1];
537
+ found = true;
538
+ break;
539
+ }
540
+ }
541
+ if (!found) {
542
+ return void 0;
543
+ }
544
+ } else {
545
+ const index = segment;
546
+ if (node.type !== "array" || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {
547
+ return void 0;
548
+ }
549
+ node = node.children[index];
550
+ }
551
+ }
552
+ return node;
553
+ }
554
+ function visit(text, visitor, options = ParseOptions.DEFAULT) {
555
+ const _scanner = createScanner(text, false);
556
+ const _jsonPath = [];
557
+ let suppressedCallbacks = 0;
558
+ function toNoArgVisit(visitFunction) {
559
+ return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
560
+ }
561
+ function toOneArgVisit(visitFunction) {
562
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
563
+ }
564
+ function toOneArgVisitWithPath(visitFunction) {
565
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;
566
+ }
567
+ function toBeginVisit(visitFunction) {
568
+ return visitFunction ? () => {
569
+ if (suppressedCallbacks > 0) {
570
+ suppressedCallbacks++;
571
+ } else {
572
+ let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());
573
+ if (cbReturn === false) {
574
+ suppressedCallbacks = 1;
575
+ }
576
+ }
577
+ } : () => true;
578
+ }
579
+ function toEndVisit(visitFunction) {
580
+ return visitFunction ? () => {
581
+ if (suppressedCallbacks > 0) {
582
+ suppressedCallbacks--;
583
+ }
584
+ if (suppressedCallbacks === 0) {
585
+ visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
586
+ }
587
+ } : () => true;
588
+ }
589
+ const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
590
+ const disallowComments = options && options.disallowComments;
591
+ const allowTrailingComma = options && options.allowTrailingComma;
592
+ function scanNext() {
593
+ while (true) {
594
+ const token = _scanner.scan();
595
+ switch (_scanner.getTokenError()) {
596
+ case 4:
597
+ handleError(
598
+ 14
599
+ /* ParseErrorCode.InvalidUnicode */
600
+ );
601
+ break;
602
+ case 5:
603
+ handleError(
604
+ 15
605
+ /* ParseErrorCode.InvalidEscapeCharacter */
606
+ );
607
+ break;
608
+ case 3:
609
+ handleError(
610
+ 13
611
+ /* ParseErrorCode.UnexpectedEndOfNumber */
612
+ );
613
+ break;
614
+ case 1:
615
+ if (!disallowComments) {
616
+ handleError(
617
+ 11
618
+ /* ParseErrorCode.UnexpectedEndOfComment */
619
+ );
620
+ }
621
+ break;
622
+ case 2:
623
+ handleError(
624
+ 12
625
+ /* ParseErrorCode.UnexpectedEndOfString */
626
+ );
627
+ break;
628
+ case 6:
629
+ handleError(
630
+ 16
631
+ /* ParseErrorCode.InvalidCharacter */
632
+ );
633
+ break;
634
+ }
635
+ switch (token) {
636
+ case 12:
637
+ case 13:
638
+ if (disallowComments) {
639
+ handleError(
640
+ 10
641
+ /* ParseErrorCode.InvalidCommentToken */
642
+ );
643
+ } else {
644
+ onComment();
645
+ }
646
+ break;
647
+ case 16:
648
+ handleError(
649
+ 1
650
+ /* ParseErrorCode.InvalidSymbol */
651
+ );
652
+ break;
653
+ case 15:
654
+ case 14:
655
+ break;
656
+ default:
657
+ return token;
658
+ }
659
+ }
660
+ }
661
+ function handleError(error, skipUntilAfter = [], skipUntil = []) {
662
+ onError(error);
663
+ if (skipUntilAfter.length + skipUntil.length > 0) {
664
+ let token = _scanner.getToken();
665
+ while (token !== 17) {
666
+ if (skipUntilAfter.indexOf(token) !== -1) {
667
+ scanNext();
668
+ break;
669
+ } else if (skipUntil.indexOf(token) !== -1) {
670
+ break;
671
+ }
672
+ token = scanNext();
673
+ }
674
+ }
675
+ }
676
+ function parseString(isValue) {
677
+ const value = _scanner.getTokenValue();
678
+ if (isValue) {
679
+ onLiteralValue(value);
680
+ } else {
681
+ onObjectProperty(value);
682
+ _jsonPath.push(value);
683
+ }
684
+ scanNext();
685
+ return true;
686
+ }
687
+ function parseLiteral() {
688
+ switch (_scanner.getToken()) {
689
+ case 11:
690
+ const tokenValue = _scanner.getTokenValue();
691
+ let value = Number(tokenValue);
692
+ if (isNaN(value)) {
693
+ handleError(
694
+ 2
695
+ /* ParseErrorCode.InvalidNumberFormat */
696
+ );
697
+ value = 0;
698
+ }
699
+ onLiteralValue(value);
700
+ break;
701
+ case 7:
702
+ onLiteralValue(null);
703
+ break;
704
+ case 8:
705
+ onLiteralValue(true);
706
+ break;
707
+ case 9:
708
+ onLiteralValue(false);
709
+ break;
710
+ default:
711
+ return false;
712
+ }
713
+ scanNext();
714
+ return true;
715
+ }
716
+ function parseProperty() {
717
+ if (_scanner.getToken() !== 10) {
718
+ handleError(3, [], [
719
+ 2,
720
+ 5
721
+ /* SyntaxKind.CommaToken */
722
+ ]);
723
+ return false;
724
+ }
725
+ parseString(false);
726
+ if (_scanner.getToken() === 6) {
727
+ onSeparator(":");
728
+ scanNext();
729
+ if (!parseValue()) {
730
+ handleError(4, [], [
731
+ 2,
732
+ 5
733
+ /* SyntaxKind.CommaToken */
734
+ ]);
735
+ }
736
+ } else {
737
+ handleError(5, [], [
738
+ 2,
739
+ 5
740
+ /* SyntaxKind.CommaToken */
741
+ ]);
742
+ }
743
+ _jsonPath.pop();
744
+ return true;
745
+ }
746
+ function parseObject() {
747
+ onObjectBegin();
748
+ scanNext();
749
+ let needsComma = false;
750
+ while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
751
+ if (_scanner.getToken() === 5) {
752
+ if (!needsComma) {
753
+ handleError(4, [], []);
754
+ }
755
+ onSeparator(",");
756
+ scanNext();
757
+ if (_scanner.getToken() === 2 && allowTrailingComma) {
758
+ break;
759
+ }
760
+ } else if (needsComma) {
761
+ handleError(6, [], []);
762
+ }
763
+ if (!parseProperty()) {
764
+ handleError(4, [], [
765
+ 2,
766
+ 5
767
+ /* SyntaxKind.CommaToken */
768
+ ]);
769
+ }
770
+ needsComma = true;
771
+ }
772
+ onObjectEnd();
773
+ if (_scanner.getToken() !== 2) {
774
+ handleError(7, [
775
+ 2
776
+ /* SyntaxKind.CloseBraceToken */
777
+ ], []);
778
+ } else {
779
+ scanNext();
780
+ }
781
+ return true;
782
+ }
783
+ function parseArray() {
784
+ onArrayBegin();
785
+ scanNext();
786
+ let isFirstElement = true;
787
+ let needsComma = false;
788
+ while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
789
+ if (_scanner.getToken() === 5) {
790
+ if (!needsComma) {
791
+ handleError(4, [], []);
792
+ }
793
+ onSeparator(",");
794
+ scanNext();
795
+ if (_scanner.getToken() === 4 && allowTrailingComma) {
796
+ break;
797
+ }
798
+ } else if (needsComma) {
799
+ handleError(6, [], []);
800
+ }
801
+ if (isFirstElement) {
802
+ _jsonPath.push(0);
803
+ isFirstElement = false;
804
+ } else {
805
+ _jsonPath[_jsonPath.length - 1]++;
806
+ }
807
+ if (!parseValue()) {
808
+ handleError(4, [], [
809
+ 4,
810
+ 5
811
+ /* SyntaxKind.CommaToken */
812
+ ]);
813
+ }
814
+ needsComma = true;
815
+ }
816
+ onArrayEnd();
817
+ if (!isFirstElement) {
818
+ _jsonPath.pop();
819
+ }
820
+ if (_scanner.getToken() !== 4) {
821
+ handleError(8, [
822
+ 4
823
+ /* SyntaxKind.CloseBracketToken */
824
+ ], []);
825
+ } else {
826
+ scanNext();
827
+ }
828
+ return true;
829
+ }
830
+ function parseValue() {
831
+ switch (_scanner.getToken()) {
832
+ case 3:
833
+ return parseArray();
834
+ case 1:
835
+ return parseObject();
836
+ case 10:
837
+ return parseString(true);
838
+ default:
839
+ return parseLiteral();
840
+ }
841
+ }
842
+ scanNext();
843
+ if (_scanner.getToken() === 17) {
844
+ if (options.allowEmptyContent) {
845
+ return true;
846
+ }
847
+ handleError(4, [], []);
848
+ return false;
849
+ }
850
+ if (!parseValue()) {
851
+ handleError(4, [], []);
852
+ return false;
853
+ }
854
+ if (_scanner.getToken() !== 17) {
855
+ handleError(9, [], []);
856
+ }
857
+ return true;
858
+ }
859
+ function getNodeType(value) {
860
+ switch (typeof value) {
861
+ case "boolean":
862
+ return "boolean";
863
+ case "number":
864
+ return "number";
865
+ case "string":
866
+ return "string";
867
+ case "object": {
868
+ if (!value) {
869
+ return "null";
870
+ } else if (Array.isArray(value)) {
871
+ return "array";
872
+ }
873
+ return "object";
874
+ }
875
+ default:
876
+ return "null";
877
+ }
878
+ }
879
+
880
+ // ../../node_modules/jsonc-parser/lib/esm/main.js
881
+ var ScanError;
882
+ (function(ScanError2) {
883
+ ScanError2[ScanError2["None"] = 0] = "None";
884
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
885
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
886
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
887
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
888
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
889
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
890
+ })(ScanError || (ScanError = {}));
891
+ var SyntaxKind;
892
+ (function(SyntaxKind2) {
893
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
894
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
895
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
896
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
897
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
898
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
899
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
900
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
901
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
902
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
903
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
904
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
905
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
906
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
907
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
908
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
909
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
910
+ })(SyntaxKind || (SyntaxKind = {}));
911
+ var parseTree2 = parseTree;
912
+ var findNodeAtLocation2 = findNodeAtLocation;
913
+ var ParseErrorCode;
914
+ (function(ParseErrorCode2) {
915
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
916
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
917
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
918
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
919
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
920
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
921
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
922
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
923
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
924
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
925
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
926
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
927
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
928
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
929
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
930
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
931
+ })(ParseErrorCode || (ParseErrorCode = {}));
932
+
933
+ // ../core/src/model.ts
934
+ function findDevice(topology, name) {
935
+ return topology.devices.find((d) => d.name === name);
936
+ }
937
+ function findNetwork(topology, name) {
938
+ return (topology.networks ?? []).find((n) => n.name === name);
939
+ }
940
+
941
+ // ../core/src/parse.ts
942
+ var TopoParseError = class extends Error {
943
+ constructor(message) {
944
+ super(message);
945
+ this.name = "TopoParseError";
946
+ }
947
+ };
948
+ function parse2(text) {
949
+ let value;
950
+ try {
951
+ value = JSON.parse(text);
952
+ } catch (e) {
953
+ throw new TopoParseError(`invalid JSON: ${e.message}`);
954
+ }
955
+ return normalize(value);
956
+ }
957
+ function normalize(value) {
958
+ if (!isPlainObject(value)) {
959
+ throw new TopoParseError("top level must be a JSON object");
960
+ }
961
+ if (!Array.isArray(value.devices)) {
962
+ throw new TopoParseError('no "devices" array found');
963
+ }
964
+ if ("version" in value && value.version !== void 0 && value.version !== 1) {
965
+ throw new TopoParseError(
966
+ `unsupported version ${JSON.stringify(value.version)} (this build reads format v1)`
967
+ );
968
+ }
969
+ const devices = value.devices.map((raw, i) => normalizeDevice(raw, i)).filter((d) => d !== void 0);
970
+ const provider_networks = asArray(value.provider_networks).map((raw, i) => normalizeProviderNetwork(raw, i)).filter((p) => p !== void 0);
971
+ const networks = asArray(value.networks).map((raw, i) => normalizeNetwork(raw, i)).filter((n) => n !== void 0);
972
+ const cables = asArray(value.cables).filter(isPlainObject).map((raw) => normalizeCable(raw));
973
+ const circuits = asArray(value.circuits).filter(isPlainObject).map((raw) => normalizeCircuit(raw));
974
+ const logical_links = asArray(value.logical_links).filter(isPlainObject).map((raw) => normalizeLogicalLink(raw, devices));
975
+ const topology = { devices };
976
+ const schema = nonEmptyString(value.$schema);
977
+ if (schema !== void 0) topology.$schema = schema;
978
+ if (value.version === 1) topology.version = 1;
979
+ if (provider_networks.length) topology.provider_networks = provider_networks;
980
+ if (networks.length) topology.networks = networks;
981
+ if (cables.length) topology.cables = cables;
982
+ if (circuits.length) topology.circuits = circuits;
983
+ if (logical_links.length) topology.logical_links = logical_links;
984
+ return reorderTopology(topology);
985
+ }
986
+ function isPlainObject(v) {
987
+ return typeof v === "object" && v !== null && !Array.isArray(v);
988
+ }
989
+ function asArray(v) {
990
+ return Array.isArray(v) ? v : [];
991
+ }
992
+ function nonEmptyString(v) {
993
+ return typeof v === "string" && v !== "" ? v : void 0;
994
+ }
995
+ function trimmedString(v) {
996
+ const s = typeof v === "string" ? v.trim() : "";
997
+ return s === "" ? void 0 : s;
998
+ }
999
+ function normalizePosition(v) {
1000
+ if (!isPlainObject(v)) return void 0;
1001
+ const x = v.x;
1002
+ const y = v.y;
1003
+ if (typeof x !== "number" || typeof y !== "number") return void 0;
1004
+ if (!Number.isFinite(x) || !Number.isFinite(y)) return void 0;
1005
+ return { x: Math.round(x), y: Math.round(y) };
1006
+ }
1007
+ function normalizeInterface(raw) {
1008
+ if (!isPlainObject(raw)) return void 0;
1009
+ const f = {};
1010
+ const name = nonEmptyString(raw.name);
1011
+ const ip = nonEmptyString(raw.ip_address);
1012
+ const type = nonEmptyString(raw.type);
1013
+ const description = nonEmptyString(raw.description);
1014
+ const lag = nonEmptyString(raw.lag);
1015
+ const vrf = nonEmptyString(raw.vrf);
1016
+ if (name !== void 0) f.name = name;
1017
+ if (ip !== void 0) f.ip_address = ip;
1018
+ if (type !== void 0) f.type = type;
1019
+ if (description !== void 0) f.description = description;
1020
+ if (lag !== void 0) f.lag = lag;
1021
+ if (vrf !== void 0) f.vrf = vrf;
1022
+ return Object.keys(f).length ? f : void 0;
1023
+ }
1024
+ function normalizeDevice(raw, index) {
1025
+ if (!isPlainObject(raw)) return void 0;
1026
+ const d = {
1027
+ name: nonEmptyString(raw.name) ?? `node-${index + 1}`
1028
+ };
1029
+ const device_type = nonEmptyString(raw.device_type);
1030
+ const role = nonEmptyString(raw.role);
1031
+ const site = nonEmptyString(raw.site);
1032
+ const tenant = nonEmptyString(raw.tenant);
1033
+ const platform = nonEmptyString(raw.platform);
1034
+ if (device_type !== void 0) d.device_type = device_type;
1035
+ if (role !== void 0) d.role = role;
1036
+ if (site !== void 0) d.site = site;
1037
+ if (tenant !== void 0) d.tenant = tenant;
1038
+ if (platform !== void 0) d.platform = platform;
1039
+ const vrfs = asArray(raw.vrfs).map((v) => String(v).trim()).filter(Boolean);
1040
+ if (vrfs.length) d.vrfs = vrfs;
1041
+ const interfaces = asArray(raw.interfaces).map(normalizeInterface).filter((f) => f !== void 0);
1042
+ if (interfaces.length) d.interfaces = interfaces;
1043
+ if (isPlainObject(raw.config_context) && Object.keys(raw.config_context).length) {
1044
+ d.config_context = raw.config_context;
1045
+ }
1046
+ const position = normalizePosition(raw.position);
1047
+ if (position) d.position = position;
1048
+ return d;
1049
+ }
1050
+ function normalizeProviderNetwork(raw, index) {
1051
+ if (!isPlainObject(raw)) return void 0;
1052
+ const p = {
1053
+ name: nonEmptyString(raw.name) ?? `pnet-${index + 1}`
1054
+ };
1055
+ const provider = nonEmptyString(raw.provider);
1056
+ const description = nonEmptyString(raw.description);
1057
+ if (provider !== void 0) p.provider = provider;
1058
+ if (description !== void 0) p.description = description;
1059
+ const position = normalizePosition(raw.position);
1060
+ if (position) p.position = position;
1061
+ return p;
1062
+ }
1063
+ function normalizeNetwork(raw, index) {
1064
+ if (!isPlainObject(raw)) return void 0;
1065
+ const n = {
1066
+ name: nonEmptyString(raw.name) ?? `net-${index + 1}`
1067
+ };
1068
+ const prefix = nonEmptyString(raw.prefix);
1069
+ const vlan = nonEmptyString(raw.vlan);
1070
+ const description = nonEmptyString(raw.description);
1071
+ if (prefix !== void 0) n.prefix = prefix;
1072
+ if (vlan !== void 0) n.vlan = vlan;
1073
+ if (isPlainObject(raw.fhrp)) {
1074
+ const fhrp = {};
1075
+ const protocol = nonEmptyString(raw.fhrp.protocol);
1076
+ const group_id = nonEmptyString(raw.fhrp.group_id) ?? nonEmptyString(raw.fhrp.group);
1077
+ const virtual_ip = nonEmptyString(raw.fhrp.virtual_ip);
1078
+ if (protocol !== void 0) fhrp.protocol = protocol;
1079
+ if (group_id !== void 0) fhrp.group_id = group_id;
1080
+ if (virtual_ip !== void 0) fhrp.virtual_ip = virtual_ip;
1081
+ if (Object.keys(fhrp).length) n.fhrp = fhrp;
1082
+ }
1083
+ if (description !== void 0) n.description = description;
1084
+ const position = normalizePosition(raw.position);
1085
+ if (position) n.position = position;
1086
+ return n;
1087
+ }
1088
+ function normalizePhysicalEndpoint(raw, keepSite) {
1089
+ if (!isPlainObject(raw)) return {};
1090
+ const pn = nonEmptyString(raw.provider_network);
1091
+ if (pn !== void 0) return { provider_network: pn };
1092
+ const ep = {};
1093
+ const site = keepSite ? nonEmptyString(raw.site) : void 0;
1094
+ const device = nonEmptyString(raw.device);
1095
+ const iface = nonEmptyString(raw.interface);
1096
+ if (site !== void 0) ep.site = site;
1097
+ if (device !== void 0) ep.device = device;
1098
+ if (iface !== void 0) ep.interface = iface;
1099
+ return ep;
1100
+ }
1101
+ function normalizeCable(raw) {
1102
+ const c = {
1103
+ a: normalizePhysicalEndpoint(raw.a, false),
1104
+ b: normalizePhysicalEndpoint(raw.b, false)
1105
+ };
1106
+ const type = nonEmptyString(raw.type);
1107
+ const bandwidth = nonEmptyString(raw.bandwidth);
1108
+ const status = nonEmptyString(raw.status);
1109
+ const label = nonEmptyString(raw.label);
1110
+ if (type !== void 0) c.type = type;
1111
+ if (bandwidth !== void 0) c.bandwidth = bandwidth;
1112
+ if (status !== void 0) c.status = status;
1113
+ if (label !== void 0) c.label = label;
1114
+ return c;
1115
+ }
1116
+ function normalizeCircuit(raw) {
1117
+ const c = {
1118
+ a: normalizePhysicalEndpoint(raw.a, true),
1119
+ b: normalizePhysicalEndpoint(raw.b, true)
1120
+ };
1121
+ const cid = nonEmptyString(raw.cid);
1122
+ const provider = nonEmptyString(raw.provider);
1123
+ const type = nonEmptyString(raw.type);
1124
+ const commit_rate = nonEmptyString(raw.commit_rate);
1125
+ const status = nonEmptyString(raw.status);
1126
+ if (cid !== void 0) c.cid = cid;
1127
+ if (provider !== void 0) c.provider = provider;
1128
+ if (type !== void 0) c.type = type;
1129
+ if (commit_rate !== void 0) c.commit_rate = commit_rate;
1130
+ if (status !== void 0) c.status = status;
1131
+ return c;
1132
+ }
1133
+ function ensureInterface(device, name) {
1134
+ device.interfaces = device.interfaces ?? [];
1135
+ let f = device.interfaces.find((x) => x.name === name);
1136
+ if (!f) {
1137
+ f = { name };
1138
+ device.interfaces.push(f);
1139
+ }
1140
+ return f;
1141
+ }
1142
+ function normalizeLogicalEndpoint(raw, topLevelVrf, devices) {
1143
+ if (!isPlainObject(raw)) return {};
1144
+ const pn = nonEmptyString(raw.provider_network);
1145
+ if (pn !== void 0) {
1146
+ const ep2 = { provider_network: pn };
1147
+ const id2 = trimmedString(raw.id);
1148
+ if (id2 !== void 0) ep2.id = id2;
1149
+ return ep2;
1150
+ }
1151
+ const net = nonEmptyString(raw.network);
1152
+ if (net !== void 0) return { network: net };
1153
+ const ep = {};
1154
+ const device = nonEmptyString(raw.device);
1155
+ const vrf = trimmedString(raw.vrf) ?? topLevelVrf;
1156
+ const id = trimmedString(raw.id);
1157
+ const iface = nonEmptyString(raw.interface);
1158
+ const ip = nonEmptyString(raw.ip_address);
1159
+ if (device !== void 0) ep.device = device;
1160
+ if (vrf !== void 0) ep.vrf = vrf;
1161
+ if (id !== void 0) ep.id = id;
1162
+ if (iface !== void 0) ep.interface = iface;
1163
+ const target = device !== void 0 ? devices.find((d) => d.name === device) : void 0;
1164
+ if (iface !== void 0 && ip !== void 0 && target) {
1165
+ const f = ensureInterface(target, iface);
1166
+ if (!f.ip_address) f.ip_address = ip;
1167
+ if (vrf !== void 0 && !f.vrf) f.vrf = vrf;
1168
+ } else if (ip !== void 0) {
1169
+ ep.ip_address = ip;
1170
+ }
1171
+ return ep;
1172
+ }
1173
+ function normalizeLogicalLink(raw, devices) {
1174
+ const topLevelVrf = trimmedString(raw.vrf);
1175
+ const l = {
1176
+ a: normalizeLogicalEndpoint(raw.a, topLevelVrf, devices),
1177
+ b: normalizeLogicalEndpoint(raw.b, topLevelVrf, devices)
1178
+ };
1179
+ const link_id = nonEmptyString(raw.link_id);
1180
+ const vlan = nonEmptyString(raw.vlan);
1181
+ const label = nonEmptyString(raw.label);
1182
+ const description = nonEmptyString(raw.description);
1183
+ if (link_id !== void 0) l.link_id = link_id;
1184
+ if (vlan !== void 0) l.vlan = vlan;
1185
+ if (label !== void 0) l.label = label;
1186
+ if (description !== void 0) l.description = description;
1187
+ return l;
1188
+ }
1189
+ function reorderTopology(t) {
1190
+ const out = {};
1191
+ if (t.$schema !== void 0) out.$schema = t.$schema;
1192
+ if (t.version !== void 0) out.version = t.version;
1193
+ out.devices = t.devices;
1194
+ if (t.provider_networks) out.provider_networks = t.provider_networks;
1195
+ if (t.networks) out.networks = t.networks;
1196
+ if (t.cables) out.cables = t.cables;
1197
+ if (t.circuits) out.circuits = t.circuits;
1198
+ if (t.logical_links) out.logical_links = t.logical_links;
1199
+ return out;
1200
+ }
1201
+
1202
+ // ../core/src/unknownFields.ts
1203
+ var TOP_LEVEL = ["$schema", "version", "devices", "provider_networks", "networks", "cables", "circuits", "logical_links"];
1204
+ var DEVICE = ["name", "device_type", "role", "site", "tenant", "platform", "vrfs", "interfaces", "config_context", "position"];
1205
+ var INTERFACE = ["name", "ip_address", "type", "description", "lag", "vrf"];
1206
+ var PROVIDER_NETWORK = ["name", "provider", "description", "position"];
1207
+ var NETWORK = ["name", "prefix", "vlan", "fhrp", "description", "position"];
1208
+ var FHRP = ["protocol", "group_id", "virtual_ip"];
1209
+ var POSITION = ["x", "y"];
1210
+ var CABLE = ["a", "b", "type", "bandwidth", "status", "label"];
1211
+ var CIRCUIT = ["a", "b", "cid", "provider", "type", "commit_rate", "status"];
1212
+ var LOGICAL_LINK = ["a", "b", "link_id", "vlan", "label", "description", "vrf"];
1213
+ var PHYSICAL_ENDPOINT = ["site", "device", "interface", "provider_network"];
1214
+ var LOGICAL_ENDPOINT = ["device", "vrf", "id", "interface", "ip_address", "provider_network", "network"];
1215
+ function levenshtein(a, b) {
1216
+ let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
1217
+ for (let i = 1; i <= a.length; i++) {
1218
+ const cur = [i];
1219
+ for (let j = 1; j <= b.length; j++) {
1220
+ cur[j] = Math.min(
1221
+ (prev[j] ?? 0) + 1,
1222
+ (cur[j - 1] ?? 0) + 1,
1223
+ (prev[j - 1] ?? 0) + (a[i - 1] === b[j - 1] ? 0 : 1)
1224
+ );
1225
+ }
1226
+ prev = cur;
1227
+ }
1228
+ return prev[b.length] ?? 0;
1229
+ }
1230
+ function isSubsequence(needle, haystack) {
1231
+ let i = 0;
1232
+ for (const c of haystack) {
1233
+ if (c === needle[i]) i++;
1234
+ if (i === needle.length) return true;
1235
+ }
1236
+ return i === needle.length;
1237
+ }
1238
+ function suggestField(field, known) {
1239
+ const lower = field.toLowerCase();
1240
+ const prefix = known.filter((k) => {
1241
+ const kl = k.toLowerCase();
1242
+ return Math.min(kl.length, lower.length) >= 2 && (kl.startsWith(lower) || lower.startsWith(kl));
1243
+ }).sort((x, y) => x.length - y.length)[0];
1244
+ if (prefix) return prefix;
1245
+ if (lower.length >= 3) {
1246
+ const subsequence = known.filter((k) => isSubsequence(lower, k.toLowerCase()));
1247
+ if (subsequence.length === 1) return subsequence[0];
1248
+ }
1249
+ let best;
1250
+ let bestDist = 3;
1251
+ for (const k of known) {
1252
+ const d = levenshtein(lower, k.toLowerCase());
1253
+ if (d < bestDist) {
1254
+ bestDist = d;
1255
+ best = k;
1256
+ }
1257
+ }
1258
+ return best;
1259
+ }
1260
+ function isPlainObject2(v) {
1261
+ return typeof v === "object" && v !== null && !Array.isArray(v);
1262
+ }
1263
+ function findUnknownFields(value) {
1264
+ const findings = [];
1265
+ if (!isPlainObject2(value)) return findings;
1266
+ const check = (obj, known, path) => {
1267
+ if (!isPlainObject2(obj)) return;
1268
+ for (const key of Object.keys(obj)) {
1269
+ if (!known.includes(key)) {
1270
+ const suggestion = suggestField(key, known);
1271
+ findings.push({ path: [...path, key], field: key, ...suggestion ? { suggestion } : {} });
1272
+ }
1273
+ }
1274
+ };
1275
+ const checkArray = (arr, path, fn) => {
1276
+ if (!Array.isArray(arr)) return;
1277
+ arr.forEach((item, i) => fn(item, [...path, i]));
1278
+ };
1279
+ check(value, TOP_LEVEL, []);
1280
+ checkArray(value.devices, ["devices"], (d, p) => {
1281
+ check(d, DEVICE, p);
1282
+ if (isPlainObject2(d)) {
1283
+ checkArray(d.interfaces, [...p, "interfaces"], (f, fp) => check(f, INTERFACE, fp));
1284
+ check(d.position, POSITION, [...p, "position"]);
1285
+ }
1286
+ });
1287
+ checkArray(value.provider_networks, ["provider_networks"], (pn, p) => {
1288
+ check(pn, PROVIDER_NETWORK, p);
1289
+ if (isPlainObject2(pn)) check(pn.position, POSITION, [...p, "position"]);
1290
+ });
1291
+ checkArray(value.networks, ["networks"], (n, p) => {
1292
+ check(n, NETWORK, p);
1293
+ if (isPlainObject2(n)) {
1294
+ check(n.fhrp, FHRP, [...p, "fhrp"]);
1295
+ check(n.position, POSITION, [...p, "position"]);
1296
+ }
1297
+ });
1298
+ const checkLinks = (key, linkKnown, endpointKnown) => checkArray(value[key], [key], (l, p) => {
1299
+ check(l, linkKnown, p);
1300
+ if (isPlainObject2(l)) {
1301
+ check(l.a, endpointKnown, [...p, "a"]);
1302
+ check(l.b, endpointKnown, [...p, "b"]);
1303
+ }
1304
+ });
1305
+ checkLinks("cables", CABLE, PHYSICAL_ENDPOINT);
1306
+ checkLinks("circuits", CIRCUIT, PHYSICAL_ENDPOINT);
1307
+ checkLinks("logical_links", LOGICAL_LINK, LOGICAL_ENDPOINT);
1308
+ return findings;
1309
+ }
1310
+
1311
+ // ../core/src/cidr.ts
1312
+ function parseIpv4(ip) {
1313
+ const bare = ip.split("/")[0] ?? "";
1314
+ const parts = bare.trim().split(".");
1315
+ if (parts.length !== 4) return null;
1316
+ let out = 0;
1317
+ for (const part of parts) {
1318
+ if (!/^\d{1,3}$/.test(part)) return null;
1319
+ const n = Number(part);
1320
+ if (n > 255) return null;
1321
+ out = out << 8 | n;
1322
+ }
1323
+ return out >>> 0;
1324
+ }
1325
+ function ipv4InCidr(ip, cidr) {
1326
+ const [base, lenStr] = cidr.trim().split("/");
1327
+ if (base === void 0 || lenStr === void 0 || !/^\d{1,2}$/.test(lenStr)) return null;
1328
+ const len = Number(lenStr);
1329
+ if (len < 0 || len > 32) return null;
1330
+ const baseN = parseIpv4(base);
1331
+ const ipN = parseIpv4(ip);
1332
+ if (baseN === null || ipN === null) return null;
1333
+ if (len === 0) return true;
1334
+ const mask = 4294967295 << 32 - len >>> 0;
1335
+ return (baseN & mask) === (ipN & mask);
1336
+ }
1337
+
1338
+ // ../core/src/validate.ts
1339
+ function validate(topology) {
1340
+ const diagnostics = [];
1341
+ if (topology.version === void 0) {
1342
+ diagnostics.push({
1343
+ severity: "info",
1344
+ code: "missing-version",
1345
+ message: 'File has no "version" field (legacy TopoDraft export); saving will add "version": 1.',
1346
+ path: []
1347
+ });
1348
+ }
1349
+ const seen = /* @__PURE__ */ new Map();
1350
+ topology.devices.forEach((d, i) => {
1351
+ if (seen.has(d.name)) {
1352
+ diagnostics.push({
1353
+ severity: "error",
1354
+ code: "duplicate-name",
1355
+ message: `Duplicate name "${d.name}" (already used by a ${seen.get(d.name)}); link references resolve to the first occurrence.`,
1356
+ path: ["devices", i, "name"]
1357
+ });
1358
+ } else {
1359
+ seen.set(d.name, "device");
1360
+ }
1361
+ });
1362
+ (topology.provider_networks ?? []).forEach((p, i) => {
1363
+ if (seen.has(p.name)) {
1364
+ diagnostics.push({
1365
+ severity: "error",
1366
+ code: "duplicate-name",
1367
+ message: `Duplicate name "${p.name}" (already used by a ${seen.get(p.name)}); link references resolve to the first occurrence.`,
1368
+ path: ["provider_networks", i, "name"]
1369
+ });
1370
+ } else {
1371
+ seen.set(p.name, "provider network");
1372
+ }
1373
+ });
1374
+ (topology.networks ?? []).forEach((n, i) => {
1375
+ if (seen.has(n.name)) {
1376
+ diagnostics.push({
1377
+ severity: "error",
1378
+ code: "duplicate-name",
1379
+ message: `Duplicate name "${n.name}" (already used by a ${seen.get(n.name)}); link references resolve to the first occurrence.`,
1380
+ path: ["networks", i, "name"]
1381
+ });
1382
+ } else {
1383
+ seen.set(n.name, "network");
1384
+ }
1385
+ });
1386
+ const deviceNames = new Set(topology.devices.map((d) => d.name));
1387
+ const pnNames = new Set((topology.provider_networks ?? []).map((p) => p.name));
1388
+ const networkNames = new Set((topology.networks ?? []).map((n) => n.name));
1389
+ const checkEndpoint = (collection, index, side, ep) => {
1390
+ const base = [collection, index, side];
1391
+ const netRef = ep.network;
1392
+ if (netRef !== void 0) {
1393
+ if (!networkNames.has(netRef)) {
1394
+ diagnostics.push({
1395
+ severity: "error",
1396
+ code: "dangling-reference",
1397
+ message: `Endpoint references network "${netRef}", which does not exist in networks[].`,
1398
+ path: [...base, "network"]
1399
+ });
1400
+ }
1401
+ return;
1402
+ }
1403
+ if (ep.provider_network !== void 0) {
1404
+ if (!pnNames.has(ep.provider_network)) {
1405
+ diagnostics.push({
1406
+ severity: "error",
1407
+ code: "dangling-reference",
1408
+ message: `Endpoint references provider network "${ep.provider_network}", which does not exist in provider_networks[].`,
1409
+ path: [...base, "provider_network"]
1410
+ });
1411
+ }
1412
+ return;
1413
+ }
1414
+ if (ep.device === void 0) {
1415
+ diagnostics.push({
1416
+ severity: "error",
1417
+ code: "dangling-reference",
1418
+ message: 'Endpoint references neither a "device", a "provider_network", nor a "network".',
1419
+ path: base
1420
+ });
1421
+ return;
1422
+ }
1423
+ if (!deviceNames.has(ep.device)) {
1424
+ diagnostics.push({
1425
+ severity: "error",
1426
+ code: "dangling-reference",
1427
+ message: `Endpoint references device "${ep.device}", which does not exist in devices[].`,
1428
+ path: [...base, "device"]
1429
+ });
1430
+ return;
1431
+ }
1432
+ const device = findDevice(topology, ep.device);
1433
+ if (!device) return;
1434
+ if (ep.interface !== void 0) {
1435
+ const exists = (device.interfaces ?? []).some((f) => f.name === ep.interface);
1436
+ if (!exists) {
1437
+ diagnostics.push({
1438
+ severity: "warning",
1439
+ code: "unknown-interface",
1440
+ message: `Interface "${ep.interface}" does not exist on device "${ep.device}".`,
1441
+ path: [...base, "interface"]
1442
+ });
1443
+ }
1444
+ }
1445
+ if (collection === "logical_links") {
1446
+ const vrf = (ep.vrf ?? "").trim();
1447
+ if (vrf) {
1448
+ const declared = new Set((device.vrfs ?? []).map((v) => v.trim()).filter(Boolean));
1449
+ for (const f of device.interfaces ?? []) {
1450
+ const v = (f.vrf ?? "").trim();
1451
+ if (v) declared.add(v);
1452
+ }
1453
+ if (!declared.has(vrf)) {
1454
+ diagnostics.push({
1455
+ severity: "warning",
1456
+ code: "undeclared-vrf",
1457
+ message: `VRF "${vrf}" on device "${ep.device}" is neither declared in devices[].vrfs nor used by any interface. The editor derives a device's VRF compartments as vrfs[] \u222A interfaces[].vrf \u222A logical-endpoint VRFs, so it will still render \u2014 but declaring it explicitly is recommended.`,
1458
+ path: [...base, "vrf"]
1459
+ });
1460
+ }
1461
+ }
1462
+ }
1463
+ };
1464
+ (topology.cables ?? []).forEach((c, i) => {
1465
+ checkEndpoint("cables", i, "a", c.a ?? {});
1466
+ checkEndpoint("cables", i, "b", c.b ?? {});
1467
+ });
1468
+ (topology.circuits ?? []).forEach((c, i) => {
1469
+ checkEndpoint("circuits", i, "a", c.a ?? {});
1470
+ checkEndpoint("circuits", i, "b", c.b ?? {});
1471
+ });
1472
+ (topology.logical_links ?? []).forEach((l, i) => {
1473
+ checkEndpoint("logical_links", i, "a", l.a ?? {});
1474
+ checkEndpoint("logical_links", i, "b", l.b ?? {});
1475
+ });
1476
+ topology.devices.forEach((d, di) => {
1477
+ (d.interfaces ?? []).forEach((f, fi) => {
1478
+ if (f.lag === void 0) return;
1479
+ const parentExists = (d.interfaces ?? []).some((x) => x.name === f.lag);
1480
+ if (!parentExists) {
1481
+ diagnostics.push({
1482
+ severity: "warning",
1483
+ code: "missing-lag-parent",
1484
+ message: `Interface "${f.name ?? ""}" on device "${d.name}" names LAG parent "${f.lag}", but no such interface exists on the same device.`,
1485
+ path: ["devices", di, "interfaces", fi, "lag"]
1486
+ });
1487
+ }
1488
+ });
1489
+ });
1490
+ (topology.networks ?? []).forEach((n, ni) => {
1491
+ const prefix = (n.prefix ?? "").trim();
1492
+ if (!prefix) return;
1493
+ const vip = (n.fhrp?.virtual_ip ?? "").trim();
1494
+ if (vip && ipv4InCidr(vip, prefix) === false) {
1495
+ diagnostics.push({
1496
+ severity: "warning",
1497
+ code: "ip-outside-prefix",
1498
+ message: `FHRP virtual IP "${vip}" is outside this network's prefix ${prefix}.`,
1499
+ path: ["networks", ni, "fhrp", "virtual_ip"]
1500
+ });
1501
+ }
1502
+ });
1503
+ (topology.logical_links ?? []).forEach((l, li) => {
1504
+ const sides = ["a", "b"];
1505
+ for (const side of sides) {
1506
+ const other = side === "a" ? "b" : "a";
1507
+ const netName = l[other].network;
1508
+ if (netName === void 0) continue;
1509
+ const prefix = (findNetwork(topology, netName)?.prefix ?? "").trim();
1510
+ if (!prefix) continue;
1511
+ const ep = l[side];
1512
+ if (ep.device === void 0) continue;
1513
+ let ip = (ep.ip_address ?? "").trim();
1514
+ let path = ["logical_links", li, side, "ip_address"];
1515
+ if (!ip && ep.interface !== void 0) {
1516
+ const device = findDevice(topology, ep.device);
1517
+ const ifIdx = (device?.interfaces ?? []).findIndex((f) => f.name === ep.interface);
1518
+ const iface = ifIdx >= 0 ? device?.interfaces?.[ifIdx] : void 0;
1519
+ if (iface?.ip_address) {
1520
+ ip = iface.ip_address.trim();
1521
+ const di = topology.devices.findIndex((d) => d.name === ep.device);
1522
+ path = ["devices", di, "interfaces", ifIdx, "ip_address"];
1523
+ }
1524
+ }
1525
+ if (ip && ipv4InCidr(ip, prefix) === false) {
1526
+ diagnostics.push({
1527
+ severity: "warning",
1528
+ code: "ip-outside-prefix",
1529
+ message: `IP "${ip}" on "${ep.device}" is outside the prefix ${prefix} of network "${netName}".`,
1530
+ path
1531
+ });
1532
+ }
1533
+ }
1534
+ });
1535
+ return diagnostics;
1536
+ }
1537
+
1538
+ // ../extension/src/diagnostics.ts
1539
+ function resolveNode(root, path) {
1540
+ for (let p = [...path]; p.length; p.pop()) {
1541
+ const node = findNodeAtLocation2(root, p);
1542
+ if (node) return node;
1543
+ }
1544
+ return root;
1545
+ }
1546
+ function computeOffsetDiagnostics(text) {
1547
+ let topology;
1548
+ try {
1549
+ topology = parse2(text);
1550
+ } catch {
1551
+ return [];
1552
+ }
1553
+ const semantic = validate(topology);
1554
+ const unknown = findUnknownFields(JSON.parse(text));
1555
+ if (!semantic.length && !unknown.length) return [];
1556
+ const root = parseTree2(text);
1557
+ const out = unknown.map((f) => {
1558
+ const valueNode = root ? resolveNode(root, f.path) : void 0;
1559
+ const node = valueNode?.parent?.type === "property" ? valueNode.parent : valueNode;
1560
+ const atRoot = !node || node === root;
1561
+ return {
1562
+ severity: "warning",
1563
+ code: "unknown-field",
1564
+ message: `Unknown field "${f.field}"` + (f.suggestion ? ` \u2014 did you mean "${f.suggestion}"?` : "") + ' Unknown fields are dropped when the editor saves. See the JSON Schema (topodraft.schema.json) or run "TopoDraft: Write AI Agent Guide (AGENTS.md)".',
1565
+ start: node && !atRoot ? node.offset : root?.offset ?? 0,
1566
+ length: node && !atRoot ? node.length : 1
1567
+ };
1568
+ });
1569
+ for (const d of semantic) {
1570
+ const node = root ? resolveNode(root, d.path) : void 0;
1571
+ const atRoot = !node || node === root;
1572
+ out.push({
1573
+ severity: d.severity,
1574
+ code: d.code,
1575
+ message: d.message,
1576
+ start: node && !atRoot ? node.offset : root?.offset ?? 0,
1577
+ length: node && !atRoot ? node.length : 1
1578
+ });
1579
+ }
1580
+ return out;
1581
+ }
1582
+
1583
+ // src/run.ts
1584
+ function lineCol(text, offset) {
1585
+ let line = 1;
1586
+ let last = -1;
1587
+ for (let i = 0; i < offset && i < text.length; i++) {
1588
+ if (text[i] === "\n") {
1589
+ line++;
1590
+ last = i;
1591
+ }
1592
+ }
1593
+ return { line, column: offset - last };
1594
+ }
1595
+ function validateText(text) {
1596
+ const syntaxErrors = [];
1597
+ parseTree2(text, syntaxErrors, { allowTrailingComma: false });
1598
+ if (syntaxErrors.length) {
1599
+ return syntaxErrors.map((e) => ({
1600
+ severity: "error",
1601
+ code: "invalid-json",
1602
+ message: "the document is not valid JSON",
1603
+ ...lineCol(text, e.offset)
1604
+ }));
1605
+ }
1606
+ try {
1607
+ parse2(text);
1608
+ } catch (e) {
1609
+ if (e instanceof TopoParseError) {
1610
+ return [
1611
+ { severity: "error", code: "invalid-topology", message: e.message, line: 1, column: 1 }
1612
+ ];
1613
+ }
1614
+ throw e;
1615
+ }
1616
+ return computeOffsetDiagnostics(text).map((d) => ({
1617
+ severity: d.severity,
1618
+ code: d.code,
1619
+ message: d.message,
1620
+ ...lineCol(text, d.start)
1621
+ }));
1622
+ }
1623
+ var ORDER = { error: 0, warning: 1, info: 2 };
1624
+ function formatHuman(file, diagnostics) {
1625
+ if (!diagnostics.length) return `${file}: OK`;
1626
+ const sorted = [...diagnostics].sort(
1627
+ (a, b) => ORDER[a.severity] - ORDER[b.severity] || a.line - b.line || a.column - b.column
1628
+ );
1629
+ return sorted.map((d) => `${file}:${d.line}:${d.column} ${d.severity} ${d.code} ${d.message}`).join("\n");
1630
+ }
1631
+ var USAGE = `topodraft \u2014 validate TopoDraft topology files (*.topo.json / *.topo)
1632
+
1633
+ Usage:
1634
+ topodraft validate [--json] [--strict] <file...>
1635
+
1636
+ Options:
1637
+ --json machine-readable output (one JSON object per run)
1638
+ --strict exit non-zero on warnings too (default: errors only)
1639
+
1640
+ Exit codes: 0 = clean, 1 = diagnostics failed the gate, 2 = usage/IO error.`;
1641
+ function runCli(argv, io, version) {
1642
+ if (argv.includes("--version") || argv.includes("-v")) {
1643
+ io.stdout(version);
1644
+ return 0;
1645
+ }
1646
+ if (argv[0] !== "validate" || argv.includes("--help") || argv.includes("-h")) {
1647
+ (argv[0] === void 0 || argv.includes("--help") || argv.includes("-h") ? io.stdout : io.stderr)(USAGE);
1648
+ return argv[0] === void 0 || argv.includes("--help") || argv.includes("-h") ? 0 : 2;
1649
+ }
1650
+ const rest = argv.slice(1);
1651
+ const json = rest.includes("--json");
1652
+ const strict = rest.includes("--strict");
1653
+ const files = rest.filter((a) => !a.startsWith("--"));
1654
+ const unknownFlags = rest.filter((a) => a.startsWith("--") && !["--json", "--strict"].includes(a));
1655
+ if (unknownFlags.length || !files.length) {
1656
+ io.stderr(unknownFlags.length ? `unknown option: ${unknownFlags[0]}
1657
+ ${USAGE}` : USAGE);
1658
+ return 2;
1659
+ }
1660
+ const results = [];
1661
+ for (const file of files) {
1662
+ try {
1663
+ results.push({ file, diagnostics: validateText(io.readFile(file)) });
1664
+ } catch (e) {
1665
+ results.push({ file, diagnostics: [], error: e.message });
1666
+ }
1667
+ }
1668
+ if (json) {
1669
+ io.stdout(JSON.stringify({ results }, null, 2));
1670
+ } else {
1671
+ for (const r of results) {
1672
+ io.stdout(r.error !== void 0 ? `${r.file}: cannot read (${r.error})` : formatHuman(r.file, r.diagnostics));
1673
+ }
1674
+ }
1675
+ if (results.some((r) => r.error !== void 0)) return 2;
1676
+ const failing = results.some(
1677
+ (r) => r.diagnostics.some((d) => d.severity === "error" || strict && d.severity === "warning")
1678
+ );
1679
+ return failing ? 1 : 0;
1680
+ }
1681
+
1682
+ // src/cli.ts
1683
+ var VERSION = true ? "0.1.0" : "dev";
1684
+ process.exitCode = runCli(
1685
+ process.argv.slice(2),
1686
+ {
1687
+ readFile: (path) => (0, import_node_fs.readFileSync)(path, "utf8"),
1688
+ stdout: (line) => process.stdout.write(line + "\n"),
1689
+ stderr: (line) => process.stderr.write(line + "\n")
1690
+ },
1691
+ VERSION
1692
+ );