@lokascript/compilation-service 2.0.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.
@@ -0,0 +1,3790 @@
1
+ import {
2
+ CoreParserAdapter,
3
+ createCoreParserAdapter
4
+ } from "./chunk-JDOSUTCM.js";
5
+ import {
6
+ SemanticParserAdapter,
7
+ createSemanticAdapter
8
+ } from "./chunk-CY26COTT.js";
9
+ import "./chunk-HMLY7DHA.js";
10
+
11
+ // ../aot-compiler/dist/index.js
12
+ var DEFAULT_OPTIONS = {
13
+ attributeNames: ["_", "data-hs", "data-hyperscript"],
14
+ includeScriptTags: true,
15
+ defaultLanguage: "en"
16
+ };
17
+ function createAttributeRegex(attrName) {
18
+ const escaped = attrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
19
+ return new RegExp(
20
+ `${escaped}\\s*=\\s*(?:"([^"]*?)"|'([^']*?)'|([^\\s>]+))`,
21
+ "gi"
22
+ );
23
+ }
24
+ var ELEMENT_REGEX = /<([a-z][a-z0-9-]*)\s+([^>]*?)>/gi;
25
+ var SCRIPT_TAG_REGEX = /<script\s+[^>]*type\s*=\s*["']text\/hyperscript["'][^>]*>([\s\S]*?)<\/script>/gi;
26
+ var ID_REGEX = /\bid\s*=\s*["']([^"']+)["']/i;
27
+ var CLASS_REGEX = /\bclass\s*=\s*["']([^"']+)["']/i;
28
+ var LANG_REGEX = /\blang\s*=\s*["']([^"']+)["']/i;
29
+ var HTMLScanner = class {
30
+ constructor(options = {}) {
31
+ this.options = { ...DEFAULT_OPTIONS, ...options };
32
+ this.attributeRegexes = /* @__PURE__ */ new Map();
33
+ for (const attr of this.options.attributeNames) {
34
+ this.attributeRegexes.set(attr, createAttributeRegex(attr));
35
+ }
36
+ }
37
+ /**
38
+ * Extract hyperscript from HTML source code.
39
+ */
40
+ extract(source, filename) {
41
+ const scripts = [];
42
+ scripts.push(...this.extractFromAttributes(source, filename));
43
+ if (this.options.includeScriptTags) {
44
+ scripts.push(...this.extractFromScriptTags(source, filename));
45
+ }
46
+ return scripts;
47
+ }
48
+ /**
49
+ * Extract hyperscript from element attributes.
50
+ */
51
+ extractFromAttributes(source, filename) {
52
+ const scripts = [];
53
+ let elementMatch;
54
+ ELEMENT_REGEX.lastIndex = 0;
55
+ while ((elementMatch = ELEMENT_REGEX.exec(source)) !== null) {
56
+ const tagName = elementMatch[1];
57
+ const attributes = elementMatch[2];
58
+ const elementStart = elementMatch.index;
59
+ const location = this.calculateLocation(source, elementStart, filename);
60
+ for (const [attrName, regex] of this.attributeRegexes) {
61
+ regex.lastIndex = 0;
62
+ const attrMatch = regex.exec(attributes);
63
+ if (attrMatch) {
64
+ const code = attrMatch[1] ?? attrMatch[2] ?? attrMatch[3];
65
+ if (code && code.trim()) {
66
+ const elementId = this.extractId(attributes);
67
+ const elementSelector = this.buildSelector(tagName, attributes, elementId);
68
+ const language = this.extractLanguage(attributes) ?? this.options.defaultLanguage;
69
+ const decodedCode = this.decodeHTMLEntities(code);
70
+ scripts.push({
71
+ code: decodedCode,
72
+ location: {
73
+ ...location,
74
+ column: location.column + attrMatch.index
75
+ },
76
+ elementId,
77
+ elementSelector,
78
+ language,
79
+ attributeName: attrName
80
+ });
81
+ }
82
+ }
83
+ }
84
+ }
85
+ return scripts;
86
+ }
87
+ /**
88
+ * Extract hyperscript from script tags.
89
+ */
90
+ extractFromScriptTags(source, filename) {
91
+ const scripts = [];
92
+ let match;
93
+ SCRIPT_TAG_REGEX.lastIndex = 0;
94
+ while ((match = SCRIPT_TAG_REGEX.exec(source)) !== null) {
95
+ const code = match[1].trim();
96
+ if (code) {
97
+ const location = this.calculateLocation(source, match.index, filename);
98
+ scripts.push({
99
+ code,
100
+ location,
101
+ language: this.options.defaultLanguage,
102
+ attributeName: "script"
103
+ });
104
+ }
105
+ }
106
+ return scripts;
107
+ }
108
+ /**
109
+ * Calculate line and column from character offset.
110
+ */
111
+ calculateLocation(source, offset, filename) {
112
+ const before = source.slice(0, offset);
113
+ const lines = before.split("\n");
114
+ const line = lines.length;
115
+ const column = (lines[lines.length - 1]?.length ?? 0) + 1;
116
+ return { file: filename, line, column };
117
+ }
118
+ /**
119
+ * Extract ID from attributes string.
120
+ */
121
+ extractId(attributes) {
122
+ const match = ID_REGEX.exec(attributes);
123
+ return match?.[1];
124
+ }
125
+ /**
126
+ * Extract language from attributes string.
127
+ */
128
+ extractLanguage(attributes) {
129
+ const match = LANG_REGEX.exec(attributes);
130
+ return match?.[1];
131
+ }
132
+ /**
133
+ * Build a CSS selector for an element.
134
+ */
135
+ buildSelector(tagName, attributes, elementId) {
136
+ if (elementId) {
137
+ return `#${elementId}`;
138
+ }
139
+ let selector = tagName;
140
+ const classMatch = CLASS_REGEX.exec(attributes);
141
+ if (classMatch) {
142
+ const classes = classMatch[1].split(/\s+/).filter(Boolean);
143
+ if (classes.length > 0) {
144
+ selector += "." + classes.join(".");
145
+ }
146
+ }
147
+ for (const attrName of this.options.attributeNames) {
148
+ if (attributes.includes(attrName + "=")) {
149
+ selector += `[${attrName}]`;
150
+ break;
151
+ }
152
+ }
153
+ return selector;
154
+ }
155
+ /**
156
+ * Decode HTML entities in attribute values.
157
+ */
158
+ decodeHTMLEntities(text) {
159
+ return text.replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&#(\d+);/g, (_, code) => String.fromCharCode(parseInt(code, 10))).replace(/&#x([0-9a-f]+);/gi, (_, code) => String.fromCharCode(parseInt(code, 16)));
160
+ }
161
+ };
162
+ var VueScanner = class extends HTMLScanner {
163
+ /**
164
+ * Extract hyperscript from Vue SFC.
165
+ */
166
+ extract(source, filename) {
167
+ const templateMatch = /<template[^>]*>([\s\S]*?)<\/template>/i.exec(source);
168
+ if (!templateMatch) {
169
+ return [];
170
+ }
171
+ const template = templateMatch[1];
172
+ const templateOffset = templateMatch.index + templateMatch[0].indexOf(">") + 1;
173
+ const scripts = super.extract(template, filename);
174
+ const linesBefore = source.slice(0, templateOffset).split("\n").length - 1;
175
+ for (const script of scripts) {
176
+ script.location.line += linesBefore;
177
+ }
178
+ return scripts;
179
+ }
180
+ };
181
+ var SvelteScanner = class extends HTMLScanner {
182
+ /**
183
+ * Extract hyperscript from Svelte component.
184
+ * Svelte components are HTML-like, so we can use the base scanner
185
+ * but need to exclude script and style blocks.
186
+ */
187
+ extract(source, filename) {
188
+ let cleanedSource = source.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, (match) => " ".repeat(match.length)).replace(/<style[^>]*>[\s\S]*?<\/style>/gi, (match) => " ".repeat(match.length));
189
+ return super.extract(cleanedSource, filename);
190
+ }
191
+ };
192
+ var JSXScanner = class {
193
+ constructor(options = {}) {
194
+ this.options = { ...DEFAULT_OPTIONS, ...options };
195
+ }
196
+ /**
197
+ * Extract hyperscript from JSX source.
198
+ * Handles both regular attributes and spread attributes.
199
+ */
200
+ extract(source, filename) {
201
+ const scripts = [];
202
+ for (const attrName of this.options.attributeNames) {
203
+ const escaped = attrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
204
+ const stringRegex = new RegExp(`${escaped}\\s*=\\s*["']([^"']+)["']`, "g");
205
+ let match;
206
+ while ((match = stringRegex.exec(source)) !== null) {
207
+ const code = match[1];
208
+ if (code && code.trim()) {
209
+ scripts.push({
210
+ code,
211
+ location: this.calculateLocation(source, match.index, filename),
212
+ language: this.options.defaultLanguage,
213
+ attributeName: attrName
214
+ });
215
+ }
216
+ }
217
+ const templateRegex = new RegExp(`${escaped}\\s*=\\s*\\{\\s*\`([^\`]+)\`\\s*\\}`, "g");
218
+ while ((match = templateRegex.exec(source)) !== null) {
219
+ const code = match[1];
220
+ if (code && code.trim()) {
221
+ scripts.push({
222
+ code,
223
+ location: this.calculateLocation(source, match.index, filename),
224
+ language: this.options.defaultLanguage,
225
+ attributeName: attrName
226
+ });
227
+ }
228
+ }
229
+ const exprRegex = new RegExp(`${escaped}\\s*=\\s*\\{\\s*["']([^"']+)["']\\s*\\}`, "g");
230
+ while ((match = exprRegex.exec(source)) !== null) {
231
+ const code = match[1];
232
+ if (code && code.trim()) {
233
+ scripts.push({
234
+ code,
235
+ location: this.calculateLocation(source, match.index, filename),
236
+ language: this.options.defaultLanguage,
237
+ attributeName: attrName
238
+ });
239
+ }
240
+ }
241
+ }
242
+ return scripts;
243
+ }
244
+ /**
245
+ * Calculate line and column from character offset.
246
+ */
247
+ calculateLocation(source, offset, filename) {
248
+ const before = source.slice(0, offset);
249
+ const lines = before.split("\n");
250
+ const line = lines.length;
251
+ const column = (lines[lines.length - 1]?.length ?? 0) + 1;
252
+ return { file: filename, line, column };
253
+ }
254
+ };
255
+ async function scanFiles(files, readFile, options = {}) {
256
+ const result = {
257
+ scripts: [],
258
+ files: [],
259
+ errors: []
260
+ };
261
+ const htmlScanner = new HTMLScanner(options);
262
+ const vueScanner = new VueScanner(options);
263
+ const svelteScanner = new SvelteScanner(options);
264
+ const jsxScanner = new JSXScanner(options);
265
+ for (const file of files) {
266
+ try {
267
+ const content = await readFile(file);
268
+ let scripts = [];
269
+ if (file.endsWith(".vue")) {
270
+ scripts = vueScanner.extract(content, file);
271
+ } else if (file.endsWith(".svelte")) {
272
+ scripts = svelteScanner.extract(content, file);
273
+ } else if (file.match(/\.(jsx|tsx)$/)) {
274
+ scripts = jsxScanner.extract(content, file);
275
+ } else if (file.match(/\.(html|htm)$/)) {
276
+ scripts = htmlScanner.extract(content, file);
277
+ }
278
+ result.scripts.push(...scripts);
279
+ result.files.push(file);
280
+ } catch (error) {
281
+ result.errors.push({
282
+ file,
283
+ error: error instanceof Error ? error.message : String(error)
284
+ });
285
+ }
286
+ }
287
+ return result;
288
+ }
289
+ function createScanner(filename, options) {
290
+ if (filename.endsWith(".vue")) {
291
+ return new VueScanner(options);
292
+ }
293
+ if (filename.endsWith(".svelte")) {
294
+ return new SvelteScanner(options);
295
+ }
296
+ if (filename.match(/\.(jsx|tsx)$/)) {
297
+ return new JSXScanner(options);
298
+ }
299
+ return new HTMLScanner(options);
300
+ }
301
+ var Analyzer = class {
302
+ /**
303
+ * Analyze an AST and return analysis results.
304
+ */
305
+ analyze(ast) {
306
+ const visitor = new AnalysisVisitor();
307
+ visitor.visit(ast);
308
+ return visitor.getResult();
309
+ }
310
+ };
311
+ var AnalysisVisitor = class {
312
+ constructor() {
313
+ this.commandsUsed = /* @__PURE__ */ new Set();
314
+ this.localVars = /* @__PURE__ */ new Map();
315
+ this.globalVars = /* @__PURE__ */ new Map();
316
+ this.contextVars = /* @__PURE__ */ new Set();
317
+ this.pureExpressions = [];
318
+ this.dynamicExpressions = [];
319
+ this.selectors = [];
320
+ this.selectorMap = /* @__PURE__ */ new Map();
321
+ this.domQueries = [];
322
+ this.eventTypes = [];
323
+ this.behaviors = [];
324
+ this.runtimeHelpers = /* @__PURE__ */ new Set();
325
+ this.warnings = [];
326
+ this.hasAsync = false;
327
+ this.hasLoops = false;
328
+ this.hasConditionals = false;
329
+ this.canThrow = false;
330
+ this.currentNestingDepth = 0;
331
+ this.maxNestingDepth = 0;
332
+ }
333
+ /**
334
+ * Visit an AST node and its children.
335
+ */
336
+ visit(node) {
337
+ if (!node) return;
338
+ switch (node.type) {
339
+ case "event":
340
+ this.visitEvent(node);
341
+ break;
342
+ case "command":
343
+ this.visitCommand(node);
344
+ break;
345
+ case "if":
346
+ this.visitIf(node);
347
+ break;
348
+ case "repeat":
349
+ this.visitRepeat(node);
350
+ break;
351
+ case "foreach":
352
+ this.visitForEach(node);
353
+ break;
354
+ case "while":
355
+ this.visitWhile(node);
356
+ break;
357
+ case "variable":
358
+ this.visitVariable(node, "read");
359
+ break;
360
+ case "selector":
361
+ this.visitSelector(node);
362
+ break;
363
+ case "binary":
364
+ this.visitBinary(node);
365
+ break;
366
+ case "call":
367
+ this.visitCall(node);
368
+ break;
369
+ case "identifier":
370
+ this.visitIdentifier(node);
371
+ break;
372
+ default:
373
+ this.visitChildren(node);
374
+ }
375
+ }
376
+ /**
377
+ * Get the analysis result.
378
+ */
379
+ getResult() {
380
+ return {
381
+ commandsUsed: this.commandsUsed,
382
+ variables: {
383
+ locals: this.localVars,
384
+ globals: this.globalVars,
385
+ contextVars: this.contextVars
386
+ },
387
+ expressions: {
388
+ pure: this.pureExpressions,
389
+ dynamic: this.dynamicExpressions,
390
+ selectors: this.selectors
391
+ },
392
+ controlFlow: {
393
+ hasAsync: this.hasAsync,
394
+ hasLoops: this.hasLoops,
395
+ hasConditionals: this.hasConditionals,
396
+ canThrow: this.canThrow,
397
+ maxNestingDepth: this.maxNestingDepth
398
+ },
399
+ dependencies: {
400
+ domQueries: [...new Set(this.domQueries)],
401
+ eventTypes: [...new Set(this.eventTypes)],
402
+ behaviors: [...new Set(this.behaviors)],
403
+ runtimeHelpers: Array.from(this.runtimeHelpers)
404
+ },
405
+ warnings: this.warnings
406
+ };
407
+ }
408
+ // ===========================================================================
409
+ // VISITOR METHODS
410
+ // ===========================================================================
411
+ visitEvent(node) {
412
+ this.eventTypes.push(node.event);
413
+ if (node.modifiers?.debounce) {
414
+ this.runtimeHelpers.add("debounce");
415
+ }
416
+ if (node.modifiers?.throttle) {
417
+ this.runtimeHelpers.add("throttle");
418
+ }
419
+ if (node.body) {
420
+ for (const child of node.body) {
421
+ this.visit(child);
422
+ }
423
+ }
424
+ }
425
+ visitCommand(node) {
426
+ this.commandsUsed.add(node.name);
427
+ switch (node.name) {
428
+ case "fetch":
429
+ this.hasAsync = true;
430
+ this.runtimeHelpers.add("fetchJSON");
431
+ this.runtimeHelpers.add("fetchText");
432
+ break;
433
+ case "wait":
434
+ case "settle":
435
+ this.hasAsync = true;
436
+ this.runtimeHelpers.add("wait");
437
+ break;
438
+ case "toggle":
439
+ this.runtimeHelpers.add("toggle");
440
+ break;
441
+ case "set":
442
+ this.runtimeHelpers.add("setProp");
443
+ break;
444
+ case "put":
445
+ this.runtimeHelpers.add("put");
446
+ break;
447
+ case "increment":
448
+ case "decrement":
449
+ this.runtimeHelpers.add("setProp");
450
+ break;
451
+ case "send":
452
+ case "trigger":
453
+ this.runtimeHelpers.add("send");
454
+ break;
455
+ case "halt":
456
+ case "exit":
457
+ this.canThrow = true;
458
+ break;
459
+ case "throw":
460
+ this.canThrow = true;
461
+ break;
462
+ case "call":
463
+ if (node.args?.[0]?.type === "identifier") {
464
+ this.behaviors.push(node.args[0].value);
465
+ }
466
+ break;
467
+ }
468
+ if (node.args) {
469
+ for (const arg of node.args) {
470
+ this.visit(arg);
471
+ }
472
+ }
473
+ if (node.target) {
474
+ this.visit(node.target);
475
+ }
476
+ }
477
+ visitIf(node) {
478
+ this.hasConditionals = true;
479
+ this.enterNesting();
480
+ this.visit(node.condition);
481
+ for (const child of node.thenBranch) {
482
+ this.visit(child);
483
+ }
484
+ if (node.elseIfBranches) {
485
+ for (const branch of node.elseIfBranches) {
486
+ this.visit(branch.condition);
487
+ for (const child of branch.body) {
488
+ this.visit(child);
489
+ }
490
+ }
491
+ }
492
+ if (node.elseBranch) {
493
+ for (const child of node.elseBranch) {
494
+ this.visit(child);
495
+ }
496
+ }
497
+ this.exitNesting();
498
+ }
499
+ visitRepeat(node) {
500
+ this.hasLoops = true;
501
+ this.enterNesting();
502
+ if (node.count && typeof node.count !== "number") {
503
+ this.visit(node.count);
504
+ }
505
+ if (node.whileCondition) {
506
+ this.visit(node.whileCondition);
507
+ }
508
+ for (const child of node.body) {
509
+ this.visit(child);
510
+ }
511
+ this.exitNesting();
512
+ }
513
+ visitForEach(node) {
514
+ this.hasLoops = true;
515
+ this.enterNesting();
516
+ this.registerVariable(node.itemName, "local", "write");
517
+ if (node.indexName) {
518
+ this.registerVariable(node.indexName, "local", "write");
519
+ }
520
+ this.visit(node.collection);
521
+ for (const child of node.body) {
522
+ this.visit(child);
523
+ }
524
+ this.exitNesting();
525
+ }
526
+ visitWhile(node) {
527
+ this.hasLoops = true;
528
+ this.enterNesting();
529
+ this.visit(node.condition);
530
+ for (const child of node.body) {
531
+ this.visit(child);
532
+ }
533
+ this.exitNesting();
534
+ }
535
+ visitVariable(node, access) {
536
+ const name = node.name.startsWith(":") || node.name.startsWith("$") ? node.name.slice(1) : node.name;
537
+ this.registerVariable(name, node.scope, access);
538
+ }
539
+ visitSelector(node) {
540
+ const selector = node.value;
541
+ if (!this.selectorMap.has(selector)) {
542
+ const info = {
543
+ selector,
544
+ usages: [],
545
+ isId: selector.startsWith("#") && !selector.includes(" "),
546
+ canCache: this.canCacheSelector(selector)
547
+ };
548
+ this.selectorMap.set(selector, info);
549
+ this.selectors.push(info);
550
+ }
551
+ this.selectorMap.get(selector).usages.push(this.currentLocation ?? { file: "", line: 0, column: 0 });
552
+ this.domQueries.push(selector);
553
+ if (this.isPureSelector(selector)) {
554
+ this.pureExpressions.push(node);
555
+ } else {
556
+ this.dynamicExpressions.push(node);
557
+ }
558
+ }
559
+ visitBinary(node) {
560
+ this.visit(node.left);
561
+ this.visit(node.right);
562
+ if (this.isPureExpression(node)) {
563
+ this.pureExpressions.push(node);
564
+ }
565
+ switch (node.operator) {
566
+ case "contains":
567
+ this.runtimeHelpers.add("contains");
568
+ break;
569
+ case "matches":
570
+ this.runtimeHelpers.add("matches");
571
+ break;
572
+ }
573
+ }
574
+ visitCall(node) {
575
+ this.visit(node.callee);
576
+ if (node.args) {
577
+ for (const arg of node.args) {
578
+ this.visit(arg);
579
+ }
580
+ }
581
+ this.dynamicExpressions.push(node);
582
+ }
583
+ visitIdentifier(node) {
584
+ const value = node.value ?? node.name;
585
+ if (!value) return;
586
+ switch (value) {
587
+ case "me":
588
+ case "my":
589
+ this.contextVars.add("me");
590
+ break;
591
+ case "you":
592
+ case "your":
593
+ this.contextVars.add("you");
594
+ break;
595
+ case "it":
596
+ case "result":
597
+ this.contextVars.add("it");
598
+ break;
599
+ case "event":
600
+ this.contextVars.add("event");
601
+ break;
602
+ case "body":
603
+ case "document":
604
+ case "window":
605
+ break;
606
+ default:
607
+ if (value.charAt(0) === value.charAt(0).toUpperCase()) {
608
+ this.behaviors.push(value);
609
+ }
610
+ }
611
+ }
612
+ // ===========================================================================
613
+ // HELPER METHODS
614
+ // ===========================================================================
615
+ visitChildren(node) {
616
+ for (const key of Object.keys(node)) {
617
+ const value = node[key];
618
+ if (value && typeof value === "object") {
619
+ if (Array.isArray(value)) {
620
+ for (const item of value) {
621
+ if (item && typeof item === "object" && "type" in item) {
622
+ this.visit(item);
623
+ }
624
+ }
625
+ } else if ("type" in value) {
626
+ this.visit(value);
627
+ }
628
+ }
629
+ }
630
+ }
631
+ registerVariable(name, scope, access) {
632
+ const map = scope === "global" ? this.globalVars : this.localVars;
633
+ if (!map.has(name)) {
634
+ map.set(name, {
635
+ name,
636
+ scope,
637
+ reads: [],
638
+ writes: [],
639
+ type: "unknown"
640
+ });
641
+ }
642
+ const info = map.get(name);
643
+ const location = this.currentLocation ?? { file: "", line: 0, column: 0 };
644
+ if (access === "read") {
645
+ info.reads.push(location);
646
+ } else {
647
+ info.writes.push(location);
648
+ }
649
+ }
650
+ enterNesting() {
651
+ this.currentNestingDepth++;
652
+ this.maxNestingDepth = Math.max(this.maxNestingDepth, this.currentNestingDepth);
653
+ }
654
+ exitNesting() {
655
+ this.currentNestingDepth--;
656
+ }
657
+ canCacheSelector(selector) {
658
+ const dynamicPseudo = /:(not|has|is|where|nth-|first-|last-|only-|empty|focus|hover|active|visited)/i;
659
+ return !dynamicPseudo.test(selector);
660
+ }
661
+ isPureSelector(selector) {
662
+ return /^[#.][a-zA-Z_][a-zA-Z0-9_-]*$/.test(selector);
663
+ }
664
+ isPureExpression(node) {
665
+ if (!node) return true;
666
+ switch (node.type) {
667
+ case "literal":
668
+ return true;
669
+ case "identifier": {
670
+ const value = node.value;
671
+ return !["me", "you", "it", "result", "event"].includes(value ?? "");
672
+ }
673
+ case "binary": {
674
+ const bin = node;
675
+ return this.isPureExpression(bin.left) && this.isPureExpression(bin.right);
676
+ }
677
+ default:
678
+ return false;
679
+ }
680
+ }
681
+ };
682
+ function analyze(ast) {
683
+ const analyzer = new Analyzer();
684
+ return analyzer.analyze(ast);
685
+ }
686
+ var ConstantFoldingPass = class {
687
+ constructor() {
688
+ this.name = "constant-folding";
689
+ }
690
+ shouldRun(analysis) {
691
+ return analysis.expressions.pure.length > 0;
692
+ }
693
+ transform(ast, _analysis) {
694
+ return this.foldNode(ast);
695
+ }
696
+ foldNode(node) {
697
+ if (!node) return node;
698
+ const processed = this.processChildren(node);
699
+ if (processed.type === "binary") {
700
+ return this.foldBinary(processed);
701
+ }
702
+ return processed;
703
+ }
704
+ processChildren(node) {
705
+ const result = { ...node };
706
+ for (const key of Object.keys(node)) {
707
+ const value = node[key];
708
+ if (Array.isArray(value)) {
709
+ result[key] = value.map(
710
+ (item) => item && typeof item === "object" && "type" in item ? this.foldNode(item) : item
711
+ );
712
+ } else if (value && typeof value === "object" && "type" in value) {
713
+ result[key] = this.foldNode(value);
714
+ }
715
+ }
716
+ return result;
717
+ }
718
+ foldBinary(node) {
719
+ const left = node.left;
720
+ const right = node.right;
721
+ if (left.type !== "literal" || right.type !== "literal") {
722
+ return node;
723
+ }
724
+ const leftVal = left.value;
725
+ const rightVal = right.value;
726
+ let result;
727
+ switch (node.operator) {
728
+ // Arithmetic
729
+ case "+":
730
+ if (typeof leftVal === "number" && typeof rightVal === "number") {
731
+ result = leftVal + rightVal;
732
+ }
733
+ break;
734
+ case "-":
735
+ if (typeof leftVal === "number" && typeof rightVal === "number") {
736
+ result = leftVal - rightVal;
737
+ }
738
+ break;
739
+ case "*":
740
+ if (typeof leftVal === "number" && typeof rightVal === "number") {
741
+ result = leftVal * rightVal;
742
+ }
743
+ break;
744
+ case "/":
745
+ if (typeof leftVal === "number" && typeof rightVal === "number" && rightVal !== 0) {
746
+ result = leftVal / rightVal;
747
+ }
748
+ break;
749
+ case "%":
750
+ if (typeof leftVal === "number" && typeof rightVal === "number" && rightVal !== 0) {
751
+ result = leftVal % rightVal;
752
+ }
753
+ break;
754
+ // String concatenation
755
+ case "&":
756
+ result = String(leftVal) + String(rightVal);
757
+ break;
758
+ // Logical
759
+ case "and":
760
+ case "&&":
761
+ result = leftVal && rightVal;
762
+ break;
763
+ case "or":
764
+ case "||":
765
+ result = leftVal || rightVal;
766
+ break;
767
+ // Comparison
768
+ case "is":
769
+ case "==":
770
+ result = leftVal === rightVal;
771
+ break;
772
+ case "is not":
773
+ case "!=":
774
+ result = leftVal !== rightVal;
775
+ break;
776
+ case "<":
777
+ if (typeof leftVal === "number" && typeof rightVal === "number") {
778
+ result = leftVal < rightVal;
779
+ }
780
+ break;
781
+ case ">":
782
+ if (typeof leftVal === "number" && typeof rightVal === "number") {
783
+ result = leftVal > rightVal;
784
+ }
785
+ break;
786
+ case "<=":
787
+ if (typeof leftVal === "number" && typeof rightVal === "number") {
788
+ result = leftVal <= rightVal;
789
+ }
790
+ break;
791
+ case ">=":
792
+ if (typeof leftVal === "number" && typeof rightVal === "number") {
793
+ result = leftVal >= rightVal;
794
+ }
795
+ break;
796
+ }
797
+ if (result !== void 0) {
798
+ return {
799
+ type: "literal",
800
+ value: result
801
+ };
802
+ }
803
+ return node;
804
+ }
805
+ };
806
+ var SelectorCachingPass = class {
807
+ constructor() {
808
+ this.name = "selector-caching";
809
+ }
810
+ shouldRun(analysis) {
811
+ return analysis.expressions.selectors.some((s) => s.usages.length > 1 && s.canCache);
812
+ }
813
+ transform(ast, analysis) {
814
+ const selectorsToCache = /* @__PURE__ */ new Set();
815
+ for (const info of analysis.expressions.selectors) {
816
+ if (info.usages.length > 1 && info.canCache) {
817
+ selectorsToCache.add(info.selector);
818
+ }
819
+ }
820
+ if (selectorsToCache.size === 0) {
821
+ return ast;
822
+ }
823
+ return this.markSelectors(ast, selectorsToCache);
824
+ }
825
+ markSelectors(node, toCache) {
826
+ if (!node) return node;
827
+ if (node.type === "selector") {
828
+ const selector = node.value;
829
+ if (toCache.has(selector)) {
830
+ return {
831
+ ...node,
832
+ _cached: true,
833
+ _cacheKey: this.generateCacheKey(selector)
834
+ };
835
+ }
836
+ return node;
837
+ }
838
+ const result = { ...node };
839
+ for (const key of Object.keys(node)) {
840
+ const value = node[key];
841
+ if (Array.isArray(value)) {
842
+ result[key] = value.map(
843
+ (item) => item && typeof item === "object" && "type" in item ? this.markSelectors(item, toCache) : item
844
+ );
845
+ } else if (value && typeof value === "object" && "type" in value) {
846
+ result[key] = this.markSelectors(value, toCache);
847
+ }
848
+ }
849
+ return result;
850
+ }
851
+ generateCacheKey(selector) {
852
+ return "_sel_" + selector.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").slice(0, 20);
853
+ }
854
+ };
855
+ var DeadCodeEliminationPass = class {
856
+ constructor() {
857
+ this.name = "dead-code-elimination";
858
+ }
859
+ shouldRun(analysis) {
860
+ return analysis.controlFlow.canThrow;
861
+ }
862
+ transform(ast, _analysis) {
863
+ return this.eliminateDeadCode(ast);
864
+ }
865
+ eliminateDeadCode(node) {
866
+ if (!node) return node;
867
+ if (Array.isArray(node)) {
868
+ return this.eliminateFromArray(node);
869
+ }
870
+ const result = { ...node };
871
+ for (const key of ["body", "thenBranch", "elseBranch"]) {
872
+ const value = node[key];
873
+ if (Array.isArray(value)) {
874
+ result[key] = this.eliminateFromArray(value);
875
+ }
876
+ }
877
+ for (const key of Object.keys(node)) {
878
+ if (["body", "thenBranch", "elseBranch"].includes(key)) continue;
879
+ const value = node[key];
880
+ if (value && typeof value === "object" && "type" in value) {
881
+ result[key] = this.eliminateDeadCode(value);
882
+ }
883
+ }
884
+ return result;
885
+ }
886
+ eliminateFromArray(nodes) {
887
+ const result = [];
888
+ for (const node of nodes) {
889
+ const processed = this.eliminateDeadCode(node);
890
+ result.push(processed);
891
+ if (this.isTerminator(node)) {
892
+ break;
893
+ }
894
+ }
895
+ return result;
896
+ }
897
+ isTerminator(node) {
898
+ if (node.type === "command") {
899
+ return ["halt", "exit", "return", "throw"].includes(node.name);
900
+ }
901
+ return false;
902
+ }
903
+ };
904
+ var LoopUnrollingPass = class {
905
+ constructor() {
906
+ this.name = "loop-unrolling";
907
+ this.maxUnrollCount = 5;
908
+ }
909
+ shouldRun(analysis) {
910
+ return analysis.controlFlow.hasLoops;
911
+ }
912
+ transform(ast, _analysis) {
913
+ return this.unrollLoops(ast);
914
+ }
915
+ unrollLoops(node) {
916
+ if (!node) return node;
917
+ if (node.type === "repeat") {
918
+ const unrolled = this.tryUnroll(node);
919
+ if (unrolled) {
920
+ return unrolled;
921
+ }
922
+ }
923
+ const result = { ...node };
924
+ for (const key of Object.keys(node)) {
925
+ const value = node[key];
926
+ if (Array.isArray(value)) {
927
+ result[key] = value.map(
928
+ (item) => item && typeof item === "object" && "type" in item ? this.unrollLoops(item) : item
929
+ );
930
+ } else if (value && typeof value === "object" && "type" in value) {
931
+ result[key] = this.unrollLoops(value);
932
+ }
933
+ }
934
+ return result;
935
+ }
936
+ tryUnroll(node) {
937
+ const repeatNode = node;
938
+ if (typeof repeatNode.count !== "number") {
939
+ return null;
940
+ }
941
+ const count = repeatNode.count;
942
+ const body = repeatNode.body ?? [];
943
+ if (count > this.maxUnrollCount) {
944
+ return null;
945
+ }
946
+ if (body.length > 3) {
947
+ return null;
948
+ }
949
+ if (this.usesIndex(body)) {
950
+ return null;
951
+ }
952
+ const unrolled = [];
953
+ for (let i = 0; i < count; i++) {
954
+ unrolled.push(...this.cloneBody(body));
955
+ }
956
+ return {
957
+ type: "sequence",
958
+ commands: unrolled,
959
+ _unrolled: true
960
+ };
961
+ }
962
+ usesIndex(nodes) {
963
+ for (const node of nodes) {
964
+ if (this.nodeUsesIndex(node)) {
965
+ return true;
966
+ }
967
+ }
968
+ return false;
969
+ }
970
+ nodeUsesIndex(node) {
971
+ if (!node) return false;
972
+ if (node.type === "identifier") {
973
+ if (node.value === "index" || node.value === ":index") {
974
+ return true;
975
+ }
976
+ }
977
+ if (node.type === "variable") {
978
+ if (node.name === "index" || node.name === ":index") {
979
+ return true;
980
+ }
981
+ }
982
+ for (const key of Object.keys(node)) {
983
+ const value = node[key];
984
+ if (Array.isArray(value)) {
985
+ for (const item of value) {
986
+ if (item && typeof item === "object" && "type" in item) {
987
+ if (this.nodeUsesIndex(item)) {
988
+ return true;
989
+ }
990
+ }
991
+ }
992
+ } else if (value && typeof value === "object" && "type" in value) {
993
+ if (this.nodeUsesIndex(value)) {
994
+ return true;
995
+ }
996
+ }
997
+ }
998
+ return false;
999
+ }
1000
+ cloneBody(nodes) {
1001
+ return JSON.parse(JSON.stringify(nodes));
1002
+ }
1003
+ };
1004
+ var OptimizationPipeline = class {
1005
+ constructor() {
1006
+ this.passes = [
1007
+ new ConstantFoldingPass(),
1008
+ new SelectorCachingPass(),
1009
+ new DeadCodeEliminationPass(),
1010
+ new LoopUnrollingPass()
1011
+ ];
1012
+ }
1013
+ /**
1014
+ * Run all applicable optimizations on the AST.
1015
+ */
1016
+ optimize(ast, analysis, level = 2) {
1017
+ if (level === 0) {
1018
+ return ast;
1019
+ }
1020
+ let current = ast;
1021
+ const appliedOptimizations = [];
1022
+ const passesToRun = level === 1 ? this.passes.slice(0, 2) : this.passes;
1023
+ for (const pass of passesToRun) {
1024
+ if (pass.shouldRun(analysis)) {
1025
+ current = pass.transform(current, analysis);
1026
+ appliedOptimizations.push(pass.name);
1027
+ }
1028
+ }
1029
+ return {
1030
+ ...current,
1031
+ _optimizations: appliedOptimizations
1032
+ };
1033
+ }
1034
+ /**
1035
+ * Add a custom optimization pass.
1036
+ */
1037
+ addPass(pass) {
1038
+ this.passes.push(pass);
1039
+ }
1040
+ };
1041
+ function createOptimizer() {
1042
+ return new OptimizationPipeline();
1043
+ }
1044
+ function optimize(ast, analysis, level = 2) {
1045
+ const pipeline = new OptimizationPipeline();
1046
+ return pipeline.optimize(ast, analysis, level);
1047
+ }
1048
+ function sanitizeClassName(name) {
1049
+ if (!/^-?[a-zA-Z_][a-zA-Z0-9_-]*$/.test(name)) {
1050
+ return null;
1051
+ }
1052
+ return name;
1053
+ }
1054
+ function sanitizeSelector(selector) {
1055
+ return selector.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\0/g, "");
1056
+ }
1057
+ function sanitizeIdentifier(name) {
1058
+ return name.replace(/[^a-zA-Z0-9_$]/g, "_");
1059
+ }
1060
+ var ExpressionCodegen = class {
1061
+ constructor(ctx) {
1062
+ this.ctx = ctx;
1063
+ }
1064
+ /**
1065
+ * Generate JavaScript code for an expression.
1066
+ */
1067
+ generate(node) {
1068
+ if (!node) {
1069
+ return "undefined";
1070
+ }
1071
+ switch (node.type) {
1072
+ case "literal":
1073
+ return this.generateLiteral(node);
1074
+ case "identifier":
1075
+ return this.generateIdentifier(node);
1076
+ case "selector":
1077
+ return this.generateSelector(node);
1078
+ case "variable":
1079
+ return this.generateVariable(node);
1080
+ case "binary":
1081
+ return this.generateBinary(node);
1082
+ case "member":
1083
+ return this.generateMember(node);
1084
+ case "possessive":
1085
+ return this.generatePossessive(node);
1086
+ case "call":
1087
+ return this.generateCall(node);
1088
+ case "positional":
1089
+ return this.generatePositional(node);
1090
+ case "array":
1091
+ return this.generateArray(node);
1092
+ case "object":
1093
+ return this.generateObject(node);
1094
+ case "template":
1095
+ return this.generateTemplate(node);
1096
+ case "unary":
1097
+ return this.generateUnary(node);
1098
+ case "conditional":
1099
+ return this.generateConditional(node);
1100
+ case "sequence":
1101
+ return "undefined";
1102
+ default:
1103
+ if ("value" in node) {
1104
+ return JSON.stringify(node.value);
1105
+ }
1106
+ throw new Error(`Unknown expression type: ${node.type}`);
1107
+ }
1108
+ }
1109
+ // ===========================================================================
1110
+ // LITERAL EXPRESSIONS
1111
+ // ===========================================================================
1112
+ generateLiteral(node) {
1113
+ const value = node.value;
1114
+ if (value === null) {
1115
+ return "null";
1116
+ }
1117
+ if (value === void 0) {
1118
+ return "undefined";
1119
+ }
1120
+ if (typeof value === "string") {
1121
+ return JSON.stringify(value);
1122
+ }
1123
+ if (typeof value === "number") {
1124
+ return String(value);
1125
+ }
1126
+ if (typeof value === "boolean") {
1127
+ return String(value);
1128
+ }
1129
+ return JSON.stringify(value);
1130
+ }
1131
+ // ===========================================================================
1132
+ // IDENTIFIER EXPRESSIONS
1133
+ // ===========================================================================
1134
+ generateIdentifier(node) {
1135
+ const name = node.value ?? node.name ?? "";
1136
+ switch (name) {
1137
+ case "me":
1138
+ case "my":
1139
+ return "_ctx.me";
1140
+ case "you":
1141
+ case "your":
1142
+ return "_ctx.you";
1143
+ case "it":
1144
+ case "result":
1145
+ return "_ctx.it";
1146
+ case "event":
1147
+ return "_ctx.event";
1148
+ case "body":
1149
+ return "document.body";
1150
+ case "document":
1151
+ return "document";
1152
+ case "window":
1153
+ return "window";
1154
+ case "true":
1155
+ return "true";
1156
+ case "false":
1157
+ return "false";
1158
+ case "null":
1159
+ return "null";
1160
+ case "undefined":
1161
+ return "undefined";
1162
+ default:
1163
+ if (name.startsWith(":")) {
1164
+ const varName = sanitizeIdentifier(name.slice(1));
1165
+ return `_ctx.locals.get('${varName}')`;
1166
+ }
1167
+ if (name.startsWith("$") || name.startsWith("::")) {
1168
+ const varName = sanitizeIdentifier(name.replace(/^(\$|::)/, ""));
1169
+ this.ctx.requireHelper("globals");
1170
+ return `_rt.globals.get('${varName}')`;
1171
+ }
1172
+ return sanitizeIdentifier(name);
1173
+ }
1174
+ }
1175
+ // ===========================================================================
1176
+ // SELECTOR EXPRESSIONS
1177
+ // ===========================================================================
1178
+ generateSelector(node) {
1179
+ const selector = node.value;
1180
+ const sanitized = sanitizeSelector(selector);
1181
+ if (this.ctx.canCacheSelector(selector)) {
1182
+ return this.ctx.getCachedSelector(selector);
1183
+ }
1184
+ if (selector.startsWith("#") && !selector.includes(" ") && !selector.includes(".")) {
1185
+ const id = selector.slice(1);
1186
+ return `document.getElementById('${sanitizeSelector(id)}')`;
1187
+ }
1188
+ return `document.querySelector('${sanitized}')`;
1189
+ }
1190
+ // ===========================================================================
1191
+ // VARIABLE EXPRESSIONS
1192
+ // ===========================================================================
1193
+ generateVariable(node) {
1194
+ const name = node.name;
1195
+ const varName = sanitizeIdentifier(
1196
+ name.startsWith(":") || name.startsWith("$") ? name.slice(1) : name
1197
+ );
1198
+ switch (node.scope) {
1199
+ case "local":
1200
+ return `_ctx.locals.get('${varName}')`;
1201
+ case "global":
1202
+ this.ctx.requireHelper("globals");
1203
+ return `_rt.globals.get('${varName}')`;
1204
+ case "element":
1205
+ return `_ctx.me.${varName}`;
1206
+ default:
1207
+ return `_ctx.locals.get('${varName}')`;
1208
+ }
1209
+ }
1210
+ // ===========================================================================
1211
+ // BINARY EXPRESSIONS
1212
+ // ===========================================================================
1213
+ generateBinary(node) {
1214
+ const left = this.generate(node.left);
1215
+ const right = this.generate(node.right);
1216
+ const op = node.operator;
1217
+ switch (op) {
1218
+ // Equality
1219
+ case "is":
1220
+ case "==":
1221
+ return `(${left} === ${right})`;
1222
+ case "is not":
1223
+ case "!=":
1224
+ return `(${left} !== ${right})`;
1225
+ // Comparison
1226
+ case "<":
1227
+ case ">":
1228
+ case "<=":
1229
+ case ">=":
1230
+ return `(${left} ${op} ${right})`;
1231
+ // Arithmetic
1232
+ case "+":
1233
+ case "-":
1234
+ case "*":
1235
+ case "/":
1236
+ case "%":
1237
+ return `(${left} ${op} ${right})`;
1238
+ // Logical
1239
+ case "and":
1240
+ case "&&":
1241
+ return `(${left} && ${right})`;
1242
+ case "or":
1243
+ case "||":
1244
+ return `(${left} || ${right})`;
1245
+ // String/collection operators
1246
+ case "contains":
1247
+ this.ctx.requireHelper("contains");
1248
+ return `_rt.contains(${left}, ${right})`;
1249
+ case "matches":
1250
+ this.ctx.requireHelper("matches");
1251
+ return `_rt.matches(${left}, ${right})`;
1252
+ case "starts with":
1253
+ return `${left}.startsWith(${right})`;
1254
+ case "ends with":
1255
+ return `${left}.endsWith(${right})`;
1256
+ // Class check
1257
+ case "has":
1258
+ if (node.right.type === "selector") {
1259
+ const sel = node.right.value;
1260
+ if (sel.startsWith(".")) {
1261
+ const className = sanitizeClassName(sel.slice(1));
1262
+ if (className) {
1263
+ return `${left}.classList.contains('${className}')`;
1264
+ }
1265
+ }
1266
+ }
1267
+ this.ctx.requireHelper("contains");
1268
+ return `_rt.contains(${left}, ${right})`;
1269
+ // Type check
1270
+ case "is a":
1271
+ case "is an":
1272
+ return `(typeof ${left} === ${right} || ${left} instanceof ${right})`;
1273
+ case "is not a":
1274
+ case "is not an":
1275
+ return `(typeof ${left} !== ${right} && !(${left} instanceof ${right}))`;
1276
+ // Concatenation
1277
+ case "&":
1278
+ return `(String(${left}) + String(${right}))`;
1279
+ default:
1280
+ return `(${left} ${op} ${right})`;
1281
+ }
1282
+ }
1283
+ // ===========================================================================
1284
+ // MEMBER EXPRESSIONS
1285
+ // ===========================================================================
1286
+ generateMember(node) {
1287
+ const object = this.generate(node.object);
1288
+ if (typeof node.property === "string") {
1289
+ const prop = node.property;
1290
+ if (prop.startsWith("*")) {
1291
+ const styleProp = prop.slice(1);
1292
+ return `${object}.style.${styleProp}`;
1293
+ }
1294
+ if (prop.startsWith("@")) {
1295
+ const attrName = prop.slice(1);
1296
+ return `${object}.getAttribute('${sanitizeSelector(attrName)}')`;
1297
+ }
1298
+ if (node.computed) {
1299
+ return `${object}[${JSON.stringify(prop)}]`;
1300
+ }
1301
+ return `${object}.${sanitizeIdentifier(prop)}`;
1302
+ }
1303
+ const propExpr = this.generate(node.property);
1304
+ return `${object}[${propExpr}]`;
1305
+ }
1306
+ // ===========================================================================
1307
+ // POSSESSIVE EXPRESSIONS
1308
+ // ===========================================================================
1309
+ generatePossessive(node) {
1310
+ const object = this.generate(node.object);
1311
+ const property = node.property;
1312
+ if (property.startsWith("*")) {
1313
+ const styleProp = property.slice(1);
1314
+ return `${object}.style.${styleProp}`;
1315
+ }
1316
+ if (property.startsWith("@")) {
1317
+ const attrName = property.slice(1);
1318
+ return `${object}.getAttribute('${sanitizeSelector(attrName)}')`;
1319
+ }
1320
+ if (property === "values") {
1321
+ this.ctx.requireHelper("getValues");
1322
+ return `_rt.getValues(${object})`;
1323
+ }
1324
+ const domProps = [
1325
+ "value",
1326
+ "textContent",
1327
+ "innerHTML",
1328
+ "innerText",
1329
+ "outerHTML",
1330
+ "checked",
1331
+ "disabled",
1332
+ "selected",
1333
+ "hidden",
1334
+ "src",
1335
+ "href",
1336
+ "id",
1337
+ "className",
1338
+ "classList",
1339
+ "parentElement",
1340
+ "parentNode",
1341
+ "children",
1342
+ "firstChild",
1343
+ "lastChild",
1344
+ "nextSibling",
1345
+ "previousSibling",
1346
+ "nextElementSibling",
1347
+ "previousElementSibling",
1348
+ "offsetWidth",
1349
+ "offsetHeight",
1350
+ "offsetTop",
1351
+ "offsetLeft",
1352
+ "clientWidth",
1353
+ "clientHeight",
1354
+ "scrollWidth",
1355
+ "scrollHeight",
1356
+ "scrollTop",
1357
+ "scrollLeft"
1358
+ ];
1359
+ if (domProps.includes(property)) {
1360
+ return `${object}.${property}`;
1361
+ }
1362
+ this.ctx.requireHelper("getProp");
1363
+ return `_rt.getProp(${object}, '${sanitizeSelector(property)}')`;
1364
+ }
1365
+ // ===========================================================================
1366
+ // CALL EXPRESSIONS
1367
+ // ===========================================================================
1368
+ generateCall(node) {
1369
+ const args = (node.args ?? []).map((arg) => this.generate(arg)).join(", ");
1370
+ if (node.callee.type === "member" || node.callee.type === "possessive") {
1371
+ const memberNode = node.callee;
1372
+ const object = this.generate(memberNode.object);
1373
+ const method = typeof memberNode.property === "string" ? memberNode.property : this.generate(memberNode.property);
1374
+ if (typeof memberNode.property === "string") {
1375
+ return `${object}.${sanitizeIdentifier(memberNode.property)}(${args})`;
1376
+ }
1377
+ return `${object}[${method}](${args})`;
1378
+ }
1379
+ const callee = this.generate(node.callee);
1380
+ return `${callee}(${args})`;
1381
+ }
1382
+ // ===========================================================================
1383
+ // POSITIONAL EXPRESSIONS
1384
+ // ===========================================================================
1385
+ generatePositional(node) {
1386
+ const position = node.position;
1387
+ const target = node.target ? this.generate(node.target) : null;
1388
+ switch (position) {
1389
+ case "first":
1390
+ if (target) {
1391
+ if (node.target?.type === "selector") {
1392
+ const sel = node.target.value;
1393
+ return `document.querySelector('${sanitizeSelector(sel)}')`;
1394
+ }
1395
+ this.ctx.requireHelper("first");
1396
+ return `_rt.first(${target})`;
1397
+ }
1398
+ return "_ctx.me";
1399
+ case "last":
1400
+ if (target) {
1401
+ if (node.target?.type === "selector") {
1402
+ const sel = node.target.value;
1403
+ const sanitized = sanitizeSelector(sel);
1404
+ return `(()=>{const _els=document.querySelectorAll('${sanitized}');return _els[_els.length-1]})()`;
1405
+ }
1406
+ this.ctx.requireHelper("last");
1407
+ return `_rt.last(${target})`;
1408
+ }
1409
+ return "_ctx.me";
1410
+ case "random":
1411
+ if (target) {
1412
+ this.ctx.requireHelper("random");
1413
+ return `_rt.random(${target})`;
1414
+ }
1415
+ return "_ctx.me";
1416
+ case "next":
1417
+ return "_ctx.me.nextElementSibling";
1418
+ case "previous":
1419
+ return "_ctx.me.previousElementSibling";
1420
+ case "closest":
1421
+ if (target && node.target?.type === "selector") {
1422
+ const sel = node.target.value;
1423
+ return `_ctx.me.closest('${sanitizeSelector(sel)}')`;
1424
+ }
1425
+ if (target) {
1426
+ return `_ctx.me.closest(${target})`;
1427
+ }
1428
+ return "_ctx.me.parentElement";
1429
+ case "parent":
1430
+ return "_ctx.me.parentElement";
1431
+ default:
1432
+ throw new Error(`Unknown positional: ${position}`);
1433
+ }
1434
+ }
1435
+ // ===========================================================================
1436
+ // ARRAY EXPRESSIONS
1437
+ // ===========================================================================
1438
+ generateArray(node) {
1439
+ const elements = node.elements ?? [];
1440
+ const items = elements.map((el) => this.generate(el)).join(", ");
1441
+ return `[${items}]`;
1442
+ }
1443
+ // ===========================================================================
1444
+ // OBJECT EXPRESSIONS
1445
+ // ===========================================================================
1446
+ generateObject(node) {
1447
+ const properties = node.properties ?? [];
1448
+ const pairs = properties.map((prop) => {
1449
+ const key = typeof prop.key === "string" ? JSON.stringify(prop.key) : this.generate(prop.key);
1450
+ const value = this.generate(prop.value);
1451
+ return `${key}: ${value}`;
1452
+ }).join(", ");
1453
+ return `{${pairs}}`;
1454
+ }
1455
+ // ===========================================================================
1456
+ // TEMPLATE EXPRESSIONS
1457
+ // ===========================================================================
1458
+ generateTemplate(node) {
1459
+ const parts = node.parts ?? [];
1460
+ const segments = parts.map((part) => {
1461
+ if (typeof part === "string") {
1462
+ return part.replace(/`/g, "\\`").replace(/\$/g, "\\$");
1463
+ }
1464
+ return "${" + this.generate(part) + "}";
1465
+ }).join("");
1466
+ return "`" + segments + "`";
1467
+ }
1468
+ // ===========================================================================
1469
+ // UNARY EXPRESSIONS
1470
+ // ===========================================================================
1471
+ generateUnary(node) {
1472
+ const operand = this.generate(node.operand);
1473
+ switch (node.operator) {
1474
+ case "not":
1475
+ case "!":
1476
+ return `!${operand}`;
1477
+ case "-":
1478
+ return `-${operand}`;
1479
+ case "+":
1480
+ return `+${operand}`;
1481
+ case "no":
1482
+ return `!${operand}`;
1483
+ default:
1484
+ return `${node.operator}${operand}`;
1485
+ }
1486
+ }
1487
+ // ===========================================================================
1488
+ // CONDITIONAL EXPRESSIONS
1489
+ // ===========================================================================
1490
+ generateConditional(node) {
1491
+ const condition = this.generate(node.condition);
1492
+ const consequent = this.generate(node.consequent);
1493
+ const alternate = this.generate(node.alternate);
1494
+ return `(${condition} ? ${consequent} : ${alternate})`;
1495
+ }
1496
+ };
1497
+ function generateExpression(node, ctx) {
1498
+ const codegen = new ExpressionCodegen(ctx);
1499
+ return codegen.generate(node);
1500
+ }
1501
+ var ToggleCodegen = class {
1502
+ constructor() {
1503
+ this.command = "toggle";
1504
+ }
1505
+ generate(node, ctx) {
1506
+ const args = node.args ?? [];
1507
+ if (args.length === 0) return null;
1508
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1509
+ const arg = args[0];
1510
+ if (arg.type === "selector") {
1511
+ const selector = arg.value;
1512
+ if (selector.startsWith(".")) {
1513
+ const className = sanitizeClassName(selector.slice(1));
1514
+ if (!className) return null;
1515
+ if (target === "_ctx.me") {
1516
+ return {
1517
+ code: `_ctx.me.classList.toggle('${className}')`,
1518
+ async: false,
1519
+ sideEffects: true
1520
+ };
1521
+ }
1522
+ return {
1523
+ code: `Array.from(document.querySelectorAll('${sanitizeSelector(selector.slice(1))}')).forEach(el => el.classList.toggle('${className}'))`,
1524
+ async: false,
1525
+ sideEffects: true
1526
+ };
1527
+ }
1528
+ }
1529
+ if (arg.type === "identifier") {
1530
+ const value = arg.value ?? "";
1531
+ if (value.startsWith("@")) {
1532
+ const attrName = value.slice(1);
1533
+ ctx.requireHelper("toggleAttr");
1534
+ return {
1535
+ code: `_rt.toggleAttr(${target}, '${sanitizeSelector(attrName)}')`,
1536
+ async: false,
1537
+ sideEffects: true
1538
+ };
1539
+ }
1540
+ }
1541
+ ctx.requireHelper("toggle");
1542
+ return {
1543
+ code: `_rt.toggle(${ctx.generateExpression(arg)}, ${target})`,
1544
+ async: false,
1545
+ sideEffects: true
1546
+ };
1547
+ }
1548
+ };
1549
+ var AddCodegen = class {
1550
+ constructor() {
1551
+ this.command = "add";
1552
+ }
1553
+ generate(node, ctx) {
1554
+ const args = node.args ?? [];
1555
+ if (args.length === 0) return null;
1556
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1557
+ const arg = args[0];
1558
+ if (arg.type === "selector") {
1559
+ const selector = arg.value;
1560
+ if (selector.startsWith(".")) {
1561
+ const className = sanitizeClassName(selector.slice(1));
1562
+ if (!className) return null;
1563
+ if (target === "_ctx.me") {
1564
+ return {
1565
+ code: `_ctx.me.classList.add('${className}')`,
1566
+ async: false,
1567
+ sideEffects: true
1568
+ };
1569
+ }
1570
+ return {
1571
+ code: `${target}.classList.add('${className}')`,
1572
+ async: false,
1573
+ sideEffects: true
1574
+ };
1575
+ }
1576
+ }
1577
+ if (arg.type === "htmlLiteral") {
1578
+ const tagNode = arg;
1579
+ const tag = tagNode.tag ?? "div";
1580
+ const classes = tagNode.classes ?? [];
1581
+ const id = tagNode.id;
1582
+ let code = `(() => { const _el = document.createElement('${tag}');`;
1583
+ if (classes.length > 0) {
1584
+ code += ` _el.className = '${classes.join(" ")}';`;
1585
+ }
1586
+ if (id) {
1587
+ code += ` _el.id = '${id}';`;
1588
+ }
1589
+ code += ` ${target}.appendChild(_el); return _el; })()`;
1590
+ return { code, async: false, sideEffects: true };
1591
+ }
1592
+ ctx.requireHelper("addClass");
1593
+ return {
1594
+ code: `_rt.addClass(${target}, ${ctx.generateExpression(arg)})`,
1595
+ async: false,
1596
+ sideEffects: true
1597
+ };
1598
+ }
1599
+ };
1600
+ var RemoveCodegen = class {
1601
+ constructor() {
1602
+ this.command = "remove";
1603
+ }
1604
+ generate(node, ctx) {
1605
+ const args = node.args ?? [];
1606
+ if (args.length === 0) {
1607
+ const target2 = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1608
+ return {
1609
+ code: `${target2}.remove()`,
1610
+ async: false,
1611
+ sideEffects: true
1612
+ };
1613
+ }
1614
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1615
+ const arg = args[0];
1616
+ if (arg.type === "selector") {
1617
+ const selector = arg.value;
1618
+ if (selector.startsWith(".")) {
1619
+ const className = sanitizeClassName(selector.slice(1));
1620
+ if (!className) return null;
1621
+ return {
1622
+ code: `${target}.classList.remove('${className}')`,
1623
+ async: false,
1624
+ sideEffects: true
1625
+ };
1626
+ }
1627
+ }
1628
+ ctx.requireHelper("removeClass");
1629
+ return {
1630
+ code: `_rt.removeClass(${target}, ${ctx.generateExpression(arg)})`,
1631
+ async: false,
1632
+ sideEffects: true
1633
+ };
1634
+ }
1635
+ };
1636
+ var SetCodegen = class {
1637
+ constructor() {
1638
+ this.command = "set";
1639
+ }
1640
+ generate(node, ctx) {
1641
+ const args = node.args ?? [];
1642
+ const modifiers = node.modifiers;
1643
+ const roles = node.roles;
1644
+ const targetNode = roles?.destination ?? args[0];
1645
+ const valueNode = roles?.patient ?? modifiers?.to ?? args[1];
1646
+ if (!targetNode || !valueNode) return null;
1647
+ const value = ctx.generateExpression(valueNode);
1648
+ if (targetNode.type === "variable") {
1649
+ const varNode = targetNode;
1650
+ const name = varNode.name.startsWith(":") ? varNode.name.slice(1) : varNode.name;
1651
+ const safeName = sanitizeIdentifier(name);
1652
+ if (varNode.scope === "local") {
1653
+ return {
1654
+ code: `_ctx.locals.set('${safeName}', ${value})`,
1655
+ async: false,
1656
+ sideEffects: true
1657
+ };
1658
+ }
1659
+ if (varNode.scope === "global") {
1660
+ ctx.requireHelper("globals");
1661
+ return {
1662
+ code: `_rt.globals.set('${safeName}', ${value})`,
1663
+ async: false,
1664
+ sideEffects: true
1665
+ };
1666
+ }
1667
+ }
1668
+ if (targetNode.type === "possessive") {
1669
+ const possessive = targetNode;
1670
+ const obj = ctx.generateExpression(possessive.object);
1671
+ const prop = possessive.property;
1672
+ if (prop.startsWith("*")) {
1673
+ const styleProp = prop.slice(1);
1674
+ return {
1675
+ code: `${obj}.style.${styleProp} = ${value}`,
1676
+ async: false,
1677
+ sideEffects: true
1678
+ };
1679
+ }
1680
+ if (prop.startsWith("@")) {
1681
+ const attrName = prop.slice(1);
1682
+ return {
1683
+ code: `${obj}.setAttribute('${sanitizeSelector(attrName)}', ${value})`,
1684
+ async: false,
1685
+ sideEffects: true
1686
+ };
1687
+ }
1688
+ return {
1689
+ code: `${obj}.${sanitizeIdentifier(prop)} = ${value}`,
1690
+ async: false,
1691
+ sideEffects: true
1692
+ };
1693
+ }
1694
+ if (targetNode.type === "member") {
1695
+ const memberCode = ctx.generateExpression(targetNode);
1696
+ return {
1697
+ code: `${memberCode} = ${value}`,
1698
+ async: false,
1699
+ sideEffects: true
1700
+ };
1701
+ }
1702
+ return null;
1703
+ }
1704
+ };
1705
+ var PutCodegen = class {
1706
+ constructor() {
1707
+ this.command = "put";
1708
+ }
1709
+ generate(node, ctx) {
1710
+ const args = node.args ?? [];
1711
+ const roles = node.roles;
1712
+ const modifiers = node.modifiers;
1713
+ const contentNode = roles?.patient ?? args[0];
1714
+ if (!contentNode) return null;
1715
+ const content = ctx.generateExpression(contentNode);
1716
+ let target = "_ctx.me";
1717
+ if (roles?.destination) {
1718
+ target = ctx.generateExpression(roles.destination);
1719
+ } else if (modifiers) {
1720
+ for (const key of ["into", "before", "after"]) {
1721
+ if (modifiers[key] && typeof modifiers[key] === "object") {
1722
+ target = ctx.generateExpression(modifiers[key]);
1723
+ break;
1724
+ }
1725
+ }
1726
+ }
1727
+ if (target === "_ctx.me" && node.target) {
1728
+ target = ctx.generateExpression(node.target);
1729
+ }
1730
+ let modifier = "into";
1731
+ if (roles?.method && roles.method.value) {
1732
+ modifier = String(roles.method.value);
1733
+ } else if (modifiers) {
1734
+ if (modifiers.before) modifier = "before";
1735
+ else if (modifiers.after) modifier = "after";
1736
+ else if (typeof modifiers.position === "string") modifier = modifiers.position;
1737
+ }
1738
+ switch (modifier) {
1739
+ case "into":
1740
+ return {
1741
+ code: `${target}.innerHTML = ${content}`,
1742
+ async: false,
1743
+ sideEffects: true
1744
+ };
1745
+ case "before":
1746
+ return {
1747
+ code: `${target}.insertAdjacentHTML('beforebegin', ${content})`,
1748
+ async: false,
1749
+ sideEffects: true
1750
+ };
1751
+ case "after":
1752
+ return {
1753
+ code: `${target}.insertAdjacentHTML('afterend', ${content})`,
1754
+ async: false,
1755
+ sideEffects: true
1756
+ };
1757
+ case "at start of":
1758
+ case "start":
1759
+ return {
1760
+ code: `${target}.insertAdjacentHTML('afterbegin', ${content})`,
1761
+ async: false,
1762
+ sideEffects: true
1763
+ };
1764
+ case "at end of":
1765
+ case "end":
1766
+ return {
1767
+ code: `${target}.insertAdjacentHTML('beforeend', ${content})`,
1768
+ async: false,
1769
+ sideEffects: true
1770
+ };
1771
+ default:
1772
+ return {
1773
+ code: `${target}.innerHTML = ${content}`,
1774
+ async: false,
1775
+ sideEffects: true
1776
+ };
1777
+ }
1778
+ }
1779
+ };
1780
+ var ShowCodegen = class {
1781
+ constructor() {
1782
+ this.command = "show";
1783
+ }
1784
+ generate(node, ctx) {
1785
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1786
+ return {
1787
+ code: `${target}.style.display = ''`,
1788
+ async: false,
1789
+ sideEffects: true
1790
+ };
1791
+ }
1792
+ };
1793
+ var HideCodegen = class {
1794
+ constructor() {
1795
+ this.command = "hide";
1796
+ }
1797
+ generate(node, ctx) {
1798
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1799
+ return {
1800
+ code: `${target}.style.display = 'none'`,
1801
+ async: false,
1802
+ sideEffects: true
1803
+ };
1804
+ }
1805
+ };
1806
+ var FocusCodegen = class {
1807
+ constructor() {
1808
+ this.command = "focus";
1809
+ }
1810
+ generate(node, ctx) {
1811
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1812
+ return {
1813
+ code: `${target}.focus()`,
1814
+ async: false,
1815
+ sideEffects: true
1816
+ };
1817
+ }
1818
+ };
1819
+ var BlurCodegen = class {
1820
+ constructor() {
1821
+ this.command = "blur";
1822
+ }
1823
+ generate(node, ctx) {
1824
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1825
+ return {
1826
+ code: `${target}.blur()`,
1827
+ async: false,
1828
+ sideEffects: true
1829
+ };
1830
+ }
1831
+ };
1832
+ var LogCodegen = class {
1833
+ constructor() {
1834
+ this.command = "log";
1835
+ }
1836
+ generate(node, ctx) {
1837
+ const args = node.args ?? [];
1838
+ const values = args.map((arg) => ctx.generateExpression(arg)).join(", ");
1839
+ return {
1840
+ code: `console.log(${values || "''"})`,
1841
+ async: false,
1842
+ sideEffects: true
1843
+ };
1844
+ }
1845
+ };
1846
+ var WaitCodegen = class {
1847
+ constructor() {
1848
+ this.command = "wait";
1849
+ }
1850
+ generate(node, ctx) {
1851
+ const args = node.args ?? [];
1852
+ const roles = node.roles;
1853
+ const arg = roles?.duration ?? args[0];
1854
+ if (!arg) return null;
1855
+ if (arg.type === "literal") {
1856
+ const value = arg.value;
1857
+ if (typeof value === "number") {
1858
+ ctx.requireHelper("wait");
1859
+ return {
1860
+ code: `await _rt.wait(${value})`,
1861
+ async: true,
1862
+ sideEffects: false
1863
+ };
1864
+ }
1865
+ if (typeof value === "string") {
1866
+ const ms = parseDuration(value);
1867
+ if (ms !== null) {
1868
+ ctx.requireHelper("wait");
1869
+ return {
1870
+ code: `await _rt.wait(${ms})`,
1871
+ async: true,
1872
+ sideEffects: false
1873
+ };
1874
+ }
1875
+ }
1876
+ }
1877
+ const duration = ctx.generateExpression(arg);
1878
+ ctx.requireHelper("wait");
1879
+ return {
1880
+ code: `await _rt.wait(${duration})`,
1881
+ async: true,
1882
+ sideEffects: false
1883
+ };
1884
+ }
1885
+ };
1886
+ var FetchCodegen = class {
1887
+ constructor() {
1888
+ this.command = "fetch";
1889
+ }
1890
+ generate(node, ctx) {
1891
+ const args = node.args ?? [];
1892
+ const roles = node.roles;
1893
+ const modifiers = node.modifiers;
1894
+ const urlNode = roles?.source ?? args[0];
1895
+ if (!urlNode) return null;
1896
+ const url = ctx.generateExpression(urlNode);
1897
+ let format = "text";
1898
+ if (roles?.responseType) {
1899
+ const rt = roles.responseType;
1900
+ format = String(rt.name ?? rt.value ?? "text");
1901
+ } else if (modifiers?.as) {
1902
+ const asVal = modifiers.as;
1903
+ if (typeof asVal === "string") {
1904
+ format = asVal;
1905
+ } else if (typeof asVal === "object" && asVal !== null) {
1906
+ format = String(
1907
+ asVal.name ?? asVal.value ?? "text"
1908
+ );
1909
+ }
1910
+ }
1911
+ switch (format) {
1912
+ case "json":
1913
+ ctx.requireHelper("fetchJSON");
1914
+ return {
1915
+ code: `_ctx.it = await _rt.fetchJSON(${url})`,
1916
+ async: true,
1917
+ sideEffects: true
1918
+ };
1919
+ case "html":
1920
+ ctx.requireHelper("fetchHTML");
1921
+ return {
1922
+ code: `_ctx.it = await _rt.fetchHTML(${url})`,
1923
+ async: true,
1924
+ sideEffects: true
1925
+ };
1926
+ case "text":
1927
+ default:
1928
+ ctx.requireHelper("fetchText");
1929
+ return {
1930
+ code: `_ctx.it = await _rt.fetchText(${url})`,
1931
+ async: true,
1932
+ sideEffects: true
1933
+ };
1934
+ }
1935
+ }
1936
+ };
1937
+ var SendCodegen = class {
1938
+ constructor() {
1939
+ this.command = "send";
1940
+ }
1941
+ generate(node, ctx) {
1942
+ const args = node.args ?? [];
1943
+ if (args.length === 0) return null;
1944
+ const eventName = ctx.generateExpression(args[0]);
1945
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1946
+ const detail = args.length > 1 ? ctx.generateExpression(args[1]) : "undefined";
1947
+ ctx.requireHelper("send");
1948
+ return {
1949
+ code: `_rt.send(${target}, ${eventName}, ${detail})`,
1950
+ async: false,
1951
+ sideEffects: true
1952
+ };
1953
+ }
1954
+ };
1955
+ var IncrementCodegen = class {
1956
+ constructor() {
1957
+ this.command = "increment";
1958
+ }
1959
+ generate(node, ctx) {
1960
+ const args = node.args ?? [];
1961
+ const roles = node.roles;
1962
+ const modifiers = node.modifiers;
1963
+ const target = roles?.destination ?? roles?.patient ?? args[0];
1964
+ if (!target) return null;
1965
+ const amountNode = roles?.quantity ?? modifiers?.by ?? args[1];
1966
+ const amount = amountNode ? ctx.generateExpression(amountNode) : "1";
1967
+ if (target.type === "variable") {
1968
+ const varNode = target;
1969
+ const name = varNode.name.startsWith(":") ? varNode.name.slice(1) : varNode.name;
1970
+ const safeName = sanitizeIdentifier(name);
1971
+ if (varNode.scope === "local") {
1972
+ return {
1973
+ code: `_ctx.locals.set('${safeName}', (_ctx.locals.get('${safeName}') || 0) + ${amount})`,
1974
+ async: false,
1975
+ sideEffects: true
1976
+ };
1977
+ }
1978
+ if (varNode.scope === "global") {
1979
+ ctx.requireHelper("globals");
1980
+ return {
1981
+ code: `_rt.globals.set('${safeName}', (_rt.globals.get('${safeName}') || 0) + ${amount})`,
1982
+ async: false,
1983
+ sideEffects: true
1984
+ };
1985
+ }
1986
+ }
1987
+ const targetCode = ctx.generateExpression(target);
1988
+ return {
1989
+ code: `${targetCode}.textContent = (parseFloat(${targetCode}.textContent) || 0) + ${amount}`,
1990
+ async: false,
1991
+ sideEffects: true
1992
+ };
1993
+ }
1994
+ };
1995
+ var DecrementCodegen = class {
1996
+ constructor() {
1997
+ this.command = "decrement";
1998
+ }
1999
+ generate(node, ctx) {
2000
+ const args = node.args ?? [];
2001
+ const roles = node.roles;
2002
+ const modifiers = node.modifiers;
2003
+ const target = roles?.destination ?? roles?.patient ?? args[0];
2004
+ if (!target) return null;
2005
+ const amountNode = roles?.quantity ?? modifiers?.by ?? args[1];
2006
+ const amount = amountNode ? ctx.generateExpression(amountNode) : "1";
2007
+ if (target.type === "variable") {
2008
+ const varNode = target;
2009
+ const name = varNode.name.startsWith(":") ? varNode.name.slice(1) : varNode.name;
2010
+ const safeName = sanitizeIdentifier(name);
2011
+ if (varNode.scope === "local") {
2012
+ return {
2013
+ code: `_ctx.locals.set('${safeName}', (_ctx.locals.get('${safeName}') || 0) - ${amount})`,
2014
+ async: false,
2015
+ sideEffects: true
2016
+ };
2017
+ }
2018
+ if (varNode.scope === "global") {
2019
+ ctx.requireHelper("globals");
2020
+ return {
2021
+ code: `_rt.globals.set('${safeName}', (_rt.globals.get('${safeName}') || 0) - ${amount})`,
2022
+ async: false,
2023
+ sideEffects: true
2024
+ };
2025
+ }
2026
+ }
2027
+ const targetCode = ctx.generateExpression(target);
2028
+ return {
2029
+ code: `${targetCode}.textContent = (parseFloat(${targetCode}.textContent) || 0) - ${amount}`,
2030
+ async: false,
2031
+ sideEffects: true
2032
+ };
2033
+ }
2034
+ };
2035
+ var HaltCodegen = class {
2036
+ constructor() {
2037
+ this.command = "halt";
2038
+ }
2039
+ generate(_node, ctx) {
2040
+ ctx.requireHelper("HALT");
2041
+ return {
2042
+ code: `throw _rt.HALT`,
2043
+ async: false,
2044
+ sideEffects: true
2045
+ };
2046
+ }
2047
+ };
2048
+ var ExitCodegen = class {
2049
+ constructor() {
2050
+ this.command = "exit";
2051
+ }
2052
+ generate(_node, ctx) {
2053
+ ctx.requireHelper("EXIT");
2054
+ return {
2055
+ code: `throw _rt.EXIT`,
2056
+ async: false,
2057
+ sideEffects: true
2058
+ };
2059
+ }
2060
+ };
2061
+ var ReturnCodegen = class {
2062
+ constructor() {
2063
+ this.command = "return";
2064
+ }
2065
+ generate(node, ctx) {
2066
+ const args = node.args ?? [];
2067
+ const value = args.length > 0 ? ctx.generateExpression(args[0]) : "undefined";
2068
+ return {
2069
+ code: `return ${value}`,
2070
+ async: false,
2071
+ sideEffects: true
2072
+ };
2073
+ }
2074
+ };
2075
+ var CallCodegen = class {
2076
+ constructor() {
2077
+ this.command = "call";
2078
+ }
2079
+ generate(node, ctx) {
2080
+ const args = node.args ?? [];
2081
+ if (args.length === 0) return null;
2082
+ const fn = ctx.generateExpression(args[0]);
2083
+ return {
2084
+ code: fn,
2085
+ async: false,
2086
+ sideEffects: true
2087
+ };
2088
+ }
2089
+ };
2090
+ var ScrollCodegen = class {
2091
+ constructor() {
2092
+ this.command = "scroll";
2093
+ }
2094
+ generate(node, ctx) {
2095
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2096
+ const behavior = node.modifiers?.smooth ? "'smooth'" : "'auto'";
2097
+ return {
2098
+ code: `${target}.scrollIntoView({ behavior: ${behavior} })`,
2099
+ async: false,
2100
+ sideEffects: true
2101
+ };
2102
+ }
2103
+ };
2104
+ var TakeCodegen = class {
2105
+ constructor() {
2106
+ this.command = "take";
2107
+ }
2108
+ generate(node, _ctx) {
2109
+ const args = node.args ?? [];
2110
+ if (args.length === 0) return null;
2111
+ const arg = args[0];
2112
+ if (arg.type !== "selector") return null;
2113
+ const selector = arg.value;
2114
+ if (!selector.startsWith(".")) return null;
2115
+ const className = sanitizeClassName(selector.slice(1));
2116
+ if (!className) return null;
2117
+ return {
2118
+ code: `(() => { const _me = _ctx.me; _me.parentElement?.querySelectorAll('.${className}').forEach(el => el.classList.remove('${className}')); _me.classList.add('${className}'); })()`,
2119
+ async: false,
2120
+ sideEffects: true
2121
+ };
2122
+ }
2123
+ };
2124
+ function generateIf(node, ctx, generateBody) {
2125
+ const exprCodegen = new ExpressionCodegen(ctx);
2126
+ const condition = exprCodegen.generate(node.condition);
2127
+ const thenBody = generateBody(node.thenBranch);
2128
+ let code = `if (${condition}) {
2129
+ ${thenBody}
2130
+ }`;
2131
+ if (node.elseIfBranches) {
2132
+ for (const branch of node.elseIfBranches) {
2133
+ const branchCondition = exprCodegen.generate(branch.condition);
2134
+ const branchBody = generateBody(branch.body);
2135
+ code += ` else if (${branchCondition}) {
2136
+ ${branchBody}
2137
+ }`;
2138
+ }
2139
+ }
2140
+ if (node.elseBranch) {
2141
+ const elseBody = generateBody(node.elseBranch);
2142
+ code += ` else {
2143
+ ${elseBody}
2144
+ }`;
2145
+ }
2146
+ return code;
2147
+ }
2148
+ function generateRepeat(node, ctx, generateBody) {
2149
+ const exprCodegen = new ExpressionCodegen(ctx);
2150
+ const body = generateBody(node.body);
2151
+ if (node.count !== void 0) {
2152
+ const count = typeof node.count === "number" ? String(node.count) : exprCodegen.generate(node.count);
2153
+ return `for (let _i = 0; _i < ${count}; _i++) {
2154
+ _ctx.locals.set('index', _i);
2155
+ ${body}
2156
+ }`;
2157
+ }
2158
+ if (node.whileCondition) {
2159
+ const condition = exprCodegen.generate(node.whileCondition);
2160
+ return `while (${condition}) {
2161
+ ${body}
2162
+ }`;
2163
+ }
2164
+ return `while (true) {
2165
+ ${body}
2166
+ }`;
2167
+ }
2168
+ function generateForEach(node, ctx, generateBody) {
2169
+ const exprCodegen = new ExpressionCodegen(ctx);
2170
+ const collection = exprCodegen.generate(node.collection);
2171
+ const itemName = sanitizeIdentifier(node.itemName);
2172
+ const indexName = node.indexName ? sanitizeIdentifier(node.indexName) : "index";
2173
+ const body = generateBody(node.body);
2174
+ return `{
2175
+ const _collection = ${collection};
2176
+ const _arr = Array.isArray(_collection) ? _collection : Array.from(_collection);
2177
+ for (let _i = 0; _i < _arr.length; _i++) {
2178
+ _ctx.locals.set('${itemName}', _arr[_i]);
2179
+ _ctx.locals.set('${indexName}', _i);
2180
+ ${body}
2181
+ }
2182
+ }`;
2183
+ }
2184
+ function generateWhile(node, ctx, generateBody) {
2185
+ const exprCodegen = new ExpressionCodegen(ctx);
2186
+ const condition = exprCodegen.generate(node.condition);
2187
+ const body = generateBody(node.body);
2188
+ return `while (${condition}) {
2189
+ ${body}
2190
+ }`;
2191
+ }
2192
+ var UnlessCodegen = class {
2193
+ constructor() {
2194
+ this.command = "unless";
2195
+ }
2196
+ generate(node, ctx) {
2197
+ const args = node.args ?? [];
2198
+ if (args.length === 0) return null;
2199
+ const condition = ctx.generateExpression(args[0]);
2200
+ return {
2201
+ code: `if (!(${condition}))`,
2202
+ async: false,
2203
+ sideEffects: false
2204
+ };
2205
+ }
2206
+ };
2207
+ var ThrowCodegen = class {
2208
+ constructor() {
2209
+ this.command = "throw";
2210
+ }
2211
+ generate(node, ctx) {
2212
+ const args = node.args ?? [];
2213
+ const value = args.length > 0 ? ctx.generateExpression(args[0]) : "'Error'";
2214
+ return {
2215
+ code: `throw new Error(${value})`,
2216
+ async: false,
2217
+ sideEffects: true
2218
+ };
2219
+ }
2220
+ };
2221
+ var DefaultCodegen = class {
2222
+ constructor() {
2223
+ this.command = "default";
2224
+ }
2225
+ generate(node, ctx) {
2226
+ const args = node.args ?? [];
2227
+ const roles = node.roles;
2228
+ const modifiers = node.modifiers;
2229
+ const targetNode = roles?.destination ?? args[0];
2230
+ const valueNode = roles?.patient ?? modifiers?.to ?? args[1];
2231
+ if (!targetNode || !valueNode) return null;
2232
+ const value = ctx.generateExpression(valueNode);
2233
+ if (targetNode.type === "variable") {
2234
+ const varNode = targetNode;
2235
+ const name = varNode.name.startsWith(":") ? varNode.name.slice(1) : varNode.name;
2236
+ const safeName = sanitizeIdentifier(name);
2237
+ if (varNode.scope === "local") {
2238
+ return {
2239
+ code: `if (_ctx.locals.get('${safeName}') == null) _ctx.locals.set('${safeName}', ${value})`,
2240
+ async: false,
2241
+ sideEffects: true
2242
+ };
2243
+ }
2244
+ if (varNode.scope === "global") {
2245
+ ctx.requireHelper("globals");
2246
+ return {
2247
+ code: `if (_rt.globals.get('${safeName}') == null) _rt.globals.set('${safeName}', ${value})`,
2248
+ async: false,
2249
+ sideEffects: true
2250
+ };
2251
+ }
2252
+ }
2253
+ return null;
2254
+ }
2255
+ };
2256
+ var GoCodegen = class {
2257
+ constructor() {
2258
+ this.command = "go";
2259
+ }
2260
+ generate(node, ctx) {
2261
+ const args = node.args ?? [];
2262
+ const roles = node.roles;
2263
+ const target = roles?.destination ?? args[0];
2264
+ if (!target) return null;
2265
+ if (target.type === "identifier") {
2266
+ const name = target.value;
2267
+ if (name === "back") {
2268
+ return { code: "history.back()", async: false, sideEffects: true };
2269
+ }
2270
+ if (name === "forward") {
2271
+ return { code: "history.forward()", async: false, sideEffects: true };
2272
+ }
2273
+ }
2274
+ const url = ctx.generateExpression(target);
2275
+ return {
2276
+ code: `window.location.href = ${url}`,
2277
+ async: false,
2278
+ sideEffects: true
2279
+ };
2280
+ }
2281
+ };
2282
+ var AppendCodegen = class {
2283
+ constructor() {
2284
+ this.command = "append";
2285
+ }
2286
+ generate(node, ctx) {
2287
+ const args = node.args ?? [];
2288
+ const roles = node.roles;
2289
+ const contentNode = roles?.patient ?? args[0];
2290
+ if (!contentNode) return null;
2291
+ const content = ctx.generateExpression(contentNode);
2292
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2293
+ return {
2294
+ code: `${target}.insertAdjacentHTML('beforeend', ${content})`,
2295
+ async: false,
2296
+ sideEffects: true
2297
+ };
2298
+ }
2299
+ };
2300
+ var PickCodegen = class {
2301
+ constructor() {
2302
+ this.command = "pick";
2303
+ }
2304
+ generate(node, ctx) {
2305
+ const args = node.args ?? [];
2306
+ const roles = node.roles;
2307
+ const collection = roles?.source ?? args[0];
2308
+ if (!collection) return null;
2309
+ const arr = ctx.generateExpression(collection);
2310
+ return {
2311
+ code: `_ctx.it = (() => { const _a = ${arr}; return _a[Math.floor(Math.random() * _a.length)]; })()`,
2312
+ async: false,
2313
+ sideEffects: true
2314
+ };
2315
+ }
2316
+ };
2317
+ var PushUrlCodegen = class {
2318
+ constructor() {
2319
+ this.command = "push-url";
2320
+ }
2321
+ generate(node, ctx) {
2322
+ const args = node.args ?? [];
2323
+ const roles = node.roles;
2324
+ const urlNode = roles?.destination ?? args[0];
2325
+ if (!urlNode) return null;
2326
+ const url = ctx.generateExpression(urlNode);
2327
+ return {
2328
+ code: `history.pushState({}, '', ${url})`,
2329
+ async: false,
2330
+ sideEffects: true
2331
+ };
2332
+ }
2333
+ };
2334
+ var ReplaceUrlCodegen = class {
2335
+ constructor() {
2336
+ this.command = "replace-url";
2337
+ }
2338
+ generate(node, ctx) {
2339
+ const args = node.args ?? [];
2340
+ const roles = node.roles;
2341
+ const urlNode = roles?.destination ?? args[0];
2342
+ if (!urlNode) return null;
2343
+ const url = ctx.generateExpression(urlNode);
2344
+ return {
2345
+ code: `history.replaceState({}, '', ${url})`,
2346
+ async: false,
2347
+ sideEffects: true
2348
+ };
2349
+ }
2350
+ };
2351
+ var GetCodegen = class {
2352
+ constructor() {
2353
+ this.command = "get";
2354
+ }
2355
+ generate(node, ctx) {
2356
+ const args = node.args ?? [];
2357
+ const roles = node.roles;
2358
+ const expr = roles?.patient ?? args[0];
2359
+ if (!expr) return null;
2360
+ const value = ctx.generateExpression(expr);
2361
+ return {
2362
+ code: `_ctx.it = _ctx.result = ${value}`,
2363
+ async: false,
2364
+ sideEffects: true
2365
+ };
2366
+ }
2367
+ };
2368
+ var BreakCodegen = class {
2369
+ constructor() {
2370
+ this.command = "break";
2371
+ }
2372
+ generate(_node, _ctx) {
2373
+ return {
2374
+ code: "break",
2375
+ async: false,
2376
+ sideEffects: false
2377
+ };
2378
+ }
2379
+ };
2380
+ var ContinueCodegen = class {
2381
+ constructor() {
2382
+ this.command = "continue";
2383
+ }
2384
+ generate(_node, _ctx) {
2385
+ return {
2386
+ code: "continue",
2387
+ async: false,
2388
+ sideEffects: false
2389
+ };
2390
+ }
2391
+ };
2392
+ var BeepCodegen = class {
2393
+ constructor() {
2394
+ this.command = "beep";
2395
+ }
2396
+ generate(node, ctx) {
2397
+ const args = node.args ?? [];
2398
+ const roles = node.roles;
2399
+ const expr = roles?.patient ?? args[0];
2400
+ if (!expr) {
2401
+ return {
2402
+ code: `console.log('%c[beep]', 'color: orange; font-weight: bold')`,
2403
+ async: false,
2404
+ sideEffects: true
2405
+ };
2406
+ }
2407
+ const value = ctx.generateExpression(expr);
2408
+ return {
2409
+ code: `console.log('%c[beep]', 'color: orange; font-weight: bold', ${value})`,
2410
+ async: false,
2411
+ sideEffects: true
2412
+ };
2413
+ }
2414
+ };
2415
+ var JsCodegen = class {
2416
+ constructor() {
2417
+ this.command = "js";
2418
+ }
2419
+ generate(node, ctx) {
2420
+ const args = node.args ?? [];
2421
+ const roles = node.roles;
2422
+ const bodyNode = roles?.patient ?? args[0];
2423
+ if (!bodyNode) return null;
2424
+ if (bodyNode.type === "literal") {
2425
+ const code = bodyNode.value;
2426
+ if (typeof code === "string") {
2427
+ return {
2428
+ code: `(function(_ctx) { ${code} })(_ctx)`,
2429
+ async: false,
2430
+ sideEffects: true
2431
+ };
2432
+ }
2433
+ }
2434
+ const value = ctx.generateExpression(bodyNode);
2435
+ return {
2436
+ code: `_ctx.it = _ctx.result = ${value}`,
2437
+ async: false,
2438
+ sideEffects: true
2439
+ };
2440
+ }
2441
+ };
2442
+ var CopyCodegen = class {
2443
+ constructor() {
2444
+ this.command = "copy";
2445
+ }
2446
+ generate(node, ctx) {
2447
+ const args = node.args ?? [];
2448
+ const roles = node.roles;
2449
+ const contentNode = roles?.patient ?? args[0];
2450
+ if (!contentNode) return null;
2451
+ const content = ctx.generateExpression(contentNode);
2452
+ return {
2453
+ code: `await navigator.clipboard.writeText(String(${content}))`,
2454
+ async: true,
2455
+ sideEffects: true
2456
+ };
2457
+ }
2458
+ };
2459
+ var MakeCodegen = class {
2460
+ constructor() {
2461
+ this.command = "make";
2462
+ }
2463
+ generate(node, ctx) {
2464
+ const args = node.args ?? [];
2465
+ const roles = node.roles;
2466
+ const targetNode = roles?.patient ?? args[0];
2467
+ if (!targetNode) return null;
2468
+ if (targetNode.type === "htmlLiteral") {
2469
+ const tagNode = targetNode;
2470
+ const tag = tagNode.tag ?? "div";
2471
+ const classes = tagNode.classes ?? [];
2472
+ const id = tagNode.id;
2473
+ const attrs = tagNode.attributes ?? {};
2474
+ let code = `(() => { const _el = document.createElement('${tag}');`;
2475
+ if (classes.length > 0) {
2476
+ code += ` _el.className = '${classes.join(" ")}';`;
2477
+ }
2478
+ if (id) {
2479
+ code += ` _el.id = '${sanitizeIdentifier(id)}';`;
2480
+ }
2481
+ for (const [attr, val] of Object.entries(attrs)) {
2482
+ code += ` _el.setAttribute('${sanitizeSelector(attr)}', '${sanitizeSelector(val)}');`;
2483
+ }
2484
+ code += ` return _el; })()`;
2485
+ return {
2486
+ code: `_ctx.it = _ctx.result = ${code}`,
2487
+ async: false,
2488
+ sideEffects: true
2489
+ };
2490
+ }
2491
+ if (targetNode.type === "literal") {
2492
+ const tag = targetNode.value;
2493
+ if (typeof tag === "string") {
2494
+ return {
2495
+ code: `_ctx.it = _ctx.result = document.createElement('${sanitizeSelector(tag)}')`,
2496
+ async: false,
2497
+ sideEffects: true
2498
+ };
2499
+ }
2500
+ }
2501
+ const expr = ctx.generateExpression(targetNode);
2502
+ return {
2503
+ code: `_ctx.it = _ctx.result = document.createElement(${expr})`,
2504
+ async: false,
2505
+ sideEffects: true
2506
+ };
2507
+ }
2508
+ };
2509
+ var SwapCodegen = class {
2510
+ constructor() {
2511
+ this.command = "swap";
2512
+ }
2513
+ generate(node, ctx) {
2514
+ const args = node.args ?? [];
2515
+ const roles = node.roles;
2516
+ if (args.length > 0 && args[0].type === "identifier" && args[0].value === "delete") {
2517
+ const targetNode2 = args[1] ?? node.target;
2518
+ if (!targetNode2) return null;
2519
+ const target2 = ctx.generateExpression(targetNode2);
2520
+ return { code: `${target2}.remove()`, async: false, sideEffects: true };
2521
+ }
2522
+ const contentNode = roles?.patient ?? args[args.length - 1];
2523
+ const targetNode = roles?.destination ?? node.target ?? args[0];
2524
+ if (!targetNode || !contentNode) return null;
2525
+ const target = ctx.generateExpression(targetNode);
2526
+ const content = ctx.generateExpression(contentNode);
2527
+ const strategy = this.resolveStrategy(node, args);
2528
+ switch (strategy) {
2529
+ case "outerHTML":
2530
+ return { code: `${target}.outerHTML = ${content}`, async: false, sideEffects: true };
2531
+ case "beforebegin":
2532
+ return {
2533
+ code: `${target}.insertAdjacentHTML('beforebegin', ${content})`,
2534
+ async: false,
2535
+ sideEffects: true
2536
+ };
2537
+ case "afterbegin":
2538
+ return {
2539
+ code: `${target}.insertAdjacentHTML('afterbegin', ${content})`,
2540
+ async: false,
2541
+ sideEffects: true
2542
+ };
2543
+ case "beforeend":
2544
+ return {
2545
+ code: `${target}.insertAdjacentHTML('beforeend', ${content})`,
2546
+ async: false,
2547
+ sideEffects: true
2548
+ };
2549
+ case "afterend":
2550
+ return {
2551
+ code: `${target}.insertAdjacentHTML('afterend', ${content})`,
2552
+ async: false,
2553
+ sideEffects: true
2554
+ };
2555
+ case "morph":
2556
+ ctx.requireHelper("morph");
2557
+ return { code: `_rt.morph(${target}, ${content})`, async: false, sideEffects: true };
2558
+ case "innerHTML":
2559
+ default:
2560
+ return { code: `${target}.innerHTML = ${content}`, async: false, sideEffects: true };
2561
+ }
2562
+ }
2563
+ resolveStrategy(node, args) {
2564
+ const mods = node.modifiers;
2565
+ if (mods?.strategy && typeof mods.strategy === "string") return mods.strategy.toLowerCase();
2566
+ if (args.length >= 2 && args[0].type === "identifier") {
2567
+ const name = (args[0].value ?? "").toLowerCase();
2568
+ const strategies = {
2569
+ innerhtml: "innerHTML",
2570
+ outerhtml: "outerHTML",
2571
+ morph: "morph",
2572
+ beforebegin: "beforebegin",
2573
+ afterbegin: "afterbegin",
2574
+ beforeend: "beforeend",
2575
+ afterend: "afterend",
2576
+ into: "innerHTML",
2577
+ over: "outerHTML"
2578
+ };
2579
+ if (strategies[name]) return strategies[name];
2580
+ }
2581
+ return "innerHTML";
2582
+ }
2583
+ };
2584
+ var MorphCodegen = class {
2585
+ constructor() {
2586
+ this.command = "morph";
2587
+ }
2588
+ generate(node, ctx) {
2589
+ const args = node.args ?? [];
2590
+ const roles = node.roles;
2591
+ const targetNode = roles?.destination ?? node.target ?? args[0];
2592
+ const contentNode = roles?.patient ?? args[args.length > 1 ? args.length - 1 : 0];
2593
+ if (!targetNode) return null;
2594
+ const target = ctx.generateExpression(targetNode);
2595
+ ctx.requireHelper("morph");
2596
+ if (!contentNode || contentNode === targetNode) {
2597
+ return { code: `_rt.morph(${target}, '')`, async: false, sideEffects: true };
2598
+ }
2599
+ const content = ctx.generateExpression(contentNode);
2600
+ return { code: `_rt.morph(${target}, ${content})`, async: false, sideEffects: true };
2601
+ }
2602
+ };
2603
+ var TransitionCodegen = class {
2604
+ constructor() {
2605
+ this.command = "transition";
2606
+ }
2607
+ generate(node, ctx) {
2608
+ const args = node.args ?? [];
2609
+ const roles = node.roles;
2610
+ const mods = node.modifiers;
2611
+ const propertyNode = roles?.patient ?? args[0];
2612
+ if (!propertyNode) return null;
2613
+ const property = ctx.generateExpression(propertyNode);
2614
+ const valueNode = mods?.to ?? args[1];
2615
+ if (!valueNode) return null;
2616
+ const value = ctx.generateExpression(valueNode);
2617
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2618
+ const durationNode = mods?.over;
2619
+ const duration = durationNode ? ctx.generateExpression(durationNode) : "300";
2620
+ const timingNode = mods?.with;
2621
+ const timing = timingNode ? ctx.generateExpression(timingNode) : "'ease'";
2622
+ ctx.requireHelper("transition");
2623
+ return {
2624
+ code: `await _rt.transition(${target}, ${property}, ${value}, ${duration}, ${timing})`,
2625
+ async: true,
2626
+ sideEffects: true
2627
+ };
2628
+ }
2629
+ };
2630
+ var MeasureCodegen = class {
2631
+ constructor() {
2632
+ this.command = "measure";
2633
+ }
2634
+ generate(node, ctx) {
2635
+ const args = node.args ?? [];
2636
+ const roles = node.roles;
2637
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2638
+ const propNode = roles?.patient ?? args[0];
2639
+ if (!propNode) {
2640
+ return {
2641
+ code: `_ctx.it = _ctx.result = ${target}.getBoundingClientRect()`,
2642
+ async: false,
2643
+ sideEffects: true
2644
+ };
2645
+ }
2646
+ if (propNode.type === "identifier") {
2647
+ const propName = propNode.value ?? "";
2648
+ const rectProps = ["width", "height", "top", "left", "right", "bottom", "x", "y"];
2649
+ if (rectProps.includes(propName.toLowerCase())) {
2650
+ return {
2651
+ code: `_ctx.it = _ctx.result = ${target}.getBoundingClientRect().${propName.toLowerCase()}`,
2652
+ async: false,
2653
+ sideEffects: true
2654
+ };
2655
+ }
2656
+ }
2657
+ const prop = ctx.generateExpression(propNode);
2658
+ ctx.requireHelper("measure");
2659
+ return {
2660
+ code: `_ctx.it = _ctx.result = _rt.measure(${target}, ${prop})`,
2661
+ async: false,
2662
+ sideEffects: true
2663
+ };
2664
+ }
2665
+ };
2666
+ var SettleCodegen = class {
2667
+ constructor() {
2668
+ this.command = "settle";
2669
+ }
2670
+ generate(node, ctx) {
2671
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2672
+ const mods = node.modifiers;
2673
+ const timeoutNode = mods?.for;
2674
+ const timeout = timeoutNode ? ctx.generateExpression(timeoutNode) : "5000";
2675
+ ctx.requireHelper("settle");
2676
+ return {
2677
+ code: `await _rt.settle(${target}, ${timeout})`,
2678
+ async: true,
2679
+ sideEffects: true
2680
+ };
2681
+ }
2682
+ };
2683
+ var TellCodegen = class {
2684
+ constructor() {
2685
+ this.command = "tell";
2686
+ }
2687
+ generate(node, ctx) {
2688
+ const args = node.args ?? [];
2689
+ const roles = node.roles;
2690
+ const targetNode = roles?.destination ?? args[0];
2691
+ if (!targetNode) return null;
2692
+ const target = ctx.generateExpression(targetNode);
2693
+ return {
2694
+ code: `{ const _prevMe = _ctx.me; _ctx.me = ${target}; _ctx.you = ${target};`,
2695
+ async: false,
2696
+ sideEffects: true
2697
+ };
2698
+ }
2699
+ };
2700
+ var AsyncCodegen = class {
2701
+ constructor() {
2702
+ this.command = "async";
2703
+ }
2704
+ generate(_node, _ctx) {
2705
+ return {
2706
+ code: `(async () => {`,
2707
+ async: false,
2708
+ // The outer handler doesn't await this
2709
+ sideEffects: true
2710
+ };
2711
+ }
2712
+ };
2713
+ var InstallCodegen = class {
2714
+ constructor() {
2715
+ this.command = "install";
2716
+ }
2717
+ generate(node, ctx) {
2718
+ const args = node.args ?? [];
2719
+ const roles = node.roles;
2720
+ const behaviorNode = roles?.patient ?? args[0];
2721
+ if (!behaviorNode) return null;
2722
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2723
+ let behaviorName;
2724
+ if (behaviorNode.type === "identifier") {
2725
+ behaviorName = behaviorNode.value ?? "";
2726
+ } else if (behaviorNode.type === "literal") {
2727
+ behaviorName = String(behaviorNode.value);
2728
+ } else {
2729
+ behaviorName = ctx.generateExpression(behaviorNode);
2730
+ ctx.requireHelper("installBehavior");
2731
+ return {
2732
+ code: `_rt.installBehavior(${target}, ${behaviorName})`,
2733
+ async: false,
2734
+ sideEffects: true
2735
+ };
2736
+ }
2737
+ ctx.requireHelper("installBehavior");
2738
+ const paramsNode = args.length > 1 ? args[1] : void 0;
2739
+ if (paramsNode && paramsNode.type === "object") {
2740
+ const params = ctx.generateExpression(paramsNode);
2741
+ return {
2742
+ code: `_rt.installBehavior(${target}, '${sanitizeIdentifier(behaviorName)}', ${params})`,
2743
+ async: false,
2744
+ sideEffects: true
2745
+ };
2746
+ }
2747
+ return {
2748
+ code: `_rt.installBehavior(${target}, '${sanitizeIdentifier(behaviorName)}')`,
2749
+ async: false,
2750
+ sideEffects: true
2751
+ };
2752
+ }
2753
+ };
2754
+ var RenderCodegen = class {
2755
+ constructor() {
2756
+ this.command = "render";
2757
+ }
2758
+ generate(node, ctx) {
2759
+ const args = node.args ?? [];
2760
+ const roles = node.roles;
2761
+ const mods = node.modifiers;
2762
+ const templateNode = roles?.patient ?? args[0];
2763
+ if (!templateNode) return null;
2764
+ const template = ctx.generateExpression(templateNode);
2765
+ const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2766
+ const varsNode = mods?.with ?? (args.length > 1 ? args[1] : void 0);
2767
+ ctx.requireHelper("render");
2768
+ if (varsNode) {
2769
+ const vars = ctx.generateExpression(varsNode);
2770
+ return {
2771
+ code: `${target}.innerHTML = _rt.render(${template}, ${vars})`,
2772
+ async: false,
2773
+ sideEffects: true
2774
+ };
2775
+ }
2776
+ return {
2777
+ code: `${target}.innerHTML = _rt.render(${template}, {})`,
2778
+ async: false,
2779
+ sideEffects: true
2780
+ };
2781
+ }
2782
+ };
2783
+ var commandCodegens = /* @__PURE__ */ new Map([
2784
+ ["toggle", new ToggleCodegen()],
2785
+ ["add", new AddCodegen()],
2786
+ ["remove", new RemoveCodegen()],
2787
+ ["set", new SetCodegen()],
2788
+ ["put", new PutCodegen()],
2789
+ ["show", new ShowCodegen()],
2790
+ ["hide", new HideCodegen()],
2791
+ ["focus", new FocusCodegen()],
2792
+ ["blur", new BlurCodegen()],
2793
+ ["log", new LogCodegen()],
2794
+ ["wait", new WaitCodegen()],
2795
+ ["fetch", new FetchCodegen()],
2796
+ ["send", new SendCodegen()],
2797
+ ["trigger", new SendCodegen()],
2798
+ // Alias
2799
+ ["increment", new IncrementCodegen()],
2800
+ ["decrement", new DecrementCodegen()],
2801
+ ["halt", new HaltCodegen()],
2802
+ ["exit", new ExitCodegen()],
2803
+ ["return", new ReturnCodegen()],
2804
+ ["call", new CallCodegen()],
2805
+ ["scroll", new ScrollCodegen()],
2806
+ ["take", new TakeCodegen()],
2807
+ ["unless", new UnlessCodegen()],
2808
+ ["throw", new ThrowCodegen()],
2809
+ ["default", new DefaultCodegen()],
2810
+ ["go", new GoCodegen()],
2811
+ ["append", new AppendCodegen()],
2812
+ ["pick", new PickCodegen()],
2813
+ ["push-url", new PushUrlCodegen()],
2814
+ ["replace-url", new ReplaceUrlCodegen()],
2815
+ ["get", new GetCodegen()],
2816
+ ["break", new BreakCodegen()],
2817
+ ["continue", new ContinueCodegen()],
2818
+ ["beep", new BeepCodegen()],
2819
+ ["js", new JsCodegen()],
2820
+ ["copy", new CopyCodegen()],
2821
+ ["make", new MakeCodegen()],
2822
+ // Phase 1 additions
2823
+ ["swap", new SwapCodegen()],
2824
+ ["morph", new MorphCodegen()],
2825
+ ["transition", new TransitionCodegen()],
2826
+ ["measure", new MeasureCodegen()],
2827
+ ["settle", new SettleCodegen()],
2828
+ ["tell", new TellCodegen()],
2829
+ ["async", new AsyncCodegen()],
2830
+ ["install", new InstallCodegen()],
2831
+ ["render", new RenderCodegen()]
2832
+ ]);
2833
+ function generateCommand(node, ctx) {
2834
+ const codegen = commandCodegens.get(node.name);
2835
+ if (!codegen) {
2836
+ return null;
2837
+ }
2838
+ return codegen.generate(node, ctx);
2839
+ }
2840
+ function parseDuration(duration) {
2841
+ const match = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/i.exec(duration.trim());
2842
+ if (!match) return null;
2843
+ const value = parseFloat(match[1]);
2844
+ const unit = (match[2] ?? "ms").toLowerCase();
2845
+ switch (unit) {
2846
+ case "ms":
2847
+ return value;
2848
+ case "s":
2849
+ return value * 1e3;
2850
+ case "m":
2851
+ return value * 6e4;
2852
+ case "h":
2853
+ return value * 36e5;
2854
+ default:
2855
+ return value;
2856
+ }
2857
+ }
2858
+ var EventHandlerCodegen = class {
2859
+ constructor(ctx, analysis) {
2860
+ this.ctx = ctx;
2861
+ this.analysis = analysis;
2862
+ }
2863
+ /**
2864
+ * Generate complete code for an event handler.
2865
+ */
2866
+ generate(node) {
2867
+ const eventName = node.event;
2868
+ const modifiers = node.modifiers ?? {};
2869
+ const body = node.body ?? [];
2870
+ const bodyCode = this.generateBody(body);
2871
+ const isAsync = this.analysis.controlFlow.hasAsync;
2872
+ const listenerOptions = this.buildListenerOptions(modifiers);
2873
+ const modifierCode = this.generateModifierCode(modifiers);
2874
+ const handlerCode = this.generateHandlerFunction(eventName, bodyCode, modifierCode, isAsync);
2875
+ const bindingCode = this.generateBindingCode(eventName, modifiers, listenerOptions);
2876
+ const cleanup = this.generateCleanupCode(eventName, modifiers);
2877
+ const imports = this.collectImports();
2878
+ return {
2879
+ handlerCode,
2880
+ bindingCode,
2881
+ cleanup,
2882
+ async: isAsync,
2883
+ imports
2884
+ };
2885
+ }
2886
+ // ===========================================================================
2887
+ // BODY GENERATION
2888
+ // ===========================================================================
2889
+ /**
2890
+ * Generate code for the handler body.
2891
+ */
2892
+ generateBody(nodes) {
2893
+ const statements = [];
2894
+ for (const node of nodes) {
2895
+ const code = this.generateNode(node);
2896
+ if (code) {
2897
+ statements.push(code);
2898
+ }
2899
+ }
2900
+ return statements.join("\n");
2901
+ }
2902
+ /**
2903
+ * Generate code for a single AST node.
2904
+ */
2905
+ generateNode(node) {
2906
+ switch (node.type) {
2907
+ case "command":
2908
+ return this.generateCommandCode(node);
2909
+ case "if":
2910
+ return generateIf(node, this.ctx, (nodes) => this.generateBody(nodes));
2911
+ case "repeat":
2912
+ return generateRepeat(node, this.ctx, (nodes) => this.generateBody(nodes));
2913
+ case "foreach":
2914
+ return generateForEach(node, this.ctx, (nodes) => this.generateBody(nodes));
2915
+ case "while":
2916
+ return generateWhile(node, this.ctx, (nodes) => this.generateBody(nodes));
2917
+ case "event": {
2918
+ const nested = node;
2919
+ return this.generateBody(nested.body ?? []);
2920
+ }
2921
+ default:
2922
+ return null;
2923
+ }
2924
+ }
2925
+ /**
2926
+ * Generate code for a command.
2927
+ */
2928
+ generateCommandCode(node) {
2929
+ const result = generateCommand(node, this.ctx);
2930
+ if (!result) {
2931
+ return null;
2932
+ }
2933
+ return result.code;
2934
+ }
2935
+ // ===========================================================================
2936
+ // MODIFIER HANDLING
2937
+ // ===========================================================================
2938
+ /**
2939
+ * Build AddEventListenerOptions from modifiers.
2940
+ */
2941
+ buildListenerOptions(modifiers) {
2942
+ const options = {};
2943
+ if (modifiers.once) {
2944
+ options.once = true;
2945
+ }
2946
+ if (modifiers.passive) {
2947
+ options.passive = true;
2948
+ }
2949
+ if (modifiers.capture) {
2950
+ options.capture = true;
2951
+ }
2952
+ return options;
2953
+ }
2954
+ /**
2955
+ * Generate code for event modifiers (prevent, stop).
2956
+ */
2957
+ generateModifierCode(modifiers) {
2958
+ const code = [];
2959
+ if (modifiers.prevent) {
2960
+ code.push("_event.preventDefault();");
2961
+ }
2962
+ if (modifiers.stop) {
2963
+ code.push("_event.stopPropagation();");
2964
+ }
2965
+ return code.join("\n");
2966
+ }
2967
+ // ===========================================================================
2968
+ // HANDLER FUNCTION GENERATION
2969
+ // ===========================================================================
2970
+ /**
2971
+ * Generate the complete handler function.
2972
+ */
2973
+ generateHandlerFunction(_eventName, bodyCode, modifierCode, isAsync) {
2974
+ const asyncKeyword = isAsync ? "async " : "";
2975
+ const handlerId = this.ctx.handlerId;
2976
+ const contextInit = `const _ctx = _rt.createContext(_event, this);`;
2977
+ const combinedBody = [modifierCode, bodyCode].filter(Boolean).join("\n");
2978
+ const needsTryCatch = this.analysis.controlFlow.canThrow;
2979
+ let functionBody;
2980
+ if (needsTryCatch) {
2981
+ functionBody = `${contextInit}
2982
+ try {
2983
+ ${combinedBody}
2984
+ } catch (_e) {
2985
+ if (_e === _rt.HALT) {
2986
+ _event.preventDefault();
2987
+ return;
2988
+ }
2989
+ if (_e === _rt.EXIT) {
2990
+ return;
2991
+ }
2992
+ throw _e;
2993
+ }`;
2994
+ } else {
2995
+ functionBody = `${contextInit}
2996
+ ${combinedBody}`;
2997
+ }
2998
+ return `${asyncKeyword}function _handler_${handlerId}(_event) {
2999
+ ${functionBody}
3000
+ }`;
3001
+ }
3002
+ // ===========================================================================
3003
+ // BINDING CODE GENERATION
3004
+ // ===========================================================================
3005
+ /**
3006
+ * Generate code to bind the handler to an element.
3007
+ */
3008
+ generateBindingCode(eventName, modifiers, options) {
3009
+ const handlerId = this.ctx.handlerId;
3010
+ const event = JSON.stringify(eventName);
3011
+ let handler = `_handler_${handlerId}`;
3012
+ if (modifiers.debounce) {
3013
+ this.ctx.requireHelper("debounce");
3014
+ handler = `_rt.debounce(${handler}, ${modifiers.debounce})`;
3015
+ }
3016
+ if (modifiers.throttle) {
3017
+ this.ctx.requireHelper("throttle");
3018
+ handler = `_rt.throttle(${handler}, ${modifiers.throttle})`;
3019
+ }
3020
+ const optionsKeys = Object.keys(options).filter((k) => options[k]);
3021
+ const optionsArg = optionsKeys.length > 0 ? `, { ${optionsKeys.map((k) => `${k}: true`).join(", ")} }` : "";
3022
+ if (modifiers.from) {
3023
+ const delegateSelector = JSON.stringify(modifiers.from);
3024
+ this.ctx.requireHelper("delegate");
3025
+ return `_rt.delegate(_el, ${event}, ${delegateSelector}, ${handler}${optionsArg});`;
3026
+ }
3027
+ return `_el.addEventListener(${event}, ${handler}${optionsArg});`;
3028
+ }
3029
+ // ===========================================================================
3030
+ // CLEANUP CODE GENERATION
3031
+ // ===========================================================================
3032
+ /**
3033
+ * Generate cleanup code for removing the handler.
3034
+ */
3035
+ generateCleanupCode(eventName, modifiers) {
3036
+ if (modifiers.once) {
3037
+ return null;
3038
+ }
3039
+ const handlerId = this.ctx.handlerId;
3040
+ const event = JSON.stringify(eventName);
3041
+ const capture = modifiers.capture ? ", true" : "";
3042
+ return `_el.removeEventListener(${event}, _handler_${handlerId}${capture});`;
3043
+ }
3044
+ // ===========================================================================
3045
+ // IMPORTS COLLECTION
3046
+ // ===========================================================================
3047
+ /**
3048
+ * Collect required runtime imports.
3049
+ */
3050
+ collectImports() {
3051
+ const imports = ["createContext"];
3052
+ for (const helper of this.ctx.requiredHelpers) {
3053
+ if (!imports.includes(helper)) {
3054
+ imports.push(helper);
3055
+ }
3056
+ }
3057
+ for (const helper of this.analysis.dependencies.runtimeHelpers) {
3058
+ if (!imports.includes(helper)) {
3059
+ imports.push(helper);
3060
+ }
3061
+ }
3062
+ return imports;
3063
+ }
3064
+ };
3065
+ function generateEventHandler(node, ctx, analysis) {
3066
+ const codegen = new EventHandlerCodegen(ctx, analysis);
3067
+ return codegen.generate(node);
3068
+ }
3069
+ function generateBindings(handlers) {
3070
+ const bindings = [];
3071
+ for (const { selector, eventName, handlerId, options } of handlers) {
3072
+ const sanitized = sanitizeSelector(selector);
3073
+ const event = JSON.stringify(eventName);
3074
+ const optionsKeys = options ? Object.keys(options).filter((k) => options[k]) : [];
3075
+ const optionsArg = optionsKeys.length > 0 ? `, { ${optionsKeys.map((k) => `${k}: true`).join(", ")} }` : "";
3076
+ bindings.push(
3077
+ `document.querySelectorAll('${sanitized}').forEach(_el => _el.addEventListener(${event}, _handler_${handlerId}${optionsArg}));`
3078
+ );
3079
+ }
3080
+ return bindings.join("\n");
3081
+ }
3082
+ function generateInitialization(handlers) {
3083
+ const bindings = generateBindings(handlers);
3084
+ return `_rt.ready(() => {
3085
+ ${bindings}
3086
+ });`;
3087
+ }
3088
+ var DEFAULT_COMPILE_OPTIONS = {
3089
+ language: "en",
3090
+ confidenceThreshold: 0.7,
3091
+ debug: false,
3092
+ codegen: {
3093
+ target: "es2020",
3094
+ mode: "esm",
3095
+ minify: false,
3096
+ sourceMaps: true,
3097
+ runtimeImport: "@hyperfixi/aot-compiler/runtime",
3098
+ preserveComments: false,
3099
+ debugMode: false
3100
+ },
3101
+ optimizationLevel: 2
3102
+ };
3103
+ var DEFAULT_CODEGEN_OPTIONS = {
3104
+ target: "es2020",
3105
+ mode: "esm",
3106
+ minify: false,
3107
+ sourceMaps: true,
3108
+ runtimeImport: "@hyperfixi/aot-compiler/runtime",
3109
+ preserveComments: false,
3110
+ debugMode: false
3111
+ };
3112
+ var AOTCompiler = class {
3113
+ constructor() {
3114
+ this.parser = null;
3115
+ this.semanticParser = null;
3116
+ this.analyzer = new Analyzer();
3117
+ this.optimizer = new OptimizationPipeline();
3118
+ this.usedIds = /* @__PURE__ */ new Set();
3119
+ }
3120
+ /**
3121
+ * Set the traditional parser instance.
3122
+ */
3123
+ setParser(parser) {
3124
+ this.parser = parser;
3125
+ }
3126
+ /**
3127
+ * Set the semantic parser for multilingual support.
3128
+ */
3129
+ setSemanticParser(parser) {
3130
+ this.semanticParser = parser;
3131
+ }
3132
+ /**
3133
+ * Reset compiler state between compilations.
3134
+ */
3135
+ reset() {
3136
+ this.usedIds.clear();
3137
+ }
3138
+ // ===========================================================================
3139
+ // EXTRACTION
3140
+ // ===========================================================================
3141
+ /**
3142
+ * Extract hyperscript from source code.
3143
+ */
3144
+ extract(source, filename) {
3145
+ const scanner = this.createScanner(filename);
3146
+ return scanner.extract(source, filename);
3147
+ }
3148
+ /**
3149
+ * Create appropriate scanner for file type.
3150
+ */
3151
+ createScanner(filename) {
3152
+ if (filename.endsWith(".vue")) {
3153
+ return new VueScanner();
3154
+ }
3155
+ if (filename.endsWith(".svelte")) {
3156
+ return new SvelteScanner();
3157
+ }
3158
+ if (filename.match(/\.(jsx|tsx)$/)) {
3159
+ return new JSXScanner();
3160
+ }
3161
+ return new HTMLScanner();
3162
+ }
3163
+ // ===========================================================================
3164
+ // PARSING
3165
+ // ===========================================================================
3166
+ /**
3167
+ * Parse a hyperscript string to AST.
3168
+ */
3169
+ parse(code, options = {}) {
3170
+ const { language = "en", confidenceThreshold = 0.7, debug = false } = options;
3171
+ let ast = null;
3172
+ if (language !== "en" && this.semanticParser?.supportsLanguage(language)) {
3173
+ const result = this.semanticParser.analyze(code, language);
3174
+ if (result.node && result.confidence >= confidenceThreshold) {
3175
+ const { ast: semanticAst, warnings } = this.semanticParser.buildAST(result.node);
3176
+ if (debug && warnings.length > 0) {
3177
+ console.log(`[aot] Semantic warnings for "${code}":`, warnings);
3178
+ }
3179
+ ast = semanticAst;
3180
+ } else if (debug) {
3181
+ console.log(
3182
+ `[aot] Semantic parse failed for "${code}": ${result.errors?.join(", ") || "low confidence"}`
3183
+ );
3184
+ }
3185
+ }
3186
+ if (!ast && this.parser) {
3187
+ try {
3188
+ ast = this.parser.parse(code, language);
3189
+ } catch (error) {
3190
+ if (debug) {
3191
+ console.log(`[aot] Parse error for "${code}":`, error);
3192
+ }
3193
+ }
3194
+ }
3195
+ if (!ast) {
3196
+ ast = this.createSimpleAST(code);
3197
+ }
3198
+ if (ast && ast.type !== "event") {
3199
+ ast = {
3200
+ type: "event",
3201
+ event: "click",
3202
+ modifiers: {},
3203
+ body: [ast]
3204
+ };
3205
+ }
3206
+ return ast;
3207
+ }
3208
+ /**
3209
+ * Create a simple AST from code (for testing without full parser).
3210
+ */
3211
+ createSimpleAST(code) {
3212
+ const eventMatch = /^on\s+(\w+)(?:\.(\w+))?\s+(.+)$/i.exec(code.trim());
3213
+ if (eventMatch) {
3214
+ const [, eventName, modifier, body] = eventMatch;
3215
+ return {
3216
+ type: "event",
3217
+ event: eventName,
3218
+ modifiers: modifier ? { [modifier]: true } : {},
3219
+ body: [this.parseSimpleCommand(body)].filter(Boolean)
3220
+ };
3221
+ }
3222
+ const cmd = this.parseSimpleCommand(code);
3223
+ if (cmd) {
3224
+ return {
3225
+ type: "event",
3226
+ event: "click",
3227
+ body: [cmd]
3228
+ };
3229
+ }
3230
+ return null;
3231
+ }
3232
+ /**
3233
+ * Parse a simple command (for testing).
3234
+ */
3235
+ parseSimpleCommand(code) {
3236
+ const trimmed = code.trim();
3237
+ const toggleMatch = /^toggle\s+\.([a-zA-Z_][a-zA-Z0-9_-]*)$/i.exec(trimmed);
3238
+ if (toggleMatch) {
3239
+ return {
3240
+ type: "command",
3241
+ name: "toggle",
3242
+ args: [{ type: "selector", value: "." + toggleMatch[1] }]
3243
+ };
3244
+ }
3245
+ const addMatch = /^add\s+\.([a-zA-Z_][a-zA-Z0-9_-]*)$/i.exec(trimmed);
3246
+ if (addMatch) {
3247
+ return {
3248
+ type: "command",
3249
+ name: "add",
3250
+ args: [{ type: "selector", value: "." + addMatch[1] }]
3251
+ };
3252
+ }
3253
+ const removeMatch = /^remove\s+\.([a-zA-Z_][a-zA-Z0-9_-]*)$/i.exec(trimmed);
3254
+ if (removeMatch) {
3255
+ return {
3256
+ type: "command",
3257
+ name: "remove",
3258
+ args: [{ type: "selector", value: "." + removeMatch[1] }]
3259
+ };
3260
+ }
3261
+ if (/^show$/i.test(trimmed)) {
3262
+ return { type: "command", name: "show", args: [] };
3263
+ }
3264
+ if (/^hide$/i.test(trimmed)) {
3265
+ return { type: "command", name: "hide", args: [] };
3266
+ }
3267
+ if (/^focus$/i.test(trimmed)) {
3268
+ return { type: "command", name: "focus", args: [] };
3269
+ }
3270
+ if (/^blur$/i.test(trimmed)) {
3271
+ return { type: "command", name: "blur", args: [] };
3272
+ }
3273
+ const setMatch = /^set\s+:(\w+)\s+to\s+(.+)$/i.exec(trimmed);
3274
+ if (setMatch) {
3275
+ const [, varName, valueStr] = setMatch;
3276
+ return {
3277
+ type: "command",
3278
+ name: "set",
3279
+ args: [{ type: "variable", name: ":" + varName, scope: "local" }],
3280
+ modifiers: { to: this.parseSimpleValue(valueStr) }
3281
+ };
3282
+ }
3283
+ const incrMatch = /^(increment|decrement)\s+:(\w+)$/i.exec(trimmed);
3284
+ if (incrMatch) {
3285
+ const [, cmd, varName] = incrMatch;
3286
+ return {
3287
+ type: "command",
3288
+ name: cmd.toLowerCase(),
3289
+ args: [{ type: "variable", name: ":" + varName, scope: "local" }]
3290
+ };
3291
+ }
3292
+ const waitMatch = /^wait\s+(\d+(?:\.\d+)?)(ms|s)$/i.exec(trimmed);
3293
+ if (waitMatch) {
3294
+ const [, value, unit] = waitMatch;
3295
+ const ms = unit.toLowerCase() === "s" ? parseFloat(value) * 1e3 : parseFloat(value);
3296
+ return {
3297
+ type: "command",
3298
+ name: "wait",
3299
+ args: [{ type: "literal", value: ms }]
3300
+ };
3301
+ }
3302
+ const logMatch = /^log\s+(.+)$/i.exec(trimmed);
3303
+ if (logMatch) {
3304
+ return {
3305
+ type: "command",
3306
+ name: "log",
3307
+ args: [this.parseSimpleValue(logMatch[1])]
3308
+ };
3309
+ }
3310
+ const sendMatch = /^send\s+"([^"]+)"(?:\s+to\s+(\w+))?$/i.exec(trimmed);
3311
+ if (sendMatch) {
3312
+ const [, eventName, target] = sendMatch;
3313
+ const node = {
3314
+ type: "command",
3315
+ name: "send",
3316
+ args: [{ type: "literal", value: eventName }]
3317
+ };
3318
+ if (target) {
3319
+ node.target = { type: "identifier", value: target };
3320
+ }
3321
+ return node;
3322
+ }
3323
+ const fetchMatch = /^fetch\s+(\S+)(?:\s+as\s+(\w+))?$/i.exec(trimmed);
3324
+ if (fetchMatch) {
3325
+ const [, url, format] = fetchMatch;
3326
+ const node = {
3327
+ type: "command",
3328
+ name: "fetch",
3329
+ args: [{ type: "literal", value: url }]
3330
+ };
3331
+ if (format) {
3332
+ node.modifiers = { as: format };
3333
+ }
3334
+ return node;
3335
+ }
3336
+ const putMatch = /^put\s+"([^"]+)"\s+(into|before|after)\s+(\S+)$/i.exec(trimmed);
3337
+ if (putMatch) {
3338
+ const [, content, position, target] = putMatch;
3339
+ return {
3340
+ type: "command",
3341
+ name: "put",
3342
+ args: [{ type: "literal", value: content }],
3343
+ modifiers: { position, [position]: this.parseSimpleValue(target) }
3344
+ };
3345
+ }
3346
+ return null;
3347
+ }
3348
+ /**
3349
+ * Parse a simple value string to an AST node.
3350
+ */
3351
+ parseSimpleValue(valueStr) {
3352
+ const trimmed = valueStr.trim();
3353
+ const strMatch = /^"([^"]*)"$/.exec(trimmed) ?? /^'([^']*)'$/.exec(trimmed);
3354
+ if (strMatch) {
3355
+ return { type: "literal", value: strMatch[1] };
3356
+ }
3357
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
3358
+ return { type: "literal", value: parseFloat(trimmed) };
3359
+ }
3360
+ if (trimmed === "true") return { type: "literal", value: true };
3361
+ if (trimmed === "false") return { type: "literal", value: false };
3362
+ if (/^[#.][a-zA-Z_]/.test(trimmed)) {
3363
+ return { type: "selector", value: trimmed };
3364
+ }
3365
+ if (trimmed.startsWith(":")) {
3366
+ return { type: "variable", name: trimmed, scope: "local" };
3367
+ }
3368
+ return { type: "identifier", value: trimmed };
3369
+ }
3370
+ // ===========================================================================
3371
+ // ANALYSIS
3372
+ // ===========================================================================
3373
+ /**
3374
+ * Analyze an AST for optimization and code generation.
3375
+ */
3376
+ analyze(ast) {
3377
+ return this.analyzer.analyze(ast);
3378
+ }
3379
+ // ===========================================================================
3380
+ // COMPILATION
3381
+ // ===========================================================================
3382
+ /**
3383
+ * Compile a single hyperscript string to JavaScript.
3384
+ */
3385
+ compileScript(code, options = {}) {
3386
+ const mergedOptions = { ...DEFAULT_COMPILE_OPTIONS, ...options };
3387
+ const ast = this.parse(code, mergedOptions);
3388
+ if (!ast) {
3389
+ return {
3390
+ success: false,
3391
+ errors: ["Failed to parse hyperscript"],
3392
+ warnings: [],
3393
+ metadata: {
3394
+ handlerId: "",
3395
+ parserUsed: "traditional",
3396
+ commandsUsed: [],
3397
+ optimizationsApplied: [],
3398
+ needsRuntime: true,
3399
+ runtimeHelpers: []
3400
+ }
3401
+ };
3402
+ }
3403
+ const analysis = this.analyze(ast);
3404
+ const optimized = this.optimizer.optimize(ast, analysis, mergedOptions.optimizationLevel ?? 2);
3405
+ const handlerId = this.generateHandlerId(ast, code);
3406
+ const ctx = this.createCodegenContext(handlerId, analysis, mergedOptions);
3407
+ const generated = this.generateCode(optimized, ctx, analysis);
3408
+ const allHelpers = /* @__PURE__ */ new Set([...ctx.requiredHelpers, ...generated.imports]);
3409
+ if (optimized.type === "event") {
3410
+ const eventNode = optimized;
3411
+ const bodyLen = eventNode.body?.length ?? 0;
3412
+ if (bodyLen > 0 && generated.code) {
3413
+ const handlerMatch = /function\s+_handler_\w+\(_event\)\s*\{([\s\S]*)\}\s*$/.exec(
3414
+ generated.code
3415
+ );
3416
+ if (handlerMatch) {
3417
+ const bodyContent = handlerMatch[1].replace(/const _ctx\s*=\s*[^;]*;/g, "").replace(/const _el\s*=\s*[^;]*;/g, "").trim();
3418
+ if (!bodyContent) {
3419
+ analysis.warnings.push(
3420
+ `Event handler body appears empty despite ${bodyLen} parsed command(s). This may indicate a code generation failure for: "${code}"`
3421
+ );
3422
+ }
3423
+ }
3424
+ }
3425
+ }
3426
+ return {
3427
+ success: true,
3428
+ code: generated.code,
3429
+ warnings: analysis.warnings,
3430
+ metadata: {
3431
+ handlerId,
3432
+ parserUsed: mergedOptions.language !== "en" ? "semantic" : "traditional",
3433
+ language: mergedOptions.language,
3434
+ commandsUsed: Array.from(analysis.commandsUsed),
3435
+ optimizationsApplied: optimized._optimizations ?? [],
3436
+ needsRuntime: allHelpers.size > 0,
3437
+ runtimeHelpers: Array.from(allHelpers)
3438
+ }
3439
+ };
3440
+ }
3441
+ /**
3442
+ * Compile a pre-parsed AST to JavaScript.
3443
+ * Skips parsing entirely — accepts an interchange-format ASTNode directly.
3444
+ * Use this when the AST has already been produced by a semantic parser,
3445
+ * explicit syntax parser, or other external source.
3446
+ */
3447
+ compileAST(ast, options = {}) {
3448
+ const mergedOptions = { ...DEFAULT_COMPILE_OPTIONS, ...options };
3449
+ let normalized = ast;
3450
+ if (normalized.type !== "event") {
3451
+ normalized = {
3452
+ type: "event",
3453
+ event: "click",
3454
+ modifiers: {},
3455
+ body: [normalized]
3456
+ };
3457
+ }
3458
+ const analysis = this.analyze(normalized);
3459
+ const optimized = this.optimizer.optimize(
3460
+ normalized,
3461
+ analysis,
3462
+ mergedOptions.optimizationLevel ?? 2
3463
+ );
3464
+ const sourceHint = JSON.stringify(ast).slice(0, 200);
3465
+ const handlerId = this.generateHandlerId(optimized, sourceHint);
3466
+ const ctx = this.createCodegenContext(handlerId, analysis, mergedOptions);
3467
+ const generated = this.generateCode(optimized, ctx, analysis);
3468
+ const allHelpers = /* @__PURE__ */ new Set([...ctx.requiredHelpers, ...generated.imports]);
3469
+ if (optimized.type === "event") {
3470
+ const eventNode = optimized;
3471
+ const bodyLen = eventNode.body?.length ?? 0;
3472
+ if (bodyLen > 0 && generated.code) {
3473
+ const handlerMatch = /function\s+_handler_\w+\(_event\)\s*\{([\s\S]*)\}\s*$/.exec(
3474
+ generated.code
3475
+ );
3476
+ if (handlerMatch) {
3477
+ const bodyContent = handlerMatch[1].replace(/const _ctx\s*=\s*[^;]*;/g, "").replace(/const _el\s*=\s*[^;]*;/g, "").trim();
3478
+ if (!bodyContent) {
3479
+ analysis.warnings.push(
3480
+ `Event handler body appears empty despite ${bodyLen} parsed command(s). This may indicate a code generation failure for pre-parsed AST.`
3481
+ );
3482
+ }
3483
+ }
3484
+ }
3485
+ }
3486
+ return {
3487
+ success: true,
3488
+ code: generated.code,
3489
+ warnings: analysis.warnings,
3490
+ metadata: {
3491
+ handlerId,
3492
+ parserUsed: "traditional",
3493
+ // pre-parsed, no parser involved
3494
+ language: mergedOptions.language,
3495
+ commandsUsed: Array.from(analysis.commandsUsed),
3496
+ optimizationsApplied: optimized._optimizations ?? [],
3497
+ needsRuntime: allHelpers.size > 0,
3498
+ runtimeHelpers: Array.from(allHelpers)
3499
+ }
3500
+ };
3501
+ }
3502
+ /**
3503
+ * Compile multiple extracted scripts.
3504
+ */
3505
+ compile(scripts, options = {}) {
3506
+ const handlers = [];
3507
+ const fallbacks = [];
3508
+ const allImports = /* @__PURE__ */ new Set();
3509
+ for (const script of scripts) {
3510
+ const scriptOptions = {
3511
+ ...options,
3512
+ language: script.language ?? options.language ?? "en"
3513
+ };
3514
+ const result = this.compileScript(script.code, scriptOptions);
3515
+ if (result.success && result.code) {
3516
+ handlers.push({
3517
+ id: result.metadata.handlerId,
3518
+ source: script.code,
3519
+ events: this.extractEvents(result.code),
3520
+ code: result.code,
3521
+ binding: {
3522
+ elementId: script.elementId,
3523
+ elementSelector: script.elementSelector
3524
+ }
3525
+ });
3526
+ for (const helper of result.metadata.runtimeHelpers) {
3527
+ allImports.add(helper);
3528
+ }
3529
+ } else {
3530
+ fallbacks.push({
3531
+ id: `fallback_${fallbacks.length}`,
3532
+ script: script.code,
3533
+ reason: result.errors?.join(", ") ?? "Unknown error",
3534
+ location: script.location
3535
+ });
3536
+ }
3537
+ }
3538
+ const combinedCode = this.generateCombinedCode(handlers, Array.from(allImports), options);
3539
+ return {
3540
+ handlers,
3541
+ code: combinedCode,
3542
+ fallbacks,
3543
+ stats: {
3544
+ total: scripts.length,
3545
+ compiled: handlers.length,
3546
+ fallbacks: fallbacks.length,
3547
+ totalSize: combinedCode.length,
3548
+ runtimeSize: this.estimateRuntimeSize(allImports)
3549
+ }
3550
+ };
3551
+ }
3552
+ // ===========================================================================
3553
+ // CODE GENERATION
3554
+ // ===========================================================================
3555
+ /**
3556
+ * Generate JavaScript code from an optimized AST.
3557
+ */
3558
+ generateCode(ast, ctx, analysis) {
3559
+ if (ast.type === "event") {
3560
+ const eventCodegen = new EventHandlerCodegen(ctx, analysis);
3561
+ const generated = eventCodegen.generate(ast);
3562
+ return {
3563
+ code: generated.handlerCode,
3564
+ imports: generated.imports
3565
+ };
3566
+ }
3567
+ const exprCodegen = new ExpressionCodegen(ctx);
3568
+ return {
3569
+ code: exprCodegen.generate(ast),
3570
+ imports: Array.from(ctx.requiredHelpers)
3571
+ };
3572
+ }
3573
+ /**
3574
+ * Generate combined code for multiple handlers.
3575
+ */
3576
+ generateCombinedCode(handlers, imports, options) {
3577
+ const codegenOptions = { ...DEFAULT_CODEGEN_OPTIONS, ...options.codegen };
3578
+ const lines = [];
3579
+ const allImports = [.../* @__PURE__ */ new Set([...imports, "ready"])];
3580
+ const importList = allImports.join(", ");
3581
+ if (codegenOptions.mode === "iife") {
3582
+ lines.push("(function() {");
3583
+ lines.push("var _ls = typeof lokascriptRuntime !== 'undefined' ? lokascriptRuntime : {};");
3584
+ lines.push("var _rt = { " + allImports.map((i) => `${i}: _ls.${i}`).join(", ") + " };");
3585
+ } else {
3586
+ if (codegenOptions.mode === "esm") {
3587
+ lines.push(`import { ${importList} } from '${codegenOptions.runtimeImport}';`);
3588
+ } else if (codegenOptions.mode === "cjs") {
3589
+ lines.push(`const { ${importList} } = require('${codegenOptions.runtimeImport}');`);
3590
+ }
3591
+ lines.push("const _rt = { " + allImports.map((i) => `${i}: ${i}`).join(", ") + " };");
3592
+ }
3593
+ lines.push("");
3594
+ for (const handler of handlers) {
3595
+ if (codegenOptions.preserveComments) {
3596
+ lines.push(`// Original: ${handler.source}`);
3597
+ }
3598
+ lines.push(handler.code);
3599
+ lines.push("");
3600
+ }
3601
+ lines.push("// Bind handlers to elements");
3602
+ lines.push("_rt.ready(() => {");
3603
+ for (const handler of handlers) {
3604
+ const selector = handler.binding.elementId ? `#${handler.binding.elementId}` : handler.binding.elementSelector ?? "[_]";
3605
+ for (const event of handler.events) {
3606
+ lines.push(` document.querySelectorAll('${selector}').forEach(_el => {`);
3607
+ lines.push(` _el.addEventListener('${event}', _handler_${handler.id});`);
3608
+ lines.push(" });");
3609
+ }
3610
+ }
3611
+ lines.push("});");
3612
+ if (codegenOptions.mode === "iife") {
3613
+ lines.push("})();");
3614
+ }
3615
+ return lines.join("\n");
3616
+ }
3617
+ // ===========================================================================
3618
+ // HELPERS
3619
+ // ===========================================================================
3620
+ /**
3621
+ * Generate a unique handler ID.
3622
+ */
3623
+ generateHandlerId(ast, code) {
3624
+ const event = ast.event ?? "handler";
3625
+ const body = ast.body ?? [];
3626
+ const firstCmd = body[0];
3627
+ const command = firstCmd?.name ?? "action";
3628
+ let hash = 5381;
3629
+ for (let i = 0; i < code.length; i++) {
3630
+ hash = (hash << 5) + hash ^ code.charCodeAt(i);
3631
+ }
3632
+ const hashStr = Math.abs(hash).toString(36).slice(0, 4);
3633
+ let id = `${event}_${command}_${hashStr}`;
3634
+ let suffix = 0;
3635
+ while (this.usedIds.has(id)) {
3636
+ id = `${event}_${command}_${hashStr}${suffix++}`;
3637
+ }
3638
+ this.usedIds.add(id);
3639
+ return id;
3640
+ }
3641
+ /**
3642
+ * Create a codegen context.
3643
+ */
3644
+ createCodegenContext(handlerId, analysis, options) {
3645
+ const selectorCache = /* @__PURE__ */ new Map();
3646
+ const requiredHelpers = /* @__PURE__ */ new Set();
3647
+ let idCounter = 0;
3648
+ for (const info of analysis.expressions.selectors) {
3649
+ if (info.canCache && info.usages.length > 1) {
3650
+ const cacheKey = "_sel_" + sanitizeIdentifier(info.selector).slice(0, 20) + "_" + idCounter++;
3651
+ selectorCache.set(info.selector, cacheKey);
3652
+ }
3653
+ }
3654
+ const exprCodegenRef = { current: null };
3655
+ const ctx = {
3656
+ handlerId,
3657
+ generateId: (prefix = "_id") => `${prefix}_${idCounter++}`,
3658
+ generateExpression: (node) => {
3659
+ if (!exprCodegenRef.current) {
3660
+ exprCodegenRef.current = new ExpressionCodegen(ctx);
3661
+ }
3662
+ return exprCodegenRef.current.generate(node);
3663
+ },
3664
+ implicitTarget: "_ctx.me",
3665
+ localVarDeclarations: "",
3666
+ canCacheSelector: (selector) => selectorCache.has(selector),
3667
+ getCachedSelector: (selector) => selectorCache.get(selector) ?? `document.querySelector('${selector}')`,
3668
+ requireHelper: (name) => {
3669
+ requiredHelpers.add(name);
3670
+ },
3671
+ requiredHelpers,
3672
+ analysis,
3673
+ options: { ...DEFAULT_CODEGEN_OPTIONS, ...options.codegen }
3674
+ };
3675
+ return ctx;
3676
+ }
3677
+ /**
3678
+ * Extract event names from generated code.
3679
+ */
3680
+ extractEvents(code) {
3681
+ const events = [];
3682
+ const match = /function\s+_handler_\w+\s*\(\s*_event\s*\)/.exec(code);
3683
+ if (match) {
3684
+ events.push("click");
3685
+ }
3686
+ return events.length > 0 ? events : ["click"];
3687
+ }
3688
+ /**
3689
+ * Estimate runtime size based on required helpers.
3690
+ */
3691
+ estimateRuntimeSize(imports) {
3692
+ const helperSizes = {
3693
+ createContext: 200,
3694
+ HALT: 50,
3695
+ EXIT: 50,
3696
+ globals: 100,
3697
+ toggle: 150,
3698
+ toggleAttr: 100,
3699
+ addClass: 80,
3700
+ removeClass: 80,
3701
+ getProp: 120,
3702
+ setProp: 120,
3703
+ getValues: 180,
3704
+ contains: 150,
3705
+ matches: 50,
3706
+ debounce: 150,
3707
+ throttle: 150,
3708
+ wait: 80,
3709
+ send: 150,
3710
+ delegate: 200,
3711
+ fetchJSON: 150,
3712
+ fetchText: 150,
3713
+ fetchHTML: 180,
3714
+ ready: 100
3715
+ };
3716
+ let total = 500;
3717
+ for (const helper of imports) {
3718
+ total += helperSizes[helper] ?? 100;
3719
+ }
3720
+ return total;
3721
+ }
3722
+ };
3723
+ function createCompiler() {
3724
+ return new AOTCompiler();
3725
+ }
3726
+ async function compileHyperscript(code, options) {
3727
+ const compiler = new AOTCompiler();
3728
+ const result = compiler.compileScript(code, options);
3729
+ if (!result.success) {
3730
+ throw new Error(result.errors?.join(", ") ?? "Compilation failed");
3731
+ }
3732
+ return result.code ?? "";
3733
+ }
3734
+ async function createMultilingualCompiler() {
3735
+ const compiler = new AOTCompiler();
3736
+ try {
3737
+ const { createCoreParserAdapter: createCoreParserAdapter2 } = await import("./core-parser-adapter-VCJB52SO-MDHRIVZ7.js");
3738
+ compiler.setParser(await createCoreParserAdapter2());
3739
+ } catch {
3740
+ }
3741
+ try {
3742
+ const { createSemanticAdapter: createSemanticAdapter2 } = await import("./semantic-adapter-7HTMTO75-MFFBR7K3.js");
3743
+ compiler.setSemanticParser(await createSemanticAdapter2());
3744
+ } catch {
3745
+ }
3746
+ return compiler;
3747
+ }
3748
+ var VERSION = "1.0.0";
3749
+ export {
3750
+ AOTCompiler,
3751
+ Analyzer,
3752
+ ConstantFoldingPass,
3753
+ CoreParserAdapter,
3754
+ DeadCodeEliminationPass,
3755
+ EventHandlerCodegen,
3756
+ ExpressionCodegen,
3757
+ HTMLScanner,
3758
+ JSXScanner,
3759
+ LoopUnrollingPass,
3760
+ OptimizationPipeline,
3761
+ SelectorCachingPass,
3762
+ SemanticParserAdapter,
3763
+ SvelteScanner,
3764
+ VERSION,
3765
+ VueScanner,
3766
+ analyze,
3767
+ commandCodegens,
3768
+ compileHyperscript,
3769
+ createCompiler,
3770
+ createCoreParserAdapter,
3771
+ createMultilingualCompiler,
3772
+ createOptimizer,
3773
+ createScanner,
3774
+ createSemanticAdapter,
3775
+ generateBindings,
3776
+ generateCommand,
3777
+ generateEventHandler,
3778
+ generateExpression,
3779
+ generateForEach,
3780
+ generateIf,
3781
+ generateInitialization,
3782
+ generateRepeat,
3783
+ generateWhile,
3784
+ optimize,
3785
+ sanitizeClassName,
3786
+ sanitizeIdentifier,
3787
+ sanitizeSelector,
3788
+ scanFiles
3789
+ };
3790
+ //# sourceMappingURL=dist-ICUX26U7.js.map