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