olova 2.0.60 → 2.0.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +42 -61
  3. package/dist/compiler.d.ts +44 -0
  4. package/dist/compiler.js +2139 -0
  5. package/dist/compiler.js.map +1 -0
  6. package/dist/core.d.ts +4 -0
  7. package/dist/core.js +859 -0
  8. package/dist/core.js.map +1 -0
  9. package/dist/global.d.ts +15 -0
  10. package/dist/global.js +226 -0
  11. package/dist/global.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +2268 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/runtime.d.ts +89 -0
  16. package/dist/runtime.js +633 -0
  17. package/dist/runtime.js.map +1 -0
  18. package/dist/signals-core-BdfWh1Yt.d.ts +43 -0
  19. package/dist/vite.d.ts +5 -0
  20. package/dist/vite.js +2268 -0
  21. package/dist/vite.js.map +1 -0
  22. package/package.json +83 -65
  23. package/dist/chunk-D7SIC5TC.js +0 -367
  24. package/dist/chunk-D7SIC5TC.js.map +0 -1
  25. package/dist/entry-server.cjs +0 -120
  26. package/dist/entry-server.cjs.map +0 -1
  27. package/dist/entry-server.js +0 -115
  28. package/dist/entry-server.js.map +0 -1
  29. package/dist/entry-worker.cjs +0 -133
  30. package/dist/entry-worker.cjs.map +0 -1
  31. package/dist/entry-worker.js +0 -127
  32. package/dist/entry-worker.js.map +0 -1
  33. package/dist/main.cjs +0 -18
  34. package/dist/main.cjs.map +0 -1
  35. package/dist/main.js +0 -16
  36. package/dist/main.js.map +0 -1
  37. package/dist/olova.cjs +0 -1680
  38. package/dist/olova.cjs.map +0 -1
  39. package/dist/olova.d.cts +0 -72
  40. package/dist/olova.d.ts +0 -72
  41. package/dist/olova.js +0 -1321
  42. package/dist/olova.js.map +0 -1
  43. package/dist/performance.cjs +0 -386
  44. package/dist/performance.cjs.map +0 -1
  45. package/dist/performance.js +0 -3
  46. package/dist/performance.js.map +0 -1
  47. package/dist/router.cjs +0 -646
  48. package/dist/router.cjs.map +0 -1
  49. package/dist/router.d.cts +0 -113
  50. package/dist/router.d.ts +0 -113
  51. package/dist/router.js +0 -632
  52. package/dist/router.js.map +0 -1
  53. package/main.tsx +0 -76
  54. package/olova.ts +0 -619
  55. package/src/entry-server.tsx +0 -165
  56. package/src/entry-worker.tsx +0 -201
  57. package/src/generator/index.ts +0 -409
  58. package/src/hydration/flight.ts +0 -320
  59. package/src/hydration/index.ts +0 -12
  60. package/src/hydration/types.ts +0 -225
  61. package/src/logger.ts +0 -182
  62. package/src/main.tsx +0 -24
  63. package/src/performance.ts +0 -488
  64. package/src/plugin/index.ts +0 -204
  65. package/src/router/ErrorBoundary.tsx +0 -145
  66. package/src/router/Link.tsx +0 -117
  67. package/src/router/OlovaRouter.tsx +0 -354
  68. package/src/router/Outlet.tsx +0 -8
  69. package/src/router/context.ts +0 -117
  70. package/src/router/index.ts +0 -29
  71. package/src/router/matching.ts +0 -63
  72. package/src/router/router.tsx +0 -23
  73. package/src/router/search-params.ts +0 -29
  74. package/src/scanner/index.ts +0 -114
  75. package/src/types/index.ts +0 -190
  76. package/src/utils/export.ts +0 -85
  77. package/src/utils/index.ts +0 -4
  78. package/src/utils/naming.ts +0 -54
  79. package/src/utils/path.ts +0 -45
  80. package/tsup.config.ts +0 -35
@@ -0,0 +1,2139 @@
1
+ import { parse } from '@babel/parser';
2
+ import generatorModule from '@babel/generator';
3
+ import traverseModule from '@babel/traverse';
4
+ import * as t from '@babel/types';
5
+ import ts from 'typescript';
6
+
7
+ // compiler/compile.ts
8
+
9
+ // compiler/parse.ts
10
+ function isWhitespace(char) {
11
+ return /\s/.test(char);
12
+ }
13
+ function skipQuoted(source, start, quote) {
14
+ let index = start + 1;
15
+ while (index < source.length) {
16
+ if (source[index] === "\\" && index + 1 < source.length) {
17
+ index += 2;
18
+ continue;
19
+ }
20
+ if (source[index] === quote) {
21
+ return index + 1;
22
+ }
23
+ index += 1;
24
+ }
25
+ return source.length;
26
+ }
27
+ function findTagEnd(source, start) {
28
+ let index = start;
29
+ while (index < source.length) {
30
+ const char = source[index];
31
+ if (char === '"' || char === "'") {
32
+ index = skipQuoted(source, index, char);
33
+ continue;
34
+ }
35
+ if (char === ">") {
36
+ return index;
37
+ }
38
+ index += 1;
39
+ }
40
+ return -1;
41
+ }
42
+ function parseAttributes(source) {
43
+ const attrs = {};
44
+ const attrRegex = /([:@A-Za-z_][-A-Za-z0-9_:.@]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g;
45
+ let match;
46
+ while ((match = attrRegex.exec(source)) !== null) {
47
+ const [, name, doubleQuoted, singleQuoted, bare] = match;
48
+ const value = doubleQuoted ?? singleQuoted ?? bare ?? true;
49
+ attrs[name] = value;
50
+ }
51
+ return attrs;
52
+ }
53
+ function readOpeningTag(source, start) {
54
+ if (source[start] !== "<") {
55
+ return null;
56
+ }
57
+ const tagEnd = findTagEnd(source, start + 1);
58
+ if (tagEnd < 0) {
59
+ return null;
60
+ }
61
+ const raw = source.slice(start + 1, tagEnd).trim();
62
+ if (!raw || raw.startsWith("/") || raw.startsWith("!")) {
63
+ return null;
64
+ }
65
+ let splitIndex = 0;
66
+ while (splitIndex < raw.length && !isWhitespace(raw[splitIndex]) && raw[splitIndex] !== "/") {
67
+ splitIndex += 1;
68
+ }
69
+ const tag = raw.slice(0, splitIndex);
70
+ const attrsSource = raw.slice(splitIndex).replace(/\/\s*$/, "").trim();
71
+ return {
72
+ tag,
73
+ openEnd: tagEnd + 1,
74
+ attrs: parseAttributes(attrsSource)
75
+ };
76
+ }
77
+ function findMatchingTag(source, start, tagName) {
78
+ const opening = readOpeningTag(source, start);
79
+ if (!opening || opening.tag.toLowerCase() !== tagName.toLowerCase()) {
80
+ return null;
81
+ }
82
+ const selfClosing = /\/\s*>$/.test(source.slice(start, opening.openEnd));
83
+ if (selfClosing) {
84
+ return {
85
+ fullStart: start,
86
+ openEnd: opening.openEnd,
87
+ closeStart: opening.openEnd,
88
+ closeEnd: opening.openEnd,
89
+ inner: "",
90
+ attrs: opening.attrs
91
+ };
92
+ }
93
+ let depth = 1;
94
+ let index = opening.openEnd;
95
+ while (index < source.length) {
96
+ const next = source.indexOf("<", index);
97
+ if (next < 0) {
98
+ break;
99
+ }
100
+ if (source.startsWith("<!--", next)) {
101
+ const commentEnd = source.indexOf("-->", next + 4);
102
+ index = commentEnd >= 0 ? commentEnd + 3 : source.length;
103
+ continue;
104
+ }
105
+ if (source[next + 1] === "/") {
106
+ const closeEnd = findTagEnd(source, next + 2);
107
+ if (closeEnd < 0) {
108
+ break;
109
+ }
110
+ const closeTag = source.slice(next + 2, closeEnd).trim();
111
+ if (closeTag.toLowerCase() === tagName.toLowerCase()) {
112
+ depth -= 1;
113
+ if (depth === 0) {
114
+ return {
115
+ fullStart: start,
116
+ openEnd: opening.openEnd,
117
+ closeStart: next,
118
+ closeEnd: closeEnd + 1,
119
+ inner: source.slice(opening.openEnd, next),
120
+ attrs: opening.attrs
121
+ };
122
+ }
123
+ }
124
+ index = closeEnd + 1;
125
+ continue;
126
+ }
127
+ const nested = readOpeningTag(source, next);
128
+ if (!nested) {
129
+ index = next + 1;
130
+ continue;
131
+ }
132
+ if (nested.tag.toLowerCase() === tagName.toLowerCase()) {
133
+ const nestedSelfClosing = /\/\s*>$/.test(source.slice(next, nested.openEnd));
134
+ if (!nestedSelfClosing) {
135
+ depth += 1;
136
+ }
137
+ }
138
+ index = nested.openEnd;
139
+ }
140
+ return null;
141
+ }
142
+ function collectTopLevelBlocks(source, tagName) {
143
+ const blocks = [];
144
+ let index = 0;
145
+ while (index < source.length) {
146
+ const next = source.indexOf(`<${tagName}`, index);
147
+ if (next < 0) {
148
+ break;
149
+ }
150
+ const previous = next > 0 ? source[next - 1] : "";
151
+ if (previous && /[A-Za-z0-9_:-]/.test(previous)) {
152
+ index = next + tagName.length + 1;
153
+ continue;
154
+ }
155
+ const block = findMatchingTag(source, next, tagName);
156
+ if (!block) {
157
+ index = next + tagName.length + 1;
158
+ continue;
159
+ }
160
+ blocks.push(block);
161
+ index = block.closeEnd;
162
+ }
163
+ return blocks;
164
+ }
165
+ function removeRanges(source, ranges) {
166
+ if (ranges.length === 0) {
167
+ return source.trim();
168
+ }
169
+ const ordered = [...ranges].sort((a, b) => a.start - b.start);
170
+ let cursor = 0;
171
+ let output = "";
172
+ for (const range of ordered) {
173
+ output += source.slice(cursor, range.start);
174
+ cursor = range.end;
175
+ }
176
+ output += source.slice(cursor);
177
+ return output.trim();
178
+ }
179
+ function parseOlovaFile(source) {
180
+ const scriptBlock = collectTopLevelBlocks(source, "script")[0] ?? null;
181
+ const styleBlocks = collectTopLevelBlocks(source, "style");
182
+ const ranges = styleBlocks.map((block) => ({
183
+ start: block.fullStart,
184
+ end: block.closeEnd
185
+ }));
186
+ if (scriptBlock) {
187
+ ranges.push({ start: scriptBlock.fullStart, end: scriptBlock.closeEnd });
188
+ }
189
+ return {
190
+ script: scriptBlock?.inner.trim() ?? "",
191
+ template: removeRanges(source, ranges),
192
+ styles: styleBlocks.map((block) => ({
193
+ content: block.inner.trim(),
194
+ attrs: block.attrs
195
+ }))
196
+ };
197
+ }
198
+
199
+ // compiler/html-parser.ts
200
+ function isWhitespace2(char) {
201
+ return /\s/.test(char);
202
+ }
203
+ function findTagEnd2(source, start) {
204
+ let index = start;
205
+ while (index < source.length) {
206
+ const char = source[index];
207
+ if (char === '"' || char === "'") {
208
+ const quoted = readQuotedValue(source, index, char);
209
+ index = quoted.end;
210
+ continue;
211
+ }
212
+ if (char === "{") {
213
+ const braced = readBraceValue(source, index);
214
+ index = braced.end;
215
+ continue;
216
+ }
217
+ if (char === ">") {
218
+ return index;
219
+ }
220
+ index += 1;
221
+ }
222
+ return -1;
223
+ }
224
+ function readQuotedValue(source, start, quote) {
225
+ let index = start + 1;
226
+ let value = "";
227
+ while (index < source.length) {
228
+ const char = source[index];
229
+ if (char === "\\" && index + 1 < source.length) {
230
+ value += source.slice(index, index + 2);
231
+ index += 2;
232
+ continue;
233
+ }
234
+ if (char === quote) {
235
+ return { value, end: index + 1 };
236
+ }
237
+ value += char;
238
+ index += 1;
239
+ }
240
+ return { value, end: source.length };
241
+ }
242
+ function readBraceValue(source, start) {
243
+ let index = start + 1;
244
+ let depth = 1;
245
+ let value = "{";
246
+ let quote = null;
247
+ while (index < source.length && depth > 0) {
248
+ const char = source[index];
249
+ const prev = source[index - 1];
250
+ value += char;
251
+ if (quote) {
252
+ if (char === quote && prev !== "\\") {
253
+ quote = null;
254
+ }
255
+ index += 1;
256
+ continue;
257
+ }
258
+ if (char === "'" || char === '"' || char === "`") {
259
+ quote = char;
260
+ index += 1;
261
+ continue;
262
+ }
263
+ if (char === "{") {
264
+ depth += 1;
265
+ } else if (char === "}") {
266
+ depth -= 1;
267
+ }
268
+ index += 1;
269
+ }
270
+ return { value, end: index };
271
+ }
272
+ function parseAttributes2(source) {
273
+ const attrs = {};
274
+ let index = 0;
275
+ while (index < source.length) {
276
+ while (index < source.length && isWhitespace2(source[index])) {
277
+ index += 1;
278
+ }
279
+ if (index >= source.length) {
280
+ break;
281
+ }
282
+ let nameEnd = index;
283
+ while (nameEnd < source.length && !isWhitespace2(source[nameEnd]) && source[nameEnd] !== "=") {
284
+ nameEnd += 1;
285
+ }
286
+ const name = source.slice(index, nameEnd).trim();
287
+ index = nameEnd;
288
+ if (!name) {
289
+ index += 1;
290
+ continue;
291
+ }
292
+ while (index < source.length && isWhitespace2(source[index])) {
293
+ index += 1;
294
+ }
295
+ if (source[index] !== "=") {
296
+ attrs[name] = true;
297
+ continue;
298
+ }
299
+ index += 1;
300
+ while (index < source.length && isWhitespace2(source[index])) {
301
+ index += 1;
302
+ }
303
+ if (index >= source.length) {
304
+ attrs[name] = true;
305
+ break;
306
+ }
307
+ const start = index;
308
+ const char = source[index];
309
+ if (char === '"' || char === "'") {
310
+ const quoted = readQuotedValue(source, index, char);
311
+ attrs[name] = quoted.value;
312
+ index = quoted.end;
313
+ continue;
314
+ }
315
+ if (char === "{") {
316
+ const braced = readBraceValue(source, index);
317
+ attrs[name] = braced.value;
318
+ index = braced.end;
319
+ continue;
320
+ }
321
+ while (index < source.length && !isWhitespace2(source[index])) {
322
+ index += 1;
323
+ }
324
+ attrs[name] = source.slice(start, index);
325
+ }
326
+ return attrs;
327
+ }
328
+ function parseHTML(html) {
329
+ const root = [];
330
+ const stack = [
331
+ { node: null, children: root }
332
+ ];
333
+ let i = 0;
334
+ while (i < html.length) {
335
+ const textStart = i;
336
+ const tagStart = html.indexOf("<", i);
337
+ if (tagStart === -1) {
338
+ if (textStart < html.length) {
339
+ stack[stack.length - 1].children.push({
340
+ type: "text",
341
+ content: html.slice(textStart)
342
+ });
343
+ }
344
+ break;
345
+ }
346
+ if (tagStart > textStart) {
347
+ stack[stack.length - 1].children.push({
348
+ type: "text",
349
+ content: html.slice(textStart, tagStart)
350
+ });
351
+ }
352
+ i = tagStart;
353
+ if (html.startsWith("<!--", i)) {
354
+ const commentEnd = html.indexOf("-->", i + 4);
355
+ if (commentEnd === -1) {
356
+ stack[stack.length - 1].children.push({
357
+ type: "comment",
358
+ content: html.slice(i + 4)
359
+ });
360
+ break;
361
+ }
362
+ stack[stack.length - 1].children.push({
363
+ type: "comment",
364
+ content: html.slice(i + 4, commentEnd)
365
+ });
366
+ i = commentEnd + 3;
367
+ continue;
368
+ }
369
+ if (html.startsWith("</", i)) {
370
+ const tagEnd2 = html.indexOf(">", i + 2);
371
+ if (tagEnd2 === -1) {
372
+ i += 2;
373
+ continue;
374
+ }
375
+ const tag2 = html.slice(i + 2, tagEnd2).trim().toLowerCase();
376
+ let closeIdx = stack.length - 1;
377
+ while (closeIdx > 0 && stack[closeIdx].node?.tag.toLowerCase() !== tag2) {
378
+ closeIdx--;
379
+ }
380
+ if (closeIdx > 0) {
381
+ stack.length = closeIdx;
382
+ }
383
+ i = tagEnd2 + 1;
384
+ continue;
385
+ }
386
+ const tagEnd = findTagEnd2(html, i + 1);
387
+ if (tagEnd === -1) {
388
+ stack[stack.length - 1].children.push({ type: "text", content: "<" });
389
+ i++;
390
+ continue;
391
+ }
392
+ const rawTag = html.slice(i + 1, tagEnd).trim();
393
+ let tagNameEnd = 0;
394
+ while (tagNameEnd < rawTag.length && !isWhitespace2(rawTag[tagNameEnd]) && rawTag[tagNameEnd] !== "/") {
395
+ tagNameEnd += 1;
396
+ }
397
+ const tag = rawTag.slice(0, tagNameEnd);
398
+ if (!tag) {
399
+ stack[stack.length - 1].children.push({ type: "text", content: "<" });
400
+ i++;
401
+ continue;
402
+ }
403
+ const attrsStr = rawTag.slice(tagNameEnd).replace(/\/\s*$/, "").trim();
404
+ const selfClose = /\/\s*$/.test(rawTag);
405
+ const attrs = parseAttributes2(attrsStr);
406
+ const isSelfClosing = !!selfClose || /^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/i.test(
407
+ tag
408
+ );
409
+ const element = {
410
+ type: "element",
411
+ tag,
412
+ attrs,
413
+ children: [],
414
+ isSelfClosing
415
+ };
416
+ stack[stack.length - 1].children.push(element);
417
+ if (!isSelfClosing) {
418
+ stack.push({ node: element, children: element.children });
419
+ }
420
+ i = tagEnd + 1;
421
+ }
422
+ return root;
423
+ }
424
+
425
+ // compiler/dom-generator.ts
426
+ var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
427
+ function splitTextFragments(text) {
428
+ const parts = [];
429
+ const tokenRe = /__O_(TEXT|HTML|SLOT|COMP|IF)_([a-zA-Z0-9_]+)__/g;
430
+ let lastIndex = 0;
431
+ let match;
432
+ while ((match = tokenRe.exec(text)) !== null) {
433
+ if (match.index > lastIndex) {
434
+ parts.push({ type: "static", value: text.slice(lastIndex, match.index) });
435
+ }
436
+ parts.push({ type: "dynamic", tokenType: match[1], id: match[2] });
437
+ lastIndex = match.index + match[0].length;
438
+ }
439
+ if (lastIndex < text.length) {
440
+ parts.push({ type: "static", value: text.slice(lastIndex) });
441
+ }
442
+ return parts;
443
+ }
444
+ function isSvgContext(tag, inSvg) {
445
+ if (tag === "foreignObject") {
446
+ return false;
447
+ }
448
+ return inSvg || tag === "svg";
449
+ }
450
+ function processNode(node, parentVar, stateNames, transformExpr, counters, buildCtx, componentNames, inSvg = false) {
451
+ if (node.type === "comment") {
452
+ return;
453
+ }
454
+ if (node.type === "text") {
455
+ const parts = splitTextFragments(node.content);
456
+ for (const part of parts) {
457
+ if (part.type === "static") {
458
+ if (!part.value) continue;
459
+ const varName = `_t${buildCtx.localCount++}`;
460
+ buildCtx.statements.push(
461
+ `const ${varName} = document.createTextNode(${JSON.stringify(part.value)});`
462
+ );
463
+ buildCtx.statements.push(`${parentVar}.appendChild(${varName});`);
464
+ } else {
465
+ const varName = `_d${buildCtx.localCount++}`;
466
+ buildCtx.statements.push(
467
+ `const ${varName} = document.createTextNode('');`
468
+ );
469
+ buildCtx.nodes.push(`'${part.id}': ${varName}`);
470
+ buildCtx.statements.push(`${parentVar}.appendChild(${varName});`);
471
+ }
472
+ }
473
+ return;
474
+ }
475
+ if (node.type === "element") {
476
+ const tag = node.tag;
477
+ const varName = `_el${buildCtx.localCount++}`;
478
+ const useSvgNamespace = isSvgContext(tag, inSvg);
479
+ buildCtx.statements.push(
480
+ useSvgNamespace ? `const ${varName} = document.createElementNS(${JSON.stringify(SVG_NAMESPACE)}, "${tag}");` : `const ${varName} = document.createElement("${tag}");`
481
+ );
482
+ for (const [attr, val] of Object.entries(node.attrs)) {
483
+ if (attr.startsWith("data-o-on-")) {
484
+ if (typeof val === "string") {
485
+ buildCtx.nodes.push(`'${val}': ${varName}`);
486
+ }
487
+ } else if (typeof val === "string" && val.includes("__O_ATTR_")) {
488
+ const match = val.match(/__O_ATTR_([a-zA-Z0-9_]+)__/);
489
+ if (match) {
490
+ buildCtx.nodes.push(`'${match[1]}': ${varName}`);
491
+ }
492
+ } else {
493
+ if (val === true) {
494
+ buildCtx.statements.push(`${varName}.setAttribute("${attr}", "");`);
495
+ } else {
496
+ buildCtx.statements.push(
497
+ `${varName}.setAttribute("${attr}", ${JSON.stringify(val)});`
498
+ );
499
+ }
500
+ }
501
+ }
502
+ for (const child of node.children) {
503
+ processNode(
504
+ child,
505
+ varName,
506
+ stateNames,
507
+ transformExpr,
508
+ counters,
509
+ buildCtx,
510
+ componentNames,
511
+ useSvgNamespace
512
+ );
513
+ }
514
+ buildCtx.statements.push(`${parentVar}.appendChild(${varName});`);
515
+ }
516
+ }
517
+ function generateBuildFunction(html, stateNames, transformExpr, counters, componentNames) {
518
+ const ast = parseHTML(html);
519
+ const buildCtx = {
520
+ statements: [],
521
+ nodes: [],
522
+ localCount: 0
523
+ };
524
+ buildCtx.statements.push("const _f = document.createDocumentFragment();");
525
+ for (const child of ast) {
526
+ processNode(
527
+ child,
528
+ "_f",
529
+ stateNames,
530
+ transformExpr,
531
+ counters,
532
+ buildCtx,
533
+ componentNames
534
+ );
535
+ }
536
+ return `function() {
537
+ ${buildCtx.statements.join("\n ")}
538
+ return { fragment: _f, nodes: { ${buildCtx.nodes.join(", ")} } };
539
+ }`;
540
+ }
541
+
542
+ // compiler/compile.ts
543
+ var generate = generatorModule.default ?? generatorModule;
544
+ var traverse = traverseModule.default ?? traverseModule;
545
+ var CORE_KNOWN_IMPORTS = /* @__PURE__ */ new Set([
546
+ "Signal",
547
+ "computed",
548
+ "createApp",
549
+ "defineComponent",
550
+ "derived",
551
+ "effect",
552
+ "getContext",
553
+ "global",
554
+ "hasContext",
555
+ "mount",
556
+ "setContext",
557
+ "state"
558
+ ]);
559
+ function escapeTemplate(source) {
560
+ return source.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
561
+ }
562
+ function indexToLocation(source, index) {
563
+ const safeIndex = Math.max(0, Math.min(index, source.length));
564
+ const lines = source.slice(0, safeIndex).split("\n");
565
+ return {
566
+ line: lines.length,
567
+ column: lines[lines.length - 1]?.length ?? 0,
568
+ index: safeIndex
569
+ };
570
+ }
571
+ function createCodeFrame(source, line, column, contextLines = 2) {
572
+ const lines = source.split("\n");
573
+ const start = Math.max(0, line - 1 - contextLines);
574
+ const end = Math.min(lines.length, line + contextLines);
575
+ return lines.slice(start, end).map((content, offset) => {
576
+ const lineNumber = start + offset + 1;
577
+ const prefix = `${String(lineNumber).padStart(4, " ")} | `;
578
+ if (lineNumber !== line) {
579
+ return `${prefix}${content}`;
580
+ }
581
+ return `${prefix}${content}
582
+ | ${" ".repeat(Math.max(column, 0))}^`;
583
+ }).join("\n");
584
+ }
585
+ function createCompileError(message, source, index) {
586
+ const loc = indexToLocation(source, index);
587
+ const error = new Error(message);
588
+ error.loc = { start: loc };
589
+ error.frame = createCodeFrame(source, loc.line, loc.column);
590
+ return error;
591
+ }
592
+ function normalizeCompileError(error, source, filename = "component.olova") {
593
+ const compileError = error instanceof Error ? error : new Error(String(error));
594
+ const start = compileError.loc?.start ?? compileError.loc;
595
+ const line = start?.line;
596
+ const column = start?.column;
597
+ const locationSuffix = line === void 0 || column === void 0 ? "" : ` (${filename}:${line}:${column + 1})`;
598
+ compileError.message = `[olova] ${compileError.message.replace(/^\[olova\]\s*/, "")}${locationSuffix}`;
599
+ if (line !== void 0 && column !== void 0 && !compileError.frame) {
600
+ compileError.frame = createCodeFrame(source, line, column);
601
+ }
602
+ throw compileError;
603
+ }
604
+ function parseModule(code) {
605
+ return parse(code, {
606
+ sourceType: "module",
607
+ plugins: ["typescript", "jsx"]
608
+ });
609
+ }
610
+ function transpileTypeScript(code, filename = "component.ts") {
611
+ const result = ts.transpileModule(code, {
612
+ fileName: filename,
613
+ compilerOptions: {
614
+ target: ts.ScriptTarget.ES2022,
615
+ module: ts.ModuleKind.ESNext,
616
+ jsx: ts.JsxEmit.Preserve,
617
+ importsNotUsedAsValues: ts.ImportsNotUsedAsValues.Remove,
618
+ verbatimModuleSyntax: false,
619
+ sourceMap: true,
620
+ inlineSources: true
621
+ }
622
+ });
623
+ return {
624
+ code: result.outputText.trim(),
625
+ map: result.sourceMapText ? JSON.parse(result.sourceMapText) : null
626
+ };
627
+ }
628
+ function compileModuleScript(script, filename = "module.olova.ts") {
629
+ const ast = parseModule(script || "");
630
+ return transpileTypeScript(
631
+ ast.program.body.map((node) => generate(node).code).join("\n"),
632
+ filename
633
+ );
634
+ }
635
+ function isModuleOnlyScript(script) {
636
+ if (!script.trim()) {
637
+ return false;
638
+ }
639
+ const ast = parseModule(script);
640
+ return ast.program.body.every(
641
+ (node) => t.isImportDeclaration(node) || t.isExportNamedDeclaration(node) || t.isExportAllDeclaration(node) || t.isExportDefaultDeclaration(node)
642
+ );
643
+ }
644
+ function isStateInit(node) {
645
+ return !!(node && t.isCallExpression(node) && (t.isIdentifier(node.callee) && node.callee.name === "state" || t.isMemberExpression(node.callee) && t.isIdentifier(node.callee.object) && node.callee.object.name === "__olovaGlobal" && t.isIdentifier(node.callee.property) && (node.callee.property.name === "state" || node.callee.property.name === "get")));
646
+ }
647
+ function isComputedInit(node) {
648
+ return !!(node && t.isCallExpression(node) && t.isIdentifier(node.callee) && (node.callee.name === "computed" || node.callee.name === "derived"));
649
+ }
650
+ function appendHmrStateKey(node, key) {
651
+ if (!node) {
652
+ return;
653
+ }
654
+ if (t.isCallExpression(node) && t.isIdentifier(node.callee) && node.callee.name === "state") {
655
+ const existingKey = node.arguments[1];
656
+ if (!existingKey || !t.isStringLiteral(existingKey)) {
657
+ node.arguments = [node.arguments[0] ?? t.identifier("undefined"), t.stringLiteral(key)];
658
+ }
659
+ return;
660
+ }
661
+ if (t.isConditionalExpression(node)) {
662
+ appendHmrStateKey(node.consequent, `${key}:then`);
663
+ appendHmrStateKey(node.alternate, `${key}:else`);
664
+ return;
665
+ }
666
+ if (t.isLogicalExpression(node)) {
667
+ appendHmrStateKey(node.left, `${key}:left`);
668
+ appendHmrStateKey(node.right, `${key}:right`);
669
+ }
670
+ }
671
+ function containsStateInit(node) {
672
+ if (!node) {
673
+ return false;
674
+ }
675
+ if (isStateInit(node)) {
676
+ return true;
677
+ }
678
+ if (t.isConditionalExpression(node)) {
679
+ return containsStateInit(node.consequent) || containsStateInit(node.alternate);
680
+ }
681
+ if (t.isLogicalExpression(node)) {
682
+ return containsStateInit(node.left) || containsStateInit(node.right);
683
+ }
684
+ return false;
685
+ }
686
+ function containsSignalInit(node) {
687
+ if (!node) {
688
+ return false;
689
+ }
690
+ if (isStateInit(node) || isComputedInit(node)) {
691
+ return true;
692
+ }
693
+ if (t.isConditionalExpression(node)) {
694
+ return containsSignalInit(node.consequent) || containsSignalInit(node.alternate);
695
+ }
696
+ if (t.isLogicalExpression(node)) {
697
+ return containsSignalInit(node.left) || containsSignalInit(node.right);
698
+ }
699
+ return false;
700
+ }
701
+ function isGlobalStateCall(node) {
702
+ return t.isMemberExpression(node.callee) && t.isIdentifier(node.callee.object) && (node.callee.object.name === "global" || node.callee.object.name === "__olovaGlobal") && t.isIdentifier(node.callee.property) && node.callee.property.name === "state";
703
+ }
704
+ function shouldSkipIdentifierTransform(path) {
705
+ if (path.parentPath?.isVariableDeclarator() && path.parentPath.node.id === path.node) {
706
+ return true;
707
+ }
708
+ if (path.parentPath?.isAssignmentExpression() && path.parentPath.node.left === path.node) {
709
+ return true;
710
+ }
711
+ if (path.parentPath?.isUpdateExpression()) {
712
+ return true;
713
+ }
714
+ if (path.parentPath?.isCallExpression() && t.isIdentifier(path.parentPath.node.callee) && path.parentPath.node.callee.name === "setContext" && path.parentPath.node.arguments.includes(path.node)) {
715
+ return true;
716
+ }
717
+ if (path.parentPath?.isMemberExpression() && path.parentPath.node.property === path.node && !path.parentPath.node.computed) {
718
+ return true;
719
+ }
720
+ if (path.parentPath?.isMemberExpression() && path.parentPath.node.object === path.node && t.isIdentifier(path.parentPath.node.property) && (path.parentPath.node.property.name === "value" || path.parentPath.node.property.name === "notify")) {
721
+ return true;
722
+ }
723
+ if (path.parentPath?.isImportSpecifier() || path.parentPath?.isExportSpecifier()) {
724
+ return true;
725
+ }
726
+ if (path.parentPath?.isObjectProperty() && path.parentPath.node.key === path.node && !path.parentPath.node.computed && !path.parentPath.node.shorthand) {
727
+ return true;
728
+ }
729
+ if (path.parentPath?.isFunctionDeclaration() && path.parentPath.node.id === path.node) {
730
+ return true;
731
+ }
732
+ if (path.parentPath?.isClassDeclaration() && path.parentPath.node.id === path.node) {
733
+ return true;
734
+ }
735
+ return false;
736
+ }
737
+ function addNestedMutationNotify(ast, stateNames) {
738
+ traverse(ast, {
739
+ AssignmentExpression(path) {
740
+ const left = path.node.left;
741
+ if (!t.isMemberExpression(left)) {
742
+ return;
743
+ }
744
+ let root = left;
745
+ while (t.isMemberExpression(root.object)) {
746
+ root = root.object;
747
+ }
748
+ if (!t.isIdentifier(root.object)) {
749
+ return;
750
+ }
751
+ if (!t.isIdentifier(root.property) || root.property.name !== "value") {
752
+ return;
753
+ }
754
+ const stateName = root.object.name;
755
+ if (!stateNames.has(stateName)) {
756
+ return;
757
+ }
758
+ if (left === root) {
759
+ return;
760
+ }
761
+ if (path.parentPath?.isSequenceExpression()) {
762
+ return;
763
+ }
764
+ path.replaceWith(
765
+ t.sequenceExpression([
766
+ path.node,
767
+ t.callExpression(
768
+ t.memberExpression(t.identifier(stateName), t.identifier("notify")),
769
+ []
770
+ )
771
+ ])
772
+ );
773
+ path.skip();
774
+ }
775
+ });
776
+ }
777
+ function collectScriptInfo(script) {
778
+ const ast = parseModule(script || "");
779
+ const stateNames = /* @__PURE__ */ new Set();
780
+ const allSignalNames = /* @__PURE__ */ new Set();
781
+ const componentNames = /* @__PURE__ */ new Set();
782
+ const jsxFunctionNames = /* @__PURE__ */ new Set();
783
+ let needsGlobalRuntime = false;
784
+ for (const node of ast.program.body) {
785
+ if (!t.isImportDeclaration(node)) {
786
+ continue;
787
+ }
788
+ for (const specifier of node.specifiers) {
789
+ componentNames.add(specifier.local.name);
790
+ }
791
+ }
792
+ const rewrittenBody = [];
793
+ for (const node of ast.program.body) {
794
+ if (t.isImportDeclaration(node) && t.isStringLiteral(node.source) && (node.source.value === "olova/global" || node.source.value === "olova/core")) {
795
+ if (node.source.value === "olova/global") {
796
+ needsGlobalRuntime = true;
797
+ const declarators = [];
798
+ for (const specifier of node.specifiers) {
799
+ if (!t.isImportSpecifier(specifier)) {
800
+ throw new Error(
801
+ "[olova] Use named imports with 'olova/global' (e.g. import { user } from 'olova/global')."
802
+ );
803
+ }
804
+ const imported = t.isIdentifier(specifier.imported) ? specifier.imported.name : specifier.imported.value;
805
+ declarators.push(
806
+ t.variableDeclarator(
807
+ t.identifier(specifier.local.name),
808
+ t.callExpression(
809
+ t.memberExpression(
810
+ t.identifier("__olovaGlobal"),
811
+ t.identifier("get")
812
+ ),
813
+ [t.stringLiteral(imported)]
814
+ )
815
+ )
816
+ );
817
+ }
818
+ if (declarators.length > 0) {
819
+ rewrittenBody.push(t.variableDeclaration("const", declarators));
820
+ }
821
+ continue;
822
+ }
823
+ const keptSpecifiers = [];
824
+ const globalDeclarators = [];
825
+ for (const specifier of node.specifiers) {
826
+ if (!t.isImportSpecifier(specifier)) {
827
+ keptSpecifiers.push(specifier);
828
+ continue;
829
+ }
830
+ const imported = t.isIdentifier(specifier.imported) ? specifier.imported.name : specifier.imported.value;
831
+ if (CORE_KNOWN_IMPORTS.has(imported)) {
832
+ keptSpecifiers.push(specifier);
833
+ continue;
834
+ }
835
+ needsGlobalRuntime = true;
836
+ globalDeclarators.push(
837
+ t.variableDeclarator(
838
+ t.identifier(specifier.local.name),
839
+ t.callExpression(
840
+ t.memberExpression(
841
+ t.identifier("__olovaGlobal"),
842
+ t.identifier("get")
843
+ ),
844
+ [t.stringLiteral(imported)]
845
+ )
846
+ )
847
+ );
848
+ }
849
+ if (keptSpecifiers.length > 0) {
850
+ rewrittenBody.push(
851
+ t.importDeclaration(keptSpecifiers, t.stringLiteral("olova/core"))
852
+ );
853
+ }
854
+ if (globalDeclarators.length > 0) {
855
+ rewrittenBody.push(t.variableDeclaration("const", globalDeclarators));
856
+ }
857
+ continue;
858
+ }
859
+ rewrittenBody.push(node);
860
+ }
861
+ ast.program.body = rewrittenBody;
862
+ traverse(ast, {
863
+ CallExpression(path) {
864
+ if (!isGlobalStateCall(path.node)) {
865
+ return;
866
+ }
867
+ needsGlobalRuntime = true;
868
+ path.node.callee = t.memberExpression(
869
+ t.identifier("__olovaGlobal"),
870
+ t.identifier("state")
871
+ );
872
+ if (path.parentPath && path.parentPath.isVariableDeclarator() && t.isIdentifier(path.parentPath.node.id)) {
873
+ const firstArg = path.node.arguments[0];
874
+ const alreadyNamed = !!firstArg && t.isStringLiteral(firstArg) && firstArg.value.length > 0;
875
+ if (!alreadyNamed) {
876
+ path.node.arguments = [
877
+ t.stringLiteral(path.parentPath.node.id.name),
878
+ ...path.node.arguments
879
+ ];
880
+ }
881
+ }
882
+ }
883
+ });
884
+ traverse(ast, {
885
+ VariableDeclarator(path) {
886
+ if (!t.isIdentifier(path.node.id)) {
887
+ return;
888
+ }
889
+ if (containsStateInit(path.node.init)) {
890
+ stateNames.add(path.node.id.name);
891
+ appendHmrStateKey(path.node.init, path.node.id.name);
892
+ }
893
+ if (containsSignalInit(path.node.init)) {
894
+ allSignalNames.add(path.node.id.name);
895
+ }
896
+ }
897
+ });
898
+ traverse(ast, {
899
+ AssignmentExpression(path) {
900
+ if (!t.isIdentifier(path.node.left)) {
901
+ return;
902
+ }
903
+ const name = path.node.left.name;
904
+ if (!stateNames.has(name)) {
905
+ return;
906
+ }
907
+ const binding = path.scope.getBinding(name);
908
+ if (!binding || !t.isVariableDeclarator(binding.path.node)) {
909
+ return;
910
+ }
911
+ if (!t.isIdentifier(binding.path.node.id) || !containsStateInit(binding.path.node.init)) {
912
+ return;
913
+ }
914
+ path.node.left = t.memberExpression(
915
+ t.identifier(name),
916
+ t.identifier("value")
917
+ );
918
+ },
919
+ UpdateExpression(path) {
920
+ if (!t.isIdentifier(path.node.argument)) {
921
+ return;
922
+ }
923
+ const name = path.node.argument.name;
924
+ if (!stateNames.has(name)) {
925
+ return;
926
+ }
927
+ const binding = path.scope.getBinding(name);
928
+ if (!binding || !t.isVariableDeclarator(binding.path.node)) {
929
+ return;
930
+ }
931
+ if (!t.isIdentifier(binding.path.node.id) || !containsStateInit(binding.path.node.init)) {
932
+ return;
933
+ }
934
+ path.node.argument = t.memberExpression(
935
+ t.identifier(name),
936
+ t.identifier("value")
937
+ );
938
+ }
939
+ });
940
+ traverse(ast, {
941
+ Identifier(path) {
942
+ const name = path.node.name;
943
+ if (!allSignalNames.has(name)) {
944
+ return;
945
+ }
946
+ if (shouldSkipIdentifierTransform(path)) {
947
+ return;
948
+ }
949
+ const binding = path.scope.getBinding(name);
950
+ if (!binding || !t.isVariableDeclarator(binding.path.node)) {
951
+ return;
952
+ }
953
+ if (!t.isIdentifier(binding.path.node.id) || !containsSignalInit(binding.path.node.init)) {
954
+ return;
955
+ }
956
+ path.replaceWith(
957
+ t.memberExpression(t.identifier(name), t.identifier("value"))
958
+ );
959
+ path.skip();
960
+ }
961
+ });
962
+ addNestedMutationNotify(ast, stateNames);
963
+ const nodeContainsJsx = (node) => {
964
+ if (!node) {
965
+ return false;
966
+ }
967
+ let found = false;
968
+ traverse(parseModule(`(${generate(node).code})`), {
969
+ JSXElement() {
970
+ found = true;
971
+ },
972
+ JSXFragment() {
973
+ found = true;
974
+ }
975
+ });
976
+ return found;
977
+ };
978
+ traverse(ast, {
979
+ FunctionDeclaration(path) {
980
+ if (path.node.id && nodeContainsJsx(path.node.body)) {
981
+ jsxFunctionNames.add(path.node.id.name);
982
+ }
983
+ },
984
+ VariableDeclarator(path) {
985
+ if (t.isIdentifier(path.node.id) && nodeContainsJsx(path.node.init)) {
986
+ jsxFunctionNames.add(path.node.id.name);
987
+ }
988
+ }
989
+ });
990
+ traverse(ast, {
991
+ JSXElement(path) {
992
+ const transformed = transformExpression(
993
+ generate(path.node).code,
994
+ stateNames,
995
+ allSignalNames,
996
+ jsxFunctionNames
997
+ );
998
+ const parsed = parseModule(`(${transformed.code})`);
999
+ const statement = parsed.program.body[0];
1000
+ if (statement && t.isExpressionStatement(statement)) {
1001
+ path.replaceWith(statement.expression);
1002
+ path.skip();
1003
+ }
1004
+ },
1005
+ JSXFragment(path) {
1006
+ const transformed = transformExpression(
1007
+ generate(path.node).code,
1008
+ stateNames,
1009
+ allSignalNames,
1010
+ jsxFunctionNames
1011
+ );
1012
+ const parsed = parseModule(`(${transformed.code})`);
1013
+ const statement = parsed.program.body[0];
1014
+ if (statement && t.isExpressionStatement(statement)) {
1015
+ path.replaceWith(statement.expression);
1016
+ path.skip();
1017
+ }
1018
+ }
1019
+ });
1020
+ if (needsGlobalRuntime) {
1021
+ ast.program.body.unshift(
1022
+ t.importDeclaration(
1023
+ [
1024
+ t.importSpecifier(
1025
+ t.identifier("__olovaGlobal"),
1026
+ t.identifier("global")
1027
+ )
1028
+ ],
1029
+ t.stringLiteral("olova/global")
1030
+ )
1031
+ );
1032
+ }
1033
+ const importNodes = ast.program.body.filter(
1034
+ (node) => t.isImportDeclaration(node)
1035
+ );
1036
+ const bodyNodes = ast.program.body.filter(
1037
+ (node) => !t.isImportDeclaration(node)
1038
+ );
1039
+ const importsCode = importNodes.map((node) => generate(node).code).join("\n");
1040
+ const scriptBodyCode = bodyNodes.map((node) => generate(node).code).join("\n");
1041
+ return {
1042
+ importsCode,
1043
+ scriptBodyCode,
1044
+ stateNames,
1045
+ allSignalNames,
1046
+ componentNames,
1047
+ jsxFunctionNames
1048
+ };
1049
+ }
1050
+ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames = /* @__PURE__ */ new Set(), scopeId) {
1051
+ const ast = parseModule(`(${expr})`);
1052
+ let containsJsx = false;
1053
+ const jsxScopeAttr = createScopeAttr(scopeId);
1054
+ traverse(ast, {
1055
+ AssignmentExpression(path) {
1056
+ if (!t.isIdentifier(path.node.left)) {
1057
+ return;
1058
+ }
1059
+ const name = path.node.left.name;
1060
+ if (!stateNames.has(name)) {
1061
+ return;
1062
+ }
1063
+ const binding = path.scope.getBinding(name);
1064
+ if (binding) {
1065
+ return;
1066
+ }
1067
+ path.node.left = t.memberExpression(
1068
+ t.identifier(name),
1069
+ t.identifier("value")
1070
+ );
1071
+ },
1072
+ UpdateExpression(path) {
1073
+ if (!t.isIdentifier(path.node.argument)) {
1074
+ return;
1075
+ }
1076
+ const name = path.node.argument.name;
1077
+ if (!stateNames.has(name)) {
1078
+ return;
1079
+ }
1080
+ const binding = path.scope.getBinding(name);
1081
+ if (binding) {
1082
+ return;
1083
+ }
1084
+ path.node.argument = t.memberExpression(
1085
+ t.identifier(name),
1086
+ t.identifier("value")
1087
+ );
1088
+ }
1089
+ });
1090
+ traverse(ast, {
1091
+ Identifier(path) {
1092
+ const name = path.node.name;
1093
+ if (!allSignalNames.has(name)) {
1094
+ return;
1095
+ }
1096
+ if (shouldSkipIdentifierTransform(path)) {
1097
+ return;
1098
+ }
1099
+ const binding = path.scope.getBinding(name);
1100
+ if (binding) {
1101
+ return;
1102
+ }
1103
+ path.replaceWith(
1104
+ t.memberExpression(t.identifier(name), t.identifier("value"))
1105
+ );
1106
+ path.skip();
1107
+ }
1108
+ });
1109
+ addNestedMutationNotify(ast, stateNames);
1110
+ const toStringCall = (input) => t.callExpression(t.identifier("__olovaToString"), [input]);
1111
+ const escapeCall = (input) => t.callExpression(t.identifier("__olovaEscape"), [input]);
1112
+ const expressionContainsJsx = (input) => {
1113
+ let found = false;
1114
+ traverse(parseModule(`(${generate(input).code})`), {
1115
+ JSXElement() {
1116
+ found = true;
1117
+ },
1118
+ JSXFragment() {
1119
+ found = true;
1120
+ }
1121
+ });
1122
+ return found;
1123
+ };
1124
+ const expressionProducesHtml = (input) => {
1125
+ if (!input) {
1126
+ return false;
1127
+ }
1128
+ if (expressionContainsJsx(input)) {
1129
+ return true;
1130
+ }
1131
+ let found = false;
1132
+ traverse(parseModule(`(${generate(input).code})`), {
1133
+ CallExpression(path) {
1134
+ if (t.isIdentifier(path.node.callee) && jsxFunctionNames.has(path.node.callee.name)) {
1135
+ found = true;
1136
+ path.stop();
1137
+ return;
1138
+ }
1139
+ if (t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.property) && (path.node.callee.property.name === "map" || path.node.callee.property.name === "flatMap")) {
1140
+ const [firstArg] = path.node.arguments;
1141
+ if (t.isIdentifier(firstArg) && jsxFunctionNames.has(firstArg.name) || nodeContainsRenderableFunction(firstArg, jsxFunctionNames)) {
1142
+ found = true;
1143
+ path.stop();
1144
+ }
1145
+ }
1146
+ }
1147
+ });
1148
+ return found;
1149
+ };
1150
+ const nodeContainsRenderableFunction = (node, knownJsxFunctions) => {
1151
+ if (!node) {
1152
+ return false;
1153
+ }
1154
+ if (t.isArrowFunctionExpression(node) || t.isFunctionExpression(node)) {
1155
+ return expressionContainsJsx(node.body) || expressionProducesHtml(node.body);
1156
+ }
1157
+ if (t.isIdentifier(node)) {
1158
+ return knownJsxFunctions.has(node.name);
1159
+ }
1160
+ return false;
1161
+ };
1162
+ const concatExpressions = (parts) => {
1163
+ if (parts.length === 0) {
1164
+ return t.stringLiteral("");
1165
+ }
1166
+ return parts.slice(1).reduce(
1167
+ (acc, current) => t.binaryExpression("+", acc, current),
1168
+ parts[0]
1169
+ );
1170
+ };
1171
+ const jsxNameToString = (name) => {
1172
+ if (t.isJSXIdentifier(name)) {
1173
+ return name.name;
1174
+ }
1175
+ if (t.isJSXNamespacedName(name)) {
1176
+ return `${name.namespace.name}:${name.name.name}`;
1177
+ }
1178
+ const walkMember = (node) => {
1179
+ if (t.isJSXIdentifier(node)) {
1180
+ return node.name;
1181
+ }
1182
+ return `${walkMember(node.object)}.${node.property.name}`;
1183
+ };
1184
+ return walkMember(name);
1185
+ };
1186
+ const transformEmbeddedJsxExpression = (input) => {
1187
+ const wrapped = parseModule(`(${generate(input).code})`);
1188
+ let containsNestedJsx = false;
1189
+ traverse(wrapped, {
1190
+ JSXElement(path) {
1191
+ containsNestedJsx = true;
1192
+ path.replaceWith(jsxElementToExpression(path.node));
1193
+ path.skip();
1194
+ },
1195
+ JSXFragment(path) {
1196
+ containsNestedJsx = true;
1197
+ path.replaceWith(jsxFragmentToExpression(path.node));
1198
+ path.skip();
1199
+ }
1200
+ });
1201
+ const statement2 = wrapped.program.body[0];
1202
+ if (!statement2 || !t.isExpressionStatement(statement2)) {
1203
+ return { expression: input, containsJsx: containsNestedJsx };
1204
+ }
1205
+ return {
1206
+ expression: statement2.expression,
1207
+ containsJsx: containsNestedJsx
1208
+ };
1209
+ };
1210
+ const jsxAttrToExpression = (attr) => {
1211
+ if (t.isJSXSpreadAttribute(attr)) {
1212
+ const transformed = transformEmbeddedJsxExpression(
1213
+ attr.argument
1214
+ );
1215
+ return t.callExpression(t.identifier("__olovaSpreadAttrs"), [
1216
+ transformed.expression
1217
+ ]);
1218
+ }
1219
+ const name = jsxNameToString(attr.name);
1220
+ if (name === "key") {
1221
+ return t.stringLiteral("");
1222
+ }
1223
+ const normalizedName = name === "className" ? "class" : name;
1224
+ const eventMatch = name.match(/^(?:on:|on)([A-Za-z]+)$/);
1225
+ if (!attr.value) {
1226
+ return t.stringLiteral(` ${normalizedName}`);
1227
+ }
1228
+ if (t.isStringLiteral(attr.value)) {
1229
+ return t.stringLiteral(` ${normalizedName}="${attr.value.value}"`);
1230
+ }
1231
+ if (t.isJSXExpressionContainer(attr.value)) {
1232
+ const transformed = transformEmbeddedJsxExpression(
1233
+ attr.value.expression ?? t.stringLiteral("")
1234
+ );
1235
+ if (eventMatch) {
1236
+ return t.callExpression(t.identifier("__olovaRegisterJsxEvent"), [
1237
+ t.stringLiteral(eventMatch[1].toLowerCase()),
1238
+ transformed.expression
1239
+ ]);
1240
+ }
1241
+ const valueExpression = normalizedName === "class" ? t.callExpression(t.identifier("__olovaNormalizeClassValue"), [
1242
+ transformed.expression
1243
+ ]) : transformed.expression;
1244
+ return concatExpressions([
1245
+ t.stringLiteral(` ${normalizedName}="`),
1246
+ escapeCall(valueExpression),
1247
+ t.stringLiteral('"')
1248
+ ]);
1249
+ }
1250
+ return t.stringLiteral("");
1251
+ };
1252
+ const jsxChildToExpression = (child) => {
1253
+ if (t.isJSXText(child)) {
1254
+ return t.stringLiteral(child.value);
1255
+ }
1256
+ if (t.isJSXExpressionContainer(child)) {
1257
+ if (t.isJSXEmptyExpression(child.expression)) {
1258
+ return t.stringLiteral("");
1259
+ }
1260
+ const rawExpression = child.expression;
1261
+ const transformed = transformEmbeddedJsxExpression(rawExpression);
1262
+ return transformed.containsJsx || expressionProducesHtml(rawExpression) ? toStringCall(transformed.expression) : escapeCall(transformed.expression);
1263
+ }
1264
+ if (t.isJSXSpreadChild(child)) {
1265
+ const transformed = transformEmbeddedJsxExpression(child.expression);
1266
+ return transformed.containsJsx || expressionProducesHtml(child.expression) ? toStringCall(transformed.expression) : escapeCall(transformed.expression);
1267
+ }
1268
+ if (t.isJSXElement(child)) {
1269
+ return jsxElementToExpression(child);
1270
+ }
1271
+ return jsxFragmentToExpression(child);
1272
+ };
1273
+ const jsxFragmentToExpression = (fragment) => {
1274
+ const parts = fragment.children.map((child) => jsxChildToExpression(child));
1275
+ return concatExpressions(parts);
1276
+ };
1277
+ const jsxElementToExpression = (element) => {
1278
+ const opening = element.openingElement;
1279
+ const tag = jsxNameToString(opening.name);
1280
+ if (tag === "For") {
1281
+ let eachExpr = t.arrayExpression([]);
1282
+ for (const attr of opening.attributes) {
1283
+ if (t.isJSXAttribute(attr) && jsxNameToString(attr.name) === "each" && attr.value && t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value.expression)) {
1284
+ eachExpr = transformEmbeddedJsxExpression(
1285
+ attr.value.expression
1286
+ ).expression;
1287
+ }
1288
+ }
1289
+ const childRenderer = element.children.find(
1290
+ (child) => t.isJSXExpressionContainer(child) && !t.isJSXEmptyExpression(child.expression)
1291
+ );
1292
+ if (!childRenderer) {
1293
+ return t.stringLiteral("");
1294
+ }
1295
+ return t.callExpression(t.identifier("__olovaFor"), [
1296
+ eachExpr,
1297
+ transformEmbeddedJsxExpression(
1298
+ childRenderer.expression
1299
+ ).expression
1300
+ ]);
1301
+ }
1302
+ if (tag === "Show") {
1303
+ let whenExpr = t.booleanLiteral(false);
1304
+ let fallbackExpr = t.stringLiteral("");
1305
+ for (const attr of opening.attributes) {
1306
+ if (!t.isJSXAttribute(attr)) {
1307
+ continue;
1308
+ }
1309
+ const attrName = jsxNameToString(attr.name);
1310
+ if (attrName === "when" && attr.value && t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value.expression)) {
1311
+ whenExpr = transformEmbeddedJsxExpression(
1312
+ attr.value.expression
1313
+ ).expression;
1314
+ }
1315
+ if (attrName === "fallback" && attr.value && t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value.expression)) {
1316
+ fallbackExpr = transformEmbeddedJsxExpression(
1317
+ attr.value.expression
1318
+ ).expression;
1319
+ }
1320
+ }
1321
+ const childExpr2 = concatExpressions(
1322
+ element.children.map((child) => jsxChildToExpression(child)).filter(Boolean)
1323
+ );
1324
+ return t.callExpression(t.identifier("__olovaShow"), [
1325
+ whenExpr,
1326
+ t.arrowFunctionExpression(
1327
+ [t.identifier("__value")],
1328
+ childExpr2
1329
+ ),
1330
+ fallbackExpr
1331
+ ]);
1332
+ }
1333
+ const attrExpr = concatExpressions(
1334
+ [
1335
+ ...jsxScopeAttr ? [t.stringLiteral(` ${jsxScopeAttr}`)] : [],
1336
+ ...opening.attributes.map((attr) => jsxAttrToExpression(attr))
1337
+ ]
1338
+ );
1339
+ const childExpr = concatExpressions(
1340
+ element.children.map((child) => jsxChildToExpression(child)).filter(Boolean)
1341
+ );
1342
+ if (opening.selfClosing) {
1343
+ return concatExpressions([
1344
+ t.stringLiteral(`<${tag}`),
1345
+ attrExpr,
1346
+ t.stringLiteral("/>")
1347
+ ]);
1348
+ }
1349
+ return concatExpressions([
1350
+ t.stringLiteral(`<${tag}`),
1351
+ attrExpr,
1352
+ t.stringLiteral(">"),
1353
+ childExpr,
1354
+ t.stringLiteral(`</${tag}>`)
1355
+ ]);
1356
+ };
1357
+ traverse(ast, {
1358
+ JSXElement(path) {
1359
+ containsJsx = true;
1360
+ path.replaceWith(jsxElementToExpression(path.node));
1361
+ path.skip();
1362
+ },
1363
+ JSXFragment(path) {
1364
+ containsJsx = true;
1365
+ path.replaceWith(jsxFragmentToExpression(path.node));
1366
+ path.skip();
1367
+ }
1368
+ });
1369
+ const statement = ast.program.body[0];
1370
+ if (!statement || !t.isExpressionStatement(statement)) {
1371
+ return { code: expr.trim(), containsJsx };
1372
+ }
1373
+ containsJsx = containsJsx || expressionProducesHtml(statement.expression);
1374
+ return { code: generate(statement.expression).code, containsJsx };
1375
+ }
1376
+ function jsxToTemplateHtml(node) {
1377
+ if (t.isJSXElement(node)) {
1378
+ const opening = node.openingElement;
1379
+ let tag = "";
1380
+ if (t.isJSXIdentifier(opening.name)) {
1381
+ tag = opening.name.name;
1382
+ } else if (t.isJSXMemberExpression(opening.name)) {
1383
+ const walk = (n) => t.isJSXIdentifier(n) ? n.name : `${walk(n.object)}.${n.property.name}`;
1384
+ tag = walk(opening.name);
1385
+ } else if (t.isJSXNamespacedName(opening.name)) {
1386
+ tag = `${opening.name.namespace.name}:${opening.name.name.name}`;
1387
+ }
1388
+ let attrsStr = "";
1389
+ for (const attr of opening.attributes) {
1390
+ if (t.isJSXSpreadAttribute(attr)) {
1391
+ attrsStr += ` {...${generate(attr.argument).code}}`;
1392
+ } else {
1393
+ let attrName = "";
1394
+ if (t.isJSXIdentifier(attr.name)) attrName = attr.name.name;
1395
+ else attrName = `${attr.name.namespace.name}:${attr.name.name.name}`;
1396
+ if (!attr.value) attrsStr += ` ${attrName}`;
1397
+ else if (t.isStringLiteral(attr.value))
1398
+ attrsStr += ` ${attrName}="${attr.value.value}"`;
1399
+ else if (t.isJSXExpressionContainer(attr.value)) {
1400
+ if (!t.isJSXEmptyExpression(attr.value.expression)) {
1401
+ attrsStr += ` ${attrName}={${generate(attr.value.expression).code}}`;
1402
+ }
1403
+ }
1404
+ }
1405
+ }
1406
+ const childrenStr = node.children.map(jsxToTemplateHtml).join("");
1407
+ if (opening.selfClosing) {
1408
+ return `<${tag}${attrsStr} />`;
1409
+ }
1410
+ return `<${tag}${attrsStr}>${childrenStr}</${tag}>`;
1411
+ }
1412
+ if (t.isJSXText(node)) {
1413
+ return node.value;
1414
+ }
1415
+ if (t.isJSXExpressionContainer(node)) {
1416
+ if (t.isJSXEmptyExpression(node.expression)) return "";
1417
+ return `{${generate(node.expression).code}}`;
1418
+ }
1419
+ if (t.isJSXFragment(node)) {
1420
+ return node.children.map(jsxToTemplateHtml).join("");
1421
+ }
1422
+ return "";
1423
+ }
1424
+ function replaceTemplateExpressions(input, replacer) {
1425
+ let output = "";
1426
+ let index = 0;
1427
+ while (index < input.length) {
1428
+ const start = input.indexOf("{", index);
1429
+ if (start < 0) {
1430
+ output += input.slice(index);
1431
+ break;
1432
+ }
1433
+ let prevIndex = start - 1;
1434
+ while (prevIndex >= 0 && /\s/.test(input[prevIndex])) {
1435
+ prevIndex -= 1;
1436
+ }
1437
+ if (prevIndex >= 0 && input[prevIndex] === "=") {
1438
+ output += input.slice(index, start + 1);
1439
+ index = start + 1;
1440
+ continue;
1441
+ }
1442
+ if (start > 0 && input[start - 1] === "$") {
1443
+ output += input.slice(index, start + 1);
1444
+ index = start + 1;
1445
+ continue;
1446
+ }
1447
+ output += input.slice(index, start);
1448
+ let depth = 1;
1449
+ let cursor = start + 1;
1450
+ let quote = null;
1451
+ while (cursor < input.length && depth > 0) {
1452
+ const char = input[cursor];
1453
+ const prev = input[cursor - 1];
1454
+ if (quote) {
1455
+ if (char === quote && prev !== "\\") {
1456
+ quote = null;
1457
+ }
1458
+ cursor += 1;
1459
+ continue;
1460
+ }
1461
+ if (char === "'" || char === '"' || char === "`") {
1462
+ quote = char;
1463
+ cursor += 1;
1464
+ continue;
1465
+ }
1466
+ if (char === "{") {
1467
+ depth += 1;
1468
+ } else if (char === "}") {
1469
+ depth -= 1;
1470
+ }
1471
+ cursor += 1;
1472
+ }
1473
+ if (depth !== 0) {
1474
+ throw createCompileError("[olova] Unclosed template expression block.", input, start);
1475
+ }
1476
+ const expression = input.slice(start + 1, cursor - 1);
1477
+ output += replacer(expression);
1478
+ index = cursor;
1479
+ }
1480
+ return output;
1481
+ }
1482
+ function parsePropsFromAttrs(attrs, stateNames, allSignalNames, jsxFunctionNames) {
1483
+ const props = [];
1484
+ for (const [key, rawValue] of Object.entries(attrs)) {
1485
+ if (key === "slot" || key === "key") {
1486
+ continue;
1487
+ }
1488
+ const propName = key === "className" ? "class" : key;
1489
+ if (rawValue === true) {
1490
+ props.push(`${JSON.stringify(propName)}: true`);
1491
+ continue;
1492
+ }
1493
+ if (rawValue.startsWith("{") && rawValue.endsWith("}")) {
1494
+ const expr = rawValue.slice(1, -1);
1495
+ const valueExpr = transformExpression(
1496
+ expr,
1497
+ stateNames,
1498
+ allSignalNames,
1499
+ jsxFunctionNames
1500
+ ).code;
1501
+ props.push(
1502
+ `${JSON.stringify(propName)}: (${propName === "class" ? `__olovaNormalizeClassValue(${valueExpr})` : valueExpr})`
1503
+ );
1504
+ continue;
1505
+ }
1506
+ props.push(`${JSON.stringify(propName)}: ${JSON.stringify(rawValue)}`);
1507
+ }
1508
+ return props.length === 0 ? "{}" : `{ ${props.join(", ")} }`;
1509
+ }
1510
+ function transformTemplate(template, stateNames, allSignalNames, jsxFunctionNames, componentNames, counters, scopeId) {
1511
+ let html = template;
1512
+ const textBindings = [];
1513
+ const htmlBindings = [];
1514
+ const attrBindings = [];
1515
+ const eventBindings = [];
1516
+ const slotBindings = [];
1517
+ const componentBindings = [];
1518
+ const ifBindings = [];
1519
+ html = replaceTemplateExpressions(html, (expr) => {
1520
+ try {
1521
+ const ast = parseModule(`(${expr})`);
1522
+ const exprNode = ast.program.body[0];
1523
+ if (t.isExpressionStatement(exprNode)) {
1524
+ const node = exprNode.expression;
1525
+ const containsJsxNode = (n) => {
1526
+ let found = false;
1527
+ traverse(parseModule(`(${generate(n).code})`), {
1528
+ JSXElement() {
1529
+ found = true;
1530
+ },
1531
+ JSXFragment() {
1532
+ found = true;
1533
+ }
1534
+ });
1535
+ return found;
1536
+ };
1537
+ if (t.isLogicalExpression(node) && node.operator === "&&") {
1538
+ if (containsJsxNode(node.right)) {
1539
+ const id = `i${counters.if++}`;
1540
+ const condition = generate(node.left).code;
1541
+ const trueBranchHtml = jsxToTemplateHtml(node.right);
1542
+ ifBindings.push({
1543
+ id,
1544
+ expr: transformExpression(
1545
+ condition,
1546
+ stateNames,
1547
+ allSignalNames,
1548
+ jsxFunctionNames,
1549
+ scopeId
1550
+ ).code,
1551
+ trueBranch: transformTemplate(
1552
+ trueBranchHtml,
1553
+ stateNames,
1554
+ allSignalNames,
1555
+ jsxFunctionNames,
1556
+ componentNames,
1557
+ counters,
1558
+ scopeId
1559
+ )
1560
+ });
1561
+ return `__O_IF_${id}__`;
1562
+ }
1563
+ } else if (t.isConditionalExpression(node)) {
1564
+ if (containsJsxNode(node.consequent) || containsJsxNode(node.alternate)) {
1565
+ const id = `i${counters.if++}`;
1566
+ const condition = generate(node.test).code;
1567
+ const trueBranchHtml = containsJsxNode(node.consequent) ? jsxToTemplateHtml(node.consequent) : `{${generate(node.consequent).code}}`;
1568
+ const falseBranchHtml = containsJsxNode(node.alternate) ? jsxToTemplateHtml(node.alternate) : `{${generate(node.alternate).code}}`;
1569
+ ifBindings.push({
1570
+ id,
1571
+ expr: transformExpression(
1572
+ condition,
1573
+ stateNames,
1574
+ allSignalNames,
1575
+ jsxFunctionNames,
1576
+ scopeId
1577
+ ).code,
1578
+ trueBranch: transformTemplate(
1579
+ trueBranchHtml,
1580
+ stateNames,
1581
+ allSignalNames,
1582
+ jsxFunctionNames,
1583
+ componentNames,
1584
+ counters,
1585
+ scopeId
1586
+ ),
1587
+ falseBranch: transformTemplate(
1588
+ falseBranchHtml,
1589
+ stateNames,
1590
+ allSignalNames,
1591
+ jsxFunctionNames,
1592
+ componentNames,
1593
+ counters,
1594
+ scopeId
1595
+ )
1596
+ });
1597
+ return `__O_IF_${id}__`;
1598
+ }
1599
+ }
1600
+ }
1601
+ } catch {
1602
+ }
1603
+ return `{${expr}}`;
1604
+ });
1605
+ const rawExpressions = [];
1606
+ html = replaceTemplateExpressions(html, (expr) => {
1607
+ const id = `raw_${rawExpressions.length}`;
1608
+ rawExpressions.push({ id, expression: expr });
1609
+ return `__O_RAW_EXPR_${id}__`;
1610
+ });
1611
+ const renderTextContent = (content) => {
1612
+ return content.replace(
1613
+ /__O_RAW_EXPR_([a-zA-Z0-9_]+)__/g,
1614
+ (_full, exprId) => {
1615
+ const found = rawExpressions.find((entry) => entry.id === exprId);
1616
+ const expr = found ? found.expression : "";
1617
+ const transformed = transformExpression(
1618
+ expr,
1619
+ stateNames,
1620
+ allSignalNames,
1621
+ jsxFunctionNames,
1622
+ scopeId
1623
+ );
1624
+ if (transformed.containsJsx) {
1625
+ const id2 = `h${counters.text++}`;
1626
+ htmlBindings.push({
1627
+ id: id2,
1628
+ expr: `__olovaDangerouslySetHtml(${transformed.code})`
1629
+ });
1630
+ return `__O_HTML_${id2}__`;
1631
+ }
1632
+ const id = `t${counters.text++}`;
1633
+ textBindings.push({ id, expr: transformed.code });
1634
+ return `__O_TEXT_${id}__`;
1635
+ }
1636
+ );
1637
+ };
1638
+ const renderAttrs = (element) => {
1639
+ let output = "";
1640
+ const scopeAttr = createScopeAttr(scopeId);
1641
+ if (scopeAttr) {
1642
+ output += ` ${scopeAttr}`;
1643
+ }
1644
+ for (const [attrName, rawValue] of Object.entries(element.attrs)) {
1645
+ if (attrName === "key") {
1646
+ continue;
1647
+ }
1648
+ const normalizedAttrName = attrName === "className" ? "class" : attrName;
1649
+ if (rawValue === true) {
1650
+ output += ` ${normalizedAttrName}`;
1651
+ continue;
1652
+ }
1653
+ if (rawValue.startsWith("{") && rawValue.endsWith("}")) {
1654
+ const expr = rawValue.slice(1, -1);
1655
+ const eventMatch = normalizedAttrName.match(/^(?:on:|on)([A-Za-z]+)$/);
1656
+ if (eventMatch) {
1657
+ const id2 = `e${counters.event++}`;
1658
+ const event = eventMatch[1].toLowerCase();
1659
+ eventBindings.push({
1660
+ id: id2,
1661
+ event,
1662
+ expr: transformExpression(
1663
+ expr,
1664
+ stateNames,
1665
+ allSignalNames,
1666
+ jsxFunctionNames
1667
+ ).code
1668
+ });
1669
+ output += ` data-o-on-${event}="${id2}"`;
1670
+ continue;
1671
+ }
1672
+ const id = `a${counters.attr++}`;
1673
+ attrBindings.push({
1674
+ id,
1675
+ attr: normalizedAttrName,
1676
+ expr: normalizedAttrName === "class" ? `__olovaNormalizeClassValue(${transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames).code})` : transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames).code
1677
+ });
1678
+ output += ` ${normalizedAttrName}="__O_ATTR_${id}__"`;
1679
+ continue;
1680
+ }
1681
+ output += ` ${normalizedAttrName}="${rawValue.replace(/"/g, "&quot;")}"`;
1682
+ }
1683
+ return output;
1684
+ };
1685
+ const serializeRawNodes = (nodes) => nodes.map((node) => {
1686
+ if (node.type === "comment") {
1687
+ return `<!--${node.content}-->`;
1688
+ }
1689
+ if (node.type === "text") {
1690
+ return node.content;
1691
+ }
1692
+ const attrs = Object.entries(node.attrs).map(([name, value]) => {
1693
+ if (value === true) {
1694
+ return ` ${name}`;
1695
+ }
1696
+ return ` ${name}="${String(value).replace(/"/g, "&quot;")}"`;
1697
+ }).join("");
1698
+ const children = serializeRawNodes(node.children);
1699
+ if (node.isSelfClosing) {
1700
+ return `<${node.tag}${attrs} />`;
1701
+ }
1702
+ return `<${node.tag}${attrs}>${children}</${node.tag}>`;
1703
+ }).join("");
1704
+ const renderNodes = (nodes) => nodes.map((node) => {
1705
+ if (node.type === "comment") {
1706
+ return `<!--${node.content}-->`;
1707
+ }
1708
+ if (node.type === "text") {
1709
+ return renderTextContent(node.content);
1710
+ }
1711
+ if (node.tag === "slot") {
1712
+ const id = `s${counters.slot++}`;
1713
+ const slotName = typeof node.attrs.name === "string" ? node.attrs.name : "default";
1714
+ slotBindings.push({ id, name: slotName });
1715
+ return `__O_SLOT_${id}__`;
1716
+ }
1717
+ if (componentNames.has(node.tag)) {
1718
+ const id = `c${counters.comp++}`;
1719
+ const namedSlotNodes = /* @__PURE__ */ new Map();
1720
+ const defaultNodes = [];
1721
+ for (const child of node.children) {
1722
+ if (child.type === "element" && child.tag === "template" && typeof child.attrs.slot === "string") {
1723
+ namedSlotNodes.set(child.attrs.slot, child.children);
1724
+ continue;
1725
+ }
1726
+ defaultNodes.push(child);
1727
+ }
1728
+ const slotFactories = [];
1729
+ if (defaultNodes.length > 0) {
1730
+ slotFactories.push({
1731
+ varName: `__slot_${id}_default`,
1732
+ name: "default",
1733
+ descriptor: transformTemplate(
1734
+ serializeRawNodes(defaultNodes),
1735
+ stateNames,
1736
+ allSignalNames,
1737
+ jsxFunctionNames,
1738
+ componentNames,
1739
+ counters,
1740
+ scopeId
1741
+ )
1742
+ });
1743
+ }
1744
+ for (const [slotName, slotChildren] of namedSlotNodes.entries()) {
1745
+ slotFactories.push({
1746
+ varName: `__slot_${id}_${slotName.replace(/[^A-Za-z0-9_$]/g, "_")}`,
1747
+ name: slotName,
1748
+ descriptor: transformTemplate(
1749
+ serializeRawNodes(slotChildren),
1750
+ stateNames,
1751
+ allSignalNames,
1752
+ jsxFunctionNames,
1753
+ componentNames,
1754
+ counters,
1755
+ scopeId
1756
+ )
1757
+ });
1758
+ }
1759
+ componentBindings.push({
1760
+ id,
1761
+ component: node.tag,
1762
+ propsExpr: parsePropsFromAttrs(
1763
+ node.attrs,
1764
+ stateNames,
1765
+ allSignalNames,
1766
+ jsxFunctionNames
1767
+ ),
1768
+ slotFactories
1769
+ });
1770
+ return `__O_COMP_${id}__`;
1771
+ }
1772
+ const attrs = renderAttrs(node);
1773
+ const children = renderNodes(node.children);
1774
+ if (node.isSelfClosing) {
1775
+ return `<${node.tag}${attrs} />`;
1776
+ }
1777
+ return `<${node.tag}${attrs}>${children}</${node.tag}>`;
1778
+ }).join("");
1779
+ html = renderNodes(parseHTML(html));
1780
+ const resolveExpr = (expr) => transformExpression(
1781
+ expr,
1782
+ stateNames,
1783
+ allSignalNames,
1784
+ jsxFunctionNames,
1785
+ scopeId
1786
+ );
1787
+ const buildFnStr = generateBuildFunction(
1788
+ escapeTemplate(html),
1789
+ stateNames,
1790
+ resolveExpr,
1791
+ counters,
1792
+ componentNames
1793
+ );
1794
+ return {
1795
+ html: escapeTemplate(html),
1796
+ textBindings,
1797
+ htmlBindings,
1798
+ attrBindings,
1799
+ eventBindings,
1800
+ slotBindings,
1801
+ componentBindings,
1802
+ ifBindings,
1803
+ buildFnStr
1804
+ };
1805
+ }
1806
+ function indentBlock(code, spaces = 2) {
1807
+ const pad = " ".repeat(spaces);
1808
+ if (!code.trim()) {
1809
+ return "";
1810
+ }
1811
+ return code.split("\n").map((line) => `${pad}${line}`).join("\n");
1812
+ }
1813
+ function renderDescriptorLiteral(descriptor, indent = " ") {
1814
+ const slotFactoryDecls = descriptor.componentBindings.flatMap(
1815
+ (binding) => binding.slotFactories.map(
1816
+ (slot) => `${indent}const ${slot.varName} = () => (${renderDescriptorLiteral(slot.descriptor, indent + " ")});`
1817
+ )
1818
+ );
1819
+ const componentBindingsCode = descriptor.componentBindings.map((binding) => {
1820
+ const slotsObject = binding.slotFactories.length === 0 ? "{}" : `{ ${binding.slotFactories.map((slot) => `${JSON.stringify(slot.name)}: ${slot.varName}`).join(", ")} }`;
1821
+ return `${indent} { id: ${JSON.stringify(binding.id)}, getComponent: () => ${binding.component}, getProps: () => (${binding.propsExpr}), getSlots: () => (${slotsObject}) }`;
1822
+ }).join(",\n");
1823
+ const buildLines = descriptor.buildFnStr ? `${indent}build: ${descriptor.buildFnStr.replace(/\n /g, "\n" + indent)},` : "";
1824
+ const objectLiteral = `{
1825
+ ${buildLines}
1826
+ ${indent}textBindings: [
1827
+ ${descriptor.textBindings.map((binding) => `${indent} { id: ${JSON.stringify(binding.id)}, get: () => (${binding.expr}) }`).join(",\n")}
1828
+ ${indent}],
1829
+ ${indent}htmlBindings: [
1830
+ ${descriptor.htmlBindings.map((binding) => `${indent} { id: ${JSON.stringify(binding.id)}, get: () => (${binding.expr}) }`).join(",\n")}
1831
+ ${indent}],
1832
+ ${indent}attrBindings: [
1833
+ ${descriptor.attrBindings.map((binding) => `${indent} { id: ${JSON.stringify(binding.id)}, attr: ${JSON.stringify(binding.attr)}, get: () => (${binding.expr}) }`).join(",\n")}
1834
+ ${indent}],
1835
+ ${indent}eventBindings: [
1836
+ ${descriptor.eventBindings.map((binding) => `${indent} { id: ${JSON.stringify(binding.id)}, event: ${JSON.stringify(binding.event)}, get: () => (${binding.expr}) }`).join(",\n")}
1837
+ ${indent}],
1838
+ ${indent}slotBindings: [
1839
+ ${descriptor.slotBindings.map((binding) => `${indent} { id: ${JSON.stringify(binding.id)}, name: ${JSON.stringify(binding.name)} }`).join(",\n")}
1840
+ ${indent}],
1841
+ ${indent}componentBindings: [
1842
+ ${componentBindingsCode}
1843
+ ${indent}],
1844
+ ${indent}ifBindings: [
1845
+ ${descriptor.ifBindings.map((binding) => {
1846
+ const trueFactory = `() => (${renderDescriptorLiteral(binding.trueBranch, indent + " ")})`;
1847
+ const falseFactory = binding.falseBranch ? `() => (${renderDescriptorLiteral(binding.falseBranch, indent + " ")})` : "undefined";
1848
+ return `${indent} { id: ${JSON.stringify(binding.id)}, get: () => (${binding.expr}), trueBranch: ${trueFactory}, falseBranch: ${falseFactory} }`;
1849
+ }).join(",\n")}
1850
+ ${indent}]
1851
+ ${indent}}`;
1852
+ if (slotFactoryDecls.length === 0) {
1853
+ return objectLiteral;
1854
+ }
1855
+ const outerIndent = indent.length >= 2 ? indent.slice(2) : "";
1856
+ return `(() => {
1857
+ ${slotFactoryDecls.join("\n")}
1858
+ ${indent}return ${objectLiteral};
1859
+ ${outerIndent}})()`;
1860
+ }
1861
+ function buildComponentCode(parsed, options) {
1862
+ const scriptInfo = collectScriptInfo(parsed.script);
1863
+ const counters = {
1864
+ text: 0,
1865
+ attr: 0,
1866
+ event: 0,
1867
+ comp: 0,
1868
+ slot: 0,
1869
+ if: 0
1870
+ };
1871
+ const transformed = transformTemplate(
1872
+ parsed.template,
1873
+ scriptInfo.stateNames,
1874
+ scriptInfo.allSignalNames,
1875
+ scriptInfo.jsxFunctionNames,
1876
+ scriptInfo.componentNames,
1877
+ counters,
1878
+ options?.scopeId
1879
+ );
1880
+ const exportHead = options?.exportName ? `export const ${options.exportName} = __defineComponent((__props, __slots) => {` : `const __olovaComponent = __defineComponent((__props, __slots) => {`;
1881
+ const exportTail = options?.exportName ? `}, ${JSON.stringify(options?.hmrId)});` : `}, ${JSON.stringify(options?.hmrId)});
1882
+ export default __olovaComponent;`;
1883
+ const hmrCode = options?.dev && !options?.exportName && options?.hmrId ? `
1884
+ if (import.meta.hot) {
1885
+ import.meta.hot.accept((nextModule) => {
1886
+ if (nextModule?.default) {
1887
+ __replaceComponent(__olovaComponent, nextModule.default);
1888
+ }
1889
+ });
1890
+ }
1891
+ ` : "";
1892
+ const code = `
1893
+ ${exportHead}
1894
+ const props = __props;
1895
+ const slots = __slots;
1896
+ const __olovaGlobalObj = globalThis;
1897
+ const __olovaJsxHandlers =
1898
+ __olovaGlobalObj.__olovaJsxHandlers ?? (__olovaGlobalObj.__olovaJsxHandlers = new Map());
1899
+ const __olovaNextJsxEventId = () => {
1900
+ __olovaGlobalObj.__olovaJsxEventId = (__olovaGlobalObj.__olovaJsxEventId ?? 0) + 1;
1901
+ return String(__olovaGlobalObj.__olovaJsxEventId);
1902
+ };
1903
+ if (typeof __olovaGlobalObj.__olovaDispatchJsxEvent !== 'function') {
1904
+ __olovaGlobalObj.__olovaDispatchJsxEvent = (event, element) => {
1905
+ const key = element?.getAttribute?.('data-o-jsx-' + event.type);
1906
+ if (!key) {
1907
+ return;
1908
+ }
1909
+
1910
+ const handler = __olovaJsxHandlers.get(key);
1911
+ if (typeof handler === 'function') {
1912
+ handler(event);
1913
+ }
1914
+ };
1915
+ }
1916
+ const __olovaRegisterJsxEvent = (eventName, handler) => {
1917
+ if (typeof handler !== 'function') {
1918
+ return '';
1919
+ }
1920
+
1921
+ const id = __olovaNextJsxEventId();
1922
+ __olovaJsxHandlers.set(id, handler);
1923
+ return ' data-o-jsx-' + eventName + '="' + id + '" on' + eventName + '="window.__olovaDispatchJsxEvent(event, this)"';
1924
+ };
1925
+ const __olovaToString = (value) => Array.isArray(value) ? value.map(__olovaToString).join('') : value == null ? '' : String(value);
1926
+ const __olovaDangerouslySetHtml = (value) => ({ __dangerousHtml: true, value: __olovaToString(value) });
1927
+ const __olovaNormalizeClassValue = (value) => {
1928
+ if (value == null || value === false) {
1929
+ return '';
1930
+ }
1931
+ if (Array.isArray(value)) {
1932
+ return value.map(__olovaNormalizeClassValue).filter(Boolean).join(' ');
1933
+ }
1934
+ if (typeof value === 'object') {
1935
+ return Object.entries(value)
1936
+ .filter(([, enabled]) => !!enabled)
1937
+ .map(([key]) => key)
1938
+ .join(' ');
1939
+ }
1940
+ return String(value);
1941
+ };
1942
+ const __olovaEscape = (value) =>
1943
+ __olovaToString(value)
1944
+ .replace(/&/g, '&amp;')
1945
+ .replace(/</g, '&lt;')
1946
+ .replace(/>/g, '&gt;')
1947
+ .replace(/"/g, '&quot;')
1948
+ .replace(/'/g, '&#39;');
1949
+ const __olovaSpreadAttrs = (input) => {
1950
+ if (input == null || input === false) {
1951
+ return '';
1952
+ }
1953
+ if (Array.isArray(input)) {
1954
+ return input.map(__olovaSpreadAttrs).join('');
1955
+ }
1956
+ if (typeof input !== 'object') {
1957
+ return '';
1958
+ }
1959
+
1960
+ return Object.entries(input).reduce((acc, [key, value]) => {
1961
+ if (value == null || value === false) {
1962
+ return acc;
1963
+ }
1964
+ const attrKey = key === 'className' ? 'class' : key;
1965
+ const normalizedValue = attrKey === 'class'
1966
+ ? __olovaNormalizeClassValue(value)
1967
+ : value;
1968
+ if (attrKey === 'key') {
1969
+ return acc;
1970
+ }
1971
+ if (normalizedValue == null || normalizedValue === false || normalizedValue === '') {
1972
+ return acc;
1973
+ }
1974
+ if (normalizedValue === true) {
1975
+ return acc + ' ' + attrKey;
1976
+ }
1977
+ return acc + ' ' + attrKey + '="' + __olovaEscape(normalizedValue) + '"';
1978
+ }, '');
1979
+ };
1980
+ const __olovaFor = (each, render) => {
1981
+ if (!Array.isArray(each) || typeof render !== 'function') {
1982
+ return '';
1983
+ }
1984
+ return each.map((item, index) => render(item, index));
1985
+ };
1986
+ const __olovaShow = (when, render, fallback = '') => {
1987
+ if (!when) {
1988
+ return fallback;
1989
+ }
1990
+ return typeof render === 'function' ? render(when) : render;
1991
+ };
1992
+ ${indentBlock(scriptInfo.scriptBodyCode, 2)}
1993
+
1994
+ return ${renderDescriptorLiteral(transformed, " ")};
1995
+ ${exportTail}
1996
+ ${hmrCode}
1997
+ `;
1998
+ return { importsCode: scriptInfo.importsCode, code };
1999
+ }
2000
+ function hashScopeSeed(input) {
2001
+ let hash = 2166136261;
2002
+ for (let index = 0; index < input.length; index += 1) {
2003
+ hash ^= input.charCodeAt(index);
2004
+ hash = Math.imul(hash, 16777619);
2005
+ }
2006
+ return Math.abs(hash >>> 0).toString(36);
2007
+ }
2008
+ function createScopeAttr(scopeId) {
2009
+ return scopeId ? `data-o-scope-${scopeId}` : null;
2010
+ }
2011
+ function scopeSelectorList(selectorList, scopeAttr) {
2012
+ const applyScopeToSegment = (segment) => {
2013
+ const trimmed = segment.trim();
2014
+ if (!trimmed) {
2015
+ return trimmed;
2016
+ }
2017
+ if (trimmed.includes(scopeAttr)) {
2018
+ return trimmed;
2019
+ }
2020
+ const globalPattern = /:global\(([^()]+)\)/g;
2021
+ const localCandidate = trimmed.replace(globalPattern, "").trim();
2022
+ const normalized = trimmed.replace(globalPattern, "$1");
2023
+ if (!localCandidate) {
2024
+ return normalized;
2025
+ }
2026
+ if (normalized === ":root") {
2027
+ return `[${scopeAttr}]`;
2028
+ }
2029
+ const pseudoIndex = normalized.search(/(?<!:):(?!:)/);
2030
+ if (pseudoIndex === -1) {
2031
+ return `${normalized}[${scopeAttr}]`;
2032
+ }
2033
+ return `${normalized.slice(0, pseudoIndex)}[${scopeAttr}]${normalized.slice(pseudoIndex)}`;
2034
+ };
2035
+ return selectorList.split(",").map((selector) => selector.trim()).filter(Boolean).map((selector) => {
2036
+ if (selector.startsWith("@") || selector.includes(scopeAttr)) {
2037
+ return selector;
2038
+ }
2039
+ return selector.split(/(\s+|[>+~])/).map((part) => {
2040
+ if (!part || /^(\s+|[>+~])$/.test(part)) {
2041
+ return part;
2042
+ }
2043
+ return applyScopeToSegment(part);
2044
+ }).join("");
2045
+ }).join(", ");
2046
+ }
2047
+ function scopeCss(css, scopeAttr) {
2048
+ let output = "";
2049
+ let index = 0;
2050
+ while (index < css.length) {
2051
+ const open = css.indexOf("{", index);
2052
+ if (open < 0) {
2053
+ output += css.slice(index);
2054
+ break;
2055
+ }
2056
+ const selector = css.slice(index, open).trim();
2057
+ let depth = 1;
2058
+ let cursor = open + 1;
2059
+ while (cursor < css.length && depth > 0) {
2060
+ if (css[cursor] === "{") {
2061
+ depth += 1;
2062
+ } else if (css[cursor] === "}") {
2063
+ depth -= 1;
2064
+ }
2065
+ cursor += 1;
2066
+ }
2067
+ const body = css.slice(open + 1, cursor - 1);
2068
+ if (/^@(?:media|supports|container|layer)\b/i.test(selector)) {
2069
+ output += `${selector} {${scopeCss(body, scopeAttr)}}`;
2070
+ } else if (/^@(?:keyframes|-webkit-keyframes)\b/i.test(selector)) {
2071
+ output += `${selector} {${body}}`;
2072
+ } else {
2073
+ output += `${scopeSelectorList(selector, scopeAttr)} {${body}}`;
2074
+ }
2075
+ index = cursor;
2076
+ }
2077
+ return output;
2078
+ }
2079
+ function collectCss(blocks, scopeId) {
2080
+ const scopeAttr = createScopeAttr(scopeId);
2081
+ return blocks.map((block) => {
2082
+ const content = block.content.trim();
2083
+ if (!content) {
2084
+ return "";
2085
+ }
2086
+ if (!("global" in block.attrs) && scopeAttr) {
2087
+ return scopeCss(content, scopeAttr);
2088
+ }
2089
+ return content;
2090
+ }).filter(Boolean).join("\n\n");
2091
+ }
2092
+ function compileOlovaScriptModule(source, options) {
2093
+ try {
2094
+ const scriptInfo = collectScriptInfo(source);
2095
+ return transpileTypeScript(
2096
+ [scriptInfo.importsCode, scriptInfo.scriptBodyCode].filter(Boolean).join("\n"),
2097
+ options?.filename ?? "module.ts"
2098
+ );
2099
+ } catch (error) {
2100
+ return normalizeCompileError(error, source, options?.filename ?? "module.ts");
2101
+ }
2102
+ }
2103
+ function compileOlova(source, options) {
2104
+ try {
2105
+ const parsed = parseOlovaFile(source);
2106
+ if (!parsed.template.trim() && isModuleOnlyScript(parsed.script)) {
2107
+ return {
2108
+ ...compileModuleScript(parsed.script, options?.filename ?? "module.olova.ts"),
2109
+ css: collectCss(parsed.styles)
2110
+ };
2111
+ }
2112
+ const scopeId = parsed.styles.some((style) => !("global" in style.attrs)) ? hashScopeSeed(`${options?.filename ?? "component.olova"}:${options?.exportName ?? "default"}`) : void 0;
2113
+ const compiled = buildComponentCode(parsed, {
2114
+ scopeId,
2115
+ hmrId: options?.filename ?? "component.olova",
2116
+ dev: options?.dev
2117
+ });
2118
+ const runtimeImport = options?.dev ? `import { defineComponent as __defineComponent, replaceComponent as __replaceComponent } from 'olova/runtime';` : `import { defineComponent as __defineComponent } from 'olova/runtime';`;
2119
+ const result = transpileTypeScript(`
2120
+ ${runtimeImport}
2121
+ ${compiled.importsCode}
2122
+ ${compiled.code}
2123
+ `, options?.filename ?? "component.olova.ts");
2124
+ return {
2125
+ ...result,
2126
+ css: collectCss(parsed.styles, scopeId)
2127
+ };
2128
+ } catch (error) {
2129
+ return normalizeCompileError(
2130
+ error,
2131
+ source,
2132
+ options?.filename ?? "component.olova"
2133
+ );
2134
+ }
2135
+ }
2136
+
2137
+ export { compileOlova, compileOlovaScriptModule, generateBuildFunction, parseHTML };
2138
+ //# sourceMappingURL=compiler.js.map
2139
+ //# sourceMappingURL=compiler.js.map