@atscript/core 0.0.1

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/index.mjs ADDED
@@ -0,0 +1,3397 @@
1
+ import fs from "node:fs";
2
+ import { readFile, readdir } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { rolldown } from "rolldown";
6
+ import { BasicNode } from "@prostojs/parser";
7
+ import path$1 from "path";
8
+ import { URL } from "url";
9
+ import { defu } from "defu";
10
+ import { glob } from "glob";
11
+ import { mkdir, writeFile } from "fs/promises";
12
+
13
+ //#region packages/core/src/parser/nodes/semantic-node.ts
14
+ function _define_property$14(obj, key, value) {
15
+ if (key in obj) Object.defineProperty(obj, key, {
16
+ value,
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true
20
+ });
21
+ else obj[key] = value;
22
+ return obj;
23
+ }
24
+ var SemanticNode = class {
25
+ registerAtDocument(doc) {
26
+ if (this.definition) this.definition.registerAtDocument(doc);
27
+ this.annotations?.forEach((val) => {
28
+ doc.registerAnnotation(val);
29
+ });
30
+ }
31
+ setDocumentation(s) {
32
+ this._documentation = s;
33
+ }
34
+ get documentation() {
35
+ return this._documentation;
36
+ }
37
+ get id() {
38
+ return this.token("identifier")?.text;
39
+ }
40
+ get referredIdentifiers() {
41
+ if (isGroup(this)) return this.getIdentifiersRecursive(this);
42
+ return this.definition ? this.getIdentifiersRecursive(this.definition) : [];
43
+ }
44
+ getIdentifiersRecursive(node) {
45
+ if (isGroup(node)) {
46
+ const r = [];
47
+ for (const n of node.unwrap()) r.push(...this.getIdentifiersRecursive(n));
48
+ return r;
49
+ } else return node.referredIdentifiers;
50
+ }
51
+ countAnnotations(name) {
52
+ return this.annotationsCounter?.get(name) ?? 0;
53
+ }
54
+ annotate(name, token) {
55
+ if (!this.annotations) this.annotations = [];
56
+ if (!this.annotationsCounter) this.annotationsCounter = new Map();
57
+ if (this.annotationsCounter.has(name)) this.annotationsCounter.set(name, this.annotationsCounter.get(name) + 1);
58
+ else this.annotationsCounter.set(name, 1);
59
+ token.parentNode = this;
60
+ const a = {
61
+ name,
62
+ token,
63
+ args: []
64
+ };
65
+ this.annotations.push(a);
66
+ return (arg) => {
67
+ arg.parentNode = this;
68
+ arg.index = a.args.length;
69
+ arg.annotationRef = token;
70
+ a.args.push(arg);
71
+ };
72
+ }
73
+ get length() {
74
+ return 0;
75
+ }
76
+ define(node) {
77
+ this.definition = node;
78
+ return this;
79
+ }
80
+ get def() {
81
+ return this.definition;
82
+ }
83
+ get identifier() {
84
+ return this.token("identifier")?.text;
85
+ }
86
+ saveToken(token, semantic) {
87
+ if (!this.tokens) this.tokens = new Map();
88
+ token.parentNode = this;
89
+ this.tokens.set(semantic, token);
90
+ return this;
91
+ }
92
+ wrap(node, token) {
93
+ this.define(node);
94
+ this.saveToken(token, "identifier");
95
+ return this;
96
+ }
97
+ token(s) {
98
+ return this.tokens?.get(s);
99
+ }
100
+ has(s) {
101
+ return this.tokens?.has(s);
102
+ }
103
+ toString(level = 0, prefix = "●") {
104
+ const indent = " ".repeat(level * 2);
105
+ let s = `${this.renderAnnotations()}${prefix} [${this.entity}] "${this.token("identifier")?.text ?? ""}"`;
106
+ this.tokens?.forEach((t, key) => {
107
+ s += key === "identifier" ? "" : ` ${key}: ${t.text} <${t.type}>`;
108
+ });
109
+ s += this.renderChildren();
110
+ return indent + s.split("\n").join(`\n${indent}`);
111
+ }
112
+ renderAnnotations() {
113
+ if (this.annotations) return `${this.annotations?.map(({ token, args }) => `${token.text} ${args.map((a) => a.type === "text" ? `"${a.text}"` : a.text).join(" ")}`).join("\n")}\n`;
114
+ return "";
115
+ }
116
+ renderChildren() {
117
+ if (this.definition) return isGroup(this.definition) ? `\n${this.definition.toString(1, "=")}\n` : `${this.definition.toString(0, ":")}`;
118
+ return "";
119
+ }
120
+ getDefinition() {
121
+ return this.definition;
122
+ }
123
+ constructor(entity) {
124
+ _define_property$14(this, "entity", void 0);
125
+ _define_property$14(this, "tokens", void 0);
126
+ _define_property$14(this, "isGroup", void 0);
127
+ _define_property$14(this, "definition", void 0);
128
+ _define_property$14(this, "annotations", void 0);
129
+ _define_property$14(this, "annotationsCounter", void 0);
130
+ _define_property$14(this, "_documentation", void 0);
131
+ this.entity = entity;
132
+ this.isGroup = false;
133
+ }
134
+ };
135
+
136
+ //#endregion
137
+ //#region packages/core/src/parser/nodes/array-node.ts
138
+ var SemanticArrayNode = class extends SemanticNode {
139
+ get props() {
140
+ if (this.definition) return isStructure(this.definition) ? this.definition.props : new Map();
141
+ return new Map();
142
+ }
143
+ constructor() {
144
+ super("array");
145
+ }
146
+ };
147
+
148
+ //#endregion
149
+ //#region packages/core/src/parser/nodes/const-node.ts
150
+ var SemanticConstNode = class extends SemanticNode {
151
+ registerAtDocument(doc) {
152
+ const token = this.token("identifier");
153
+ if (token && token.type === "text" && token.multiline) doc.registerMessage(token, "Unexpected end of string");
154
+ }
155
+ constructor() {
156
+ super("const");
157
+ }
158
+ };
159
+
160
+ //#endregion
161
+ //#region packages/core/src/parser/nodes/group-node.ts
162
+ function _define_property$13(obj, key, value) {
163
+ if (key in obj) Object.defineProperty(obj, key, {
164
+ value,
165
+ enumerable: true,
166
+ configurable: true,
167
+ writable: true
168
+ });
169
+ else obj[key] = value;
170
+ return obj;
171
+ }
172
+ var SemanticGroup = class extends SemanticNode {
173
+ registerAtDocument(doc) {
174
+ if (this.nodes.length > 0) this.unwrap().forEach((n) => n.registerAtDocument(doc));
175
+ }
176
+ get length() {
177
+ return this.nodes.length;
178
+ }
179
+ get first() {
180
+ return this.nodes[0];
181
+ }
182
+ get op() {
183
+ return this.operator;
184
+ }
185
+ define(node) {
186
+ if (isGroup(node)) {
187
+ this.nodes = node.unwrap();
188
+ this.operator = node.op;
189
+ } else this.nodes = [node];
190
+ return this;
191
+ }
192
+ wrap(node, token) {
193
+ node.define(this);
194
+ node.saveToken(token, "identifier");
195
+ return this;
196
+ }
197
+ unwrap() {
198
+ return this.nodes;
199
+ }
200
+ renderChildren() {
201
+ let s = " (\n";
202
+ s += this.nodes.map((n) => n.toString(2)).join(` <${this.operator || ""}>\n`);
203
+ s += "\n )";
204
+ return s;
205
+ }
206
+ constructor(nodes = [], operator) {
207
+ super("group"), _define_property$13(this, "nodes", void 0), _define_property$13(this, "operator", void 0), _define_property$13(this, "isGroup", void 0), this.nodes = nodes, this.operator = operator, this.isGroup = true;
208
+ }
209
+ };
210
+
211
+ //#endregion
212
+ //#region packages/core/src/parser/nodes/import-node.ts
213
+ var SemanticImportNode = class extends SemanticNode {
214
+ registerAtDocument(doc) {
215
+ const imports = this.definition ? this.getIdentifiersRecursive(this.definition) : [];
216
+ doc.registerImport({
217
+ from: this.token("path"),
218
+ imports,
219
+ block: this.token("inner")
220
+ });
221
+ }
222
+ constructor() {
223
+ super("import");
224
+ }
225
+ };
226
+
227
+ //#endregion
228
+ //#region packages/core/src/parser/nodes/interface-node.ts
229
+ var SemanticInterfaceNode = class extends SemanticNode {
230
+ registerAtDocument(doc) {
231
+ super.registerAtDocument(doc);
232
+ const token = this.token("identifier");
233
+ doc.registerDefinition(token);
234
+ if (token && this.token("export")) {
235
+ token.exported = true;
236
+ doc.registerExport(this);
237
+ }
238
+ }
239
+ get props() {
240
+ if (this.definition) return isStructure(this.definition) ? this.definition.props : new Map();
241
+ return new Map();
242
+ }
243
+ constructor() {
244
+ super("interface");
245
+ }
246
+ };
247
+
248
+ //#endregion
249
+ //#region packages/core/src/parser/token.ts
250
+ function _define_property$12(obj, key, value) {
251
+ if (key in obj) Object.defineProperty(obj, key, {
252
+ value,
253
+ enumerable: true,
254
+ configurable: true,
255
+ writable: true
256
+ });
257
+ else obj[key] = value;
258
+ return obj;
259
+ }
260
+ var Token = class Token {
261
+ toString() {
262
+ const children = this.hasChildren ? ` (${this.children.length})` : "";
263
+ return `[${this.type}] "${this.text}"${children}`;
264
+ }
265
+ clone(replace) {
266
+ const t = {
267
+ ...this._data,
268
+ ...replace
269
+ };
270
+ return new Token(t);
271
+ }
272
+ get text() {
273
+ return this._data.text || "";
274
+ }
275
+ get type() {
276
+ return this._data.type;
277
+ }
278
+ get range() {
279
+ return this._data.getRange();
280
+ }
281
+ get children() {
282
+ return this._data.children || [];
283
+ }
284
+ get hasChildren() {
285
+ return Boolean(this._data.children?.length);
286
+ }
287
+ /**
288
+ * This is truth if the text token was ended with a newline character
289
+ */ get multiline() {
290
+ return this._data.multiline;
291
+ }
292
+ get isAnnotation() {
293
+ return this._data.type === "annotation";
294
+ }
295
+ constructor(_data) {
296
+ _define_property$12(this, "_data", void 0);
297
+ /**
298
+ * Set this to file path (e.g. "./src/file.as") for path token in import statement
299
+ */ _define_property$12(this, "fromPath", void 0);
300
+ /**
301
+ * All definitions that exported must be marked with this flag
302
+ */ _define_property$12(this, "exported", void 0);
303
+ /**
304
+ * All the definitions must be marked with this flag
305
+ */ _define_property$12(this, "isDefinition", void 0);
306
+ /**
307
+ * All the references must be marked with this flag
308
+ */ _define_property$12(this, "isReference", void 0);
309
+ /**
310
+ * All the import tokens must be marked with this flag
311
+ */ _define_property$12(this, "imported", void 0);
312
+ /**
313
+ * All the props must be marked with this flag
314
+ */ _define_property$12(this, "isProp", void 0);
315
+ /**
316
+ * Refs chained via . or ["propName"] are marked with this flag
317
+ */ _define_property$12(this, "isChain", void 0);
318
+ _define_property$12(this, "parentNode", void 0);
319
+ /**
320
+ * Only for annotation arguments: reference to their annotation token
321
+ */ _define_property$12(this, "annotationRef", void 0);
322
+ _define_property$12(this, "index", void 0);
323
+ /**
324
+ * Block type
325
+ */ _define_property$12(this, "blockType", void 0);
326
+ this._data = _data;
327
+ }
328
+ };
329
+
330
+ //#endregion
331
+ //#region packages/core/src/parser/nodes/primitive-node.ts
332
+ function _define_property$11(obj, key, value) {
333
+ if (key in obj) Object.defineProperty(obj, key, {
334
+ value,
335
+ enumerable: true,
336
+ configurable: true,
337
+ writable: true
338
+ });
339
+ else obj[key] = value;
340
+ return obj;
341
+ }
342
+ var SemanticPrimitiveNode = class SemanticPrimitiveNode extends SemanticNode {
343
+ applyAnnotations() {
344
+ this.annotations = [];
345
+ if (this.type === "string" || this.type === "array") {
346
+ if (typeof this.config.expect?.minLength === "number") this.annotations.push({
347
+ name: "expect.minLength",
348
+ token: dummyToken,
349
+ args: [num(this.config.expect.minLength)]
350
+ });
351
+ if (typeof this.config.expect?.maxLength === "number") this.annotations.push({
352
+ name: "expect.maxLength",
353
+ token: dummyToken,
354
+ args: [num(this.config.expect.maxLength)]
355
+ });
356
+ }
357
+ if (this.type === "string") {
358
+ if (typeof this.config.expect?.pattern !== "undefined") {
359
+ const patterns = Array.isArray(this.config.expect.pattern) ? this.config.expect.pattern : [this.config.expect.pattern];
360
+ for (const p of patterns) {
361
+ const args = typeof p === "string" ? [text$1(p)] : [text$1(p.source), text$1(p.flags)];
362
+ if (this.config.expect.message) args[2] = text$1(this.config.expect.message);
363
+ this.annotations.push({
364
+ name: "expect.pattern",
365
+ token: dummyToken,
366
+ args
367
+ });
368
+ }
369
+ }
370
+ }
371
+ if (this.type === "number") {
372
+ if (typeof this.config.expect?.min === "number") this.annotations.push({
373
+ name: "expect.min",
374
+ token: dummyToken,
375
+ args: [num(this.config.expect.min)]
376
+ });
377
+ if (typeof this.config.expect?.max === "number") this.annotations.push({
378
+ name: "expect.max",
379
+ token: dummyToken,
380
+ args: [num(this.config.expect.max)]
381
+ });
382
+ if (this.config.expect?.int === true) this.annotations.push({
383
+ name: "expect.int",
384
+ token: dummyToken,
385
+ args: []
386
+ });
387
+ }
388
+ }
389
+ get key() {
390
+ return this.parentKey ? `${this.parentKey}.${this._id}` : this._id;
391
+ }
392
+ getAllTags(_processed) {
393
+ const allTags = [this._id];
394
+ const processed = _processed || new Set();
395
+ processed.add(this);
396
+ for (const [, node] of this.props) {
397
+ if (processed.has(node)) continue;
398
+ processed.add(node);
399
+ allTags.push(...node.getAllTags(processed));
400
+ }
401
+ return allTags;
402
+ }
403
+ get id() {
404
+ return this._id;
405
+ }
406
+ get documentation() {
407
+ return this.config.documentation ? `**${this.key}** - ${this.config.documentation}` : `**${this.key}**`;
408
+ }
409
+ toString(level = 0, prefix = "●") {
410
+ const indent = " ".repeat(level * 2);
411
+ let s = `${this.renderAnnotations()}${prefix} [${this.entity}] ${JSON.stringify(this.config.type)}`;
412
+ s += this.renderChildren();
413
+ return indent + s.split("\n").join(`\n${indent}`);
414
+ }
415
+ constructor(_id, config, parentKey = "") {
416
+ super("primitive"), _define_property$11(this, "_id", void 0), _define_property$11(this, "config", void 0), _define_property$11(this, "parentKey", void 0), _define_property$11(this, "type", void 0), _define_property$11(this, "props", void 0), _define_property$11(this, "tags", void 0), this._id = _id, this.config = config, this.parentKey = parentKey;
417
+ this.props = new Map();
418
+ this.tags = new Set([_id, ...config?.tags || []]);
419
+ for (const [ext, def] of Object.entries(config.extensions || {})) {
420
+ const node = new SemanticPrimitiveNode(ext, {
421
+ type: def.type ?? config.type,
422
+ documentation: def.documentation ?? config.documentation,
423
+ extensions: def.extensions,
424
+ tags: Array.from(new Set([...def.tags || [], ...Array.from(this.tags)])),
425
+ expect: {
426
+ ...config.expect,
427
+ ...def.expect
428
+ }
429
+ }, this.key);
430
+ this.props.set(ext, node);
431
+ }
432
+ if (typeof config.type === "object") this.type = config.type.kind === "final" ? config.type.value : config.type.kind;
433
+ else this.type = config.type;
434
+ this.applyAnnotations();
435
+ }
436
+ };
437
+ const dummyToken = new Token({
438
+ getRange: () => ({
439
+ end: {
440
+ character: 0,
441
+ line: 0
442
+ },
443
+ start: {
444
+ character: 0,
445
+ line: 0
446
+ }
447
+ }),
448
+ text: "",
449
+ type: "identifier"
450
+ });
451
+ const num = (val) => new Token({
452
+ getRange: () => ({
453
+ end: {
454
+ character: 0,
455
+ line: 0
456
+ },
457
+ start: {
458
+ character: 0,
459
+ line: 0
460
+ }
461
+ }),
462
+ text: val.toString(),
463
+ type: "number"
464
+ });
465
+ const text$1 = (val) => new Token({
466
+ getRange: () => ({
467
+ end: {
468
+ character: 0,
469
+ line: 0
470
+ },
471
+ start: {
472
+ character: 0,
473
+ line: 0
474
+ }
475
+ }),
476
+ text: val,
477
+ type: "text"
478
+ });
479
+
480
+ //#endregion
481
+ //#region packages/core/src/parser/nodes/prop-node.ts
482
+ var SemanticPropNode = class extends SemanticNode {
483
+ registerAtDocument(doc) {
484
+ super.registerAtDocument(doc);
485
+ const token = this.token("identifier");
486
+ if (token && token.type === "text" && token.multiline) doc.registerMessage(token, "Unexpected end of string");
487
+ }
488
+ get nestedProps() {
489
+ if (this.definition && isStructure(this.definition)) return this.definition.props;
490
+ }
491
+ get nestedType() {
492
+ if (this.definition && isRef(this.definition)) return this.definition;
493
+ }
494
+ constructor() {
495
+ super("prop");
496
+ }
497
+ };
498
+
499
+ //#endregion
500
+ //#region packages/core/src/parser/nodes/ref-node.ts
501
+ function _define_property$10(obj, key, value) {
502
+ if (key in obj) Object.defineProperty(obj, key, {
503
+ value,
504
+ enumerable: true,
505
+ configurable: true,
506
+ writable: true
507
+ });
508
+ else obj[key] = value;
509
+ return obj;
510
+ }
511
+ var SemanticRefNode = class extends SemanticNode {
512
+ get referredIdentifiers() {
513
+ return [this.token("identifier")];
514
+ }
515
+ registerAtDocument(doc) {
516
+ super.registerAtDocument(doc);
517
+ this.token("identifier").index = 0;
518
+ this._chain.forEach((c) => {
519
+ doc.tokensIndex.add(c);
520
+ });
521
+ this._dots.forEach((d) => {
522
+ doc.tokensIndex.add(d);
523
+ });
524
+ }
525
+ addChain(token) {
526
+ token.parentNode = this;
527
+ token.isChain = true;
528
+ token.index = this._chain.length + 1;
529
+ this._chain.push(token);
530
+ }
531
+ addDot(token) {
532
+ token.parentNode = this;
533
+ token.isChain = true;
534
+ token.index = this._chain.length;
535
+ this._dots.push(token);
536
+ }
537
+ get chain() {
538
+ return this._chain;
539
+ }
540
+ get hasChain() {
541
+ return this._chain.length > 0;
542
+ }
543
+ toString(level = 0, prefix = "●") {
544
+ const indent = " ".repeat(level * 2);
545
+ let s = `${this.renderAnnotations()}${prefix} [${this.entity}] "${this.token("identifier")?.text ?? ""}"`;
546
+ this.tokens?.forEach((t, key) => {
547
+ s += key === "identifier" ? "" : ` ${key}: ${t.text} <${t.type}>`;
548
+ });
549
+ s += this.hasChain ? `.${this.chain.map((c) => `["${c.text}"]`).join(".")}` : "";
550
+ return indent + s.split("\n").join(`\n${indent}`);
551
+ }
552
+ constructor() {
553
+ super("ref"), _define_property$10(this, "_chain", []), _define_property$10(this, "_dots", []);
554
+ }
555
+ };
556
+
557
+ //#endregion
558
+ //#region packages/core/src/parser/nodes/structure-node.ts
559
+ function _define_property$9(obj, key, value) {
560
+ if (key in obj) Object.defineProperty(obj, key, {
561
+ value,
562
+ enumerable: true,
563
+ configurable: true,
564
+ writable: true
565
+ });
566
+ else obj[key] = value;
567
+ return obj;
568
+ }
569
+ var SemanticStructureNode = class extends SemanticGroup {
570
+ /**
571
+ * Shortcut to set props, used as utility
572
+ */ setProps(props$1) {
573
+ this.nodes = props$1;
574
+ for (const prop of props$1) this.props.set(prop.id, prop);
575
+ }
576
+ registerAtDocument(doc) {
577
+ super.registerAtDocument(doc);
578
+ const block$2 = this.token("identifier");
579
+ block$2.blockType = "structure";
580
+ doc.blocksIndex.add(block$2);
581
+ for (const node of this.nodes) {
582
+ const token = node.token("identifier");
583
+ if (!token) {
584
+ doc.registerMessage(block$2, "Has empty prop node");
585
+ continue;
586
+ }
587
+ const name = token.text;
588
+ if (typeof name !== "string") {
589
+ doc.registerMessage(token, "Prop node has no name");
590
+ continue;
591
+ }
592
+ if (this.props.has(name)) {
593
+ doc.registerMessage(token, "Duplicate prop identifier");
594
+ continue;
595
+ }
596
+ if (!isProp(node)) {
597
+ doc.registerMessage(token, "Non-prop node");
598
+ continue;
599
+ }
600
+ this.props.set(name, node);
601
+ }
602
+ }
603
+ addVirtualProp(opts) {
604
+ const token = opts.refToken || this.token("identifier");
605
+ const propToken = token.clone({
606
+ type: "identifier",
607
+ text: opts.name
608
+ });
609
+ const prop = new SemanticPropNode();
610
+ if (opts.documentation) prop.setDocumentation(opts.documentation);
611
+ prop.saveToken(propToken, "identifier");
612
+ if (typeof opts.type === "string") {
613
+ const ref$1 = new SemanticRefNode();
614
+ const [first, ...rest] = opts.type.split(".");
615
+ const refToken = token.clone({
616
+ type: "identifier",
617
+ text: first
618
+ });
619
+ ref$1.saveToken(refToken, "identifier");
620
+ for (const chain of rest) {
621
+ const chainToken = token.clone({
622
+ type: "identifier",
623
+ text: chain
624
+ });
625
+ ref$1.addChain(chainToken);
626
+ }
627
+ prop.define(ref$1);
628
+ } else prop.define(opts.type);
629
+ this.nodes.push(prop);
630
+ this.props.set(opts.name, prop);
631
+ }
632
+ constructor() {
633
+ super(), _define_property$9(this, "props", new Map());
634
+ this.entity = "structure";
635
+ }
636
+ };
637
+
638
+ //#endregion
639
+ //#region packages/core/src/parser/nodes/tuple-node.ts
640
+ var SemanticTupleNode = class extends SemanticGroup {
641
+ constructor() {
642
+ super();
643
+ this.entity = "tuple";
644
+ }
645
+ };
646
+
647
+ //#endregion
648
+ //#region packages/core/src/parser/nodes/type-node.ts
649
+ var SemanticTypeNode = class extends SemanticNode {
650
+ registerAtDocument(doc) {
651
+ super.registerAtDocument(doc);
652
+ const token = this.token("identifier");
653
+ doc.registerDefinition(token);
654
+ if (token && this.token("export")) {
655
+ token.exported = true;
656
+ doc.registerExport(this);
657
+ }
658
+ if (this.definition) {}
659
+ }
660
+ constructor() {
661
+ super("type");
662
+ }
663
+ };
664
+
665
+ //#endregion
666
+ //#region packages/core/src/parser/nodes/index.ts
667
+ const $n = {
668
+ SemanticGroup,
669
+ SemanticInterfaceNode,
670
+ SemanticTypeNode,
671
+ SemanticRefNode,
672
+ SemanticConstNode,
673
+ SemanticPropNode,
674
+ SemanticStructureNode,
675
+ SemanticTupleNode,
676
+ SemanticArrayNode,
677
+ SemanticImportNode,
678
+ SemanticPrimitiveNode
679
+ };
680
+ function isGroup(node) {
681
+ return node?.entity === "group" || node?.entity === "structure" || node?.entity === "tuple";
682
+ }
683
+ function isInterface(node) {
684
+ return node?.entity === "interface";
685
+ }
686
+ function isType(node) {
687
+ return node?.entity === "type";
688
+ }
689
+ function isRef(node) {
690
+ return node?.entity === "ref";
691
+ }
692
+ function isConst(node) {
693
+ return node?.entity === "const";
694
+ }
695
+ function isProp(node) {
696
+ return node?.entity === "prop";
697
+ }
698
+ function isStructure(node) {
699
+ return node?.entity === "structure";
700
+ }
701
+ function isTuple(node) {
702
+ return node?.entity === "tuple";
703
+ }
704
+ function isArray(node) {
705
+ return node?.entity === "array";
706
+ }
707
+ function isImport(node) {
708
+ return node?.entity === "import";
709
+ }
710
+ function isPrimitive(node) {
711
+ return node?.entity === "primitive";
712
+ }
713
+
714
+ //#endregion
715
+ //#region packages/core/src/annotations/annotation-spec.ts
716
+ function _define_property$8(obj, key, value) {
717
+ if (key in obj) Object.defineProperty(obj, key, {
718
+ value,
719
+ enumerable: true,
720
+ configurable: true,
721
+ writable: true
722
+ });
723
+ else obj[key] = value;
724
+ return obj;
725
+ }
726
+ var AnnotationSpec = class {
727
+ get arguments() {
728
+ if (!this.config.argument) return [];
729
+ return Array.isArray(this.config.argument) ? this.config.argument : [this.config.argument];
730
+ }
731
+ get argumentsSnippet() {
732
+ if (this.arguments.length === 0) return "";
733
+ return this.arguments.map((arg, index) => {
734
+ const placeholderIndex = index + 1;
735
+ const defaultValue = this.getDefaultValueForType(arg.name, arg.type);
736
+ const quote = arg.type === "string" ? `'` : "";
737
+ return `${quote}\${${placeholderIndex}:${defaultValue}}${quote}`;
738
+ }).join(", ");
739
+ }
740
+ validateType(tokenType, type$1) {
741
+ switch (type$1) {
742
+ case "string": return tokenType === "text" ? undefined : "string expected.";
743
+ case "number": return tokenType === "number" ? undefined : "number expected.";
744
+ case "boolean": return tokenType === "identifier" ? undefined : "boolean expected.";
745
+ default: return `unknown type "${type$1}".`;
746
+ }
747
+ }
748
+ modify(mainToken, args, doc) {
749
+ if (this.config.modify) this.config.modify(mainToken, args, doc);
750
+ }
751
+ validate(mainToken, args, doc) {
752
+ const messages = [];
753
+ const specArgs = this.arguments;
754
+ if (!mainToken.parentNode) return;
755
+ if (mainToken.parentNode.countAnnotations(mainToken.text.slice(1)) > 1 && !this.config.multiple) messages.push({
756
+ severity: 1,
757
+ message: `Multiple "${mainToken.text}" annotations are not allowed.`,
758
+ range: mainToken.range
759
+ });
760
+ if (this.config.nodeType && this.config.nodeType.length > 0 && !this.config.nodeType.includes(mainToken.parentNode.entity)) messages.push({
761
+ severity: 1,
762
+ message: `${mainToken.text} applies only to ${this.config.nodeType.join(", ")} nodes.`,
763
+ range: mainToken.range
764
+ });
765
+ const requiredCount = specArgs.filter((a) => !a.optional).length;
766
+ if (args.length < requiredCount) messages.push({
767
+ severity: 1,
768
+ message: `${mainToken.text} requires at least ${requiredCount} arguments, but got ${args.length}.`,
769
+ range: mainToken.range
770
+ });
771
+ if (args.length > specArgs.length) {
772
+ const i = specArgs.length;
773
+ messages.push({
774
+ severity: 1,
775
+ message: `${mainToken.text} got ${args.length} arguments, expected ${specArgs.length}.`,
776
+ range: {
777
+ start: args[i].range.start,
778
+ end: args[args.length - 1].range.end
779
+ }
780
+ });
781
+ }
782
+ for (let i = 0; i < args.length; i++) {
783
+ const token = args[i];
784
+ if (i >= specArgs.length) break;
785
+ const argSpec = specArgs[i];
786
+ const tokenType = token.type;
787
+ const valueText = token.text;
788
+ const typeMessage = this.validateType(tokenType, argSpec.type);
789
+ if (typeMessage) {
790
+ messages.push({
791
+ severity: 1,
792
+ message: `${mainToken.text} at argument #${i + 1}: ${typeMessage}`,
793
+ range: token.range
794
+ });
795
+ continue;
796
+ }
797
+ const values = argSpec.type === "boolean" ? ["true", "false"] : argSpec.values;
798
+ if (values && !values.includes(valueText)) messages.push({
799
+ severity: 1,
800
+ message: `${mainToken.text} at argument #${i + 1} ("${argSpec.name}") must be one of [${values.join(", ")}]`,
801
+ range: token.range
802
+ });
803
+ if (this.config.defType?.length) {
804
+ let def = mainToken.parentNode.getDefinition();
805
+ if (isRef(def)) def = doc.unwindType(def.id, def.chain)?.def || def;
806
+ let defEntity = def?.entity || "unknown";
807
+ if (isInterface(def) || isStructure(def)) defEntity = "object";
808
+ else if (isGroup(def) && def.entity !== "tuple") defEntity = def.op === "&" ? "intersection" : "union";
809
+ if (!isPrimitive(def) && !this.config.defType.includes(defEntity) || isPrimitive(def) && !this.config.defType.includes(def.type)) messages.push({
810
+ message: `Expected type is (${this.config.defType.join(" | ")}), got "${isPrimitive(def) ? def.type : def?.entity || "unknown"}"`,
811
+ severity: 1,
812
+ range: mainToken.range
813
+ });
814
+ }
815
+ }
816
+ if (this.config.validate) messages.push(...this.config.validate(mainToken, args, doc) || []);
817
+ return messages.length > 0 ? messages : undefined;
818
+ }
819
+ renderDocs(index) {
820
+ if (typeof index === "number") {
821
+ const a = this.arguments[index];
822
+ if (a) {
823
+ const values = a.values ? `\n\nValues:\n${a.values.join(", ")}` : "";
824
+ return `### \`${a.name}${a.optional ? "?" : ""}: ${a.type}\`\n\n${a.description}${values}`;
825
+ }
826
+ } else {
827
+ const args = this.arguments;
828
+ return `### ${index} ${args.map((a) => `\`${a.name}${a.optional ? "?" : ""}: ${a.type}\``).join(", ")}\n\n${this.config.description}`;
829
+ }
830
+ }
831
+ getDefaultValueForType(name, type$1) {
832
+ switch (type$1) {
833
+ case "string": return name;
834
+ case "number": return "0";
835
+ case "boolean": return "true";
836
+ default: return "";
837
+ }
838
+ }
839
+ constructor(config) {
840
+ _define_property$8(this, "config", void 0);
841
+ _define_property$8(this, "__is_annotation_spec", void 0);
842
+ this.config = config;
843
+ this.__is_annotation_spec = true;
844
+ }
845
+ };
846
+ function isAnnotationSpec(a) {
847
+ return Boolean(a) && a.__is_annotation_spec;
848
+ }
849
+ function resolveAnnotation(name, annotationsTree) {
850
+ const parts = name.split(".");
851
+ let current = annotationsTree;
852
+ for (const part of parts) {
853
+ if (!current || isAnnotationSpec(current)) return undefined;
854
+ current = current[part];
855
+ }
856
+ return isAnnotationSpec(current) ? current : undefined;
857
+ }
858
+
859
+ //#endregion
860
+ //#region packages/core/src/config/define-config.ts
861
+ function defineConfig(config) {
862
+ return config;
863
+ }
864
+
865
+ //#endregion
866
+ //#region packages/core/src/config/load-config.ts
867
+ async function bundleTsConfig(configFile, forceFormat) {
868
+ const dirnameVarName = "injected_original_dirname";
869
+ const filenameVarName = "injected_original_filename";
870
+ const importMetaUrlVarName = "injected_original_import_meta_url";
871
+ const bundle = await rolldown({
872
+ input: configFile,
873
+ platform: "node",
874
+ resolve: { mainFields: ["main"] },
875
+ define: {
876
+ "__dirname": dirnameVarName,
877
+ "__filename": filenameVarName,
878
+ "import.meta.url": importMetaUrlVarName,
879
+ "import.meta.dirname": dirnameVarName,
880
+ "import.meta.filename": filenameVarName
881
+ },
882
+ treeshake: false,
883
+ external: [/^[\w@][^:]/u],
884
+ plugins: [{
885
+ name: "inject-file-scope-variables",
886
+ transform: {
887
+ filter: { id: /\.[cm]?[jt]s$/u },
888
+ handler(code, id) {
889
+ const injectValues = `const ${dirnameVarName} = ${JSON.stringify(path.dirname(id))};` + `const ${filenameVarName} = ${JSON.stringify(id)};` + `const ${importMetaUrlVarName} = ${JSON.stringify(pathToFileURL(id).href)};`;
890
+ return {
891
+ code: injectValues + code,
892
+ map: null
893
+ };
894
+ }
895
+ }
896
+ }]
897
+ });
898
+ const outputDir = path.dirname(configFile);
899
+ const result = await bundle.write({
900
+ dir: outputDir,
901
+ format: forceFormat || "esm",
902
+ sourcemap: "inline",
903
+ entryFileNames: forceFormat === "cjs" ? "atscript.config.[hash].cjs" : "atscript.config.[hash].mjs"
904
+ });
905
+ const fileName = result.output.find((chunk) => chunk.type === "chunk" && chunk.isEntry).fileName;
906
+ return path.join(outputDir, fileName);
907
+ }
908
+ const SUPPORTED_JS_CONFIG_FORMATS = [
909
+ ".js",
910
+ ".mjs",
911
+ ".cjs"
912
+ ];
913
+ const SUPPORTED_TS_CONFIG_FORMATS = [
914
+ ".ts",
915
+ ".mts",
916
+ ".cts"
917
+ ];
918
+ const SUPPORTED_CONFIG_FORMATS = [...SUPPORTED_JS_CONFIG_FORMATS, ...SUPPORTED_TS_CONFIG_FORMATS];
919
+ const DEFAULT_CONFIG_BASE = "atscript.config";
920
+ async function resolveConfigFile(docUri, _root) {
921
+ const startDir = docUri.endsWith(".as") ? path.dirname(docUri) : docUri;
922
+ const root$1 = _root || startDir;
923
+ let currentDir = startDir;
924
+ const rootId = "file://" + root$1;
925
+ while (true) {
926
+ const candidate = await findConfigFileName(currentDir);
927
+ if (candidate) return candidate;
928
+ const parentDir = path.dirname(currentDir);
929
+ if (currentDir === rootId || parentDir === currentDir) break;
930
+ currentDir = parentDir;
931
+ }
932
+ return undefined;
933
+ }
934
+ async function findConfigFileName(d) {
935
+ const p = d.startsWith("file://") ? d.slice(7) : d;
936
+ const filesInWorkingDirectory = new Set(await readdir(decodeURIComponent(p)));
937
+ for (const extension of SUPPORTED_CONFIG_FORMATS) {
938
+ const fileName = `${DEFAULT_CONFIG_BASE}${extension}`;
939
+ if (filesInWorkingDirectory.has(fileName)) return fileName;
940
+ }
941
+ }
942
+ async function loadTsConfig(configFile, forceFormat) {
943
+ const file = await bundleTsConfig(configFile, forceFormat);
944
+ try {
945
+ return (await import(pathToFileURL(file).href)).default;
946
+ } catch (error) {
947
+ console.error("Could not load config file", file, error);
948
+ return {};
949
+ } finally {
950
+ fs.unlink(file, () => {});
951
+ }
952
+ }
953
+ async function loadConfig(configPath, forceFormat) {
954
+ const ext = path.extname(configPath);
955
+ try {
956
+ if (SUPPORTED_JS_CONFIG_FORMATS.includes(ext)) return forceFormat ? await loadTsConfig(path.resolve(configPath), forceFormat) : (await import(pathToFileURL(configPath).href)).default;
957
+ else if (SUPPORTED_TS_CONFIG_FORMATS.includes(ext)) {
958
+ const rawConfigPath = path.resolve(configPath);
959
+ return await loadTsConfig(rawConfigPath, forceFormat);
960
+ } else throw new Error(`Unsupported config format. Expected: \`${SUPPORTED_CONFIG_FORMATS.join(",")}\` but got \`${ext}\``);
961
+ } catch (error) {
962
+ throw new Error("Error happened while loading config.");
963
+ }
964
+ }
965
+
966
+ //#endregion
967
+ //#region packages/core/src/parser/id-registry.ts
968
+ function _define_property$7(obj, key, value) {
969
+ if (key in obj) Object.defineProperty(obj, key, {
970
+ value,
971
+ enumerable: true,
972
+ configurable: true,
973
+ writable: true
974
+ });
975
+ else obj[key] = value;
976
+ return obj;
977
+ }
978
+ var IdRegistry = class {
979
+ clear() {
980
+ this.definitions.clear();
981
+ this.duplicates.clear();
982
+ this.forbidden.clear();
983
+ }
984
+ registerDefinition(token) {
985
+ if (!token) return;
986
+ if (this.reserved.has(token.text)) this.forbidden.add(token);
987
+ else if (this.definitions.has(token.text)) this.duplicates.add(token);
988
+ else this.definitions.set(token.text, token);
989
+ }
990
+ isDefined(t) {
991
+ const text$2 = typeof t === "string" ? t : t.text;
992
+ return this.definitions.has(text$2) || this.globalTypes.has(text$2);
993
+ }
994
+ getErrors() {
995
+ return [...Array.from(this.duplicates, (t) => ({
996
+ severity: 1,
997
+ message: `Duplicate identifier "${t.text}"`,
998
+ range: t.range
999
+ })), ...Array.from(this.forbidden, (t) => ({
1000
+ severity: 1,
1001
+ message: `Reserved keyword "${t.text}"`,
1002
+ range: t.range
1003
+ }))];
1004
+ }
1005
+ constructor(globalTypes = []) {
1006
+ _define_property$7(this, "reserved", void 0);
1007
+ _define_property$7(this, "globalTypes", void 0);
1008
+ _define_property$7(this, "definitions", new Map());
1009
+ _define_property$7(this, "duplicates", new Set());
1010
+ _define_property$7(this, "forbidden", new Set());
1011
+ this.reserved = new Set([
1012
+ "interface",
1013
+ "type",
1014
+ "import",
1015
+ "from",
1016
+ "export"
1017
+ ].concat(globalTypes));
1018
+ this.globalTypes = new Set(globalTypes);
1019
+ }
1020
+ };
1021
+
1022
+ //#endregion
1023
+ //#region packages/core/src/parser/iterator.ts
1024
+ function _define_property$6(obj, key, value) {
1025
+ if (key in obj) Object.defineProperty(obj, key, {
1026
+ value,
1027
+ enumerable: true,
1028
+ configurable: true,
1029
+ writable: true
1030
+ });
1031
+ else obj[key] = value;
1032
+ return obj;
1033
+ }
1034
+ var NodeIterator = class NodeIterator {
1035
+ get index() {
1036
+ return this.i;
1037
+ }
1038
+ get lastNode() {
1039
+ return this.nodes[this.nodes.length - 1];
1040
+ }
1041
+ unexpectedEOB() {
1042
+ this.issues.unexpectedEOB = true;
1043
+ }
1044
+ unfork(fork) {
1045
+ this.i = fork.index;
1046
+ this.update();
1047
+ }
1048
+ accepted() {
1049
+ if (this.$ && this.$.accepted !== false) {
1050
+ this.$.accepted = true;
1051
+ this.badNodes.delete(this.$);
1052
+ }
1053
+ }
1054
+ toString() {
1055
+ return this.$ ? `[${this.$.type}] ${this.$.text}` : `void`;
1056
+ }
1057
+ update() {
1058
+ this.$ = this.nodes[this.i];
1059
+ return this;
1060
+ }
1061
+ move(v = 1) {
1062
+ this.i += v;
1063
+ this.$ = this.nodes[this.i];
1064
+ return this;
1065
+ }
1066
+ /** @deprecated */ killNextNode(n = 1) {
1067
+ this.nodes.splice(this.i + 1, n);
1068
+ }
1069
+ next(skip) {
1070
+ return this.fork().move().skip(skip);
1071
+ }
1072
+ fork(nodes) {
1073
+ return new NodeIterator(nodes || this.nodes, this.messages, this.badNodes, this.issues, nodes ? this.$ : this.parent, nodes ? 0 : this.i).update();
1074
+ }
1075
+ skip(pun$1) {
1076
+ while (this.$?.type === "comment" || this.$?.type === "punctuation" && pun$1?.length && pun$1.includes(this.$.text)) this.move();
1077
+ return this;
1078
+ }
1079
+ skipUntil(pun$1) {
1080
+ while (this.$ && !this.satisfies({
1081
+ node: "punctuation",
1082
+ text: pun$1
1083
+ })) this.move();
1084
+ }
1085
+ unexpected(force = false, msg = "Unexpected token") {
1086
+ if (force && this.$) this.$.accepted = false;
1087
+ if (this.$ && !this.badNodes.has(this.$)) this.badNodes.set(this.$, msg);
1088
+ }
1089
+ shouldHaveError(depth) {
1090
+ for (let i = this.i; i <= depth; i++) if (i < this.nodes.length) this.nodes[i].accepted = false;
1091
+ }
1092
+ nodesLeft() {
1093
+ return this.nodes.length > 0 && this.index < this.nodes.length;
1094
+ }
1095
+ satisfies(...rules) {
1096
+ for (const rule of rules) {
1097
+ const passed = Array.isArray(rule.node) ? rule.node.includes(this.$?.type) : this.$?.type === rule.node;
1098
+ if (passed && rule.text === undefined) return true;
1099
+ if (passed && Array.isArray(rule.text) ? rule.text.includes(this.$?.text) : this.$?.text === rule.text) return true;
1100
+ }
1101
+ return false;
1102
+ }
1103
+ confirmIssues() {
1104
+ if (this.issues.unexpectedEOB) {
1105
+ const node = this.lastNode || this.parent;
1106
+ const pos = node?.getRange().end || {
1107
+ character: 1,
1108
+ line: 1
1109
+ };
1110
+ this.messages.push({
1111
+ severity: 1,
1112
+ message: `Unexpected end of block`,
1113
+ range: {
1114
+ start: pos,
1115
+ end: pos
1116
+ }
1117
+ });
1118
+ this.issues.unexpectedEOB = false;
1119
+ }
1120
+ }
1121
+ getErrors() {
1122
+ this.badNodes.forEach((msg, node) => {
1123
+ if (node.accepted) this.badNodes.delete(node);
1124
+ });
1125
+ return Array.from(this.badNodes.entries(), ([node, msg]) => ({
1126
+ severity: 1,
1127
+ message: msg,
1128
+ range: node.getRange?.() || {
1129
+ start: {
1130
+ character: 1,
1131
+ line: 1
1132
+ },
1133
+ end: {
1134
+ character: 1,
1135
+ line: 1
1136
+ }
1137
+ }
1138
+ })).concat(this.messages);
1139
+ }
1140
+ constructor(nodes, messages = [], badNodes = new Map(), issues = {}, parent, i = -1) {
1141
+ _define_property$6(this, "nodes", void 0);
1142
+ _define_property$6(this, "messages", void 0);
1143
+ _define_property$6(this, "badNodes", void 0);
1144
+ _define_property$6(this, "issues", void 0);
1145
+ _define_property$6(this, "parent", void 0);
1146
+ _define_property$6(this, "i", void 0);
1147
+ _define_property$6(this, "$", void 0);
1148
+ this.nodes = nodes;
1149
+ this.messages = messages;
1150
+ this.badNodes = badNodes;
1151
+ this.issues = issues;
1152
+ this.parent = parent;
1153
+ this.i = i;
1154
+ }
1155
+ };
1156
+
1157
+ //#endregion
1158
+ //#region packages/core/src/parser/utils.ts
1159
+ function toVsCodeRange(start, end, startOffset = 0, endOffset = 0) {
1160
+ return {
1161
+ start: {
1162
+ line: start.row - 1,
1163
+ character: start.col + startOffset
1164
+ },
1165
+ end: {
1166
+ line: end.row - 1,
1167
+ character: end.col + endOffset
1168
+ }
1169
+ };
1170
+ }
1171
+ function resolveAtscriptFromPath(from, id) {
1172
+ return `file://${path$1.join(id.slice(7).split("/").slice(0, -1).join("/"), from)}.as`;
1173
+ }
1174
+ function getRelPath(fromUri, toUri) {
1175
+ const fromPath = new URL(fromUri).pathname;
1176
+ const toPath = new URL(toUri).pathname;
1177
+ const relPath = path$1.relative(path$1.dirname(fromPath), toPath);
1178
+ const { dir, name } = path$1.parse(relPath);
1179
+ const prefix = dir.startsWith("..") ? "" : "./";
1180
+ return `${prefix}${dir ? `${dir}/` : ""}${name}`;
1181
+ }
1182
+
1183
+ //#endregion
1184
+ //#region packages/core/src/tokenizer/tokens/a-identifier.token.ts
1185
+ const AIdentifierToken = new BasicNode({
1186
+ icon: "@",
1187
+ tokens: [RegExp("@[\\p{ID_Continue}$.]*", "u"), RegExp("[^\\p{ID_Continue}$.]", "u")],
1188
+ tokenOE: "-eject"
1189
+ }).mapContent("text", "join-clear").onMatch((context) => {
1190
+ context.customData.type = "annotation";
1191
+ });
1192
+
1193
+ //#endregion
1194
+ //#region packages/core/src/tokenizer/tokens/block.token.ts
1195
+ const pairs = {
1196
+ "{": "}",
1197
+ "(": ")",
1198
+ "[": "]"
1199
+ };
1200
+ const BlockToken = new BasicNode({
1201
+ label: "block",
1202
+ icon: "→",
1203
+ tokens: [RegExp("(?<text>[([{])", "u"), (context) => pairs[context.getCustomData().text] || ""],
1204
+ tokenOE: "omit-omit",
1205
+ skipToken: /\s/u
1206
+ }).onMatch((context) => {
1207
+ context.customData.type = "block";
1208
+ });
1209
+
1210
+ //#endregion
1211
+ //#region packages/core/src/tokenizer/tokens/comment.token.ts
1212
+ const inline = new BasicNode({
1213
+ label: "inline-comment",
1214
+ icon: "“",
1215
+ tokens: ["//", /$/mu],
1216
+ tokenOE: "omit-omit"
1217
+ }).mapContent("text", "join-clear").popsAtEOFSource(true).onMatch((context) => {
1218
+ context.customData.type = "comment";
1219
+ });
1220
+ const block$1 = new BasicNode({
1221
+ label: "block-comment",
1222
+ icon: "“",
1223
+ tokens: ["/*", "*/"],
1224
+ tokenOE: "omit-omit"
1225
+ }).mapContent("text", "join-clear").popsAtEOFSource(true).onMatch((context) => {
1226
+ context.customData.type = "comment";
1227
+ });
1228
+ const commentNodes = {
1229
+ inline,
1230
+ block: block$1,
1231
+ all: [inline, block$1]
1232
+ };
1233
+
1234
+ //#endregion
1235
+ //#region packages/core/src/tokenizer/tokens/identifier.token.ts
1236
+ const IdentifierToken = new BasicNode({
1237
+ icon: "I",
1238
+ tokens: [RegExp("[\\p{ID_Start}$_][\\p{ID_Continue}$]*", "u"), RegExp("[^\\p{ID_Continue}$]", "u")],
1239
+ tokenOE: "consume-eject"
1240
+ }).mapContent("text", "join-clear").onMatch((context) => {
1241
+ context.customData.type = "identifier";
1242
+ });
1243
+
1244
+ //#endregion
1245
+ //#region packages/core/src/tokenizer/tokens/number.token.ts
1246
+ const NumberToken = new BasicNode({
1247
+ icon: "N",
1248
+ tokens: [RegExp("\\d[\\p{ID_Continue}$]*", "u"), RegExp("[^\\p{ID_Continue}$]", "u")],
1249
+ tokenOE: "consume-eject"
1250
+ }).mapContent("text", "join-clear").onMatch((context) => {
1251
+ context.customData.type = "number";
1252
+ });
1253
+
1254
+ //#endregion
1255
+ //#region packages/core/src/tokenizer/tokens/punctuation.token.ts
1256
+ const PunctuationToken = new BasicNode({
1257
+ tokens: [RegExp("(?<text>[\\n!&+,\\-./:;=?|])", "u"), ""],
1258
+ tokenOE: "omit-omit",
1259
+ icon: "..."
1260
+ }).onMatch((context) => {
1261
+ context.customData.type = "punctuation";
1262
+ });
1263
+
1264
+ //#endregion
1265
+ //#region packages/core/src/tokenizer/tokens/text.node.ts
1266
+ const TextToken = new BasicNode({
1267
+ icon: "T",
1268
+ tokens: [RegExp("(?<quote>[\"'])", "u"), (context) => new RegExp(`(?<end>${context.getCustomData().quote || ""}|\\n)`)],
1269
+ backSlash: "-ignore",
1270
+ tokenOE: "omit-omit"
1271
+ }).mapContent("text", "join-clear").onMatch((context) => {
1272
+ context.customData.type = "text";
1273
+ }).onPop((context) => {
1274
+ context.customData.multiline = context.customData.end === "\n";
1275
+ });
1276
+
1277
+ //#endregion
1278
+ //#region packages/core/src/tokenizer/tokens/index.ts
1279
+ const tokens = {
1280
+ aIdentifier: AIdentifierToken,
1281
+ punctuation: PunctuationToken,
1282
+ comments: commentNodes.all,
1283
+ inlineComment: commentNodes.inline,
1284
+ blockComment: commentNodes.block,
1285
+ block: BlockToken,
1286
+ identifier: IdentifierToken,
1287
+ number: NumberToken,
1288
+ text: TextToken,
1289
+ root: undefined
1290
+ };
1291
+ const root = new BasicNode({
1292
+ label: "root",
1293
+ skipToken: /\s/u
1294
+ }).addRecognizes(...tokens.comments, tokens.block, tokens.aIdentifier, tokens.identifier, tokens.text, tokens.number, tokens.punctuation);
1295
+ tokens.root = root;
1296
+ BlockToken.addRecognizes(...tokens.comments, tokens.block, tokens.aIdentifier, tokens.identifier, tokens.text, tokens.number, tokens.punctuation);
1297
+ const mapContent = (content) => content.map((item) => {
1298
+ if (typeof item === "string") return {
1299
+ type: "unknown",
1300
+ text: item
1301
+ };
1302
+ const data = item.getCustomData();
1303
+ data.getRange = () => toVsCodeRange(item.startPos, item.endPos, data.startOffset, data.endOffset);
1304
+ return data;
1305
+ });
1306
+ for (const node of Object.values(tokens)) if (node instanceof BasicNode) node.popsAtEOFSource(true).mapContent("children", mapContent);
1307
+
1308
+ //#endregion
1309
+ //#region packages/core/src/tokenizer/index.ts
1310
+ function tokenize(source, debug = false) {
1311
+ const tokens$1 = root.parse(source);
1312
+ if (debug) console.log(tokens$1.toTree());
1313
+ return mapContent(tokens$1.content);
1314
+ }
1315
+
1316
+ //#endregion
1317
+ //#region packages/core/src/parser/pipes/tokens.pipe.ts
1318
+ const identifier = (...text$2) => $token("identifier", text$2.length > 0 ? text$2 : undefined);
1319
+ const text = (...text$2) => $token("text", text$2.length > 0 ? text$2 : undefined);
1320
+ const block = (...text$2) => $token("block", text$2.length > 0 ? text$2.map((v) => v[0]) : undefined);
1321
+ const pun = (...text$2) => $token("punctuation", text$2.length > 0 ? text$2 : undefined);
1322
+ function $token(name, text$2) {
1323
+ const opts = {
1324
+ optional: false,
1325
+ saveAs: undefined,
1326
+ skip: undefined,
1327
+ expect: [{
1328
+ node: name,
1329
+ text: text$2
1330
+ }],
1331
+ isGlobal: false,
1332
+ empty: false,
1333
+ wrapper: undefined,
1334
+ wrapMultiple: false,
1335
+ debug: false,
1336
+ eob: false,
1337
+ suppressEobError: false,
1338
+ lookBehind: false
1339
+ };
1340
+ return {
1341
+ expect: [{
1342
+ node: name,
1343
+ text: text$2
1344
+ }],
1345
+ handler(ni, target) {
1346
+ if (opts.debug) debugger;
1347
+ let firstRun = true;
1348
+ while (firstRun || opts.wrapMultiple) {
1349
+ firstRun = false;
1350
+ if (!ni.$) {
1351
+ const ok = opts.eob || opts.optional;
1352
+ if (!ok && !opts.suppressEobError) ni.unexpectedEOB();
1353
+ return ok;
1354
+ }
1355
+ let matched = ni.satisfies(...opts.expect);
1356
+ if (!matched && opts.lookBehind) {
1357
+ matched = ni.fork().move(-1).satisfies(...opts.expect);
1358
+ if (matched) ni.move(-1);
1359
+ }
1360
+ if (matched) {
1361
+ if (opts.empty && ni.$.children?.length) {
1362
+ ni.unexpected(false, `Expected empty block`);
1363
+ return opts.optional;
1364
+ }
1365
+ if (opts.saveAs) target.node.saveToken(new Token(ni.$), opts.saveAs);
1366
+ ni.accepted();
1367
+ if (opts.wrapper) {
1368
+ const wrapped = target.node;
1369
+ target.node = opts.wrapper().wrap(wrapped, new Token(ni.$));
1370
+ }
1371
+ ni.move();
1372
+ if (opts.skip) ni.skip(opts.skip);
1373
+ if (opts.wrapMultiple) continue;
1374
+ else return true;
1375
+ } else {
1376
+ if (!opts.optional) ni.unexpected();
1377
+ return opts.optional;
1378
+ }
1379
+ }
1380
+ return true;
1381
+ },
1382
+ saveAs(v) {
1383
+ opts.saveAs = v;
1384
+ return this;
1385
+ },
1386
+ wrap(sn, multiple = false) {
1387
+ opts.wrapper = sn;
1388
+ opts.wrapMultiple = multiple;
1389
+ return this;
1390
+ },
1391
+ optional() {
1392
+ opts.optional = true;
1393
+ return this;
1394
+ },
1395
+ empty() {
1396
+ opts.empty = true;
1397
+ return this;
1398
+ },
1399
+ skip(...p) {
1400
+ opts.skip = p;
1401
+ return this;
1402
+ },
1403
+ or(t) {
1404
+ opts.expect.push(...t.expect);
1405
+ return this;
1406
+ },
1407
+ orEob() {
1408
+ opts.eob = true;
1409
+ return this;
1410
+ },
1411
+ suppressEobError() {
1412
+ opts.suppressEobError = true;
1413
+ return this;
1414
+ },
1415
+ global() {
1416
+ opts.isGlobal = true;
1417
+ return this;
1418
+ },
1419
+ lookBehind() {
1420
+ opts.lookBehind = true;
1421
+ return this;
1422
+ },
1423
+ debug() {
1424
+ opts.debug = true;
1425
+ return this;
1426
+ }
1427
+ };
1428
+ }
1429
+
1430
+ //#endregion
1431
+ //#region packages/core/src/parser/pipes/core.pipe.ts
1432
+ function $pipe(entity, pipe = []) {
1433
+ pipe.forEach((p, i) => Object.assign(p, { toString: () => `${entity}.${i}` }));
1434
+ return {
1435
+ targetFactory: () => {
1436
+ switch (entity) {
1437
+ case "interface": return new $n.SemanticInterfaceNode();
1438
+ case "array": return new $n.SemanticArrayNode();
1439
+ case "const": return new $n.SemanticConstNode();
1440
+ case "group": return new $n.SemanticGroup();
1441
+ case "prop": return new $n.SemanticPropNode();
1442
+ case "type": return new $n.SemanticTypeNode();
1443
+ case "ref": return new $n.SemanticRefNode();
1444
+ case "structure": return new $n.SemanticStructureNode();
1445
+ case "tuple": return new $n.SemanticTupleNode();
1446
+ case "import": return new $n.SemanticImportNode();
1447
+ case "primitive": throw new Error("Can't create pipe for primitive node");
1448
+ default: throw new Error(`Can't create pipe for ${entity} node`);
1449
+ }
1450
+ },
1451
+ pipe,
1452
+ toString: () => entity,
1453
+ skipTokens: [],
1454
+ stopCondition: undefined,
1455
+ skip(...s) {
1456
+ this.skipTokens.push(...s);
1457
+ return this;
1458
+ },
1459
+ stop(sc) {
1460
+ this.stopCondition = sc;
1461
+ return this;
1462
+ },
1463
+ t(node, skip = []) {
1464
+ this.pipe.push($token(node).saveAs("identifier").skip(...skip));
1465
+ return this;
1466
+ }
1467
+ };
1468
+ }
1469
+ function runPipes(pipes$1, ni, singlePass = false) {
1470
+ const nodes = [];
1471
+ while (ni.$) {
1472
+ let matched = true;
1473
+ let depth = ni.index;
1474
+ for (const { targetFactory, pipe, skipTokens: skip, stopCondition } of pipes$1) {
1475
+ const target = { node: targetFactory() };
1476
+ const fork = ni.fork();
1477
+ fork.skip(skip);
1478
+ if (!fork.$) {
1479
+ ni.unfork(fork);
1480
+ break;
1481
+ }
1482
+ matched = true;
1483
+ for (const { handler } of pipe) if (!handler(fork, target)) {
1484
+ matched = false;
1485
+ break;
1486
+ }
1487
+ if (fork.index > depth) depth = fork.index;
1488
+ if (matched) {
1489
+ nodes.push(target.node);
1490
+ ni.unfork(fork);
1491
+ if (stopCondition && stopCondition(fork)) return nodes;
1492
+ ni.move(-1);
1493
+ break;
1494
+ }
1495
+ }
1496
+ if (singlePass) return nodes;
1497
+ if (!matched) {
1498
+ ni.shouldHaveError(depth);
1499
+ ni.move(depth - ni.index);
1500
+ }
1501
+ ni.move();
1502
+ if (matched) {} else {
1503
+ ni.confirmIssues();
1504
+ ni.skipUntil([";", "\n"]);
1505
+ }
1506
+ }
1507
+ return nodes;
1508
+ }
1509
+ function runPipesOnce(pipes$1, ni) {
1510
+ return runPipes(pipes$1, ni, true)[0];
1511
+ }
1512
+
1513
+ //#endregion
1514
+ //#region packages/core/src/parser/grouping.ts
1515
+ function groupByPriority(nodes, priority) {
1516
+ if (nodes.length === 1) return nodes[0];
1517
+ if (nodes.length === 0) return undefined;
1518
+ if (nodes.length % 2 === 0) throw new Error(`Invalid number of nodes ${nodes.length}. Odd number expected`);
1519
+ let currentPass = nodes;
1520
+ let temporaryResult = [];
1521
+ let groupped = [];
1522
+ for (const p of priority) {
1523
+ for (const [i, node] of currentPass.entries()) {
1524
+ const isOperator = i % 2 === 1;
1525
+ if (!isOperator && node instanceof Token) throw new Error(`Unexpected token ${node.toString()} at ${i}`);
1526
+ else if (isOperator && !(node instanceof Token)) throw new Error(`Unexpected token ${isGroup(node) ? node.op : node.token.toString()} at ${i}`);
1527
+ if (isOperator) {
1528
+ if (node.text !== p) temporaryResult.push(node);
1529
+ continue;
1530
+ }
1531
+ const prev = currentPass[i - 1]?.text;
1532
+ const next = currentPass[i + 1]?.text;
1533
+ if (prev !== p && next !== p) {
1534
+ temporaryResult.push(node);
1535
+ continue;
1536
+ }
1537
+ if (prev === p || next === p) {
1538
+ groupped.push(node);
1539
+ if (next !== p) {
1540
+ temporaryResult.push(new $n.SemanticGroup(groupped, p));
1541
+ groupped = [];
1542
+ }
1543
+ }
1544
+ }
1545
+ currentPass = temporaryResult;
1546
+ temporaryResult = [];
1547
+ }
1548
+ const output = currentPass[0];
1549
+ return output.length === 1 ? output.first : output;
1550
+ }
1551
+
1552
+ //#endregion
1553
+ //#region packages/core/src/parser/pipes/special.pipe.ts
1554
+ function refWithChain() {
1555
+ const s = {
1556
+ id: { node: "identifier" },
1557
+ dot: {
1558
+ node: "punctuation",
1559
+ text: "."
1560
+ },
1561
+ block: {
1562
+ node: "block",
1563
+ text: "["
1564
+ },
1565
+ end: {
1566
+ node: "punctuation",
1567
+ text: ";"
1568
+ }
1569
+ };
1570
+ return { handler(ni, target) {
1571
+ ni.skip(["\n"]);
1572
+ if (!ni.$) return false;
1573
+ if (ni.satisfies(s.id)) {
1574
+ ni.accepted();
1575
+ target.node.saveToken(new Token(ni.$), "identifier");
1576
+ } else return false;
1577
+ ni.move();
1578
+ if (ni.fork().skip(["\n"]).satisfies(s.end)) {
1579
+ ni.skip(["\n", ";"]);
1580
+ return true;
1581
+ }
1582
+ const fork = ni.fork();
1583
+ let isDot = fork.skip(["\n"]).satisfies(s.dot);
1584
+ let isBlock = fork.satisfies(s.block);
1585
+ while (fork.$ && (isDot || isBlock)) {
1586
+ if (isBlock) if (fork.$.children?.length === 0) {
1587
+ while (isBlock && fork.$.children?.length === 0) {
1588
+ target.node = new SemanticArrayNode().wrap(target.node, new Token(fork.$));
1589
+ fork.move();
1590
+ fork.skip(["\n", ";"]);
1591
+ isBlock = fork.satisfies(s.block);
1592
+ }
1593
+ ni.unfork(fork);
1594
+ return true;
1595
+ } else if (fork.$.children?.length === 1 && fork.$.children[0].type === "text") {
1596
+ if (isRef(target.node)) target.node.addChain(new Token(fork.$.children[0]));
1597
+ } else return true;
1598
+ else {
1599
+ fork.skip(["\n"]);
1600
+ if (fork.next().satisfies(s.id)) {
1601
+ if (isRef(target.node)) target.node.addDot(new Token(fork.$));
1602
+ fork.move();
1603
+ if (isRef(target.node) && fork.$) target.node.addChain(new Token(fork.$));
1604
+ } else {
1605
+ if (isRef(target.node)) target.node.addDot(new Token(fork.$));
1606
+ fork.unexpected();
1607
+ fork.move(1);
1608
+ fork.unexpected();
1609
+ ni.unfork(fork);
1610
+ ni.move();
1611
+ ni.skip([";", "\n"]);
1612
+ return true;
1613
+ }
1614
+ }
1615
+ fork.move();
1616
+ ni.unfork(fork);
1617
+ if (ni.fork().skip(["\n"]).satisfies(s.end)) {
1618
+ ni.skip(["\n", ";"]);
1619
+ return true;
1620
+ }
1621
+ isDot = fork.skip(["\n"]).satisfies(s.dot);
1622
+ isBlock = fork.satisfies(s.block);
1623
+ }
1624
+ return true;
1625
+ } };
1626
+ }
1627
+ function annotations() {
1628
+ const opts = {
1629
+ annotation: { node: "annotation" },
1630
+ argument: [{ node: ["number", "text"] }, {
1631
+ node: "identifier",
1632
+ text: [
1633
+ "true",
1634
+ "false",
1635
+ "undefined",
1636
+ "null"
1637
+ ]
1638
+ }],
1639
+ comma: {
1640
+ node: "punctuation",
1641
+ text: ","
1642
+ },
1643
+ end: {
1644
+ node: "punctuation",
1645
+ text: [";", "\n"]
1646
+ }
1647
+ };
1648
+ return { handler(ni, target) {
1649
+ while (ni.$ && ni.satisfies(opts.annotation)) {
1650
+ const key = ni.$.text?.slice(1);
1651
+ ni.accepted();
1652
+ const addArgument = target.node.annotate(key, new Token(ni.$));
1653
+ ni.move();
1654
+ while (ni.satisfies(opts.comma)) {
1655
+ addArgument(new Token(ni.$));
1656
+ ni.accepted();
1657
+ ni.move();
1658
+ }
1659
+ while (ni.satisfies(...opts.argument)) {
1660
+ addArgument(new Token(ni.$));
1661
+ ni.accepted();
1662
+ ni.move();
1663
+ if (ni.satisfies(opts.comma)) {
1664
+ ni.accepted();
1665
+ ni.move();
1666
+ while (ni.satisfies(opts.comma)) {
1667
+ addArgument(new Token(ni.$));
1668
+ ni.accepted();
1669
+ ni.move();
1670
+ }
1671
+ } else break;
1672
+ }
1673
+ if (ni.satisfies(opts.end)) ni.skip([";", "\n"]);
1674
+ else if (ni.$) {
1675
+ ni.unexpected(false, `Unexpected token in annotation ${ni.toString()}`);
1676
+ ni.skipUntil([";", "\n"]);
1677
+ ni.skip([";", "\n"]);
1678
+ }
1679
+ }
1680
+ return true;
1681
+ } };
1682
+ }
1683
+ function definition(pipes$1) {
1684
+ const opts = {
1685
+ sep: [],
1686
+ priority: false,
1687
+ multiple: false,
1688
+ from: undefined,
1689
+ debug: false,
1690
+ skip: []
1691
+ };
1692
+ return {
1693
+ handler(ni, target) {
1694
+ const targetNode = target.node;
1695
+ if (opts.debug) debugger;
1696
+ if (!ni.$ && !opts.from) return false;
1697
+ if (opts.from && !targetNode.has(opts.from)) {
1698
+ ni.unexpected(false, `Unexpected definition`);
1699
+ return false;
1700
+ }
1701
+ const fork = opts.from ? ni.fork(targetNode.token(opts.from)?.children) : ni;
1702
+ if (opts.from && !fork.nodesLeft()) {
1703
+ targetNode.define(new $n.SemanticGroup());
1704
+ return true;
1705
+ }
1706
+ const resolvedPipes = pipes$1.map((p) => typeof p === "function" ? p() : p);
1707
+ const node = runPipesOnce(resolvedPipes, fork);
1708
+ if (node) {
1709
+ fork.accepted();
1710
+ fork.move();
1711
+ fork.skip(opts.skip);
1712
+ if (!opts.multiple) {
1713
+ targetNode.define(node);
1714
+ return true;
1715
+ }
1716
+ } else {
1717
+ fork.unexpected();
1718
+ return false;
1719
+ }
1720
+ const nodes = [node];
1721
+ while (opts.multiple && fork.$) {
1722
+ if (opts.sep.length > 0) if (fork.satisfies({
1723
+ node: "punctuation",
1724
+ text: opts.sep
1725
+ })) {
1726
+ if (opts.priority) if (fork.next(opts.skip).$) nodes.push(new Token(fork.$));
1727
+ else {
1728
+ fork.unexpected(false, "Unexpected end of group");
1729
+ break;
1730
+ }
1731
+ fork.accepted();
1732
+ fork.move();
1733
+ fork.skip(opts.skip);
1734
+ } else {
1735
+ if (fork.$) fork.unexpected();
1736
+ break;
1737
+ }
1738
+ const nextNode = runPipesOnce(resolvedPipes, fork);
1739
+ if (nextNode) {
1740
+ nodes.push(nextNode);
1741
+ fork.accepted();
1742
+ fork.move();
1743
+ fork.skip(opts.skip);
1744
+ } else {
1745
+ fork.unexpected();
1746
+ return false;
1747
+ }
1748
+ }
1749
+ if (nodes.length === 1) targetNode.define(nodes[0]);
1750
+ else if (opts.priority && opts.sep.length > 0) {
1751
+ if (nodes.length % 2 === 0) {
1752
+ fork.next().unexpected(false, "Error in group definition");
1753
+ return false;
1754
+ }
1755
+ targetNode.define(groupByPriority(nodes, opts.sep));
1756
+ } else targetNode.define(new $n.SemanticGroup(nodes));
1757
+ return true;
1758
+ },
1759
+ separatedBy(...p) {
1760
+ opts.multiple = true;
1761
+ opts.sep.push(...p);
1762
+ return this;
1763
+ },
1764
+ respectPriority() {
1765
+ opts.priority = true;
1766
+ return this;
1767
+ },
1768
+ multiple() {
1769
+ opts.multiple = true;
1770
+ return this;
1771
+ },
1772
+ from(attr) {
1773
+ opts.from = attr;
1774
+ return this;
1775
+ },
1776
+ skip(...skip) {
1777
+ opts.skip = skip;
1778
+ return this;
1779
+ },
1780
+ debug() {
1781
+ opts.debug = true;
1782
+ return this;
1783
+ }
1784
+ };
1785
+ }
1786
+ function unwrap(attr) {
1787
+ const opts = { pipes: [] };
1788
+ return {
1789
+ handler(ni, target) {
1790
+ if (!target.node.has(attr)) return false;
1791
+ const token = target.node.token(attr);
1792
+ const fork = ni.fork(token.children || []);
1793
+ const nodes = runPipes(opts.pipes, fork);
1794
+ target.node.define(new $n.SemanticGroup(nodes));
1795
+ return true;
1796
+ },
1797
+ with(pipes$1) {
1798
+ opts.pipes = pipes$1;
1799
+ return this;
1800
+ }
1801
+ };
1802
+ }
1803
+
1804
+ //#endregion
1805
+ //#region packages/core/src/parser/pipes/pipes.ts
1806
+ const ref = $pipe("ref", [refWithChain()]);
1807
+ const constText = defineValuePipe("const", "text", false);
1808
+ const constNumber = defineValuePipe("const", "number", false);
1809
+ const allowedValuesPipeArray = [
1810
+ ref,
1811
+ constText,
1812
+ constNumber
1813
+ ];
1814
+ const tuplePipeArray = [
1815
+ block("[]").saveAs("identifier"),
1816
+ definition(allowedValuesPipeArray).from("identifier").separatedBy("&", "|", ",").skip("\n").respectPriority(),
1817
+ block("[]").optional().empty().wrap(() => new SemanticArrayNode(), true)
1818
+ ];
1819
+ const groupPipeArray = [
1820
+ block("()").saveAs("identifier"),
1821
+ definition(allowedValuesPipeArray).from("identifier").separatedBy("&", "|").skip("\n").respectPriority(),
1822
+ block("[]").optional().empty().wrap(() => new $n.SemanticArrayNode(), true)
1823
+ ];
1824
+ const tuple = $pipe("tuple", tuplePipeArray).skip("\n");
1825
+ const group = $pipe("group", groupPipeArray).skip("\n");
1826
+ allowedValuesPipeArray.unshift(tuple);
1827
+ allowedValuesPipeArray.unshift(group);
1828
+ const type = $pipe("type", [
1829
+ annotations(),
1830
+ identifier("export").saveAs("export").optional().skip("\n"),
1831
+ identifier("type").saveAs("type").skip("\n").suppressEobError(),
1832
+ identifier().saveAs("identifier").global().skip("\n"),
1833
+ pun("=").skip("\n"),
1834
+ definition(allowedValuesPipeArray).separatedBy("&", "|").skip("\n").respectPriority()
1835
+ ]).skip("\n", ";");
1836
+ const props = $pipe("prop", [
1837
+ annotations(),
1838
+ identifier().or(text()).saveAs("identifier").skip("\n"),
1839
+ pun("?").saveAs("optional").optional().skip("\n"),
1840
+ pun(":").skip("\n"),
1841
+ definition(allowedValuesPipeArray).separatedBy("&", "|").skip("\n").respectPriority(),
1842
+ pun(";", ",", "\n").orEob().lookBehind()
1843
+ ]).skip("\n", ";", ",");
1844
+ const structurePipeArray = [
1845
+ block("{}").saveAs("identifier"),
1846
+ unwrap("identifier").with([props]),
1847
+ block("[]").optional().empty().wrap(() => new $n.SemanticArrayNode(), true)
1848
+ ];
1849
+ function structureBlock(array = false) {
1850
+ return $pipe("structure", array ? structurePipeArray : structurePipeArray.slice(0, 2)).skip("\n", ";");
1851
+ }
1852
+ allowedValuesPipeArray.unshift(structureBlock(true));
1853
+ const interfaceType = $pipe("interface", [
1854
+ annotations(),
1855
+ identifier("export").saveAs("export").optional().skip("\n"),
1856
+ identifier("interface").saveAs("type").skip("\n").suppressEobError(),
1857
+ identifier().saveAs("identifier").global().skip("\n"),
1858
+ definition([structureBlock()])
1859
+ ]).skip("\n", ";");
1860
+ function defineValuePipe(entity, name, supportArray = false) {
1861
+ const steps = [$token(name).saveAs("identifier")];
1862
+ if (supportArray) steps.push(block("[]").optional().empty().wrap(() => new $n.SemanticArrayNode(), true));
1863
+ return $pipe(entity, steps).skip("\n");
1864
+ }
1865
+ const importPipe = $pipe("import", [
1866
+ identifier("import").saveAs("identifier").skip("\n"),
1867
+ block("{}").saveAs("inner").skip("\n"),
1868
+ identifier("from").saveAs("from").skip("\n"),
1869
+ text().saveAs("path").skip(";", "\n"),
1870
+ definition([$pipe("ref", [identifier().saveAs("identifier").skip("\n")])]).from("inner").separatedBy(",").skip("\n").respectPriority()
1871
+ ]).skip("\n", ";");
1872
+ const pipes = {
1873
+ type,
1874
+ props,
1875
+ interfaceType,
1876
+ importPipe,
1877
+ tuple
1878
+ };
1879
+
1880
+ //#endregion
1881
+ //#region packages/core/src/token-index/blocks-index.ts
1882
+ function _define_property$5(obj, key, value) {
1883
+ if (key in obj) Object.defineProperty(obj, key, {
1884
+ value,
1885
+ enumerable: true,
1886
+ configurable: true,
1887
+ writable: true
1888
+ });
1889
+ else obj[key] = value;
1890
+ return obj;
1891
+ }
1892
+ /**
1893
+ * Compares two positions.
1894
+ * @param a - The first position.
1895
+ * @param b - The second position.
1896
+ * @returns -1 if `a` is less than `b`, 1 if `a` is greater than `b`, 0 if they are equal.
1897
+ */ function comparePos(a, b) {
1898
+ if (a.line < b.line) return -1;
1899
+ if (a.line > b.line) return 1;
1900
+ if (a.character < b.character) return -1;
1901
+ if (a.character > b.character) return 1;
1902
+ return 0;
1903
+ }
1904
+ /**
1905
+ * Checks if a given position (line, character) is contained within a token's range.
1906
+ * @param token - The token to check.
1907
+ * @param line - The line number of the position.
1908
+ * @param character - The character number of the position.
1909
+ * @returns `true` if the position is within the token's range, `false` otherwise.
1910
+ */ function contains(token, line, character) {
1911
+ const startCmp = comparePos(token.range.start, {
1912
+ line,
1913
+ character
1914
+ });
1915
+ const endCmp = comparePos(token.range.end, {
1916
+ line,
1917
+ character
1918
+ });
1919
+ return startCmp <= 0 && endCmp > 0;
1920
+ }
1921
+ /**
1922
+ * Determines if token `a` is more nested than token `b`.
1923
+ * @param a - The first token.
1924
+ * @param b - The second token.
1925
+ * @returns `true` if `a` is more nested than `b`, `false` otherwise.
1926
+ */ function moreNested(a, b) {
1927
+ const startCmp = comparePos(a.range.start, b.range.start);
1928
+ const endCmp = comparePos(a.range.end, b.range.end);
1929
+ return startCmp >= 0 && endCmp <= 0;
1930
+ }
1931
+ var BlocksIndex = class {
1932
+ /**
1933
+ * Adds a new token to the index. The token collection is maintained in sorted order by start position.
1934
+ * @param block - The token to add.
1935
+ */ add(block$2) {
1936
+ let left = 0;
1937
+ let right = this.blocks.length;
1938
+ while (left < right) {
1939
+ const mid = left + right >> 1;
1940
+ if (comparePos(this.blocks[mid].range.start, block$2.range.start) < 0) left = mid + 1;
1941
+ else right = mid;
1942
+ }
1943
+ this.blocks.splice(left, 0, block$2);
1944
+ }
1945
+ /**
1946
+ * Finds the most nested token at a specific position.
1947
+ * @param line - The line number of the position.
1948
+ * @param character - The character number of the position.
1949
+ * @returns The most nested token at the given position, or `undefined` if no token is found.
1950
+ */ at(line, character) {
1951
+ const candidates = [];
1952
+ for (const block$2 of this.blocks) {
1953
+ if (comparePos(block$2.range.start, {
1954
+ line,
1955
+ character
1956
+ }) > 0) break;
1957
+ if (contains(block$2, line, character)) candidates.push(block$2);
1958
+ }
1959
+ if (candidates.length === 0) return undefined;
1960
+ let result = candidates[0];
1961
+ for (let i = 1; i < candidates.length; i++) if (moreNested(candidates[i], result)) result = candidates[i];
1962
+ return result;
1963
+ }
1964
+ before(line, character) {
1965
+ throw new Error("Not implemented");
1966
+ }
1967
+ constructor() {
1968
+ _define_property$5(this, "blocks", []);
1969
+ }
1970
+ };
1971
+
1972
+ //#endregion
1973
+ //#region packages/core/src/token-index/tokens-index.ts
1974
+ function _define_property$4(obj, key, value) {
1975
+ if (key in obj) Object.defineProperty(obj, key, {
1976
+ value,
1977
+ enumerable: true,
1978
+ configurable: true,
1979
+ writable: true
1980
+ });
1981
+ else obj[key] = value;
1982
+ return obj;
1983
+ }
1984
+ var TokensIndex = class {
1985
+ /**
1986
+ * Adds a token to the index. The token is stored based on its starting line.
1987
+ * @param token - The token to add to the index.
1988
+ */ add(token) {
1989
+ if (!token?.range) return;
1990
+ const line = token.range.start.line;
1991
+ this.tokensMap[line] = this.tokensMap[line] ?? new Set();
1992
+ this.tokensMap[line].add(token);
1993
+ }
1994
+ /**
1995
+ * Retrieves a token at a specific line and character, if one exists.
1996
+ * @param line - The line number to search in.
1997
+ * @param character - The character position within the line to search for.
1998
+ * @returns The token at the specified line and character, or `undefined` if none exists.
1999
+ */ at(line, character) {
2000
+ const tokens$1 = this.tokensMap[line];
2001
+ if (!tokens$1) return undefined;
2002
+ return Array.from(tokens$1).find((t) => t.range.start.character <= character && t.range.end.character >= character);
2003
+ }
2004
+ /**
2005
+ * Retrieves either the token at the specified (line, character), or if none exists,
2006
+ * the closest token that ends on or before that position. This method checks:
2007
+ * 1. If a token spans (line, character), return it immediately.
2008
+ * 2. Otherwise, look within the same line for tokens that end before `character`.
2009
+ * 3. If still none found, move upwards to previous lines and return the token that ends last.
2010
+ * @param line - The line number to search in.
2011
+ * @param character - The character position within the line to search for.
2012
+ * @returns The found token, or `undefined` if no suitable token is found.
2013
+ */ before(line, character) {
2014
+ const current = this.at(line, character);
2015
+ if (current) return current;
2016
+ const tokensAtLine = this.tokensMap[line];
2017
+ if (tokensAtLine) {
2018
+ let candidate;
2019
+ for (const t of tokensAtLine) if (t.range.end.character < character && (!candidate || t.range.end.character > candidate.range.end.character)) candidate = t;
2020
+ if (candidate) return candidate;
2021
+ }
2022
+ for (let l = line - 1; l >= 0; l--) {
2023
+ const tokens$1 = this.tokensMap[l];
2024
+ if (tokens$1 && tokens$1.size > 0) {
2025
+ let candidate;
2026
+ for (const t of tokens$1) if (!candidate || t.range.end.character > candidate.range.end.character) candidate = t;
2027
+ if (candidate) return candidate;
2028
+ }
2029
+ }
2030
+ return undefined;
2031
+ }
2032
+ constructor() {
2033
+ /**
2034
+ * An array where each index corresponds to a line number, storing a set of tokens
2035
+ * associated with that line.
2036
+ */ _define_property$4(this, "tokensMap", []);
2037
+ }
2038
+ };
2039
+
2040
+ //#endregion
2041
+ //#region packages/core/src/document.ts
2042
+ function _define_property$3(obj, key, value) {
2043
+ if (key in obj) Object.defineProperty(obj, key, {
2044
+ value,
2045
+ enumerable: true,
2046
+ configurable: true,
2047
+ writable: true
2048
+ });
2049
+ else obj[key] = value;
2050
+ return obj;
2051
+ }
2052
+ var AtscriptDoc = class {
2053
+ get name() {
2054
+ return this.id.split("/").pop();
2055
+ }
2056
+ get primitives() {
2057
+ return Array.from(this.config.primitives?.values() ?? []);
2058
+ }
2059
+ async render(format) {
2060
+ return this.manager?.render(this, format);
2061
+ }
2062
+ resolveAnnotation(name) {
2063
+ return resolveAnnotation(name, this.config.annotations);
2064
+ }
2065
+ updateDependencies(docs) {
2066
+ const newDependencies = new Set(docs);
2067
+ this.dependencies.forEach((d) => {
2068
+ if (!newDependencies.has(d)) {
2069
+ d.dependants.delete(this);
2070
+ this.dependencies.delete(d);
2071
+ this.dependenciesMap.delete(d.id);
2072
+ }
2073
+ });
2074
+ newDependencies.forEach((d) => {
2075
+ d.dependants.add(this);
2076
+ this.dependencies.add(d);
2077
+ this.dependenciesMap.set(d.id, d);
2078
+ });
2079
+ }
2080
+ get text() {
2081
+ return this._text;
2082
+ }
2083
+ update(text$2, debug = false) {
2084
+ this._text = text$2;
2085
+ this.cleanup();
2086
+ const rawTokens = tokenize(text$2, debug);
2087
+ const ni = new NodeIterator(rawTokens, []).move();
2088
+ this.nodes = runPipes([
2089
+ pipes.importPipe,
2090
+ pipes.type,
2091
+ pipes.interfaceType
2092
+ ], ni);
2093
+ if (debug) console.log(this.nodes.map((n) => n.toString()).join("\n"));
2094
+ this.semanticMessages = ni.getErrors();
2095
+ this.registerNodes(this.nodes);
2096
+ }
2097
+ cleanup() {
2098
+ this.exports.clear();
2099
+ this.registry.clear();
2100
+ this.importedDefs.clear();
2101
+ this.messages = [];
2102
+ this.referred = [];
2103
+ this.imports.clear();
2104
+ this._allMessages = undefined;
2105
+ this.tokensIndex = new TokensIndex();
2106
+ this.blocksIndex = new BlocksIndex();
2107
+ this.resolvedAnnotations = [];
2108
+ this.annotations = [];
2109
+ }
2110
+ registerNodes(nodes) {
2111
+ for (const node of nodes) {
2112
+ node.registerAtDocument(this);
2113
+ node.referredIdentifiers.forEach((t) => {
2114
+ t.isReference = true;
2115
+ this.referred.push(t);
2116
+ this.tokensIndex.add(t);
2117
+ });
2118
+ }
2119
+ }
2120
+ registerAnnotation(annotationTokens) {
2121
+ this.annotations.push(annotationTokens);
2122
+ const mainToken = annotationTokens.token;
2123
+ const args = annotationTokens.args;
2124
+ this.tokensIndex.add(mainToken);
2125
+ args?.forEach((a) => this.tokensIndex.add(a));
2126
+ const annotationSpec = this.resolveAnnotation(mainToken.text.slice(1));
2127
+ if (annotationSpec) {
2128
+ this.registerMessages(annotationSpec.validate(mainToken, args || [], this));
2129
+ annotationSpec.modify(mainToken, args || [], this);
2130
+ this.resolvedAnnotations.push(mainToken);
2131
+ } else {
2132
+ let severity = 0;
2133
+ switch (this.config.unknownAnnotation) {
2134
+ case "warn":
2135
+ severity = 2;
2136
+ break;
2137
+ case "error":
2138
+ severity = 1;
2139
+ break;
2140
+ default:
2141
+ }
2142
+ if (severity > 0) this.registerMessage(mainToken, `Unknown annotation "${mainToken.text}"`, severity, "dim");
2143
+ }
2144
+ }
2145
+ /**
2146
+ * Recursively resolves a type reference (and any property chain) to find the final underlying definition.
2147
+ *
2148
+ * This method performs a **multi-step** resolution:
2149
+ * 1. Locates the declaration owner of the type (via `getDeclarationOwnerNode`).
2150
+ * 2. Follows references, type aliases, or nested property chains:
2151
+ * - For “Ref” nodes, it uses the identifier to look up the next type.
2152
+ * - For “Type” nodes, it calls `getDefinition()` to move to the underlying structure.
2153
+ * - For property chains (`chain`), it navigates nested properties or nested types,
2154
+ * resolving each level until the final type is reached.
2155
+ *
2156
+ * @param {string} name - The name of the type or identifier to resolve.
2157
+ * @param {Array<string | Token>} [chain=[]] - An optional chain of properties or tokens, each of which
2158
+ * refines the path to the final type (e.g., for `SomeType.prop1.prop2`, `chain` might be `[ "prop1", "prop2" ]`).
2159
+ * @returns {Object | undefined} An object containing:
2160
+ * - `doc`: The `AtscriptDoc` where the final definition is located.
2161
+ * - `node`: The last encountered `SemanticNode` before reaching the final underlying definition (often a `Prop` node).
2162
+ * - `def`: The final resolved `SemanticNode`.
2163
+ *
2164
+ * If the type cannot be resolved or does not exist, returns `undefined`.
2165
+ */ unwindType(name, chain = [], watchCb, _tracked) {
2166
+ const tracked = _tracked || new Set();
2167
+ const decl = this.getDeclarationOwnerNode(name);
2168
+ if (!decl) return undefined;
2169
+ const callCb = watchCb ? () => {
2170
+ if (def && !tracked.has(def) && [
2171
+ "type",
2172
+ "primitive",
2173
+ "prop",
2174
+ "interface"
2175
+ ].includes(def.entity)) {
2176
+ tracked.add(def);
2177
+ watchCb(def);
2178
+ }
2179
+ } : () => {};
2180
+ let node;
2181
+ let def = decl.node;
2182
+ let doc = decl.doc;
2183
+ const resolveRef = () => {
2184
+ if (isRef(def)) {
2185
+ const d = doc.unwindType(def.token("identifier").text, def.chain, watchCb, tracked);
2186
+ doc = d?.doc || doc;
2187
+ def = d?.def;
2188
+ }
2189
+ };
2190
+ const resolveType = () => {
2191
+ while (isType(def)) {
2192
+ callCb();
2193
+ def = def.getDefinition();
2194
+ node = def;
2195
+ resolveRef();
2196
+ }
2197
+ };
2198
+ resolveType();
2199
+ if (!def) return undefined;
2200
+ for (const item of chain) {
2201
+ const itemText = typeof item === "string" ? item : item.text;
2202
+ if (!def) return undefined;
2203
+ if (isProp(def)) if (def.nestedProps?.get(itemText)) def = def.nestedProps.get(itemText);
2204
+ else {
2205
+ def = def.nestedType;
2206
+ resolveRef();
2207
+ resolveType();
2208
+ if (isStructure(def) || isInterface(def)) def = def.props.get(itemText);
2209
+ }
2210
+ else if (isStructure(def) || isInterface(def) || isPrimitive(def)) def = def.props.get(itemText);
2211
+ }
2212
+ if (_tracked) callCb();
2213
+ while (isProp(def)) {
2214
+ node = def;
2215
+ def = def.getDefinition();
2216
+ resolveRef();
2217
+ resolveType();
2218
+ }
2219
+ return def ? {
2220
+ def,
2221
+ doc,
2222
+ node
2223
+ } : undefined;
2224
+ }
2225
+ getUsageListAt(line, character) {
2226
+ const token = this.tokensIndex.at(line, character);
2227
+ if (token) return this.usageListFor(token);
2228
+ }
2229
+ evalAnnotationsForNode(givenNode) {
2230
+ let right = givenNode.annotations;
2231
+ let def = givenNode.getDefinition();
2232
+ if (def) {
2233
+ if (isRef(def)) {
2234
+ const unwound = this.unwindType(def.token("identifier").text, def.chain, (intermediate) => {
2235
+ if (intermediate?.annotations) right = this.mergeNodesAnnotations(intermediate.annotations, right);
2236
+ });
2237
+ def = unwound?.def || def;
2238
+ }
2239
+ if (def) {
2240
+ const merged = this.mergeIntersection(def);
2241
+ right = this.mergeNodesAnnotations(merged.annotations, right);
2242
+ }
2243
+ }
2244
+ return right;
2245
+ }
2246
+ usageListFor(token) {
2247
+ if (token.isDefinition) {
2248
+ const refs = this.referred.filter((t) => t.text === token.text).map((r) => ({
2249
+ uri: this.id,
2250
+ range: r.range,
2251
+ token: r
2252
+ }));
2253
+ if (token.exported) for (const d of this.dependants) {
2254
+ const imp = d.imports.get(this.id);
2255
+ if (imp?.imports.find((t) => t.text === token.text)) refs.push(...d.referred.filter((t) => t.text === token.text).map((r) => ({
2256
+ uri: d.id,
2257
+ range: r.range,
2258
+ token: r
2259
+ })));
2260
+ }
2261
+ return refs;
2262
+ }
2263
+ if (isProp(token.parentNode)) {} else {
2264
+ const defForToken = this.getDefinitionFor(token);
2265
+ if (defForToken?.token?.isDefinition && defForToken.doc) return defForToken.doc.usageListFor(defForToken.token);
2266
+ }
2267
+ return undefined;
2268
+ }
2269
+ /**
2270
+ * Retrieves the definition (i.e., the “go to definition” target) for a given token.
2271
+ *
2272
+ * This method provides a **single-step** resolution of the defining token:
2273
+ * - If the token is defined in the same document, returns that definition.
2274
+ * - If the token is imported, follows the import to return the defining token from the relevant document.
2275
+ * - If the token is a reference to a locally defined identifier, retrieves the local definition.
2276
+ *
2277
+ * @param {Token} token - The token for which to locate the definition.
2278
+ * @returns {Object | undefined} An object containing:
2279
+ * - `uri`: The file path (URI) of the document where the definition is found.
2280
+ * - `doc`: The `AtscriptDoc` instance that owns the definition (if found).
2281
+ * - `token`: The defining token itself (if found).
2282
+ *
2283
+ * If no definition is found, returns `undefined`.
2284
+ */ getDefinitionFor(token) {
2285
+ if (token.isDefinition && !token.imported) return {
2286
+ uri: this.id,
2287
+ doc: this,
2288
+ token
2289
+ };
2290
+ if (token.fromPath) {
2291
+ const absolutePath = resolveAtscriptFromPath(token.fromPath, this.id);
2292
+ return {
2293
+ uri: absolutePath,
2294
+ doc: this.dependenciesMap.get(absolutePath),
2295
+ token
2296
+ };
2297
+ }
2298
+ if ((token.isReference || token.imported) && this.importedDefs.has(token.text) && this.dependenciesMap.size > 0) {
2299
+ const from = this.importedDefs.get(token.text).text;
2300
+ const absolutePath = resolveAtscriptFromPath(from, this.id);
2301
+ const targetDoc = this.dependenciesMap.get(absolutePath);
2302
+ if (targetDoc) {
2303
+ const target = targetDoc.registry.definitions.get(token.text);
2304
+ return target ? {
2305
+ uri: targetDoc.id,
2306
+ doc: targetDoc,
2307
+ token: target
2308
+ } : undefined;
2309
+ }
2310
+ }
2311
+ if (token.isReference) {
2312
+ const def = this.registry.definitions.get(token.text);
2313
+ return def ? {
2314
+ uri: this.id,
2315
+ doc: this,
2316
+ token: def
2317
+ } : undefined;
2318
+ }
2319
+ }
2320
+ getToDefinitionAt(line, character) {
2321
+ const token = this.tokensIndex.at(line, character);
2322
+ if (token) if (token.isChain && isRef(token.parentNode) && typeof token.index === "number") {
2323
+ const id = token.parentNode.id;
2324
+ const unwound = this.unwindType(id, token.parentNode.chain.slice(0, token.index));
2325
+ if (unwound?.node) return [{
2326
+ targetUri: unwound.doc.id,
2327
+ targetRange: unwound.node.token("identifier")?.range ?? zeroRange,
2328
+ targetSelectionRange: unwound.node.token("identifier")?.range ?? zeroRange,
2329
+ originSelectionRange: token.range
2330
+ }];
2331
+ } else {
2332
+ const result = this.getDefinitionFor(token);
2333
+ return result ? [{
2334
+ targetUri: result.uri,
2335
+ targetRange: result.token?.range ?? zeroRange,
2336
+ targetSelectionRange: result.token?.range ?? zeroRange,
2337
+ originSelectionRange: token.range
2338
+ }] : undefined;
2339
+ }
2340
+ }
2341
+ registerImport({ from, imports, block: block$2 }) {
2342
+ const importId = resolveAtscriptFromPath(from.text, this.id);
2343
+ this.imports.set(importId, {
2344
+ from,
2345
+ imports
2346
+ });
2347
+ this.blocksIndex.add(block$2);
2348
+ block$2.blockType = "import";
2349
+ block$2.fromPath = from.text;
2350
+ imports.forEach((t) => {
2351
+ t.imported = true;
2352
+ t.fromPath = from.text;
2353
+ this.registerDefinition(t, true);
2354
+ this.tokensIndex.add(t);
2355
+ this.tokensIndex.add(from);
2356
+ this.importedDefs.set(t.text, from);
2357
+ from.fromPath = from.text;
2358
+ });
2359
+ }
2360
+ registerDefinition(token, asImport = false) {
2361
+ if (token) {
2362
+ token.isDefinition = !asImport;
2363
+ if (asImport) token.isReference = true;
2364
+ this.tokensIndex.add(token);
2365
+ this.registry.registerDefinition(token);
2366
+ }
2367
+ }
2368
+ /**
2369
+ * Finds the owning document and semantic node responsible for declaring a given identifier.
2370
+ *
2371
+ * This method checks:
2372
+ * 1. Whether the identifier is a known primitive (from this document’s config).
2373
+ * 2. If there's a local definition in this document's registry.
2374
+ * - If the definition is imported, it resolves the `fromPath`, locates the correct `AtscriptDoc`
2375
+ * in the dependency map, and recursively tries to get the declaration owner there.
2376
+ * - If the definition is local (not imported), it returns the current document (`this`) along with
2377
+ * the parent node that owns the definition and the token itself.
2378
+ *
2379
+ * @param {string} identifier - The name/identifier whose declaring node should be found.
2380
+ * @returns {{ doc: AtscriptDoc; node?: SemanticNode; token?: Token } | undefined} An object containing:
2381
+ * - `doc`: The `AtscriptDoc` in which the identifier was ultimately declared.
2382
+ * - `node`: The parent `SemanticNode` that defines or owns the declaration (if applicable).
2383
+ * - `token`: The specific token for the declaration (if applicable).
2384
+ *
2385
+ * If no declaration is found, returns `undefined`.
2386
+ */ getDeclarationOwnerNode(identifier$1) {
2387
+ if (this.config.primitives?.has(identifier$1)) return {
2388
+ doc: this,
2389
+ node: this.config.primitives.get(identifier$1)
2390
+ };
2391
+ const def = this.registry.definitions.get(identifier$1);
2392
+ if (def?.imported && def.fromPath) {
2393
+ const absolutePath = resolveAtscriptFromPath(def.fromPath, this.id);
2394
+ const doc = this.dependenciesMap.get(absolutePath);
2395
+ return doc?.getDeclarationOwnerNode(identifier$1);
2396
+ } else if (!def?.imported) return def ? {
2397
+ doc: this,
2398
+ node: def.parentNode,
2399
+ token: def
2400
+ } : undefined;
2401
+ }
2402
+ registerExport(node) {
2403
+ if (node.id) this.exports.set(node.id, node);
2404
+ }
2405
+ registerMessage(token, message, severity = 1, tag) {
2406
+ if (this._allMessages) this._allMessages = undefined;
2407
+ this.messages.push({
2408
+ severity,
2409
+ message,
2410
+ range: token.range,
2411
+ tags: tag === "dim" ? [1] : tag === "crossed" ? [2] : []
2412
+ });
2413
+ }
2414
+ registerMessages(messages) {
2415
+ if (messages) this.messages.push(...messages);
2416
+ }
2417
+ clearMessages() {
2418
+ this._allMessages = undefined;
2419
+ }
2420
+ getUnusedTokens() {
2421
+ const refSet = new Set(this.referred.filter((r) => !r.imported).map((r) => r.text));
2422
+ const tokens$1 = [];
2423
+ for (const [key, token] of Array.from(this.registry.definitions.entries())) if (!refSet.has(key) && !this.exports.has(key)) tokens$1.push(token);
2424
+ return tokens$1;
2425
+ }
2426
+ getDiagMessages() {
2427
+ if (!this._allMessages) {
2428
+ this._allMessages = [
2429
+ ...this.registry.getErrors(),
2430
+ ...this.semanticMessages,
2431
+ ...this.messages
2432
+ ];
2433
+ for (const t of this.referred) {
2434
+ if (!this.registry.isDefined(t)) {
2435
+ this._allMessages.push({
2436
+ severity: 1,
2437
+ message: `Unknown identifier "${t.text}"`,
2438
+ range: t.range
2439
+ });
2440
+ continue;
2441
+ }
2442
+ if (isRef(t.parentNode)) {
2443
+ const def = this.unwindType(t.parentNode.id, t.parentNode.chain)?.def;
2444
+ if (isPrimitive(def) && !def.config.type) {
2445
+ const token = t.parentNode.chain[t.parentNode.chain.length - 1] || t;
2446
+ this._allMessages.push({
2447
+ severity: 1,
2448
+ message: "Invalid type",
2449
+ range: token.range
2450
+ });
2451
+ }
2452
+ if (t.parentNode.hasChain) {
2453
+ const length = t.parentNode.chain.length - 1;
2454
+ for (let i = length; i >= 0; i--) {
2455
+ const token = t.parentNode.chain[i];
2456
+ const decl = this.unwindType(t.parentNode.id, t.parentNode.chain.slice(0, i + 1));
2457
+ if (!decl?.def) this._allMessages.push({
2458
+ severity: 1,
2459
+ message: `Unknown member "${token.text}"`,
2460
+ range: token.range
2461
+ });
2462
+ }
2463
+ }
2464
+ }
2465
+ }
2466
+ }
2467
+ return this._allMessages;
2468
+ }
2469
+ mergeIntersection(node) {
2470
+ if (!isGroup(node)) return node;
2471
+ if (node.op !== "&") return node;
2472
+ const nodes = node.unwrap();
2473
+ if (nodes.length === 0) return node;
2474
+ if (nodes.length === 1) return nodes[0];
2475
+ const newGroup = [];
2476
+ let left = nodes[0];
2477
+ for (let i = 1; i < nodes.length; i++) {
2478
+ const right = nodes[i];
2479
+ const merged = this.mergeDefs(left, right);
2480
+ if (merged.length === 2) {
2481
+ left = merged[1];
2482
+ newGroup.push(merged[0]);
2483
+ } else left = merged[0];
2484
+ }
2485
+ newGroup.push(left);
2486
+ if (newGroup.length > 1) {
2487
+ const newNode = new SemanticGroup(newGroup, "&");
2488
+ return newNode;
2489
+ } else return newGroup[0];
2490
+ }
2491
+ mergeDefs(_left, _right) {
2492
+ let left = _left;
2493
+ let right = _right;
2494
+ if (isRef(left)) left = this.unwindType(left.id, left.chain)?.def;
2495
+ if (isRef(right)) right = this.unwindType(right.id, right.chain)?.def;
2496
+ if (!left || !right) return [_left, _right];
2497
+ if (isPrimitive(left) && isPrimitive(right)) {
2498
+ if (left.config.type === right.config.type) return [left];
2499
+ const never$1 = new SemanticRefNode();
2500
+ never$1.saveToken(new Token({
2501
+ text: "never",
2502
+ type: "identifier",
2503
+ getRange: () => zeroRange
2504
+ }), "identifier");
2505
+ return [never$1];
2506
+ }
2507
+ if ((isStructure(left) || isInterface(left)) && (isStructure(right) || isInterface(right))) {
2508
+ const mergedProps = [];
2509
+ const allProps = new Set([...left.props.keys(), ...right.props.keys()]);
2510
+ for (const key of allProps) {
2511
+ const leftProp = left.props.get(key);
2512
+ const rightProp = right.props.get(key);
2513
+ let mergedDef;
2514
+ if (leftProp && rightProp) {
2515
+ const grp = new SemanticGroup([leftProp.getDefinition(), rightProp.getDefinition()], "&");
2516
+ mergedDef = this.mergeIntersection(grp);
2517
+ } else {
2518
+ const oldProp = leftProp || rightProp;
2519
+ mergedDef = this.mergeIntersection(oldProp.getDefinition());
2520
+ }
2521
+ const prop = new SemanticPropNode();
2522
+ prop.saveToken((leftProp || rightProp).token("identifier"), "identifier");
2523
+ if (isPrimitive(mergedDef)) {
2524
+ const name = mergedDef.id;
2525
+ mergedDef = new SemanticRefNode();
2526
+ mergedDef.saveToken(new Token({
2527
+ text: name,
2528
+ type: "identifier",
2529
+ getRange: () => zeroRange
2530
+ }), "identifier");
2531
+ }
2532
+ prop.define(mergedDef);
2533
+ prop.annotations = this.mergeNodesAnnotations(leftProp?.annotations, rightProp?.annotations);
2534
+ const oldProps = [leftProp, rightProp].filter(Boolean);
2535
+ let optionalToken = oldProps[0]?.token("optional");
2536
+ for (const oldProp of oldProps) if (!oldProp.token("optional")) {
2537
+ optionalToken = undefined;
2538
+ break;
2539
+ }
2540
+ if (optionalToken) prop.saveToken(optionalToken, "optional");
2541
+ mergedProps.push(prop);
2542
+ }
2543
+ const mergedStructure = new SemanticStructureNode();
2544
+ mergedStructure.setProps(mergedProps);
2545
+ this.resolveAnnotation;
2546
+ mergedStructure.annotations = this.mergeNodesAnnotations(left.annotations, right.annotations);
2547
+ return [mergedStructure];
2548
+ }
2549
+ const never = new SemanticRefNode();
2550
+ never.saveToken(new Token({
2551
+ text: "never",
2552
+ type: "identifier",
2553
+ getRange: () => zeroRange
2554
+ }), "identifier");
2555
+ return [never];
2556
+ }
2557
+ /**
2558
+ * Merges two arrays of annotation tokens, ensuring that annotations from the
2559
+ * `right` array take precedence over those from the `left` array.
2560
+ *
2561
+ * - Annotations from `right` are always included.
2562
+ * - Annotations from `left` are included only if they are not already present in `right`.
2563
+ * - This ensures that if an annotation exists in both arrays, the one from `right` is kept.
2564
+ *
2565
+ * @param left - An optional array of annotation tokens to merge (lower priority).
2566
+ * @param right - An optional array of annotation tokens to merge (higher priority).
2567
+ * @returns A merged array of annotation tokens, preserving order while preventing duplicates.
2568
+ */ mergeNodesAnnotations(left, right) {
2569
+ const annotations$1 = [];
2570
+ const savedAnnotations = new Set();
2571
+ for (const a of right || []) {
2572
+ annotations$1.push(a);
2573
+ savedAnnotations.add(a.token.text);
2574
+ }
2575
+ for (const a of left || []) {
2576
+ const spec = this.resolveAnnotation(a.token.text);
2577
+ let append = spec && spec.config.multiple && spec.config.mergeStrategy === "append";
2578
+ if (append || !savedAnnotations.has(a.token.text)) annotations$1.push(a);
2579
+ }
2580
+ return annotations$1;
2581
+ }
2582
+ constructor(id, config, manager) {
2583
+ _define_property$3(this, "id", void 0);
2584
+ _define_property$3(this, "config", void 0);
2585
+ _define_property$3(this, "manager", void 0);
2586
+ _define_property$3(this, "registry", void 0);
2587
+ _define_property$3(this, "semanticMessages", void 0);
2588
+ _define_property$3(this, "messages", void 0);
2589
+ /**
2590
+ * All the non-blocks tokens, that could be referred
2591
+ */ _define_property$3(this, "tokensIndex", void 0);
2592
+ /**
2593
+ * All the block-tokens
2594
+ */ _define_property$3(this, "blocksIndex", void 0);
2595
+ /**
2596
+ * Imports map by URI, contains from Token and imports[] tokens
2597
+ */ _define_property$3(this, "imports", void 0);
2598
+ /**
2599
+ * Map of imported definitions by type/interface identifier
2600
+ */ _define_property$3(this, "importedDefs", void 0);
2601
+ /**
2602
+ * Exported nodes by identifier
2603
+ */ _define_property$3(this, "exports", void 0);
2604
+ /**
2605
+ * Set of documents that this document depend on
2606
+ */ _define_property$3(this, "dependencies", void 0);
2607
+ /**
2608
+ * Set of documents that depend on this document
2609
+ */ _define_property$3(this, "dependants", void 0);
2610
+ /**
2611
+ * List of tokens that refer to some type or interface
2612
+ */ _define_property$3(this, "referred", void 0);
2613
+ /**
2614
+ * Map of dependencies (documents) by URI
2615
+ */ _define_property$3(this, "dependenciesMap", void 0);
2616
+ _define_property$3(this, "nodes", void 0);
2617
+ _define_property$3(this, "_text", void 0);
2618
+ _define_property$3(this, "resolvedAnnotations", void 0);
2619
+ _define_property$3(this, "annotations", void 0);
2620
+ _define_property$3(this, "_allMessages", void 0);
2621
+ this.id = id;
2622
+ this.config = config;
2623
+ this.manager = manager;
2624
+ this.semanticMessages = [];
2625
+ this.messages = [];
2626
+ this.tokensIndex = new TokensIndex();
2627
+ this.blocksIndex = new BlocksIndex();
2628
+ this.imports = new Map();
2629
+ this.importedDefs = new Map();
2630
+ this.exports = new Map();
2631
+ this.dependencies = new Set();
2632
+ this.dependants = new Set();
2633
+ this.referred = [];
2634
+ this.dependenciesMap = new Map();
2635
+ this.nodes = [];
2636
+ this._text = "";
2637
+ this.resolvedAnnotations = [];
2638
+ this.annotations = [];
2639
+ this._allMessages = undefined;
2640
+ this.registry = new IdRegistry(Array.from(config.primitives?.keys() || []));
2641
+ }
2642
+ };
2643
+ const zeroRange = {
2644
+ start: {
2645
+ line: 0,
2646
+ character: 0
2647
+ },
2648
+ end: {
2649
+ line: 0,
2650
+ character: 0
2651
+ }
2652
+ };
2653
+
2654
+ //#endregion
2655
+ //#region packages/core/src/defaults/meta-annotations.ts
2656
+ const metaAnnotations = {
2657
+ label: new AnnotationSpec({
2658
+ description: "Defines a **human-readable label** for a property or entity. Useful for UI, logs, and documentation.\n\n**Example:**```atscript@meta.label \"User Name\"name: string```",
2659
+ argument: {
2660
+ name: "text",
2661
+ type: "string",
2662
+ description: "The label to be used for this field or entity."
2663
+ }
2664
+ }),
2665
+ id: new AnnotationSpec({
2666
+ description: "Marks a field as a unique identifier across multiple domains (DB, API, UI, logs).\n\n**Example:**```atscript@meta.id \"userId\"id: string```",
2667
+ argument: {
2668
+ optional: true,
2669
+ name: "name",
2670
+ type: "string",
2671
+ description: "Custom identifier name (defaults to property name if omitted)."
2672
+ }
2673
+ }),
2674
+ description: new AnnotationSpec({
2675
+ description: "Provides a **detailed description** of a field or entity, often used in documentation.\n\n**Example:**```atscript@meta.description \"Stores the user email address\"email: string```",
2676
+ argument: {
2677
+ name: "text",
2678
+ type: "string",
2679
+ description: "Detailed description for this field or entity."
2680
+ }
2681
+ }),
2682
+ documentation: new AnnotationSpec({
2683
+ description: "Provides **multi-line documentation** for a field or entity.\n\n**Example:**```atscript@meta.documentation \"# bio\"@meta.documentation \"## documentation of bio\"@meta.documentation \"your documentation\"bio: string```",
2684
+ multiple: true,
2685
+ argument: {
2686
+ name: "text",
2687
+ type: "string",
2688
+ description: "A line of documentation text. Multiple annotations can be used to form a full Markdown document."
2689
+ }
2690
+ }),
2691
+ placeholder: new AnnotationSpec({
2692
+ description: "Defines a **default placeholder value** for UI input fields.\n\n**Example:**```atscript@meta.placeholder \"Enter your name\"name: string```",
2693
+ nodeType: ["prop"],
2694
+ argument: {
2695
+ name: "text",
2696
+ type: "string",
2697
+ description: "The placeholder text to display in UI forms."
2698
+ }
2699
+ }),
2700
+ sensitive: new AnnotationSpec({
2701
+ description: "Marks a field as **sensitive** (e.g., passwords, API keys), ensuring it is hidden in logs and UI.\n\n**Example:**```atscript@meta.sensitivepassword: string```",
2702
+ nodeType: ["prop"],
2703
+ multiple: false
2704
+ }),
2705
+ readonly: new AnnotationSpec({
2706
+ description: "Marks a field as **read-only**, preventing modifications after creation.\n\n**Example:**```atscript@meta.readonlycreatedAt: date```",
2707
+ nodeType: ["prop"],
2708
+ multiple: false
2709
+ })
2710
+ };
2711
+
2712
+ //#endregion
2713
+ //#region packages/core/src/defaults/primitives.ts
2714
+ const positive = {
2715
+ documentation: "Number that greater than or equal to zero.",
2716
+ expect: { min: 0 }
2717
+ };
2718
+ const negative = {
2719
+ documentation: "Number that less than or equal to zero.",
2720
+ expect: { max: 0 }
2721
+ };
2722
+ const positiveOrNegative = {
2723
+ positive,
2724
+ negative
2725
+ };
2726
+ const primitives = {
2727
+ never: { documentation: "Represents impossible type." },
2728
+ string: {
2729
+ type: "string",
2730
+ documentation: "Represents textual data.",
2731
+ extensions: {
2732
+ email: {
2733
+ documentation: "Represents an email address.",
2734
+ expect: {
2735
+ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
2736
+ message: "Invalid email format."
2737
+ }
2738
+ },
2739
+ phone: {
2740
+ documentation: "Represents an phone number.",
2741
+ expect: {
2742
+ pattern: /^\+?[0-9\s-]{10,15}$/,
2743
+ message: "Invalid phone number format."
2744
+ }
2745
+ },
2746
+ date: {
2747
+ documentation: "Represents a date string.",
2748
+ expect: {
2749
+ pattern: [
2750
+ /^\d{4}-\d{2}-\d{2}$/,
2751
+ /^\d{2}\/\d{2}\/\d{4}$/,
2752
+ /^\d{2}-\d{2}-\d{4}$/,
2753
+ /^\d{1,2} [A-Za-z]+ \d{4}$/
2754
+ ],
2755
+ message: "Invalid date format."
2756
+ }
2757
+ },
2758
+ isoDate: {
2759
+ documentation: "Represents a date string in ISO format.",
2760
+ expect: {
2761
+ pattern: [/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?([+-]\d{2}:\d{2})$/],
2762
+ message: "Invalid ISO date format."
2763
+ }
2764
+ },
2765
+ uuid: {
2766
+ documentation: "Represents a UUID.",
2767
+ expect: {
2768
+ pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
2769
+ message: "Invalid UUID format."
2770
+ }
2771
+ }
2772
+ }
2773
+ },
2774
+ number: {
2775
+ type: "number",
2776
+ documentation: "Represents numeric data.",
2777
+ extensions: {
2778
+ ...positiveOrNegative,
2779
+ single: {
2780
+ extensions: positiveOrNegative,
2781
+ documentation: "Represents a single-precision floating-point number."
2782
+ },
2783
+ double: {
2784
+ extensions: positiveOrNegative,
2785
+ documentation: "Represents a double-precision floating-point number."
2786
+ },
2787
+ int: {
2788
+ extensions: positiveOrNegative,
2789
+ documentation: "Represents an integer number.",
2790
+ expect: { int: true }
2791
+ },
2792
+ timestamp: {
2793
+ documentation: "Represents a timestamp.",
2794
+ expect: { int: true }
2795
+ }
2796
+ }
2797
+ },
2798
+ boolean: {
2799
+ type: "boolean",
2800
+ documentation: "Represents true/false values.",
2801
+ extensions: {
2802
+ true: { documentation: "Represents a true value." },
2803
+ false: { documentation: "Represents a false value." }
2804
+ }
2805
+ },
2806
+ null: {
2807
+ type: "null",
2808
+ documentation: "Represents NULL value."
2809
+ },
2810
+ void: {
2811
+ type: "void",
2812
+ documentation: "Represents no value."
2813
+ },
2814
+ undefined: {
2815
+ type: "void",
2816
+ documentation: "Represents no value."
2817
+ }
2818
+ };
2819
+
2820
+ //#endregion
2821
+ //#region packages/core/src/defaults/expect-annotations.ts
2822
+ const expectAnnotations = {
2823
+ minLength: new AnnotationSpec({
2824
+ description: "Validates that a string or array has a minimum length.\n\n**Example:**```atscript@expect.minLength 5name: string```",
2825
+ defType: ["array", "string"],
2826
+ argument: {
2827
+ name: "length",
2828
+ type: "number",
2829
+ description: "The minimum length of the string or array."
2830
+ }
2831
+ }),
2832
+ maxLength: new AnnotationSpec({
2833
+ description: "Validates that a string or array has a maximum length.\n\n**Example:**```atscript@expect.maxLength 5name: string```",
2834
+ defType: ["array", "string"],
2835
+ argument: {
2836
+ name: "length",
2837
+ type: "number",
2838
+ description: "The maximum length of the string or array."
2839
+ }
2840
+ }),
2841
+ min: new AnnotationSpec({
2842
+ description: "Validates that a number is greater than or equal to a minimum value.\n\n**Example:**```atscript@expect.min 18age: number```",
2843
+ defType: ["number"],
2844
+ argument: {
2845
+ name: "minValue",
2846
+ type: "number",
2847
+ description: "The minimum value."
2848
+ }
2849
+ }),
2850
+ max: new AnnotationSpec({
2851
+ description: "Validates that a number is less than or equal to a maximum value.\n\n**Example:**```atscript@expect.max 10count: number```",
2852
+ defType: ["number"],
2853
+ argument: {
2854
+ name: "maxValue",
2855
+ type: "number",
2856
+ description: "The maximum value."
2857
+ }
2858
+ }),
2859
+ int: new AnnotationSpec({
2860
+ description: "Validates that a number is an integer (no decimal places).\n\n**Example:**```atscript@expect.intage: number```",
2861
+ defType: ["number"]
2862
+ }),
2863
+ pattern: new AnnotationSpec({
2864
+ description: "Validates that a string matches a specific pattern.\n\n**Example:**```atscript@expect.pattern \"[a-z]+\", \"u\"name: string```",
2865
+ defType: ["string"],
2866
+ multiple: true,
2867
+ mergeStrategy: "append",
2868
+ argument: [
2869
+ {
2870
+ name: "pattern",
2871
+ type: "string",
2872
+ description: "The regular expression pattern to match."
2873
+ },
2874
+ {
2875
+ name: "flags",
2876
+ optional: true,
2877
+ type: "string",
2878
+ values: [
2879
+ "g",
2880
+ "gi",
2881
+ "gim",
2882
+ "gims",
2883
+ "gimsu",
2884
+ "gimsuy",
2885
+ "gimsy",
2886
+ "gimu",
2887
+ "gimuy",
2888
+ "gimy",
2889
+ "gis",
2890
+ "gisu",
2891
+ "gisuy",
2892
+ "gisy",
2893
+ "giu",
2894
+ "giuy",
2895
+ "giy",
2896
+ "gm",
2897
+ "gms",
2898
+ "gmsu",
2899
+ "gmsuy",
2900
+ "gmsy",
2901
+ "gmu",
2902
+ "gmuy",
2903
+ "gmy",
2904
+ "gs",
2905
+ "gsu",
2906
+ "gsuy",
2907
+ "gsy",
2908
+ "gu",
2909
+ "guy",
2910
+ "gy",
2911
+ "i",
2912
+ "im",
2913
+ "ims",
2914
+ "imsu",
2915
+ "imsuy",
2916
+ "imsy",
2917
+ "imu",
2918
+ "imuy",
2919
+ "imy",
2920
+ "is",
2921
+ "isu",
2922
+ "isuy",
2923
+ "isy",
2924
+ "iu",
2925
+ "iuy",
2926
+ "iy",
2927
+ "m",
2928
+ "ms",
2929
+ "msu",
2930
+ "msuy",
2931
+ "msy",
2932
+ "mu",
2933
+ "muy",
2934
+ "my",
2935
+ "s",
2936
+ "su",
2937
+ "suy",
2938
+ "sy",
2939
+ "u",
2940
+ "uy",
2941
+ "y"
2942
+ ],
2943
+ description: "Optional flags for the regular expression."
2944
+ },
2945
+ {
2946
+ name: "message",
2947
+ optional: true,
2948
+ type: "string",
2949
+ description: "Optional error message to display if the validation fails."
2950
+ }
2951
+ ],
2952
+ validate(mainToken, args) {
2953
+ if (args[0]) try {
2954
+ new RegExp(args[0].text);
2955
+ return [];
2956
+ } catch (e) {
2957
+ return [{
2958
+ message: "Invalid regular expression",
2959
+ range: args[0].range,
2960
+ severity: 1
2961
+ }];
2962
+ }
2963
+ return [];
2964
+ }
2965
+ })
2966
+ };
2967
+
2968
+ //#endregion
2969
+ //#region packages/core/src/default-atscript-config.ts
2970
+ function getDefaultAtscriptConfig() {
2971
+ const defaulTAtscriptConfig = {
2972
+ primitives,
2973
+ annotations: {
2974
+ meta: { ...metaAnnotations },
2975
+ expect: { ...expectAnnotations }
2976
+ }
2977
+ };
2978
+ return defaulTAtscriptConfig;
2979
+ }
2980
+
2981
+ //#endregion
2982
+ //#region packages/core/src/plugin/plugin-manager.ts
2983
+ function _define_property$2(obj, key, value) {
2984
+ if (key in obj) Object.defineProperty(obj, key, {
2985
+ value,
2986
+ enumerable: true,
2987
+ configurable: true,
2988
+ writable: true
2989
+ });
2990
+ else obj[key] = value;
2991
+ return obj;
2992
+ }
2993
+ var PluginManager = class {
2994
+ get plugins() {
2995
+ return this.cfg.plugins ?? [];
2996
+ }
2997
+ async getDocConfig() {
2998
+ if (!this._docConfig) {
2999
+ const raw = await this.config();
3000
+ this._docConfig = {};
3001
+ if (raw?.primitives) {
3002
+ this._docConfig.primitives = this._docConfig.primitives || new Map();
3003
+ for (const [key, value] of Object.entries(raw.primitives)) this._docConfig.primitives.set(key, new SemanticPrimitiveNode(key, value));
3004
+ }
3005
+ if (raw?.annotations) {
3006
+ this._docConfig.annotations = this._docConfig.annotations || {};
3007
+ Object.assign(this._docConfig.annotations, raw.annotations);
3008
+ }
3009
+ this._docConfig.unknownAnnotation = raw?.unknownAnnotation;
3010
+ }
3011
+ return this._docConfig;
3012
+ }
3013
+ async config(config = this.cfg) {
3014
+ if (!this._config) {
3015
+ const processed = new Set();
3016
+ config = defu(config, getDefaultAtscriptConfig());
3017
+ const filtered = this.plugins.filter((plugin) => !processed.has(plugin.name));
3018
+ let i = 0;
3019
+ while (processed.size !== filtered.length) {
3020
+ i++;
3021
+ for (const plugin of filtered) {
3022
+ if (processed.has(plugin.name)) continue;
3023
+ config = defu(await plugin.config?.(config), config);
3024
+ processed.add(plugin.name);
3025
+ }
3026
+ if (i > 100) throw new Error(`Too many iterations in config`);
3027
+ }
3028
+ this._config = config;
3029
+ }
3030
+ return this._config;
3031
+ }
3032
+ async resolve(id) {
3033
+ let newId = id;
3034
+ for (const plugin of this.plugins) if (plugin.resolve) newId = await plugin.resolve(id);
3035
+ return newId;
3036
+ }
3037
+ async load(id) {
3038
+ const filePath = id.startsWith("file://") ? id.slice(7) : id;
3039
+ for (const plugin of this.plugins) if (plugin.load) {
3040
+ const content$1 = await plugin.load(id);
3041
+ if (content$1) return content$1;
3042
+ }
3043
+ const content = await readFile(filePath, "utf8");
3044
+ return content.toString();
3045
+ }
3046
+ async onDocumnet(doc) {
3047
+ for (const plugin of this.plugins) if (plugin.onDocumnet) await plugin.onDocumnet(doc);
3048
+ }
3049
+ async render(doc, format) {
3050
+ const files = [];
3051
+ for (const plugin of this.plugins) if (plugin.render) {
3052
+ const newFiles = await plugin.render(doc, format);
3053
+ if (newFiles?.length > 0) files.push(...newFiles.map((f) => ({
3054
+ ...f,
3055
+ source: doc.id.startsWith("file://") ? doc.id.slice(7) : doc.id
3056
+ })));
3057
+ }
3058
+ return files;
3059
+ }
3060
+ async buildEnd(output, format, repo) {
3061
+ for (const plugin of this.plugins) if (plugin.buildEnd) await plugin.buildEnd(output, format, repo);
3062
+ }
3063
+ async loopInAnnotationsSpec(cb) {
3064
+ const config = await this.config();
3065
+ const annotations$1 = config.annotations || {};
3066
+ return this._loopInAnnotationsSpec(annotations$1, cb);
3067
+ }
3068
+ _loopInAnnotationsSpec(annotations$1, cb, prefix) {
3069
+ for (const [key, value] of Object.entries(annotations$1)) if (isAnnotationSpec(value)) cb(prefix ? `${prefix}.${key}` : key, value);
3070
+ else this._loopInAnnotationsSpec(value, cb, prefix ? `${prefix}.${key}` : key);
3071
+ }
3072
+ constructor(cfg) {
3073
+ _define_property$2(this, "cfg", void 0);
3074
+ _define_property$2(this, "_config", void 0);
3075
+ _define_property$2(this, "name", void 0);
3076
+ _define_property$2(this, "_docConfig", void 0);
3077
+ this.cfg = cfg;
3078
+ this.name = "plugin-manager";
3079
+ }
3080
+ };
3081
+
3082
+ //#endregion
3083
+ //#region packages/core/src/repo.ts
3084
+ function _define_property$1(obj, key, value) {
3085
+ if (key in obj) Object.defineProperty(obj, key, {
3086
+ value,
3087
+ enumerable: true,
3088
+ configurable: true,
3089
+ writable: true
3090
+ });
3091
+ else obj[key] = value;
3092
+ return obj;
3093
+ }
3094
+ var AtscriptRepo = class {
3095
+ getSharedPluginManager() {
3096
+ return this.sharedPluginManager?.manager;
3097
+ }
3098
+ async getPrimitivesTags() {
3099
+ const manager = await this.getSharedPluginManager();
3100
+ if (!manager) return undefined;
3101
+ const docConfig = await manager.getDocConfig();
3102
+ const primitives$1 = Array.from(docConfig.primitives?.entries() || []);
3103
+ const tags = [];
3104
+ const processed = new Set();
3105
+ for (const [, primitive] of primitives$1) tags.push(...primitive.getAllTags(processed));
3106
+ return new Set(tags);
3107
+ }
3108
+ async getUsedAnnotations() {
3109
+ const manager = await this.getSharedPluginManager();
3110
+ const annotations$1 = {};
3111
+ if (manager) await manager.loopInAnnotationsSpec((name, spec) => {
3112
+ const types = [];
3113
+ const multiple = !!spec.config.multiple;
3114
+ if (Array.isArray(spec.config.argument)) {
3115
+ const o = {
3116
+ type: "object",
3117
+ props: {}
3118
+ };
3119
+ for (const a of spec.arguments) o.props[a.name] = {
3120
+ type: a.type,
3121
+ optional: a.optional
3122
+ };
3123
+ types.push(o);
3124
+ } else if (spec.config.argument) types.push({
3125
+ type: spec.config.argument.type,
3126
+ optional: spec.config.argument.optional
3127
+ });
3128
+ else types.push({ type: "boolean" });
3129
+ annotations$1[name] = {
3130
+ multiple,
3131
+ fromSpec: true,
3132
+ typeSet: new Set(),
3133
+ types
3134
+ };
3135
+ });
3136
+ for (const doc of Array.from(this.atscripts.values())) {
3137
+ const awaited = await doc;
3138
+ for (const { name, token, args } of awaited.annotations) {
3139
+ if (annotations$1[name]?.fromSpec) continue;
3140
+ if (!annotations$1[name]) {
3141
+ let types = [];
3142
+ let multiple = false;
3143
+ annotations$1[name] = {
3144
+ multiple,
3145
+ fromSpec: false,
3146
+ typeSet: new Set(),
3147
+ types
3148
+ };
3149
+ }
3150
+ const isArray$1 = token.parentNode.countAnnotations(name) > 1;
3151
+ if (isArray$1) annotations$1[name].multiple = true;
3152
+ for (const arg of args) if (arg.type === "text") {
3153
+ if (!annotations$1[name].typeSet.has("string")) {
3154
+ annotations$1[name].typeSet.add("string");
3155
+ annotations$1[name].types.push({ type: "string" });
3156
+ }
3157
+ } else if (arg.type === "number") {
3158
+ if (!annotations$1[name].typeSet.has("number")) {
3159
+ annotations$1[name].typeSet.add("number");
3160
+ annotations$1[name].types.push({ type: "number" });
3161
+ }
3162
+ } else if (arg.type === "identifier" && ["true", "false"].includes(arg.text)) {
3163
+ if (!annotations$1[name].typeSet.has("boolean")) {
3164
+ annotations$1[name].typeSet.add("boolean");
3165
+ annotations$1[name].types.push({ type: "boolean" });
3166
+ }
3167
+ } else if (!annotations$1[name].typeSet.has("unknown")) {
3168
+ annotations$1[name].typeSet.add("unknown");
3169
+ annotations$1[name].types.push({ type: "unknown" });
3170
+ }
3171
+ if (args.length === 0 && !annotations$1[name].typeSet.has("boolean")) {
3172
+ annotations$1[name].typeSet.add("boolean");
3173
+ annotations$1[name].types.push({ type: "boolean" });
3174
+ }
3175
+ }
3176
+ }
3177
+ return annotations$1;
3178
+ }
3179
+ async loadPluginManagerFor(id) {
3180
+ if (this.sharedConfig) {
3181
+ if (!this.sharedPluginManager) this.sharedPluginManager = {
3182
+ manager: new PluginManager(this.sharedConfig),
3183
+ dependants: new Set()
3184
+ };
3185
+ return this.sharedPluginManager;
3186
+ }
3187
+ const configFile = await resolveConfigFile(id, this.root);
3188
+ if (configFile) {
3189
+ const globalPathToConfig = path.join(this.root, configFile);
3190
+ if (!this.configFiles.has(globalPathToConfig)) {
3191
+ const rawConfigPromise = loadConfig(configFile, this.configFormat);
3192
+ this.configFiles.set(globalPathToConfig, rawConfigPromise);
3193
+ }
3194
+ const rawConfig = await this.configFiles.get(globalPathToConfig);
3195
+ if (!rawConfig.rootDir) rawConfig.rootDir = path.dirname(configFile);
3196
+ const manager = new PluginManager(rawConfig);
3197
+ await manager.getDocConfig();
3198
+ return {
3199
+ file: globalPathToConfig,
3200
+ manager,
3201
+ dependants: new Set()
3202
+ };
3203
+ } else {
3204
+ const manager = new PluginManager({ rootDir: process.cwd() });
3205
+ await manager.getDocConfig();
3206
+ return {
3207
+ manager,
3208
+ dependants: new Set()
3209
+ };
3210
+ }
3211
+ }
3212
+ async resolveConfig(id) {
3213
+ let config = this.configs.get(id);
3214
+ if (!config) {
3215
+ config = this.loadPluginManagerFor(id);
3216
+ config.then((c) => {
3217
+ c.dependants.add(id);
3218
+ });
3219
+ this.configs.set(id, config);
3220
+ }
3221
+ return config;
3222
+ }
3223
+ async openDocument(id, text$2) {
3224
+ let atscript = this.atscripts.get(id);
3225
+ if (atscript) {
3226
+ if (text$2) atscript.then((d) => {
3227
+ d.update(text$2);
3228
+ return d;
3229
+ });
3230
+ } else {
3231
+ atscript = this._openDocument(id, text$2);
3232
+ atscript.catch(() => {
3233
+ this.atscripts.delete(id);
3234
+ });
3235
+ this.atscripts.set(id, atscript);
3236
+ }
3237
+ return atscript;
3238
+ }
3239
+ async _openDocument(id, text$2) {
3240
+ const { manager } = await this.resolveConfig(id);
3241
+ const newId = await manager.resolve(id);
3242
+ if (!newId) throw new Error(`Document not resolved: ${id}`);
3243
+ const content = text$2 || await manager.load(newId);
3244
+ if (typeof content !== "string") throw new Error(`Document not found: ${newId}`);
3245
+ const atscript = new AtscriptDoc(id, await manager.getDocConfig(), manager);
3246
+ atscript.update(content);
3247
+ await manager.onDocumnet(atscript);
3248
+ return atscript;
3249
+ }
3250
+ async checkDoc(atscript) {
3251
+ await this.checkImports(atscript);
3252
+ }
3253
+ async checkImports(atscript) {
3254
+ const promise = Promise.all(Array.from(atscript.imports.values(), async ({ from, imports }) => this.checkImport(atscript, from, imports)));
3255
+ const results = await promise;
3256
+ atscript.updateDependencies(results.filter(Boolean));
3257
+ }
3258
+ async checkImport(atscript, from, imports) {
3259
+ const forId = resolveAtscriptFromPath(from.text, atscript.id);
3260
+ if (forId === atscript.id) {
3261
+ const messages = atscript.getDiagMessages();
3262
+ messages.push({
3263
+ severity: 1,
3264
+ message: "\"import\" cannot import itself",
3265
+ range: from.range
3266
+ });
3267
+ return;
3268
+ }
3269
+ const errors = [];
3270
+ let external;
3271
+ try {
3272
+ external = await this.openDocument(forId);
3273
+ for (const token of imports) if (!external.exports.has(token.text)) errors.push({
3274
+ severity: 1,
3275
+ message: `"${from.text}" has no exported member "${token.text}"`,
3276
+ range: token.range
3277
+ });
3278
+ } catch (error) {
3279
+ errors.push({
3280
+ severity: 1,
3281
+ message: `"${from.text}" not found`,
3282
+ range: from.range
3283
+ });
3284
+ }
3285
+ if (errors.length > 0) {
3286
+ const messages = atscript.getDiagMessages();
3287
+ messages.push(...errors);
3288
+ }
3289
+ return external;
3290
+ }
3291
+ constructor(root$1 = process.cwd(), sharedConfig) {
3292
+ _define_property$1(this, "root", void 0);
3293
+ _define_property$1(this, "sharedConfig", void 0);
3294
+ _define_property$1(this, "configFormat", void 0);
3295
+ /**
3296
+ * Configs cache
3297
+ */ _define_property$1(this, "configs", void 0);
3298
+ /**
3299
+ * .as Documents cache
3300
+ */ _define_property$1(this, "atscripts", void 0);
3301
+ _define_property$1(this, "sharedPluginManager", void 0);
3302
+ /**
3303
+ * cache for raw content of config files
3304
+ */ _define_property$1(this, "configFiles", void 0);
3305
+ this.root = root$1;
3306
+ this.sharedConfig = sharedConfig;
3307
+ this.configs = new Map();
3308
+ this.atscripts = new Map();
3309
+ this.configFiles = new Map();
3310
+ }
3311
+ };
3312
+
3313
+ //#endregion
3314
+ //#region packages/core/src/plugin/types.ts
3315
+ const createAtscriptPlugin = (plugin) => plugin;
3316
+
3317
+ //#endregion
3318
+ //#region packages/core/src/build.ts
3319
+ function _define_property(obj, key, value) {
3320
+ if (key in obj) Object.defineProperty(obj, key, {
3321
+ value,
3322
+ enumerable: true,
3323
+ configurable: true,
3324
+ writable: true
3325
+ });
3326
+ else obj[key] = value;
3327
+ return obj;
3328
+ }
3329
+ async function build(config) {
3330
+ const rootDir = config.rootDir ? config.rootDir.startsWith("/") ? config.rootDir : path$1.join(process.cwd(), config.rootDir) : process.cwd();
3331
+ config.rootDir = rootDir;
3332
+ const repo = new AtscriptRepo(rootDir, config);
3333
+ const entries = [];
3334
+ if (config.entries && config.entries.length > 0) for (const entry of config.entries) entries.push(path$1.join(rootDir, entry));
3335
+ else {
3336
+ const includes = config.include && config.include.length > 0 ? config.include : ["**/*.as"];
3337
+ const excludes = config.exclude && config.exclude.length > 0 ? config.exclude : ["node_modules"];
3338
+ const found = await glob(includes, {
3339
+ cwd: rootDir,
3340
+ absolute: true,
3341
+ ignore: excludes
3342
+ });
3343
+ entries.push(...found);
3344
+ }
3345
+ const documents = [];
3346
+ for (const entry of entries) documents.push(await repo.openDocument("file://" + entry));
3347
+ return new BuildRepo(rootDir, repo, documents.filter(Boolean));
3348
+ }
3349
+ var BuildRepo = class {
3350
+ async diagnostics() {
3351
+ const docMessages = new Map();
3352
+ for (const document of this.docs) {
3353
+ await this.repo.checkDoc(document);
3354
+ docMessages.set(document.id, document.getDiagMessages());
3355
+ }
3356
+ return docMessages;
3357
+ }
3358
+ async generate(config, docs = this.docs) {
3359
+ const outFiles = [];
3360
+ for (const document of docs) {
3361
+ const out = await document.render(config.format);
3362
+ if (out?.length) outFiles.push(...out);
3363
+ }
3364
+ for (const outFile of outFiles) {
3365
+ const docPath = outFile.source.replace(/^file:\/\//, "");
3366
+ if (config.outDir) {
3367
+ const rel = path$1.relative(this.rootDir, docPath);
3368
+ const relDir = path$1.dirname(rel);
3369
+ outFile.target = path$1.join(this.rootDir, config.outDir, relDir, outFile.fileName);
3370
+ } else outFile.target = path$1.join(path$1.dirname(docPath), outFile.fileName);
3371
+ }
3372
+ if (this.repo.sharedConfig && this.docs === docs && this.docs[0]) {
3373
+ const { manager } = await this.repo.loadPluginManagerFor(this.docs[0].id);
3374
+ await manager.buildEnd(outFiles, config.format, this.repo);
3375
+ }
3376
+ return outFiles;
3377
+ }
3378
+ async write(config, docs = this.docs) {
3379
+ const outFiles = await this.generate(config, docs);
3380
+ for (const o of outFiles) if (o.target) {
3381
+ await mkdir(path$1.dirname(o.target), { recursive: true });
3382
+ writeFile(o.target, o.content);
3383
+ }
3384
+ return outFiles;
3385
+ }
3386
+ constructor(rootDir, repo, docs) {
3387
+ _define_property(this, "rootDir", void 0);
3388
+ _define_property(this, "repo", void 0);
3389
+ _define_property(this, "docs", void 0);
3390
+ this.rootDir = rootDir;
3391
+ this.repo = repo;
3392
+ this.docs = docs;
3393
+ }
3394
+ };
3395
+
3396
+ //#endregion
3397
+ export { $n, AnnotationSpec, AtscriptDoc, AtscriptRepo, BuildRepo, PluginManager, SemanticArrayNode, SemanticConstNode, SemanticGroup, SemanticImportNode, SemanticInterfaceNode, SemanticNode, SemanticPrimitiveNode, SemanticPropNode, SemanticRefNode, SemanticStructureNode, SemanticTupleNode, SemanticTypeNode, Token, build, createAtscriptPlugin, defineConfig, getRelPath, isAnnotationSpec, isArray, isConst, isGroup, isImport, isInterface, isPrimitive, isProp, isRef, isStructure, isTuple, isType, loadConfig, loadTsConfig, resolveAnnotation, resolveAtscriptFromPath, resolveConfigFile };