@quartz-community/bases-page 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/LICENSE +21 -0
- package/README.md +315 -0
- package/dist/BasesBody-B4CEJjEp.d.ts +6 -0
- package/dist/chunk-2AUMER56.js +44 -0
- package/dist/chunk-2AUMER56.js.map +1 -0
- package/dist/chunk-4HXXKSJ4.js +929 -0
- package/dist/chunk-4HXXKSJ4.js.map +1 -0
- package/dist/chunk-TDUJOYTU.js +42 -0
- package/dist/chunk-TDUJOYTU.js.map +1 -0
- package/dist/chunk-X2AZ5GOJ.js +1931 -0
- package/dist/chunk-X2AZ5GOJ.js.map +1 -0
- package/dist/compiler/index.d.ts +146 -0
- package/dist/compiler/index.js +7 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/components/index.d.ts +13 -0
- package/dist/components/index.js +9 -0
- package/dist/components/index.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +18703 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +48 -0
- package/dist/registry.js +7 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +181 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +143 -0
|
@@ -0,0 +1,1931 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
|
|
3
|
+
createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
// src/compiler/errors.ts
|
|
6
|
+
var CompilerError = class extends Error {
|
|
7
|
+
span;
|
|
8
|
+
severity;
|
|
9
|
+
constructor(message, span, severity = "error" /* Error */) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "CompilerError";
|
|
12
|
+
this.span = span;
|
|
13
|
+
this.severity = severity;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/compiler/compiler.ts
|
|
18
|
+
var LAZY_METHODS = /* @__PURE__ */ new Set(["filter", "map", "find", "some", "every", "flatMap"]);
|
|
19
|
+
var Compiler = class _Compiler {
|
|
20
|
+
instructions = [];
|
|
21
|
+
compile(expression) {
|
|
22
|
+
this.compileExpression(expression);
|
|
23
|
+
return this.instructions;
|
|
24
|
+
}
|
|
25
|
+
compileExpression(expression) {
|
|
26
|
+
switch (expression.type) {
|
|
27
|
+
case "Literal":
|
|
28
|
+
this.compileLiteral(expression);
|
|
29
|
+
return;
|
|
30
|
+
case "Identifier":
|
|
31
|
+
this.compileIdentifier(expression);
|
|
32
|
+
return;
|
|
33
|
+
case "List":
|
|
34
|
+
this.compileList(expression);
|
|
35
|
+
return;
|
|
36
|
+
case "Unary":
|
|
37
|
+
this.compileUnary(expression);
|
|
38
|
+
return;
|
|
39
|
+
case "Binary":
|
|
40
|
+
this.compileBinary(expression);
|
|
41
|
+
return;
|
|
42
|
+
case "Member":
|
|
43
|
+
this.compileMember(expression);
|
|
44
|
+
return;
|
|
45
|
+
case "Index":
|
|
46
|
+
this.compileIndex(expression);
|
|
47
|
+
return;
|
|
48
|
+
case "Call":
|
|
49
|
+
this.compileCall(expression);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
compileLiteral(expression) {
|
|
54
|
+
this.emit({ type: "Const", value: expression.value });
|
|
55
|
+
}
|
|
56
|
+
compileIdentifier(expression) {
|
|
57
|
+
this.emit({ type: "Ident", name: expression.name });
|
|
58
|
+
}
|
|
59
|
+
compileList(expression) {
|
|
60
|
+
for (const element of expression.elements) {
|
|
61
|
+
this.compileExpression(element);
|
|
62
|
+
}
|
|
63
|
+
this.emit({ type: "List", count: expression.elements.length });
|
|
64
|
+
}
|
|
65
|
+
compileUnary(expression) {
|
|
66
|
+
this.compileExpression(expression.argument);
|
|
67
|
+
this.emit({ type: "Unary", operator: expression.operator });
|
|
68
|
+
}
|
|
69
|
+
compileBinary(expression) {
|
|
70
|
+
if (expression.operator === "&&" || expression.operator === "||") {
|
|
71
|
+
this.compileLogical(expression);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.compileExpression(expression.left);
|
|
75
|
+
this.compileExpression(expression.right);
|
|
76
|
+
this.emit({ type: "Binary", operator: expression.operator });
|
|
77
|
+
}
|
|
78
|
+
compileLogical(expression) {
|
|
79
|
+
const operator = expression.operator;
|
|
80
|
+
this.compileExpression(expression.left);
|
|
81
|
+
this.emit({ type: "ToBool" });
|
|
82
|
+
if (operator === "&&") {
|
|
83
|
+
const jumpFalse = this.emit({ type: "JumpIfFalse", offset: 0 });
|
|
84
|
+
this.compileExpression(expression.right);
|
|
85
|
+
this.emit({ type: "ToBool" });
|
|
86
|
+
const jumpEnd2 = this.emit({ type: "Jump", offset: 0 });
|
|
87
|
+
const falseIndex = this.instructions.length;
|
|
88
|
+
this.emit({ type: "Const", value: false });
|
|
89
|
+
const endIndex2 = this.instructions.length;
|
|
90
|
+
this.patchJump(jumpFalse, falseIndex);
|
|
91
|
+
this.patchJump(jumpEnd2, endIndex2);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const jumpTrue = this.emit({ type: "JumpIfTrue", offset: 0 });
|
|
95
|
+
this.compileExpression(expression.right);
|
|
96
|
+
this.emit({ type: "ToBool" });
|
|
97
|
+
const jumpEnd = this.emit({ type: "Jump", offset: 0 });
|
|
98
|
+
const trueIndex = this.instructions.length;
|
|
99
|
+
this.emit({ type: "Const", value: true });
|
|
100
|
+
const endIndex = this.instructions.length;
|
|
101
|
+
this.patchJump(jumpTrue, trueIndex);
|
|
102
|
+
this.patchJump(jumpEnd, endIndex);
|
|
103
|
+
}
|
|
104
|
+
compileMember(expression) {
|
|
105
|
+
if (expression.object.type === "Identifier" && expression.object.name === "formula" && expression.property) {
|
|
106
|
+
this.emit({ type: "LoadFormula", name: expression.property });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.compileExpression(expression.object);
|
|
110
|
+
this.emit({ type: "Member", name: expression.property });
|
|
111
|
+
}
|
|
112
|
+
compileIndex(expression) {
|
|
113
|
+
this.compileExpression(expression.object);
|
|
114
|
+
this.compileExpression(expression.index);
|
|
115
|
+
this.emit({ type: "Index" });
|
|
116
|
+
}
|
|
117
|
+
compileCall(expression) {
|
|
118
|
+
if (expression.callee.type === "Identifier" && expression.callee.name === "if") {
|
|
119
|
+
this.compileIfExpression(expression.args);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (expression.callee.type === "Identifier") {
|
|
123
|
+
for (const arg of expression.args) {
|
|
124
|
+
this.compileExpression(arg);
|
|
125
|
+
}
|
|
126
|
+
this.emit({
|
|
127
|
+
type: "CallGlobal",
|
|
128
|
+
name: expression.callee.name,
|
|
129
|
+
argc: expression.args.length
|
|
130
|
+
});
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (expression.callee.type === "Member") {
|
|
134
|
+
if (LAZY_METHODS.has(expression.callee.property)) {
|
|
135
|
+
this.compileExpression(expression.callee.object);
|
|
136
|
+
const argPrograms = [];
|
|
137
|
+
for (const arg of expression.args) {
|
|
138
|
+
const subCompiler = new _Compiler();
|
|
139
|
+
argPrograms.push(subCompiler.compile(arg));
|
|
140
|
+
}
|
|
141
|
+
this.emit({
|
|
142
|
+
type: "CallMethodLazy",
|
|
143
|
+
name: expression.callee.property,
|
|
144
|
+
argPrograms
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.compileExpression(expression.callee.object);
|
|
149
|
+
for (const arg of expression.args) {
|
|
150
|
+
this.compileExpression(arg);
|
|
151
|
+
}
|
|
152
|
+
this.emit({
|
|
153
|
+
type: "CallMethod",
|
|
154
|
+
name: expression.callee.property,
|
|
155
|
+
argc: expression.args.length
|
|
156
|
+
});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
throw new CompilerError("Unsupported call target", expression.span);
|
|
160
|
+
}
|
|
161
|
+
compileIfExpression(args) {
|
|
162
|
+
const condition = args[0];
|
|
163
|
+
const whenTrue = args[1];
|
|
164
|
+
const whenFalse = args[2];
|
|
165
|
+
if (!condition) {
|
|
166
|
+
this.emit({ type: "Const", value: void 0 });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
this.compileExpression(condition);
|
|
170
|
+
this.emit({ type: "ToBool" });
|
|
171
|
+
const jumpFalse = this.emit({ type: "JumpIfFalse", offset: 0 });
|
|
172
|
+
if (whenTrue) {
|
|
173
|
+
this.compileExpression(whenTrue);
|
|
174
|
+
} else {
|
|
175
|
+
this.emit({ type: "Const", value: void 0 });
|
|
176
|
+
}
|
|
177
|
+
const jumpEnd = this.emit({ type: "Jump", offset: 0 });
|
|
178
|
+
const falseIndex = this.instructions.length;
|
|
179
|
+
if (whenFalse) {
|
|
180
|
+
this.compileExpression(whenFalse);
|
|
181
|
+
} else {
|
|
182
|
+
this.emit({ type: "Const", value: void 0 });
|
|
183
|
+
}
|
|
184
|
+
const endIndex = this.instructions.length;
|
|
185
|
+
this.patchJump(jumpFalse, falseIndex);
|
|
186
|
+
this.patchJump(jumpEnd, endIndex);
|
|
187
|
+
}
|
|
188
|
+
emit(instruction) {
|
|
189
|
+
this.instructions.push(instruction);
|
|
190
|
+
return this.instructions.length - 1;
|
|
191
|
+
}
|
|
192
|
+
patchJump(index, target) {
|
|
193
|
+
const instruction = this.instructions[index];
|
|
194
|
+
if (!instruction) {
|
|
195
|
+
throw new CompilerError("Invalid jump patch", { start: 0, end: 0 });
|
|
196
|
+
}
|
|
197
|
+
if (instruction.type === "Jump") {
|
|
198
|
+
this.instructions[index] = { ...instruction, offset: target - index };
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (instruction.type === "JumpIfFalse") {
|
|
202
|
+
this.instructions[index] = { ...instruction, offset: target - index };
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (instruction.type === "JumpIfTrue") {
|
|
206
|
+
this.instructions[index] = { ...instruction, offset: target - index };
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
throw new CompilerError("Cannot patch non-jump instruction", { start: 0, end: 0 });
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function compileAst(expression) {
|
|
213
|
+
const compiler = new Compiler();
|
|
214
|
+
const instructions = compiler.compile(expression);
|
|
215
|
+
return { ast: expression, instructions };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/compiler/lexer.ts
|
|
219
|
+
var KEYWORDS = /* @__PURE__ */ new Map([
|
|
220
|
+
["true", "True" /* True */],
|
|
221
|
+
["false", "False" /* False */],
|
|
222
|
+
["null", "Null" /* Null */],
|
|
223
|
+
["and", "And" /* And */],
|
|
224
|
+
["or", "Or" /* Or */],
|
|
225
|
+
["not", "Not" /* Not */]
|
|
226
|
+
]);
|
|
227
|
+
function isWhitespace(ch) {
|
|
228
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r";
|
|
229
|
+
}
|
|
230
|
+
function isDigit(ch) {
|
|
231
|
+
if (!ch) return false;
|
|
232
|
+
const code = ch.charCodeAt(0);
|
|
233
|
+
return code >= 48 && code <= 57;
|
|
234
|
+
}
|
|
235
|
+
function isAlpha(ch) {
|
|
236
|
+
if (!ch) return false;
|
|
237
|
+
const code = ch.charCodeAt(0);
|
|
238
|
+
return code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
239
|
+
}
|
|
240
|
+
function isIdentifierStart(ch) {
|
|
241
|
+
return isAlpha(ch) || ch === "_" || ch === "$";
|
|
242
|
+
}
|
|
243
|
+
function isIdentifierPart(ch) {
|
|
244
|
+
return isIdentifierStart(ch) || isDigit(ch);
|
|
245
|
+
}
|
|
246
|
+
var Lexer = class {
|
|
247
|
+
input;
|
|
248
|
+
index = 0;
|
|
249
|
+
constructor(input) {
|
|
250
|
+
this.input = input;
|
|
251
|
+
}
|
|
252
|
+
tokenize() {
|
|
253
|
+
const tokens = [];
|
|
254
|
+
while (!this.isAtEnd()) {
|
|
255
|
+
const ch = this.peek();
|
|
256
|
+
if (isWhitespace(ch)) {
|
|
257
|
+
this.advance();
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (isDigit(ch)) {
|
|
261
|
+
tokens.push(this.readNumber());
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (isIdentifierStart(ch)) {
|
|
265
|
+
tokens.push(this.readIdentifier());
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (ch === '"' || ch === "'") {
|
|
269
|
+
tokens.push(this.readString());
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
tokens.push(this.readSymbol());
|
|
273
|
+
}
|
|
274
|
+
tokens.push({
|
|
275
|
+
type: "EOF" /* EOF */,
|
|
276
|
+
value: "",
|
|
277
|
+
span: { start: this.index, end: this.index }
|
|
278
|
+
});
|
|
279
|
+
return tokens;
|
|
280
|
+
}
|
|
281
|
+
readNumber() {
|
|
282
|
+
const start = this.index;
|
|
283
|
+
while (isDigit(this.peek())) {
|
|
284
|
+
this.advance();
|
|
285
|
+
}
|
|
286
|
+
if (this.peek() === "." && isDigit(this.peekNext())) {
|
|
287
|
+
this.advance();
|
|
288
|
+
while (isDigit(this.peek())) {
|
|
289
|
+
this.advance();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const value = this.input.slice(start, this.index);
|
|
293
|
+
return this.makeToken("Number" /* Number */, value, start, this.index);
|
|
294
|
+
}
|
|
295
|
+
readIdentifier() {
|
|
296
|
+
const start = this.index;
|
|
297
|
+
while (isIdentifierPart(this.peek())) {
|
|
298
|
+
this.advance();
|
|
299
|
+
}
|
|
300
|
+
const value = this.input.slice(start, this.index);
|
|
301
|
+
const keyword = KEYWORDS.get(value);
|
|
302
|
+
if (keyword) {
|
|
303
|
+
return this.makeToken(keyword, value, start, this.index);
|
|
304
|
+
}
|
|
305
|
+
return this.makeToken("Identifier" /* Identifier */, value, start, this.index);
|
|
306
|
+
}
|
|
307
|
+
readString() {
|
|
308
|
+
const start = this.index;
|
|
309
|
+
const quote = this.advance();
|
|
310
|
+
let value = "";
|
|
311
|
+
while (!this.isAtEnd()) {
|
|
312
|
+
const ch = this.advance();
|
|
313
|
+
if (ch === quote) {
|
|
314
|
+
return this.makeToken("String" /* String */, value, start, this.index);
|
|
315
|
+
}
|
|
316
|
+
if (ch === "\\") {
|
|
317
|
+
if (this.isAtEnd()) break;
|
|
318
|
+
const escaped = this.advance();
|
|
319
|
+
value += this.decodeEscape(escaped);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
value += ch;
|
|
323
|
+
}
|
|
324
|
+
throw new CompilerError("Unterminated string literal", { start, end: this.index });
|
|
325
|
+
}
|
|
326
|
+
readSymbol() {
|
|
327
|
+
const start = this.index;
|
|
328
|
+
const ch = this.advance();
|
|
329
|
+
if (ch === "+") return this.makeToken("Plus" /* Plus */, ch, start, this.index);
|
|
330
|
+
if (ch === "-") return this.makeToken("Minus" /* Minus */, ch, start, this.index);
|
|
331
|
+
if (ch === "*") return this.makeToken("Star" /* Star */, ch, start, this.index);
|
|
332
|
+
if (ch === "/") return this.makeToken("Slash" /* Slash */, ch, start, this.index);
|
|
333
|
+
if (ch === "%") return this.makeToken("Percent" /* Percent */, ch, start, this.index);
|
|
334
|
+
if (ch === "(") return this.makeToken("LeftParen" /* LeftParen */, ch, start, this.index);
|
|
335
|
+
if (ch === ")") return this.makeToken("RightParen" /* RightParen */, ch, start, this.index);
|
|
336
|
+
if (ch === "[") return this.makeToken("LeftBracket" /* LeftBracket */, ch, start, this.index);
|
|
337
|
+
if (ch === "]") return this.makeToken("RightBracket" /* RightBracket */, ch, start, this.index);
|
|
338
|
+
if (ch === ",") return this.makeToken("Comma" /* Comma */, ch, start, this.index);
|
|
339
|
+
if (ch === ".") return this.makeToken("Dot" /* Dot */, ch, start, this.index);
|
|
340
|
+
if (ch === "!") {
|
|
341
|
+
if (this.match("=")) {
|
|
342
|
+
return this.makeToken("BangEquals" /* BangEquals */, "!=", start, this.index);
|
|
343
|
+
}
|
|
344
|
+
return this.makeToken("Bang" /* Bang */, ch, start, this.index);
|
|
345
|
+
}
|
|
346
|
+
if (ch === "=") {
|
|
347
|
+
if (this.match("=")) {
|
|
348
|
+
return this.makeToken("EqualsEquals" /* EqualsEquals */, "==", start, this.index);
|
|
349
|
+
}
|
|
350
|
+
throw new CompilerError("Unexpected '='", { start, end: this.index });
|
|
351
|
+
}
|
|
352
|
+
if (ch === ">") {
|
|
353
|
+
if (this.match("=")) {
|
|
354
|
+
return this.makeToken("GreaterEqual" /* GreaterEqual */, ">=", start, this.index);
|
|
355
|
+
}
|
|
356
|
+
return this.makeToken("Greater" /* Greater */, ch, start, this.index);
|
|
357
|
+
}
|
|
358
|
+
if (ch === "<") {
|
|
359
|
+
if (this.match("=")) {
|
|
360
|
+
return this.makeToken("LessEqual" /* LessEqual */, "<=", start, this.index);
|
|
361
|
+
}
|
|
362
|
+
return this.makeToken("Less" /* Less */, ch, start, this.index);
|
|
363
|
+
}
|
|
364
|
+
if (ch === "&") {
|
|
365
|
+
if (this.match("&")) {
|
|
366
|
+
return this.makeToken("AndAnd" /* AndAnd */, "&&", start, this.index);
|
|
367
|
+
}
|
|
368
|
+
throw new CompilerError("Unexpected '&'", { start, end: this.index });
|
|
369
|
+
}
|
|
370
|
+
if (ch === "|") {
|
|
371
|
+
if (this.match("|")) {
|
|
372
|
+
return this.makeToken("OrOr" /* OrOr */, "||", start, this.index);
|
|
373
|
+
}
|
|
374
|
+
throw new CompilerError("Unexpected '|'", { start, end: this.index });
|
|
375
|
+
}
|
|
376
|
+
throw new CompilerError(`Unexpected character '${ch}'`, { start, end: this.index });
|
|
377
|
+
}
|
|
378
|
+
decodeEscape(ch) {
|
|
379
|
+
if (ch === "n") return "\n";
|
|
380
|
+
if (ch === "r") return "\r";
|
|
381
|
+
if (ch === "t") return " ";
|
|
382
|
+
if (ch === "\\") return "\\";
|
|
383
|
+
if (ch === '"') return '"';
|
|
384
|
+
if (ch === "'") return "'";
|
|
385
|
+
return ch;
|
|
386
|
+
}
|
|
387
|
+
makeToken(type, value, start, end) {
|
|
388
|
+
const span = { start, end };
|
|
389
|
+
return { type, value, span };
|
|
390
|
+
}
|
|
391
|
+
match(expected) {
|
|
392
|
+
if (this.peek() !== expected) return false;
|
|
393
|
+
this.advance();
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
peek() {
|
|
397
|
+
return this.input[this.index] ?? "";
|
|
398
|
+
}
|
|
399
|
+
peekNext() {
|
|
400
|
+
return this.input[this.index + 1] ?? "";
|
|
401
|
+
}
|
|
402
|
+
advance() {
|
|
403
|
+
const ch = this.input[this.index] ?? "";
|
|
404
|
+
this.index += 1;
|
|
405
|
+
return ch;
|
|
406
|
+
}
|
|
407
|
+
isAtEnd() {
|
|
408
|
+
return this.index >= this.input.length;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
function lex(input) {
|
|
412
|
+
const lexer = new Lexer(input);
|
|
413
|
+
return lexer.tokenize();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/compiler/parser.ts
|
|
417
|
+
var Parser = class {
|
|
418
|
+
tokens;
|
|
419
|
+
index = 0;
|
|
420
|
+
constructor(tokens) {
|
|
421
|
+
this.tokens = tokens;
|
|
422
|
+
}
|
|
423
|
+
parseExpression(precedence = 0 /* Lowest */) {
|
|
424
|
+
let left = this.parsePrefix();
|
|
425
|
+
while (!this.isAtEnd() && precedence < this.getPrecedence(this.peek())) {
|
|
426
|
+
left = this.parseInfix(left);
|
|
427
|
+
}
|
|
428
|
+
return left;
|
|
429
|
+
}
|
|
430
|
+
parsePrefix() {
|
|
431
|
+
const token = this.advance();
|
|
432
|
+
switch (token.type) {
|
|
433
|
+
case "Number" /* Number */: {
|
|
434
|
+
const value = Number(token.value);
|
|
435
|
+
if (Number.isNaN(value)) {
|
|
436
|
+
throw new CompilerError("Invalid number literal", token.span);
|
|
437
|
+
}
|
|
438
|
+
return { type: "Literal", value, span: token.span };
|
|
439
|
+
}
|
|
440
|
+
case "String" /* String */:
|
|
441
|
+
return { type: "Literal", value: token.value, span: token.span };
|
|
442
|
+
case "True" /* True */:
|
|
443
|
+
return { type: "Literal", value: true, span: token.span };
|
|
444
|
+
case "False" /* False */:
|
|
445
|
+
return { type: "Literal", value: false, span: token.span };
|
|
446
|
+
case "Null" /* Null */:
|
|
447
|
+
return { type: "Literal", value: null, span: token.span };
|
|
448
|
+
case "Identifier" /* Identifier */:
|
|
449
|
+
return { type: "Identifier", name: token.value, span: token.span };
|
|
450
|
+
case "Bang" /* Bang */:
|
|
451
|
+
case "Not" /* Not */:
|
|
452
|
+
case "Minus" /* Minus */: {
|
|
453
|
+
const operator = this.toUnaryOperator(token);
|
|
454
|
+
const argument = this.parseExpression(7 /* Unary */);
|
|
455
|
+
const span = this.mergeSpan(token.span, argument.span);
|
|
456
|
+
return { type: "Unary", operator, argument, span };
|
|
457
|
+
}
|
|
458
|
+
case "LeftParen" /* LeftParen */: {
|
|
459
|
+
const expression = this.parseExpression();
|
|
460
|
+
this.expect("RightParen" /* RightParen */, "Expected ')' after expression");
|
|
461
|
+
return expression;
|
|
462
|
+
}
|
|
463
|
+
case "LeftBracket" /* LeftBracket */:
|
|
464
|
+
return this.parseList(token.span);
|
|
465
|
+
default:
|
|
466
|
+
throw new CompilerError("Unexpected token", token.span);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
parseInfix(left) {
|
|
470
|
+
const token = this.peek();
|
|
471
|
+
if (token.type === "LeftParen" /* LeftParen */) {
|
|
472
|
+
this.advance();
|
|
473
|
+
return this.parseCall(left);
|
|
474
|
+
}
|
|
475
|
+
if (token.type === "Dot" /* Dot */) {
|
|
476
|
+
this.advance();
|
|
477
|
+
return this.parseMember(left);
|
|
478
|
+
}
|
|
479
|
+
if (token.type === "LeftBracket" /* LeftBracket */) {
|
|
480
|
+
this.advance();
|
|
481
|
+
return this.parseIndex(left);
|
|
482
|
+
}
|
|
483
|
+
const operator = this.toBinaryOperator(token);
|
|
484
|
+
const precedence = this.getPrecedence(token);
|
|
485
|
+
this.advance();
|
|
486
|
+
const right = this.parseExpression(precedence);
|
|
487
|
+
const span = this.mergeSpan(left.span, right.span);
|
|
488
|
+
return { type: "Binary", operator, left, right, span };
|
|
489
|
+
}
|
|
490
|
+
parseCall(callee) {
|
|
491
|
+
const args = [];
|
|
492
|
+
if (!this.check("RightParen" /* RightParen */)) {
|
|
493
|
+
do {
|
|
494
|
+
args.push(this.parseExpression());
|
|
495
|
+
} while (this.match("Comma" /* Comma */));
|
|
496
|
+
}
|
|
497
|
+
const endToken = this.expect("RightParen" /* RightParen */, "Expected ')' after arguments");
|
|
498
|
+
const span = this.mergeSpan(callee.span, endToken.span);
|
|
499
|
+
return { type: "Call", callee, args, span };
|
|
500
|
+
}
|
|
501
|
+
parseMember(object) {
|
|
502
|
+
const propertyToken = this.expect("Identifier" /* Identifier */, "Expected property name after '.'");
|
|
503
|
+
const span = this.mergeSpan(object.span, propertyToken.span);
|
|
504
|
+
return { type: "Member", object, property: propertyToken.value, span };
|
|
505
|
+
}
|
|
506
|
+
parseIndex(object) {
|
|
507
|
+
const index = this.parseExpression();
|
|
508
|
+
const endToken = this.expect("RightBracket" /* RightBracket */, "Expected ']' after index");
|
|
509
|
+
const span = this.mergeSpan(object.span, endToken.span);
|
|
510
|
+
return { type: "Index", object, index, span };
|
|
511
|
+
}
|
|
512
|
+
parseList(startSpan) {
|
|
513
|
+
const elements = [];
|
|
514
|
+
if (!this.check("RightBracket" /* RightBracket */)) {
|
|
515
|
+
do {
|
|
516
|
+
elements.push(this.parseExpression());
|
|
517
|
+
} while (this.match("Comma" /* Comma */));
|
|
518
|
+
}
|
|
519
|
+
const endToken = this.expect("RightBracket" /* RightBracket */, "Expected ']' after list");
|
|
520
|
+
const span = this.mergeSpan(startSpan, endToken.span);
|
|
521
|
+
return { type: "List", elements, span };
|
|
522
|
+
}
|
|
523
|
+
toUnaryOperator(token) {
|
|
524
|
+
if (token.type === "Bang" /* Bang */ || token.type === "Not" /* Not */) return "!";
|
|
525
|
+
if (token.type === "Minus" /* Minus */) return "-";
|
|
526
|
+
throw new CompilerError("Unsupported unary operator", token.span);
|
|
527
|
+
}
|
|
528
|
+
toBinaryOperator(token) {
|
|
529
|
+
switch (token.type) {
|
|
530
|
+
case "Plus" /* Plus */:
|
|
531
|
+
return "+";
|
|
532
|
+
case "Minus" /* Minus */:
|
|
533
|
+
return "-";
|
|
534
|
+
case "Star" /* Star */:
|
|
535
|
+
return "*";
|
|
536
|
+
case "Slash" /* Slash */:
|
|
537
|
+
return "/";
|
|
538
|
+
case "Percent" /* Percent */:
|
|
539
|
+
return "%";
|
|
540
|
+
case "EqualsEquals" /* EqualsEquals */:
|
|
541
|
+
return "==";
|
|
542
|
+
case "BangEquals" /* BangEquals */:
|
|
543
|
+
return "!=";
|
|
544
|
+
case "Greater" /* Greater */:
|
|
545
|
+
return ">";
|
|
546
|
+
case "GreaterEqual" /* GreaterEqual */:
|
|
547
|
+
return ">=";
|
|
548
|
+
case "Less" /* Less */:
|
|
549
|
+
return "<";
|
|
550
|
+
case "LessEqual" /* LessEqual */:
|
|
551
|
+
return "<=";
|
|
552
|
+
case "AndAnd" /* AndAnd */:
|
|
553
|
+
case "And" /* And */:
|
|
554
|
+
return "&&";
|
|
555
|
+
case "OrOr" /* OrOr */:
|
|
556
|
+
case "Or" /* Or */:
|
|
557
|
+
return "||";
|
|
558
|
+
default:
|
|
559
|
+
throw new CompilerError("Unsupported binary operator", token.span);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
getPrecedence(token) {
|
|
563
|
+
switch (token.type) {
|
|
564
|
+
case "OrOr" /* OrOr */:
|
|
565
|
+
case "Or" /* Or */:
|
|
566
|
+
return 1 /* Or */;
|
|
567
|
+
case "AndAnd" /* AndAnd */:
|
|
568
|
+
case "And" /* And */:
|
|
569
|
+
return 2 /* And */;
|
|
570
|
+
case "EqualsEquals" /* EqualsEquals */:
|
|
571
|
+
case "BangEquals" /* BangEquals */:
|
|
572
|
+
return 3 /* Equality */;
|
|
573
|
+
case "Greater" /* Greater */:
|
|
574
|
+
case "GreaterEqual" /* GreaterEqual */:
|
|
575
|
+
case "Less" /* Less */:
|
|
576
|
+
case "LessEqual" /* LessEqual */:
|
|
577
|
+
return 4 /* Comparison */;
|
|
578
|
+
case "Plus" /* Plus */:
|
|
579
|
+
case "Minus" /* Minus */:
|
|
580
|
+
return 5 /* Term */;
|
|
581
|
+
case "Star" /* Star */:
|
|
582
|
+
case "Slash" /* Slash */:
|
|
583
|
+
case "Percent" /* Percent */:
|
|
584
|
+
return 6 /* Factor */;
|
|
585
|
+
case "LeftParen" /* LeftParen */:
|
|
586
|
+
case "LeftBracket" /* LeftBracket */:
|
|
587
|
+
case "Dot" /* Dot */:
|
|
588
|
+
return 8 /* Call */;
|
|
589
|
+
default:
|
|
590
|
+
return 0 /* Lowest */;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
mergeSpan(start, end) {
|
|
594
|
+
return { start: start.start, end: end.end };
|
|
595
|
+
}
|
|
596
|
+
check(type) {
|
|
597
|
+
return this.peek().type === type;
|
|
598
|
+
}
|
|
599
|
+
match(type) {
|
|
600
|
+
if (!this.check(type)) return false;
|
|
601
|
+
this.advance();
|
|
602
|
+
return true;
|
|
603
|
+
}
|
|
604
|
+
expect(type, message) {
|
|
605
|
+
const token = this.peek();
|
|
606
|
+
if (token.type === type) {
|
|
607
|
+
return this.advance();
|
|
608
|
+
}
|
|
609
|
+
throw new CompilerError(message, token.span);
|
|
610
|
+
}
|
|
611
|
+
advance() {
|
|
612
|
+
const token = this.peek();
|
|
613
|
+
this.index += 1;
|
|
614
|
+
return token;
|
|
615
|
+
}
|
|
616
|
+
peek() {
|
|
617
|
+
return this.tokens[this.index] ?? this.tokens[this.tokens.length - 1] ?? {
|
|
618
|
+
type: "EOF" /* EOF */,
|
|
619
|
+
value: "",
|
|
620
|
+
span: { start: 0, end: 0 }
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
isAtEnd() {
|
|
624
|
+
return this.peek().type === "EOF" /* EOF */;
|
|
625
|
+
}
|
|
626
|
+
finish() {
|
|
627
|
+
this.expect("EOF" /* EOF */, "Unexpected token after expression");
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
function parse(tokens) {
|
|
631
|
+
const parser = new Parser(tokens);
|
|
632
|
+
const expression = parser.parseExpression();
|
|
633
|
+
parser.finish();
|
|
634
|
+
return expression;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// node_modules/github-slugger/regex.js
|
|
638
|
+
var regex = /[\0-\x1F!-,\.\/:-@\[-\^`\{-\xA9\xAB-\xB4\xB6-\xB9\xBB-\xBF\xD7\xF7\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0378\u0379\u037E\u0380-\u0385\u0387\u038B\u038D\u03A2\u03F6\u0482\u0530\u0557\u0558\u055A-\u055F\u0589-\u0590\u05BE\u05C0\u05C3\u05C6\u05C8-\u05CF\u05EB-\u05EE\u05F3-\u060F\u061B-\u061F\u066A-\u066D\u06D4\u06DD\u06DE\u06E9\u06FD\u06FE\u0700-\u070F\u074B\u074C\u07B2-\u07BF\u07F6-\u07F9\u07FB\u07FC\u07FE\u07FF\u082E-\u083F\u085C-\u085F\u086B-\u089F\u08B5\u08C8-\u08D2\u08E2\u0964\u0965\u0970\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09F2-\u09FB\u09FD\u09FF\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF0-\u0AF8\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B54\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B70\u0B72-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BF0-\u0BFF\u0C0D\u0C11\u0C29\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5B-\u0C5F\u0C64\u0C65\u0C70-\u0C7F\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0CFF\u0D0D\u0D11\u0D45\u0D49\u0D4F-\u0D53\u0D58-\u0D5E\u0D64\u0D65\u0D70-\u0D79\u0D80\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DE5\u0DF0\u0DF1\u0DF4-\u0E00\u0E3B-\u0E3F\u0E4F\u0E5A-\u0E80\u0E83\u0E85\u0E8B\u0EA4\u0EA6\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F01-\u0F17\u0F1A-\u0F1F\u0F2A-\u0F34\u0F36\u0F38\u0F3A-\u0F3D\u0F48\u0F6D-\u0F70\u0F85\u0F98\u0FBD-\u0FC5\u0FC7-\u0FFF\u104A-\u104F\u109E\u109F\u10C6\u10C8-\u10CC\u10CE\u10CF\u10FB\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u1360-\u137F\u1390-\u139F\u13F6\u13F7\u13FE-\u1400\u166D\u166E\u1680\u169B-\u169F\u16EB-\u16ED\u16F9-\u16FF\u170D\u1715-\u171F\u1735-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17D4-\u17D6\u17D8-\u17DB\u17DE\u17DF\u17EA-\u180A\u180E\u180F\u181A-\u181F\u1879-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191F\u192C-\u192F\u193C-\u1945\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DA-\u19FF\u1A1C-\u1A1F\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1AA6\u1AA8-\u1AAF\u1AC1-\u1AFF\u1B4C-\u1B4F\u1B5A-\u1B6A\u1B74-\u1B7F\u1BF4-\u1BFF\u1C38-\u1C3F\u1C4A-\u1C4C\u1C7E\u1C7F\u1C89-\u1C8F\u1CBB\u1CBC\u1CC0-\u1CCF\u1CD3\u1CFB-\u1CFF\u1DFA\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FBD\u1FBF-\u1FC1\u1FC5\u1FCD-\u1FCF\u1FD4\u1FD5\u1FDC-\u1FDF\u1FED-\u1FF1\u1FF5\u1FFD-\u203E\u2041-\u2053\u2055-\u2070\u2072-\u207E\u2080-\u208F\u209D-\u20CF\u20F1-\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u2140-\u2144\u214A-\u214D\u214F-\u215F\u2189-\u24B5\u24EA-\u2BFF\u2C2F\u2C5F\u2CE5-\u2CEA\u2CF4-\u2CFF\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D70-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E00-\u2E2E\u2E30-\u3004\u3008-\u3020\u3030\u3036\u3037\u303D-\u3040\u3097\u3098\u309B\u309C\u30A0\u30FB\u3100-\u3104\u3130\u318F-\u319F\u31C0-\u31EF\u3200-\u33FF\u4DC0-\u4DFF\u9FFD-\u9FFF\uA48D-\uA4CF\uA4FE\uA4FF\uA60D-\uA60F\uA62C-\uA63F\uA673\uA67E\uA6F2-\uA716\uA720\uA721\uA789\uA78A\uA7C0\uA7C1\uA7CB-\uA7F4\uA828-\uA82B\uA82D-\uA83F\uA874-\uA87F\uA8C6-\uA8CF\uA8DA-\uA8DF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA954-\uA95F\uA97D-\uA97F\uA9C1-\uA9CE\uA9DA-\uA9DF\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A-\uAA5F\uAA77-\uAA79\uAAC3-\uAADA\uAADE\uAADF\uAAF0\uAAF1\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F\uAB5B\uAB6A-\uAB6F\uABEB\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB29\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBB2-\uFBD2\uFD3E-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFC-\uFDFF\uFE10-\uFE1F\uFE30-\uFE32\uFE35-\uFE4C\uFE50-\uFE6F\uFE75\uFEFD-\uFF0F\uFF1A-\uFF20\uFF3B-\uFF3E\uFF40\uFF5B-\uFF65\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFFF]|\uD800[\uDC0C\uDC27\uDC3B\uDC3E\uDC4E\uDC4F\uDC5E-\uDC7F\uDCFB-\uDD3F\uDD75-\uDDFC\uDDFE-\uDE7F\uDE9D-\uDE9F\uDED1-\uDEDF\uDEE1-\uDEFF\uDF20-\uDF2C\uDF4B-\uDF4F\uDF7B-\uDF7F\uDF9E\uDF9F\uDFC4-\uDFC7\uDFD0\uDFD6-\uDFFF]|\uD801[\uDC9E\uDC9F\uDCAA-\uDCAF\uDCD4-\uDCD7\uDCFC-\uDCFF\uDD28-\uDD2F\uDD64-\uDDFF\uDF37-\uDF3F\uDF56-\uDF5F\uDF68-\uDFFF]|\uD802[\uDC06\uDC07\uDC09\uDC36\uDC39-\uDC3B\uDC3D\uDC3E\uDC56-\uDC5F\uDC77-\uDC7F\uDC9F-\uDCDF\uDCF3\uDCF6-\uDCFF\uDD16-\uDD1F\uDD3A-\uDD7F\uDDB8-\uDDBD\uDDC0-\uDDFF\uDE04\uDE07-\uDE0B\uDE14\uDE18\uDE36\uDE37\uDE3B-\uDE3E\uDE40-\uDE5F\uDE7D-\uDE7F\uDE9D-\uDEBF\uDEC8\uDEE7-\uDEFF\uDF36-\uDF3F\uDF56-\uDF5F\uDF73-\uDF7F\uDF92-\uDFFF]|\uD803[\uDC49-\uDC7F\uDCB3-\uDCBF\uDCF3-\uDCFF\uDD28-\uDD2F\uDD3A-\uDE7F\uDEAA\uDEAD-\uDEAF\uDEB2-\uDEFF\uDF1D-\uDF26\uDF28-\uDF2F\uDF51-\uDFAF\uDFC5-\uDFDF\uDFF7-\uDFFF]|\uD804[\uDC47-\uDC65\uDC70-\uDC7E\uDCBB-\uDCCF\uDCE9-\uDCEF\uDCFA-\uDCFF\uDD35\uDD40-\uDD43\uDD48-\uDD4F\uDD74\uDD75\uDD77-\uDD7F\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDFF\uDE12\uDE38-\uDE3D\uDE3F-\uDE7F\uDE87\uDE89\uDE8E\uDE9E\uDEA9-\uDEAF\uDEEB-\uDEEF\uDEFA-\uDEFF\uDF04\uDF0D\uDF0E\uDF11\uDF12\uDF29\uDF31\uDF34\uDF3A\uDF45\uDF46\uDF49\uDF4A\uDF4E\uDF4F\uDF51-\uDF56\uDF58-\uDF5C\uDF64\uDF65\uDF6D-\uDF6F\uDF75-\uDFFF]|\uD805[\uDC4B-\uDC4F\uDC5A-\uDC5D\uDC62-\uDC7F\uDCC6\uDCC8-\uDCCF\uDCDA-\uDD7F\uDDB6\uDDB7\uDDC1-\uDDD7\uDDDE-\uDDFF\uDE41-\uDE43\uDE45-\uDE4F\uDE5A-\uDE7F\uDEB9-\uDEBF\uDECA-\uDEFF\uDF1B\uDF1C\uDF2C-\uDF2F\uDF3A-\uDFFF]|\uD806[\uDC3B-\uDC9F\uDCEA-\uDCFE\uDD07\uDD08\uDD0A\uDD0B\uDD14\uDD17\uDD36\uDD39\uDD3A\uDD44-\uDD4F\uDD5A-\uDD9F\uDDA8\uDDA9\uDDD8\uDDD9\uDDE2\uDDE5-\uDDFF\uDE3F-\uDE46\uDE48-\uDE4F\uDE9A-\uDE9C\uDE9E-\uDEBF\uDEF9-\uDFFF]|\uD807[\uDC09\uDC37\uDC41-\uDC4F\uDC5A-\uDC71\uDC90\uDC91\uDCA8\uDCB7-\uDCFF\uDD07\uDD0A\uDD37-\uDD39\uDD3B\uDD3E\uDD48-\uDD4F\uDD5A-\uDD5F\uDD66\uDD69\uDD8F\uDD92\uDD99-\uDD9F\uDDAA-\uDEDF\uDEF7-\uDFAF\uDFB1-\uDFFF]|\uD808[\uDF9A-\uDFFF]|\uD809[\uDC6F-\uDC7F\uDD44-\uDFFF]|[\uD80A\uD80B\uD80E-\uD810\uD812-\uD819\uD824-\uD82B\uD82D\uD82E\uD830-\uD833\uD837\uD839\uD83D\uD83F\uD87B-\uD87D\uD87F\uD885-\uDB3F\uDB41-\uDBFF][\uDC00-\uDFFF]|\uD80D[\uDC2F-\uDFFF]|\uD811[\uDE47-\uDFFF]|\uD81A[\uDE39-\uDE3F\uDE5F\uDE6A-\uDECF\uDEEE\uDEEF\uDEF5-\uDEFF\uDF37-\uDF3F\uDF44-\uDF4F\uDF5A-\uDF62\uDF78-\uDF7C\uDF90-\uDFFF]|\uD81B[\uDC00-\uDE3F\uDE80-\uDEFF\uDF4B-\uDF4E\uDF88-\uDF8E\uDFA0-\uDFDF\uDFE2\uDFE5-\uDFEF\uDFF2-\uDFFF]|\uD821[\uDFF8-\uDFFF]|\uD823[\uDCD6-\uDCFF\uDD09-\uDFFF]|\uD82C[\uDD1F-\uDD4F\uDD53-\uDD63\uDD68-\uDD6F\uDEFC-\uDFFF]|\uD82F[\uDC6B-\uDC6F\uDC7D-\uDC7F\uDC89-\uDC8F\uDC9A-\uDC9C\uDC9F-\uDFFF]|\uD834[\uDC00-\uDD64\uDD6A-\uDD6C\uDD73-\uDD7A\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDE41\uDE45-\uDFFF]|\uD835[\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDEC1\uDEDB\uDEFB\uDF15\uDF35\uDF4F\uDF6F\uDF89\uDFA9\uDFC3\uDFCC\uDFCD]|\uD836[\uDC00-\uDDFF\uDE37-\uDE3A\uDE6D-\uDE74\uDE76-\uDE83\uDE85-\uDE9A\uDEA0\uDEB0-\uDFFF]|\uD838[\uDC07\uDC19\uDC1A\uDC22\uDC25\uDC2B-\uDCFF\uDD2D-\uDD2F\uDD3E\uDD3F\uDD4A-\uDD4D\uDD4F-\uDEBF\uDEFA-\uDFFF]|\uD83A[\uDCC5-\uDCCF\uDCD7-\uDCFF\uDD4C-\uDD4F\uDD5A-\uDFFF]|\uD83B[\uDC00-\uDDFF\uDE04\uDE20\uDE23\uDE25\uDE26\uDE28\uDE33\uDE38\uDE3A\uDE3C-\uDE41\uDE43-\uDE46\uDE48\uDE4A\uDE4C\uDE50\uDE53\uDE55\uDE56\uDE58\uDE5A\uDE5C\uDE5E\uDE60\uDE63\uDE65\uDE66\uDE6B\uDE73\uDE78\uDE7D\uDE7F\uDE8A\uDE9C-\uDEA0\uDEA4\uDEAA\uDEBC-\uDFFF]|\uD83C[\uDC00-\uDD2F\uDD4A-\uDD4F\uDD6A-\uDD6F\uDD8A-\uDFFF]|\uD83E[\uDC00-\uDFEF\uDFFA-\uDFFF]|\uD869[\uDEDE-\uDEFF]|\uD86D[\uDF35-\uDF3F]|\uD86E[\uDC1E\uDC1F]|\uD873[\uDEA2-\uDEAF]|\uD87A[\uDFE1-\uDFFF]|\uD87E[\uDE1E-\uDFFF]|\uD884[\uDF4B-\uDFFF]|\uDB40[\uDC00-\uDCFF\uDDF0-\uDFFF]/g;
|
|
639
|
+
function slug(value, maintainCase) {
|
|
640
|
+
if (typeof value !== "string") return "";
|
|
641
|
+
value = value.toLowerCase();
|
|
642
|
+
return value.replace(regex, "").replace(/ /g, "-");
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// node_modules/preact/dist/preact.mjs
|
|
646
|
+
var n;
|
|
647
|
+
var l;
|
|
648
|
+
var u;
|
|
649
|
+
var w = [];
|
|
650
|
+
function k(l2, u3, t2) {
|
|
651
|
+
var i2, r2, o2, e2 = {};
|
|
652
|
+
for (o2 in u3) "key" == o2 ? i2 = u3[o2] : "ref" == o2 ? r2 = u3[o2] : e2[o2] = u3[o2];
|
|
653
|
+
if (arguments.length > 2 && (e2.children = arguments.length > 3 ? n.call(arguments, 2) : t2), "function" == typeof l2 && null != l2.defaultProps) for (o2 in l2.defaultProps) void 0 === e2[o2] && (e2[o2] = l2.defaultProps[o2]);
|
|
654
|
+
return x(l2, e2, i2, r2, null);
|
|
655
|
+
}
|
|
656
|
+
function x(n2, t2, i2, r2, o2) {
|
|
657
|
+
var e2 = { type: n2, props: t2, key: i2, ref: r2, __k: null, __: null, __b: 0, __e: null, __c: null, constructor: void 0, __v: null == o2 ? ++u : o2, __i: -1, __u: 0 };
|
|
658
|
+
return null != l.vnode && l.vnode(e2), e2;
|
|
659
|
+
}
|
|
660
|
+
function S(n2) {
|
|
661
|
+
return n2.children;
|
|
662
|
+
}
|
|
663
|
+
n = w.slice, l = { __e: function(n2, l2, u3, t2) {
|
|
664
|
+
for (var i2, r2, o2; l2 = l2.__; ) if ((i2 = l2.__c) && !i2.__) try {
|
|
665
|
+
if ((r2 = i2.constructor) && null != r2.getDerivedStateFromError && (i2.setState(r2.getDerivedStateFromError(n2)), o2 = i2.__d), null != i2.componentDidCatch && (i2.componentDidCatch(n2, t2 || {}), o2 = i2.__d), o2) return i2.__E = i2;
|
|
666
|
+
} catch (l3) {
|
|
667
|
+
n2 = l3;
|
|
668
|
+
}
|
|
669
|
+
throw n2;
|
|
670
|
+
} }, u = 0, "function" == typeof Promise ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout, Math.random().toString(8);
|
|
671
|
+
|
|
672
|
+
// node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
|
|
673
|
+
var f2 = 0;
|
|
674
|
+
function u2(e2, t2, n2, o2, i2, u3) {
|
|
675
|
+
t2 || (t2 = {});
|
|
676
|
+
var a2, c2, p2 = t2;
|
|
677
|
+
if ("ref" in p2) for (c2 in p2 = {}, t2) "ref" == c2 ? a2 = t2[c2] : p2[c2] = t2[c2];
|
|
678
|
+
var l2 = { type: e2, props: p2, key: n2, ref: a2, __k: null, __: null, __b: 0, __e: null, __c: null, constructor: void 0, __v: --f2, __i: -1, __u: 0, __source: i2, __self: u3 };
|
|
679
|
+
if ("function" == typeof e2 && (a2 = e2.defaultProps)) for (c2 in a2) void 0 === p2[c2] && (p2[c2] = a2[c2]);
|
|
680
|
+
return l.vnode && l.vnode(l2), l2;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// node_modules/@quartz-community/utils/dist/index.js
|
|
684
|
+
function simplifySlug(fp) {
|
|
685
|
+
const res = stripSlashes(trimSuffix(fp, "index"), true);
|
|
686
|
+
return res.length === 0 ? "/" : res;
|
|
687
|
+
}
|
|
688
|
+
function slugifyFilePath(fp, excludeExt) {
|
|
689
|
+
fp = stripSlashes(fp);
|
|
690
|
+
const ext = getFileExtension(fp);
|
|
691
|
+
const withoutFileExt = fp.replace(new RegExp(ext + "$"), "");
|
|
692
|
+
const finalExt = excludeExt || [".md", ".html", void 0].includes(ext) ? "" : ext;
|
|
693
|
+
let slug2 = _sluggify(withoutFileExt);
|
|
694
|
+
if (endsWith(slug2, "_index")) {
|
|
695
|
+
slug2 = slug2.replace(/_index$/, "index");
|
|
696
|
+
}
|
|
697
|
+
const segments = slug2.split("/");
|
|
698
|
+
if (segments.length >= 2 && segments[segments.length - 1] === segments[segments.length - 2]) {
|
|
699
|
+
segments[segments.length - 1] = "index";
|
|
700
|
+
slug2 = segments.join("/");
|
|
701
|
+
}
|
|
702
|
+
return slug2 + (finalExt ?? "");
|
|
703
|
+
}
|
|
704
|
+
function joinSegments(...args) {
|
|
705
|
+
if (args.length === 0) {
|
|
706
|
+
return "";
|
|
707
|
+
}
|
|
708
|
+
let joined = args.filter((segment) => segment !== "" && segment !== "/").map((segment) => stripSlashes(segment)).join("/");
|
|
709
|
+
const first = args[0];
|
|
710
|
+
const last = args[args.length - 1];
|
|
711
|
+
if (first?.startsWith("/")) {
|
|
712
|
+
joined = "/" + joined;
|
|
713
|
+
}
|
|
714
|
+
if (last?.endsWith("/")) {
|
|
715
|
+
joined = joined + "/";
|
|
716
|
+
}
|
|
717
|
+
return joined;
|
|
718
|
+
}
|
|
719
|
+
function endsWith(s2, suffix) {
|
|
720
|
+
return s2 === suffix || s2.endsWith("/" + suffix);
|
|
721
|
+
}
|
|
722
|
+
function trimSuffix(s2, suffix) {
|
|
723
|
+
if (endsWith(s2, suffix)) {
|
|
724
|
+
s2 = s2.slice(0, -suffix.length);
|
|
725
|
+
}
|
|
726
|
+
return s2;
|
|
727
|
+
}
|
|
728
|
+
function stripSlashes(s2, onlyStripPrefix) {
|
|
729
|
+
if (s2.startsWith("/")) {
|
|
730
|
+
s2 = s2.substring(1);
|
|
731
|
+
}
|
|
732
|
+
if (!onlyStripPrefix && s2.endsWith("/")) {
|
|
733
|
+
s2 = s2.slice(0, -1);
|
|
734
|
+
}
|
|
735
|
+
return s2;
|
|
736
|
+
}
|
|
737
|
+
function getFileExtension(s2) {
|
|
738
|
+
return s2.match(/\.[A-Za-z0-9]+$/)?.[0];
|
|
739
|
+
}
|
|
740
|
+
function isFolderPath(fplike) {
|
|
741
|
+
return fplike.endsWith("/") || endsWith(fplike, "index") || endsWith(fplike, "index.md") || endsWith(fplike, "index.html");
|
|
742
|
+
}
|
|
743
|
+
function pathToRoot(slug2) {
|
|
744
|
+
let rootPath = slug2.split("/").filter((x2) => x2 !== "").slice(0, -1).map((_2) => "..").join("/");
|
|
745
|
+
if (rootPath.length === 0) {
|
|
746
|
+
rootPath = ".";
|
|
747
|
+
}
|
|
748
|
+
return rootPath;
|
|
749
|
+
}
|
|
750
|
+
function resolveRelative(current, target) {
|
|
751
|
+
const res = joinSegments(pathToRoot(current), simplifySlug(target));
|
|
752
|
+
return res;
|
|
753
|
+
}
|
|
754
|
+
function splitAnchor(link) {
|
|
755
|
+
const [fp, anchor] = link.split("#", 2);
|
|
756
|
+
if (fp.endsWith(".pdf")) {
|
|
757
|
+
return [fp, anchor === void 0 ? "" : `#${anchor}`];
|
|
758
|
+
}
|
|
759
|
+
if (anchor === void 0) {
|
|
760
|
+
return [fp, ""];
|
|
761
|
+
}
|
|
762
|
+
const bare = anchor.startsWith("^") ? anchor.slice(1) : anchor;
|
|
763
|
+
const slugged = "#" + slug(bare);
|
|
764
|
+
return [fp, slugged];
|
|
765
|
+
}
|
|
766
|
+
function transformInternalLink(link) {
|
|
767
|
+
const [fplike, anchor] = splitAnchor(decodeURI(link));
|
|
768
|
+
const segments = fplike.split("/").filter((x2) => x2.length > 0);
|
|
769
|
+
const prefix = segments.filter(_isRelativeSegment).join("/");
|
|
770
|
+
const fp = segments.filter((seg) => !_isRelativeSegment(seg) && seg !== "").join("/");
|
|
771
|
+
const slugged = slugifyFilePath(fp);
|
|
772
|
+
const simpleSlug = simplifySlug(slugged);
|
|
773
|
+
const folderPath = isFolderPath(fplike) || isFolderPath(slugged);
|
|
774
|
+
const joined = joinSegments(stripSlashes(prefix), stripSlashes(simpleSlug));
|
|
775
|
+
const trail = folderPath ? "/" : "";
|
|
776
|
+
const res = _addRelativeToStart(joined) + trail + anchor;
|
|
777
|
+
return res;
|
|
778
|
+
}
|
|
779
|
+
function transformLink(src, target, opts) {
|
|
780
|
+
const targetSlug = transformInternalLink(target);
|
|
781
|
+
if (opts.strategy === "relative") {
|
|
782
|
+
return targetSlug;
|
|
783
|
+
} else {
|
|
784
|
+
const effectiveSrc = !endsWith(src, "index") && opts.allSlugs.includes(`${src}/index`) ? `${src}/index` : src;
|
|
785
|
+
const folderTail = isFolderPath(targetSlug) ? "/" : "";
|
|
786
|
+
const canonicalSlug = stripSlashes(targetSlug.slice(".".length));
|
|
787
|
+
const [targetCanonical, targetAnchor] = splitAnchor(canonicalSlug);
|
|
788
|
+
if (opts.strategy === "shortest") {
|
|
789
|
+
const isMultiSegment = targetCanonical.includes("/");
|
|
790
|
+
const isFolderTarget = isFolderPath(targetSlug);
|
|
791
|
+
const matchingFileNames = opts.allSlugs.filter((slug2) => {
|
|
792
|
+
if (isMultiSegment) {
|
|
793
|
+
if (slug2 === targetCanonical || slug2.endsWith("/" + targetCanonical)) {
|
|
794
|
+
return true;
|
|
795
|
+
}
|
|
796
|
+
if (isFolderTarget) {
|
|
797
|
+
const withIndex = targetCanonical + "/index";
|
|
798
|
+
return slug2 === withIndex || slug2.endsWith("/" + withIndex);
|
|
799
|
+
}
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
const parts = slug2.split("/");
|
|
803
|
+
const fileName = parts.at(-1);
|
|
804
|
+
return targetCanonical === fileName;
|
|
805
|
+
});
|
|
806
|
+
if (matchingFileNames.length === 1) {
|
|
807
|
+
const matchedSlug = matchingFileNames[0];
|
|
808
|
+
return resolveRelative(effectiveSrc, matchedSlug) + targetAnchor;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return joinSegments(pathToRoot(effectiveSrc), canonicalSlug) + folderTail;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
function slugifyPath(s2) {
|
|
815
|
+
return s2.split("/").map(
|
|
816
|
+
(segment) => segment.replace(/\s/g, "-").replace(/&/g, "-and-").replace(/%/g, "-percent").replace(/\?/g, "").replace(/#/g, "").replace(/[<>:"|*]/g, "").toLowerCase()
|
|
817
|
+
).join("/").replace(/\/$/, "");
|
|
818
|
+
}
|
|
819
|
+
function _sluggify(s2) {
|
|
820
|
+
return slugifyPath(s2);
|
|
821
|
+
}
|
|
822
|
+
function _isRelativeSegment(s2) {
|
|
823
|
+
return /^\.{0,2}$/.test(s2);
|
|
824
|
+
}
|
|
825
|
+
function _addRelativeToStart(s2) {
|
|
826
|
+
if (s2 === "") {
|
|
827
|
+
s2 = ".";
|
|
828
|
+
}
|
|
829
|
+
if (!s2.startsWith(".")) {
|
|
830
|
+
s2 = joinSegments(".", s2);
|
|
831
|
+
}
|
|
832
|
+
return s2;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// src/compiler/functions.ts
|
|
836
|
+
var globalFunctions = /* @__PURE__ */ new Map();
|
|
837
|
+
var methodFunctions = /* @__PURE__ */ new Map();
|
|
838
|
+
function getGlobalFunction(name) {
|
|
839
|
+
return globalFunctions.get(name);
|
|
840
|
+
}
|
|
841
|
+
function getMethodFunction(name, target) {
|
|
842
|
+
const category = getMethodTarget(target);
|
|
843
|
+
if (!category) return void 0;
|
|
844
|
+
return methodFunctions.get(category)?.get(name);
|
|
845
|
+
}
|
|
846
|
+
function registerGlobalFunction(name, fn) {
|
|
847
|
+
globalFunctions.set(name, fn);
|
|
848
|
+
}
|
|
849
|
+
function registerMethodFunction(target, name, fn) {
|
|
850
|
+
const group = methodFunctions.get(target) ?? /* @__PURE__ */ new Map();
|
|
851
|
+
group.set(name, fn);
|
|
852
|
+
methodFunctions.set(target, group);
|
|
853
|
+
}
|
|
854
|
+
function isRecord(value) {
|
|
855
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
856
|
+
}
|
|
857
|
+
function toStringValue(value) {
|
|
858
|
+
if (value === void 0 || value === null) return "";
|
|
859
|
+
return String(value);
|
|
860
|
+
}
|
|
861
|
+
function toNumber(value) {
|
|
862
|
+
if (typeof value === "number" && !Number.isNaN(value)) return value;
|
|
863
|
+
if (typeof value === "string") {
|
|
864
|
+
const parsed = Number(value);
|
|
865
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
866
|
+
}
|
|
867
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
function toInteger(value, fallback) {
|
|
871
|
+
const numberValue = toNumber(value);
|
|
872
|
+
if (numberValue === null) return fallback;
|
|
873
|
+
return Math.trunc(numberValue);
|
|
874
|
+
}
|
|
875
|
+
function roundTo(value, decimals) {
|
|
876
|
+
const factor = 10 ** decimals;
|
|
877
|
+
return Math.round(value * factor) / factor;
|
|
878
|
+
}
|
|
879
|
+
function flattenArgs(args) {
|
|
880
|
+
if (args.length === 1 && Array.isArray(args[0])) return args[0];
|
|
881
|
+
return args;
|
|
882
|
+
}
|
|
883
|
+
function collectNumericArgs(args) {
|
|
884
|
+
const values = flattenArgs(args);
|
|
885
|
+
const numbers = [];
|
|
886
|
+
for (const value of values) {
|
|
887
|
+
const numberValue = toNumber(value);
|
|
888
|
+
if (numberValue !== null) numbers.push(numberValue);
|
|
889
|
+
}
|
|
890
|
+
return numbers;
|
|
891
|
+
}
|
|
892
|
+
function isFileValue(value) {
|
|
893
|
+
if (!isRecord(value)) return false;
|
|
894
|
+
return typeof value.name === "string" && typeof value.path === "string" && typeof value.folder === "string" && typeof value.ext === "string" && Array.isArray(value.tags) && Array.isArray(value.links) && typeof value.basename === "string";
|
|
895
|
+
}
|
|
896
|
+
function resolveSelfName(value) {
|
|
897
|
+
if (!isRecord(value)) return null;
|
|
898
|
+
if (isRecord(value.file) && typeof value.file.name === "string") {
|
|
899
|
+
return value.file.name;
|
|
900
|
+
}
|
|
901
|
+
if (typeof value.name === "string" && typeof value.path === "string") {
|
|
902
|
+
return value.basename || value.name;
|
|
903
|
+
}
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
function resolveSelfPath(value) {
|
|
907
|
+
if (!isRecord(value)) return null;
|
|
908
|
+
if (isRecord(value.file) && typeof value.file.path === "string") {
|
|
909
|
+
return value.file.path;
|
|
910
|
+
}
|
|
911
|
+
if (typeof value.path === "string") {
|
|
912
|
+
return value.path;
|
|
913
|
+
}
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
function listContainsName(list, name, selfPath) {
|
|
917
|
+
const slugName = slugifyPath(name);
|
|
918
|
+
const selfSlug = selfPath ? slugifyFilePath(selfPath) : null;
|
|
919
|
+
return list.some((item) => {
|
|
920
|
+
if (typeof item !== "string") return false;
|
|
921
|
+
const match = item.match(/^\[\[([^\]|]+)(?:\|[^\]]+)?\]\]$/);
|
|
922
|
+
if (match?.[1]) {
|
|
923
|
+
return match[1] === name || match[1].endsWith(`/${name}`);
|
|
924
|
+
}
|
|
925
|
+
if (item === name) return true;
|
|
926
|
+
if (item === slugName || item.endsWith(`/${slugName}`)) return true;
|
|
927
|
+
if (selfSlug && (item === selfSlug || selfSlug.endsWith(`/${item}`) || item.endsWith(`/${selfSlug}`)))
|
|
928
|
+
return true;
|
|
929
|
+
return false;
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
function isDateValue(value) {
|
|
933
|
+
return value instanceof Date;
|
|
934
|
+
}
|
|
935
|
+
function isAlpha2(ch) {
|
|
936
|
+
if (!ch) return false;
|
|
937
|
+
const code = ch.charCodeAt(0);
|
|
938
|
+
return code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
939
|
+
}
|
|
940
|
+
function isDigit2(ch) {
|
|
941
|
+
if (!ch) return false;
|
|
942
|
+
const code = ch.charCodeAt(0);
|
|
943
|
+
return code >= 48 && code <= 57;
|
|
944
|
+
}
|
|
945
|
+
function parseDuration(value) {
|
|
946
|
+
const trimmed = value.trim();
|
|
947
|
+
if (!trimmed) return void 0;
|
|
948
|
+
const multipliers = {
|
|
949
|
+
ms: 1,
|
|
950
|
+
millisecond: 1,
|
|
951
|
+
milliseconds: 1,
|
|
952
|
+
s: 1e3,
|
|
953
|
+
sec: 1e3,
|
|
954
|
+
second: 1e3,
|
|
955
|
+
seconds: 1e3,
|
|
956
|
+
m: 6e4,
|
|
957
|
+
min: 6e4,
|
|
958
|
+
minute: 6e4,
|
|
959
|
+
minutes: 6e4,
|
|
960
|
+
h: 36e5,
|
|
961
|
+
hr: 36e5,
|
|
962
|
+
hour: 36e5,
|
|
963
|
+
hours: 36e5,
|
|
964
|
+
d: 864e5,
|
|
965
|
+
day: 864e5,
|
|
966
|
+
days: 864e5,
|
|
967
|
+
w: 6048e5,
|
|
968
|
+
week: 6048e5,
|
|
969
|
+
weeks: 6048e5,
|
|
970
|
+
mo: 2592e6,
|
|
971
|
+
month: 2592e6,
|
|
972
|
+
months: 2592e6,
|
|
973
|
+
y: 31536e6,
|
|
974
|
+
year: 31536e6,
|
|
975
|
+
years: 31536e6
|
|
976
|
+
};
|
|
977
|
+
let index = 0;
|
|
978
|
+
let total = 0;
|
|
979
|
+
while (index < trimmed.length) {
|
|
980
|
+
while (trimmed[index] === " " || trimmed[index] === " ") {
|
|
981
|
+
index += 1;
|
|
982
|
+
}
|
|
983
|
+
if (index >= trimmed.length) break;
|
|
984
|
+
const start = index;
|
|
985
|
+
let hasDot = false;
|
|
986
|
+
while (index < trimmed.length) {
|
|
987
|
+
const ch = trimmed[index] ?? "";
|
|
988
|
+
if (isDigit2(ch)) {
|
|
989
|
+
index += 1;
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
if (ch === "." && !hasDot) {
|
|
993
|
+
hasDot = true;
|
|
994
|
+
index += 1;
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
break;
|
|
998
|
+
}
|
|
999
|
+
if (start === index) return void 0;
|
|
1000
|
+
const amount = Number(trimmed.slice(start, index));
|
|
1001
|
+
if (Number.isNaN(amount)) return void 0;
|
|
1002
|
+
while (index < trimmed.length && (trimmed[index] === " " || trimmed[index] === " ")) {
|
|
1003
|
+
index += 1;
|
|
1004
|
+
}
|
|
1005
|
+
const unitStart = index;
|
|
1006
|
+
while (index < trimmed.length && isAlpha2(trimmed[index] ?? "")) {
|
|
1007
|
+
index += 1;
|
|
1008
|
+
}
|
|
1009
|
+
const unit = trimmed.slice(unitStart, index).toLowerCase();
|
|
1010
|
+
const multiplier = unit ? multipliers[unit] : 1;
|
|
1011
|
+
if (unit && multiplier === void 0) return void 0;
|
|
1012
|
+
total += amount * (multiplier ?? 1);
|
|
1013
|
+
}
|
|
1014
|
+
return total;
|
|
1015
|
+
}
|
|
1016
|
+
function parseDate(value) {
|
|
1017
|
+
if (value instanceof Date) return value;
|
|
1018
|
+
if (typeof value === "number") {
|
|
1019
|
+
const date = new Date(value);
|
|
1020
|
+
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
1021
|
+
}
|
|
1022
|
+
if (typeof value === "string") {
|
|
1023
|
+
const parsed = Date.parse(value);
|
|
1024
|
+
if (Number.isNaN(parsed)) return void 0;
|
|
1025
|
+
return new Date(parsed);
|
|
1026
|
+
}
|
|
1027
|
+
return void 0;
|
|
1028
|
+
}
|
|
1029
|
+
function buildFileValue(path) {
|
|
1030
|
+
const normalized = path.trim();
|
|
1031
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
1032
|
+
const fileName = lastSlash >= 0 ? normalized.slice(lastSlash + 1) : normalized;
|
|
1033
|
+
const lastDot = fileName.lastIndexOf(".");
|
|
1034
|
+
const basename = lastDot > 0 ? fileName.slice(0, lastDot) : fileName;
|
|
1035
|
+
const ext = lastDot > 0 ? fileName.slice(lastDot + 1) : "";
|
|
1036
|
+
const folder = lastSlash >= 0 ? normalized.slice(0, lastSlash) : "";
|
|
1037
|
+
return {
|
|
1038
|
+
name: fileName || normalized,
|
|
1039
|
+
basename: basename || fileName || normalized,
|
|
1040
|
+
path: normalized,
|
|
1041
|
+
folder,
|
|
1042
|
+
ext,
|
|
1043
|
+
tags: [],
|
|
1044
|
+
links: []
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
function getMethodTarget(value) {
|
|
1048
|
+
if (typeof value === "string") return "string";
|
|
1049
|
+
if (typeof value === "number" && !Number.isNaN(value)) return "number";
|
|
1050
|
+
if (isDateValue(value)) return "date";
|
|
1051
|
+
if (Array.isArray(value)) return "list";
|
|
1052
|
+
if (isFileValue(value)) return "file";
|
|
1053
|
+
if (isRecord(value)) return "object";
|
|
1054
|
+
return void 0;
|
|
1055
|
+
}
|
|
1056
|
+
registerGlobalFunction("if", ([cond, whenTrue, whenFalse]) => {
|
|
1057
|
+
return cond ? whenTrue : whenFalse;
|
|
1058
|
+
});
|
|
1059
|
+
registerGlobalFunction("contains", ([haystack, needle]) => {
|
|
1060
|
+
if (Array.isArray(haystack)) {
|
|
1061
|
+
if (haystack.includes(needle)) return true;
|
|
1062
|
+
const name = resolveSelfName(needle);
|
|
1063
|
+
return name ? listContainsName(haystack, name, resolveSelfPath(needle)) : false;
|
|
1064
|
+
}
|
|
1065
|
+
if (typeof haystack === "string") return haystack.includes(toStringValue(needle));
|
|
1066
|
+
return false;
|
|
1067
|
+
});
|
|
1068
|
+
registerGlobalFunction("date", ([value]) => parseDate(value));
|
|
1069
|
+
registerGlobalFunction("duration", ([value]) => {
|
|
1070
|
+
if (typeof value === "number") return value;
|
|
1071
|
+
if (typeof value === "string") return parseDuration(value);
|
|
1072
|
+
return void 0;
|
|
1073
|
+
});
|
|
1074
|
+
registerGlobalFunction("now", () => /* @__PURE__ */ new Date());
|
|
1075
|
+
registerGlobalFunction("today", () => {
|
|
1076
|
+
const now = /* @__PURE__ */ new Date();
|
|
1077
|
+
return new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
1078
|
+
});
|
|
1079
|
+
registerGlobalFunction("number", ([value]) => {
|
|
1080
|
+
const numberValue = toNumber(value);
|
|
1081
|
+
return numberValue === null ? void 0 : numberValue;
|
|
1082
|
+
});
|
|
1083
|
+
registerGlobalFunction("min", (args) => {
|
|
1084
|
+
const numbers = collectNumericArgs(args);
|
|
1085
|
+
if (numbers.length === 0) return void 0;
|
|
1086
|
+
return Math.min(...numbers);
|
|
1087
|
+
});
|
|
1088
|
+
registerGlobalFunction("max", (args) => {
|
|
1089
|
+
const numbers = collectNumericArgs(args);
|
|
1090
|
+
if (numbers.length === 0) return void 0;
|
|
1091
|
+
return Math.max(...numbers);
|
|
1092
|
+
});
|
|
1093
|
+
registerGlobalFunction("list", ([value]) => {
|
|
1094
|
+
if (value === void 0 || value === null) return [];
|
|
1095
|
+
if (Array.isArray(value)) return value;
|
|
1096
|
+
return [value];
|
|
1097
|
+
});
|
|
1098
|
+
registerGlobalFunction("link", ([path, display]) => {
|
|
1099
|
+
const target = isFileValue(path) ? path.path.replace(/\.md$/, "") : toStringValue(path);
|
|
1100
|
+
if (!target) return "";
|
|
1101
|
+
const label = isFileValue(display) ? display.basename : toStringValue(display);
|
|
1102
|
+
return label ? `[[${target}|${label}]]` : `[[${target}]]`;
|
|
1103
|
+
});
|
|
1104
|
+
registerGlobalFunction("image", ([path]) => {
|
|
1105
|
+
const target = isFileValue(path) ? path.path.replace(/\.md$/, "") : toStringValue(path);
|
|
1106
|
+
if (!target) return "";
|
|
1107
|
+
return `![[${target}]]`;
|
|
1108
|
+
});
|
|
1109
|
+
registerGlobalFunction("icon", ([name]) => {
|
|
1110
|
+
const value = toStringValue(name);
|
|
1111
|
+
if (!value) return "";
|
|
1112
|
+
return `:${value}:`;
|
|
1113
|
+
});
|
|
1114
|
+
registerGlobalFunction("html", ([value]) => toStringValue(value));
|
|
1115
|
+
registerGlobalFunction("escapeHTML", ([value]) => {
|
|
1116
|
+
const text = toStringValue(value);
|
|
1117
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1118
|
+
});
|
|
1119
|
+
registerGlobalFunction("file", ([path]) => {
|
|
1120
|
+
if (typeof path !== "string") return void 0;
|
|
1121
|
+
if (!path.trim()) return void 0;
|
|
1122
|
+
return buildFileValue(path);
|
|
1123
|
+
});
|
|
1124
|
+
registerMethodFunction("file", "hasTag", (target, args) => {
|
|
1125
|
+
if (!isFileValue(target)) return false;
|
|
1126
|
+
if (args.length === 0) return false;
|
|
1127
|
+
return args.every((tag) => {
|
|
1128
|
+
const value = toStringValue(tag)?.toLowerCase();
|
|
1129
|
+
if (!value) return false;
|
|
1130
|
+
const prefix = value.endsWith("/") ? value : `${value}/`;
|
|
1131
|
+
return target.tags.some((t2) => {
|
|
1132
|
+
const lower = t2.toLowerCase();
|
|
1133
|
+
return lower === value || lower.startsWith(prefix);
|
|
1134
|
+
});
|
|
1135
|
+
});
|
|
1136
|
+
});
|
|
1137
|
+
registerMethodFunction("file", "hasLink", (target, [link]) => {
|
|
1138
|
+
if (!isFileValue(target)) return false;
|
|
1139
|
+
const value = toStringValue(link);
|
|
1140
|
+
if (!value) return false;
|
|
1141
|
+
return target.links.includes(value);
|
|
1142
|
+
});
|
|
1143
|
+
registerMethodFunction("file", "inFolder", (target, [folder]) => {
|
|
1144
|
+
if (!isFileValue(target)) return false;
|
|
1145
|
+
const value = toStringValue(folder);
|
|
1146
|
+
if (!value) return false;
|
|
1147
|
+
const normalized = value.endsWith("/") ? value.slice(0, -1) : value;
|
|
1148
|
+
return target.folder === normalized || target.folder.startsWith(`${normalized}/`);
|
|
1149
|
+
});
|
|
1150
|
+
registerMethodFunction("file", "hasProperty", (_target, [prop], context) => {
|
|
1151
|
+
const value = toStringValue(prop);
|
|
1152
|
+
if (!value) return false;
|
|
1153
|
+
const parts = value.split(".");
|
|
1154
|
+
let target = context.note;
|
|
1155
|
+
for (const part of parts) {
|
|
1156
|
+
if (!isRecord(target)) return false;
|
|
1157
|
+
if (!Object.hasOwn(target, part)) return false;
|
|
1158
|
+
target = target[part];
|
|
1159
|
+
}
|
|
1160
|
+
return true;
|
|
1161
|
+
});
|
|
1162
|
+
registerMethodFunction("string", "contains", (target, [needle]) => {
|
|
1163
|
+
const value = toStringValue(target);
|
|
1164
|
+
return value.includes(toStringValue(needle));
|
|
1165
|
+
});
|
|
1166
|
+
registerMethodFunction("string", "startsWith", (target, [prefix]) => {
|
|
1167
|
+
const value = toStringValue(target);
|
|
1168
|
+
return value.startsWith(toStringValue(prefix));
|
|
1169
|
+
});
|
|
1170
|
+
registerMethodFunction("string", "endsWith", (target, [suffix]) => {
|
|
1171
|
+
const value = toStringValue(target);
|
|
1172
|
+
return value.endsWith(toStringValue(suffix));
|
|
1173
|
+
});
|
|
1174
|
+
registerMethodFunction("string", "lower", (target) => toStringValue(target).toLowerCase());
|
|
1175
|
+
registerMethodFunction("string", "upper", (target) => toStringValue(target).toUpperCase());
|
|
1176
|
+
registerMethodFunction("string", "trim", (target) => toStringValue(target).trim());
|
|
1177
|
+
registerMethodFunction("string", "replace", (target, [search, replacement]) => {
|
|
1178
|
+
const source = toStringValue(target);
|
|
1179
|
+
const needle = toStringValue(search);
|
|
1180
|
+
if (!needle) return source;
|
|
1181
|
+
const replacementText = toStringValue(replacement);
|
|
1182
|
+
return source.split(needle).join(replacementText);
|
|
1183
|
+
});
|
|
1184
|
+
registerMethodFunction("string", "slice", (target, [start, end]) => {
|
|
1185
|
+
const source = toStringValue(target);
|
|
1186
|
+
const startIndex = toInteger(start, 0);
|
|
1187
|
+
if (end === void 0) return source.slice(startIndex);
|
|
1188
|
+
const endIndex = toInteger(end, source.length);
|
|
1189
|
+
return source.slice(startIndex, endIndex);
|
|
1190
|
+
});
|
|
1191
|
+
registerMethodFunction("string", "isEmpty", (target) => toStringValue(target).length === 0);
|
|
1192
|
+
registerMethodFunction("string", "repeat", (target, [count]) => {
|
|
1193
|
+
const source = toStringValue(target);
|
|
1194
|
+
const times = toInteger(count, 0);
|
|
1195
|
+
if (times <= 0) return "";
|
|
1196
|
+
return source.repeat(times);
|
|
1197
|
+
});
|
|
1198
|
+
registerMethodFunction(
|
|
1199
|
+
"string",
|
|
1200
|
+
"reverse",
|
|
1201
|
+
(target) => toStringValue(target).split("").reverse().join("")
|
|
1202
|
+
);
|
|
1203
|
+
registerMethodFunction("number", "toFixed", (target, [digits]) => {
|
|
1204
|
+
const value = toNumber(target);
|
|
1205
|
+
if (value === null) return void 0;
|
|
1206
|
+
const decimals = toInteger(digits, 0);
|
|
1207
|
+
return value.toFixed(decimals);
|
|
1208
|
+
});
|
|
1209
|
+
registerMethodFunction("number", "round", (target, [digits]) => {
|
|
1210
|
+
const value = toNumber(target);
|
|
1211
|
+
if (value === null) return void 0;
|
|
1212
|
+
const decimals = toInteger(digits, 0);
|
|
1213
|
+
return roundTo(value, decimals);
|
|
1214
|
+
});
|
|
1215
|
+
registerMethodFunction("number", "floor", (target) => {
|
|
1216
|
+
const value = toNumber(target);
|
|
1217
|
+
if (value === null) return void 0;
|
|
1218
|
+
return Math.floor(value);
|
|
1219
|
+
});
|
|
1220
|
+
registerMethodFunction("number", "ceil", (target) => {
|
|
1221
|
+
const value = toNumber(target);
|
|
1222
|
+
if (value === null) return void 0;
|
|
1223
|
+
return Math.ceil(value);
|
|
1224
|
+
});
|
|
1225
|
+
registerMethodFunction("number", "abs", (target) => {
|
|
1226
|
+
const value = toNumber(target);
|
|
1227
|
+
if (value === null) return void 0;
|
|
1228
|
+
return Math.abs(value);
|
|
1229
|
+
});
|
|
1230
|
+
function formatDateToken(date, token) {
|
|
1231
|
+
const pad = (n2, len = 2) => String(n2).padStart(len, "0");
|
|
1232
|
+
const y2 = date.getFullYear();
|
|
1233
|
+
const M = date.getMonth() + 1;
|
|
1234
|
+
const d2 = date.getDate();
|
|
1235
|
+
const H2 = date.getHours();
|
|
1236
|
+
const h2 = H2 % 12 || 12;
|
|
1237
|
+
const m2 = date.getMinutes();
|
|
1238
|
+
const s2 = date.getSeconds();
|
|
1239
|
+
const A2 = H2 < 12 ? "AM" : "PM";
|
|
1240
|
+
switch (token) {
|
|
1241
|
+
case "YYYY":
|
|
1242
|
+
return String(y2);
|
|
1243
|
+
case "YY":
|
|
1244
|
+
return String(y2).slice(-2);
|
|
1245
|
+
case "MM":
|
|
1246
|
+
return pad(M);
|
|
1247
|
+
case "M":
|
|
1248
|
+
return String(M);
|
|
1249
|
+
case "DD":
|
|
1250
|
+
return pad(d2);
|
|
1251
|
+
case "D":
|
|
1252
|
+
return String(d2);
|
|
1253
|
+
case "HH":
|
|
1254
|
+
return pad(H2);
|
|
1255
|
+
case "H":
|
|
1256
|
+
return String(H2);
|
|
1257
|
+
case "hh":
|
|
1258
|
+
return pad(h2);
|
|
1259
|
+
case "h":
|
|
1260
|
+
return String(h2);
|
|
1261
|
+
case "mm":
|
|
1262
|
+
return pad(m2);
|
|
1263
|
+
case "m":
|
|
1264
|
+
return String(m2);
|
|
1265
|
+
case "ss":
|
|
1266
|
+
return pad(s2);
|
|
1267
|
+
case "s":
|
|
1268
|
+
return String(s2);
|
|
1269
|
+
case "A":
|
|
1270
|
+
return A2;
|
|
1271
|
+
case "a":
|
|
1272
|
+
return A2.toLowerCase();
|
|
1273
|
+
default:
|
|
1274
|
+
return token;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
function formatDate(date, format) {
|
|
1278
|
+
const tokenPattern = /YYYY|YY|MM|M|DD|D|HH|H|hh|h|mm|m|ss|s|A|a/g;
|
|
1279
|
+
let result = "";
|
|
1280
|
+
let lastIndex = 0;
|
|
1281
|
+
let match = tokenPattern.exec(format);
|
|
1282
|
+
while (match !== null) {
|
|
1283
|
+
result += format.slice(lastIndex, match.index);
|
|
1284
|
+
result += formatDateToken(date, match[0]);
|
|
1285
|
+
lastIndex = tokenPattern.lastIndex;
|
|
1286
|
+
match = tokenPattern.exec(format);
|
|
1287
|
+
}
|
|
1288
|
+
result += format.slice(lastIndex);
|
|
1289
|
+
return result;
|
|
1290
|
+
}
|
|
1291
|
+
registerMethodFunction("date", "format", (target, [format]) => {
|
|
1292
|
+
if (!isDateValue(target)) return void 0;
|
|
1293
|
+
const timestamp = target.getTime();
|
|
1294
|
+
if (Number.isNaN(timestamp)) return "";
|
|
1295
|
+
if (typeof format === "string" && format) {
|
|
1296
|
+
return formatDate(target, format);
|
|
1297
|
+
}
|
|
1298
|
+
return target.toISOString();
|
|
1299
|
+
});
|
|
1300
|
+
registerMethodFunction(
|
|
1301
|
+
"date",
|
|
1302
|
+
"year",
|
|
1303
|
+
(target) => isDateValue(target) ? target.getFullYear() : void 0
|
|
1304
|
+
);
|
|
1305
|
+
registerMethodFunction(
|
|
1306
|
+
"date",
|
|
1307
|
+
"month",
|
|
1308
|
+
(target) => isDateValue(target) ? target.getMonth() + 1 : void 0
|
|
1309
|
+
);
|
|
1310
|
+
registerMethodFunction(
|
|
1311
|
+
"date",
|
|
1312
|
+
"day",
|
|
1313
|
+
(target) => isDateValue(target) ? target.getDate() : void 0
|
|
1314
|
+
);
|
|
1315
|
+
registerMethodFunction("date", "date", (target) => {
|
|
1316
|
+
if (!isDateValue(target)) return void 0;
|
|
1317
|
+
const pad = (n2, len = 2) => String(n2).padStart(len, "0");
|
|
1318
|
+
return `${target.getFullYear()}-${pad(target.getMonth() + 1)}-${pad(target.getDate())}`;
|
|
1319
|
+
});
|
|
1320
|
+
registerMethodFunction("date", "time", (target) => {
|
|
1321
|
+
if (!isDateValue(target)) return void 0;
|
|
1322
|
+
const pad = (n2) => String(n2).padStart(2, "0");
|
|
1323
|
+
return `${pad(target.getHours())}:${pad(target.getMinutes())}:${pad(target.getSeconds())}`;
|
|
1324
|
+
});
|
|
1325
|
+
registerMethodFunction("date", "relative", (target) => {
|
|
1326
|
+
if (!isDateValue(target)) return void 0;
|
|
1327
|
+
const time = target.getTime();
|
|
1328
|
+
if (Number.isNaN(time)) return "";
|
|
1329
|
+
const diff = time - Date.now();
|
|
1330
|
+
const abs = Math.abs(diff);
|
|
1331
|
+
const minutes = Math.round(abs / 6e4);
|
|
1332
|
+
const hours = Math.round(abs / 36e5);
|
|
1333
|
+
const days = Math.round(abs / 864e5);
|
|
1334
|
+
if (days >= 1) return diff < 0 ? `${days}d ago` : `in ${days}d`;
|
|
1335
|
+
if (hours >= 1) return diff < 0 ? `${hours}h ago` : `in ${hours}h`;
|
|
1336
|
+
if (minutes >= 1) return diff < 0 ? `${minutes}m ago` : `in ${minutes}m`;
|
|
1337
|
+
return diff < 0 ? "just now" : "soon";
|
|
1338
|
+
});
|
|
1339
|
+
registerMethodFunction("date", "isEmpty", (target) => {
|
|
1340
|
+
if (!isDateValue(target)) return true;
|
|
1341
|
+
return Number.isNaN(target.getTime());
|
|
1342
|
+
});
|
|
1343
|
+
registerMethodFunction("list", "sum", (target) => {
|
|
1344
|
+
if (!Array.isArray(target)) return void 0;
|
|
1345
|
+
return target.reduce((total, item) => {
|
|
1346
|
+
const value = toNumber(item);
|
|
1347
|
+
return value === null ? total : total + value;
|
|
1348
|
+
}, 0);
|
|
1349
|
+
});
|
|
1350
|
+
registerMethodFunction("list", "mean", (target) => {
|
|
1351
|
+
if (!Array.isArray(target)) return void 0;
|
|
1352
|
+
const numbers = collectNumericArgs(target);
|
|
1353
|
+
if (numbers.length === 0) return void 0;
|
|
1354
|
+
const sum = numbers.reduce((total, value) => total + value, 0);
|
|
1355
|
+
return sum / numbers.length;
|
|
1356
|
+
});
|
|
1357
|
+
registerMethodFunction("list", "count", (target) => Array.isArray(target) ? target.length : 0);
|
|
1358
|
+
registerMethodFunction("list", "min", (target) => {
|
|
1359
|
+
if (!Array.isArray(target)) return void 0;
|
|
1360
|
+
const numbers = collectNumericArgs(target);
|
|
1361
|
+
if (numbers.length === 0) return void 0;
|
|
1362
|
+
return Math.min(...numbers);
|
|
1363
|
+
});
|
|
1364
|
+
registerMethodFunction("list", "max", (target) => {
|
|
1365
|
+
if (!Array.isArray(target)) return void 0;
|
|
1366
|
+
const numbers = collectNumericArgs(target);
|
|
1367
|
+
if (numbers.length === 0) return void 0;
|
|
1368
|
+
return Math.max(...numbers);
|
|
1369
|
+
});
|
|
1370
|
+
registerMethodFunction("list", "round", (target, [digits]) => {
|
|
1371
|
+
if (!Array.isArray(target)) return void 0;
|
|
1372
|
+
const decimals = toInteger(digits, 0);
|
|
1373
|
+
return target.map((item) => {
|
|
1374
|
+
const numberValue = toNumber(item);
|
|
1375
|
+
if (numberValue === null) return item;
|
|
1376
|
+
return roundTo(numberValue, decimals);
|
|
1377
|
+
});
|
|
1378
|
+
});
|
|
1379
|
+
registerMethodFunction("file", "asLink", (target, args) => {
|
|
1380
|
+
if (!isFileValue(target)) return "";
|
|
1381
|
+
const path = target.path.replace(/\.md$/, "");
|
|
1382
|
+
const display = args.length > 0 ? toStringValue(args[0]) : "";
|
|
1383
|
+
return display ? `[[${path}|${display}]]` : `[[${path}]]`;
|
|
1384
|
+
});
|
|
1385
|
+
registerMethodFunction("string", "containsAll", (target, args) => {
|
|
1386
|
+
const value = toStringValue(target);
|
|
1387
|
+
return args.every((needle) => value.includes(toStringValue(needle)));
|
|
1388
|
+
});
|
|
1389
|
+
registerMethodFunction("string", "containsAny", (target, args) => {
|
|
1390
|
+
const value = toStringValue(target);
|
|
1391
|
+
return args.some((needle) => value.includes(toStringValue(needle)));
|
|
1392
|
+
});
|
|
1393
|
+
registerMethodFunction("string", "split", (target, [separator]) => {
|
|
1394
|
+
const value = toStringValue(target);
|
|
1395
|
+
const sep = toStringValue(separator);
|
|
1396
|
+
return value.split(sep);
|
|
1397
|
+
});
|
|
1398
|
+
registerMethodFunction("string", "title", (target) => {
|
|
1399
|
+
const value = toStringValue(target);
|
|
1400
|
+
return value.replace(/\b\w/g, (ch) => ch.toUpperCase());
|
|
1401
|
+
});
|
|
1402
|
+
registerMethodFunction("string", "asFile", (target, _args, context) => {
|
|
1403
|
+
const path = toStringValue(target);
|
|
1404
|
+
if (!path) return void 0;
|
|
1405
|
+
const lookup = context._fileLookup;
|
|
1406
|
+
if (lookup) {
|
|
1407
|
+
const normalized = path.trim();
|
|
1408
|
+
const found = lookup.get(normalized) ?? lookup.get(normalized.replace(/\.md$/, "")) ?? (!normalized.endsWith(".md") ? lookup.get(`${normalized}.md`) : void 0);
|
|
1409
|
+
if (found) return { ...found };
|
|
1410
|
+
const suffix = `/${normalized}`;
|
|
1411
|
+
const suffixMd = `/${normalized}.md`;
|
|
1412
|
+
for (const [key, value] of lookup) {
|
|
1413
|
+
if (key.endsWith(suffix) || key.endsWith(suffixMd)) {
|
|
1414
|
+
return { ...value };
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
return buildFileValue(path);
|
|
1419
|
+
});
|
|
1420
|
+
registerMethodFunction("list", "contains", (target, [needle]) => {
|
|
1421
|
+
if (!Array.isArray(target)) return false;
|
|
1422
|
+
if (target.includes(needle)) return true;
|
|
1423
|
+
const name = resolveSelfName(needle);
|
|
1424
|
+
return name ? listContainsName(target, name, resolveSelfPath(needle)) : false;
|
|
1425
|
+
});
|
|
1426
|
+
registerMethodFunction("list", "containsAll", (target, args) => {
|
|
1427
|
+
if (!Array.isArray(target)) return false;
|
|
1428
|
+
return args.every((needle) => target.includes(needle));
|
|
1429
|
+
});
|
|
1430
|
+
registerMethodFunction("list", "containsAny", (target, args) => {
|
|
1431
|
+
if (!Array.isArray(target)) return false;
|
|
1432
|
+
return args.some((needle) => target.includes(needle));
|
|
1433
|
+
});
|
|
1434
|
+
registerMethodFunction("list", "flat", (target) => {
|
|
1435
|
+
if (!Array.isArray(target)) return void 0;
|
|
1436
|
+
return target.flat();
|
|
1437
|
+
});
|
|
1438
|
+
registerMethodFunction("list", "isEmpty", (target) => {
|
|
1439
|
+
if (!Array.isArray(target)) return true;
|
|
1440
|
+
return target.length === 0;
|
|
1441
|
+
});
|
|
1442
|
+
registerMethodFunction("list", "join", (target, [separator]) => {
|
|
1443
|
+
if (!Array.isArray(target)) return "";
|
|
1444
|
+
const sep = separator === void 0 ? ", " : toStringValue(separator);
|
|
1445
|
+
return target.map((item) => toStringValue(item)).join(sep);
|
|
1446
|
+
});
|
|
1447
|
+
registerMethodFunction("list", "reverse", (target) => {
|
|
1448
|
+
if (!Array.isArray(target)) return void 0;
|
|
1449
|
+
return [...target].reverse();
|
|
1450
|
+
});
|
|
1451
|
+
registerMethodFunction("list", "slice", (target, [start, end]) => {
|
|
1452
|
+
if (!Array.isArray(target)) return void 0;
|
|
1453
|
+
const startIndex = toInteger(start, 0);
|
|
1454
|
+
if (end === void 0) return target.slice(startIndex);
|
|
1455
|
+
const endIndex = toInteger(end, target.length);
|
|
1456
|
+
return target.slice(startIndex, endIndex);
|
|
1457
|
+
});
|
|
1458
|
+
registerMethodFunction("list", "sort", (target) => {
|
|
1459
|
+
if (!Array.isArray(target)) return void 0;
|
|
1460
|
+
return [...target].sort((a2, b2) => {
|
|
1461
|
+
if (typeof a2 === "number" && typeof b2 === "number") return a2 - b2;
|
|
1462
|
+
return String(a2).localeCompare(String(b2));
|
|
1463
|
+
});
|
|
1464
|
+
});
|
|
1465
|
+
registerMethodFunction("list", "unique", (target) => {
|
|
1466
|
+
if (!Array.isArray(target)) return void 0;
|
|
1467
|
+
return [...new Set(target)];
|
|
1468
|
+
});
|
|
1469
|
+
registerMethodFunction("number", "isEmpty", (target) => {
|
|
1470
|
+
const value = toNumber(target);
|
|
1471
|
+
return value === null || Number.isNaN(value);
|
|
1472
|
+
});
|
|
1473
|
+
registerMethodFunction("object", "isEmpty", (target) => {
|
|
1474
|
+
if (!isRecord(target)) return true;
|
|
1475
|
+
return Object.keys(target).length === 0;
|
|
1476
|
+
});
|
|
1477
|
+
registerMethodFunction("object", "keys", (target) => {
|
|
1478
|
+
if (!isRecord(target)) return [];
|
|
1479
|
+
return Object.keys(target);
|
|
1480
|
+
});
|
|
1481
|
+
registerMethodFunction("object", "values", (target) => {
|
|
1482
|
+
if (!isRecord(target)) return [];
|
|
1483
|
+
return Object.values(target);
|
|
1484
|
+
});
|
|
1485
|
+
function registerAnyMethod(name, fn) {
|
|
1486
|
+
const targets = ["string", "number", "date", "list", "file", "object"];
|
|
1487
|
+
for (const target of targets) {
|
|
1488
|
+
registerMethodFunction(target, name, fn);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
registerAnyMethod("isTruthy", (target) => Boolean(target));
|
|
1492
|
+
registerAnyMethod("isType", (target, [typeName]) => {
|
|
1493
|
+
const expected = toStringValue(typeName).toLowerCase();
|
|
1494
|
+
if (typeof target === "string") return expected === "string";
|
|
1495
|
+
if (typeof target === "number") return expected === "number";
|
|
1496
|
+
if (isDateValue(target)) return expected === "date";
|
|
1497
|
+
if (Array.isArray(target)) return expected === "list" || expected === "array";
|
|
1498
|
+
if (isFileValue(target)) return expected === "file";
|
|
1499
|
+
if (isRecord(target)) return expected === "object";
|
|
1500
|
+
return false;
|
|
1501
|
+
});
|
|
1502
|
+
registerAnyMethod("toString", (target) => {
|
|
1503
|
+
if (isDateValue(target)) return target.toISOString();
|
|
1504
|
+
if (Array.isArray(target)) return target.map((item) => toStringValue(item)).join(", ");
|
|
1505
|
+
if (isRecord(target)) return JSON.stringify(target);
|
|
1506
|
+
return toStringValue(target);
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
// src/compiler/interpreter.ts
|
|
1510
|
+
function isRecord2(value) {
|
|
1511
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1512
|
+
}
|
|
1513
|
+
function toBoolean(value) {
|
|
1514
|
+
return Boolean(value);
|
|
1515
|
+
}
|
|
1516
|
+
function toNumber2(value) {
|
|
1517
|
+
if (typeof value === "number" && !Number.isNaN(value)) return value;
|
|
1518
|
+
if (typeof value === "string") {
|
|
1519
|
+
const parsed = Number(value);
|
|
1520
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
1521
|
+
}
|
|
1522
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
1523
|
+
return null;
|
|
1524
|
+
}
|
|
1525
|
+
function toStringValue2(value) {
|
|
1526
|
+
if (value === void 0 || value === null) return "";
|
|
1527
|
+
return String(value);
|
|
1528
|
+
}
|
|
1529
|
+
function compareValues(left, right, operator) {
|
|
1530
|
+
if (operator === "==") {
|
|
1531
|
+
if (isDateValue2(left) && isDateValue2(right)) return left.getTime() === right.getTime();
|
|
1532
|
+
return left === right;
|
|
1533
|
+
}
|
|
1534
|
+
if (operator === "!=") {
|
|
1535
|
+
if (isDateValue2(left) && isDateValue2(right)) return left.getTime() !== right.getTime();
|
|
1536
|
+
return left !== right;
|
|
1537
|
+
}
|
|
1538
|
+
if (isDateValue2(left) && isDateValue2(right)) {
|
|
1539
|
+
const leftMs = left.getTime();
|
|
1540
|
+
const rightMs = right.getTime();
|
|
1541
|
+
if (operator === ">") return leftMs > rightMs;
|
|
1542
|
+
if (operator === "<") return leftMs < rightMs;
|
|
1543
|
+
if (operator === ">=") return leftMs >= rightMs;
|
|
1544
|
+
if (operator === "<=") return leftMs <= rightMs;
|
|
1545
|
+
}
|
|
1546
|
+
const leftNum = toNumber2(left);
|
|
1547
|
+
const rightNum = toNumber2(right);
|
|
1548
|
+
if (leftNum !== null && rightNum !== null) {
|
|
1549
|
+
if (operator === ">") return leftNum > rightNum;
|
|
1550
|
+
if (operator === "<") return leftNum < rightNum;
|
|
1551
|
+
if (operator === ">=") return leftNum >= rightNum;
|
|
1552
|
+
if (operator === "<=") return leftNum <= rightNum;
|
|
1553
|
+
}
|
|
1554
|
+
const leftStr = toStringValue2(left);
|
|
1555
|
+
const rightStr = toStringValue2(right);
|
|
1556
|
+
if (operator === ">") return leftStr > rightStr;
|
|
1557
|
+
if (operator === "<") return leftStr < rightStr;
|
|
1558
|
+
if (operator === ">=") return leftStr >= rightStr;
|
|
1559
|
+
if (operator === "<=") return leftStr <= rightStr;
|
|
1560
|
+
return false;
|
|
1561
|
+
}
|
|
1562
|
+
function isDateValue2(value) {
|
|
1563
|
+
return value instanceof Date && !Number.isNaN(value.getTime());
|
|
1564
|
+
}
|
|
1565
|
+
function applyBinary(operator, left, right) {
|
|
1566
|
+
if (operator === "+") {
|
|
1567
|
+
if (isDateValue2(left) && typeof right === "number") {
|
|
1568
|
+
return new Date(left.getTime() + right);
|
|
1569
|
+
}
|
|
1570
|
+
if (typeof left === "number" && isDateValue2(right)) {
|
|
1571
|
+
return new Date(right.getTime() + left);
|
|
1572
|
+
}
|
|
1573
|
+
if (typeof left === "string" || typeof right === "string") {
|
|
1574
|
+
return `${toStringValue2(left)}${toStringValue2(right)}`;
|
|
1575
|
+
}
|
|
1576
|
+
const leftNum = toNumber2(left);
|
|
1577
|
+
const rightNum = toNumber2(right);
|
|
1578
|
+
if (leftNum === null || rightNum === null) return void 0;
|
|
1579
|
+
return leftNum + rightNum;
|
|
1580
|
+
}
|
|
1581
|
+
if (operator === "-") {
|
|
1582
|
+
if (isDateValue2(left) && typeof right === "number") {
|
|
1583
|
+
return new Date(left.getTime() - right);
|
|
1584
|
+
}
|
|
1585
|
+
if (isDateValue2(left) && isDateValue2(right)) {
|
|
1586
|
+
return left.getTime() - right.getTime();
|
|
1587
|
+
}
|
|
1588
|
+
const leftNum = toNumber2(left);
|
|
1589
|
+
const rightNum = toNumber2(right);
|
|
1590
|
+
if (leftNum === null || rightNum === null) return void 0;
|
|
1591
|
+
return leftNum - rightNum;
|
|
1592
|
+
}
|
|
1593
|
+
if (operator === "*") {
|
|
1594
|
+
const leftNum = toNumber2(left);
|
|
1595
|
+
const rightNum = toNumber2(right);
|
|
1596
|
+
if (leftNum === null || rightNum === null) return void 0;
|
|
1597
|
+
return leftNum * rightNum;
|
|
1598
|
+
}
|
|
1599
|
+
if (operator === "/") {
|
|
1600
|
+
const leftNum = toNumber2(left);
|
|
1601
|
+
const rightNum = toNumber2(right);
|
|
1602
|
+
if (leftNum === null || rightNum === null) return void 0;
|
|
1603
|
+
return rightNum === 0 ? 0 : leftNum / rightNum;
|
|
1604
|
+
}
|
|
1605
|
+
if (operator === "%") {
|
|
1606
|
+
const leftNum = toNumber2(left);
|
|
1607
|
+
const rightNum = toNumber2(right);
|
|
1608
|
+
if (leftNum === null || rightNum === null) return void 0;
|
|
1609
|
+
return rightNum === 0 ? 0 : leftNum % rightNum;
|
|
1610
|
+
}
|
|
1611
|
+
return compareValues(left, right, operator);
|
|
1612
|
+
}
|
|
1613
|
+
function getNestedValue(target, path) {
|
|
1614
|
+
let current = target;
|
|
1615
|
+
for (const part of path) {
|
|
1616
|
+
if (!part) continue;
|
|
1617
|
+
if (Array.isArray(current)) {
|
|
1618
|
+
const index = Number(part);
|
|
1619
|
+
if (Number.isNaN(index)) return void 0;
|
|
1620
|
+
current = current[index];
|
|
1621
|
+
continue;
|
|
1622
|
+
}
|
|
1623
|
+
if (!isRecord2(current)) return void 0;
|
|
1624
|
+
current = current[part];
|
|
1625
|
+
}
|
|
1626
|
+
return current;
|
|
1627
|
+
}
|
|
1628
|
+
function resolvePropertyValue(path, context) {
|
|
1629
|
+
if (typeof path !== "string") return void 0;
|
|
1630
|
+
const trimmed = path.trim();
|
|
1631
|
+
if (!trimmed) return void 0;
|
|
1632
|
+
if (trimmed.startsWith("this.")) {
|
|
1633
|
+
return getNestedValue(context.self ?? {}, trimmed.slice(5).split("."));
|
|
1634
|
+
}
|
|
1635
|
+
if (trimmed.startsWith("note.")) {
|
|
1636
|
+
return getNestedValue(context.note, trimmed.slice(5).split("."));
|
|
1637
|
+
}
|
|
1638
|
+
if (trimmed.startsWith("file.")) {
|
|
1639
|
+
return getNestedValue(context.file, trimmed.slice(5).split("."));
|
|
1640
|
+
}
|
|
1641
|
+
if (trimmed.startsWith("formula.")) {
|
|
1642
|
+
return getNestedValue(context.formula, trimmed.slice(8).split("."));
|
|
1643
|
+
}
|
|
1644
|
+
return getNestedValue(context.note, trimmed.split("."));
|
|
1645
|
+
}
|
|
1646
|
+
function resolveIdentifier(name, context) {
|
|
1647
|
+
if (name.includes(".")) return resolvePropertyValue(name, context);
|
|
1648
|
+
if (name === "this") return context.self ?? {};
|
|
1649
|
+
if (name === "note") return context.note;
|
|
1650
|
+
if (name === "file") return context.file;
|
|
1651
|
+
if (name === "formula") return context.formula;
|
|
1652
|
+
if (name === "value") return context._lambdaValue;
|
|
1653
|
+
return context.note[name];
|
|
1654
|
+
}
|
|
1655
|
+
function resolveMember(target, name) {
|
|
1656
|
+
if (target === void 0 || target === null) return void 0;
|
|
1657
|
+
if (isDateValue2(target)) {
|
|
1658
|
+
switch (name) {
|
|
1659
|
+
case "year":
|
|
1660
|
+
return target.getFullYear();
|
|
1661
|
+
case "month":
|
|
1662
|
+
return target.getMonth() + 1;
|
|
1663
|
+
case "day":
|
|
1664
|
+
return target.getDate();
|
|
1665
|
+
case "hour":
|
|
1666
|
+
return target.getHours();
|
|
1667
|
+
case "minute":
|
|
1668
|
+
return target.getMinutes();
|
|
1669
|
+
case "second":
|
|
1670
|
+
return target.getSeconds();
|
|
1671
|
+
default:
|
|
1672
|
+
return void 0;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
if (Array.isArray(target)) {
|
|
1676
|
+
if (name === "length") return target.length;
|
|
1677
|
+
const index = Number(name);
|
|
1678
|
+
if (Number.isNaN(index)) return void 0;
|
|
1679
|
+
return target[index];
|
|
1680
|
+
}
|
|
1681
|
+
if (typeof target === "string") {
|
|
1682
|
+
if (name === "length") return target.length;
|
|
1683
|
+
const index = Number(name);
|
|
1684
|
+
if (Number.isNaN(index)) return void 0;
|
|
1685
|
+
return target.charAt(index);
|
|
1686
|
+
}
|
|
1687
|
+
if (isRecord2(target)) return target[name];
|
|
1688
|
+
return void 0;
|
|
1689
|
+
}
|
|
1690
|
+
function resolveIndex(target, indexValue) {
|
|
1691
|
+
if (target === void 0 || target === null) return void 0;
|
|
1692
|
+
if (Array.isArray(target)) {
|
|
1693
|
+
const index = toNumber2(indexValue);
|
|
1694
|
+
if (index === null) return void 0;
|
|
1695
|
+
return target[Math.trunc(index)];
|
|
1696
|
+
}
|
|
1697
|
+
if (typeof target === "string") {
|
|
1698
|
+
const index = toNumber2(indexValue);
|
|
1699
|
+
if (index === null) return void 0;
|
|
1700
|
+
return target.charAt(Math.trunc(index));
|
|
1701
|
+
}
|
|
1702
|
+
if (isRecord2(target)) {
|
|
1703
|
+
if (typeof indexValue === "string" || typeof indexValue === "number") {
|
|
1704
|
+
return target[String(indexValue)];
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
return void 0;
|
|
1708
|
+
}
|
|
1709
|
+
function popArgs(stack, count) {
|
|
1710
|
+
const args = new Array(count);
|
|
1711
|
+
for (let i2 = count - 1; i2 >= 0; i2 -= 1) {
|
|
1712
|
+
args[i2] = stack.pop();
|
|
1713
|
+
}
|
|
1714
|
+
return args;
|
|
1715
|
+
}
|
|
1716
|
+
function evaluateLambda(program, elementValue, context) {
|
|
1717
|
+
const lambdaContext = { ...context, _lambdaValue: elementValue };
|
|
1718
|
+
return interpret(program, lambdaContext);
|
|
1719
|
+
}
|
|
1720
|
+
function executeLazyMethod(name, target, argPrograms, context) {
|
|
1721
|
+
if (!Array.isArray(target)) return void 0;
|
|
1722
|
+
const body = argPrograms[0];
|
|
1723
|
+
if (!body) return void 0;
|
|
1724
|
+
switch (name) {
|
|
1725
|
+
case "filter":
|
|
1726
|
+
return target.filter((element) => {
|
|
1727
|
+
const result = evaluateLambda(body, element, context);
|
|
1728
|
+
return Boolean(result);
|
|
1729
|
+
});
|
|
1730
|
+
case "map":
|
|
1731
|
+
return target.map((element) => evaluateLambda(body, element, context));
|
|
1732
|
+
case "flatMap": {
|
|
1733
|
+
const mapped = target.map((element) => evaluateLambda(body, element, context));
|
|
1734
|
+
return mapped.flat();
|
|
1735
|
+
}
|
|
1736
|
+
case "find":
|
|
1737
|
+
return target.find((element) => {
|
|
1738
|
+
const result = evaluateLambda(body, element, context);
|
|
1739
|
+
return Boolean(result);
|
|
1740
|
+
});
|
|
1741
|
+
case "some":
|
|
1742
|
+
return target.some((element) => {
|
|
1743
|
+
const result = evaluateLambda(body, element, context);
|
|
1744
|
+
return Boolean(result);
|
|
1745
|
+
});
|
|
1746
|
+
case "every":
|
|
1747
|
+
return target.every((element) => {
|
|
1748
|
+
const result = evaluateLambda(body, element, context);
|
|
1749
|
+
return Boolean(result);
|
|
1750
|
+
});
|
|
1751
|
+
default:
|
|
1752
|
+
return void 0;
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
function interpret(instructions, context) {
|
|
1756
|
+
const stack = [];
|
|
1757
|
+
let ip = 0;
|
|
1758
|
+
while (ip < instructions.length) {
|
|
1759
|
+
const instruction = instructions[ip];
|
|
1760
|
+
if (!instruction) break;
|
|
1761
|
+
switch (instruction.type) {
|
|
1762
|
+
case "Const":
|
|
1763
|
+
stack.push(instruction.value);
|
|
1764
|
+
ip += 1;
|
|
1765
|
+
break;
|
|
1766
|
+
case "Ident":
|
|
1767
|
+
stack.push(resolveIdentifier(instruction.name, context));
|
|
1768
|
+
ip += 1;
|
|
1769
|
+
break;
|
|
1770
|
+
case "LoadFormula":
|
|
1771
|
+
stack.push(context.formula[instruction.name]);
|
|
1772
|
+
ip += 1;
|
|
1773
|
+
break;
|
|
1774
|
+
case "Member": {
|
|
1775
|
+
const target = stack.pop();
|
|
1776
|
+
stack.push(resolveMember(target, instruction.name));
|
|
1777
|
+
ip += 1;
|
|
1778
|
+
break;
|
|
1779
|
+
}
|
|
1780
|
+
case "Index": {
|
|
1781
|
+
const indexValue = stack.pop();
|
|
1782
|
+
const target = stack.pop();
|
|
1783
|
+
stack.push(resolveIndex(target, indexValue));
|
|
1784
|
+
ip += 1;
|
|
1785
|
+
break;
|
|
1786
|
+
}
|
|
1787
|
+
case "List": {
|
|
1788
|
+
const items = popArgs(stack, instruction.count);
|
|
1789
|
+
stack.push(items);
|
|
1790
|
+
ip += 1;
|
|
1791
|
+
break;
|
|
1792
|
+
}
|
|
1793
|
+
case "Unary": {
|
|
1794
|
+
const value = stack.pop();
|
|
1795
|
+
if (instruction.operator === "!") {
|
|
1796
|
+
stack.push(!toBoolean(value));
|
|
1797
|
+
} else if (instruction.operator === "-") {
|
|
1798
|
+
const numberValue = toNumber2(value);
|
|
1799
|
+
stack.push(numberValue === null ? void 0 : -numberValue);
|
|
1800
|
+
} else {
|
|
1801
|
+
stack.push(void 0);
|
|
1802
|
+
}
|
|
1803
|
+
ip += 1;
|
|
1804
|
+
break;
|
|
1805
|
+
}
|
|
1806
|
+
case "Binary": {
|
|
1807
|
+
const right = stack.pop();
|
|
1808
|
+
const left = stack.pop();
|
|
1809
|
+
stack.push(applyBinary(instruction.operator, left, right));
|
|
1810
|
+
ip += 1;
|
|
1811
|
+
break;
|
|
1812
|
+
}
|
|
1813
|
+
case "ToBool": {
|
|
1814
|
+
const value = stack.pop();
|
|
1815
|
+
stack.push(toBoolean(value));
|
|
1816
|
+
ip += 1;
|
|
1817
|
+
break;
|
|
1818
|
+
}
|
|
1819
|
+
case "CallGlobal": {
|
|
1820
|
+
const args = popArgs(stack, instruction.argc);
|
|
1821
|
+
const fn = getGlobalFunction(instruction.name);
|
|
1822
|
+
if (!fn) {
|
|
1823
|
+
stack.push(void 0);
|
|
1824
|
+
ip += 1;
|
|
1825
|
+
break;
|
|
1826
|
+
}
|
|
1827
|
+
try {
|
|
1828
|
+
stack.push(fn(args, context));
|
|
1829
|
+
} catch {
|
|
1830
|
+
stack.push(void 0);
|
|
1831
|
+
}
|
|
1832
|
+
ip += 1;
|
|
1833
|
+
break;
|
|
1834
|
+
}
|
|
1835
|
+
case "CallMethod": {
|
|
1836
|
+
const args = popArgs(stack, instruction.argc);
|
|
1837
|
+
const target = stack.pop();
|
|
1838
|
+
if ((target === null || target === void 0) && instruction.name === "isEmpty") {
|
|
1839
|
+
stack.push(true);
|
|
1840
|
+
ip += 1;
|
|
1841
|
+
break;
|
|
1842
|
+
}
|
|
1843
|
+
const fn = getMethodFunction(instruction.name, target);
|
|
1844
|
+
if (!fn) {
|
|
1845
|
+
stack.push(void 0);
|
|
1846
|
+
ip += 1;
|
|
1847
|
+
break;
|
|
1848
|
+
}
|
|
1849
|
+
try {
|
|
1850
|
+
stack.push(fn(target, args, context));
|
|
1851
|
+
} catch {
|
|
1852
|
+
stack.push(void 0);
|
|
1853
|
+
}
|
|
1854
|
+
ip += 1;
|
|
1855
|
+
break;
|
|
1856
|
+
}
|
|
1857
|
+
case "CallMethodLazy": {
|
|
1858
|
+
const target = stack.pop();
|
|
1859
|
+
const result = executeLazyMethod(
|
|
1860
|
+
instruction.name,
|
|
1861
|
+
target,
|
|
1862
|
+
instruction.argPrograms,
|
|
1863
|
+
context
|
|
1864
|
+
);
|
|
1865
|
+
stack.push(result);
|
|
1866
|
+
ip += 1;
|
|
1867
|
+
break;
|
|
1868
|
+
}
|
|
1869
|
+
case "Jump":
|
|
1870
|
+
ip += instruction.offset;
|
|
1871
|
+
break;
|
|
1872
|
+
case "JumpIfFalse": {
|
|
1873
|
+
const value = stack.pop();
|
|
1874
|
+
if (!toBoolean(value)) {
|
|
1875
|
+
ip += instruction.offset;
|
|
1876
|
+
} else {
|
|
1877
|
+
ip += 1;
|
|
1878
|
+
}
|
|
1879
|
+
break;
|
|
1880
|
+
}
|
|
1881
|
+
case "JumpIfTrue": {
|
|
1882
|
+
const value = stack.pop();
|
|
1883
|
+
if (toBoolean(value)) {
|
|
1884
|
+
ip += instruction.offset;
|
|
1885
|
+
} else {
|
|
1886
|
+
ip += 1;
|
|
1887
|
+
}
|
|
1888
|
+
break;
|
|
1889
|
+
}
|
|
1890
|
+
default:
|
|
1891
|
+
ip += 1;
|
|
1892
|
+
break;
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
return stack.pop();
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// src/compiler/index.ts
|
|
1899
|
+
function compile(expression) {
|
|
1900
|
+
const tokens = lex(expression);
|
|
1901
|
+
const ast = parse(tokens);
|
|
1902
|
+
return compileAst(ast);
|
|
1903
|
+
}
|
|
1904
|
+
function evaluate(expression, context) {
|
|
1905
|
+
try {
|
|
1906
|
+
const compiled = compile(expression);
|
|
1907
|
+
return interpret(compiled.instructions, context);
|
|
1908
|
+
} catch {
|
|
1909
|
+
return void 0;
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
function evaluateFilter(node, context) {
|
|
1913
|
+
if (!node) return true;
|
|
1914
|
+
if (typeof node === "string") {
|
|
1915
|
+
return Boolean(evaluate(node, context));
|
|
1916
|
+
}
|
|
1917
|
+
if ("and" in node) {
|
|
1918
|
+
return node.and.every((child) => evaluateFilter(child, context));
|
|
1919
|
+
}
|
|
1920
|
+
if ("or" in node) {
|
|
1921
|
+
return node.or.some((child) => evaluateFilter(child, context));
|
|
1922
|
+
}
|
|
1923
|
+
if ("not" in node) {
|
|
1924
|
+
return !node.not.every((child) => evaluateFilter(child, context));
|
|
1925
|
+
}
|
|
1926
|
+
return true;
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
export { S, compile, evaluate, evaluateFilter, k, l, resolvePropertyValue, slugifyFilePath, slugifyPath, transformLink, u2 as u };
|
|
1930
|
+
//# sourceMappingURL=chunk-X2AZ5GOJ.js.map
|
|
1931
|
+
//# sourceMappingURL=chunk-X2AZ5GOJ.js.map
|