@swiftuijs/twill 0.1.0

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.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +138 -0
  3. package/bin/twill.mjs +12 -0
  4. package/dist/branches.d.ts +12 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +128 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/compiler-Bi9TNOhX.js +1127 -0
  9. package/dist/compiler-Bi9TNOhX.js.map +1 -0
  10. package/dist/compiler.d.ts +50 -0
  11. package/dist/config.d.ts +6 -0
  12. package/dist/config.js +55 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/declarations.d.ts +14 -0
  15. package/dist/declarations.js +132 -0
  16. package/dist/declarations.js.map +1 -0
  17. package/dist/defer.d.ts +17 -0
  18. package/dist/doctor.d.ts +20 -0
  19. package/dist/doctor.js +198 -0
  20. package/dist/doctor.js.map +1 -0
  21. package/dist/editor.d.ts +53 -0
  22. package/dist/editor.js +261 -0
  23. package/dist/editor.js.map +1 -0
  24. package/dist/esbuild.d.ts +3 -0
  25. package/dist/esbuild.js +7 -0
  26. package/dist/esbuild.js.map +1 -0
  27. package/dist/files-D1mERoxc.js +46 -0
  28. package/dist/files-D1mERoxc.js.map +1 -0
  29. package/dist/files.d.ts +5 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +2 -0
  32. package/dist/loader.d.ts +3 -0
  33. package/dist/loader.js +54 -0
  34. package/dist/loader.js.map +1 -0
  35. package/dist/parser.d.ts +9 -0
  36. package/dist/plugin-BGabvyT6.js +112 -0
  37. package/dist/plugin-BGabvyT6.js.map +1 -0
  38. package/dist/plugin.d.ts +9 -0
  39. package/dist/project.d.ts +62 -0
  40. package/dist/project.js +416 -0
  41. package/dist/project.js.map +1 -0
  42. package/dist/recovery.d.ts +3 -0
  43. package/dist/register.d.ts +1 -0
  44. package/dist/register.js +7 -0
  45. package/dist/register.js.map +1 -0
  46. package/dist/rollup.d.ts +3 -0
  47. package/dist/rollup.js +7 -0
  48. package/dist/rollup.js.map +1 -0
  49. package/dist/rspack.d.ts +3 -0
  50. package/dist/rspack.js +7 -0
  51. package/dist/rspack.js.map +1 -0
  52. package/dist/syntax.d.ts +11 -0
  53. package/dist/syntax.js +10 -0
  54. package/dist/syntax.js.map +1 -0
  55. package/dist/transpile-DwVekVFM.js +51 -0
  56. package/dist/transpile-DwVekVFM.js.map +1 -0
  57. package/dist/transpile.d.ts +11 -0
  58. package/dist/typescript-plugin.LICENSE.txt +375 -0
  59. package/dist/typescript-plugin.cjs +17741 -0
  60. package/dist/typescript-plugin.cjs.map +1 -0
  61. package/dist/typescript-plugin.d.ts +5 -0
  62. package/dist/vite-react.d.ts +10 -0
  63. package/dist/vite-react.js +22 -0
  64. package/dist/vite-react.js.map +1 -0
  65. package/dist/vite.d.ts +3 -0
  66. package/dist/vite.js +7 -0
  67. package/dist/vite.js.map +1 -0
  68. package/dist/webpack.d.ts +3 -0
  69. package/dist/webpack.js +7 -0
  70. package/dist/webpack.js.map +1 -0
  71. package/package.json +180 -0
  72. package/schemas/twill.schema.json +16 -0
@@ -0,0 +1,1127 @@
1
+ import MagicString from "magic-string";
2
+ import { Parser, tokTypes } from "acorn";
3
+ import { tsPlugin } from "acorn-typescript";
4
+ import jsx from "acorn-jsx";
5
+ import { GREATEST_LOWER_BOUND, TraceMap, generatedPositionFor, originalPositionFor } from "@jridgewell/trace-mapping";
6
+ //#region src/parser.js
7
+ var options = {
8
+ ecmaVersion: "latest",
9
+ sourceType: "module",
10
+ locations: true
11
+ };
12
+ var bases = {
13
+ js: Parser,
14
+ jsx: Parser.extend(jsx()),
15
+ ts: Parser.extend(tsPlugin({ allowSatisfies: true })),
16
+ tsx: Parser.extend(tsPlugin({ allowSatisfies: true }))
17
+ };
18
+ function guardAt(input, offset, implicitMember = false) {
19
+ const lexer = Parser.tokenizer(input.slice(offset), { ecmaVersion: "latest" });
20
+ const stack = [];
21
+ let first = true;
22
+ try {
23
+ for (;;) {
24
+ const label = lexer.getToken().type.label;
25
+ if (first && [
26
+ "=",
27
+ ".",
28
+ "?.",
29
+ ":",
30
+ "++/--",
31
+ "*",
32
+ "/",
33
+ "%",
34
+ "==/!=/===/!==",
35
+ "in",
36
+ "instanceof"
37
+ ].includes(label) && !(implicitMember && label === ".")) return false;
38
+ if (!stack.length && [
39
+ "if",
40
+ "for",
41
+ "while",
42
+ "switch",
43
+ "try",
44
+ "return",
45
+ "throw",
46
+ "var",
47
+ "export"
48
+ ].includes(label)) return false;
49
+ if (!first && !stack.length && label === "const") return false;
50
+ first = false;
51
+ if (!stack.length && label === "else") return true;
52
+ if (!stack.length && [
53
+ "eof",
54
+ ";",
55
+ "}"
56
+ ].includes(label)) return false;
57
+ if ([
58
+ "(",
59
+ "[",
60
+ "{",
61
+ "${"
62
+ ].includes(label)) stack.push(label);
63
+ else if ([
64
+ ")",
65
+ "]",
66
+ "}"
67
+ ].includes(label)) {
68
+ if (!stack.length) return false;
69
+ stack.pop();
70
+ }
71
+ }
72
+ } catch {
73
+ return false;
74
+ }
75
+ }
76
+ function exits(node) {
77
+ switch (node.type) {
78
+ case "ReturnStatement":
79
+ case "ThrowStatement":
80
+ case "BreakStatement":
81
+ case "ContinueStatement": return true;
82
+ case "BlockStatement": return node.body.some(exits);
83
+ case "IfStatement": return !!node.alternate && exits(node.consequent) && exits(node.alternate);
84
+ default: return false;
85
+ }
86
+ }
87
+ function awaits(node) {
88
+ if (!node || typeof node !== "object") return false;
89
+ if (node.type === "AwaitExpression" || node.await === true || node.kind === "await using") return true;
90
+ if (node.type === "DeferStatement") return node.awaited;
91
+ if ([
92
+ "FunctionDeclaration",
93
+ "FunctionExpression",
94
+ "ArrowFunctionExpression"
95
+ ].includes(node.type)) return false;
96
+ if (["ClassDeclaration", "ClassExpression"].includes(node.type)) return awaits(node.superClass) || node.body.body.some((member) => member.computed && awaits(member.key));
97
+ return Object.entries(node).some(([key, value]) => {
98
+ if (key === "loc" || key === "trailing") return false;
99
+ return Array.isArray(value) ? value.some(awaits) : !!value?.type && awaits(value);
100
+ });
101
+ }
102
+ function deferAt(input, offset) {
103
+ try {
104
+ const next = Parser.tokenizer(input.slice(offset), { ecmaVersion: "latest" }).getToken();
105
+ return next.type === tokTypes.braceL && !/[\r\n\u2028\u2029]/.test(input.slice(offset, offset + next.start));
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
110
+ function headerAt(input, offset) {
111
+ const lexer = Parser.tokenizer(input.slice(offset), options);
112
+ const stack = [];
113
+ let first = true;
114
+ const tokens = [];
115
+ try {
116
+ for (;;) {
117
+ const token = lexer.getToken();
118
+ const label = token.type.label;
119
+ if (first && label !== "name" && label !== "(") return null;
120
+ first = false;
121
+ if (!stack.length && label === "in") {
122
+ const async = tokens.length > 1 && tokens[0].value === "async";
123
+ const firstParam = tokens[async ? 1 : 0];
124
+ return {
125
+ start: offset,
126
+ end: offset + token.end,
127
+ inStart: offset + token.start,
128
+ text: input.slice(offset + tokens[0].start, offset + tokens.at(-1).end),
129
+ textStart: offset + tokens[0].start,
130
+ async,
131
+ asyncEnd: async ? offset + tokens[0].end : null,
132
+ parenthesized: firstParam.type.label === "("
133
+ };
134
+ }
135
+ if (label === "eof" || !stack.length && [
136
+ ";",
137
+ "{",
138
+ "}",
139
+ "=>"
140
+ ].includes(label)) return null;
141
+ if ([
142
+ "(",
143
+ "[",
144
+ "{"
145
+ ].includes(label)) stack.push(label);
146
+ if ([
147
+ ")",
148
+ "]",
149
+ "}"
150
+ ].includes(label)) {
151
+ if (!stack.length) return null;
152
+ stack.pop();
153
+ }
154
+ tokens.push(token);
155
+ }
156
+ } catch {
157
+ return null;
158
+ }
159
+ }
160
+ function moveNodes(node, delta, locate) {
161
+ if (!node || typeof node !== "object") return;
162
+ if (typeof node.start === "number") {
163
+ node.start += delta;
164
+ node.end += delta;
165
+ node.loc = {
166
+ start: locate(node.start),
167
+ end: locate(node.end)
168
+ };
169
+ }
170
+ for (const [key, value] of Object.entries(node)) {
171
+ if (key === "loc") continue;
172
+ if (Array.isArray(value)) value.forEach((item) => moveNodes(item, delta, locate));
173
+ else if (value && typeof value === "object") moveNodes(value, delta, locate);
174
+ }
175
+ }
176
+ var parsers = /* @__PURE__ */ new Map();
177
+ function parserFor(language) {
178
+ if (parsers.has(language)) return parsers.get(language);
179
+ const Base = bases[language];
180
+ class TwillParser extends Base {
181
+ skipHeader = null;
182
+ closures = [];
183
+ lineStarts = null;
184
+ classSuperDepth = null;
185
+ subscriptDepth = 0;
186
+ derivedClassElement = false;
187
+ implicitClosure = null;
188
+ locate(offset) {
189
+ if (!this.lineStarts) {
190
+ this.lineStarts = [0];
191
+ const breaks = /\r\n?|\n|\u2028|\u2029/g;
192
+ while (breaks.exec(this.input)) this.lineStarts.push(breaks.lastIndex);
193
+ }
194
+ let low = 0;
195
+ let high = this.lineStarts.length;
196
+ while (low + 1 < high) {
197
+ const mid = low + high >>> 1;
198
+ if (this.lineStarts[mid] <= offset) low = mid;
199
+ else high = mid;
200
+ }
201
+ return {
202
+ line: low + 1,
203
+ column: offset - this.lineStarts[low]
204
+ };
205
+ }
206
+ parseStatement(context, ...args) {
207
+ if (this.isContextual("defer") && deferAt(this.input, this.end)) {
208
+ const node = this.startNode();
209
+ const async = this.canAwait;
210
+ this.next();
211
+ const enclosing = this.implicitClosure;
212
+ const implicit = enclosing && this.currentVarScope() === this.scopeStack[enclosing.scopeIndex] ? enclosing : null;
213
+ const previousScope = implicit?.scopeIndex;
214
+ if (implicit) implicit.scopeIndex = this.scopeStack.length;
215
+ let cleanup;
216
+ try {
217
+ cleanup = this.parseArrowExpression(this.startNode(), [], async, false);
218
+ } finally {
219
+ if (implicit) implicit.scopeIndex = previousScope;
220
+ }
221
+ node.awaited = awaits(cleanup.body);
222
+ cleanup.async = node.awaited;
223
+ node.cleanup = cleanup;
224
+ return this.finishNode(node, "DeferStatement");
225
+ }
226
+ if (!this.isContextual("guard") || !guardAt(this.input, this.end, !!this.implicitClosure)) return super.parseStatement(context, ...args);
227
+ const node = this.startNode();
228
+ node.singleStatement = !!context;
229
+ this.next();
230
+ node.binding = null;
231
+ if (this.type === tokTypes._const) {
232
+ if (context) this.raise(node.start, "A guard binding requires a block; add braces around this body.");
233
+ const declaration = this.startNode();
234
+ this.next();
235
+ this.parseVar(declaration, false, "const");
236
+ node.binding = this.finishNode(declaration, "VariableDeclaration");
237
+ if (node.binding.declarations.length !== 1) this.raise(node.start, "guard const requires one binding declaration.");
238
+ } else node.test = this.parseExpression();
239
+ node.elseStart = this.start;
240
+ this.expect(tokTypes._else);
241
+ if (this.type !== tokTypes.braceL) this.unexpected();
242
+ node.failure = this.parseBlock();
243
+ if (!exits(node.failure)) this.raise(node.failure.start, "Every guard else path must exit with return, throw, break or continue.");
244
+ return this.finishNode(node, "GuardStatement");
245
+ }
246
+ tsParseTypeParameter(...args) {
247
+ const start = this.start;
248
+ const loc = this.startLoc;
249
+ const constant = this.type === tokTypes._const;
250
+ if (constant) this.next();
251
+ const parameter = super.tsParseTypeParameter(...args);
252
+ if (constant) {
253
+ parameter.const = true;
254
+ parameter.start = start;
255
+ parameter.loc.start = loc;
256
+ }
257
+ return parameter;
258
+ }
259
+ parseExprSubscripts(...args) {
260
+ this.subscriptDepth++;
261
+ try {
262
+ return super.parseExprSubscripts(...args);
263
+ } finally {
264
+ this.subscriptDepth--;
265
+ }
266
+ }
267
+ parseClassSuper(...args) {
268
+ const previous = this.classSuperDepth;
269
+ this.classSuperDepth = this.subscriptDepth;
270
+ try {
271
+ return super.parseClassSuper(...args);
272
+ } finally {
273
+ this.classSuperDepth = previous;
274
+ }
275
+ }
276
+ parseClassElement(...args) {
277
+ const previous = this.derivedClassElement;
278
+ this.derivedClassElement = !!args[0];
279
+ try {
280
+ return super.parseClassElement(...args);
281
+ } finally {
282
+ this.derivedClassElement = previous;
283
+ }
284
+ }
285
+ raise(position, message, ...args) {
286
+ if (language.startsWith("ts") && this.derivedClassElement && typeof message === "string" && message.includes("cannot have an 'override' modifier")) return;
287
+ return super.raise(position, message, ...args);
288
+ }
289
+ readToken(code) {
290
+ if (language === "ts" && code === 60 && !this.inType && this.exprAllowed) return this.readToken_lt_gt(code);
291
+ return super.readToken(code);
292
+ }
293
+ parseExprAtom(...args) {
294
+ if (this.type === tokTypes.dot) {
295
+ const closure = this.implicitClosure;
296
+ if (!closure || this.currentVarScope() !== this.scopeStack[closure.scopeIndex]) this.raise(this.start, "Implicit member access requires a trailing closure without a parameter header.");
297
+ const node = this.startNode();
298
+ node.name = "__twillImplicit";
299
+ closure.members.push(node);
300
+ return this.finishNodeAt(node, "Identifier", this.start, this.startLoc);
301
+ }
302
+ if (this.type === tokTypes._switch) return this.parseSwitchExpression();
303
+ if (language === "ts" && this.type === tokTypes.relational && this.value === "<") {
304
+ const node = this.startNode();
305
+ this.tsInType(() => {
306
+ this.next();
307
+ node.typeAnnotation = this.tsParseType();
308
+ if (!this.tsMatchRightRelational()) this.unexpected();
309
+ this.next();
310
+ });
311
+ node.expression = this.parseMaybeUnary(null, false, false, args[1]);
312
+ if (node.expression.type === "ArrowFunctionExpression") this.unexpected(node.start);
313
+ return this.finishNode(node, "TSTypeAssertion");
314
+ }
315
+ return super.parseExprAtom(...args);
316
+ }
317
+ parseSwitchExpression() {
318
+ const node = this.startNode();
319
+ this.next();
320
+ node.parenStart = this.start;
321
+ node.discriminant = this.parseParenExpression();
322
+ node.parenEnd = this.lastTokStart;
323
+ this.expect(tokTypes.braceL);
324
+ node.cases = [];
325
+ let mode, discriminator, sawDefault = false;
326
+ while (this.type !== tokTypes.braceR) {
327
+ const branch = this.startNode();
328
+ const isCase = this.type === tokTypes._case;
329
+ if (!isCase && this.type !== tokTypes._default) this.unexpected();
330
+ this.next();
331
+ this.enterScope(0);
332
+ if (!isCase) {
333
+ if (sawDefault) this.raise(branch.start, "Multiple default clauses.");
334
+ sawDefault = true;
335
+ branch.test = null;
336
+ } else if (this.type === tokTypes.braceL) {
337
+ if (mode === "value") this.raise(branch.start, "Cannot mix object patterns and value cases.");
338
+ mode = "pattern";
339
+ const errors = {
340
+ shorthandAssign: -1,
341
+ trailingComma: -1,
342
+ parenthesizedAssign: -1,
343
+ parenthesizedBind: -1,
344
+ doubleProto: -1
345
+ };
346
+ const pattern = this.parseObj(false, errors);
347
+ const tags = pattern.properties.filter((property) => property.type === "Property" && !property.computed && !property.method && property.kind === "init" && (property.value.type === "Literal" && !property.value.regex || property.value.type === "UnaryExpression" && ["+", "-"].includes(property.value.operator) && property.value.argument.type === "Literal" && typeof property.value.argument.value === "number"));
348
+ if (tags.length !== 1) this.raise(pattern.start, "An object case needs exactly one literal discriminator; other properties bind values.");
349
+ const tag = tags[0];
350
+ const key = String(tag.key.name ?? tag.key.value);
351
+ if (discriminator !== void 0 && key !== discriminator) this.raise(tag.start, "Object cases must use the same discriminator property.");
352
+ discriminator = key;
353
+ pattern.properties = pattern.properties.filter((property) => property !== tag);
354
+ this.toAssignable(pattern, true, errors);
355
+ this.checkLValPattern(pattern, 2, false);
356
+ pattern.properties.push(tag);
357
+ pattern.properties.sort((a, b) => a.start - b.start);
358
+ branch.pattern = pattern;
359
+ branch.tag = tag;
360
+ } else {
361
+ if (mode === "pattern") this.raise(branch.start, "Cannot mix object patterns and value cases.");
362
+ mode = "value";
363
+ branch.test = this.parseExpression();
364
+ }
365
+ branch.colonStart = this.start;
366
+ this.expect(tokTypes.colon);
367
+ if (this.type === tokTypes._throw) {
368
+ const thrown = this.parseThrowStatement(this.startNode());
369
+ branch.value = thrown.argument;
370
+ branch.throw = true;
371
+ branch.valueEnd = thrown.end;
372
+ } else {
373
+ branch.value = this.parseMaybeAssign();
374
+ branch.valueEnd = this.lastTokEnd;
375
+ this.semicolon();
376
+ }
377
+ this.exitScope();
378
+ node.cases.push(this.finishNode(branch, "TwillSwitchCase"));
379
+ }
380
+ this.next();
381
+ if (!node.cases.length) this.raise(node.start, "A switch expression requires at least one arm.");
382
+ node.discriminator = discriminator;
383
+ return this.finishNode(node, "TwillSwitchExpression");
384
+ }
385
+ next(...args) {
386
+ super.next(...args);
387
+ if (this.skipHeader !== null) {
388
+ const end = this.skipHeader;
389
+ this.skipHeader = null;
390
+ while (this.start < end && this.type !== tokTypes.eof) super.next(...args);
391
+ }
392
+ }
393
+ parseTrailingClosure(callee, label) {
394
+ const start = this.start;
395
+ const header = headerAt(this.input, this.end);
396
+ let params = [];
397
+ let async = false;
398
+ let parameterText = "()";
399
+ if (header) {
400
+ let text = header.text.trim();
401
+ async = header.async;
402
+ if (async) text = text.replace(/^async\s+/, "");
403
+ parameterText = text.startsWith("(") ? text : `(${text})`;
404
+ const prefix = async ? "async " : "";
405
+ try {
406
+ params = Base.parse(`${prefix}${parameterText} => {}`, {
407
+ ...options,
408
+ sourceType: this.options.sourceType
409
+ }).body[0].expression.params;
410
+ const sourceStart = header.textStart + header.text.indexOf(text);
411
+ const addedParen = text.startsWith("(") ? 0 : 1;
412
+ params.forEach((param) => moveNodes(param, sourceStart - prefix.length - addedParen, (offset) => this.locate(offset)));
413
+ } catch (error) {
414
+ this.raise(start, `Invalid trailing closure parameters: ${error.message}`);
415
+ }
416
+ }
417
+ const node = this.startNode();
418
+ this.skipHeader = header?.end ?? null;
419
+ const previous = this.implicitClosure;
420
+ const implicit = header ? null : {
421
+ scopeIndex: this.scopeStack.length,
422
+ members: []
423
+ };
424
+ this.implicitClosure = implicit;
425
+ let arrow;
426
+ try {
427
+ arrow = this.parseArrowExpression(node, params, async, false);
428
+ } finally {
429
+ this.implicitClosure = previous;
430
+ }
431
+ this.closures.push({
432
+ node: arrow,
433
+ callee,
434
+ label,
435
+ header,
436
+ parameterText,
437
+ async,
438
+ implicitMembers: implicit?.members ?? []
439
+ });
440
+ return arrow;
441
+ }
442
+ parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow, optionalChained, forInit) {
443
+ const classBody = this.classSuperDepth !== null && this.subscriptDepth === this.classSuperDepth + 1;
444
+ if (!noCalls && !classBody && this.tsMatchLeftRelational?.() && this.start === base.end) {
445
+ const parameters = this.tsTryParseAndCatch(() => {
446
+ const parsed = this.tsParseTypeArgumentsInExpression();
447
+ return parsed && this.type === tokTypes.braceL && !/[\r\n\u2028\u2029]/.test(this.input.slice(parsed.end, this.start)) ? parsed : void 0;
448
+ });
449
+ if (parameters) {
450
+ const instantiation = this.startNodeAt(startPos, startLoc);
451
+ instantiation.expression = base;
452
+ instantiation.typeParameters = parameters;
453
+ base = this.finishNode(instantiation, "TSInstantiationExpression");
454
+ }
455
+ }
456
+ const supported = [
457
+ "CallExpression",
458
+ "Identifier",
459
+ "MemberExpression",
460
+ "TSInstantiationExpression"
461
+ ].includes(base.type);
462
+ if (!noCalls && supported && this.type === tokTypes.braceL && !classBody) {
463
+ if (base.trailing) this.raise(this.start, "Additional trailing closures require labels (for example completion: { ... }).");
464
+ if (base.type !== "CallExpression" && /[\r\n]/.test(this.input.slice(base.end, this.start))) return base;
465
+ const hadParens = base.type === "CallExpression" && base.end === this.lastTokEnd;
466
+ const callee = hadParens ? base.callee : base.type === "TSInstantiationExpression" ? base.expression : base;
467
+ const node = this.startNodeAt(startPos, startLoc);
468
+ node.callee = callee;
469
+ node.arguments = hadParens ? [...base.arguments] : [];
470
+ node.optional = base.optional ?? false;
471
+ if ((hadParens || base.type === "TSInstantiationExpression") && base.typeParameters) node.typeParameters = base.typeParameters;
472
+ const callEnd = this.lastTokEnd;
473
+ const args = [this.parseTrailingClosure(callee, null)];
474
+ while (this.type === tokTypes.name) {
475
+ const tail = this.input.slice(this.end);
476
+ const lexer = Parser.tokenizer(tail, options);
477
+ if (lexer.getToken().type !== tokTypes.colon || lexer.getToken().type !== tokTypes.braceL) break;
478
+ const label = {
479
+ name: this.value,
480
+ start: this.start,
481
+ end: this.end
482
+ };
483
+ this.next();
484
+ this.expect(tokTypes.colon);
485
+ args.push(this.parseTrailingClosure(callee, label));
486
+ }
487
+ node.arguments.push(...args);
488
+ node.trailing = {
489
+ callEnd,
490
+ hadParens,
491
+ originalArgs: hadParens ? base.arguments : [],
492
+ closures: args
493
+ };
494
+ return this.finishNode(node, "CallExpression");
495
+ }
496
+ return super.parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow, optionalChained, forInit);
497
+ }
498
+ }
499
+ parsers.set(language, TwillParser);
500
+ return TwillParser;
501
+ }
502
+ function parse(source, language = "ts", sourceType = "module") {
503
+ const TwillParser = parserFor(language);
504
+ const comments = [];
505
+ const parser = new TwillParser({
506
+ ...options,
507
+ sourceType,
508
+ allowHashBang: true,
509
+ onComment: comments
510
+ }, source);
511
+ const ast = parser.parse();
512
+ const live = /* @__PURE__ */ new Set();
513
+ const calls = [];
514
+ const guards = [];
515
+ const defers = [];
516
+ const switches = [];
517
+ const visit = (node) => {
518
+ if (!node || typeof node !== "object") return;
519
+ if (node.type === "ArrowFunctionExpression" || node.type === "Identifier" && node.start === node.end && node.name === "__twillImplicit") live.add(node);
520
+ if (node.trailing) calls.push(node);
521
+ if (node.type === "GuardStatement") guards.push(node);
522
+ if (node.type === "DeferStatement") defers.push(node);
523
+ if (node.type === "TwillSwitchExpression") switches.push(node);
524
+ for (const [key, value] of Object.entries(node)) {
525
+ if (key === "trailing" || key === "loc") continue;
526
+ if (Array.isArray(value)) value.forEach(visit);
527
+ else if (value?.type) visit(value);
528
+ }
529
+ };
530
+ visit(ast);
531
+ return {
532
+ ast,
533
+ calls,
534
+ guards,
535
+ defers,
536
+ switches,
537
+ comments,
538
+ closures: parser.closures.filter((closure) => live.has(closure.node)).map((closure) => ({
539
+ ...closure,
540
+ implicitMembers: closure.implicitMembers.filter((node) => live.has(node)).map((node) => node.start)
541
+ }))
542
+ };
543
+ }
544
+ //#endregion
545
+ //#region src/defer.ts
546
+ var functions = /* @__PURE__ */ new Set([
547
+ "FunctionDeclaration",
548
+ "FunctionExpression",
549
+ "ArrowFunctionExpression"
550
+ ]);
551
+ function children(node, visit) {
552
+ for (const [key, value] of Object.entries(node)) {
553
+ if (key === "loc" || key === "trailing") continue;
554
+ if (Array.isArray(value)) value.forEach((child) => {
555
+ if (child?.type) visit(child);
556
+ });
557
+ else if (value?.type) visit(value);
558
+ }
559
+ }
560
+ /** Scope-local cleanup callbacks; dynamic registrations use lazy stacks. */
561
+ function lowerDefers(source, ast, code, language, usedNames, contentStarts, comments, fail) {
562
+ const scopes = [];
563
+ const visit = (node, scope, parent) => {
564
+ if (functions.has(node.type) || [
565
+ "Program",
566
+ "TSModuleBlock",
567
+ "SwitchCase"
568
+ ].includes(node.type)) scope = void 0;
569
+ if (node.type === "BlockStatement" || node.type === "StaticBlock") {
570
+ scope = {
571
+ block: node,
572
+ functionBody: !!parent && functions.has(parent.type) && parent.body === node,
573
+ defers: []
574
+ };
575
+ scopes.push(scope);
576
+ }
577
+ if (node.type === "DeferStatement") {
578
+ if (!scope) fail(node, "defer requires an explicit block or function body; wrap a switch case in braces.");
579
+ scope.defers.push(node);
580
+ const check = (item) => {
581
+ if (functions.has(item.type)) return;
582
+ if (item.type === "ReturnStatement") fail(item, "A defer cleanup cannot return; use a nested function for local early returns.");
583
+ children(item, check);
584
+ };
585
+ check(node.cleanup.body);
586
+ }
587
+ children(node, (child) => visit(child, scope, node));
588
+ };
589
+ visit(ast, void 0);
590
+ let counter = 0;
591
+ const fresh = (part) => {
592
+ let name;
593
+ do
594
+ name = `__twill${part}${counter++}`;
595
+ while (usedNames.has(name));
596
+ usedNames.add(name);
597
+ return name;
598
+ };
599
+ const sortedComments = [...comments].sort((a, b) => b.end - a.end);
600
+ const leadingComment = (statement, minimum) => {
601
+ let start = statement.start;
602
+ for (const comment of sortedComments) {
603
+ if (comment.end > start || comment.start < minimum) continue;
604
+ if (/\S/.test(source.slice(comment.end, start))) break;
605
+ if (comment.type === "Block" && comment.value.startsWith("*")) start = comment.start;
606
+ else break;
607
+ }
608
+ return start;
609
+ };
610
+ for (const scope of scopes) {
611
+ if (!scope.defers.length) continue;
612
+ const { block } = scope;
613
+ const statements = block.body;
614
+ const single = scope.defers.length === 1 && statements.includes(scope.defers[0]);
615
+ const stack = fresh(single ? "Cleanup" : "Defers");
616
+ const failure = single ? "" : fresh("Failure");
617
+ const failed = single ? "" : fresh("Failed");
618
+ const callback = single ? stack : fresh("Cleanup");
619
+ const error = single ? "" : fresh("Error");
620
+ const anyAsync = scope.defers.some((node) => node.awaited);
621
+ const allAsync = scope.defers.every((node) => node.awaited);
622
+ const mixed = anyAsync && !allAsync;
623
+ const storageType = single ? "(() => unknown) | undefined" : `Array<${mixed ? "{ run: () => unknown; async: boolean }" : "() => unknown"}> | undefined`;
624
+ const annotation = language.startsWith("ts") ? `: ${storageType}` : "";
625
+ const jsdoc = language.startsWith("js") ? `\n/** @type {${storageType}} */\n` : "";
626
+ let start = contentStarts.get(block) ?? block.start + 1;
627
+ if (block.type === "StaticBlock") start = statements[0].start;
628
+ let index = 0;
629
+ while (statements[index]?.directive) start = statements[index++].end;
630
+ const ordinary = statements.slice(index);
631
+ const declarations = scope.functionBody ? ordinary.filter((node) => node.type === "FunctionDeclaration") : [];
632
+ if (scope.functionBody && ordinary.some((node) => node.type === "TSDeclareFunction")) fail(ordinary.find((node) => node.type === "TSDeclareFunction"), "Function overloads/ambient function declarations in a defer scope are not supported; move them to a separate scope.");
633
+ const names = [...new Set(declarations.map((node) => node.id.name))];
634
+ code.appendLeft(start, `;${jsdoc}let ${stack}${annotation};${names.length ? `var ${names.join(",")};` : ""}try {\n`);
635
+ let anchor = start;
636
+ const initial = /* @__PURE__ */ new Set();
637
+ for (const statement of ordinary) {
638
+ if (statement.type !== "FunctionDeclaration") break;
639
+ initial.add(statement);
640
+ anchor = statement.end;
641
+ }
642
+ for (const declaration of declarations) {
643
+ const commentStart = leadingComment(declaration, start);
644
+ if (!initial.has(declaration)) code.move(commentStart, declaration.end, anchor);
645
+ if (commentStart < declaration.start) code.prependLeft(commentStart, "\n");
646
+ code.move(declaration.start, declaration.id.start, declaration.id.end);
647
+ code.appendLeft(declaration.id.end, " = ");
648
+ code.appendLeft(declaration.end, ";");
649
+ }
650
+ for (const node of scope.defers) {
651
+ const arrow = `${node.awaited ? "async " : ""}() => `;
652
+ const prefix = single ? `${stack} = ${arrow}` : `(${stack} ??= []).push(${mixed ? `{ async: ${node.awaited}, run: ` : ""}${arrow}`;
653
+ code.overwrite(node.start, node.cleanup.body.start, prefix);
654
+ code.appendLeft(node.end, single ? ";" : `${mixed ? "}" : ""});`);
655
+ }
656
+ if (single) {
657
+ const call = allAsync ? `if (${stack}) await ${stack}();` : `${stack}?.();`;
658
+ code.prependLeft(block.end - 1, `\n} finally { ${call} }\n`);
659
+ continue;
660
+ }
661
+ const call = mixed ? `if (${callback}.async) await ${callback}.run(); else ${callback}.run();` : `${allAsync ? "await " : ""}${callback}();`;
662
+ code.prependLeft(block.end - 1, `} finally { let ${failed} = false, ${failure}; while (${stack}?.length) { const ${callback} = ${stack}.pop(); if (${callback}) { try { ${call} } catch (${error}) { ${failed} = true; ${failure} = ${error}; } } } if (${failed}) throw ${failure}; }`);
663
+ }
664
+ }
665
+ //#endregion
666
+ //#region src/branches.ts
667
+ function suspension(node) {
668
+ if (["AwaitExpression", "YieldExpression"].includes(node.type)) return node;
669
+ if ([
670
+ "FunctionDeclaration",
671
+ "FunctionExpression",
672
+ "ArrowFunctionExpression"
673
+ ].includes(node.type)) return;
674
+ for (const [key, value] of Object.entries(node)) {
675
+ if ([
676
+ "loc",
677
+ "trailing",
678
+ "tag"
679
+ ].includes(key)) continue;
680
+ for (const child of Array.isArray(value) ? value : [value]) if (child?.type) {
681
+ const found = suspension(child);
682
+ if (found) return found;
683
+ }
684
+ }
685
+ }
686
+ /** Native switches with per-arm scopes; expression contexts use a synchronous
687
+ * lexical IIFE. Direct returns need no extra function or scheduling. */
688
+ function lowerSwitchExpressions(source, ast, switches, code, language, usedNames, fail) {
689
+ const returns = /* @__PURE__ */ new Set();
690
+ const visit = (node) => {
691
+ if (node.type === "ReturnStatement" && node.argument?.type === "TwillSwitchExpression") {
692
+ returns.add(node.argument);
693
+ code.remove(node.start, node.start + 6);
694
+ for (const [start, end] of [[node.start + 6, node.argument.start], [node.argument.end, node.end]]) {
695
+ const tokens = Parser.tokenizer(source.slice(start, end), { ecmaVersion: "latest" });
696
+ for (;;) {
697
+ const token = tokens.getToken();
698
+ if (token.type === tokTypes.eof) break;
699
+ if (token.type === tokTypes.parenL || token.type === tokTypes.parenR) code.remove(start + token.start, start + token.end);
700
+ }
701
+ }
702
+ }
703
+ for (const [key, value] of Object.entries(node)) {
704
+ if ([
705
+ "loc",
706
+ "trailing",
707
+ "tag"
708
+ ].includes(key)) continue;
709
+ for (const child of Array.isArray(value) ? value : [value]) if (child?.type) visit(child);
710
+ }
711
+ };
712
+ visit(ast);
713
+ let counter = 0;
714
+ const fresh = (part) => {
715
+ let name;
716
+ do
717
+ name = `__twill${part}${counter++}`;
718
+ while (usedNames.has(name));
719
+ usedNames.add(name);
720
+ return name;
721
+ };
722
+ for (const node of switches) {
723
+ const direct = returns.has(node);
724
+ const suspended = !direct && suspension(node);
725
+ if (suspended) fail(suspended, "await/yield inside a switch expression requires a direct return. Bind the subject first, or await the whole result explicitly.");
726
+ const subject = fresh("Subject");
727
+ code.appendLeft(node.start, `${direct ? "{" : "(() => {"}const ${subject} = `);
728
+ code.remove(node.parenStart, node.parenStart + 1);
729
+ code.move(node.start, node.start + 6, node.parenEnd);
730
+ code.appendLeft(node.parenEnd, "; ");
731
+ code.overwrite(node.parenEnd, node.parenEnd + 1, ` (${subject}${node.discriminator === void 0 ? "" : `[${JSON.stringify(node.discriminator)}]`})`);
732
+ for (const branch of node.cases) if (branch.pattern) {
733
+ const { pattern, tag } = branch;
734
+ code.appendLeft(tag.value.start, fresh("Tag"));
735
+ code.move(tag.value.start, tag.value.end, pattern.start);
736
+ code.appendLeft(tag.value.end, ": { const ");
737
+ code.overwrite(branch.colonStart, branch.colonStart + 1, ` = ${subject}; ${branch.throw ? "" : "return "}`);
738
+ code.appendLeft(branch.valueEnd, "; }");
739
+ if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
740
+ } else if (!branch.throw) code.appendLeft(branch.colonStart + 1, " return ");
741
+ const hasDefault = node.cases.some((branch) => !branch.pattern && branch.test === null);
742
+ const check = !hasDefault && language.startsWith("ts") ? ` ${subject} satisfies never;` : "";
743
+ const failure = hasDefault ? "" : `${check} throw new TypeError('Non-exhaustive switch expression');`;
744
+ code.overwrite(node.end - 1, node.end, `}${failure}${direct ? "}" : "})()"}`);
745
+ }
746
+ }
747
+ //#endregion
748
+ //#region src/compiler.ts
749
+ var extensions = [".twill", ".twillx"];
750
+ function isTwillFile(id) {
751
+ return extensions.some((extension) => id.split(/[?#]/, 1)[0].endsWith(extension));
752
+ }
753
+ function inferLanguage(filename) {
754
+ if (/\.(?:twillx|tsx)$/.test(filename)) return "tsx";
755
+ if (/\.jsx$/.test(filename)) return "jsx";
756
+ if (/\.(?:js|mjs|cjs)$/.test(filename)) return "js";
757
+ return "ts";
758
+ }
759
+ var TwillSyntaxError = class extends SyntaxError {
760
+ filename;
761
+ line;
762
+ column;
763
+ offset;
764
+ frame;
765
+ constructor(source, filename, error) {
766
+ const line = error.loc?.line ?? 1;
767
+ const column = error.loc?.column ?? 0;
768
+ super(`${filename}:${line}:${column + 1}: ${error.message.replace(/\s*\(\d+:\d+\)$/, "")}`);
769
+ this.name = "TwillSyntaxError";
770
+ this.filename = filename;
771
+ this.line = line;
772
+ this.column = column;
773
+ this.offset = error.pos ?? 0;
774
+ this.frame = `${source.split(/\r\n|[\r\n\u2028\u2029]/)[line - 1] ?? ""}\n${" ".repeat(column)}^`;
775
+ }
776
+ };
777
+ function walk(node, visit) {
778
+ visit(node);
779
+ for (const [key, value] of Object.entries(node)) {
780
+ if (["loc", "trailing"].includes(key)) continue;
781
+ if (Array.isArray(value)) value.forEach((child) => {
782
+ if (child?.type) walk(child, visit);
783
+ });
784
+ else if (value?.type) walk(value, visit);
785
+ }
786
+ }
787
+ function calleeName(node) {
788
+ if (node.type === "Identifier") return node.start === node.end ? void 0 : node.name;
789
+ if (node.type === "MemberExpression" && !node.computed) {
790
+ const object = calleeName(node.object);
791
+ if (object) return `${object}.${node.property.name}`;
792
+ }
793
+ }
794
+ function transform(source, options = {}) {
795
+ const filename = options.filename ?? "input.twill";
796
+ let parsed;
797
+ try {
798
+ parsed = parse(source, options.language ?? inferLanguage(filename), options.sourceType ?? "module");
799
+ } catch (error) {
800
+ throw new TwillSyntaxError(source, filename, error);
801
+ }
802
+ const code = new MagicString(source);
803
+ const usedNames = /* @__PURE__ */ new Set();
804
+ if (parsed.guards.filter((guard) => guard.binding && guard.binding.declarations[0].id.type !== "Identifier").length || parsed.switches.length || parsed.defers.length || parsed.closures.some((closure) => closure.implicitMembers.length) || /\.twillx$/.test(filename.split(/[?#]/, 1)[0])) walk(parsed.ast, (node) => {
805
+ if (node.type === "Identifier") usedNames.add(node.name);
806
+ });
807
+ let guardCounter = 0;
808
+ for (const guard of parsed.guards) {
809
+ if (guard.singleStatement) {
810
+ code.prependLeft(guard.start, "{");
811
+ code.appendLeft(guard.end, "}");
812
+ }
813
+ if (guard.binding) {
814
+ const binding = guard.binding.declarations[0].id;
815
+ if (binding.type === "Identifier") code.remove(guard.start, guard.start + 5);
816
+ else {
817
+ let temporary;
818
+ do
819
+ temporary = `__twillGuard${guardCounter++}`;
820
+ while (usedNames.has(temporary));
821
+ usedNames.add(temporary);
822
+ const patternEnd = binding.typeAnnotation?.start ?? binding.end;
823
+ code.overwrite(guard.start, binding.start, `const ${temporary}`);
824
+ code.move(binding.start, patternEnd, guard.end);
825
+ code.prependRight(binding.start, "; const ");
826
+ code.appendLeft(patternEnd, ` = ${temporary};`);
827
+ code.overwrite(guard.elseStart, guard.elseStart + 4, `; if (${temporary} == null)`);
828
+ continue;
829
+ }
830
+ code.overwrite(guard.elseStart, guard.elseStart + 4, `; if (${binding.name} == null)`);
831
+ } else {
832
+ code.overwrite(guard.start, guard.start + 5, "if (!(");
833
+ code.overwrite(guard.elseStart, guard.elseStart + 4, "))");
834
+ }
835
+ }
836
+ const uiFile = /\.twillx$/.test(filename.split(/[?#]/, 1)[0]);
837
+ const metadataByNode = new Map(parsed.closures.map((item) => [item.node, item]));
838
+ const componentCalls = new Set(parsed.calls.filter((node) => {
839
+ const name = calleeName(node.callee);
840
+ return uiFile && node.start === node.callee.start && !!name && /^[A-Z]/.test(name.split(".").at(-1));
841
+ }));
842
+ for (const call of componentCalls) {
843
+ const implicit = call.trailing.closures.flatMap((closure) => metadataByNode.get(closure).implicitMembers)[0];
844
+ if (implicit !== void 0) throw new TwillSyntaxError(source, filename, {
845
+ message: "Implicit member access is for ordinary callbacks. Use explicit parameters for component render props or slots.",
846
+ pos: implicit,
847
+ loc: {
848
+ line: source.slice(0, implicit).split(/\r\n|[\r\n\u2028\u2029]/).length,
849
+ column: source.slice(0, implicit).split(/\r\n|[\r\n\u2028\u2029]/).at(-1).length
850
+ }
851
+ });
852
+ }
853
+ let implicitCounter = 0;
854
+ for (const metadata of parsed.closures) {
855
+ if (!metadata.implicitMembers.length) continue;
856
+ let name;
857
+ do
858
+ name = `__twillArg${implicitCounter++}`;
859
+ while (usedNames.has(name));
860
+ usedNames.add(name);
861
+ code.overwrite(metadata.node.start, metadata.node.start + 1, `(${name}) => {`);
862
+ for (const offset of metadata.implicitMembers) code.appendLeft(offset, name);
863
+ }
864
+ const pragma = [...parsed.comments.filter((comment) => comment.start < (parsed.ast.body[0]?.start ?? source.length)).map((comment) => comment.value).join("\n").matchAll(/@jsxImportSource\s+(\S+)/g)].at(-1)?.[1];
865
+ const imports = parsed.ast.body.filter((node) => node.type === "ImportDeclaration").map((node) => node.source.value);
866
+ const vueImport = imports.some((name) => name === "vue" || name.startsWith("@vue/"));
867
+ const reactImport = imports.some((name) => name === "react" || name.startsWith("react/"));
868
+ if (componentCalls.size && !pragma && !options.jsxImportSource && vueImport && reactImport) throw new TwillSyntaxError(source, filename, {
869
+ message: "Both React and Vue are imported. Select the standard JSX runtime with @jsxImportSource or tsconfig jsxImportSource.",
870
+ pos: parsed.calls[0].start,
871
+ loc: parsed.calls[0].loc.start
872
+ });
873
+ const jsxImportSource = pragma ?? options.jsxImportSource ?? (vueImport ? "vue" : "react");
874
+ const vue = jsxImportSource === "vue";
875
+ if (uiFile && !pragma && jsxImportSource !== "react") {
876
+ const start = source.startsWith("#!") ? source.indexOf("\n") + 1 : 0;
877
+ code.appendLeft(start, `/** @jsxImportSource ${jsxImportSource} */\n`);
878
+ }
879
+ const attributeClosings = [];
880
+ const componentProps = [];
881
+ const stripPunctuation = (start, end, types) => {
882
+ const text = source.slice(start, end);
883
+ const lexer = Parser.tokenizer(text, { ecmaVersion: "latest" });
884
+ const edits = new MagicString(text);
885
+ for (let token = lexer.getToken(); token.type !== tokTypes.eof; token = lexer.getToken()) if (types.includes(token.type)) edits.remove(token.start, token.end);
886
+ return edits.toString();
887
+ };
888
+ let counter = 0;
889
+ for (const node of parsed.calls) {
890
+ const { callEnd, hadParens, originalArgs, closures } = node.trailing;
891
+ const component = componentCalls.has(node);
892
+ if (component) {
893
+ if (originalArgs.length > 1 || originalArgs[0]?.type === "SpreadElement" || node.optional || node.callee.optional) throw new TwillSyntaxError(source, filename, {
894
+ message: "Component syntax accepts one props object and children; optional calls use ordinary callbacks.",
895
+ pos: node.start,
896
+ loc: node.loc.start
897
+ });
898
+ if (closures.length > 1 && !vue) throw new TwillSyntaxError(source, filename, {
899
+ message: "React components accept one children closure. Supply render props in the props object.",
900
+ pos: closures[1].start,
901
+ loc: closures[1].loc.start
902
+ });
903
+ if (vue) {
904
+ const labels = /* @__PURE__ */ new Set(["default"]);
905
+ for (const closure of closures.slice(1)) {
906
+ const label = metadataByNode.get(closure).label;
907
+ const name = source.slice(label.start, label.end);
908
+ if (labels.has(name)) throw new TwillSyntaxError(source, filename, {
909
+ message: `Duplicate Vue slot: ${name}`,
910
+ pos: label.start,
911
+ loc: closure.loc.start
912
+ });
913
+ labels.add(name);
914
+ }
915
+ }
916
+ const opening = vue ? ">{({default: " : ">{(";
917
+ const tagEnd = node.typeParameters?.end ?? node.callee.end;
918
+ code.appendLeft(node.callee.start, "(<");
919
+ const props = originalArgs[0];
920
+ if (!vue && props?.type === "ObjectExpression" && props.properties.every((property) => property.type === "SpreadElement" || property.kind === "init" && !property.method && !property.computed && (property.key.name ?? property.key.value) !== "__proto__" && /^[A-Za-z_$][\w$.:-]*$/.test(String(property.key.name ?? property.key.value)))) {
921
+ componentProps.push({
922
+ start: props.start,
923
+ end: props.end,
924
+ properties: props.properties.filter((property) => property.type !== "SpreadElement").map((property) => ({
925
+ name: String(property.key.name ?? property.key.value),
926
+ start: property.key.start,
927
+ end: property.key.end,
928
+ shorthand: Boolean(property.shorthand)
929
+ }))
930
+ });
931
+ code.overwrite(tagEnd, props.start + 1, " " + stripPunctuation(tagEnd, props.start, [tokTypes.parenL]));
932
+ let previous = props.start + 1;
933
+ for (const property of props.properties) {
934
+ if (previous < property.start) code.overwrite(previous, property.start, stripPunctuation(previous, property.start, [tokTypes.comma]) + " ");
935
+ if (property.type === "SpreadElement") code.prependLeft(property.start, "{");
936
+ else {
937
+ const name = String(property.key.name ?? property.key.value);
938
+ if (property.shorthand) code.prependLeft(property.start, `${name}={`);
939
+ else {
940
+ code.overwrite(property.key.start, property.key.end, name);
941
+ const start = property.key.end;
942
+ const colon = Parser.tokenizer(source.slice(start, property.value.start), { ecmaVersion: "latest" }).getToken();
943
+ code.overwrite(start + colon.start, start + colon.end, "={");
944
+ }
945
+ }
946
+ attributeClosings.push(property.end);
947
+ previous = property.end;
948
+ }
949
+ const end = props.end - 1;
950
+ code.overwrite(previous, callEnd, stripPunctuation(previous, end, [tokTypes.comma]) + stripPunctuation(props.end, callEnd, [tokTypes.parenR, tokTypes.comma]) + opening);
951
+ } else if (originalArgs.length) {
952
+ const head = source.slice(tagEnd, originalArgs[0].start);
953
+ const paren = Parser.tokenizer(head, { ecmaVersion: "latest" }).getToken();
954
+ code.overwrite(tagEnd, originalArgs[0].start, " {...(" + head.slice(0, paren.start) + head.slice(paren.end));
955
+ const tailStart = originalArgs[0].end;
956
+ const tail = Parser.tokenizer(source.slice(tailStart, callEnd - 1), { ecmaVersion: "latest" });
957
+ for (let token = tail.getToken(); token.type !== tokTypes.eof; token = tail.getToken()) if (token.type === tokTypes.comma) code.remove(tailStart + token.start, tailStart + token.end);
958
+ code.overwrite(callEnd - 1, callEnd, ")}" + opening);
959
+ } else if (hadParens) {
960
+ const gap = source.slice(tagEnd, callEnd);
961
+ const tokens = Parser.tokenizer(gap, { ecmaVersion: "latest" });
962
+ const first = tokens.getToken();
963
+ const last = tokens.getToken();
964
+ code.overwrite(tagEnd, callEnd, opening + gap.slice(first.end, last.start));
965
+ } else code.appendLeft(callEnd, opening);
966
+ } else if (hadParens) {
967
+ const tailStart = originalArgs.at(-1)?.end ?? callEnd - 1;
968
+ const tail = source.slice(tailStart, callEnd - 1);
969
+ const token = Parser.tokenizer(tail, { ecmaVersion: "latest" }).getToken();
970
+ if (token.type === tokTypes.comma) code.remove(tailStart + token.start, tailStart + token.end);
971
+ code.overwrite(callEnd - 1, callEnd, originalArgs.length ? "," : "");
972
+ } else code.appendLeft(callEnd, "(");
973
+ let directChild = false;
974
+ for (const closure of closures) {
975
+ const metadata = metadataByNode.get(closure);
976
+ const body = closure.body.body;
977
+ const content = component && (vue || !metadata.header);
978
+ const expressions = body.filter((statement) => statement.type === "ExpressionStatement");
979
+ const singleContent = content && expressions.length === 1 && body.every((statement) => [
980
+ "ExpressionStatement",
981
+ "VariableDeclaration",
982
+ "FunctionDeclaration",
983
+ "ClassDeclaration",
984
+ "DeferStatement",
985
+ "EmptyStatement"
986
+ ].includes(statement.type)) && body.filter((statement) => statement.type !== "EmptyStatement").at(-1) === expressions[0];
987
+ if (singleContent && body.length === 1 && !vue) {
988
+ directChild = true;
989
+ code.remove(closure.start, closure.start + 1);
990
+ code.remove(closure.end - 1, closure.end);
991
+ const statement = expressions[0];
992
+ if (source[statement.end - 1] === ";") code.remove(statement.end - 1, statement.end);
993
+ continue;
994
+ }
995
+ if (metadata.label) {
996
+ const label = source.slice(metadata.label.start, metadata.label.end).replace(/\s*:\s*$/, "");
997
+ code.overwrite(metadata.label.start, closure.start, component && vue ? `, [${JSON.stringify(label)}]: ` : ", ");
998
+ }
999
+ if (metadata.header) {
1000
+ const header = metadata.header;
1001
+ code.overwrite(closure.start, closure.start + 1, header.parenthesized || metadata.async ? "" : "(");
1002
+ if (metadata.async && !header.parenthesized) code.appendLeft(header.asyncEnd, " (");
1003
+ code.overwrite(header.inStart, header.end, `${header.parenthesized ? "" : ") "}=> {`);
1004
+ } else if (!metadata.implicitMembers.length) code.overwrite(closure.start, closure.start + 1, "() => {");
1005
+ if (content && !singleContent) {
1006
+ let collector;
1007
+ do
1008
+ collector = `__twillChildren${counter++}`;
1009
+ while (usedNames.has(collector));
1010
+ const bodyStart = metadata.header?.end ?? closure.start + 1;
1011
+ const collect = (statement) => {
1012
+ switch (statement.type) {
1013
+ case "ExpressionStatement":
1014
+ code.prependLeft(statement.start, `${collector}.push(`);
1015
+ code.appendLeft(source[statement.end - 1] === ";" ? statement.end - 1 : statement.end, ")");
1016
+ break;
1017
+ case "BlockStatement":
1018
+ statement.body.forEach(collect);
1019
+ break;
1020
+ case "IfStatement":
1021
+ collect(statement.consequent);
1022
+ if (statement.alternate) collect(statement.alternate);
1023
+ break;
1024
+ case "GuardStatement":
1025
+ collect(statement.failure);
1026
+ break;
1027
+ case "ForStatement":
1028
+ case "ForOfStatement":
1029
+ case "ForInStatement":
1030
+ case "WhileStatement":
1031
+ case "DoWhileStatement":
1032
+ collect(statement.body);
1033
+ break;
1034
+ case "SwitchStatement":
1035
+ statement.cases.forEach((branch) => branch.consequent.forEach(collect));
1036
+ break;
1037
+ case "TryStatement":
1038
+ collect(statement.block);
1039
+ if (statement.handler) collect(statement.handler.body);
1040
+ if (statement.finalizer) collect(statement.finalizer);
1041
+ break;
1042
+ case "LabeledStatement":
1043
+ collect(statement.body);
1044
+ break;
1045
+ case "ReturnStatement": throw new TwillSyntaxError(source, filename, {
1046
+ message: "Component children collect expressions; use expressions instead of return.",
1047
+ pos: statement.start,
1048
+ loc: statement.loc.start
1049
+ });
1050
+ }
1051
+ };
1052
+ body.forEach(collect);
1053
+ code.prependLeft(bodyStart, `const ${collector} = [];`);
1054
+ code.prependLeft(closure.end - 1, vue ? `;return ${collector};` : `;return ${collector}.length === 1 ? ${collector}[0] : ${collector};`);
1055
+ } else if (singleContent || options.implicitReturn !== false && body.length === 1 && body[0].type === "ExpressionStatement") {
1056
+ const statement = singleContent ? expressions[0] : body[0];
1057
+ code.prependLeft(statement.start, "return (");
1058
+ code.appendLeft(source[statement.end - 1] === ";" ? statement.end - 1 : statement.end, ")");
1059
+ }
1060
+ }
1061
+ if (component) code.prependLeft(closures.at(-1).end, (vue ? "})}" : directChild || metadataByNode.get(closures[0]).header ? ")}" : ")()}") + `</${calleeName(node.callee)}>)`);
1062
+ else code.appendLeft(closures.at(-1).end, ")");
1063
+ }
1064
+ if (parsed.switches.length) lowerSwitchExpressions(source, parsed.ast, parsed.switches, code, options.language ?? inferLanguage(filename), usedNames, (node, message) => {
1065
+ throw new TwillSyntaxError(source, filename, {
1066
+ message,
1067
+ pos: node.start,
1068
+ loc: node.loc.start
1069
+ });
1070
+ });
1071
+ for (const end of attributeClosings) code.appendLeft(end, "}");
1072
+ if (parsed.defers.length) {
1073
+ const starts = /* @__PURE__ */ new Map();
1074
+ for (const metadata of parsed.closures) if (metadata.header) starts.set(metadata.node.body, metadata.header.end);
1075
+ lowerDefers(source, parsed.ast, code, options.language ?? inferLanguage(filename), usedNames, starts, parsed.comments, (node, message) => {
1076
+ throw new TwillSyntaxError(source, filename, {
1077
+ message,
1078
+ pos: node.start,
1079
+ loc: node.loc.start
1080
+ });
1081
+ });
1082
+ }
1083
+ const map = code.generateMap({
1084
+ source: filename,
1085
+ file: filename.replace(/\.twillx?$/, ".js"),
1086
+ includeContent: true,
1087
+ hires: true
1088
+ });
1089
+ return {
1090
+ code: code.toString(),
1091
+ map,
1092
+ changed: code.hasChanged(),
1093
+ closures: parsed.closures.length,
1094
+ guards: parsed.guards.length,
1095
+ defers: parsed.defers.length,
1096
+ switches: parsed.switches.length,
1097
+ componentProps
1098
+ };
1099
+ }
1100
+ var traceMaps = /* @__PURE__ */ new WeakMap();
1101
+ function traceMap(result) {
1102
+ let map = traceMaps.get(result);
1103
+ if (!map) {
1104
+ map = new TraceMap(result.map);
1105
+ traceMaps.set(result, map);
1106
+ }
1107
+ return map;
1108
+ }
1109
+ function originalPosition(result, line, column) {
1110
+ return originalPositionFor(traceMap(result), {
1111
+ line,
1112
+ column,
1113
+ bias: GREATEST_LOWER_BOUND
1114
+ });
1115
+ }
1116
+ function generatedPosition(result, line, column) {
1117
+ return generatedPositionFor(traceMap(result), {
1118
+ source: result.map.sources[0],
1119
+ line,
1120
+ column,
1121
+ bias: GREATEST_LOWER_BOUND
1122
+ });
1123
+ }
1124
+ //#endregion
1125
+ export { isTwillFile as a, parse as c, inferLanguage as i, extensions as n, originalPosition as o, generatedPosition as r, transform as s, TwillSyntaxError as t };
1126
+
1127
+ //# sourceMappingURL=compiler-Bi9TNOhX.js.map