@aliou/obsdx-base-ast 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.
@@ -0,0 +1,101 @@
1
+ //#region src/expressions/ast.d.ts
2
+ type Expr = {
3
+ kind: "literal";
4
+ value: unknown;
5
+ } | {
6
+ kind: "regex";
7
+ pattern: string;
8
+ flags: string;
9
+ } | {
10
+ kind: "array";
11
+ elements: Expr[];
12
+ } | {
13
+ kind: "identifier";
14
+ name: string;
15
+ } | {
16
+ kind: "member";
17
+ object: Expr;
18
+ property: string;
19
+ } | {
20
+ kind: "index";
21
+ object: Expr;
22
+ index: Expr;
23
+ } | {
24
+ kind: "call";
25
+ callee: Expr;
26
+ args: Expr[];
27
+ } | {
28
+ kind: "unary";
29
+ operator: "!" | "-";
30
+ right: Expr;
31
+ } | {
32
+ kind: "binary";
33
+ left: Expr;
34
+ operator: string;
35
+ right: Expr;
36
+ };
37
+ //#endregion
38
+ //#region src/expressions/lexer.d.ts
39
+ type TokenType = "identifier" | "number" | "string" | "regex" | "operator" | "punct" | "eof";
40
+ type Token = {
41
+ type: TokenType;
42
+ lexeme: string;
43
+ value?: unknown;
44
+ };
45
+ declare function lexExpression(source: string): Token[];
46
+ //#endregion
47
+ //#region src/expressions/parser.d.ts
48
+ declare function parseExpression(source: string): Expr;
49
+ //#endregion
50
+ //#region src/filter.d.ts
51
+ type FilterNode = {
52
+ op: "expr";
53
+ expression: unknown;
54
+ } | {
55
+ op: "and";
56
+ children: FilterNode[];
57
+ } | {
58
+ op: "or";
59
+ children: FilterNode[];
60
+ } | {
61
+ op: "not";
62
+ children: FilterNode[];
63
+ };
64
+ //#endregion
65
+ //#region src/parser.d.ts
66
+ type BasePropertyConfig = {
67
+ displayName?: string;
68
+ };
69
+ type BaseSort = {
70
+ property: string;
71
+ direction?: "ASC" | "DESC";
72
+ };
73
+ type BaseGroupBy = {
74
+ property: string;
75
+ direction?: "ASC" | "DESC";
76
+ };
77
+ type BaseView = {
78
+ type: string;
79
+ name: string;
80
+ filters?: unknown;
81
+ order?: string[];
82
+ sort?: BaseSort[];
83
+ limit?: number;
84
+ groupBy?: BaseGroupBy;
85
+ summaries?: Record<string, unknown>;
86
+ raw: Record<string, unknown>;
87
+ };
88
+ type BaseDefinition = {
89
+ path: string;
90
+ source: Record<string, unknown>;
91
+ properties: Record<string, BasePropertyConfig>;
92
+ formulas: Record<string, string>;
93
+ filters?: unknown;
94
+ summaries?: Record<string, string>;
95
+ views: BaseView[];
96
+ };
97
+ declare function parseBase(path: string, source: string): BaseDefinition;
98
+ declare function validateBase(base: BaseDefinition): string[];
99
+ //#endregion
100
+ export { type BaseDefinition, type BaseGroupBy, type BasePropertyConfig, type BaseSort, type BaseView, type Expr, type FilterNode, type Token, type TokenType, lexExpression, parseBase, parseExpression, validateBase };
101
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,453 @@
1
+ import YAML from "yaml";
2
+ //#region src/expressions/lexer.ts
3
+ const OPERATORS = [
4
+ "==",
5
+ "!=",
6
+ "<=",
7
+ ">=",
8
+ "&&",
9
+ "||"
10
+ ];
11
+ const SINGLE = new Set([
12
+ "!",
13
+ "<",
14
+ ">",
15
+ "+",
16
+ "-",
17
+ "*",
18
+ "%"
19
+ ]);
20
+ const PUNCT = new Set([
21
+ "(",
22
+ ")",
23
+ "[",
24
+ "]",
25
+ ".",
26
+ ","
27
+ ]);
28
+ function lexExpression(source) {
29
+ const tokens = [];
30
+ let index = 0;
31
+ while (index < source.length) {
32
+ const char = source[index] ?? "";
33
+ if (/\s/u.test(char)) {
34
+ index += 1;
35
+ continue;
36
+ }
37
+ const two = source.slice(index, index + 2);
38
+ if (OPERATORS.includes(two)) {
39
+ tokens.push({
40
+ type: "operator",
41
+ lexeme: two
42
+ });
43
+ index += 2;
44
+ continue;
45
+ }
46
+ if (SINGLE.has(char)) {
47
+ tokens.push({
48
+ type: "operator",
49
+ lexeme: char
50
+ });
51
+ index += 1;
52
+ continue;
53
+ }
54
+ if (PUNCT.has(char)) {
55
+ tokens.push({
56
+ type: "punct",
57
+ lexeme: char
58
+ });
59
+ index += 1;
60
+ continue;
61
+ }
62
+ if (char === "\"" || char === "'") {
63
+ const parsed = readString(source, index, char);
64
+ tokens.push({
65
+ type: "string",
66
+ lexeme: parsed.raw,
67
+ value: parsed.value
68
+ });
69
+ index = parsed.next;
70
+ continue;
71
+ }
72
+ if (char === "/") {
73
+ if (expectsOperand(tokens[tokens.length - 1])) {
74
+ const parsed = readRegex(source, index);
75
+ tokens.push({
76
+ type: "regex",
77
+ lexeme: parsed.raw,
78
+ value: parsed.value
79
+ });
80
+ index = parsed.next;
81
+ continue;
82
+ }
83
+ tokens.push({
84
+ type: "operator",
85
+ lexeme: "/"
86
+ });
87
+ index += 1;
88
+ continue;
89
+ }
90
+ if (/\d/u.test(char)) {
91
+ const match = source.slice(index).match(/^\d+(?:\.\d+)?/u);
92
+ if (match) {
93
+ tokens.push({
94
+ type: "number",
95
+ lexeme: match[0],
96
+ value: Number(match[0])
97
+ });
98
+ index += match[0].length;
99
+ continue;
100
+ }
101
+ }
102
+ if (/[A-Za-z_]/u.test(char)) {
103
+ const match = source.slice(index).match(/^[A-Za-z_][A-Za-z0-9_-]*/u);
104
+ if (match) {
105
+ tokens.push({
106
+ type: "identifier",
107
+ lexeme: match[0]
108
+ });
109
+ index += match[0].length;
110
+ continue;
111
+ }
112
+ }
113
+ throw new Error(`Unexpected token near "${source.slice(index)}"`);
114
+ }
115
+ tokens.push({
116
+ type: "eof",
117
+ lexeme: ""
118
+ });
119
+ return tokens;
120
+ }
121
+ /**
122
+ * Returns true if the previous token implies the next token should be
123
+ * an operand (value), making a leading `/` a regex literal rather than
124
+ * the division operator.
125
+ */
126
+ function expectsOperand(prev) {
127
+ if (!prev || prev.type === "eof") return true;
128
+ if (prev.type === "operator") return true;
129
+ if (prev.type === "punct") return prev.lexeme === "(" || prev.lexeme === "[" || prev.lexeme === ",";
130
+ return false;
131
+ }
132
+ function readRegex(source, start) {
133
+ let index = start + 1;
134
+ let pattern = "";
135
+ let inCharClass = false;
136
+ while (index < source.length) {
137
+ const char = source[index] ?? "";
138
+ if (char === "\\") {
139
+ pattern += source.slice(index, index + 2);
140
+ index += 2;
141
+ continue;
142
+ }
143
+ if (char === "[") {
144
+ inCharClass = true;
145
+ pattern += char;
146
+ index += 1;
147
+ continue;
148
+ }
149
+ if (char === "]" && inCharClass) {
150
+ inCharClass = false;
151
+ pattern += char;
152
+ index += 1;
153
+ continue;
154
+ }
155
+ if (char === "/" && !inCharClass) {
156
+ const raw = source.slice(start, index + 1);
157
+ const flagStart = index + 1;
158
+ const flags = source.slice(flagStart).match(/^[gimsuy]*/u)?.[0] ?? "";
159
+ return {
160
+ raw: raw + flags,
161
+ value: {
162
+ pattern,
163
+ flags
164
+ },
165
+ next: flagStart + flags.length
166
+ };
167
+ }
168
+ pattern += char;
169
+ index += 1;
170
+ }
171
+ throw new Error("Unterminated regex literal");
172
+ }
173
+ function readString(source, start, quote) {
174
+ let value = "";
175
+ let index = start + 1;
176
+ while (index < source.length) {
177
+ const char = source[index] ?? "";
178
+ if (char === quote) return {
179
+ raw: source.slice(start, index + 1),
180
+ value,
181
+ next: index + 1
182
+ };
183
+ if (char === "\\") {
184
+ value += source[index + 1] ?? "";
185
+ index += 2;
186
+ continue;
187
+ }
188
+ value += char;
189
+ index += 1;
190
+ }
191
+ throw new Error("Unterminated string literal");
192
+ }
193
+ //#endregion
194
+ //#region src/expressions/parser.ts
195
+ const PRECEDENCE = new Map([
196
+ ["||", 1],
197
+ ["&&", 2],
198
+ ["==", 3],
199
+ ["!=", 3],
200
+ ["<", 4],
201
+ ["<=", 4],
202
+ [">", 4],
203
+ [">=", 4],
204
+ ["+", 5],
205
+ ["-", 5],
206
+ ["*", 6],
207
+ ["/", 6],
208
+ ["%", 6]
209
+ ]);
210
+ function parseExpression(source) {
211
+ return new Parser(lexExpression(source)).parse();
212
+ }
213
+ var Parser = class {
214
+ tokens;
215
+ #current = 0;
216
+ constructor(tokens) {
217
+ this.tokens = tokens;
218
+ }
219
+ parse() {
220
+ const expression = this.parseExpression(0);
221
+ this.consume("eof");
222
+ return expression;
223
+ }
224
+ parseExpression(minPrecedence) {
225
+ let left = this.parsePrefix();
226
+ while (this.peek().type === "operator") {
227
+ const operator = this.peek().lexeme;
228
+ const precedence = PRECEDENCE.get(operator);
229
+ if (precedence === void 0 || precedence < minPrecedence) break;
230
+ this.advance();
231
+ const right = this.parseExpression(precedence + 1);
232
+ left = {
233
+ kind: "binary",
234
+ left,
235
+ operator,
236
+ right
237
+ };
238
+ }
239
+ return left;
240
+ }
241
+ parsePrefix() {
242
+ if (this.match("operator", "!")) return {
243
+ kind: "unary",
244
+ operator: "!",
245
+ right: this.parsePrefix()
246
+ };
247
+ if (this.match("operator", "-")) return {
248
+ kind: "unary",
249
+ operator: "-",
250
+ right: this.parsePrefix()
251
+ };
252
+ return this.parsePostfix(this.parsePrimary());
253
+ }
254
+ parsePrimary() {
255
+ const token = this.advance();
256
+ if (token.type === "number" || token.type === "string") return {
257
+ kind: "literal",
258
+ value: token.value
259
+ };
260
+ if (token.type === "regex") {
261
+ const value = token.value;
262
+ return {
263
+ kind: "regex",
264
+ pattern: value.pattern,
265
+ flags: value.flags
266
+ };
267
+ }
268
+ if (token.type === "identifier") {
269
+ if (token.lexeme === "true") return {
270
+ kind: "literal",
271
+ value: true
272
+ };
273
+ if (token.lexeme === "false") return {
274
+ kind: "literal",
275
+ value: false
276
+ };
277
+ if (token.lexeme === "null") return {
278
+ kind: "literal",
279
+ value: null
280
+ };
281
+ return {
282
+ kind: "identifier",
283
+ name: token.lexeme
284
+ };
285
+ }
286
+ if (token.type === "punct" && token.lexeme === "[") {
287
+ const elements = [];
288
+ if (!this.check("punct", "]")) do
289
+ elements.push(this.parseExpression(0));
290
+ while (this.match("punct", ","));
291
+ this.consume("punct", "]");
292
+ return {
293
+ kind: "array",
294
+ elements
295
+ };
296
+ }
297
+ if (token.type === "punct" && token.lexeme === "(") {
298
+ const expression = this.parseExpression(0);
299
+ this.consume("punct", ")");
300
+ return expression;
301
+ }
302
+ throw new Error(`Expected expression near "${token.lexeme}"`);
303
+ }
304
+ parsePostfix(expression) {
305
+ let current = expression;
306
+ while (true) {
307
+ if (this.match("punct", ".")) {
308
+ const property = this.consume("identifier").lexeme;
309
+ current = {
310
+ kind: "member",
311
+ object: current,
312
+ property
313
+ };
314
+ continue;
315
+ }
316
+ if (this.match("punct", "[")) {
317
+ const index = this.parseExpression(0);
318
+ this.consume("punct", "]");
319
+ current = {
320
+ kind: "index",
321
+ object: current,
322
+ index
323
+ };
324
+ continue;
325
+ }
326
+ if (this.match("punct", "(")) {
327
+ const args = [];
328
+ if (!this.check("punct", ")")) do
329
+ args.push(this.parseExpression(0));
330
+ while (this.match("punct", ","));
331
+ this.consume("punct", ")");
332
+ current = {
333
+ kind: "call",
334
+ callee: current,
335
+ args
336
+ };
337
+ continue;
338
+ }
339
+ return current;
340
+ }
341
+ }
342
+ match(type, lexeme) {
343
+ if (!this.check(type, lexeme)) return false;
344
+ this.advance();
345
+ return true;
346
+ }
347
+ consume(type, lexeme) {
348
+ if (!this.check(type, lexeme)) throw new Error(`Expected ${lexeme ?? type}, got "${this.peek().lexeme}"`);
349
+ return this.advance();
350
+ }
351
+ check(type, lexeme) {
352
+ const token = this.peek();
353
+ return token.type === type && (lexeme === void 0 || token.lexeme === lexeme);
354
+ }
355
+ advance() {
356
+ const token = this.peek();
357
+ this.#current += 1;
358
+ return token;
359
+ }
360
+ peek() {
361
+ return this.tokens[this.#current] ?? {
362
+ type: "eof",
363
+ lexeme: ""
364
+ };
365
+ }
366
+ };
367
+ //#endregion
368
+ //#region src/parser.ts
369
+ function parseBase(path, source) {
370
+ const parsed = YAML.parse(source);
371
+ if (!isRecord(parsed)) throw new Error("Base file must contain a YAML object");
372
+ return {
373
+ path,
374
+ source: parsed,
375
+ properties: parseProperties(parsed.properties),
376
+ formulas: parseFormulas(parsed.formulas),
377
+ filters: parsed.filters,
378
+ summaries: parseSummaries(parsed.summaries),
379
+ views: parseViews(parsed.views)
380
+ };
381
+ }
382
+ function validateBase(base) {
383
+ const errors = [];
384
+ if (!Array.isArray(base.source.views)) errors.push("views must be a list");
385
+ for (const [index, view] of base.views.entries()) {
386
+ if (!view.name) errors.push(`views[${index}].name is required`);
387
+ if (!view.type) errors.push(`views[${index}].type is required`);
388
+ }
389
+ return errors;
390
+ }
391
+ function parseProperties(value) {
392
+ if (!isRecord(value)) return {};
393
+ const properties = {};
394
+ for (const [name, config] of Object.entries(value)) properties[name] = isRecord(config) ? { displayName: stringValue(config.displayName) } : {};
395
+ return properties;
396
+ }
397
+ function parseFormulas(value) {
398
+ if (!isRecord(value)) return {};
399
+ const formulas = {};
400
+ for (const [name, formula] of Object.entries(value)) formulas[name] = String(formula);
401
+ return formulas;
402
+ }
403
+ function parseSummaries(value) {
404
+ if (!isRecord(value)) return;
405
+ const summaries = {};
406
+ for (const [name, formula] of Object.entries(value)) summaries[name] = String(formula);
407
+ return summaries;
408
+ }
409
+ function parseViews(value) {
410
+ if (!Array.isArray(value)) return [];
411
+ return value.filter(isRecord).map((view) => ({
412
+ type: stringValue(view.type) ?? "table",
413
+ name: stringValue(view.name) ?? "",
414
+ filters: view.filters,
415
+ order: Array.isArray(view.order) ? view.order.map(String) : void 0,
416
+ sort: parseSort(view.sort),
417
+ limit: typeof view.limit === "number" ? view.limit : void 0,
418
+ groupBy: parseGroupBy(view.groupBy),
419
+ summaries: isRecord(view.summaries) ? view.summaries : void 0,
420
+ raw: view
421
+ }));
422
+ }
423
+ function parseGroupBy(value) {
424
+ if (!isRecord(value)) return;
425
+ const property = stringValue(value.property);
426
+ if (!property) return;
427
+ return {
428
+ property,
429
+ direction: value.direction === "DESC" ? "DESC" : "ASC"
430
+ };
431
+ }
432
+ function parseSort(value) {
433
+ if (!Array.isArray(value)) return;
434
+ const sort = value.filter(isRecord).flatMap((item) => {
435
+ const property = stringValue(item.property);
436
+ if (!property) return [];
437
+ return [{
438
+ property,
439
+ direction: item.direction === "DESC" ? "DESC" : "ASC"
440
+ }];
441
+ });
442
+ return sort.length > 0 ? sort : void 0;
443
+ }
444
+ function stringValue(value) {
445
+ return typeof value === "string" ? value : void 0;
446
+ }
447
+ function isRecord(value) {
448
+ return typeof value === "object" && value !== null && !Array.isArray(value);
449
+ }
450
+ //#endregion
451
+ export { lexExpression, parseBase, parseExpression, validateBase };
452
+
453
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["#current"],"sources":["../src/expressions/lexer.ts","../src/expressions/parser.ts","../src/parser.ts"],"sourcesContent":["export type TokenType =\n | \"identifier\"\n | \"number\"\n | \"string\"\n | \"regex\"\n | \"operator\"\n | \"punct\"\n | \"eof\";\n\nexport type Token = {\n type: TokenType;\n lexeme: string;\n value?: unknown;\n};\n\nconst OPERATORS = [\"==\", \"!=\", \"<=\", \">=\", \"&&\", \"||\"] as const;\nconst SINGLE = new Set([\"!\", \"<\", \">\", \"+\", \"-\", \"*\", \"%\"]);\nconst PUNCT = new Set([\"(\", \")\", \"[\", \"]\", \".\", \",\"]);\n\nexport function lexExpression(source: string): Token[] {\n const tokens: Token[] = [];\n let index = 0;\n\n while (index < source.length) {\n const char = source[index] ?? \"\";\n if (/\\s/u.test(char)) {\n index += 1;\n continue;\n }\n\n const two = source.slice(index, index + 2);\n if (OPERATORS.includes(two as (typeof OPERATORS)[number])) {\n tokens.push({ type: \"operator\", lexeme: two });\n index += 2;\n continue;\n }\n\n if (SINGLE.has(char)) {\n tokens.push({ type: \"operator\", lexeme: char });\n index += 1;\n continue;\n }\n\n if (PUNCT.has(char)) {\n tokens.push({ type: \"punct\", lexeme: char });\n index += 1;\n continue;\n }\n\n if (char === '\"' || char === \"'\") {\n const parsed = readString(source, index, char);\n tokens.push({ type: \"string\", lexeme: parsed.raw, value: parsed.value });\n index = parsed.next;\n continue;\n }\n\n // Regex literal vs division disambiguation:\n // / is a regex start when we expect an operand (beginning of expression,\n // after an operator, or after opening/separator punctuation).\n // Otherwise / is the division operator.\n if (char === \"/\") {\n if (expectsOperand(tokens[tokens.length - 1])) {\n const parsed = readRegex(source, index);\n tokens.push({\n type: \"regex\",\n lexeme: parsed.raw,\n value: parsed.value,\n });\n index = parsed.next;\n continue;\n }\n\n tokens.push({ type: \"operator\", lexeme: \"/\" });\n index += 1;\n continue;\n }\n\n if (/\\d/u.test(char)) {\n const match = source.slice(index).match(/^\\d+(?:\\.\\d+)?/u);\n if (match) {\n tokens.push({\n type: \"number\",\n lexeme: match[0],\n value: Number(match[0]),\n });\n index += match[0].length;\n continue;\n }\n }\n\n if (/[A-Za-z_]/u.test(char)) {\n const match = source.slice(index).match(/^[A-Za-z_][A-Za-z0-9_-]*/u);\n if (match) {\n tokens.push({ type: \"identifier\", lexeme: match[0] });\n index += match[0].length;\n continue;\n }\n }\n\n throw new Error(`Unexpected token near \"${source.slice(index)}\"`);\n }\n\n tokens.push({ type: \"eof\", lexeme: \"\" });\n return tokens;\n}\n\n/**\n * Returns true if the previous token implies the next token should be\n * an operand (value), making a leading `/` a regex literal rather than\n * the division operator.\n */\nfunction expectsOperand(prev?: Token): boolean {\n if (!prev || prev.type === \"eof\") return true;\n if (prev.type === \"operator\") return true;\n if (prev.type === \"punct\") {\n return prev.lexeme === \"(\" || prev.lexeme === \"[\" || prev.lexeme === \",\";\n }\n return false;\n}\n\nfunction readRegex(\n source: string,\n start: number,\n): { raw: string; value: { pattern: string; flags: string }; next: number } {\n let index = start + 1; // skip opening /\n let pattern = \"\";\n let inCharClass = false;\n\n while (index < source.length) {\n const char = source[index] ?? \"\";\n\n if (char === \"\\\\\") {\n // Escaped character inside regex -- consume both the backslash and\n // the following character so \\/ does not terminate the pattern.\n pattern += source.slice(index, index + 2);\n index += 2;\n continue;\n }\n\n if (char === \"[\") {\n inCharClass = true;\n pattern += char;\n index += 1;\n continue;\n }\n\n if (char === \"]\" && inCharClass) {\n inCharClass = false;\n pattern += char;\n index += 1;\n continue;\n }\n\n if (char === \"/\" && !inCharClass) {\n // Closing delimiter found.\n const raw = source.slice(start, index + 1);\n\n // Read optional flags after the closing /.\n const flagStart = index + 1;\n const flagMatch = source.slice(flagStart).match(/^[gimsuy]*/u);\n const flags = flagMatch?.[0] ?? \"\";\n\n return {\n raw: raw + flags,\n value: { pattern, flags },\n next: flagStart + flags.length,\n };\n }\n\n pattern += char;\n index += 1;\n }\n\n throw new Error(\"Unterminated regex literal\");\n}\n\nfunction readString(\n source: string,\n start: number,\n quote: string,\n): { raw: string; value: string; next: number } {\n let value = \"\";\n let index = start + 1;\n\n while (index < source.length) {\n const char = source[index] ?? \"\";\n if (char === quote) {\n return {\n raw: source.slice(start, index + 1),\n value,\n next: index + 1,\n };\n }\n\n if (char === \"\\\\\") {\n value += source[index + 1] ?? \"\";\n index += 2;\n continue;\n }\n\n value += char;\n index += 1;\n }\n\n throw new Error(\"Unterminated string literal\");\n}\n","import type { Expr } from \"./ast\";\nimport { lexExpression, type Token } from \"./lexer\";\n\nconst PRECEDENCE = new Map([\n [\"||\", 1],\n [\"&&\", 2],\n [\"==\", 3],\n [\"!=\", 3],\n [\"<\", 4],\n [\"<=\", 4],\n [\">\", 4],\n [\">=\", 4],\n [\"+\", 5],\n [\"-\", 5],\n [\"*\", 6],\n [\"/\", 6],\n [\"%\", 6],\n]);\n\nexport function parseExpression(source: string): Expr {\n return new Parser(lexExpression(source)).parse();\n}\n\nclass Parser {\n #current = 0;\n\n constructor(private readonly tokens: Token[]) {}\n\n parse(): Expr {\n const expression = this.parseExpression(0);\n this.consume(\"eof\");\n return expression;\n }\n\n private parseExpression(minPrecedence: number): Expr {\n let left = this.parsePrefix();\n\n while (this.peek().type === \"operator\") {\n const operator = this.peek().lexeme;\n const precedence = PRECEDENCE.get(operator);\n if (precedence === undefined || precedence < minPrecedence) {\n break;\n }\n\n this.advance();\n const right = this.parseExpression(precedence + 1);\n left = { kind: \"binary\", left, operator, right };\n }\n\n return left;\n }\n\n private parsePrefix(): Expr {\n if (this.match(\"operator\", \"!\")) {\n return { kind: \"unary\", operator: \"!\", right: this.parsePrefix() };\n }\n\n if (this.match(\"operator\", \"-\")) {\n return { kind: \"unary\", operator: \"-\", right: this.parsePrefix() };\n }\n\n return this.parsePostfix(this.parsePrimary());\n }\n\n private parsePrimary(): Expr {\n const token = this.advance();\n\n if (token.type === \"number\" || token.type === \"string\") {\n return { kind: \"literal\", value: token.value };\n }\n\n if (token.type === \"regex\") {\n const value = token.value as { pattern: string; flags: string };\n return { kind: \"regex\", pattern: value.pattern, flags: value.flags };\n }\n\n if (token.type === \"identifier\") {\n if (token.lexeme === \"true\") {\n return { kind: \"literal\", value: true };\n }\n if (token.lexeme === \"false\") {\n return { kind: \"literal\", value: false };\n }\n if (token.lexeme === \"null\") {\n return { kind: \"literal\", value: null };\n }\n return { kind: \"identifier\", name: token.lexeme };\n }\n\n // Array literal: [expr, expr, ...]\n if (token.type === \"punct\" && token.lexeme === \"[\") {\n const elements: Expr[] = [];\n if (!this.check(\"punct\", \"]\")) {\n do {\n elements.push(this.parseExpression(0));\n } while (this.match(\"punct\", \",\"));\n }\n this.consume(\"punct\", \"]\");\n return { kind: \"array\", elements };\n }\n\n if (token.type === \"punct\" && token.lexeme === \"(\") {\n const expression = this.parseExpression(0);\n this.consume(\"punct\", \")\");\n return expression;\n }\n\n throw new Error(`Expected expression near \"${token.lexeme}\"`);\n }\n\n private parsePostfix(expression: Expr): Expr {\n let current = expression;\n\n while (true) {\n if (this.match(\"punct\", \".\")) {\n const property = this.consume(\"identifier\").lexeme;\n current = { kind: \"member\", object: current, property };\n continue;\n }\n\n if (this.match(\"punct\", \"[\")) {\n const index = this.parseExpression(0);\n this.consume(\"punct\", \"]\");\n current = { kind: \"index\", object: current, index };\n continue;\n }\n\n if (this.match(\"punct\", \"(\")) {\n const args: Expr[] = [];\n if (!this.check(\"punct\", \")\")) {\n do {\n args.push(this.parseExpression(0));\n } while (this.match(\"punct\", \",\"));\n }\n this.consume(\"punct\", \")\");\n current = { kind: \"call\", callee: current, args };\n continue;\n }\n\n return current;\n }\n }\n\n private match(type: Token[\"type\"], lexeme?: string): boolean {\n if (!this.check(type, lexeme)) {\n return false;\n }\n this.advance();\n return true;\n }\n\n private consume(type: Token[\"type\"], lexeme?: string): Token {\n if (!this.check(type, lexeme)) {\n throw new Error(\n `Expected ${lexeme ?? type}, got \"${this.peek().lexeme}\"`,\n );\n }\n\n return this.advance();\n }\n\n private check(type: Token[\"type\"], lexeme?: string): boolean {\n const token = this.peek();\n return (\n token.type === type && (lexeme === undefined || token.lexeme === lexeme)\n );\n }\n\n private advance(): Token {\n const token = this.peek();\n this.#current += 1;\n return token;\n }\n\n private peek(): Token {\n return this.tokens[this.#current] ?? { type: \"eof\", lexeme: \"\" };\n }\n}\n","import YAML from \"yaml\";\n\nexport type BasePropertyConfig = {\n displayName?: string;\n};\n\nexport type BaseSort = {\n property: string;\n direction?: \"ASC\" | \"DESC\";\n};\n\nexport type BaseGroupBy = {\n property: string;\n direction?: \"ASC\" | \"DESC\";\n};\n\nexport type BaseView = {\n type: string;\n name: string;\n filters?: unknown;\n order?: string[];\n sort?: BaseSort[];\n limit?: number;\n groupBy?: BaseGroupBy;\n summaries?: Record<string, unknown>;\n raw: Record<string, unknown>;\n};\n\nexport type BaseDefinition = {\n path: string;\n source: Record<string, unknown>;\n properties: Record<string, BasePropertyConfig>;\n formulas: Record<string, string>;\n filters?: unknown;\n summaries?: Record<string, string>;\n views: BaseView[];\n};\n\nexport function parseBase(path: string, source: string): BaseDefinition {\n const parsed = YAML.parse(source) as unknown;\n if (!isRecord(parsed)) {\n throw new Error(\"Base file must contain a YAML object\");\n }\n\n return {\n path,\n source: parsed,\n properties: parseProperties(parsed.properties),\n formulas: parseFormulas(parsed.formulas),\n filters: parsed.filters,\n summaries: parseSummaries(parsed.summaries),\n views: parseViews(parsed.views),\n };\n}\n\nexport function validateBase(base: BaseDefinition): string[] {\n const errors: string[] = [];\n\n if (!Array.isArray(base.source.views)) {\n errors.push(\"views must be a list\");\n }\n\n for (const [index, view] of base.views.entries()) {\n if (!view.name) {\n errors.push(`views[${index}].name is required`);\n }\n if (!view.type) {\n errors.push(`views[${index}].type is required`);\n }\n }\n\n return errors;\n}\n\nfunction parseProperties(value: unknown): Record<string, BasePropertyConfig> {\n if (!isRecord(value)) {\n return {};\n }\n\n const properties: Record<string, BasePropertyConfig> = {};\n for (const [name, config] of Object.entries(value)) {\n properties[name] = isRecord(config)\n ? { displayName: stringValue(config.displayName) }\n : {};\n }\n\n return properties;\n}\n\nfunction parseFormulas(value: unknown): Record<string, string> {\n if (!isRecord(value)) {\n return {};\n }\n\n const formulas: Record<string, string> = {};\n for (const [name, formula] of Object.entries(value)) {\n formulas[name] = String(formula);\n }\n\n return formulas;\n}\n\nfunction parseSummaries(value: unknown): Record<string, string> | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n\n const summaries: Record<string, string> = {};\n for (const [name, formula] of Object.entries(value)) {\n summaries[name] = String(formula);\n }\n\n return summaries;\n}\n\nfunction parseViews(value: unknown): BaseView[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value.filter(isRecord).map((view) => ({\n type: stringValue(view.type) ?? \"table\",\n name: stringValue(view.name) ?? \"\",\n filters: view.filters,\n order: Array.isArray(view.order) ? view.order.map(String) : undefined,\n sort: parseSort(view.sort),\n limit: typeof view.limit === \"number\" ? view.limit : undefined,\n groupBy: parseGroupBy(view.groupBy),\n summaries: isRecord(view.summaries) ? view.summaries : undefined,\n raw: view,\n }));\n}\n\nfunction parseGroupBy(value: unknown): BaseGroupBy | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n\n const property = stringValue(value.property);\n if (!property) {\n return undefined;\n }\n\n return {\n property,\n direction: value.direction === \"DESC\" ? \"DESC\" : \"ASC\",\n };\n}\n\nfunction parseSort(value: unknown): BaseSort[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const sort = value.filter(isRecord).flatMap((item) => {\n const property = stringValue(item.property);\n if (!property) {\n return [];\n }\n\n return [\n {\n property,\n direction: item.direction === \"DESC\" ? \"DESC\" : \"ASC\",\n } satisfies BaseSort,\n ];\n });\n\n return sort.length > 0 ? sort : undefined;\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@aliou/obsdx-base-ast",
3
+ "version": "0.0.1",
4
+ "description": "Obsidian Base syntax parsing for obsdx",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.mts",
10
+ "import": "./dist/index.mjs"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist/index.d.mts",
15
+ "dist/index.mjs",
16
+ "dist/index.mjs.map"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/aliou/obsdx",
21
+ "directory": "packages/base-ast"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "engines": {
27
+ "node": ">=25.7.0"
28
+ },
29
+ "dependencies": {
30
+ "yaml": "^2.7.0"
31
+ }
32
+ }