@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 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
@@ -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":";;;;;;;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"}
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
- 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);
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
- collectReferences(program, null, "", references);
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.forEach((specifier) => names.add(specifier.local.name));
114
+ for (const specifier of declaration.specifiers) names.add(specifier.local.name);
97
115
  break;
98
116
  case "VariableDeclaration":
99
- declaration.declarations.forEach((declarator) => collectPatternNames(declarator.id, names));
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
- const visit = (child) => {
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.forEach((property) => visit(property.type === "RestElement" ? property.argument : property.value));
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.forEach(visit);
136
+ for (const element of pattern.elements) collectPatternNames(element, names);
120
137
  break;
121
138
  case "RestElement":
122
- visit(pattern.argument);
139
+ collectPatternNames(pattern.argument, names);
123
140
  break;
124
- case "AssignmentPattern": visit(pattern.left);
141
+ case "AssignmentPattern": collectPatternNames(pattern.left, names);
125
142
  }
126
143
  }
127
- function collectReferences(node, parent, key, out) {
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)) 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);
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
- return typeof value?.type === "string";
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
- return { keys: resolvedKeys(program, exported) };
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": break;
194
+ case "initialState":
195
+ case "configs": break;
166
196
  case "id":
167
- id = pageId(value, source, file);
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
- 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
- }
203
+ hooks.push(...readHooks(value, source, file));
175
204
  break;
176
205
  case "mutations":
177
- mutations = resolvedKeys(program, value);
206
+ mutations = resolvedProperties(program, value);
178
207
  break;
179
208
  case "actions":
180
- actions = resolvedKeys(program, value);
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
- mutations,
190
- actions,
191
- hooks
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 resolvedKeys(program, node) {
262
+ function resolvedProperties(program, node) {
198
263
  const object = resolveObject(program, node);
199
264
  if (!object) return null;
200
- return staticKeys(object);
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) if (declarator.id.type === "Identifier" && declarator.id.name === target.name) return declarator.init ? resolveObject(program, declarator.init) : null;
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 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) {
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 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);
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`: the dot's page folders, starting page first", source, options.start, file);
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 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) => {
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 pageId(element, source, file);
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("Empty expression", source, 0);
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 [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);
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 convert(node, source) {
359
+ function toExprNode(node, source) {
280
360
  switch (node.type) {
281
361
  case "Literal":
282
- if (typeof node.value === "bigint" || node.value instanceof RegExp) break;
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") break;
293
- const object = convert(node.object, source);
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: convert(node.property, source)
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)) break;
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: convert(node.argument, source)
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)) break;
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: convert(node.left, source),
322
- right: convert(node.right, source)
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: convert(node.test, source),
327
- consequent: convert(node.consequent, source),
328
- alternate: convert(node.alternate, source)
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("Function calls are currently not allowed in bindings", source, node.start);
411
+ case "NewExpression": return failAt("Bindings can't call functions", source, node.start);
332
412
  case "AssignmentExpression":
333
- case "UpdateExpression": return failAt("Update expressions are currently not allowed in bindings", source, node.start);
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(`Unsupported syntax in binding: ${node.type}${detail}`, source, node.start);
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.2",
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.2"
35
+ "@monimesl/dot-core": "0.1.0-alpha.23"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"