@monimesl/dot-script-parser 0.1.0-alpha.2 → 0.1.0-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +179 -96
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import "oxc-parser";
|
|
2
2
|
import { SourceError } from "@monimesl/dot-core";
|
|
3
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
4
|
export declare function unboundReferences(source: string, names: readonly string[], file?: string): string[];
|
|
5
|
+
export declare function globalMemberUses(source: string, name: string, file?: string): string[];
|
|
9
6
|
//#endregion
|
|
10
7
|
//#region src/dot.d.ts
|
|
11
8
|
interface DotModuleIR {
|
|
12
|
-
/** Page folders under `pages/`, in order; the first is where the dot starts. */
|
|
13
9
|
readonly pages: readonly string[];
|
|
10
|
+
readonly lastPage: {
|
|
11
|
+
readonly start: number;
|
|
12
|
+
readonly end: number;
|
|
13
|
+
};
|
|
14
14
|
}
|
|
15
|
-
/** Reads `export default defineDot({ pages: [...] })`. The pages must be string literals. */
|
|
16
15
|
export declare function parseDotModule(source: string, file?: string): DotModuleIR;
|
|
17
16
|
//#endregion
|
|
18
17
|
//#region src/errors.d.ts
|
|
@@ -64,12 +63,15 @@ export declare function parseExpression(source: string): ExprNode;
|
|
|
64
63
|
//#region src/ast/page/types.d.ts
|
|
65
64
|
interface PageStateModule {
|
|
66
65
|
readonly keys: readonly string[] | null;
|
|
66
|
+
readonly keyOffsets: Readonly<Record<string, number>>;
|
|
67
67
|
}
|
|
68
68
|
interface PageModule {
|
|
69
69
|
readonly id: string | null;
|
|
70
|
+
readonly share: readonly string[] | null;
|
|
70
71
|
readonly hooks: readonly string[];
|
|
71
72
|
readonly mutations: readonly string[] | null;
|
|
72
73
|
readonly actions: readonly string[] | null;
|
|
74
|
+
readonly handlerOffsets: Readonly<Record<string, number>>;
|
|
73
75
|
}
|
|
74
76
|
//#endregion
|
|
75
77
|
//#region src/ast/page/parse.d.ts
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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":"
|
|
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":";;;wBAagB,kBACd,gBACA,0BACA;wBAcc,iBAAiB,gBAAgB,cAAc;;;UCzB9C;WACN;WACA;aAAqB;aAAwB;;;wBAGxC,eAAe,gBAAgB,gBAAkB;;;qBCPpD,yBAAyB;WAClB;;;;cCJP;cAEA;KAoBD;KAEP;WAAyB;WAA0B,OAAO;;KAE1D;WAA4B;WAA6B;;KAEzD;WACM;WACA,QAAQ;WACR,UAAU;;KAGT,wBAAwB;KAE/B;WACM;WACA,UAAU;WACV,UAAU;;KAGT,yBAAyB;KAEhC;WACM;WACA,UAAU;WACV,MAAM;WACN,OAAO;;KAGb;WACM;WACA,MAAM;WACN,YAAY;WACZ,WAAW;;KAGV,WACV,cAAc,iBAAiB,aAAa,gBAAgB,iBAAiB;;;wBCpD/D,gBAAgB,iBAAiB;;;UCPhC;WAEN;WAEA,YAAY,SAAS;;UAGf;WACN;WAEA;WACA;WACA;WACA;WAEA,gBAAgB,SAAS;;;;wBCHpB,iBAAiB,gBAAgB,gBAAoB;wBAarD,iBAAiB,gBAAgB,gBAAyB"}
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,5 @@
|
|
|
1
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
|
|
2
|
+
import { MAX_SHARED_OPTIONS, PAGE_HOOKS, SourceError, isPageId, isSharedOptionName, locationAt } from "@monimesl/dot-core";
|
|
15
3
|
//#region src/utils.ts
|
|
16
4
|
function propertyName(key) {
|
|
17
5
|
if (key.type === "Identifier") return key.name;
|
|
@@ -40,12 +28,22 @@ function withoutExport(statement) {
|
|
|
40
28
|
return statement;
|
|
41
29
|
}
|
|
42
30
|
//#endregion
|
|
31
|
+
//#region src/errors.ts
|
|
32
|
+
var ScriptParseError = class extends SourceError {
|
|
33
|
+
name = "ScriptParseError";
|
|
34
|
+
};
|
|
35
|
+
function failAt(reason, source, offset, file) {
|
|
36
|
+
throw new ScriptParseError(reason, file, locationAt(source, offset));
|
|
37
|
+
}
|
|
38
|
+
function failOnSyntaxError(errors, source, file) {
|
|
39
|
+
const [error] = errors;
|
|
40
|
+
if (error) failAt(error.message, source, error.labels[0]?.start ?? 0, file);
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
43
|
//#region src/module.ts
|
|
44
44
|
function parseModule(source, file) {
|
|
45
|
-
let lang = "ts";
|
|
46
|
-
if (file.endsWith(".tsx") || file.endsWith(".jsx")) lang = "tsx";
|
|
47
45
|
const { program, errors } = parseSync(file, source, {
|
|
48
|
-
lang,
|
|
46
|
+
lang: "ts",
|
|
49
47
|
sourceType: "module"
|
|
50
48
|
});
|
|
51
49
|
failOnSyntaxError(errors, source, file);
|
|
@@ -65,9 +63,16 @@ function defaultExport(program) {
|
|
|
65
63
|
}
|
|
66
64
|
function defineCall(program, source, file, callee) {
|
|
67
65
|
const exported = defaultExport(program);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (
|
|
66
|
+
let options;
|
|
67
|
+
if (exported) options = callOptions(unwrapExpression(exported), callee);
|
|
68
|
+
if (!options) return failAt(`${fileName(file)} must \`export default ${callee}({ ... })\``, source, exported?.start ?? 0, file);
|
|
69
|
+
return options;
|
|
70
|
+
}
|
|
71
|
+
function callOptions(expression, callee) {
|
|
72
|
+
if (expression.type !== "CallExpression") return;
|
|
73
|
+
if (expression.callee.type !== "Identifier" || expression.callee.name !== callee) return;
|
|
74
|
+
const [options] = expression.arguments;
|
|
75
|
+
if (options?.type !== "ObjectExpression") return;
|
|
71
76
|
return options;
|
|
72
77
|
}
|
|
73
78
|
function fileName(path) {
|
|
@@ -76,27 +81,40 @@ function fileName(path) {
|
|
|
76
81
|
}
|
|
77
82
|
//#endregion
|
|
78
83
|
//#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
84
|
function unboundReferences(source, names, file = "module.ts") {
|
|
84
85
|
const program = parseModule(source, file);
|
|
85
86
|
const bound = topLevelBindings(program);
|
|
86
87
|
const references = /* @__PURE__ */ new Set();
|
|
87
|
-
|
|
88
|
+
forEachReference(program, (identifier) => {
|
|
89
|
+
references.add(identifier.name);
|
|
90
|
+
});
|
|
88
91
|
return names.filter((name) => references.has(name) && !bound.has(name));
|
|
89
92
|
}
|
|
93
|
+
function globalMemberUses(source, name, file = "module.ts") {
|
|
94
|
+
const program = parseModule(source, file);
|
|
95
|
+
if (topLevelBindings(program).has(name)) return [];
|
|
96
|
+
const uses = [];
|
|
97
|
+
forEachReference(program, (identifier, parent, key) => {
|
|
98
|
+
if (identifier.name === name) uses.push(memberRead(parent, key));
|
|
99
|
+
});
|
|
100
|
+
return uses;
|
|
101
|
+
}
|
|
102
|
+
function memberRead(parent, key) {
|
|
103
|
+
if (parent?.type !== "MemberExpression" || key !== "object" || parent.computed === true) return "";
|
|
104
|
+
const property = parent.property;
|
|
105
|
+
if (property?.type !== "Identifier") return "";
|
|
106
|
+
return property.name;
|
|
107
|
+
}
|
|
90
108
|
function topLevelBindings(program) {
|
|
91
109
|
const names = /* @__PURE__ */ new Set();
|
|
92
110
|
for (const statement of program.body) {
|
|
93
111
|
const declaration = withoutExport(statement);
|
|
94
112
|
switch (declaration?.type) {
|
|
95
113
|
case "ImportDeclaration":
|
|
96
|
-
declaration.specifiers
|
|
114
|
+
for (const specifier of declaration.specifiers) names.add(specifier.local.name);
|
|
97
115
|
break;
|
|
98
116
|
case "VariableDeclaration":
|
|
99
|
-
declaration.declarations
|
|
117
|
+
for (const declarator of declaration.declarations) collectPatternNames(declarator.id, names);
|
|
100
118
|
break;
|
|
101
119
|
case "FunctionDeclaration":
|
|
102
120
|
case "ClassDeclaration": if (declaration.id) names.add(declaration.id.name);
|
|
@@ -105,31 +123,35 @@ function topLevelBindings(program) {
|
|
|
105
123
|
return names;
|
|
106
124
|
}
|
|
107
125
|
function collectPatternNames(pattern, names) {
|
|
108
|
-
|
|
109
|
-
if (isNode(child)) collectPatternNames(child, names);
|
|
110
|
-
};
|
|
126
|
+
if (!isNode(pattern)) return;
|
|
111
127
|
switch (pattern.type) {
|
|
112
128
|
case "Identifier":
|
|
113
129
|
names.add(pattern.name);
|
|
114
130
|
break;
|
|
115
131
|
case "ObjectPattern":
|
|
116
|
-
pattern.properties
|
|
132
|
+
for (const property of pattern.properties) if (property.type === "RestElement") collectPatternNames(property.argument, names);
|
|
133
|
+
else collectPatternNames(property.value, names);
|
|
117
134
|
break;
|
|
118
135
|
case "ArrayPattern":
|
|
119
|
-
pattern.elements
|
|
136
|
+
for (const element of pattern.elements) collectPatternNames(element, names);
|
|
120
137
|
break;
|
|
121
138
|
case "RestElement":
|
|
122
|
-
|
|
139
|
+
collectPatternNames(pattern.argument, names);
|
|
123
140
|
break;
|
|
124
|
-
case "AssignmentPattern":
|
|
141
|
+
case "AssignmentPattern": collectPatternNames(pattern.left, names);
|
|
125
142
|
}
|
|
126
143
|
}
|
|
127
|
-
function
|
|
144
|
+
function forEachReference(program, visit) {
|
|
145
|
+
visitReferences(program, null, "", visit);
|
|
146
|
+
}
|
|
147
|
+
function visitReferences(node, parent, key, visit) {
|
|
128
148
|
if (node.type === "ImportDeclaration") return;
|
|
129
|
-
if (node.type === "Identifier" && isReference(parent, key))
|
|
130
|
-
for (const [childKey, value] of Object.entries(node))
|
|
149
|
+
if (node.type === "Identifier" && isReference(parent, key)) visit(node, parent, key);
|
|
150
|
+
for (const [childKey, value] of Object.entries(node)) {
|
|
151
|
+
const children = Array.isArray(value) ? value : [value];
|
|
152
|
+
for (const child of children) if (isNode(child)) visitReferences(child, node, childKey, visit);
|
|
153
|
+
}
|
|
131
154
|
}
|
|
132
|
-
/** False for identifiers that name a property or label rather than refer to a variable. */
|
|
133
155
|
function isReference(parent, key) {
|
|
134
156
|
switch (parent?.type) {
|
|
135
157
|
case "MemberExpression": return key !== "property" || parent.computed === true;
|
|
@@ -143,63 +165,116 @@ function isReference(parent, key) {
|
|
|
143
165
|
}
|
|
144
166
|
}
|
|
145
167
|
function isNode(value) {
|
|
146
|
-
|
|
168
|
+
if (typeof value !== "object" || value === null) return false;
|
|
169
|
+
return typeof value.type === "string";
|
|
147
170
|
}
|
|
148
171
|
//#endregion
|
|
149
172
|
//#region src/ast/page/parse.ts
|
|
150
173
|
const HOOKS = new Set(PAGE_HOOKS);
|
|
174
|
+
const SHARE_EXAMPLE = "such as share: { options: ['show'] }";
|
|
151
175
|
function parseStateModule(source, file = "state.ts") {
|
|
152
176
|
const program = parseModule(source, file);
|
|
153
177
|
const exported = defaultExport(program);
|
|
154
178
|
if (!exported) return failAt("state.ts must have a default export", source, 0, file);
|
|
155
|
-
|
|
179
|
+
const properties = resolvedProperties(program, exported);
|
|
180
|
+
return {
|
|
181
|
+
keys: namesOf(properties),
|
|
182
|
+
keyOffsets: offsetsOf(properties ?? [])
|
|
183
|
+
};
|
|
156
184
|
}
|
|
157
185
|
function parseLogicModule(source, file = "controller.ts") {
|
|
158
186
|
const program = parseModule(source, file);
|
|
159
187
|
const options = defineCall(program, source, file, "definePage");
|
|
160
188
|
let id = null;
|
|
189
|
+
let share = null;
|
|
161
190
|
let mutations = [];
|
|
162
191
|
let actions = [];
|
|
163
192
|
const hooks = [];
|
|
164
193
|
for (const { name, value, start } of staticProperties(options)) switch (name) {
|
|
165
|
-
case "initialState":
|
|
194
|
+
case "initialState":
|
|
195
|
+
case "configs": break;
|
|
166
196
|
case "id":
|
|
167
|
-
id =
|
|
197
|
+
id = readPageId(value, source, file);
|
|
198
|
+
break;
|
|
199
|
+
case "share":
|
|
200
|
+
share = readSharedOptions(value, source, file);
|
|
168
201
|
break;
|
|
169
202
|
case "hooks":
|
|
170
|
-
|
|
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
|
-
}
|
|
203
|
+
hooks.push(...readHooks(value, source, file));
|
|
175
204
|
break;
|
|
176
205
|
case "mutations":
|
|
177
|
-
mutations =
|
|
206
|
+
mutations = resolvedProperties(program, value);
|
|
178
207
|
break;
|
|
179
208
|
case "actions":
|
|
180
|
-
actions =
|
|
209
|
+
actions = resolvedProperties(program, value);
|
|
181
210
|
break;
|
|
182
211
|
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);
|
|
212
|
+
else failAt(`Unknown option \`${name}\`. definePage takes id, initialState, configs, share, hooks, mutations and actions`, source, start, file);
|
|
213
|
+
}
|
|
214
|
+
const mutationNames = namesOf(mutations);
|
|
215
|
+
const actionNames = namesOf(actions);
|
|
216
|
+
if (mutationNames && actionNames) {
|
|
217
|
+
const clash = mutationNames.find((name) => actionNames.includes(name));
|
|
218
|
+
if (clash) failAt(`\`${clash}\` is both a mutation and an action`, source, options.start, file);
|
|
184
219
|
}
|
|
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
220
|
return {
|
|
188
221
|
id,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
222
|
+
share,
|
|
223
|
+
mutations: mutationNames,
|
|
224
|
+
actions: actionNames,
|
|
225
|
+
hooks,
|
|
226
|
+
handlerOffsets: offsetsOf([...mutations ?? [], ...actions ?? []])
|
|
192
227
|
};
|
|
193
228
|
}
|
|
229
|
+
function readSharedOptions(node, source, file) {
|
|
230
|
+
const object = unwrapExpression(node);
|
|
231
|
+
if (object.type !== "ObjectExpression") return failAt(`Write \`share\` out in place, ${SHARE_EXAMPLE}`, source, node.start, file);
|
|
232
|
+
const properties = staticProperties(object);
|
|
233
|
+
if (properties.length !== object.properties.length) return failAt(`Write \`share\` out in place, ${SHARE_EXAMPLE}`, source, object.start, file);
|
|
234
|
+
const options = [];
|
|
235
|
+
for (const property of properties) {
|
|
236
|
+
if (property.name !== "options") return failAt(`Unknown share option \`${property.name}\`. share only takes options`, source, property.start, file);
|
|
237
|
+
const list = unwrapExpression(property.value);
|
|
238
|
+
if (list.type !== "ArrayExpression") return failAt(`share's options must be a list of names, ${SHARE_EXAMPLE}`, source, list.start, file);
|
|
239
|
+
for (const element of list.elements) {
|
|
240
|
+
if (!element || element.type !== "Literal" || typeof element.value !== "string") return failAt(`share's options must be names written as strings, ${SHARE_EXAMPLE}`, source, element?.start ?? list.start, file);
|
|
241
|
+
const name = element.value;
|
|
242
|
+
if (!isSharedOptionName(name)) return failAt(`"${name}" can't go in a link. Use letters, digits, "-" and "_"`, source, element.start, file);
|
|
243
|
+
if (options.includes(name)) return failAt(`"${name}" is in share's options twice`, source, element.start, file);
|
|
244
|
+
options.push(name);
|
|
245
|
+
}
|
|
246
|
+
if (options.length > MAX_SHARED_OPTIONS) return failAt(`A link can carry at most ${MAX_SHARED_OPTIONS} options`, source, list.start, file);
|
|
247
|
+
}
|
|
248
|
+
return options;
|
|
249
|
+
}
|
|
250
|
+
function readHooks(node, source, file) {
|
|
251
|
+
if (node.type !== "ObjectExpression") return [];
|
|
252
|
+
const hooks = [];
|
|
253
|
+
for (const hook of staticProperties(node)) {
|
|
254
|
+
if (!HOOKS.has(hook.name)) failAt(`Unknown page hook \`${hook.name}\`. The hooks are ${PAGE_HOOKS.join(", ")}`, source, hook.start, file);
|
|
255
|
+
hooks.push(hook.name);
|
|
256
|
+
}
|
|
257
|
+
return hooks;
|
|
258
|
+
}
|
|
194
259
|
function isFunction(node) {
|
|
195
260
|
return node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
|
196
261
|
}
|
|
197
|
-
function
|
|
262
|
+
function resolvedProperties(program, node) {
|
|
198
263
|
const object = resolveObject(program, node);
|
|
199
264
|
if (!object) return null;
|
|
200
|
-
|
|
265
|
+
const properties = staticProperties(object);
|
|
266
|
+
if (properties.length !== object.properties.length) return null;
|
|
267
|
+
return properties;
|
|
268
|
+
}
|
|
269
|
+
function namesOf(properties) {
|
|
270
|
+
if (properties === null) return null;
|
|
271
|
+
return properties.map((property) => property.name);
|
|
272
|
+
}
|
|
273
|
+
function offsetsOf(properties) {
|
|
274
|
+
const offsets = {};
|
|
275
|
+
for (const property of properties) offsets[property.name] = property.start;
|
|
276
|
+
return offsets;
|
|
201
277
|
}
|
|
202
|
-
/** Follows `export default state` back to `const state = { ... }`. */
|
|
203
278
|
function resolveObject(program, node) {
|
|
204
279
|
const target = unwrapExpression(node);
|
|
205
280
|
if (target.type === "ObjectExpression") return target;
|
|
@@ -207,37 +282,42 @@ function resolveObject(program, node) {
|
|
|
207
282
|
for (const statement of program.body) {
|
|
208
283
|
const declaration = withoutExport(statement);
|
|
209
284
|
if (declaration?.type !== "VariableDeclaration" || declaration.kind !== "const") continue;
|
|
210
|
-
for (const declarator of declaration.declarations)
|
|
285
|
+
for (const declarator of declaration.declarations) {
|
|
286
|
+
if (declarator.id.type !== "Identifier" || declarator.id.name !== target.name) continue;
|
|
287
|
+
if (!declarator.init) return null;
|
|
288
|
+
return resolveObject(program, declarator.init);
|
|
289
|
+
}
|
|
211
290
|
}
|
|
212
291
|
return null;
|
|
213
292
|
}
|
|
214
|
-
function
|
|
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) {
|
|
293
|
+
function readPageId(node, source, file) {
|
|
221
294
|
const value = unwrapExpression(node);
|
|
222
|
-
if (value.type !== "Literal" || typeof value.value !== "string") return failAt("A page id must be a string
|
|
223
|
-
if (!isPageId(value.value)) return failAt(`
|
|
295
|
+
if (value.type !== "Literal" || typeof value.value !== "string") return failAt("A page id must be written as a string, such as 'cart'", source, node.start, file);
|
|
296
|
+
if (!isPageId(value.value)) return failAt(`"${value.value}" isn't a valid page id. Use letters, digits, "-" and "_", with "/" between folders`, source, node.start, file);
|
|
224
297
|
return value.value;
|
|
225
298
|
}
|
|
226
299
|
//#endregion
|
|
227
300
|
//#region src/dot.ts
|
|
228
|
-
/** Reads `export default defineDot({ pages: [...] })`. The pages must be string literals. */
|
|
229
301
|
function parseDotModule(source, file = "dot.ts") {
|
|
230
302
|
const options = defineCall(parseModule(source, file), source, file, "defineDot");
|
|
231
303
|
const pagesProperty = staticProperties(options).find((property) => property.name === "pages");
|
|
232
|
-
if (!pagesProperty) return failAt("defineDot needs `pages
|
|
304
|
+
if (!pagesProperty) return failAt("defineDot needs `pages`, a list of page folders with the entry page first", source, options.start, file);
|
|
233
305
|
const { value, start } = pagesProperty;
|
|
234
|
-
const
|
|
235
|
-
if (
|
|
236
|
-
if (
|
|
237
|
-
|
|
306
|
+
const pageList = unwrapExpression(value);
|
|
307
|
+
if (pageList.type !== "ArrayExpression") return failAt("`pages` must be a list of page folders", source, start, file);
|
|
308
|
+
if (pageList.elements.length === 0) return failAt("`pages` needs at least one page", source, start, file);
|
|
309
|
+
const pages = pageList.elements.map((element) => {
|
|
238
310
|
if (!element || element.type === "SpreadElement") return failAt("`pages` must list each page folder as a string", source, element?.start ?? start, file);
|
|
239
|
-
return
|
|
240
|
-
})
|
|
311
|
+
return readPageId(element, source, file);
|
|
312
|
+
});
|
|
313
|
+
const lastPage = pageList.elements.at(-1);
|
|
314
|
+
return {
|
|
315
|
+
pages,
|
|
316
|
+
lastPage: {
|
|
317
|
+
start: lastPage.start,
|
|
318
|
+
end: lastPage.end
|
|
319
|
+
}
|
|
320
|
+
};
|
|
241
321
|
}
|
|
242
322
|
//#endregion
|
|
243
323
|
//#region src/ast/expression/types.ts
|
|
@@ -269,17 +349,17 @@ const BINARY_OPERATORS = [
|
|
|
269
349
|
//#endregion
|
|
270
350
|
//#region src/ast/expression/parse.ts
|
|
271
351
|
function parseExpression(source) {
|
|
272
|
-
if (source.trim().length === 0) failAt("
|
|
352
|
+
if (source.trim().length === 0) failAt("The binding is empty", source, 0);
|
|
273
353
|
const { program, errors } = parseSync("binding.js", source, { preserveParens: false });
|
|
274
354
|
failOnSyntaxError(errors, source);
|
|
275
|
-
const
|
|
276
|
-
if (
|
|
277
|
-
return
|
|
355
|
+
const statement = program.body[0];
|
|
356
|
+
if (program.body.length !== 1 || statement?.type !== "ExpressionStatement") return failAt("A binding must be one expression", source, statement?.start ?? 0);
|
|
357
|
+
return toExprNode(statement.expression, source);
|
|
278
358
|
}
|
|
279
|
-
function
|
|
359
|
+
function toExprNode(node, source) {
|
|
280
360
|
switch (node.type) {
|
|
281
361
|
case "Literal":
|
|
282
|
-
if (typeof node.value === "bigint" || node.value instanceof RegExp)
|
|
362
|
+
if (typeof node.value === "bigint" || node.value instanceof RegExp) return failUnsupported(node, source);
|
|
283
363
|
return {
|
|
284
364
|
type: "Literal",
|
|
285
365
|
value: node.value
|
|
@@ -289,12 +369,12 @@ function convert(node, source) {
|
|
|
289
369
|
name: node.name
|
|
290
370
|
};
|
|
291
371
|
case "MemberExpression": {
|
|
292
|
-
if (node.object.type === "Super" || node.property.type === "PrivateIdentifier")
|
|
293
|
-
const object =
|
|
372
|
+
if (node.object.type === "Super" || node.property.type === "PrivateIdentifier") return failUnsupported(node, source);
|
|
373
|
+
const object = toExprNode(node.object, source);
|
|
294
374
|
if (node.computed) return {
|
|
295
375
|
type: "Member",
|
|
296
376
|
object,
|
|
297
|
-
property:
|
|
377
|
+
property: toExprNode(node.property, source)
|
|
298
378
|
};
|
|
299
379
|
return {
|
|
300
380
|
type: "Member",
|
|
@@ -306,40 +386,43 @@ function convert(node, source) {
|
|
|
306
386
|
};
|
|
307
387
|
}
|
|
308
388
|
case "UnaryExpression":
|
|
309
|
-
if (!isOneOf(UNARY_OPERATORS, node.operator))
|
|
389
|
+
if (!isOneOf(UNARY_OPERATORS, node.operator)) return failUnsupported(node, source);
|
|
310
390
|
return {
|
|
311
391
|
type: "Unary",
|
|
312
392
|
operator: node.operator,
|
|
313
|
-
argument:
|
|
393
|
+
argument: toExprNode(node.argument, source)
|
|
314
394
|
};
|
|
315
395
|
case "BinaryExpression":
|
|
316
396
|
case "LogicalExpression":
|
|
317
|
-
if (node.left.type === "PrivateIdentifier" || !isOneOf(BINARY_OPERATORS, node.operator))
|
|
397
|
+
if (node.left.type === "PrivateIdentifier" || !isOneOf(BINARY_OPERATORS, node.operator)) return failUnsupported(node, source);
|
|
318
398
|
return {
|
|
319
399
|
type: "Binary",
|
|
320
400
|
operator: node.operator,
|
|
321
|
-
left:
|
|
322
|
-
right:
|
|
401
|
+
left: toExprNode(node.left, source),
|
|
402
|
+
right: toExprNode(node.right, source)
|
|
323
403
|
};
|
|
324
404
|
case "ConditionalExpression": return {
|
|
325
405
|
type: "Conditional",
|
|
326
|
-
test:
|
|
327
|
-
consequent:
|
|
328
|
-
alternate:
|
|
406
|
+
test: toExprNode(node.test, source),
|
|
407
|
+
consequent: toExprNode(node.consequent, source),
|
|
408
|
+
alternate: toExprNode(node.alternate, source)
|
|
329
409
|
};
|
|
330
410
|
case "CallExpression":
|
|
331
|
-
case "NewExpression": return failAt("
|
|
411
|
+
case "NewExpression": return failAt("Bindings can't call functions", source, node.start);
|
|
332
412
|
case "AssignmentExpression":
|
|
333
|
-
case "UpdateExpression": return failAt("
|
|
413
|
+
case "UpdateExpression": return failAt("Bindings can't change values", source, node.start);
|
|
414
|
+
default: return failUnsupported(node, source);
|
|
334
415
|
}
|
|
416
|
+
}
|
|
417
|
+
function failUnsupported(node, source) {
|
|
335
418
|
let detail = "";
|
|
336
419
|
if ("operator" in node) detail = ` \`${node.operator}\``;
|
|
337
|
-
return failAt(`
|
|
420
|
+
return failAt(`Bindings can't use ${node.type}${detail}`, source, node.start);
|
|
338
421
|
}
|
|
339
422
|
function isOneOf(list, value) {
|
|
340
423
|
return list.includes(value);
|
|
341
424
|
}
|
|
342
425
|
//#endregion
|
|
343
|
-
export { ScriptParseError, parseDotModule, parseExpression, parseLogicModule, parseStateModule, unboundReferences };
|
|
426
|
+
export { ScriptParseError, globalMemberUses, parseDotModule, parseExpression, parseLogicModule, parseStateModule, unboundReferences };
|
|
344
427
|
|
|
345
428
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/utils.ts","../src/errors.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 { 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 readonly start: number;\n}\n\n// The properties of an object literal whose names are written out. Computed ones are skipped.\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// Unwraps `export const ...` and the like to the declaration. Other statements pass through.\nexport function withoutExport(statement: TopLevelStatement): TopLevelStatement | null {\n if (statement.type === 'ExportNamedDeclaration') {\n return statement.declaration;\n }\n return statement;\n}\n","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 { parseSync } from 'oxc-parser';\nimport type { Expression, ObjectExpression, Program } from 'oxc-parser';\n\nimport { unwrapExpression } from './utils';\nimport { failAt, failOnSyntaxError } from './errors';\n\nexport function parseModule(source: string, file: string): Program {\n const { program, errors } = parseSync(file, source, { lang: 'ts', 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\n// The `{ ... }` in `export default <callee>({ ... })`.\nexport function defineCall(\n program: Program,\n source: string,\n file: string,\n callee: string,\n): ObjectExpression {\n const exported = defaultExport(program);\n let options: ObjectExpression | undefined;\n if (exported) {\n options = callOptions(unwrapExpression(exported), callee);\n }\n if (!options) {\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\nfunction callOptions(expression: Expression, callee: string): ObjectExpression | undefined {\n if (expression.type !== 'CallExpression') {\n return undefined;\n }\n if (expression.callee.type !== 'Identifier' || expression.callee.name !== callee) {\n return undefined;\n }\n const [options] = expression.arguments;\n if (options?.type !== 'ObjectExpression') {\n return undefined;\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\ntype ReferenceVisitor = (identifier: Node, parent: Node | null, key: string) => void;\n\n// Which of `names` a module uses without declaring or importing, for the compiler to import.\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 forEachReference(program, (identifier) => {\n references.add(identifier.name as string);\n });\n return names.filter((name) => references.has(name) && !bound.has(name));\n}\n\n// The first property read off each use of the global `name`, such as \"utils\" for\n// `dash.utils.base64.encode(text)`, and \"\" for a use that reads none, such as passing it along.\n// None when the module declares or imports its own `name`.\nexport function globalMemberUses(source: string, name: string, file = 'module.ts'): string[] {\n const program = parseModule(source, file);\n if (topLevelBindings(program).has(name)) {\n return [];\n }\n const uses: string[] = [];\n forEachReference(program, (identifier, parent, key) => {\n if (identifier.name === name) {\n uses.push(memberRead(parent, key));\n }\n });\n return uses;\n}\n\n// The property name in `name.property`, or \"\" when the identifier isn't read that way.\nfunction memberRead(parent: Node | null, key: string): string {\n if (parent?.type !== 'MemberExpression' || key !== 'object' || parent.computed === true) {\n return '';\n }\n const property = parent.property as Node | undefined;\n if (property?.type !== 'Identifier') {\n return '';\n }\n return property.name as string;\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 for (const specifier of declaration.specifiers) {\n names.add(specifier.local.name);\n }\n break;\n case 'VariableDeclaration':\n for (const declarator of declaration.declarations) {\n collectPatternNames(declarator.id, 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: unknown, names: Set<string>): void {\n if (!isNode(pattern)) {\n return;\n }\n switch (pattern.type) {\n case 'Identifier':\n names.add(pattern.name as string);\n break;\n case 'ObjectPattern':\n for (const property of pattern.properties as Node[]) {\n if (property.type === 'RestElement') {\n collectPatternNames(property.argument, names);\n } else {\n collectPatternNames(property.value, names);\n }\n }\n break;\n case 'ArrayPattern':\n for (const element of pattern.elements as unknown[]) {\n collectPatternNames(element, names);\n }\n break;\n case 'RestElement':\n collectPatternNames(pattern.argument, names);\n break;\n case 'AssignmentPattern':\n collectPatternNames(pattern.left, names);\n break;\n }\n}\n\n// Visits each identifier that refers to a variable, in source order. Imports are skipped, since\n// they declare names rather than use them.\nfunction forEachReference(program: Program, visit: ReferenceVisitor): void {\n visitReferences(program as unknown as Node, null, '', visit);\n}\n\nfunction visitReferences(\n node: Node,\n parent: Node | null,\n key: string,\n visit: ReferenceVisitor,\n): void {\n if (node.type === 'ImportDeclaration') {\n return;\n }\n if (node.type === 'Identifier' && isReference(parent, key)) {\n visit(node, parent, key);\n }\n for (const [childKey, value] of Object.entries(node)) {\n const children: unknown[] = Array.isArray(value) ? value : [value];\n for (const child of children) {\n if (isNode(child)) {\n visitReferences(child, node, childKey, visit);\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 if (typeof value !== 'object' || value === null) {\n return false;\n }\n return typeof (value as { type?: unknown }).type === 'string';\n}\n","import { isPageId, isSharedOptionName, MAX_SHARED_OPTIONS, 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 type { StaticProperty } from '../../utils';\nimport { staticProperties, unwrapExpression, withoutExport } from '../../utils';\n\nconst HOOKS = new Set<string>(PAGE_HOOKS);\nconst SHARE_EXAMPLE = \"such as share: { options: ['show'] }\";\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 const properties = resolvedProperties(program, exported);\n return {\n keys: namesOf(properties),\n keyOffsets: offsetsOf(properties ?? []),\n };\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 share: string[] | null = null;\n let mutations: StaticProperty[] | null = [];\n let actions: StaticProperty[] | null = [];\n const hooks: string[] = [];\n for (const { name, value, start } of staticProperties(options)) {\n switch (name) {\n case 'initialState':\n case 'configs':\n break;\n case 'id':\n id = readPageId(value, source, file);\n break;\n case 'share':\n share = readSharedOptions(value, source, file);\n break;\n case 'hooks':\n hooks.push(...readHooks(value, source, file));\n break;\n case 'mutations':\n mutations = resolvedProperties(program, value);\n break;\n case 'actions':\n actions = resolvedProperties(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, configs, share, hooks, mutations and actions`,\n source,\n start,\n file,\n );\n }\n }\n }\n const mutationNames = namesOf(mutations);\n const actionNames = namesOf(actions);\n if (mutationNames && actionNames) {\n const clash = mutationNames.find((name) => actionNames.includes(name));\n if (clash) {\n failAt(`\\`${clash}\\` is both a mutation and an action`, source, options.start, file);\n }\n }\n return {\n id,\n share,\n mutations: mutationNames,\n actions: actionNames,\n hooks,\n handlerOffsets: offsetsOf([...(mutations ?? []), ...(actions ?? [])]),\n };\n}\n\n// `share: { options: ['show'] }`, written out so the build can read it.\nfunction readSharedOptions(node: Expression, source: string, file: string): string[] {\n const object = unwrapExpression(node);\n if (object.type !== 'ObjectExpression') {\n return failAt(`Write \\`share\\` out in place, ${SHARE_EXAMPLE}`, source, node.start, file);\n }\n const properties = staticProperties(object);\n if (properties.length !== object.properties.length) {\n return failAt(`Write \\`share\\` out in place, ${SHARE_EXAMPLE}`, source, object.start, file);\n }\n const options: string[] = [];\n for (const property of properties) {\n if (property.name !== 'options') {\n return failAt(\n `Unknown share option \\`${property.name}\\`. share only takes options`,\n source,\n property.start,\n file,\n );\n }\n const list = unwrapExpression(property.value);\n if (list.type !== 'ArrayExpression') {\n return failAt(\n `share's options must be a list of names, ${SHARE_EXAMPLE}`,\n source,\n list.start,\n file,\n );\n }\n for (const element of list.elements) {\n if (!element || element.type !== 'Literal' || typeof element.value !== 'string') {\n return failAt(\n `share's options must be names written as strings, ${SHARE_EXAMPLE}`,\n source,\n element?.start ?? list.start,\n file,\n );\n }\n const name = element.value;\n if (!isSharedOptionName(name)) {\n return failAt(\n `\"${name}\" can't go in a link. Use letters, digits, \"-\" and \"_\"`,\n source,\n element.start,\n file,\n );\n }\n if (options.includes(name)) {\n return failAt(`\"${name}\" is in share's options twice`, source, element.start, file);\n }\n options.push(name);\n }\n if (options.length > MAX_SHARED_OPTIONS) {\n return failAt(\n `A link can carry at most ${MAX_SHARED_OPTIONS} options`,\n source,\n list.start,\n file,\n );\n }\n }\n return options;\n}\n\n// Only hooks written in an object literal are checked.\nfunction readHooks(node: Expression, source: string, file: string): string[] {\n if (node.type !== 'ObjectExpression') {\n return [];\n }\n const hooks: string[] = [];\n for (const hook of staticProperties(node)) {\n if (!HOOKS.has(hook.name)) {\n failAt(\n `Unknown page hook \\`${hook.name}\\`. The hooks are ${PAGE_HOOKS.join(', ')}`,\n source,\n hook.start,\n file,\n );\n }\n hooks.push(hook.name);\n }\n return hooks;\n}\n\nfunction isFunction(node: Expression): boolean {\n return node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression';\n}\n\n// The properties of the object literal that `node` is or names. Null when any can't be read\n// without running the code.\nfunction resolvedProperties(program: Program, node: Expression): StaticProperty[] | null {\n const object = resolveObject(program, node);\n if (!object) {\n return null;\n }\n const properties = staticProperties(object);\n if (properties.length !== object.properties.length) {\n return null;\n }\n return properties;\n}\n\nfunction namesOf(properties: readonly StaticProperty[] | null): string[] | null {\n if (properties === null) {\n return null;\n }\n return properties.map((property) => property.name);\n}\n\nfunction offsetsOf(properties: readonly StaticProperty[]): Record<string, number> {\n const offsets: Record<string, number> = {};\n for (const property of properties) {\n offsets[property.name] = property.start;\n }\n return offsets;\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 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 continue;\n }\n if (!declarator.init) {\n return null;\n }\n return resolveObject(program, declarator.init);\n }\n }\n return null;\n}\n\nexport function readPageId(node: Expression, source: string, file: string): string {\n const value = unwrapExpression(node);\n if (value.type !== 'Literal' || typeof value.value !== 'string') {\n return failAt(\n \"A page id must be written as a string, such as 'cart'\",\n source,\n node.start,\n file,\n );\n }\n if (!isPageId(value.value)) {\n return failAt(\n `\"${value.value}\" isn't a valid page id. Use letters, digits, \"-\" and \"_\", with \"/\" between folders`,\n source,\n node.start,\n file,\n );\n }\n return value.value;\n}\n","import { failAt } from './errors';\nimport { readPageId } from './ast/page/parse';\nimport { defineCall, parseModule } from './module';\nimport { staticProperties, unwrapExpression } from './utils';\n\nexport interface DotModuleIR {\n readonly pages: readonly string[];\n readonly lastPage: { readonly start: number; readonly end: number };\n}\n\nexport function parseDotModule(source: string, file = 'dot.ts'): DotModuleIR {\n const program = parseModule(source, file);\n const options = defineCall(program, source, file, 'defineDot');\n const pagesProperty = staticProperties(options).find((property) => property.name === 'pages');\n if (!pagesProperty) {\n return failAt(\n 'defineDot needs `pages`, a list of page folders with the entry page first',\n source,\n options.start,\n file,\n );\n }\n const { value, start } = pagesProperty;\n const pageList = unwrapExpression(value);\n if (pageList.type !== 'ArrayExpression') {\n return failAt('`pages` must be a list of page folders', source, start, file);\n }\n if (pageList.elements.length === 0) {\n return failAt('`pages` needs at least one page', source, start, file);\n }\n const pages = pageList.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 readPageId(element, source, file);\n });\n // The check above fails on a hole, so the last element is there.\n const lastPage = pageList.elements.at(-1)!;\n return { pages, lastPage: { start: lastPage.start, end: lastPage.end } };\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\ntype LiteralNode = { readonly type: 'Literal'; readonly value: LiteralValue };\n\ntype IdentifierNode = { readonly type: 'Identifier'; readonly name: string };\n\ntype MemberNode = {\n readonly type: 'Member';\n readonly object: ExprNode;\n readonly property: ExprNode;\n};\n\nexport type UnaryOperator = (typeof UNARY_OPERATORS)[number];\n\ntype UnaryExprNode = {\n readonly type: 'Unary';\n readonly operator: UnaryOperator;\n readonly argument: ExprNode;\n};\n\nexport type BinaryOperator = (typeof BINARY_OPERATORS)[number];\n\ntype BinaryExprNode = {\n readonly type: 'Binary';\n readonly operator: BinaryOperator;\n readonly left: ExprNode;\n readonly right: ExprNode;\n};\n\ntype 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 what's inside a `{{ }}` binding into an expression tree.\nexport function parseExpression(source: string): ExprNode {\n if (source.trim().length === 0) {\n failAt('The binding is empty', source, 0);\n }\n const { program, errors } = parseSync('binding.js', source, { preserveParens: false });\n failOnSyntaxError(errors, source);\n const statement = program.body[0];\n if (program.body.length !== 1 || statement?.type !== 'ExpressionStatement') {\n return failAt('A binding must be one expression', source, statement?.start ?? 0);\n }\n return toExprNode(statement.expression, source);\n}\n\nfunction toExprNode(node: Expression, source: string): ExprNode {\n switch (node.type) {\n case 'Literal':\n if (typeof node.value === 'bigint' || node.value instanceof RegExp) {\n return failUnsupported(node, source);\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 return failUnsupported(node, source);\n }\n const object = toExprNode(node.object, source);\n if (node.computed) {\n return { type: 'Member', object, property: toExprNode(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 return failUnsupported(node, source);\n }\n return {\n type: 'Unary',\n operator: node.operator,\n argument: toExprNode(node.argument, source),\n };\n case 'BinaryExpression':\n case 'LogicalExpression':\n if (node.left.type === 'PrivateIdentifier' || !isOneOf(BINARY_OPERATORS, node.operator)) {\n return failUnsupported(node, source);\n }\n return {\n type: 'Binary',\n operator: node.operator,\n left: toExprNode(node.left, source),\n right: toExprNode(node.right, source),\n };\n case 'ConditionalExpression':\n return {\n type: 'Conditional',\n test: toExprNode(node.test, source),\n consequent: toExprNode(node.consequent, source),\n alternate: toExprNode(node.alternate, source),\n };\n case 'CallExpression':\n case 'NewExpression':\n return failAt(\"Bindings can't call functions\", source, node.start);\n case 'AssignmentExpression':\n case 'UpdateExpression':\n return failAt(\"Bindings can't change values\", source, node.start);\n default:\n return failUnsupported(node, source);\n }\n}\n\nfunction failUnsupported(node: Expression, source: string): never {\n let detail = '';\n if ('operator' in node) {\n detail = ` \\`${node.operator}\\``;\n }\n return failAt(`Bindings can't use ${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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monimesl/dot-script-parser",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.23",
|
|
4
4
|
"description": "Dot page script parser: page state and logic -> intermediary representation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"oxc-parser": "^0.151.0",
|
|
35
|
-
"@monimesl/dot-core": "0.1.0-alpha.
|
|
35
|
+
"@monimesl/dot-core": "0.1.0-alpha.23"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|