@monimesl/dot-script-parser 0.1.0-alpha.2

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/README.md ADDED
@@ -0,0 +1 @@
1
+ # @monimesl/dot-script-parser
@@ -0,0 +1,80 @@
1
+ import "oxc-parser";
2
+ import { SourceError } from "@monimesl/dot-core";
3
+ //#region src/globals.d.ts
4
+ /**
5
+ * Which of `names` a module reads without declaring or importing them at its top level. The
6
+ * compiler imports those for the module, so a dot's code can use framework functions as globals.
7
+ */
8
+ export declare function unboundReferences(source: string, names: readonly string[], file?: string): string[];
9
+ //#endregion
10
+ //#region src/dot.d.ts
11
+ interface DotModuleIR {
12
+ /** Page folders under `pages/`, in order; the first is where the dot starts. */
13
+ readonly pages: readonly string[];
14
+ }
15
+ /** Reads `export default defineDot({ pages: [...] })`. The pages must be string literals. */
16
+ export declare function parseDotModule(source: string, file?: string): DotModuleIR;
17
+ //#endregion
18
+ //#region src/errors.d.ts
19
+ export declare class ScriptParseError extends SourceError {
20
+ readonly name = "ScriptParseError";
21
+ }
22
+ //#endregion
23
+ //#region src/ast/expression/types.d.ts
24
+ declare const UNARY_OPERATORS: readonly ["!", "-", "+", "typeof"];
25
+ declare const BINARY_OPERATORS: readonly ["==", "!=", "===", "!==", "<", "<=", ">", ">=", "+", "-", "*", "/", "%", "**", "&&", "||", "??"];
26
+ type LiteralValue = string | number | boolean | null;
27
+ type LiteralNode = {
28
+ readonly type: 'Literal';
29
+ readonly value: LiteralValue;
30
+ };
31
+ type IdentifierNode = {
32
+ readonly type: 'Identifier';
33
+ readonly name: string;
34
+ };
35
+ type MemberNode = {
36
+ readonly type: 'Member';
37
+ readonly object: ExprNode;
38
+ readonly property: ExprNode;
39
+ };
40
+ type UnaryOperator = (typeof UNARY_OPERATORS)[number];
41
+ type UnaryExprNode = {
42
+ readonly type: 'Unary';
43
+ readonly operator: UnaryOperator;
44
+ readonly argument: ExprNode;
45
+ };
46
+ type BinaryOperator = (typeof BINARY_OPERATORS)[number];
47
+ type BinaryExprNode = {
48
+ readonly type: 'Binary';
49
+ readonly operator: BinaryOperator;
50
+ readonly left: ExprNode;
51
+ readonly right: ExprNode;
52
+ };
53
+ type ConditionalExprNode = {
54
+ readonly type: 'Conditional';
55
+ readonly test: ExprNode;
56
+ readonly consequent: ExprNode;
57
+ readonly alternate: ExprNode;
58
+ };
59
+ type ExprNode = LiteralNode | IdentifierNode | MemberNode | UnaryExprNode | BinaryExprNode | ConditionalExprNode;
60
+ //#endregion
61
+ //#region src/ast/expression/parse.d.ts
62
+ export declare function parseExpression(source: string): ExprNode;
63
+ //#endregion
64
+ //#region src/ast/page/types.d.ts
65
+ interface PageStateModule {
66
+ readonly keys: readonly string[] | null;
67
+ }
68
+ interface PageModule {
69
+ readonly id: string | null;
70
+ readonly hooks: readonly string[];
71
+ readonly mutations: readonly string[] | null;
72
+ readonly actions: readonly string[] | null;
73
+ }
74
+ //#endregion
75
+ //#region src/ast/page/parse.d.ts
76
+ export declare function parseStateModule(source: string, file?: string): PageStateModule;
77
+ export declare function parseLogicModule(source: string, file?: string): PageModule;
78
+ //#endregion
79
+ export type { BinaryOperator, DotModuleIR, ExprNode, LiteralValue, PageModule, PageStateModule, UnaryOperator };
80
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/globals.ts","../src/dot.ts","../src/errors.ts","../src/ast/expression/types.ts","../src/ast/expression/parse.ts","../src/ast/page/types.ts","../src/ast/page/parse.ts"],"mappings":";;;;;;;wBAcgB,kBACd,gBACA,0BACA;;;UCZe;;WAEN;;;wBAIK,eAAe,gBAAgB,gBAAkB;;;qBCRpD,yBAAyB;WAClB;;;;cCJP;cAEA;KAoBD;KAEA;WAAyB;WAA0B,OAAO;;KAE1D;WAA4B;WAA6B;;KAEzD;WACD;WACA,QAAQ;WACR,UAAU;;KAGT,wBAAwB;KAExB;WACD;WACA,UAAU;WACV,UAAU;;KAGT,yBAAyB;KAEzB;WACD;WACA,UAAU;WACV,MAAM;WACN,OAAO;;KAGN;WACD;WACA,MAAM;WACN,YAAY;WACZ,WAAW;;KAGV,WACV,cAAc,iBAAiB,aAAa,gBAAgB,iBAAiB;;;wBCpD/D,gBAAgB,iBAAiB;;;UCPhC;WAEN;;UAGM;WACN;WACA;WACA;WACA;;;;wBCCK,iBAAiB,gBAAgB,gBAAoB;wBASrD,iBAAiB,gBAAgB,gBAAyB"}
package/dist/index.js ADDED
@@ -0,0 +1,345 @@
1
+ import { parseSync } from "oxc-parser";
2
+ import { PAGE_HOOKS, SourceError, isPageId, locationAt } from "@monimesl/dot-core";
3
+ //#region src/errors.ts
4
+ var ScriptParseError = class extends SourceError {
5
+ name = "ScriptParseError";
6
+ };
7
+ function failAt(reason, source, offset, file) {
8
+ throw new ScriptParseError(reason, file, locationAt(source, offset));
9
+ }
10
+ function failOnSyntaxError(errors, source, file) {
11
+ const [error] = errors;
12
+ if (error) failAt(error.message, source, error.labels[0]?.start ?? 0, file);
13
+ }
14
+ //#endregion
15
+ //#region src/utils.ts
16
+ function propertyName(key) {
17
+ if (key.type === "Identifier") return key.name;
18
+ if (key.type === "Literal" && typeof key.value === "string") return key.value;
19
+ return null;
20
+ }
21
+ function unwrapExpression(node) {
22
+ while (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression" || node.type === "TSNonNullExpression") node = node.expression;
23
+ return node;
24
+ }
25
+ function staticProperties(object) {
26
+ const properties = [];
27
+ for (const property of object.properties) {
28
+ if (property.type !== "Property" || property.computed) continue;
29
+ const name = propertyName(property.key);
30
+ if (name !== null) properties.push({
31
+ name,
32
+ value: property.value,
33
+ start: property.start
34
+ });
35
+ }
36
+ return properties;
37
+ }
38
+ function withoutExport(statement) {
39
+ if (statement.type === "ExportNamedDeclaration") return statement.declaration;
40
+ return statement;
41
+ }
42
+ //#endregion
43
+ //#region src/module.ts
44
+ function parseModule(source, file) {
45
+ let lang = "ts";
46
+ if (file.endsWith(".tsx") || file.endsWith(".jsx")) lang = "tsx";
47
+ const { program, errors } = parseSync(file, source, {
48
+ lang,
49
+ sourceType: "module"
50
+ });
51
+ failOnSyntaxError(errors, source, file);
52
+ return program;
53
+ }
54
+ function defaultExport(program) {
55
+ for (const statement of program.body) {
56
+ if (statement.type !== "ExportDefaultDeclaration") continue;
57
+ const { declaration } = statement;
58
+ switch (declaration.type) {
59
+ case "FunctionDeclaration":
60
+ case "ClassDeclaration":
61
+ case "TSInterfaceDeclaration": return;
62
+ default: return declaration;
63
+ }
64
+ }
65
+ }
66
+ function defineCall(program, source, file, callee) {
67
+ const exported = defaultExport(program);
68
+ const call = exported && unwrapExpression(exported);
69
+ const options = call?.type === "CallExpression" ? call.arguments[0] : void 0;
70
+ if (call?.type !== "CallExpression" || call.callee.type !== "Identifier" || call.callee.name !== callee || options?.type !== "ObjectExpression") return failAt(`${fileName(file)} must \`export default ${callee}({ ... })\``, source, exported?.start ?? 0, file);
71
+ return options;
72
+ }
73
+ function fileName(path) {
74
+ const lastSeparator = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
75
+ return path.slice(lastSeparator + 1);
76
+ }
77
+ //#endregion
78
+ //#region src/globals.ts
79
+ /**
80
+ * Which of `names` a module reads without declaring or importing them at its top level. The
81
+ * compiler imports those for the module, so a dot's code can use framework functions as globals.
82
+ */
83
+ function unboundReferences(source, names, file = "module.ts") {
84
+ const program = parseModule(source, file);
85
+ const bound = topLevelBindings(program);
86
+ const references = /* @__PURE__ */ new Set();
87
+ collectReferences(program, null, "", references);
88
+ return names.filter((name) => references.has(name) && !bound.has(name));
89
+ }
90
+ function topLevelBindings(program) {
91
+ const names = /* @__PURE__ */ new Set();
92
+ for (const statement of program.body) {
93
+ const declaration = withoutExport(statement);
94
+ switch (declaration?.type) {
95
+ case "ImportDeclaration":
96
+ declaration.specifiers.forEach((specifier) => names.add(specifier.local.name));
97
+ break;
98
+ case "VariableDeclaration":
99
+ declaration.declarations.forEach((declarator) => collectPatternNames(declarator.id, names));
100
+ break;
101
+ case "FunctionDeclaration":
102
+ case "ClassDeclaration": if (declaration.id) names.add(declaration.id.name);
103
+ }
104
+ }
105
+ return names;
106
+ }
107
+ function collectPatternNames(pattern, names) {
108
+ const visit = (child) => {
109
+ if (isNode(child)) collectPatternNames(child, names);
110
+ };
111
+ switch (pattern.type) {
112
+ case "Identifier":
113
+ names.add(pattern.name);
114
+ break;
115
+ case "ObjectPattern":
116
+ pattern.properties.forEach((property) => visit(property.type === "RestElement" ? property.argument : property.value));
117
+ break;
118
+ case "ArrayPattern":
119
+ pattern.elements.forEach(visit);
120
+ break;
121
+ case "RestElement":
122
+ visit(pattern.argument);
123
+ break;
124
+ case "AssignmentPattern": visit(pattern.left);
125
+ }
126
+ }
127
+ function collectReferences(node, parent, key, out) {
128
+ if (node.type === "ImportDeclaration") return;
129
+ if (node.type === "Identifier" && isReference(parent, key)) out.add(node.name);
130
+ for (const [childKey, value] of Object.entries(node)) for (const child of Array.isArray(value) ? value : [value]) if (isNode(child)) collectReferences(child, node, childKey, out);
131
+ }
132
+ /** False for identifiers that name a property or label rather than refer to a variable. */
133
+ function isReference(parent, key) {
134
+ switch (parent?.type) {
135
+ case "MemberExpression": return key !== "property" || parent.computed === true;
136
+ case "Property":
137
+ case "MethodDefinition":
138
+ case "PropertyDefinition": return key !== "key" || parent.computed === true;
139
+ case "LabeledStatement":
140
+ case "BreakStatement":
141
+ case "ContinueStatement": return key !== "label";
142
+ default: return true;
143
+ }
144
+ }
145
+ function isNode(value) {
146
+ return typeof value?.type === "string";
147
+ }
148
+ //#endregion
149
+ //#region src/ast/page/parse.ts
150
+ const HOOKS = new Set(PAGE_HOOKS);
151
+ function parseStateModule(source, file = "state.ts") {
152
+ const program = parseModule(source, file);
153
+ const exported = defaultExport(program);
154
+ if (!exported) return failAt("state.ts must have a default export", source, 0, file);
155
+ return { keys: resolvedKeys(program, exported) };
156
+ }
157
+ function parseLogicModule(source, file = "controller.ts") {
158
+ const program = parseModule(source, file);
159
+ const options = defineCall(program, source, file, "definePage");
160
+ let id = null;
161
+ let mutations = [];
162
+ let actions = [];
163
+ const hooks = [];
164
+ for (const { name, value, start } of staticProperties(options)) switch (name) {
165
+ case "initialState": break;
166
+ case "id":
167
+ id = pageId(value, source, file);
168
+ break;
169
+ case "hooks":
170
+ if (value.type !== "ObjectExpression") break;
171
+ for (const hook of staticProperties(value)) {
172
+ if (!HOOKS.has(hook.name)) failAt(`Unknown page hook \`${hook.name}\`. Page hooks: ${PAGE_HOOKS.join(", ")}`, source, hook.start, file);
173
+ hooks.push(hook.name);
174
+ }
175
+ break;
176
+ case "mutations":
177
+ mutations = resolvedKeys(program, value);
178
+ break;
179
+ case "actions":
180
+ actions = resolvedKeys(program, value);
181
+ break;
182
+ default: if (isFunction(value)) failAt(`\`${name}\` must go in \`mutations\` or \`actions\``, source, start, file);
183
+ else failAt(`Unknown option \`${name}\`. definePage takes id, initialState, hooks, mutations and actions`, source, start, file);
184
+ }
185
+ const clash = mutations?.find((name) => actions?.includes(name));
186
+ if (clash) failAt(`\`${clash}\` is both a mutation and an action`, source, options.start, file);
187
+ return {
188
+ id,
189
+ mutations,
190
+ actions,
191
+ hooks
192
+ };
193
+ }
194
+ function isFunction(node) {
195
+ return node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
196
+ }
197
+ function resolvedKeys(program, node) {
198
+ const object = resolveObject(program, node);
199
+ if (!object) return null;
200
+ return staticKeys(object);
201
+ }
202
+ /** Follows `export default state` back to `const state = { ... }`. */
203
+ function resolveObject(program, node) {
204
+ const target = unwrapExpression(node);
205
+ if (target.type === "ObjectExpression") return target;
206
+ if (target.type !== "Identifier") return null;
207
+ for (const statement of program.body) {
208
+ const declaration = withoutExport(statement);
209
+ if (declaration?.type !== "VariableDeclaration" || declaration.kind !== "const") continue;
210
+ for (const declarator of declaration.declarations) if (declarator.id.type === "Identifier" && declarator.id.name === target.name) return declarator.init ? resolveObject(program, declarator.init) : null;
211
+ }
212
+ return null;
213
+ }
214
+ function staticKeys(object) {
215
+ const properties = staticProperties(object);
216
+ if (properties.length !== object.properties.length) return null;
217
+ return properties.map((property) => property.name);
218
+ }
219
+ /** Reads a page id, which must be a string literal made of safe characters. */
220
+ function pageId(node, source, file) {
221
+ const value = unwrapExpression(node);
222
+ if (value.type !== "Literal" || typeof value.value !== "string") return failAt("A page id must be a string literal", source, node.start, file);
223
+ if (!isPageId(value.value)) return failAt(`Invalid page id "${value.value}". Use letters, digits, "-" and "_", with "/" between segments`, source, node.start, file);
224
+ return value.value;
225
+ }
226
+ //#endregion
227
+ //#region src/dot.ts
228
+ /** Reads `export default defineDot({ pages: [...] })`. The pages must be string literals. */
229
+ function parseDotModule(source, file = "dot.ts") {
230
+ const options = defineCall(parseModule(source, file), source, file, "defineDot");
231
+ const pagesProperty = staticProperties(options).find((property) => property.name === "pages");
232
+ if (!pagesProperty) return failAt("defineDot needs `pages`: the dot's page folders, starting page first", source, options.start, file);
233
+ const { value, start } = pagesProperty;
234
+ const array = unwrapExpression(value);
235
+ if (array.type !== "ArrayExpression") return failAt("`pages` must be an array of page folders", source, start, file);
236
+ if (array.elements.length === 0) return failAt("`pages` needs at least one page", source, start, file);
237
+ return { pages: array.elements.map((element) => {
238
+ if (!element || element.type === "SpreadElement") return failAt("`pages` must list each page folder as a string", source, element?.start ?? start, file);
239
+ return pageId(element, source, file);
240
+ }) };
241
+ }
242
+ //#endregion
243
+ //#region src/ast/expression/types.ts
244
+ const UNARY_OPERATORS = [
245
+ "!",
246
+ "-",
247
+ "+",
248
+ "typeof"
249
+ ];
250
+ const BINARY_OPERATORS = [
251
+ "==",
252
+ "!=",
253
+ "===",
254
+ "!==",
255
+ "<",
256
+ "<=",
257
+ ">",
258
+ ">=",
259
+ "+",
260
+ "-",
261
+ "*",
262
+ "/",
263
+ "%",
264
+ "**",
265
+ "&&",
266
+ "||",
267
+ "??"
268
+ ];
269
+ //#endregion
270
+ //#region src/ast/expression/parse.ts
271
+ function parseExpression(source) {
272
+ if (source.trim().length === 0) failAt("Empty expression", source, 0);
273
+ const { program, errors } = parseSync("binding.js", source, { preserveParens: false });
274
+ failOnSyntaxError(errors, source);
275
+ const [statement, extra] = program.body;
276
+ if (!statement || extra || statement.type !== "ExpressionStatement") return failAt("Expected a single expression statement", source, statement?.start ?? 0);
277
+ return convert(statement.expression, source);
278
+ }
279
+ function convert(node, source) {
280
+ switch (node.type) {
281
+ case "Literal":
282
+ if (typeof node.value === "bigint" || node.value instanceof RegExp) break;
283
+ return {
284
+ type: "Literal",
285
+ value: node.value
286
+ };
287
+ case "Identifier": return {
288
+ type: "Identifier",
289
+ name: node.name
290
+ };
291
+ case "MemberExpression": {
292
+ if (node.object.type === "Super" || node.property.type === "PrivateIdentifier") break;
293
+ const object = convert(node.object, source);
294
+ if (node.computed) return {
295
+ type: "Member",
296
+ object,
297
+ property: convert(node.property, source)
298
+ };
299
+ return {
300
+ type: "Member",
301
+ object,
302
+ property: {
303
+ type: "Literal",
304
+ value: node.property.name
305
+ }
306
+ };
307
+ }
308
+ case "UnaryExpression":
309
+ if (!isOneOf(UNARY_OPERATORS, node.operator)) break;
310
+ return {
311
+ type: "Unary",
312
+ operator: node.operator,
313
+ argument: convert(node.argument, source)
314
+ };
315
+ case "BinaryExpression":
316
+ case "LogicalExpression":
317
+ if (node.left.type === "PrivateIdentifier" || !isOneOf(BINARY_OPERATORS, node.operator)) break;
318
+ return {
319
+ type: "Binary",
320
+ operator: node.operator,
321
+ left: convert(node.left, source),
322
+ right: convert(node.right, source)
323
+ };
324
+ case "ConditionalExpression": return {
325
+ type: "Conditional",
326
+ test: convert(node.test, source),
327
+ consequent: convert(node.consequent, source),
328
+ alternate: convert(node.alternate, source)
329
+ };
330
+ case "CallExpression":
331
+ case "NewExpression": return failAt("Function calls are currently not allowed in bindings", source, node.start);
332
+ case "AssignmentExpression":
333
+ case "UpdateExpression": return failAt("Update expressions are currently not allowed in bindings", source, node.start);
334
+ }
335
+ let detail = "";
336
+ if ("operator" in node) detail = ` \`${node.operator}\``;
337
+ return failAt(`Unsupported syntax in binding: ${node.type}${detail}`, source, node.start);
338
+ }
339
+ function isOneOf(list, value) {
340
+ return list.includes(value);
341
+ }
342
+ //#endregion
343
+ export { ScriptParseError, parseDotModule, parseExpression, parseLogicModule, parseStateModule, unboundReferences };
344
+
345
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/utils.ts","../src/module.ts","../src/globals.ts","../src/ast/page/parse.ts","../src/dot.ts","../src/ast/expression/types.ts","../src/ast/expression/parse.ts"],"sourcesContent":["import type { OxcError } from 'oxc-parser';\nimport { locationAt, SourceError } from '@monimesl/dot-core';\n\nexport class ScriptParseError extends SourceError {\n override readonly name = 'ScriptParseError';\n}\n\nexport function failAt(reason: string, source: string, offset: number, file?: string): never {\n throw new ScriptParseError(reason, file, locationAt(source, offset));\n}\n\nexport function failOnSyntaxError(\n errors: readonly OxcError[],\n source: string,\n file?: string,\n): void {\n const [error] = errors;\n if (error) {\n failAt(error.message, source, error.labels[0]?.start ?? 0, file);\n }\n}\n","import type { Expression, ObjectExpression, Program, PropertyKey } from 'oxc-parser';\n\ntype TopLevelStatement = Program['body'][number];\n\nfunction propertyName(key: PropertyKey): string | null {\n if (key.type === 'Identifier') {\n return key.name;\n }\n if (key.type === 'Literal' && typeof key.value === 'string') {\n return key.value;\n }\n return null;\n}\n\nexport function unwrapExpression(node: Expression): Expression {\n while (\n node.type === 'TSAsExpression' ||\n node.type === 'TSSatisfiesExpression' ||\n node.type === 'TSNonNullExpression'\n ) {\n node = node.expression;\n }\n return node;\n}\n\nexport interface StaticProperty {\n readonly name: string;\n readonly value: Expression;\n // Where the property starts in the source, for error locations.\n readonly start: number;\n}\n\n// The properties of an object literal whose names are written out, skipping computed ones.\nexport function staticProperties(object: ObjectExpression): StaticProperty[] {\n const properties: StaticProperty[] = [];\n for (const property of object.properties) {\n if (property.type !== 'Property' || property.computed) {\n continue;\n }\n const name = propertyName(property.key);\n if (name !== null) {\n properties.push({ name, value: property.value, start: property.start });\n }\n }\n return properties;\n}\n\n// The declaration inside `export const ...` and the like; other statements as they are.\nexport function withoutExport(statement: TopLevelStatement): TopLevelStatement | null {\n if (statement.type === 'ExportNamedDeclaration') {\n return statement.declaration;\n }\n return statement;\n}\n","import type { Expression, ObjectExpression, Program } from 'oxc-parser';\nimport { parseSync } from 'oxc-parser';\n\nimport { failAt, failOnSyntaxError } from './errors';\nimport { unwrapExpression } from './utils';\n\nexport function parseModule(source: string, file: string): Program {\n let lang: 'ts' | 'tsx' = 'ts';\n if (file.endsWith('.tsx') || file.endsWith('.jsx')) {\n lang = 'tsx';\n }\n const { program, errors } = parseSync(file, source, { lang, sourceType: 'module' });\n failOnSyntaxError(errors, source, file);\n return program;\n}\n\nexport function defaultExport(program: Program): Expression | undefined {\n for (const statement of program.body) {\n if (statement.type !== 'ExportDefaultDeclaration') {\n continue;\n }\n const { declaration } = statement;\n switch (declaration.type) {\n case 'FunctionDeclaration':\n case 'ClassDeclaration':\n case 'TSInterfaceDeclaration':\n return undefined;\n default:\n return declaration;\n }\n }\n return undefined;\n}\n\nexport function defineCall(\n program: Program,\n source: string,\n file: string,\n callee: string,\n): ObjectExpression {\n const exported = defaultExport(program);\n const call = exported && unwrapExpression(exported);\n const options = call?.type === 'CallExpression' ? call.arguments[0] : undefined;\n if (\n call?.type !== 'CallExpression' ||\n call.callee.type !== 'Identifier' ||\n call.callee.name !== callee ||\n options?.type !== 'ObjectExpression'\n ) {\n return failAt(\n `${fileName(file)} must \\`export default ${callee}({ ... })\\``,\n source,\n exported?.start ?? 0,\n file,\n );\n }\n return options;\n}\n\n// The last segment of a path, with either separator.\nfunction fileName(path: string): string {\n const lastSeparator = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\\\'));\n return path.slice(lastSeparator + 1);\n}\n","import type { Program } from 'oxc-parser';\n\nimport { parseModule } from './module';\nimport { withoutExport } from './utils';\n\ninterface Node {\n readonly type: string;\n readonly [key: string]: unknown;\n}\n\n/**\n * Which of `names` a module reads without declaring or importing them at its top level. The\n * compiler imports those for the module, so a dot's code can use framework functions as globals.\n */\nexport function unboundReferences(\n source: string,\n names: readonly string[],\n file = 'module.ts',\n): string[] {\n const program = parseModule(source, file);\n const bound = topLevelBindings(program);\n const references = new Set<string>();\n collectReferences(program as unknown as Node, null, '', references);\n return names.filter((name) => references.has(name) && !bound.has(name));\n}\n\nfunction topLevelBindings(program: Program): Set<string> {\n const names = new Set<string>();\n for (const statement of program.body) {\n const declaration = withoutExport(statement);\n switch (declaration?.type) {\n case 'ImportDeclaration':\n declaration.specifiers.forEach((specifier) => names.add(specifier.local.name));\n break;\n case 'VariableDeclaration':\n declaration.declarations.forEach((declarator) =>\n collectPatternNames(declarator.id as unknown as Node, names),\n );\n break;\n case 'FunctionDeclaration':\n case 'ClassDeclaration':\n if (declaration.id) {\n names.add(declaration.id.name);\n }\n break;\n }\n }\n return names;\n}\n\nfunction collectPatternNames(pattern: Node, names: Set<string>): void {\n const visit = (child: unknown) => {\n if (isNode(child)) {\n collectPatternNames(child, names);\n }\n };\n switch (pattern.type) {\n case 'Identifier':\n names.add(pattern.name as string);\n break;\n case 'ObjectPattern':\n (pattern.properties as Node[]).forEach((property) =>\n visit(property.type === 'RestElement' ? property.argument : property.value),\n );\n break;\n case 'ArrayPattern':\n (pattern.elements as unknown[]).forEach(visit);\n break;\n case 'RestElement':\n visit(pattern.argument);\n break;\n case 'AssignmentPattern':\n visit(pattern.left);\n break;\n }\n}\n\nfunction collectReferences(node: Node, parent: Node | null, key: string, out: Set<string>): void {\n if (node.type === 'ImportDeclaration') {\n return;\n }\n if (node.type === 'Identifier' && isReference(parent, key)) {\n out.add(node.name as string);\n }\n for (const [childKey, value] of Object.entries(node)) {\n for (const child of Array.isArray(value) ? value : [value]) {\n if (isNode(child)) {\n collectReferences(child, node, childKey, out);\n }\n }\n }\n}\n\n/** False for identifiers that name a property or label rather than refer to a variable. */\nfunction isReference(parent: Node | null, key: string): boolean {\n switch (parent?.type) {\n case 'MemberExpression':\n return key !== 'property' || parent.computed === true;\n case 'Property':\n case 'MethodDefinition':\n case 'PropertyDefinition':\n return key !== 'key' || parent.computed === true;\n case 'LabeledStatement':\n case 'BreakStatement':\n case 'ContinueStatement':\n return key !== 'label';\n default:\n return true;\n }\n}\n\nfunction isNode(value: unknown): value is Node {\n return typeof (value as Node | null)?.type === 'string';\n}\n","import { isPageId, PAGE_HOOKS } from '@monimesl/dot-core';\nimport type { Expression, ObjectExpression, Program } from 'oxc-parser';\n\nimport type { PageModule, PageStateModule } from './types';\nimport { failAt } from '../../errors';\nimport { defaultExport, defineCall, parseModule } from '../../module';\nimport { staticProperties, unwrapExpression, withoutExport } from '../../utils';\n\nconst HOOKS = new Set<string>(PAGE_HOOKS);\n\nexport function parseStateModule(source: string, file = 'state.ts'): PageStateModule {\n const program = parseModule(source, file);\n const exported = defaultExport(program);\n if (!exported) {\n return failAt('state.ts must have a default export', source, 0, file);\n }\n return { keys: resolvedKeys(program, exported) };\n}\n\nexport function parseLogicModule(source: string, file = 'controller.ts'): PageModule {\n const program = parseModule(source, file);\n const options = defineCall(program, source, file, 'definePage');\n let id: string | null = null;\n let mutations: string[] | null = [];\n let actions: string[] | null = [];\n const hooks: string[] = [];\n for (const { name, value, start } of staticProperties(options)) {\n switch (name) {\n case 'initialState':\n break;\n case 'id':\n id = pageId(value, source, file);\n break;\n case 'hooks':\n if (value.type !== 'ObjectExpression') {\n break;\n }\n for (const hook of staticProperties(value)) {\n if (!HOOKS.has(hook.name)) {\n failAt(\n `Unknown page hook \\`${hook.name}\\`. Page hooks: ${PAGE_HOOKS.join(', ')}`,\n source,\n hook.start,\n file,\n );\n }\n hooks.push(hook.name);\n }\n break;\n case 'mutations':\n mutations = resolvedKeys(program, value);\n break;\n case 'actions':\n actions = resolvedKeys(program, value);\n break;\n default:\n if (isFunction(value)) {\n failAt(`\\`${name}\\` must go in \\`mutations\\` or \\`actions\\``, source, start, file);\n } else {\n failAt(\n `Unknown option \\`${name}\\`. definePage takes id, initialState, hooks, mutations and actions`,\n source,\n start,\n file,\n );\n }\n }\n }\n const clash = mutations?.find((name) => actions?.includes(name));\n if (clash) {\n failAt(`\\`${clash}\\` is both a mutation and an action`, source, options.start, file);\n }\n return { id, mutations, actions, hooks };\n}\n\nfunction isFunction(node: Expression): boolean {\n return node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression';\n}\n\n// The keys of the object literal `node` is or names, or null when they cannot be read statically.\nfunction resolvedKeys(program: Program, node: Expression): string[] | null {\n const object = resolveObject(program, node);\n if (!object) {\n return null;\n }\n return staticKeys(object);\n}\n\n/** Follows `export default state` back to `const state = { ... }`. */\nfunction resolveObject(program: Program, node: Expression): ObjectExpression | null {\n const target = unwrapExpression(node);\n if (target.type === 'ObjectExpression') {\n return target;\n }\n if (target.type !== 'Identifier') {\n return null;\n }\n\n for (const statement of program.body) {\n const declaration = withoutExport(statement);\n if (declaration?.type !== 'VariableDeclaration' || declaration.kind !== 'const') {\n continue;\n }\n for (const declarator of declaration.declarations) {\n if (declarator.id.type === 'Identifier' && declarator.id.name === target.name) {\n return declarator.init ? resolveObject(program, declarator.init) : null;\n }\n }\n }\n return null;\n}\n\nfunction staticKeys(object: ObjectExpression): string[] | null {\n const properties = staticProperties(object);\n if (properties.length !== object.properties.length) {\n return null;\n }\n return properties.map((property) => property.name);\n}\n\n/** Reads a page id, which must be a string literal made of safe characters. */\nexport function pageId(node: Expression, source: string, file: string): string {\n const value = unwrapExpression(node);\n if (value.type !== 'Literal' || typeof value.value !== 'string') {\n return failAt('A page id must be a string literal', source, node.start, file);\n }\n if (!isPageId(value.value)) {\n return failAt(\n `Invalid page id \"${value.value}\". Use letters, digits, \"-\" and \"_\", with \"/\" between segments`,\n source,\n node.start,\n file,\n );\n }\n return value.value;\n}\n","import { failAt } from './errors';\nimport { defineCall, parseModule } from './module';\nimport { pageId } from './ast/page/parse';\nimport { staticProperties, unwrapExpression } from './utils';\n\nexport interface DotModuleIR {\n /** Page folders under `pages/`, in order; the first is where the dot starts. */\n readonly pages: readonly string[];\n}\n\n/** Reads `export default defineDot({ pages: [...] })`. The pages must be string literals. */\nexport function parseDotModule(source: string, file = 'dot.ts'): DotModuleIR {\n const program = parseModule(source, file);\n const options = defineCall(program, source, file, 'defineDot');\n\n const pagesProperty = staticProperties(options).find((property) => property.name === 'pages');\n if (!pagesProperty) {\n return failAt(\n \"defineDot needs `pages`: the dot's page folders, starting page first\",\n source,\n options.start,\n file,\n );\n }\n const { value, start } = pagesProperty;\n const array = unwrapExpression(value);\n if (array.type !== 'ArrayExpression') {\n return failAt('`pages` must be an array of page folders', source, start, file);\n }\n if (array.elements.length === 0) {\n return failAt('`pages` needs at least one page', source, start, file);\n }\n\n const pages = array.elements.map((element) => {\n if (!element || element.type === 'SpreadElement') {\n return failAt(\n '`pages` must list each page folder as a string',\n source,\n element?.start ?? start,\n file,\n );\n }\n return pageId(element, source, file);\n });\n return { pages };\n}\n","export const UNARY_OPERATORS = ['!', '-', '+', 'typeof'] as const;\n\nexport const BINARY_OPERATORS = [\n '==',\n '!=',\n '===',\n '!==',\n '<',\n '<=',\n '>',\n '>=',\n '+',\n '-',\n '*',\n '/',\n '%',\n '**',\n '&&',\n '||',\n '??',\n] as const;\n\nexport type LiteralValue = string | number | boolean | null;\n\nexport type LiteralNode = { readonly type: 'Literal'; readonly value: LiteralValue };\n\nexport type IdentifierNode = { readonly type: 'Identifier'; readonly name: string };\n\nexport type MemberNode = {\n readonly type: 'Member';\n readonly object: ExprNode;\n readonly property: ExprNode;\n};\n\nexport type UnaryOperator = (typeof UNARY_OPERATORS)[number];\n\nexport type UnaryExprNode = {\n readonly type: 'Unary';\n readonly operator: UnaryOperator;\n readonly argument: ExprNode;\n};\n\nexport type BinaryOperator = (typeof BINARY_OPERATORS)[number];\n\nexport type BinaryExprNode = {\n readonly type: 'Binary';\n readonly operator: BinaryOperator;\n readonly left: ExprNode;\n readonly right: ExprNode;\n};\n\nexport type ConditionalExprNode = {\n readonly type: 'Conditional';\n readonly test: ExprNode;\n readonly consequent: ExprNode;\n readonly alternate: ExprNode;\n};\n\nexport type ExprNode =\n LiteralNode | IdentifierNode | MemberNode | UnaryExprNode | BinaryExprNode | ConditionalExprNode;\n","import type { Expression } from 'oxc-parser';\nimport { parseSync } from 'oxc-parser';\n\nimport { failAt, failOnSyntaxError } from '../../errors';\nimport { BINARY_OPERATORS, type ExprNode, UNARY_OPERATORS } from './types';\n\n// Parses the body of a binding (`{{ }}`) into an expression tree.\nexport function parseExpression(source: string): ExprNode {\n if (source.trim().length === 0) {\n failAt('Empty expression', source, 0);\n }\n const { program, errors } = parseSync('binding.js', source, { preserveParens: false });\n failOnSyntaxError(errors, source);\n const [statement, extra] = program.body;\n if (!statement || extra || statement.type !== 'ExpressionStatement') {\n return failAt('Expected a single expression statement', source, statement?.start ?? 0);\n }\n return convert(statement.expression, source);\n}\n\nfunction convert(node: Expression, source: string): ExprNode {\n switch (node.type) {\n case 'Literal':\n if (typeof node.value === 'bigint' || node.value instanceof RegExp) {\n break;\n }\n return { type: 'Literal', value: node.value };\n case 'Identifier':\n return { type: 'Identifier', name: node.name };\n case 'MemberExpression': {\n if (node.object.type === 'Super' || node.property.type === 'PrivateIdentifier') {\n break;\n }\n const object = convert(node.object, source);\n if (node.computed) {\n return { type: 'Member', object, property: convert(node.property, source) };\n }\n return { type: 'Member', object, property: { type: 'Literal', value: node.property.name } };\n }\n case 'UnaryExpression': {\n if (!isOneOf(UNARY_OPERATORS, node.operator)) {\n break;\n }\n return { type: 'Unary', operator: node.operator, argument: convert(node.argument, source) };\n }\n case 'BinaryExpression':\n case 'LogicalExpression': {\n if (node.left.type === 'PrivateIdentifier' || !isOneOf(BINARY_OPERATORS, node.operator)) {\n break;\n }\n return {\n type: 'Binary',\n operator: node.operator,\n left: convert(node.left, source),\n right: convert(node.right, source),\n };\n }\n case 'ConditionalExpression': {\n return {\n type: 'Conditional',\n test: convert(node.test, source),\n consequent: convert(node.consequent, source),\n alternate: convert(node.alternate, source),\n };\n }\n case 'CallExpression':\n case 'NewExpression':\n return failAt('Function calls are currently not allowed in bindings', source, node.start);\n case 'AssignmentExpression':\n case 'UpdateExpression':\n return failAt('Update expressions are currently not allowed in bindings', source, node.start);\n }\n let detail = '';\n if ('operator' in node) {\n detail = ` \\`${node.operator}\\``;\n }\n return failAt(`Unsupported syntax in binding: ${node.type}${detail}`, source, node.start);\n}\n\nfunction isOneOf<T extends string>(list: readonly T[], value: string): value is T {\n return (list as readonly string[]).includes(value);\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@monimesl/dot-script-parser",
3
+ "version": "0.1.0-alpha.2",
4
+ "description": "Dot page script parser: page state and logic -> intermediary representation",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/monime-lab/dot.git",
9
+ "directory": "packages/parsers/script"
10
+ },
11
+ "sideEffects": false,
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "exports": {
16
+ ".": {
17
+ "@monimesl/dot-source": "./src/index.ts",
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "devDependencies": {
27
+ "publint": "^0.3.24",
28
+ "rimraf": "^6.1.3",
29
+ "tsdown": "^0.23.0",
30
+ "typescript": "^5.9.3",
31
+ "vitest": "^5.0.1"
32
+ },
33
+ "dependencies": {
34
+ "oxc-parser": "^0.151.0",
35
+ "@monimesl/dot-core": "0.1.0-alpha.2"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "scripts": {
41
+ "build": "tsdown",
42
+ "dev": "tsdown --watch",
43
+ "typecheck": "tsc --noEmit -p tsconfig.json",
44
+ "test": "vitest run",
45
+ "clean": "rimraf dist *.tsbuildinfo"
46
+ }
47
+ }