@monimesl/dot-script-parser 0.1.0-alpha.4 → 0.1.0-alpha.41

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,11 +1,8 @@
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 {
@@ -70,6 +67,7 @@ interface PageStateModule {
70
67
  }
71
68
  interface PageModule {
72
69
  readonly id: string | null;
70
+ readonly share: readonly string[] | null;
73
71
  readonly hooks: readonly string[];
74
72
  readonly mutations: readonly string[] | null;
75
73
  readonly actions: readonly string[] | null;
@@ -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;WACN;WACA;aAAqB;aAAwB;;;wBAGxC,eAAe,gBAAgB,gBAAkB;;;qBCPpD,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;WAEA,YAAY,SAAS;;UAGf;WACN;WACA;WACA;WACA;WAEA,gBAAgB,SAAS;;;;wBCFpB,iBAAiB,gBAAgB,gBAAoB;wBAarD,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,5 +1,5 @@
1
1
  import { parseSync } from "oxc-parser";
2
- import { PAGE_HOOKS, SourceError, isPageId, locationAt } from "@monimesl/dot-core";
2
+ import { MAX_SHARED_OPTIONS, PAGE_HOOKS, SourceError, isPageId, isSharedOptionName, locationAt } from "@monimesl/dot-core";
3
3
  //#region src/utils.ts
4
4
  function propertyName(key) {
5
5
  if (key.type === "Identifier") return key.name;
@@ -63,9 +63,16 @@ function defaultExport(program) {
63
63
  }
64
64
  function defineCall(program, source, file, callee) {
65
65
  const exported = defaultExport(program);
66
- const call = exported && unwrapExpression(exported);
67
- const options = call?.type === "CallExpression" ? call.arguments[0] : void 0;
68
- 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;
69
76
  return options;
70
77
  }
71
78
  function fileName(path) {
@@ -74,27 +81,40 @@ function fileName(path) {
74
81
  }
75
82
  //#endregion
76
83
  //#region src/globals.ts
77
- /**
78
- * Which of `names` a module reads without declaring or importing them at its top level. The
79
- * compiler imports those for the module, so a dot's code can use framework functions as globals.
80
- */
81
84
  function unboundReferences(source, names, file = "module.ts") {
82
85
  const program = parseModule(source, file);
83
86
  const bound = topLevelBindings(program);
84
87
  const references = /* @__PURE__ */ new Set();
85
- collectReferences(program, null, "", references);
88
+ forEachReference(program, (identifier) => {
89
+ references.add(identifier.name);
90
+ });
86
91
  return names.filter((name) => references.has(name) && !bound.has(name));
87
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
+ }
88
108
  function topLevelBindings(program) {
89
109
  const names = /* @__PURE__ */ new Set();
90
110
  for (const statement of program.body) {
91
111
  const declaration = withoutExport(statement);
92
112
  switch (declaration?.type) {
93
113
  case "ImportDeclaration":
94
- declaration.specifiers.forEach((specifier) => names.add(specifier.local.name));
114
+ for (const specifier of declaration.specifiers) names.add(specifier.local.name);
95
115
  break;
96
116
  case "VariableDeclaration":
97
- declaration.declarations.forEach((declarator) => collectPatternNames(declarator.id, names));
117
+ for (const declarator of declaration.declarations) collectPatternNames(declarator.id, names);
98
118
  break;
99
119
  case "FunctionDeclaration":
100
120
  case "ClassDeclaration": if (declaration.id) names.add(declaration.id.name);
@@ -103,31 +123,35 @@ function topLevelBindings(program) {
103
123
  return names;
104
124
  }
105
125
  function collectPatternNames(pattern, names) {
106
- const visit = (child) => {
107
- if (isNode(child)) collectPatternNames(child, names);
108
- };
126
+ if (!isNode(pattern)) return;
109
127
  switch (pattern.type) {
110
128
  case "Identifier":
111
129
  names.add(pattern.name);
112
130
  break;
113
131
  case "ObjectPattern":
114
- 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);
115
134
  break;
116
135
  case "ArrayPattern":
117
- pattern.elements.forEach(visit);
136
+ for (const element of pattern.elements) collectPatternNames(element, names);
118
137
  break;
119
138
  case "RestElement":
120
- visit(pattern.argument);
139
+ collectPatternNames(pattern.argument, names);
121
140
  break;
122
- case "AssignmentPattern": visit(pattern.left);
141
+ case "AssignmentPattern": collectPatternNames(pattern.left, names);
123
142
  }
124
143
  }
125
- function collectReferences(node, parent, key, out) {
144
+ function forEachReference(program, visit) {
145
+ visitReferences(program, null, "", visit);
146
+ }
147
+ function visitReferences(node, parent, key, visit) {
126
148
  if (node.type === "ImportDeclaration") return;
127
- if (node.type === "Identifier" && isReference(parent, key)) out.add(node.name);
128
- 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
+ }
129
154
  }
130
- /** False for identifiers that name a property or label rather than refer to a variable. */
131
155
  function isReference(parent, key) {
132
156
  switch (parent?.type) {
133
157
  case "MemberExpression": return key !== "property" || parent.computed === true;
@@ -141,18 +165,20 @@ function isReference(parent, key) {
141
165
  }
142
166
  }
143
167
  function isNode(value) {
144
- return typeof value?.type === "string";
168
+ if (typeof value !== "object" || value === null) return false;
169
+ return typeof value.type === "string";
145
170
  }
146
171
  //#endregion
147
172
  //#region src/ast/page/parse.ts
148
173
  const HOOKS = new Set(PAGE_HOOKS);
174
+ const SHARE_EXAMPLE = "such as share: { options: ['show'] }";
149
175
  function parseStateModule(source, file = "state.ts") {
150
176
  const program = parseModule(source, file);
151
177
  const exported = defaultExport(program);
152
178
  if (!exported) return failAt("state.ts must have a default export", source, 0, file);
153
179
  const properties = resolvedProperties(program, exported);
154
180
  return {
155
- keys: properties?.map((property) => property.name) ?? null,
181
+ keys: namesOf(properties),
156
182
  keyOffsets: offsetsOf(properties ?? [])
157
183
  };
158
184
  }
@@ -160,6 +186,7 @@ function parseLogicModule(source, file = "controller.ts") {
160
186
  const program = parseModule(source, file);
161
187
  const options = defineCall(program, source, file, "definePage");
162
188
  let id = null;
189
+ let share = null;
163
190
  let mutations = [];
164
191
  let actions = [];
165
192
  const hooks = [];
@@ -167,14 +194,13 @@ function parseLogicModule(source, file = "controller.ts") {
167
194
  case "initialState":
168
195
  case "configs": break;
169
196
  case "id":
170
- id = pageId(value, source, file);
197
+ id = readPageId(value, source, file);
198
+ break;
199
+ case "share":
200
+ share = readSharedOptions(value, source, file);
171
201
  break;
172
202
  case "hooks":
173
- if (value.type !== "ObjectExpression") break;
174
- for (const hook of staticProperties(value)) {
175
- if (!HOOKS.has(hook.name)) failAt(`Unknown page hook \`${hook.name}\`. Page hooks: ${PAGE_HOOKS.join(", ")}`, source, hook.start, file);
176
- hooks.push(hook.name);
177
- }
203
+ hooks.push(...readHooks(value, source, file));
178
204
  break;
179
205
  case "mutations":
180
206
  mutations = resolvedProperties(program, value);
@@ -183,20 +209,53 @@ function parseLogicModule(source, file = "controller.ts") {
183
209
  actions = resolvedProperties(program, value);
184
210
  break;
185
211
  default: if (isFunction(value)) failAt(`\`${name}\` must go in \`mutations\` or \`actions\``, source, start, file);
186
- else failAt(`Unknown option \`${name}\`. definePage takes id, initialState, configs, 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);
187
219
  }
188
- const mutationNames = mutations?.map((property) => property.name) ?? null;
189
- const actionNames = actions?.map((property) => property.name) ?? null;
190
- const clash = mutationNames?.find((name) => actionNames?.includes(name));
191
- if (clash) failAt(`\`${clash}\` is both a mutation and an action`, source, options.start, file);
192
220
  return {
193
221
  id,
222
+ share,
194
223
  mutations: mutationNames,
195
224
  actions: actionNames,
196
225
  hooks,
197
226
  handlerOffsets: offsetsOf([...mutations ?? [], ...actions ?? []])
198
227
  };
199
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
+ }
200
259
  function isFunction(node) {
201
260
  return node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
202
261
  }
@@ -204,14 +263,18 @@ function resolvedProperties(program, node) {
204
263
  const object = resolveObject(program, node);
205
264
  if (!object) return null;
206
265
  const properties = staticProperties(object);
207
- return properties.length === object.properties.length ? properties : null;
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);
208
272
  }
209
273
  function offsetsOf(properties) {
210
274
  const offsets = {};
211
275
  for (const property of properties) offsets[property.name] = property.start;
212
276
  return offsets;
213
277
  }
214
- /** Follows `export default state` back to `const state = { ... }`. */
215
278
  function resolveObject(program, node) {
216
279
  const target = unwrapExpression(node);
217
280
  if (target.type === "ObjectExpression") return target;
@@ -219,15 +282,18 @@ function resolveObject(program, node) {
219
282
  for (const statement of program.body) {
220
283
  const declaration = withoutExport(statement);
221
284
  if (declaration?.type !== "VariableDeclaration" || declaration.kind !== "const") continue;
222
- 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
+ }
223
290
  }
224
291
  return null;
225
292
  }
226
- /** Reads a page id, which must be a string literal made of safe characters. */
227
- function pageId(node, source, file) {
293
+ function readPageId(node, source, file) {
228
294
  const value = unwrapExpression(node);
229
- if (value.type !== "Literal" || typeof value.value !== "string") return failAt("A page id must be a string literal", source, node.start, file);
230
- 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);
231
297
  return value.value;
232
298
  }
233
299
  //#endregion
@@ -235,21 +301,21 @@ function pageId(node, source, file) {
235
301
  function parseDotModule(source, file = "dot.ts") {
236
302
  const options = defineCall(parseModule(source, file), source, file, "defineDot");
237
303
  const pagesProperty = staticProperties(options).find((property) => property.name === "pages");
238
- 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);
239
305
  const { value, start } = pagesProperty;
240
- const array = unwrapExpression(value);
241
- if (array.type !== "ArrayExpression") return failAt("`pages` must be an array of page folders", source, start, file);
242
- if (array.elements.length === 0) return failAt("`pages` needs at least one page", source, start, file);
243
- const 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) => {
244
310
  if (!element || element.type === "SpreadElement") return failAt("`pages` must list each page folder as a string", source, element?.start ?? start, file);
245
- return pageId(element, source, file);
311
+ return readPageId(element, source, file);
246
312
  });
247
- const last = array.elements.at(-1);
313
+ const lastPage = pageList.elements.at(-1);
248
314
  return {
249
315
  pages,
250
316
  lastPage: {
251
- start: last.start,
252
- end: last.end
317
+ start: lastPage.start,
318
+ end: lastPage.end
253
319
  }
254
320
  };
255
321
  }
@@ -283,17 +349,17 @@ const BINARY_OPERATORS = [
283
349
  //#endregion
284
350
  //#region src/ast/expression/parse.ts
285
351
  function parseExpression(source) {
286
- if (source.trim().length === 0) failAt("Empty expression", source, 0);
352
+ if (source.trim().length === 0) failAt("The binding is empty", source, 0);
287
353
  const { program, errors } = parseSync("binding.js", source, { preserveParens: false });
288
354
  failOnSyntaxError(errors, source);
289
- const [statement, extra] = program.body;
290
- if (!statement || extra || statement.type !== "ExpressionStatement") return failAt("Expected a single expression statement", source, statement?.start ?? 0);
291
- 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);
292
358
  }
293
- function convert(node, source) {
359
+ function toExprNode(node, source) {
294
360
  switch (node.type) {
295
361
  case "Literal":
296
- if (typeof node.value === "bigint" || node.value instanceof RegExp) break;
362
+ if (typeof node.value === "bigint" || node.value instanceof RegExp) return failUnsupported(node, source);
297
363
  return {
298
364
  type: "Literal",
299
365
  value: node.value
@@ -303,12 +369,12 @@ function convert(node, source) {
303
369
  name: node.name
304
370
  };
305
371
  case "MemberExpression": {
306
- if (node.object.type === "Super" || node.property.type === "PrivateIdentifier") break;
307
- 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);
308
374
  if (node.computed) return {
309
375
  type: "Member",
310
376
  object,
311
- property: convert(node.property, source)
377
+ property: toExprNode(node.property, source)
312
378
  };
313
379
  return {
314
380
  type: "Member",
@@ -320,40 +386,43 @@ function convert(node, source) {
320
386
  };
321
387
  }
322
388
  case "UnaryExpression":
323
- if (!isOneOf(UNARY_OPERATORS, node.operator)) break;
389
+ if (!isOneOf(UNARY_OPERATORS, node.operator)) return failUnsupported(node, source);
324
390
  return {
325
391
  type: "Unary",
326
392
  operator: node.operator,
327
- argument: convert(node.argument, source)
393
+ argument: toExprNode(node.argument, source)
328
394
  };
329
395
  case "BinaryExpression":
330
396
  case "LogicalExpression":
331
- 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);
332
398
  return {
333
399
  type: "Binary",
334
400
  operator: node.operator,
335
- left: convert(node.left, source),
336
- right: convert(node.right, source)
401
+ left: toExprNode(node.left, source),
402
+ right: toExprNode(node.right, source)
337
403
  };
338
404
  case "ConditionalExpression": return {
339
405
  type: "Conditional",
340
- test: convert(node.test, source),
341
- consequent: convert(node.consequent, source),
342
- alternate: convert(node.alternate, source)
406
+ test: toExprNode(node.test, source),
407
+ consequent: toExprNode(node.consequent, source),
408
+ alternate: toExprNode(node.alternate, source)
343
409
  };
344
410
  case "CallExpression":
345
- 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);
346
412
  case "AssignmentExpression":
347
- 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);
348
415
  }
416
+ }
417
+ function failUnsupported(node, source) {
349
418
  let detail = "";
350
419
  if ("operator" in node) detail = ` \`${node.operator}\``;
351
- 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);
352
421
  }
353
422
  function isOneOf(list, value) {
354
423
  return list.includes(value);
355
424
  }
356
425
  //#endregion
357
- export { ScriptParseError, parseDotModule, parseExpression, parseLogicModule, parseStateModule, unboundReferences };
426
+ export { ScriptParseError, globalMemberUses, parseDotModule, parseExpression, parseLogicModule, parseStateModule, unboundReferences };
358
427
 
359
428
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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, 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 { 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\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 type { StaticProperty } from '../../utils';\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 const properties = resolvedProperties(program, exported);\n return {\n keys: properties?.map((property) => property.name) ?? null,\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 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 = 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 = 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, hooks, mutations and actions`,\n source,\n start,\n file,\n );\n }\n }\n }\n const mutationNames = mutations?.map((property) => property.name) ?? null;\n const actionNames = actions?.map((property) => property.name) ?? null;\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 return {\n id,\n mutations: mutationNames,\n actions: actionNames,\n hooks,\n handlerOffsets: offsetsOf([...(mutations ?? []), ...(actions ?? [])]),\n };\n}\n\nfunction isFunction(node: Expression): boolean {\n return node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression';\n}\n\n// The properties of the object literal `node` is or names, or null when they cannot all be read\n// statically.\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 return properties.length === object.properties.length ? properties : null;\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\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\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 { pageId } 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`: 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 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 const last = array.elements.at(-1)!;\n return { pages, lastPage: { start: last.start, end: last.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\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":";;;AAIA,SAAS,aAAa,KAAiC;CACrD,IAAI,IAAI,SAAS,cACf,OAAO,IAAI;CAEb,IAAI,IAAI,SAAS,aAAa,OAAO,IAAI,UAAU,UACjD,OAAO,IAAI;CAEb,OAAO;AACT;AAEA,SAAgB,iBAAiB,MAA8B;CAC7D,OACE,KAAK,SAAS,oBACd,KAAK,SAAS,2BACd,KAAK,SAAS,uBAEd,OAAO,KAAK;CAEd,OAAO;AACT;AASA,SAAgB,iBAAiB,QAA4C;CAC3E,MAAM,aAA+B,CAAC;CACtC,KAAK,MAAM,YAAY,OAAO,YAAY;EACxC,IAAI,SAAS,SAAS,cAAc,SAAS,UAC3C;EAEF,MAAM,OAAO,aAAa,SAAS,GAAG;EACtC,IAAI,SAAS,MACX,WAAW,KAAK;GAAE;GAAM,OAAO,SAAS;GAAO,OAAO,SAAS;EAAM,CAAC;CAE1E;CACA,OAAO;AACT;AAGA,SAAgB,cAAc,WAAwD;CACpF,IAAI,UAAU,SAAS,0BACrB,OAAO,UAAU;CAEnB,OAAO;AACT;;;ACjDA,IAAa,mBAAb,cAAsC,YAAY;CAChD,OAAyB;AAC3B;AAEA,SAAgB,OAAO,QAAgB,QAAgB,QAAgB,MAAsB;CAC3F,MAAM,IAAI,iBAAiB,QAAQ,MAAM,WAAW,QAAQ,MAAM,CAAC;AACrE;AAEA,SAAgB,kBACd,QACA,QACA,MACM;CACN,MAAM,CAAC,SAAS;CAChB,IAAI,OACF,OAAO,MAAM,SAAS,QAAQ,MAAM,OAAO,EAAE,EAAE,SAAS,GAAG,IAAI;AAEnE;;;ACdA,SAAgB,YAAY,QAAgB,MAAuB;CACjE,MAAM,EAAE,SAAS,WAAW,UAAU,MAAM,QAAQ;EAAE,MAAM;EAAM,YAAY;CAAS,CAAC;CACxF,kBAAkB,QAAQ,QAAQ,IAAI;CACtC,OAAO;AACT;AAEA,SAAgB,cAAc,SAA0C;CACtE,KAAK,MAAM,aAAa,QAAQ,MAAM;EACpC,IAAI,UAAU,SAAS,4BACrB;EAEF,MAAM,EAAE,gBAAgB;EACxB,QAAQ,YAAY,MAApB;GACE,KAAK;GACL,KAAK;GACL,KAAK,0BACH;GACF,SACE,OAAO;EACX;CACF;AAEF;AAGA,SAAgB,WACd,SACA,QACA,MACA,QACkB;CAClB,MAAM,WAAW,cAAc,OAAO;CACtC,IAAI;CACJ,IAAI,UACF,UAAU,YAAY,iBAAiB,QAAQ,GAAG,MAAM;CAE1D,IAAI,CAAC,SACH,OAAO,OACL,GAAG,SAAS,IAAI,EAAE,yBAAyB,OAAO,cAClD,QACA,UAAU,SAAS,GACnB,IACF;CAEF,OAAO;AACT;AAEA,SAAS,YAAY,YAAwB,QAA8C;CACzF,IAAI,WAAW,SAAS,kBACtB;CAEF,IAAI,WAAW,OAAO,SAAS,gBAAgB,WAAW,OAAO,SAAS,QACxE;CAEF,MAAM,CAAC,WAAW,WAAW;CAC7B,IAAI,SAAS,SAAS,oBACpB;CAEF,OAAO;AACT;AAGA,SAAS,SAAS,MAAsB;CACtC,MAAM,gBAAgB,KAAK,IAAI,KAAK,YAAY,GAAG,GAAG,KAAK,YAAY,IAAI,CAAC;CAC5E,OAAO,KAAK,MAAM,gBAAgB,CAAC;AACrC;;;AC1DA,SAAgB,kBACd,QACA,OACA,OAAO,aACG;CACV,MAAM,UAAU,YAAY,QAAQ,IAAI;CACxC,MAAM,QAAQ,iBAAiB,OAAO;CACtC,MAAM,6BAAa,IAAI,IAAY;CACnC,iBAAiB,UAAU,eAAe;EACxC,WAAW,IAAI,WAAW,IAAc;CAC1C,CAAC;CACD,OAAO,MAAM,QAAQ,SAAS,WAAW,IAAI,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;AACxE;AAKA,SAAgB,iBAAiB,QAAgB,MAAc,OAAO,aAAuB;CAC3F,MAAM,UAAU,YAAY,QAAQ,IAAI;CACxC,IAAI,iBAAiB,OAAO,CAAC,CAAC,IAAI,IAAI,GACpC,OAAO,CAAC;CAEV,MAAM,OAAiB,CAAC;CACxB,iBAAiB,UAAU,YAAY,QAAQ,QAAQ;EACrD,IAAI,WAAW,SAAS,MACtB,KAAK,KAAK,WAAW,QAAQ,GAAG,CAAC;CAErC,CAAC;CACD,OAAO;AACT;AAGA,SAAS,WAAW,QAAqB,KAAqB;CAC5D,IAAI,QAAQ,SAAS,sBAAsB,QAAQ,YAAY,OAAO,aAAa,MACjF,OAAO;CAET,MAAM,WAAW,OAAO;CACxB,IAAI,UAAU,SAAS,cACrB,OAAO;CAET,OAAO,SAAS;AAClB;AAEA,SAAS,iBAAiB,SAA+B;CACvD,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,aAAa,QAAQ,MAAM;EACpC,MAAM,cAAc,cAAc,SAAS;EAC3C,QAAQ,aAAa,MAArB;GACE,KAAK;IACH,KAAK,MAAM,aAAa,YAAY,YAClC,MAAM,IAAI,UAAU,MAAM,IAAI;IAEhC;GACF,KAAK;IACH,KAAK,MAAM,cAAc,YAAY,cACnC,oBAAoB,WAAW,IAAI,KAAK;IAE1C;GACF,KAAK;GACL,KAAK,oBACH,IAAI,YAAY,IACd,MAAM,IAAI,YAAY,GAAG,IAAI;EAGnC;CACF;CACA,OAAO;AACT;AAEA,SAAS,oBAAoB,SAAkB,OAA0B;CACvE,IAAI,CAAC,OAAO,OAAO,GACjB;CAEF,QAAQ,QAAQ,MAAhB;EACE,KAAK;GACH,MAAM,IAAI,QAAQ,IAAc;GAChC;EACF,KAAK;GACH,KAAK,MAAM,YAAY,QAAQ,YAC7B,IAAI,SAAS,SAAS,eACpB,oBAAoB,SAAS,UAAU,KAAK;QAE5C,oBAAoB,SAAS,OAAO,KAAK;GAG7C;EACF,KAAK;GACH,KAAK,MAAM,WAAW,QAAQ,UAC5B,oBAAoB,SAAS,KAAK;GAEpC;EACF,KAAK;GACH,oBAAoB,QAAQ,UAAU,KAAK;GAC3C;EACF,KAAK,qBACH,oBAAoB,QAAQ,MAAM,KAAK;CAE3C;AACF;AAIA,SAAS,iBAAiB,SAAkB,OAA+B;CACzE,gBAAgB,SAA4B,MAAM,IAAI,KAAK;AAC7D;AAEA,SAAS,gBACP,MACA,QACA,KACA,OACM;CACN,IAAI,KAAK,SAAS,qBAChB;CAEF,IAAI,KAAK,SAAS,gBAAgB,YAAY,QAAQ,GAAG,GACvD,MAAM,MAAM,QAAQ,GAAG;CAEzB,KAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,IAAI,GAAG;EACpD,MAAM,WAAsB,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;EACjE,KAAK,MAAM,SAAS,UAClB,IAAI,OAAO,KAAK,GACd,gBAAgB,OAAO,MAAM,UAAU,KAAK;CAGlD;AACF;AAGA,SAAS,YAAY,QAAqB,KAAsB;CAC9D,QAAQ,QAAQ,MAAhB;EACE,KAAK,oBACH,OAAO,QAAQ,cAAc,OAAO,aAAa;EACnD,KAAK;EACL,KAAK;EACL,KAAK,sBACH,OAAO,QAAQ,SAAS,OAAO,aAAa;EAC9C,KAAK;EACL,KAAK;EACL,KAAK,qBACH,OAAO,QAAQ;EACjB,SACE,OAAO;CACX;AACF;AAEA,SAAS,OAAO,OAA+B;CAC7C,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;CAET,OAAO,OAAQ,MAA6B,SAAS;AACvD;;;AC3JA,MAAM,QAAQ,IAAI,IAAY,UAAU;AACxC,MAAM,gBAAgB;AAEtB,SAAgB,iBAAiB,QAAgB,OAAO,YAA6B;CACnF,MAAM,UAAU,YAAY,QAAQ,IAAI;CACxC,MAAM,WAAW,cAAc,OAAO;CACtC,IAAI,CAAC,UACH,OAAO,OAAO,uCAAuC,QAAQ,GAAG,IAAI;CAEtE,MAAM,aAAa,mBAAmB,SAAS,QAAQ;CACvD,OAAO;EACL,MAAM,QAAQ,UAAU;EACxB,YAAY,UAAU,cAAc,CAAC,CAAC;CACxC;AACF;AAEA,SAAgB,iBAAiB,QAAgB,OAAO,iBAA6B;CACnF,MAAM,UAAU,YAAY,QAAQ,IAAI;CACxC,MAAM,UAAU,WAAW,SAAS,QAAQ,MAAM,YAAY;CAC9D,IAAI,KAAoB;CACxB,IAAI,QAAyB;CAC7B,IAAI,YAAqC,CAAC;CAC1C,IAAI,UAAmC,CAAC;CACxC,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,EAAE,MAAM,OAAO,WAAW,iBAAiB,OAAO,GAC3D,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,WACH;EACF,KAAK;GACH,KAAK,WAAW,OAAO,QAAQ,IAAI;GACnC;EACF,KAAK;GACH,QAAQ,kBAAkB,OAAO,QAAQ,IAAI;GAC7C;EACF,KAAK;GACH,MAAM,KAAK,GAAG,UAAU,OAAO,QAAQ,IAAI,CAAC;GAC5C;EACF,KAAK;GACH,YAAY,mBAAmB,SAAS,KAAK;GAC7C;EACF,KAAK;GACH,UAAU,mBAAmB,SAAS,KAAK;GAC3C;EACF,SACE,IAAI,WAAW,KAAK,GAClB,OAAO,KAAK,KAAK,6CAA6C,QAAQ,OAAO,IAAI;OAEjF,OACE,oBAAoB,KAAK,sFACzB,QACA,OACA,IACF;CAEN;CAEF,MAAM,gBAAgB,QAAQ,SAAS;CACvC,MAAM,cAAc,QAAQ,OAAO;CACnC,IAAI,iBAAiB,aAAa;EAChC,MAAM,QAAQ,cAAc,MAAM,SAAS,YAAY,SAAS,IAAI,CAAC;EACrE,IAAI,OACF,OAAO,KAAK,MAAM,sCAAsC,QAAQ,QAAQ,OAAO,IAAI;CAEvF;CACA,OAAO;EACL;EACA;EACA,WAAW;EACX,SAAS;EACT;EACA,gBAAgB,UAAU,CAAC,GAAI,aAAa,CAAC,GAAI,GAAI,WAAW,CAAC,CAAE,CAAC;CACtE;AACF;AAGA,SAAS,kBAAkB,MAAkB,QAAgB,MAAwB;CACnF,MAAM,SAAS,iBAAiB,IAAI;CACpC,IAAI,OAAO,SAAS,oBAClB,OAAO,OAAO,iCAAiC,iBAAiB,QAAQ,KAAK,OAAO,IAAI;CAE1F,MAAM,aAAa,iBAAiB,MAAM;CAC1C,IAAI,WAAW,WAAW,OAAO,WAAW,QAC1C,OAAO,OAAO,iCAAiC,iBAAiB,QAAQ,OAAO,OAAO,IAAI;CAE5F,MAAM,UAAoB,CAAC;CAC3B,KAAK,MAAM,YAAY,YAAY;EACjC,IAAI,SAAS,SAAS,WACpB,OAAO,OACL,0BAA0B,SAAS,KAAK,+BACxC,QACA,SAAS,OACT,IACF;EAEF,MAAM,OAAO,iBAAiB,SAAS,KAAK;EAC5C,IAAI,KAAK,SAAS,mBAChB,OAAO,OACL,4CAA4C,iBAC5C,QACA,KAAK,OACL,IACF;EAEF,KAAK,MAAM,WAAW,KAAK,UAAU;GACnC,IAAI,CAAC,WAAW,QAAQ,SAAS,aAAa,OAAO,QAAQ,UAAU,UACrE,OAAO,OACL,qDAAqD,iBACrD,QACA,SAAS,SAAS,KAAK,OACvB,IACF;GAEF,MAAM,OAAO,QAAQ;GACrB,IAAI,CAAC,mBAAmB,IAAI,GAC1B,OAAO,OACL,IAAI,KAAK,yDACT,QACA,QAAQ,OACR,IACF;GAEF,IAAI,QAAQ,SAAS,IAAI,GACvB,OAAO,OAAO,IAAI,KAAK,gCAAgC,QAAQ,QAAQ,OAAO,IAAI;GAEpF,QAAQ,KAAK,IAAI;EACnB;EACA,IAAI,QAAQ,SAAS,oBACnB,OAAO,OACL,4BAA4B,mBAAmB,WAC/C,QACA,KAAK,OACL,IACF;CAEJ;CACA,OAAO;AACT;AAGA,SAAS,UAAU,MAAkB,QAAgB,MAAwB;CAC3E,IAAI,KAAK,SAAS,oBAChB,OAAO,CAAC;CAEV,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,QAAQ,iBAAiB,IAAI,GAAG;EACzC,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,GACtB,OACE,uBAAuB,KAAK,KAAK,oBAAoB,WAAW,KAAK,IAAI,KACzE,QACA,KAAK,OACL,IACF;EAEF,MAAM,KAAK,KAAK,IAAI;CACtB;CACA,OAAO;AACT;AAEA,SAAS,WAAW,MAA2B;CAC7C,OAAO,KAAK,SAAS,wBAAwB,KAAK,SAAS;AAC7D;AAIA,SAAS,mBAAmB,SAAkB,MAA2C;CACvF,MAAM,SAAS,cAAc,SAAS,IAAI;CAC1C,IAAI,CAAC,QACH,OAAO;CAET,MAAM,aAAa,iBAAiB,MAAM;CAC1C,IAAI,WAAW,WAAW,OAAO,WAAW,QAC1C,OAAO;CAET,OAAO;AACT;AAEA,SAAS,QAAQ,YAA+D;CAC9E,IAAI,eAAe,MACjB,OAAO;CAET,OAAO,WAAW,KAAK,aAAa,SAAS,IAAI;AACnD;AAEA,SAAS,UAAU,YAA+D;CAChF,MAAM,UAAkC,CAAC;CACzC,KAAK,MAAM,YAAY,YACrB,QAAQ,SAAS,QAAQ,SAAS;CAEpC,OAAO;AACT;AAGA,SAAS,cAAc,SAAkB,MAA2C;CAClF,MAAM,SAAS,iBAAiB,IAAI;CACpC,IAAI,OAAO,SAAS,oBAClB,OAAO;CAET,IAAI,OAAO,SAAS,cAClB,OAAO;CAET,KAAK,MAAM,aAAa,QAAQ,MAAM;EACpC,MAAM,cAAc,cAAc,SAAS;EAC3C,IAAI,aAAa,SAAS,yBAAyB,YAAY,SAAS,SACtE;EAEF,KAAK,MAAM,cAAc,YAAY,cAAc;GACjD,IAAI,WAAW,GAAG,SAAS,gBAAgB,WAAW,GAAG,SAAS,OAAO,MACvE;GAEF,IAAI,CAAC,WAAW,MACd,OAAO;GAET,OAAO,cAAc,SAAS,WAAW,IAAI;EAC/C;CACF;CACA,OAAO;AACT;AAEA,SAAgB,WAAW,MAAkB,QAAgB,MAAsB;CACjF,MAAM,QAAQ,iBAAiB,IAAI;CACnC,IAAI,MAAM,SAAS,aAAa,OAAO,MAAM,UAAU,UACrD,OAAO,OACL,yDACA,QACA,KAAK,OACL,IACF;CAEF,IAAI,CAAC,SAAS,MAAM,KAAK,GACvB,OAAO,OACL,IAAI,MAAM,MAAM,sFAChB,QACA,KAAK,OACL,IACF;CAEF,OAAO,MAAM;AACf;;;AC7OA,SAAgB,eAAe,QAAgB,OAAO,UAAuB;CAE3E,MAAM,UAAU,WADA,YAAY,QAAQ,IACT,GAAS,QAAQ,MAAM,WAAW;CAC7D,MAAM,gBAAgB,iBAAiB,OAAO,CAAC,CAAC,MAAM,aAAa,SAAS,SAAS,OAAO;CAC5F,IAAI,CAAC,eACH,OAAO,OACL,6EACA,QACA,QAAQ,OACR,IACF;CAEF,MAAM,EAAE,OAAO,UAAU;CACzB,MAAM,WAAW,iBAAiB,KAAK;CACvC,IAAI,SAAS,SAAS,mBACpB,OAAO,OAAO,0CAA0C,QAAQ,OAAO,IAAI;CAE7E,IAAI,SAAS,SAAS,WAAW,GAC/B,OAAO,OAAO,mCAAmC,QAAQ,OAAO,IAAI;CAEtE,MAAM,QAAQ,SAAS,SAAS,KAAK,YAAY;EAC/C,IAAI,CAAC,WAAW,QAAQ,SAAS,iBAC/B,OAAO,OACL,kDACA,QACA,SAAS,SAAS,OAClB,IACF;EAEF,OAAO,WAAW,SAAS,QAAQ,IAAI;CACzC,CAAC;CAED,MAAM,WAAW,SAAS,SAAS,GAAG,EAAE;CACxC,OAAO;EAAE;EAAO,UAAU;GAAE,OAAO,SAAS;GAAO,KAAK,SAAS;EAAI;CAAE;AACzE;;;AC5CA,MAAa,kBAAkB;CAAC;CAAK;CAAK;CAAK;AAAQ;AAEvD,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACbA,SAAgB,gBAAgB,QAA0B;CACxD,IAAI,OAAO,KAAK,CAAC,CAAC,WAAW,GAC3B,OAAO,wBAAwB,QAAQ,CAAC;CAE1C,MAAM,EAAE,SAAS,WAAW,UAAU,cAAc,QAAQ,EAAE,gBAAgB,MAAM,CAAC;CACrF,kBAAkB,QAAQ,MAAM;CAChC,MAAM,YAAY,QAAQ,KAAK;CAC/B,IAAI,QAAQ,KAAK,WAAW,KAAK,WAAW,SAAS,uBACnD,OAAO,OAAO,oCAAoC,QAAQ,WAAW,SAAS,CAAC;CAEjF,OAAO,WAAW,UAAU,YAAY,MAAM;AAChD;AAEA,SAAS,WAAW,MAAkB,QAA0B;CAC9D,QAAQ,KAAK,MAAb;EACE,KAAK;GACH,IAAI,OAAO,KAAK,UAAU,YAAY,KAAK,iBAAiB,QAC1D,OAAO,gBAAgB,MAAM,MAAM;GAErC,OAAO;IAAE,MAAM;IAAW,OAAO,KAAK;GAAM;EAC9C,KAAK,cACH,OAAO;GAAE,MAAM;GAAc,MAAM,KAAK;EAAK;EAC/C,KAAK,oBAAoB;GACvB,IAAI,KAAK,OAAO,SAAS,WAAW,KAAK,SAAS,SAAS,qBACzD,OAAO,gBAAgB,MAAM,MAAM;GAErC,MAAM,SAAS,WAAW,KAAK,QAAQ,MAAM;GAC7C,IAAI,KAAK,UACP,OAAO;IAAE,MAAM;IAAU;IAAQ,UAAU,WAAW,KAAK,UAAU,MAAM;GAAE;GAE/E,OAAO;IAAE,MAAM;IAAU;IAAQ,UAAU;KAAE,MAAM;KAAW,OAAO,KAAK,SAAS;IAAK;GAAE;EAC5F;EACA,KAAK;GACH,IAAI,CAAC,QAAQ,iBAAiB,KAAK,QAAQ,GACzC,OAAO,gBAAgB,MAAM,MAAM;GAErC,OAAO;IACL,MAAM;IACN,UAAU,KAAK;IACf,UAAU,WAAW,KAAK,UAAU,MAAM;GAC5C;EACF,KAAK;EACL,KAAK;GACH,IAAI,KAAK,KAAK,SAAS,uBAAuB,CAAC,QAAQ,kBAAkB,KAAK,QAAQ,GACpF,OAAO,gBAAgB,MAAM,MAAM;GAErC,OAAO;IACL,MAAM;IACN,UAAU,KAAK;IACf,MAAM,WAAW,KAAK,MAAM,MAAM;IAClC,OAAO,WAAW,KAAK,OAAO,MAAM;GACtC;EACF,KAAK,yBACH,OAAO;GACL,MAAM;GACN,MAAM,WAAW,KAAK,MAAM,MAAM;GAClC,YAAY,WAAW,KAAK,YAAY,MAAM;GAC9C,WAAW,WAAW,KAAK,WAAW,MAAM;EAC9C;EACF,KAAK;EACL,KAAK,iBACH,OAAO,OAAO,iCAAiC,QAAQ,KAAK,KAAK;EACnE,KAAK;EACL,KAAK,oBACH,OAAO,OAAO,gCAAgC,QAAQ,KAAK,KAAK;EAClE,SACE,OAAO,gBAAgB,MAAM,MAAM;CACvC;AACF;AAEA,SAAS,gBAAgB,MAAkB,QAAuB;CAChE,IAAI,SAAS;CACb,IAAI,cAAc,MAChB,SAAS,MAAM,KAAK,SAAS;CAE/B,OAAO,OAAO,sBAAsB,KAAK,OAAO,UAAU,QAAQ,KAAK,KAAK;AAC9E;AAEA,SAAS,QAA0B,MAAoB,OAA2B;CAChF,OAAQ,KAA2B,SAAS,KAAK;AACnD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monimesl/dot-script-parser",
3
- "version": "0.1.0-alpha.4",
3
+ "version": "0.1.0-alpha.41",
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.4"
35
+ "@monimesl/dot-core": "0.1.0-alpha.41"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"