@hyperfixi/vite-plugin 3.3.0 → 4.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.
- package/README.md +100 -95
- package/dist/index.cjs +244 -1856
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -130
- package/dist/index.d.ts +36 -130
- package/dist/index.js +243 -1863
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,67 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import
|
|
1
|
+
// src/engine-modules.ts
|
|
2
|
+
import * as engine from "@hyperfixi/engine";
|
|
3
|
+
import { createGrammar, everything } from "@hyperfixi/engine";
|
|
4
|
+
function exportNameOf(mod) {
|
|
5
|
+
for (const [name, value] of Object.entries(engine)) {
|
|
6
|
+
if (value === mod) return name;
|
|
7
|
+
}
|
|
8
|
+
throw new Error("[hyperfixi] an engine module in `everything` is not a named export");
|
|
9
|
+
}
|
|
10
|
+
var ENGINE_MODULES = everything.map((mod) => {
|
|
11
|
+
const grammar = createGrammar();
|
|
12
|
+
mod(grammar);
|
|
13
|
+
return {
|
|
14
|
+
name: exportNameOf(mod),
|
|
15
|
+
// The template text line registers under a keyword no identifier can be
|
|
16
|
+
// spelled as (`#text`); it is not something a scan can find.
|
|
17
|
+
commands: Object.keys(grammar.commands).filter((k) => /^[a-z]+$/.test(k)),
|
|
18
|
+
features: Object.keys(grammar.features)
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
var byName = new Map(ENGINE_MODULES.map((m) => [m.name, m]));
|
|
22
|
+
var COMMAND_KEYWORDS = new Map(
|
|
23
|
+
ENGINE_MODULES.flatMap((m) => m.commands.map((k) => [k, m.name]))
|
|
24
|
+
);
|
|
25
|
+
var FEATURE_KEYWORDS = new Map(
|
|
26
|
+
ENGINE_MODULES.flatMap((m) => m.features.map((k) => [k, m.name]))
|
|
27
|
+
);
|
|
28
|
+
var NOT_SCANNED = /* @__PURE__ */ new Set(["on", "if", "live", "when", "bind"]);
|
|
29
|
+
var SCANNABLE_KEYWORDS = [
|
|
30
|
+
.../* @__PURE__ */ new Set([...COMMAND_KEYWORDS.keys(), ...FEATURE_KEYWORDS.keys()])
|
|
31
|
+
].filter((k) => !NOT_SCANNED.has(k)).sort();
|
|
32
|
+
var BLOCK_MODULES = {
|
|
33
|
+
if: ["ifCommand"],
|
|
34
|
+
repeat: ["repeat", "loopControl"],
|
|
35
|
+
for: ["repeat", "loopControl"],
|
|
36
|
+
while: ["repeat", "loopControl"],
|
|
37
|
+
fetch: ["fetchCommand"]
|
|
38
|
+
};
|
|
39
|
+
var ALWAYS = ["on", "conversions"];
|
|
40
|
+
function resolveModules(usage) {
|
|
41
|
+
const wanted = new Set(ALWAYS);
|
|
42
|
+
const unknown = [];
|
|
43
|
+
for (const name of usage.commands) {
|
|
44
|
+
const mod = COMMAND_KEYWORDS.get(name) ?? FEATURE_KEYWORDS.get(name);
|
|
45
|
+
if (mod) wanted.add(mod);
|
|
46
|
+
else if (!(name in BLOCK_MODULES)) unknown.push(name);
|
|
47
|
+
}
|
|
48
|
+
for (const block of usage.blocks) {
|
|
49
|
+
for (const mod of BLOCK_MODULES[block] ?? []) wanted.add(mod);
|
|
50
|
+
}
|
|
51
|
+
if (usage.positional) wanted.add("expressionsExtra");
|
|
52
|
+
if (usage.reactivity) {
|
|
53
|
+
wanted.add("reactivity");
|
|
54
|
+
wanted.add("liveTemplates");
|
|
55
|
+
}
|
|
56
|
+
if (usage.construct) wanted.add("construct");
|
|
57
|
+
if (usage.cookies) wanted.add("cookies");
|
|
58
|
+
if (wanted.has("toggle")) wanted.add("toggleElement");
|
|
59
|
+
const modules = ENGINE_MODULES.filter((m) => wanted.has(m.name)).map((m) => m.name);
|
|
60
|
+
for (const name of wanted) {
|
|
61
|
+
if (!byName.has(name)) throw new Error(`[hyperfixi] no engine module named ${name}`);
|
|
62
|
+
}
|
|
63
|
+
return { modules, unknown: [...new Set(unknown)].sort() };
|
|
64
|
+
}
|
|
3
65
|
|
|
4
66
|
// src/language-keywords.ts
|
|
5
67
|
var SUPPORTED_LANGUAGES = [
|
|
@@ -1036,17 +1098,7 @@ var SSE_NS_PATTERN = /\bsse-[\w\-\p{L}]+\s*=\s*["']/u;
|
|
|
1036
1098
|
var WS_NS_PATTERN = /\bws-[\w\-\p{L}]+\s*=\s*["']/u;
|
|
1037
1099
|
|
|
1038
1100
|
// src/scanner.ts
|
|
1039
|
-
var
|
|
1040
|
-
.../* @__PURE__ */ new Set([...AVAILABLE_COMMANDS, ...FULL_RUNTIME_ONLY_COMMANDS])
|
|
1041
|
-
].filter(
|
|
1042
|
-
(cmd) => /^[A-Za-z]+$/.test(cmd) && // `unless` is handled by the block detection below (it compiles to the
|
|
1043
|
-
// lite-capable `if` block — flagging it as a full-runtime-only COMMAND
|
|
1044
|
-
// would needlessly bump every unless-user to a full-runtime bundle).
|
|
1045
|
-
// `bind` is handled by the dedicated reactivity detection below, which
|
|
1046
|
-
// routes to the hx-v4 bundle (the tier that actually ships reactivity).
|
|
1047
|
-
cmd !== "unless" && cmd !== "bind"
|
|
1048
|
-
);
|
|
1049
|
-
var COMMAND_PATTERN_SOURCE = `\\b(${SCANNABLE_COMMANDS.join("|")})\\b`;
|
|
1101
|
+
var COMMAND_PATTERN_SOURCE = `\\b(${SCANNABLE_KEYWORDS.join("|")})\\b`;
|
|
1050
1102
|
var HTMX_REQUEST_PATTERN = /\b(hx-get|hx-post|hx-put|hx-patch|hx-delete)\s*=\s*["']([^"']+)["']/gi;
|
|
1051
1103
|
var FIXI_ACTION_PATTERN = /\bfx-action\s*=\s*["']([^"']+)["']/gi;
|
|
1052
1104
|
var FIXI_METHOD_PATTERN = /\bfx-method\s*=\s*["'](GET|POST|PUT|PATCH|DELETE)["']/gi;
|
|
@@ -1098,7 +1150,9 @@ var Scanner = class {
|
|
|
1098
1150
|
positional: false,
|
|
1099
1151
|
detectedLanguages: /* @__PURE__ */ new Set(),
|
|
1100
1152
|
needsReactivity: false,
|
|
1101
|
-
needsBindToProperty: false
|
|
1153
|
+
needsBindToProperty: false,
|
|
1154
|
+
needsConstruct: false,
|
|
1155
|
+
needsCookies: false
|
|
1102
1156
|
};
|
|
1103
1157
|
const attrPatterns = [
|
|
1104
1158
|
/_\s*=\s*"([^"]+)"/g,
|
|
@@ -1166,9 +1220,11 @@ var Scanner = class {
|
|
|
1166
1220
|
if (/\bfor\s+(each|every)\b/i.test(script)) usage.blocks.add("for");
|
|
1167
1221
|
if (/\bwhile\b/.test(script)) usage.blocks.add("while");
|
|
1168
1222
|
if (/\bfetch\b/.test(script)) usage.blocks.add("fetch");
|
|
1169
|
-
if (/\b(first|last|next|previous|closest|parent)\b/.test(script)) {
|
|
1223
|
+
if (/\b(first|last|next|previous|closest|parent|random)\b/.test(script) || /\b(where|sorted\s+by|mapped\s+to|split\s+by|joined\s+by|some|beep!)/.test(script)) {
|
|
1170
1224
|
usage.positional = true;
|
|
1171
1225
|
}
|
|
1226
|
+
if (/\bnew\s+[A-Z$_][\w$.]*\s*\(/.test(script)) usage.needsConstruct = true;
|
|
1227
|
+
if (/\bcookies\b/.test(script)) usage.needsCookies = true;
|
|
1172
1228
|
const languages = detectLanguages(script);
|
|
1173
1229
|
for (const lang of languages) {
|
|
1174
1230
|
usage.detectedLanguages.add(lang);
|
|
@@ -1363,7 +1419,8 @@ var Aggregator = class {
|
|
|
1363
1419
|
const positionalEqual = existing.positional === usage.positional;
|
|
1364
1420
|
const languagesEqual = this.setsEqual(existing.detectedLanguages, usage.detectedLanguages);
|
|
1365
1421
|
const htmxEqual = this.htmxUsageEqual(existing.htmx, usage.htmx);
|
|
1366
|
-
|
|
1422
|
+
const flagsEqual = !!existing.needsReactivity === !!usage.needsReactivity && !!existing.needsBindToProperty === !!usage.needsBindToProperty && !!existing.needsConstruct === !!usage.needsConstruct && !!existing.needsCookies === !!usage.needsCookies;
|
|
1423
|
+
if (commandsEqual && blocksEqual && positionalEqual && languagesEqual && htmxEqual && flagsEqual) {
|
|
1367
1424
|
return false;
|
|
1368
1425
|
}
|
|
1369
1426
|
}
|
|
@@ -1411,6 +1468,8 @@ var Aggregator = class {
|
|
|
1411
1468
|
};
|
|
1412
1469
|
let needsReactivity = false;
|
|
1413
1470
|
let needsBindToProperty = false;
|
|
1471
|
+
let needsConstruct = false;
|
|
1472
|
+
let needsCookies = false;
|
|
1414
1473
|
for (const usage of this.fileUsage.values()) {
|
|
1415
1474
|
for (const cmd of usage.commands) commands.add(cmd);
|
|
1416
1475
|
for (const block of usage.blocks) blocks.add(block);
|
|
@@ -1418,6 +1477,8 @@ var Aggregator = class {
|
|
|
1418
1477
|
if (usage.positional) positional = true;
|
|
1419
1478
|
if (usage.needsReactivity) needsReactivity = true;
|
|
1420
1479
|
if (usage.needsBindToProperty) needsBindToProperty = true;
|
|
1480
|
+
if (usage.needsConstruct) needsConstruct = true;
|
|
1481
|
+
if (usage.needsCookies) needsCookies = true;
|
|
1421
1482
|
if (usage.htmx) {
|
|
1422
1483
|
if (usage.htmx.hasHtmxAttributes) htmx.hasHtmxAttributes = true;
|
|
1423
1484
|
if (usage.htmx.hasFixiAttributes) htmx.hasFixiAttributes = true;
|
|
@@ -1446,6 +1507,8 @@ var Aggregator = class {
|
|
|
1446
1507
|
htmx,
|
|
1447
1508
|
needsReactivity,
|
|
1448
1509
|
needsBindToProperty,
|
|
1510
|
+
needsConstruct,
|
|
1511
|
+
needsCookies,
|
|
1449
1512
|
fileUsage: new Map(this.fileUsage)
|
|
1450
1513
|
};
|
|
1451
1514
|
return this.cachedUsage;
|
|
@@ -1500,9 +1563,9 @@ var Aggregator = class {
|
|
|
1500
1563
|
htmxUsageEqual(a, b) {
|
|
1501
1564
|
if (!a && !b) return true;
|
|
1502
1565
|
if (!a || !b) return false;
|
|
1503
|
-
return a.hasHtmxAttributes === b.hasHtmxAttributes && a.hasFixiAttributes === b.hasFixiAttributes && this.setsEqual(a.httpMethods, b.httpMethods) && this.setsEqual(a.swapStrategies, b.swapStrategies) && this.setsEqual(a.triggerModifiers, b.triggerModifiers) && this.setsEqual(a.urlManagement, b.urlManagement) && a.usesConfirm === b.usesConfirm && !!a.needsSwapTiming === !!b.needsSwapTiming && // htmx
|
|
1504
|
-
// so a change must count as "usage changed" or HMR serves a
|
|
1505
|
-
// bundle. They were omitted when the v4 surface landed (#623).
|
|
1566
|
+
return a.hasHtmxAttributes === b.hasHtmxAttributes && a.hasFixiAttributes === b.hasFixiAttributes && this.setsEqual(a.httpMethods, b.httpMethods) && this.setsEqual(a.swapStrategies, b.swapStrategies) && this.setsEqual(a.triggerModifiers, b.triggerModifiers) && this.setsEqual(a.urlManagement, b.urlManagement) && a.usesConfirm === b.usesConfirm && !!a.needsSwapTiming === !!b.needsSwapTiming && // htmx / reactivity flags: these decide which engine modules the bundle
|
|
1567
|
+
// registers, so a change must count as "usage changed" or HMR serves a
|
|
1568
|
+
// stale bundle. They were omitted when the v4 surface landed (#623).
|
|
1506
1569
|
!!a.needsHxLive === !!b.needsHxLive && !!a.needsSSE === !!b.needsSSE && !!a.needsWS === !!b.needsWS && !!a.needsBindToProperty === !!b.needsBindToProperty && !!a.needsReactivity === !!b.needsReactivity && this.arraysEqual(a.onHandlers, b.onHandlers);
|
|
1507
1570
|
}
|
|
1508
1571
|
arraysEqual(a, b) {
|
|
@@ -1512,236 +1575,7 @@ var Aggregator = class {
|
|
|
1512
1575
|
}
|
|
1513
1576
|
};
|
|
1514
1577
|
|
|
1515
|
-
// src/generator.ts
|
|
1516
|
-
import {
|
|
1517
|
-
COMMAND_IMPLEMENTATIONS as COMMAND_IMPL_TS,
|
|
1518
|
-
BLOCK_IMPLEMENTATIONS as BLOCK_IMPL_TS,
|
|
1519
|
-
STYLE_COMMANDS,
|
|
1520
|
-
ELEMENT_ARRAY_COMMANDS,
|
|
1521
|
-
MORPH_COMMANDS,
|
|
1522
|
-
LITE_PARSER_TEMPLATE,
|
|
1523
|
-
HYBRID_PARSER_TEMPLATE,
|
|
1524
|
-
canUseLiteParser,
|
|
1525
|
-
FULL_RUNTIME_ONLY_COMMANDS as FULL_RUNTIME_ONLY_COMMANDS2,
|
|
1526
|
-
isAvailableCommand
|
|
1527
|
-
} from "@hyperfixi/core/bundle-generator";
|
|
1528
|
-
|
|
1529
1578
|
// src/semantic-integration.ts
|
|
1530
|
-
var MULTILINGUAL_COMMAND_ALIASES = {
|
|
1531
|
-
ja: {
|
|
1532
|
-
\u30C8\u30B0\u30EB: "toggle",
|
|
1533
|
-
\u5207\u308A\u66FF\u3048: "toggle",
|
|
1534
|
-
\u8FFD\u52A0: "add",
|
|
1535
|
-
\u524A\u9664: "remove",
|
|
1536
|
-
\u8868\u793A: "show",
|
|
1537
|
-
\u96A0\u3059: "hide",
|
|
1538
|
-
\u975E\u8868\u793A: "hide",
|
|
1539
|
-
\u8A2D\u5B9A: "set",
|
|
1540
|
-
\u30BB\u30C3\u30C8: "set",
|
|
1541
|
-
\u5897\u52A0: "increment",
|
|
1542
|
-
\u6E1B\u5C11: "decrement",
|
|
1543
|
-
\u30ED\u30B0: "log",
|
|
1544
|
-
\u51FA\u529B: "log"
|
|
1545
|
-
},
|
|
1546
|
-
ko: {
|
|
1547
|
-
\uD1A0\uAE00: "toggle",
|
|
1548
|
-
\uC804\uD658: "toggle",
|
|
1549
|
-
\uCD94\uAC00: "add",
|
|
1550
|
-
\uC81C\uAC70: "remove",
|
|
1551
|
-
\uC0AD\uC81C: "remove",
|
|
1552
|
-
\uD45C\uC2DC: "show",
|
|
1553
|
-
\uC228\uAE30\uB2E4: "hide",
|
|
1554
|
-
\uC124\uC815: "set",
|
|
1555
|
-
\uC99D\uAC00: "increment",
|
|
1556
|
-
\uAC10\uC18C: "decrement",
|
|
1557
|
-
\uB85C\uADF8: "log"
|
|
1558
|
-
},
|
|
1559
|
-
zh: {
|
|
1560
|
-
\u5207\u6362: "toggle",
|
|
1561
|
-
\u6DFB\u52A0: "add",
|
|
1562
|
-
\u79FB\u9664: "remove",
|
|
1563
|
-
\u5220\u9664: "remove",
|
|
1564
|
-
\u663E\u793A: "show",
|
|
1565
|
-
\u9690\u85CF: "hide",
|
|
1566
|
-
\u8BBE\u7F6E: "set",
|
|
1567
|
-
\u8BBE\u5B9A: "set",
|
|
1568
|
-
\u589E\u52A0: "increment",
|
|
1569
|
-
\u51CF\u5C11: "decrement",
|
|
1570
|
-
\u65E5\u5FD7: "log",
|
|
1571
|
-
\u8BB0\u5F55: "log"
|
|
1572
|
-
},
|
|
1573
|
-
ar: {
|
|
1574
|
-
\u0628\u062F\u0651\u0644: "toggle",
|
|
1575
|
-
\u0628\u062F\u0644: "toggle",
|
|
1576
|
-
\u0623\u0636\u0641: "add",
|
|
1577
|
-
\u0627\u0636\u0641: "add",
|
|
1578
|
-
\u0623\u0632\u0644: "remove",
|
|
1579
|
-
\u0627\u0632\u0644: "remove",
|
|
1580
|
-
\u0627\u062D\u0630\u0641: "remove",
|
|
1581
|
-
\u0623\u0638\u0647\u0631: "show",
|
|
1582
|
-
\u0627\u0638\u0647\u0631: "show",
|
|
1583
|
-
\u0623\u062E\u0641\u0650: "hide",
|
|
1584
|
-
\u0627\u062E\u0641: "hide",
|
|
1585
|
-
\u0636\u0639: "set",
|
|
1586
|
-
\u0627\u0636\u0639: "set",
|
|
1587
|
-
\u0632\u0650\u062F: "increment",
|
|
1588
|
-
\u0623\u0646\u0642\u0635: "decrement"
|
|
1589
|
-
},
|
|
1590
|
-
es: {
|
|
1591
|
-
alternar: "toggle",
|
|
1592
|
-
a\u00F1adir: "add",
|
|
1593
|
-
agregar: "add",
|
|
1594
|
-
quitar: "remove",
|
|
1595
|
-
eliminar: "remove",
|
|
1596
|
-
mostrar: "show",
|
|
1597
|
-
ocultar: "hide",
|
|
1598
|
-
esconder: "hide",
|
|
1599
|
-
establecer: "set",
|
|
1600
|
-
fijar: "set",
|
|
1601
|
-
incrementar: "increment",
|
|
1602
|
-
decrementar: "decrement"
|
|
1603
|
-
},
|
|
1604
|
-
pt: {
|
|
1605
|
-
alternar: "toggle",
|
|
1606
|
-
adicionar: "add",
|
|
1607
|
-
remover: "remove",
|
|
1608
|
-
mostrar: "show",
|
|
1609
|
-
esconder: "hide",
|
|
1610
|
-
ocultar: "hide",
|
|
1611
|
-
definir: "set",
|
|
1612
|
-
incrementar: "increment",
|
|
1613
|
-
decrementar: "decrement"
|
|
1614
|
-
},
|
|
1615
|
-
fr: {
|
|
1616
|
-
basculer: "toggle",
|
|
1617
|
-
ajouter: "add",
|
|
1618
|
-
supprimer: "remove",
|
|
1619
|
-
retirer: "remove",
|
|
1620
|
-
afficher: "show",
|
|
1621
|
-
montrer: "show",
|
|
1622
|
-
cacher: "hide",
|
|
1623
|
-
masquer: "hide",
|
|
1624
|
-
d\u00E9finir: "set",
|
|
1625
|
-
incr\u00E9menter: "increment",
|
|
1626
|
-
d\u00E9cr\u00E9menter: "decrement"
|
|
1627
|
-
},
|
|
1628
|
-
de: {
|
|
1629
|
-
umschalten: "toggle",
|
|
1630
|
-
hinzuf\u00FCgen: "add",
|
|
1631
|
-
entfernen: "remove",
|
|
1632
|
-
l\u00F6schen: "remove",
|
|
1633
|
-
anzeigen: "show",
|
|
1634
|
-
zeigen: "show",
|
|
1635
|
-
verbergen: "hide",
|
|
1636
|
-
verstecken: "hide",
|
|
1637
|
-
setzen: "set",
|
|
1638
|
-
festlegen: "set",
|
|
1639
|
-
erh\u00F6hen: "increment",
|
|
1640
|
-
verringern: "decrement"
|
|
1641
|
-
},
|
|
1642
|
-
tr: {
|
|
1643
|
-
de\u011Fi\u015Ftir: "toggle",
|
|
1644
|
-
de\u011Fistir: "toggle",
|
|
1645
|
-
ekle: "add",
|
|
1646
|
-
kald\u0131r: "remove",
|
|
1647
|
-
kaldir: "remove",
|
|
1648
|
-
sil: "remove",
|
|
1649
|
-
g\u00F6ster: "show",
|
|
1650
|
-
gizle: "hide",
|
|
1651
|
-
sakla: "hide",
|
|
1652
|
-
ayarla: "set",
|
|
1653
|
-
belirle: "set",
|
|
1654
|
-
artt\u0131r: "increment",
|
|
1655
|
-
azalt: "decrement"
|
|
1656
|
-
},
|
|
1657
|
-
id: {
|
|
1658
|
-
alih: "toggle",
|
|
1659
|
-
beralih: "toggle",
|
|
1660
|
-
tambah: "add",
|
|
1661
|
-
hapus: "remove",
|
|
1662
|
-
buang: "remove",
|
|
1663
|
-
tampilkan: "show",
|
|
1664
|
-
sembunyikan: "hide",
|
|
1665
|
-
atur: "set",
|
|
1666
|
-
tetapkan: "set",
|
|
1667
|
-
tambahkan: "increment",
|
|
1668
|
-
kurangi: "decrement"
|
|
1669
|
-
},
|
|
1670
|
-
sw: {
|
|
1671
|
-
badilisha: "toggle",
|
|
1672
|
-
ongeza: "add",
|
|
1673
|
-
ondoa: "remove",
|
|
1674
|
-
futa: "remove",
|
|
1675
|
-
onyesha: "show",
|
|
1676
|
-
ficha: "hide",
|
|
1677
|
-
weka: "set",
|
|
1678
|
-
sanidi: "set",
|
|
1679
|
-
ongezea: "increment",
|
|
1680
|
-
punguza: "decrement"
|
|
1681
|
-
},
|
|
1682
|
-
qu: {
|
|
1683
|
-
tikray: "toggle",
|
|
1684
|
-
yapay: "add",
|
|
1685
|
-
qichuy: "remove",
|
|
1686
|
-
pichay: "remove",
|
|
1687
|
-
rikuchiy: "show",
|
|
1688
|
-
pakay: "hide",
|
|
1689
|
-
churay: "set",
|
|
1690
|
-
pisiyachiy: "decrement"
|
|
1691
|
-
}
|
|
1692
|
-
};
|
|
1693
|
-
function getMultilingualCommandAliases(languages) {
|
|
1694
|
-
const aliases = {};
|
|
1695
|
-
for (const lang of languages) {
|
|
1696
|
-
const langAliases = MULTILINGUAL_COMMAND_ALIASES[lang];
|
|
1697
|
-
if (langAliases) {
|
|
1698
|
-
Object.assign(aliases, langAliases);
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
return aliases;
|
|
1702
|
-
}
|
|
1703
|
-
function generateMultilingualAliases(languages) {
|
|
1704
|
-
const aliases = {};
|
|
1705
|
-
for (const lang of languages) {
|
|
1706
|
-
const langAliases = MULTILINGUAL_COMMAND_ALIASES[lang];
|
|
1707
|
-
if (langAliases) {
|
|
1708
|
-
Object.assign(aliases, langAliases);
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
if (Object.keys(aliases).length === 0) {
|
|
1712
|
-
return `
|
|
1713
|
-
// No multilingual aliases needed - just pass through
|
|
1714
|
-
function preprocessMultilingual(code) { return code; }
|
|
1715
|
-
`;
|
|
1716
|
-
}
|
|
1717
|
-
const aliasEntries = Object.entries(aliases).map(([key, val]) => ` '${key}': '${val}'`).join(",\n");
|
|
1718
|
-
const escapedKeys = Object.keys(aliases).map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
1719
|
-
return `
|
|
1720
|
-
// Multilingual command aliases for HybridParser fallback
|
|
1721
|
-
const MULTILINGUAL_ALIASES = {
|
|
1722
|
-
${aliasEntries}
|
|
1723
|
-
};
|
|
1724
|
-
|
|
1725
|
-
// Register multilingual aliases with the parser
|
|
1726
|
-
addCommandAliases(MULTILINGUAL_ALIASES);
|
|
1727
|
-
|
|
1728
|
-
// Preprocessing regex to translate multilingual keywords to English
|
|
1729
|
-
// The HybridParser tokenizer only accepts ASCII identifiers, so we need
|
|
1730
|
-
// to translate non-ASCII keywords before parsing.
|
|
1731
|
-
const MULTILINGUAL_KEYWORD_REGEX = new RegExp('(^|\\\\s)(${escapedKeys})(?=\\\\s|\\\\.|$)', 'g');
|
|
1732
|
-
|
|
1733
|
-
/**
|
|
1734
|
-
* Preprocess multilingual code to replace non-ASCII keywords with English equivalents.
|
|
1735
|
-
* This is needed because HybridParser's tokenizer only accepts ASCII identifiers.
|
|
1736
|
-
*/
|
|
1737
|
-
function preprocessMultilingual(code) {
|
|
1738
|
-
return code.replace(MULTILINGUAL_KEYWORD_REGEX, (match, prefix, keyword) => {
|
|
1739
|
-
const english = MULTILINGUAL_ALIASES[keyword];
|
|
1740
|
-
return english ? prefix + english : match;
|
|
1741
|
-
});
|
|
1742
|
-
}
|
|
1743
|
-
`;
|
|
1744
|
-
}
|
|
1745
1579
|
function resolveSemanticConfig(options, detectedLanguages) {
|
|
1746
1580
|
const grammarEnabled = options.grammar ?? false;
|
|
1747
1581
|
let semanticEnabled = grammarEnabled;
|
|
@@ -1957,15 +1791,11 @@ function generateSemanticIntegrationCode(config) {
|
|
|
1957
1791
|
const languages = [...config.languages].join("', '");
|
|
1958
1792
|
let code = `
|
|
1959
1793
|
// =============================================================================
|
|
1960
|
-
//
|
|
1794
|
+
// MULTILINGUAL (semantic) \u2014 translated as read; the attribute stays as written
|
|
1961
1795
|
// =============================================================================
|
|
1962
1796
|
|
|
1963
1797
|
// Core infrastructure (no language data bundled)
|
|
1964
|
-
import {
|
|
1965
|
-
parseWithConfidence,
|
|
1966
|
-
buildAST,
|
|
1967
|
-
isLanguageSupported,
|
|
1968
|
-
} from '@lokascript/semantic/core';
|
|
1798
|
+
import { parseWithConfidence, render, isLanguageRegistered } from '@lokascript/semantic/core';
|
|
1969
1799
|
|
|
1970
1800
|
// Register required languages (self-registering side-effect imports)
|
|
1971
1801
|
`;
|
|
@@ -1979,58 +1809,36 @@ import {
|
|
|
1979
1809
|
import { translate } from '@lokascript/semantic/core';
|
|
1980
1810
|
`;
|
|
1981
1811
|
}
|
|
1982
|
-
const aliasesCode = generateMultilingualAliases(config.languages);
|
|
1983
1812
|
code += `
|
|
1984
1813
|
const SUPPORTED_SEMANTIC_LANGUAGES = ['${languages}', 'en'];
|
|
1985
1814
|
const SEMANTIC_CONFIDENCE_THRESHOLD = 0.7;
|
|
1986
1815
|
|
|
1987
|
-
|
|
1816
|
+
/** The element's language: data-lang, data-hyperscript-lang, the lang cascade, the document's. */
|
|
1817
|
+
function resolveLanguage(elt) {
|
|
1818
|
+
const code =
|
|
1819
|
+
elt.getAttribute('data-lang') ||
|
|
1820
|
+
elt.closest?.('[data-hyperscript-lang]')?.getAttribute('data-hyperscript-lang') ||
|
|
1821
|
+
elt.closest?.('[lang]')?.getAttribute('lang') ||
|
|
1822
|
+
(typeof document !== 'undefined' ? document.documentElement?.lang : null);
|
|
1823
|
+
return code ? code.toLowerCase().split(/[-_]/)[0] : null;
|
|
1824
|
+
}
|
|
1988
1825
|
|
|
1989
1826
|
/**
|
|
1990
|
-
*
|
|
1991
|
-
*
|
|
1992
|
-
*
|
|
1993
|
-
*
|
|
1994
|
-
* @param code - The hyperscript code to parse
|
|
1995
|
-
* @param lang - Optional language hint. If provided, tries this language first.
|
|
1827
|
+
* The engine's source transform: the English for a non-English script, or null
|
|
1828
|
+
* to leave the script as written (English, an unregistered language, a parse
|
|
1829
|
+
* below the confidence threshold, or a render that changed nothing).
|
|
1996
1830
|
*/
|
|
1997
|
-
function
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
}
|
|
2006
|
-
|
|
2007
|
-
// Try each language until one succeeds
|
|
2008
|
-
for (const tryLang of languagesToTry) {
|
|
2009
|
-
if (!isLanguageSupported(tryLang)) continue;
|
|
2010
|
-
try {
|
|
2011
|
-
const result = parseWithConfidence(code, tryLang);
|
|
2012
|
-
if (result && result.confidence >= SEMANTIC_CONFIDENCE_THRESHOLD) {
|
|
2013
|
-
// buildAST returns {ast, warnings} - extract the ast
|
|
2014
|
-
const buildResult = buildAST(result.node);
|
|
2015
|
-
const ast = buildResult.ast;
|
|
2016
|
-
|
|
2017
|
-
// Semantic parser doesn't fully handle event handlers - fallback to HybridParser
|
|
2018
|
-
// Event handlers like "on click toggle .active" produce incomplete AST
|
|
2019
|
-
if (ast && ast.type === 'command' && ast.name === 'on') {
|
|
2020
|
-
break; // Fallback to HybridParser
|
|
2021
|
-
}
|
|
2022
|
-
|
|
2023
|
-
return ast;
|
|
2024
|
-
}
|
|
2025
|
-
} catch (e) {
|
|
2026
|
-
// Continue trying other languages
|
|
2027
|
-
}
|
|
1831
|
+
function translateSource(src, elt) {
|
|
1832
|
+
const lang = elt ? resolveLanguage(elt) : null;
|
|
1833
|
+
if (!lang || lang === 'en' || !isLanguageRegistered(lang)) return null;
|
|
1834
|
+
try {
|
|
1835
|
+
const result = parseWithConfidence(src, lang);
|
|
1836
|
+
if (!result || !result.node || result.confidence < SEMANTIC_CONFIDENCE_THRESHOLD) return null;
|
|
1837
|
+
const english = render(result.node, 'en');
|
|
1838
|
+
return english && english !== src ? english : null;
|
|
1839
|
+
} catch {
|
|
1840
|
+
return null;
|
|
2028
1841
|
}
|
|
2029
|
-
|
|
2030
|
-
// Fallback to HybridParser for event handlers and unrecognized patterns
|
|
2031
|
-
// Preprocess to translate non-ASCII keywords to English (tokenizer only accepts ASCII)
|
|
2032
|
-
const preprocessedCode = preprocessMultilingual(code);
|
|
2033
|
-
return new HybridParser(preprocessedCode).parse();
|
|
2034
1842
|
}
|
|
2035
1843
|
`;
|
|
2036
1844
|
if (config.grammarEnabled) {
|
|
@@ -2040,9 +1848,7 @@ function parseWithSemantic(code, lang = null) {
|
|
|
2040
1848
|
*
|
|
2041
1849
|
* Returns the input UNCHANGED when it cannot be parsed in \`fromLang\`, or when
|
|
2042
1850
|
* \`toLang\` is not one of the languages this bundle registered. The semantic
|
|
2043
|
-
* translator throws in both cases; the
|
|
2044
|
-
* degraded to word substitution, which turned unparseable input into plausible
|
|
2045
|
-
* nonsense. Returning the source is the honest degradation.
|
|
1851
|
+
* translator throws in both cases; returning the source is the honest degradation.
|
|
2046
1852
|
*/
|
|
2047
1853
|
function translateHyperscript(code, fromLang, toLang) {
|
|
2048
1854
|
try {
|
|
@@ -2058,7 +1864,7 @@ function translateHyperscript(code, fromLang, toLang) {
|
|
|
2058
1864
|
function getSemanticExports(config) {
|
|
2059
1865
|
const exports = [];
|
|
2060
1866
|
if (config.enabled) {
|
|
2061
|
-
exports.push("
|
|
1867
|
+
exports.push("translateSource");
|
|
2062
1868
|
exports.push("SUPPORTED_SEMANTIC_LANGUAGES");
|
|
2063
1869
|
}
|
|
2064
1870
|
if (config.grammarEnabled) {
|
|
@@ -2068,421 +1874,77 @@ function getSemanticExports(config) {
|
|
|
2068
1874
|
}
|
|
2069
1875
|
|
|
2070
1876
|
// src/generator.ts
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
/:\s*(?:string|number|boolean|any|unknown|void|never|null|undefined|object|symbol|bigint)(?=\s*[=;,)\]])/g,
|
|
2074
|
-
""
|
|
2075
|
-
).replace(/:\s*[A-Z]\w*(?:\[\])?(?=\s*[=;,)\]])/g, "").replace(/\((\w+):\s*(?:\w+|unknown|any)\)/g, "($1)").replace(/Promise<[^>]+>/g, "Promise").replace(/Array<[^>]+>/g, "Array").replace(/\):\s*\w+(?:<[^>]*>)?(?:\[\])?\s*(?=[{=])/g, ") ").replace(/\):\s*\w+(?:<[^>]*>)?\s*=>/g, ") =>").replace(
|
|
2076
|
-
/:\s*(?:TransitionEvent|MouseEvent|KeyboardEvent|Event|Element|HTMLElement|Node)(?=\s*[=;,)\]])/g,
|
|
2077
|
-
""
|
|
2078
|
-
).replace(/(\w)!(?=[,;)\].\s])/g, "$1");
|
|
2079
|
-
}
|
|
2080
|
-
var COMMAND_IMPLEMENTATIONS = {};
|
|
2081
|
-
var BLOCK_IMPLEMENTATIONS = {};
|
|
2082
|
-
for (const [name, code] of Object.entries(COMMAND_IMPL_TS)) {
|
|
2083
|
-
COMMAND_IMPLEMENTATIONS[name] = stripTypes(code);
|
|
2084
|
-
}
|
|
2085
|
-
for (const [name, code] of Object.entries(BLOCK_IMPL_TS)) {
|
|
2086
|
-
BLOCK_IMPLEMENTATIONS[name] = stripTypes(code);
|
|
2087
|
-
}
|
|
2088
|
-
function generateBundleCode(config) {
|
|
1877
|
+
var ENGINE_API_NAMES = ["api", "boot", "register"];
|
|
1878
|
+
function generateBundleCode(spec) {
|
|
2089
1879
|
const {
|
|
2090
1880
|
name,
|
|
1881
|
+
modules,
|
|
2091
1882
|
commands,
|
|
2092
|
-
blocks
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
const
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
2104
|
-
const
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
1883
|
+
blocks,
|
|
1884
|
+
positional,
|
|
1885
|
+
reactivity,
|
|
1886
|
+
htmxIntegration,
|
|
1887
|
+
globalName,
|
|
1888
|
+
autoInit,
|
|
1889
|
+
esModule,
|
|
1890
|
+
semantic
|
|
1891
|
+
} = spec;
|
|
1892
|
+
const semanticCode = generateSemanticIntegrationCode(semantic);
|
|
1893
|
+
const semanticExports = getSemanticExports(semantic);
|
|
1894
|
+
const languages = semantic.enabled ? [...semantic.languages].sort() : [];
|
|
1895
|
+
const headerLines = [
|
|
1896
|
+
`Modules: ${modules.join(", ")}`,
|
|
1897
|
+
commands.length > 0 ? `Commands: ${commands.join(", ")}` : "",
|
|
1898
|
+
blocks.length > 0 ? `Blocks: ${blocks.join(", ")}` : "",
|
|
1899
|
+
positional ? "Expressions: positional / collection (expressionsExtra)" : "",
|
|
1900
|
+
reactivity ? "Reactivity: live / when / bind" : "",
|
|
1901
|
+
semantic.enabled ? `Multilingual: ${languages.join(", ") || "en"} (translated as read, through the engine's source transform)` : "",
|
|
1902
|
+
htmxIntegration ? "htmx: content swapped in is processed (htmx:load / htmx:afterSettle)" : ""
|
|
1903
|
+
].filter(Boolean);
|
|
1904
|
+
const bundleInfo = JSON.stringify({
|
|
1905
|
+
generator: "@hyperfixi/vite-plugin",
|
|
1906
|
+
modules,
|
|
1907
|
+
commands,
|
|
1908
|
+
blocks,
|
|
1909
|
+
languages
|
|
1910
|
+
});
|
|
1911
|
+
const apiProps = [`bundle: ${bundleInfo}`, ...semanticExports].map((p) => ` ${p},`).join("\n");
|
|
1912
|
+
const installGlobal = globalName === "_hyperscript" ? "" : ` window.${globalName} = api;
|
|
1913
|
+
`;
|
|
1914
|
+
const htmxHooks = htmxIntegration ? `
|
|
1915
|
+
// htmx (any major) announces swapped-in content on these; hand it to the engine.
|
|
1916
|
+
for (const type of ['htmx:load', 'htmx:afterSettle']) {
|
|
1917
|
+
document.addEventListener(type, event => {
|
|
1918
|
+
const detail = event.detail;
|
|
1919
|
+
const target = (detail && (detail.elt || detail.target)) || event.target;
|
|
1920
|
+
if (target instanceof Element) api.processNode(target);
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
2110
1923
|
` : "";
|
|
2111
1924
|
return `/**
|
|
2112
|
-
*
|
|
1925
|
+
* hyperfixi ${name} bundle (auto-generated)
|
|
2113
1926
|
*
|
|
2114
1927
|
* Generated by: @hyperfixi/vite-plugin
|
|
2115
|
-
*
|
|
2116
|
-
*
|
|
2117
|
-
* Blocks: ${blocks.join(", ")}` : ""}${positionalExpressions ? "\n * Positional expressions: enabled" : ""}${needsMorphlex ? "\n * Morphing: morphlex (~2.5KB)" : ""}
|
|
1928
|
+
* Engine: @hyperfixi/engine \u2014 the grammar is exactly the modules registered below.
|
|
1929
|
+
${headerLines.map((l) => ` * ${l}`).join("\n")}
|
|
2118
1930
|
*
|
|
2119
1931
|
* DO NOT EDIT - This file is automatically regenerated.
|
|
2120
1932
|
*/
|
|
2121
1933
|
|
|
2122
|
-
${
|
|
2123
|
-
${
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
${
|
|
2128
|
-
|
|
2129
|
-
async function evaluate(node, ctx) {
|
|
2130
|
-
switch (node.type) {
|
|
2131
|
-
case 'literal': return node.value;
|
|
2132
|
-
|
|
2133
|
-
case 'identifier':
|
|
2134
|
-
if (node.value === 'me' || node.value === 'my') return ctx.me;
|
|
2135
|
-
if (node.value === 'it') return ctx.it;
|
|
2136
|
-
if (node.value === 'you') return ctx.you;
|
|
2137
|
-
if (node.value === 'event') return ctx.event;
|
|
2138
|
-
if (node.value === 'body') return document.body;
|
|
2139
|
-
if (node.value === 'document') return document;
|
|
2140
|
-
if (node.value === 'window') return window;
|
|
2141
|
-
if (ctx.locals.has(node.value)) return ctx.locals.get(node.value);
|
|
2142
|
-
if (node.value in ctx.me) return ctx.me[node.value];
|
|
2143
|
-
return node.value;
|
|
2144
|
-
|
|
2145
|
-
case 'contextReference':
|
|
2146
|
-
// Semantic AST format for context references (me, you, it, etc.)
|
|
2147
|
-
switch (node.contextType || node.name) {
|
|
2148
|
-
case 'me': return ctx.me;
|
|
2149
|
-
case 'it': return ctx.it;
|
|
2150
|
-
case 'you': return ctx.you;
|
|
2151
|
-
case 'event': return ctx.event;
|
|
2152
|
-
case 'body': return document.body;
|
|
2153
|
-
case 'document': return document;
|
|
2154
|
-
case 'window': return window;
|
|
2155
|
-
default: return ctx.me;
|
|
2156
|
-
}
|
|
2157
|
-
|
|
2158
|
-
case 'variable':
|
|
2159
|
-
if (node.scope === 'local') return ctx.locals.get(node.name.slice(1));
|
|
2160
|
-
const gName = node.name.slice(1);
|
|
2161
|
-
if (globalVars.has(gName)) return globalVars.get(gName);
|
|
2162
|
-
return window[node.name];
|
|
2163
|
-
|
|
2164
|
-
case 'selector':
|
|
2165
|
-
const elements = document.querySelectorAll(node.value);
|
|
2166
|
-
return elements.length === 1 ? elements[0] : Array.from(elements);
|
|
2167
|
-
|
|
2168
|
-
case 'binary':
|
|
2169
|
-
return evaluateBinary(node, ctx);
|
|
2170
|
-
|
|
2171
|
-
case 'possessive':
|
|
2172
|
-
case 'member':
|
|
2173
|
-
const obj = await evaluate(node.object, ctx);
|
|
2174
|
-
if (obj == null) return undefined;
|
|
2175
|
-
const prop = node.computed ? await evaluate(node.property, ctx) : node.property;
|
|
2176
|
-
if (prop === 'values' && obj instanceof Element) {
|
|
2177
|
-
if (obj instanceof HTMLFormElement) return new FormData(obj);
|
|
2178
|
-
const fd = new FormData();
|
|
2179
|
-
obj.querySelectorAll('input, select, textarea').forEach(input => {
|
|
2180
|
-
const name = input.getAttribute('name');
|
|
2181
|
-
if (name && 'value' in input) fd.append(name, input.value);
|
|
2182
|
-
});
|
|
2183
|
-
return fd;
|
|
2184
|
-
}
|
|
2185
|
-
return obj[prop];
|
|
2186
|
-
|
|
2187
|
-
case 'call': {
|
|
2188
|
-
let callContext = null;
|
|
2189
|
-
let callee;
|
|
2190
|
-
|
|
2191
|
-
if (node.callee.type === 'member' || node.callee.type === 'possessive') {
|
|
2192
|
-
callContext = await evaluate(node.callee.object, ctx);
|
|
2193
|
-
const p = node.callee.computed
|
|
2194
|
-
? await evaluate(node.callee.property, ctx)
|
|
2195
|
-
: node.callee.property;
|
|
2196
|
-
callee = callContext?.[p];
|
|
2197
|
-
} else {
|
|
2198
|
-
callee = await evaluate(node.callee, ctx);
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
|
-
const args = await Promise.all(node.args.map(a => evaluate(a, ctx)));
|
|
2202
|
-
if (typeof callee === 'function') return callee.apply(callContext, args);
|
|
2203
|
-
return undefined;
|
|
2204
|
-
}
|
|
2205
|
-
${positionalExpressions ? `
|
|
2206
|
-
case 'positional':
|
|
2207
|
-
return evaluatePositional(node, ctx);
|
|
2208
|
-
` : ""}
|
|
2209
|
-
default: return undefined;
|
|
2210
|
-
}
|
|
2211
|
-
}
|
|
2212
|
-
|
|
2213
|
-
async function evaluateBinary(node, ctx) {
|
|
2214
|
-
if (node.operator === 'has') {
|
|
2215
|
-
const left = await evaluate(node.left, ctx);
|
|
2216
|
-
if (left instanceof Element && node.right.type === 'selector' && node.right.value.startsWith('.')) {
|
|
2217
|
-
return left.classList.contains(node.right.value.slice(1));
|
|
2218
|
-
}
|
|
2219
|
-
return false;
|
|
2220
|
-
}
|
|
2221
|
-
|
|
2222
|
-
const left = await evaluate(node.left, ctx);
|
|
2223
|
-
const right = await evaluate(node.right, ctx);
|
|
2224
|
-
|
|
2225
|
-
switch (node.operator) {
|
|
2226
|
-
case '+': return left + right;
|
|
2227
|
-
case '-': return left - right;
|
|
2228
|
-
case '*': return left * right;
|
|
2229
|
-
case '/': return left / right;
|
|
2230
|
-
case '%': return left % right;
|
|
2231
|
-
case '==': case 'is': return left == right;
|
|
2232
|
-
case '!=': case 'is not': return left != right;
|
|
2233
|
-
case '<': return left < right;
|
|
2234
|
-
case '>': return left > right;
|
|
2235
|
-
case '<=': return left <= right;
|
|
2236
|
-
case '>=': return left >= right;
|
|
2237
|
-
case 'and': case '&&': return left && right;
|
|
2238
|
-
case 'or': case '||': return left || right;
|
|
2239
|
-
case 'contains': case 'includes':
|
|
2240
|
-
if (typeof left === 'string') return left.includes(right);
|
|
2241
|
-
if (Array.isArray(left)) return left.includes(right);
|
|
2242
|
-
if (left instanceof Element) return left.contains(right);
|
|
2243
|
-
return false;
|
|
2244
|
-
case 'matches':
|
|
2245
|
-
if (left instanceof Element) return left.matches(right);
|
|
2246
|
-
if (typeof left === 'string') return new RegExp(right).test(left);
|
|
2247
|
-
return false;
|
|
2248
|
-
default: return undefined;
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
${positionalExpressions ? `
|
|
2252
|
-
function evaluatePositional(node, ctx) {
|
|
2253
|
-
const target = node.target;
|
|
2254
|
-
let elements = [];
|
|
2255
|
-
|
|
2256
|
-
let selector = null;
|
|
2257
|
-
if (target.type === 'selector') {
|
|
2258
|
-
selector = target.value;
|
|
2259
|
-
} else if (target.type === 'identifier') {
|
|
2260
|
-
selector = target.value;
|
|
2261
|
-
} else if (target.type === 'htmlSelector') {
|
|
2262
|
-
selector = target.value;
|
|
2263
|
-
}
|
|
2264
|
-
if (selector) {
|
|
2265
|
-
elements = Array.from(document.querySelectorAll(selector));
|
|
2266
|
-
}
|
|
2267
|
-
|
|
2268
|
-
switch (node.position) {
|
|
2269
|
-
case 'first': return elements[0] || null;
|
|
2270
|
-
case 'last': return elements[elements.length - 1] || null;
|
|
2271
|
-
case 'next': return ctx.me.nextElementSibling;
|
|
2272
|
-
case 'previous': return ctx.me.previousElementSibling;
|
|
2273
|
-
case 'closest': return target.value ? ctx.me.closest(target.value) : null;
|
|
2274
|
-
case 'parent': return ctx.me.parentElement;
|
|
2275
|
-
default: return elements[0] || null;
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
` : ""}
|
|
2279
|
-
${needsStyleHelpers ? `
|
|
2280
|
-
const isStyleProp = (prop) => prop?.startsWith('*');
|
|
2281
|
-
const getStyleName = (prop) => prop.substring(1);
|
|
2282
|
-
const setStyleProp = (el, prop, value) => {
|
|
2283
|
-
if (!isStyleProp(prop)) return false;
|
|
2284
|
-
el.style.setProperty(getStyleName(prop), String(value));
|
|
2285
|
-
return true;
|
|
2286
|
-
};
|
|
2287
|
-
` : ""}
|
|
2288
|
-
|
|
2289
|
-
${needsElementArrayHelper ? `
|
|
2290
|
-
const toElementArray = (val) => {
|
|
2291
|
-
if (Array.isArray(val)) return val.filter(e => e instanceof Element);
|
|
2292
|
-
if (val instanceof Element) return [val];
|
|
2293
|
-
if (typeof val === 'string') return Array.from(document.querySelectorAll(val));
|
|
2294
|
-
return [];
|
|
2295
|
-
};
|
|
2296
|
-
` : ""}
|
|
2297
|
-
|
|
2298
|
-
async function executeCommand(cmd, ctx) {
|
|
2299
|
-
const getTarget = async () => {
|
|
2300
|
-
// Support both HybridParser (cmd.target) and semantic AST (cmd.modifiers.on) formats
|
|
2301
|
-
const target = cmd.target || cmd.modifiers?.on;
|
|
2302
|
-
if (!target) return [ctx.me];
|
|
2303
|
-
const t = await evaluate(target, ctx);
|
|
2304
|
-
if (Array.isArray(t)) return t;
|
|
2305
|
-
if (t instanceof Element) return [t];
|
|
2306
|
-
if (typeof t === 'string') return Array.from(document.querySelectorAll(t));
|
|
2307
|
-
return [ctx.me];
|
|
2308
|
-
};
|
|
2309
|
-
|
|
2310
|
-
const getClassName = (node) => {
|
|
2311
|
-
if (!node) return '';
|
|
2312
|
-
if (node.type === 'selector') return node.value.slice(1);
|
|
2313
|
-
if (node.type === 'string' || node.type === 'literal') {
|
|
2314
|
-
const val = node.value;
|
|
2315
|
-
return typeof val === 'string' && val.startsWith('.') ? val.slice(1) : String(val);
|
|
2316
|
-
}
|
|
2317
|
-
if (node.type === 'identifier') return node.value;
|
|
2318
|
-
return '';
|
|
2319
|
-
};
|
|
2320
|
-
|
|
2321
|
-
switch (cmd.name) {
|
|
2322
|
-
${commandCases}
|
|
2323
|
-
|
|
2324
|
-
default:
|
|
2325
|
-
console.warn(\`${name} bundle: Unknown command '\${cmd.name}'\`);
|
|
2326
|
-
return null;
|
|
2327
|
-
}
|
|
2328
|
-
}
|
|
2329
|
-
${hasBlocks ? `
|
|
2330
|
-
async function executeBlock(block, ctx) {
|
|
2331
|
-
switch (block.type) {
|
|
2332
|
-
${blockCases}
|
|
2333
|
-
|
|
2334
|
-
default:
|
|
2335
|
-
console.warn(\`${name} bundle: Unknown block '\${block.type}'\`);
|
|
2336
|
-
return null;
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
` : ""}
|
|
2340
|
-
async function executeSequence(nodes, ctx) {
|
|
2341
|
-
let result;
|
|
2342
|
-
for (const node of nodes) {
|
|
2343
|
-
if (node.type === 'command') {
|
|
2344
|
-
result = await executeCommand(node, ctx);
|
|
2345
|
-
}${hasBlocks ? ` else if (['if', 'repeat', 'for', 'while', 'fetch'].includes(node.type)) {
|
|
2346
|
-
result = await executeBlock(node, ctx);
|
|
2347
|
-
}` : ""}
|
|
2348
|
-
}
|
|
2349
|
-
return result;
|
|
2350
|
-
}
|
|
2351
|
-
${hasBlocks ? `
|
|
2352
|
-
async function executeSequenceWithBlocks(nodes, ctx) {
|
|
2353
|
-
try {
|
|
2354
|
-
return await executeSequence(nodes, ctx);
|
|
2355
|
-
} catch (e) {
|
|
2356
|
-
if (e?.type === 'return') throw e;
|
|
2357
|
-
throw e;
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
` : ""}
|
|
2361
|
-
async function executeAST(ast, me, event) {
|
|
2362
|
-
const ctx = { me, event, locals: new Map() };
|
|
2363
|
-
|
|
2364
|
-
if (ast.type === 'sequence') {
|
|
2365
|
-
${hasReturn || hasBlocks ? "try { return await executeSequence(ast.commands, ctx); } catch (e) { if (e?.type === 'return') return e.value; throw e; }" : "return executeSequence(ast.commands, ctx);"}
|
|
2366
|
-
}
|
|
2367
|
-
|
|
2368
|
-
if (ast.type === 'event') {
|
|
2369
|
-
const eventNode = ast;
|
|
2370
|
-
const eventName = eventNode.event;
|
|
2371
|
-
|
|
2372
|
-
if (eventName === 'init') {
|
|
2373
|
-
${hasReturn || hasBlocks ? "try { await executeSequence(eventNode.body, ctx); } catch (e) { if (e?.type !== 'return') throw e; }" : "await executeSequence(eventNode.body, ctx);"}
|
|
2374
|
-
return;
|
|
2375
|
-
}
|
|
2376
|
-
|
|
2377
|
-
const target = eventNode.filter ? await evaluate(eventNode.filter, ctx) : me;
|
|
2378
|
-
const targetEl = target instanceof Element ? target : me;
|
|
2379
|
-
const mods = eventNode.modifiers;
|
|
2380
|
-
|
|
2381
|
-
let handler = async (e) => {
|
|
2382
|
-
if (mods.prevent) e.preventDefault();
|
|
2383
|
-
if (mods.stop) e.stopPropagation();
|
|
2384
|
-
|
|
2385
|
-
const handlerCtx = {
|
|
2386
|
-
me, event: e,
|
|
2387
|
-
you: e.target instanceof Element ? e.target : undefined,
|
|
2388
|
-
locals: new Map(),
|
|
2389
|
-
};
|
|
2390
|
-
${hasReturn || hasBlocks ? "try { await executeSequence(eventNode.body, handlerCtx); } catch (err) { if (err?.type !== 'return') throw err; }" : "await executeSequence(eventNode.body, handlerCtx);"}
|
|
2391
|
-
};
|
|
2392
|
-
|
|
2393
|
-
if (mods.debounce) {
|
|
2394
|
-
let timeout;
|
|
2395
|
-
const orig = handler;
|
|
2396
|
-
handler = async (e) => {
|
|
2397
|
-
clearTimeout(timeout);
|
|
2398
|
-
timeout = setTimeout(() => orig(e), mods.debounce);
|
|
2399
|
-
};
|
|
2400
|
-
}
|
|
2401
|
-
|
|
2402
|
-
if (mods.throttle) {
|
|
2403
|
-
let lastCall = 0;
|
|
2404
|
-
const orig = handler;
|
|
2405
|
-
handler = async (e) => {
|
|
2406
|
-
const now = Date.now();
|
|
2407
|
-
if (now - lastCall >= mods.throttle) {
|
|
2408
|
-
lastCall = now;
|
|
2409
|
-
await orig(e);
|
|
2410
|
-
}
|
|
2411
|
-
};
|
|
2412
|
-
}
|
|
2413
|
-
|
|
2414
|
-
targetEl.addEventListener(eventName, handler, { once: !!mods.once });
|
|
2415
|
-
return;
|
|
2416
|
-
}
|
|
2417
|
-
|
|
2418
|
-
// Handle single command (not wrapped in event or sequence)
|
|
2419
|
-
if (ast.type === 'command') {
|
|
2420
|
-
return executeCommand(ast, ctx);
|
|
2421
|
-
}
|
|
2422
|
-
|
|
2423
|
-
return null;
|
|
2424
|
-
}
|
|
2425
|
-
|
|
2426
|
-
function processElement(el) {
|
|
2427
|
-
const code = el.getAttribute('_');
|
|
2428
|
-
if (!code) return;
|
|
2429
|
-
|
|
2430
|
-
try {
|
|
2431
|
-
const ast = ${parserType === "lite" ? "parseLite(code)" : "new HybridParser(code).parse()"};
|
|
2432
|
-
executeAST(ast, el);
|
|
2433
|
-
} catch (err) {
|
|
2434
|
-
console.error('LokaScript ${name} error:', err, 'Code:', code);
|
|
2435
|
-
}
|
|
2436
|
-
}
|
|
2437
|
-
|
|
2438
|
-
function processElements(root = document) {
|
|
2439
|
-
const elements = root.querySelectorAll('[_]');
|
|
2440
|
-
elements.forEach(processElement);
|
|
2441
|
-
}
|
|
2442
|
-
|
|
2443
|
-
const api = {
|
|
2444
|
-
version: '1.0.0-${name.toLowerCase().replace(/\s+/g, "-")}',
|
|
2445
|
-
|
|
2446
|
-
parse(code) {
|
|
2447
|
-
return ${parserType === "lite" ? "parseLite(code)" : "new HybridParser(code).parse()"};
|
|
2448
|
-
},
|
|
2449
|
-
|
|
2450
|
-
async execute(code, element) {
|
|
2451
|
-
const me = element || document.body;
|
|
2452
|
-
const ast = ${parserType === "lite" ? "parseLite(code)" : "new HybridParser(code).parse()"};
|
|
2453
|
-
return executeAST(ast, me);
|
|
2454
|
-
},
|
|
2455
|
-
|
|
2456
|
-
run: async (code, element) => api.execute(code, element),
|
|
2457
|
-
eval: async (code, element) => api.execute(code, element),
|
|
2458
|
-
|
|
2459
|
-
init: processElements,
|
|
2460
|
-
process: processElements,
|
|
2461
|
-
|
|
2462
|
-
commands: ${JSON.stringify(commands)},
|
|
2463
|
-
${blocks.length > 0 ? `blocks: ${JSON.stringify(blocks)},` : ""}
|
|
2464
|
-
parserName: '${parserType}',
|
|
2465
|
-
};
|
|
1934
|
+
import { ${[...ENGINE_API_NAMES, ...modules].join(", ")} } from '@hyperfixi/engine';
|
|
1935
|
+
${semanticCode}
|
|
1936
|
+
register(${modules.join(", ")});
|
|
1937
|
+
${semantic.enabled ? "api.addSourceTransform(translateSource);\n" : ""}
|
|
1938
|
+
Object.assign(api, {
|
|
1939
|
+
${apiProps}
|
|
1940
|
+
});
|
|
2466
1941
|
${autoInit ? `
|
|
2467
1942
|
if (typeof window !== 'undefined') {
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
document.addEventListener('DOMContentLoaded', () => processElements());
|
|
2472
|
-
} else {
|
|
2473
|
-
processElements();
|
|
2474
|
-
}
|
|
2475
|
-
${htmxIntegration ? `
|
|
2476
|
-
document.addEventListener('htmx:afterSettle', (e) => {
|
|
2477
|
-
const target = e.detail?.target;
|
|
2478
|
-
if (target) processElements(target);
|
|
2479
|
-
});
|
|
2480
|
-
` : ""}
|
|
2481
|
-
}
|
|
2482
|
-
` : ""}
|
|
2483
|
-
${esModule ? `
|
|
1943
|
+
${installGlobal} boot();
|
|
1944
|
+
${htmxHooks}}
|
|
1945
|
+
` : ""}${esModule ? `
|
|
2484
1946
|
export default api;
|
|
2485
|
-
export { api
|
|
1947
|
+
export { api };
|
|
2486
1948
|
` : ""}`;
|
|
2487
1949
|
}
|
|
2488
1950
|
var Generator = class {
|
|
@@ -2493,148 +1955,70 @@ var Generator = class {
|
|
|
2493
1955
|
* Generate bundle code from aggregated usage
|
|
2494
1956
|
*/
|
|
2495
1957
|
generate(usage, options) {
|
|
2496
|
-
const commands = [...usage.commands, ...options.extraCommands ?? []];
|
|
2497
|
-
const blocks = [...usage.blocks, ...options.extraBlocks ?? []];
|
|
1958
|
+
const commands = [.../* @__PURE__ */ new Set([...usage.commands, ...options.extraCommands ?? []])];
|
|
1959
|
+
const blocks = [.../* @__PURE__ */ new Set([...usage.blocks, ...options.extraBlocks ?? []])];
|
|
2498
1960
|
const positional = usage.positional || options.positional || false;
|
|
2499
|
-
const
|
|
2500
|
-
|
|
1961
|
+
const reactivity = Boolean(
|
|
1962
|
+
usage.needsReactivity || usage.needsBindToProperty || usage.htmx?.needsReactivity
|
|
1963
|
+
);
|
|
1964
|
+
const semantic = resolveSemanticConfig(options, usage.detectedLanguages);
|
|
1965
|
+
if (commands.length === 0 && blocks.length === 0 && !positional && !reactivity && !semantic.enabled) {
|
|
2501
1966
|
return this.generateEmptyBundle(options);
|
|
2502
1967
|
}
|
|
2503
|
-
const
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
1968
|
+
const moduleUsage = {
|
|
1969
|
+
commands,
|
|
1970
|
+
blocks,
|
|
1971
|
+
positional,
|
|
1972
|
+
reactivity,
|
|
1973
|
+
construct: usage.needsConstruct,
|
|
1974
|
+
cookies: usage.needsCookies
|
|
1975
|
+
};
|
|
1976
|
+
const { modules, unknown } = resolveModules(moduleUsage);
|
|
1977
|
+
if (this.debug) {
|
|
1978
|
+
if (unknown.length > 0) {
|
|
2512
1979
|
console.log(
|
|
2513
|
-
`[hyperfixi]
|
|
2514
|
-
Using the hx-v4 premade bundle (auto-installs reactivity + SSE/WS).`
|
|
1980
|
+
`[hyperfixi] Scanned names with no engine module (a form the engine dropped, or a false positive): ${unknown.join(", ")}`
|
|
2515
1981
|
);
|
|
2516
|
-
const onlyReactivity = usage.needsReactivity && !usage.htmx?.needsHxLive && !usage.htmx?.needsSSE && !usage.htmx?.needsWS && !usage.htmx?.hasHtmxAttributes;
|
|
2517
|
-
if (onlyReactivity) {
|
|
2518
|
-
console.log(
|
|
2519
|
-
` Note: this project uses reactivity only (no hx-*/sse-*/ws-* attributes). A reactivity-only fallback is parked pending size feedback.`
|
|
2520
|
-
);
|
|
2521
|
-
}
|
|
2522
1982
|
}
|
|
2523
|
-
|
|
2524
|
-
}
|
|
2525
|
-
const unsupportedCommands = this.getUnsupportedCommands(commands);
|
|
2526
|
-
if (unsupportedCommands.length > 0) {
|
|
2527
|
-
if (this.debug) {
|
|
1983
|
+
if (usage.htmx?.needsHxLive || usage.htmx?.needsSSE || usage.htmx?.needsWS) {
|
|
2528
1984
|
console.log(
|
|
2529
|
-
|
|
2530
|
-
Falling back to full browser bundle for complete functionality.`
|
|
1985
|
+
"[hyperfixi] hx-live / sse-* / ws-* attributes seen: these are htmx 4 features on the engine (load htmx 4 beside this bundle; a hyperscript-bodied hx-live is a `live \u2026 end` block)."
|
|
2531
1986
|
);
|
|
2532
1987
|
}
|
|
2533
|
-
return this.generateDevFallback("full");
|
|
2534
|
-
}
|
|
2535
|
-
const parserType = canUseLiteParser(commands, blocks, positional) ? "lite" : "hybrid";
|
|
2536
|
-
const config = {
|
|
2537
|
-
name: options.bundleName ?? "ViteAutoGenerated",
|
|
2538
|
-
commands,
|
|
2539
|
-
blocks,
|
|
2540
|
-
positionalExpressions: positional,
|
|
2541
|
-
htmxIntegration: options.htmx ?? usage.htmx?.hasHtmxAttributes ?? false,
|
|
2542
|
-
globalName: options.globalName ?? "hyperfixi",
|
|
2543
|
-
parserType,
|
|
2544
|
-
autoInit: true,
|
|
2545
|
-
esModule: true
|
|
2546
|
-
};
|
|
2547
|
-
if (this.debug) {
|
|
2548
1988
|
const bundleInfo = {
|
|
1989
|
+
modules,
|
|
2549
1990
|
commands,
|
|
2550
1991
|
blocks,
|
|
2551
1992
|
positional,
|
|
2552
|
-
|
|
2553
|
-
semantic: semanticConfig.enabled,
|
|
2554
|
-
parserType
|
|
1993
|
+
reactivity
|
|
2555
1994
|
};
|
|
2556
|
-
if (
|
|
2557
|
-
const sizeInfo = getSemanticBundleSize(
|
|
2558
|
-
bundleInfo.semanticBundle =
|
|
1995
|
+
if (semantic.enabled && semantic.bundleType) {
|
|
1996
|
+
const sizeInfo = getSemanticBundleSize(semantic.bundleType);
|
|
1997
|
+
bundleInfo.semanticBundle = semantic.bundleType;
|
|
2559
1998
|
bundleInfo.semanticSize = sizeInfo.gzip;
|
|
2560
|
-
bundleInfo.languages = [...
|
|
2561
|
-
bundleInfo.grammar =
|
|
1999
|
+
bundleInfo.languages = [...semantic.languages];
|
|
2000
|
+
bundleInfo.grammar = semantic.grammarEnabled;
|
|
2562
2001
|
}
|
|
2563
2002
|
console.log("[hyperfixi] Generating bundle:", bundleInfo);
|
|
2564
|
-
if (
|
|
2003
|
+
if (semantic.bundleType === "all" || semantic.bundleType === "priority") {
|
|
2565
2004
|
console.log(
|
|
2566
|
-
`[hyperfixi] Note: Using '${
|
|
2005
|
+
`[hyperfixi] Note: Using '${semantic.bundleType}' semantic bundle (${getSemanticBundleSize(semantic.bundleType).gzip}). Consider using 'region' option to select a smaller regional bundle if all languages aren't needed.`
|
|
2567
2006
|
);
|
|
2568
2007
|
}
|
|
2569
2008
|
}
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
if (parserImportEnd === -1) {
|
|
2584
|
-
bundleCode = semanticCode + "\n" + bundleCode;
|
|
2585
|
-
} else {
|
|
2586
|
-
bundleCode = bundleCode.slice(0, parserImportEnd) + semanticCode + "\n\n" + bundleCode.slice(parserImportEnd);
|
|
2587
|
-
}
|
|
2588
|
-
bundleCode = bundleCode.replace(
|
|
2589
|
-
/function processElement\(el\) \{\s*const code = el\.getAttribute\('_'\);\s*if \(!code\) return;\s*try \{\s*const ast = (?:new HybridParser\(code\)\.parse\(\)|parseLite\(code\));/g,
|
|
2590
|
-
`function processElement(el) {
|
|
2591
|
-
const code = el.getAttribute('_');
|
|
2592
|
-
if (!code) return;
|
|
2593
|
-
|
|
2594
|
-
try {
|
|
2595
|
-
const ast = parseWithSemantic(code);`
|
|
2596
|
-
);
|
|
2597
|
-
bundleCode = bundleCode.replace(
|
|
2598
|
-
/parse\(code\) \{\s*return (?:new HybridParser\(code\)\.parse\(\)|parseLite\(code\));/g,
|
|
2599
|
-
`parse(code, lang = null) {
|
|
2600
|
-
return parseWithSemantic(code, lang);`
|
|
2601
|
-
);
|
|
2602
|
-
bundleCode = bundleCode.replace(
|
|
2603
|
-
/async execute\(code, element\) \{\s*const me = element \|\| document\.body;\s*const ast = (?:new HybridParser\(code\)\.parse\(\)|parseLite\(code\));/g,
|
|
2604
|
-
`async execute(code, element, lang = null) {
|
|
2605
|
-
const me = element || document.body;
|
|
2606
|
-
const ast = parseWithSemantic(code, lang);`
|
|
2607
|
-
);
|
|
2608
|
-
if (semanticExports.length > 0) {
|
|
2609
|
-
const apiExportsMarkerRegex = /parserName: '(?:lite|hybrid)',/;
|
|
2610
|
-
const additionalApiProps = semanticExports.map((exp) => ` ${exp},`).join("\n");
|
|
2611
|
-
bundleCode = bundleCode.replace(
|
|
2612
|
-
apiExportsMarkerRegex,
|
|
2613
|
-
`parserName: 'semantic',
|
|
2614
|
-
${additionalApiProps}`
|
|
2615
|
-
);
|
|
2616
|
-
}
|
|
2617
|
-
return bundleCode;
|
|
2618
|
-
}
|
|
2619
|
-
/**
|
|
2620
|
-
* Get commands that require the full runtime and are not available in generated bundles
|
|
2621
|
-
*/
|
|
2622
|
-
getUnsupportedCommands(commands) {
|
|
2623
|
-
const unsupported = [];
|
|
2624
|
-
for (const cmd of commands) {
|
|
2625
|
-
if (FULL_RUNTIME_ONLY_COMMANDS2.includes(cmd)) {
|
|
2626
|
-
unsupported.push(cmd);
|
|
2627
|
-
} else if (!isAvailableCommand(cmd) && !COMMAND_IMPLEMENTATIONS[cmd]) {
|
|
2628
|
-
unsupported.push(cmd);
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2631
|
-
return unsupported;
|
|
2632
|
-
}
|
|
2633
|
-
/**
|
|
2634
|
-
* Check if any commands require full runtime and should trigger fallback
|
|
2635
|
-
*/
|
|
2636
|
-
requiresFullRuntime(commands) {
|
|
2637
|
-
return this.getUnsupportedCommands(commands).length > 0;
|
|
2009
|
+
return generateBundleCode({
|
|
2010
|
+
name: options.bundleName ?? "ViteAutoGenerated",
|
|
2011
|
+
modules,
|
|
2012
|
+
commands,
|
|
2013
|
+
blocks,
|
|
2014
|
+
positional,
|
|
2015
|
+
reactivity,
|
|
2016
|
+
htmxIntegration: options.htmx ?? usage.htmx?.hasHtmxAttributes ?? false,
|
|
2017
|
+
globalName: options.globalName ?? "hyperfixi",
|
|
2018
|
+
autoInit: true,
|
|
2019
|
+
esModule: true,
|
|
2020
|
+
semantic
|
|
2021
|
+
});
|
|
2638
2022
|
}
|
|
2639
2023
|
/**
|
|
2640
2024
|
* Generate an empty bundle when no hyperscript is detected
|
|
@@ -2642,7 +2026,7 @@ ${additionalApiProps}`
|
|
|
2642
2026
|
generateEmptyBundle(options) {
|
|
2643
2027
|
const globalName = options.globalName ?? "hyperfixi";
|
|
2644
2028
|
return `/**
|
|
2645
|
-
*
|
|
2029
|
+
* hyperfixi Empty Bundle (Auto-Generated)
|
|
2646
2030
|
*
|
|
2647
2031
|
* No hyperscript usage detected. This bundle provides a minimal API.
|
|
2648
2032
|
* Add hyperscript attributes (_="...") to your HTML to enable features.
|
|
@@ -2652,28 +2036,24 @@ ${additionalApiProps}`
|
|
|
2652
2036
|
|
|
2653
2037
|
const api = {
|
|
2654
2038
|
version: '1.0.0-empty',
|
|
2655
|
-
commands: [],
|
|
2656
|
-
parserName: 'none',
|
|
2039
|
+
bundle: { generator: '@hyperfixi/vite-plugin', modules: [], commands: [], blocks: [], languages: [] },
|
|
2657
2040
|
|
|
2658
2041
|
parse() {
|
|
2659
|
-
console.warn('
|
|
2660
|
-
return {
|
|
2042
|
+
console.warn('hyperfixi: No engine loaded. Add hyperscript to your HTML to enable parsing.');
|
|
2043
|
+
return { errors: [] };
|
|
2661
2044
|
},
|
|
2662
2045
|
|
|
2663
|
-
async
|
|
2664
|
-
console.warn('
|
|
2046
|
+
async evaluate(code, element) {
|
|
2047
|
+
console.warn('hyperfixi: No modules loaded. Detected commands will be automatically included.');
|
|
2665
2048
|
return null;
|
|
2666
2049
|
},
|
|
2667
2050
|
|
|
2668
|
-
|
|
2669
|
-
eval: async (code, element) => api.execute(code, element),
|
|
2670
|
-
|
|
2671
|
-
init() {},
|
|
2051
|
+
processNode() {},
|
|
2672
2052
|
process() {},
|
|
2673
2053
|
};
|
|
2674
2054
|
|
|
2675
2055
|
if (typeof window !== 'undefined') {
|
|
2676
|
-
|
|
2056
|
+
window.${globalName} = api;
|
|
2677
2057
|
}
|
|
2678
2058
|
|
|
2679
2059
|
export default api;
|
|
@@ -2681,947 +2061,40 @@ export { api };
|
|
|
2681
2061
|
`;
|
|
2682
2062
|
}
|
|
2683
2063
|
/**
|
|
2684
|
-
* Generate a development fallback bundle.
|
|
2064
|
+
* Generate a development fallback bundle: the engine with every module.
|
|
2685
2065
|
*
|
|
2686
|
-
*
|
|
2687
|
-
*
|
|
2688
|
-
*
|
|
2689
|
-
*
|
|
2690
|
-
* or `bind ... to <expr>.<prop>` in `_=` bodies — the minimal
|
|
2691
|
-
* generator can't satisfy those features (the slim runtime lacks the
|
|
2692
|
-
* reactive notify chain and the SSE/WS modules). Larger artifact but
|
|
2693
|
-
* correct end-to-end.
|
|
2066
|
+
* One shape serves every former fallback (`hybrid-complete`, `full`, `hx-v4`):
|
|
2067
|
+
* the engine's `everything` is 34 KB gzipped and carries the reactive features
|
|
2068
|
+
* (`live`, `when`, `bind`) the hx-v4 fallback existed for. The argument is kept
|
|
2069
|
+
* for the option's type; its value no longer changes the output.
|
|
2694
2070
|
*/
|
|
2695
|
-
generateDevFallback(
|
|
2696
|
-
const bundle = fallback === "full" ? "@hyperfixi/core/browser" : fallback === "hx-v4" ? "@hyperfixi/core/browser/hybrid-hx-v4" : "@hyperfixi/core/browser/hybrid-complete";
|
|
2071
|
+
generateDevFallback(_fallback = "everything") {
|
|
2697
2072
|
return `/**
|
|
2698
|
-
*
|
|
2073
|
+
* hyperfixi Dev Fallback Bundle
|
|
2699
2074
|
*
|
|
2700
|
-
*
|
|
2701
|
-
* Production builds
|
|
2075
|
+
* The engine with every module, for faster development rebuilds.
|
|
2076
|
+
* Production builds register only the modules the project uses.
|
|
2702
2077
|
*
|
|
2703
2078
|
* Generated by: @hyperfixi/vite-plugin
|
|
2704
2079
|
*/
|
|
2705
2080
|
|
|
2706
|
-
|
|
2707
|
-
export { default } from '${bundle}';
|
|
2708
|
-
`;
|
|
2709
|
-
}
|
|
2710
|
-
};
|
|
2711
|
-
|
|
2712
|
-
// src/compiler.ts
|
|
2713
|
-
import { HybridParser } from "@hyperfixi/core/parser/hybrid/parser-core";
|
|
2714
|
-
var semanticParse = null;
|
|
2715
|
-
var supportsLanguage = null;
|
|
2716
|
-
var buildASTFn = null;
|
|
2717
|
-
function setSemanticParser(parse, supports, buildAST) {
|
|
2718
|
-
semanticParse = parse;
|
|
2719
|
-
supportsLanguage = supports;
|
|
2720
|
-
buildASTFn = buildAST;
|
|
2721
|
-
}
|
|
2722
|
-
function clearSemanticParser() {
|
|
2723
|
-
semanticParse = null;
|
|
2724
|
-
supportsLanguage = null;
|
|
2725
|
-
buildASTFn = null;
|
|
2726
|
-
}
|
|
2727
|
-
function hasSemanticParser() {
|
|
2728
|
-
return semanticParse !== null && supportsLanguage !== null && buildASTFn !== null;
|
|
2729
|
-
}
|
|
2730
|
-
var SEMANTIC_CONFIDENCE_THRESHOLD = 0.7;
|
|
2731
|
-
var multilingualAliases = {};
|
|
2732
|
-
var multilingualRegex = null;
|
|
2733
|
-
function setMultilingualAliases(aliases) {
|
|
2734
|
-
multilingualAliases = { ...aliases };
|
|
2735
|
-
if (Object.keys(aliases).length > 0) {
|
|
2736
|
-
const escapedKeys = Object.keys(aliases).map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
2737
|
-
multilingualRegex = new RegExp(`(^|\\s)(${escapedKeys})(?=\\s|\\.|$)`, "g");
|
|
2738
|
-
} else {
|
|
2739
|
-
multilingualRegex = null;
|
|
2740
|
-
}
|
|
2741
|
-
}
|
|
2742
|
-
function preprocessMultilingual(code) {
|
|
2743
|
-
if (!multilingualRegex) return code;
|
|
2744
|
-
return code.replace(multilingualRegex, (match, prefix, keyword) => {
|
|
2745
|
-
const english = multilingualAliases[keyword];
|
|
2746
|
-
return english ? prefix + english : match;
|
|
2747
|
-
});
|
|
2748
|
-
}
|
|
2749
|
-
function sanitizeClassName(name) {
|
|
2750
|
-
if (!/^-?[a-zA-Z_][a-zA-Z0-9_-]*$/.test(name)) {
|
|
2751
|
-
return null;
|
|
2752
|
-
}
|
|
2753
|
-
return name;
|
|
2754
|
-
}
|
|
2755
|
-
function sanitizeSelector(selector) {
|
|
2756
|
-
return selector.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\0/g, "");
|
|
2757
|
-
}
|
|
2758
|
-
function hashScript(script) {
|
|
2759
|
-
let hash = 5381;
|
|
2760
|
-
for (let i = 0; i < script.length; i++) {
|
|
2761
|
-
hash = (hash << 5) + hash ^ script.charCodeAt(i);
|
|
2762
|
-
}
|
|
2763
|
-
return Math.abs(hash).toString(36).slice(0, 4);
|
|
2764
|
-
}
|
|
2765
|
-
var usedIds = /* @__PURE__ */ new Set();
|
|
2766
|
-
function resetCompiler() {
|
|
2767
|
-
usedIds.clear();
|
|
2768
|
-
}
|
|
2769
|
-
function generateHandlerId(event, command, script) {
|
|
2770
|
-
const hash = hashScript(script);
|
|
2771
|
-
let id = `${event}_${command}_${hash}`;
|
|
2772
|
-
let suffix = 0;
|
|
2773
|
-
while (usedIds.has(id)) {
|
|
2774
|
-
id = `${event}_${command}_${hash}${suffix++}`;
|
|
2775
|
-
}
|
|
2776
|
-
usedIds.add(id);
|
|
2777
|
-
return id;
|
|
2778
|
-
}
|
|
2779
|
-
function compile(script, options = {}) {
|
|
2780
|
-
const { language = "en", debug = false } = options;
|
|
2781
|
-
try {
|
|
2782
|
-
let ast;
|
|
2783
|
-
if (language !== "en" && semanticParse && supportsLanguage && buildASTFn) {
|
|
2784
|
-
if (supportsLanguage(language)) {
|
|
2785
|
-
const result = semanticParse(script, language);
|
|
2786
|
-
if (result.node && result.confidence >= SEMANTIC_CONFIDENCE_THRESHOLD) {
|
|
2787
|
-
const { ast: builtAST, warnings } = buildASTFn(result.node);
|
|
2788
|
-
if (debug && warnings.length > 0) {
|
|
2789
|
-
console.log(`[hyperfixi] Semantic AST warnings for "${script}":`, warnings);
|
|
2790
|
-
}
|
|
2791
|
-
ast = builtAST;
|
|
2792
|
-
if (debug) {
|
|
2793
|
-
console.log(
|
|
2794
|
-
`[hyperfixi] Compiled ${language}: "${script}" (confidence: ${result.confidence.toFixed(2)})`
|
|
2795
|
-
);
|
|
2796
|
-
}
|
|
2797
|
-
} else {
|
|
2798
|
-
if (debug) {
|
|
2799
|
-
const reason = result.error || `low confidence (${result.confidence.toFixed(2)})`;
|
|
2800
|
-
console.log(`[hyperfixi] Semantic parse failed for "${script}": ${reason}`);
|
|
2801
|
-
}
|
|
2802
|
-
return null;
|
|
2803
|
-
}
|
|
2804
|
-
} else {
|
|
2805
|
-
if (debug) {
|
|
2806
|
-
console.log(`[hyperfixi] Language "${language}" not supported by semantic parser`);
|
|
2807
|
-
}
|
|
2808
|
-
return null;
|
|
2809
|
-
}
|
|
2810
|
-
} else if (language !== "en") {
|
|
2811
|
-
if (debug) {
|
|
2812
|
-
console.log(
|
|
2813
|
-
`[hyperfixi] Semantic parser not available for "${language}". Install @lokascript/semantic and call setSemanticParser().`
|
|
2814
|
-
);
|
|
2815
|
-
}
|
|
2816
|
-
return null;
|
|
2817
|
-
} else {
|
|
2818
|
-
const preprocessedScript = preprocessMultilingual(script);
|
|
2819
|
-
const parser = new HybridParser(preprocessedScript);
|
|
2820
|
-
ast = parser.parse();
|
|
2821
|
-
}
|
|
2822
|
-
return compileAST(ast, script);
|
|
2823
|
-
} catch (error) {
|
|
2824
|
-
if (debug) {
|
|
2825
|
-
console.warn(`[hyperfixi] Failed to compile: ${script}`, error);
|
|
2826
|
-
}
|
|
2827
|
-
return null;
|
|
2828
|
-
}
|
|
2829
|
-
}
|
|
2830
|
-
function extractPrimaryCommand(body) {
|
|
2831
|
-
if (body.length === 0) return "handler";
|
|
2832
|
-
const first = body[0];
|
|
2833
|
-
if (first.type === "command") {
|
|
2834
|
-
return first.name || "cmd";
|
|
2835
|
-
}
|
|
2836
|
-
return first.type || "handler";
|
|
2837
|
-
}
|
|
2838
|
-
function compileAST(ast, original) {
|
|
2839
|
-
if (ast.type !== "event") {
|
|
2840
|
-
return null;
|
|
2841
|
-
}
|
|
2842
|
-
const eventNode = ast;
|
|
2843
|
-
const event = eventNode.event;
|
|
2844
|
-
const modifiers = eventNode.modifiers || {};
|
|
2845
|
-
const body = eventNode.body || [];
|
|
2846
|
-
const { code, needsEvaluator, needsLocals, needsGlobals } = compileBody(body);
|
|
2847
|
-
if (code === null || code === "") {
|
|
2848
|
-
return null;
|
|
2849
|
-
}
|
|
2850
|
-
const command = extractPrimaryCommand(body);
|
|
2851
|
-
const id = generateHandlerId(event, command, original);
|
|
2852
|
-
return {
|
|
2853
|
-
id,
|
|
2854
|
-
event,
|
|
2855
|
-
modifiers: {
|
|
2856
|
-
prevent: modifiers.prevent,
|
|
2857
|
-
stop: modifiers.stop,
|
|
2858
|
-
once: modifiers.once,
|
|
2859
|
-
debounce: modifiers.debounce,
|
|
2860
|
-
throttle: modifiers.throttle
|
|
2861
|
-
},
|
|
2862
|
-
code,
|
|
2863
|
-
needsEvaluator: needsEvaluator || needsLocals || needsGlobals,
|
|
2864
|
-
original
|
|
2865
|
-
};
|
|
2866
|
-
}
|
|
2867
|
-
function compileBody(nodes) {
|
|
2868
|
-
const statements = [];
|
|
2869
|
-
let needsEvaluator = false;
|
|
2870
|
-
let needsLocals = false;
|
|
2871
|
-
let needsGlobals = false;
|
|
2872
|
-
for (const node of nodes) {
|
|
2873
|
-
const result = compileNode(node);
|
|
2874
|
-
if (result === null) {
|
|
2875
|
-
return { code: null, needsEvaluator: false, needsLocals: false, needsGlobals: false };
|
|
2876
|
-
}
|
|
2877
|
-
statements.push(result.code);
|
|
2878
|
-
needsEvaluator = needsEvaluator || result.needsEvaluator;
|
|
2879
|
-
needsLocals = needsLocals || result.needsLocals;
|
|
2880
|
-
needsGlobals = needsGlobals || result.needsGlobals;
|
|
2881
|
-
}
|
|
2882
|
-
return {
|
|
2883
|
-
code: statements.join("\n"),
|
|
2884
|
-
needsEvaluator,
|
|
2885
|
-
needsLocals,
|
|
2886
|
-
needsGlobals
|
|
2887
|
-
};
|
|
2888
|
-
}
|
|
2889
|
-
function compileNode(node) {
|
|
2890
|
-
if (node.type === "command") {
|
|
2891
|
-
return compileCommand(node);
|
|
2892
|
-
}
|
|
2893
|
-
return null;
|
|
2894
|
-
}
|
|
2895
|
-
function compileCommand(cmd) {
|
|
2896
|
-
const target = cmd.target ? compileTarget(cmd.target) : "m";
|
|
2897
|
-
switch (cmd.name) {
|
|
2898
|
-
case "toggle":
|
|
2899
|
-
return compileToggle(cmd.args, target);
|
|
2900
|
-
case "add":
|
|
2901
|
-
return compileAdd(cmd.args, target);
|
|
2902
|
-
case "remove":
|
|
2903
|
-
return compileRemove(cmd.args, target);
|
|
2904
|
-
case "removeClass":
|
|
2905
|
-
return compileRemoveClass(cmd.args, target);
|
|
2906
|
-
case "show":
|
|
2907
|
-
return {
|
|
2908
|
-
code: `${target}.style.display = ''`,
|
|
2909
|
-
needsEvaluator: false,
|
|
2910
|
-
needsLocals: false,
|
|
2911
|
-
needsGlobals: false
|
|
2912
|
-
};
|
|
2913
|
-
case "hide":
|
|
2914
|
-
return {
|
|
2915
|
-
code: `${target}.style.display = 'none'`,
|
|
2916
|
-
needsEvaluator: false,
|
|
2917
|
-
needsLocals: false,
|
|
2918
|
-
needsGlobals: false
|
|
2919
|
-
};
|
|
2920
|
-
case "focus":
|
|
2921
|
-
return {
|
|
2922
|
-
code: `${target}.focus()`,
|
|
2923
|
-
needsEvaluator: false,
|
|
2924
|
-
needsLocals: false,
|
|
2925
|
-
needsGlobals: false
|
|
2926
|
-
};
|
|
2927
|
-
case "blur":
|
|
2928
|
-
return {
|
|
2929
|
-
code: `${target}.blur()`,
|
|
2930
|
-
needsEvaluator: false,
|
|
2931
|
-
needsLocals: false,
|
|
2932
|
-
needsGlobals: false
|
|
2933
|
-
};
|
|
2934
|
-
case "log":
|
|
2935
|
-
return compileLog(cmd.args);
|
|
2936
|
-
case "set":
|
|
2937
|
-
return compileSet(cmd.args);
|
|
2938
|
-
case "increment":
|
|
2939
|
-
return compileIncrement(cmd.args);
|
|
2940
|
-
case "decrement":
|
|
2941
|
-
return compileDecrement(cmd.args);
|
|
2942
|
-
case "put":
|
|
2943
|
-
return compilePut(cmd.args, target, cmd.modifier);
|
|
2944
|
-
case "send":
|
|
2945
|
-
case "trigger":
|
|
2946
|
-
return compileTrigger(cmd.args, target);
|
|
2947
|
-
case "wait":
|
|
2948
|
-
return compileWait(cmd.args);
|
|
2949
|
-
default:
|
|
2950
|
-
return null;
|
|
2951
|
-
}
|
|
2952
|
-
}
|
|
2953
|
-
function compileToggle(args, target) {
|
|
2954
|
-
const className = extractClassName(args[0]);
|
|
2955
|
-
if (!className) return null;
|
|
2956
|
-
if (target === "m") {
|
|
2957
|
-
return {
|
|
2958
|
-
code: `m.classList.toggle('${className}')`,
|
|
2959
|
-
needsEvaluator: false,
|
|
2960
|
-
needsLocals: false,
|
|
2961
|
-
needsGlobals: false
|
|
2962
|
-
};
|
|
2963
|
-
}
|
|
2964
|
-
return {
|
|
2965
|
-
code: `${target}.forEach(el => el.classList.toggle('${className}'))`,
|
|
2966
|
-
needsEvaluator: false,
|
|
2967
|
-
needsLocals: false,
|
|
2968
|
-
needsGlobals: false
|
|
2969
|
-
};
|
|
2970
|
-
}
|
|
2971
|
-
function compileAdd(args, target) {
|
|
2972
|
-
const className = extractClassName(args[0]);
|
|
2973
|
-
if (!className) return null;
|
|
2974
|
-
if (target === "m") {
|
|
2975
|
-
return {
|
|
2976
|
-
code: `m.classList.add('${className}')`,
|
|
2977
|
-
needsEvaluator: false,
|
|
2978
|
-
needsLocals: false,
|
|
2979
|
-
needsGlobals: false
|
|
2980
|
-
};
|
|
2981
|
-
}
|
|
2982
|
-
return {
|
|
2983
|
-
code: `${target}.forEach(el => el.classList.add('${className}'))`,
|
|
2984
|
-
needsEvaluator: false,
|
|
2985
|
-
needsLocals: false,
|
|
2986
|
-
needsGlobals: false
|
|
2987
|
-
};
|
|
2988
|
-
}
|
|
2989
|
-
function compileRemove(args, target) {
|
|
2990
|
-
if (!args || args.length === 0) {
|
|
2991
|
-
return {
|
|
2992
|
-
code: `${target}.remove()`,
|
|
2993
|
-
needsEvaluator: false,
|
|
2994
|
-
needsLocals: false,
|
|
2995
|
-
needsGlobals: false
|
|
2996
|
-
};
|
|
2997
|
-
}
|
|
2998
|
-
const className = extractClassName(args[0]);
|
|
2999
|
-
if (!className) return null;
|
|
3000
|
-
if (target === "m") {
|
|
3001
|
-
return {
|
|
3002
|
-
code: `m.classList.remove('${className}')`,
|
|
3003
|
-
needsEvaluator: false,
|
|
3004
|
-
needsLocals: false,
|
|
3005
|
-
needsGlobals: false
|
|
3006
|
-
};
|
|
3007
|
-
}
|
|
3008
|
-
return {
|
|
3009
|
-
code: `${target}.forEach(el => el.classList.remove('${className}'))`,
|
|
3010
|
-
needsEvaluator: false,
|
|
3011
|
-
needsLocals: false,
|
|
3012
|
-
needsGlobals: false
|
|
3013
|
-
};
|
|
3014
|
-
}
|
|
3015
|
-
function compileRemoveClass(args, target) {
|
|
3016
|
-
const className = extractClassName(args[0]);
|
|
3017
|
-
if (!className) return null;
|
|
3018
|
-
if (target === "m") {
|
|
3019
|
-
return {
|
|
3020
|
-
code: `m.classList.remove('${className}')`,
|
|
3021
|
-
needsEvaluator: false,
|
|
3022
|
-
needsLocals: false,
|
|
3023
|
-
needsGlobals: false
|
|
3024
|
-
};
|
|
3025
|
-
}
|
|
3026
|
-
return {
|
|
3027
|
-
code: `${target}.forEach(el => el.classList.remove('${className}'))`,
|
|
3028
|
-
needsEvaluator: false,
|
|
3029
|
-
needsLocals: false,
|
|
3030
|
-
needsGlobals: false
|
|
3031
|
-
};
|
|
3032
|
-
}
|
|
3033
|
-
function compileLog(args) {
|
|
3034
|
-
const compiled = args.map(compileExpression).filter(Boolean);
|
|
3035
|
-
if (compiled.length !== args.length) {
|
|
3036
|
-
return {
|
|
3037
|
-
code: `console.log(${compiled.join(", ")})`,
|
|
3038
|
-
needsEvaluator: true,
|
|
3039
|
-
needsLocals: false,
|
|
3040
|
-
needsGlobals: false
|
|
3041
|
-
};
|
|
3042
|
-
}
|
|
3043
|
-
return {
|
|
3044
|
-
code: `console.log(${compiled.join(", ")})`,
|
|
3045
|
-
needsEvaluator: false,
|
|
3046
|
-
needsLocals: false,
|
|
3047
|
-
needsGlobals: false
|
|
3048
|
-
};
|
|
3049
|
-
}
|
|
3050
|
-
function compileSet(args) {
|
|
3051
|
-
if (args.length < 2) return null;
|
|
3052
|
-
const [target, value] = args;
|
|
3053
|
-
const compiledValue = compileExpression(value);
|
|
3054
|
-
if (!compiledValue) return null;
|
|
3055
|
-
if (target.type === "variable") {
|
|
3056
|
-
const varNode = target;
|
|
3057
|
-
if (varNode.scope === "local") {
|
|
3058
|
-
const varName = varNode.name.slice(1);
|
|
3059
|
-
return {
|
|
3060
|
-
code: `L.${varName} = ${compiledValue}`,
|
|
3061
|
-
needsEvaluator: false,
|
|
3062
|
-
needsLocals: true,
|
|
3063
|
-
needsGlobals: false
|
|
3064
|
-
};
|
|
3065
|
-
}
|
|
3066
|
-
if (varNode.scope === "global") {
|
|
3067
|
-
const varName = varNode.name.slice(1);
|
|
3068
|
-
return {
|
|
3069
|
-
code: `G.${varName} = ${compiledValue}`,
|
|
3070
|
-
needsEvaluator: false,
|
|
3071
|
-
needsLocals: false,
|
|
3072
|
-
needsGlobals: true
|
|
3073
|
-
};
|
|
3074
|
-
}
|
|
3075
|
-
}
|
|
3076
|
-
if (target.type === "possessive") {
|
|
3077
|
-
const possNode = target;
|
|
3078
|
-
const obj = compileExpression(possNode.object);
|
|
3079
|
-
const prop = possNode.property;
|
|
3080
|
-
if (!obj) return null;
|
|
3081
|
-
if (prop.startsWith("*")) {
|
|
3082
|
-
const styleProp = prop.slice(1);
|
|
3083
|
-
return {
|
|
3084
|
-
code: `${obj}.style.${styleProp} = ${compiledValue}`,
|
|
3085
|
-
needsEvaluator: false,
|
|
3086
|
-
needsLocals: false,
|
|
3087
|
-
needsGlobals: false
|
|
3088
|
-
};
|
|
3089
|
-
}
|
|
3090
|
-
return {
|
|
3091
|
-
code: `${obj}.${prop} = ${compiledValue}`,
|
|
3092
|
-
needsEvaluator: false,
|
|
3093
|
-
needsLocals: false,
|
|
3094
|
-
needsGlobals: false
|
|
3095
|
-
};
|
|
3096
|
-
}
|
|
3097
|
-
if (target.type === "member") {
|
|
3098
|
-
const memNode = target;
|
|
3099
|
-
const obj = compileExpression(memNode.object);
|
|
3100
|
-
const prop = typeof memNode.property === "string" ? memNode.property : null;
|
|
3101
|
-
if (!obj || !prop) return null;
|
|
3102
|
-
if (prop.startsWith("*")) {
|
|
3103
|
-
const styleProp = prop.slice(1);
|
|
3104
|
-
return {
|
|
3105
|
-
code: `${obj}.style.${styleProp} = ${compiledValue}`,
|
|
3106
|
-
needsEvaluator: false,
|
|
3107
|
-
needsLocals: false,
|
|
3108
|
-
needsGlobals: false
|
|
3109
|
-
};
|
|
3110
|
-
}
|
|
3111
|
-
return {
|
|
3112
|
-
code: `${obj}.${prop} = ${compiledValue}`,
|
|
3113
|
-
needsEvaluator: false,
|
|
3114
|
-
needsLocals: false,
|
|
3115
|
-
needsGlobals: false
|
|
3116
|
-
};
|
|
3117
|
-
}
|
|
3118
|
-
return null;
|
|
3119
|
-
}
|
|
3120
|
-
function compileIncrement(args) {
|
|
3121
|
-
if (args.length < 1) return null;
|
|
3122
|
-
const target = args[0];
|
|
3123
|
-
const amount = args.length > 1 ? compileExpression(args[1]) : "1";
|
|
3124
|
-
if (target.type === "variable") {
|
|
3125
|
-
const varNode = target;
|
|
3126
|
-
if (varNode.scope === "local") {
|
|
3127
|
-
const varName = varNode.name.slice(1);
|
|
3128
|
-
return {
|
|
3129
|
-
code: `L.${varName} = (L.${varName} || 0) + ${amount}`,
|
|
3130
|
-
needsEvaluator: false,
|
|
3131
|
-
needsLocals: true,
|
|
3132
|
-
needsGlobals: false
|
|
3133
|
-
};
|
|
3134
|
-
}
|
|
3135
|
-
if (varNode.scope === "global") {
|
|
3136
|
-
const varName = varNode.name.slice(1);
|
|
3137
|
-
return {
|
|
3138
|
-
code: `G.${varName} = (G.${varName} || 0) + ${amount}`,
|
|
3139
|
-
needsEvaluator: false,
|
|
3140
|
-
needsLocals: false,
|
|
3141
|
-
needsGlobals: true
|
|
3142
|
-
};
|
|
3143
|
-
}
|
|
3144
|
-
}
|
|
3145
|
-
const compiled = compileExpression(target);
|
|
3146
|
-
if (compiled) {
|
|
3147
|
-
return {
|
|
3148
|
-
code: `${compiled}.textContent = (parseFloat(${compiled}.textContent) || 0) + ${amount}`,
|
|
3149
|
-
needsEvaluator: false,
|
|
3150
|
-
needsLocals: false,
|
|
3151
|
-
needsGlobals: false
|
|
3152
|
-
};
|
|
3153
|
-
}
|
|
3154
|
-
return null;
|
|
3155
|
-
}
|
|
3156
|
-
function compileDecrement(args) {
|
|
3157
|
-
if (args.length < 1) return null;
|
|
3158
|
-
const target = args[0];
|
|
3159
|
-
const amount = args.length > 1 ? compileExpression(args[1]) : "1";
|
|
3160
|
-
if (target.type === "variable") {
|
|
3161
|
-
const varNode = target;
|
|
3162
|
-
if (varNode.scope === "local") {
|
|
3163
|
-
const varName = varNode.name.slice(1);
|
|
3164
|
-
return {
|
|
3165
|
-
code: `L.${varName} = (L.${varName} || 0) - ${amount}`,
|
|
3166
|
-
needsEvaluator: false,
|
|
3167
|
-
needsLocals: true,
|
|
3168
|
-
needsGlobals: false
|
|
3169
|
-
};
|
|
3170
|
-
}
|
|
3171
|
-
if (varNode.scope === "global") {
|
|
3172
|
-
const varName = varNode.name.slice(1);
|
|
3173
|
-
return {
|
|
3174
|
-
code: `G.${varName} = (G.${varName} || 0) - ${amount}`,
|
|
3175
|
-
needsEvaluator: false,
|
|
3176
|
-
needsLocals: false,
|
|
3177
|
-
needsGlobals: true
|
|
3178
|
-
};
|
|
3179
|
-
}
|
|
3180
|
-
}
|
|
3181
|
-
const compiled = compileExpression(target);
|
|
3182
|
-
if (compiled) {
|
|
3183
|
-
return {
|
|
3184
|
-
code: `${compiled}.textContent = (parseFloat(${compiled}.textContent) || 0) - ${amount}`,
|
|
3185
|
-
needsEvaluator: false,
|
|
3186
|
-
needsLocals: false,
|
|
3187
|
-
needsGlobals: false
|
|
3188
|
-
};
|
|
3189
|
-
}
|
|
3190
|
-
return null;
|
|
3191
|
-
}
|
|
3192
|
-
function compilePut(args, target, modifier) {
|
|
3193
|
-
if (args.length < 1) return null;
|
|
3194
|
-
const content = compileExpression(args[0]);
|
|
3195
|
-
if (!content) return null;
|
|
3196
|
-
const mod = modifier || "into";
|
|
3197
|
-
switch (mod) {
|
|
3198
|
-
case "into":
|
|
3199
|
-
return {
|
|
3200
|
-
code: `${target}.innerHTML = ${content}`,
|
|
3201
|
-
needsEvaluator: false,
|
|
3202
|
-
needsLocals: false,
|
|
3203
|
-
needsGlobals: false
|
|
3204
|
-
};
|
|
3205
|
-
case "before":
|
|
3206
|
-
return {
|
|
3207
|
-
code: `${target}.insertAdjacentHTML('beforebegin', ${content})`,
|
|
3208
|
-
needsEvaluator: false,
|
|
3209
|
-
needsLocals: false,
|
|
3210
|
-
needsGlobals: false
|
|
3211
|
-
};
|
|
3212
|
-
case "after":
|
|
3213
|
-
return {
|
|
3214
|
-
code: `${target}.insertAdjacentHTML('afterend', ${content})`,
|
|
3215
|
-
needsEvaluator: false,
|
|
3216
|
-
needsLocals: false,
|
|
3217
|
-
needsGlobals: false
|
|
3218
|
-
};
|
|
3219
|
-
case "at start of":
|
|
3220
|
-
return {
|
|
3221
|
-
code: `${target}.insertAdjacentHTML('afterbegin', ${content})`,
|
|
3222
|
-
needsEvaluator: false,
|
|
3223
|
-
needsLocals: false,
|
|
3224
|
-
needsGlobals: false
|
|
3225
|
-
};
|
|
3226
|
-
case "at end of":
|
|
3227
|
-
return {
|
|
3228
|
-
code: `${target}.insertAdjacentHTML('beforeend', ${content})`,
|
|
3229
|
-
needsEvaluator: false,
|
|
3230
|
-
needsLocals: false,
|
|
3231
|
-
needsGlobals: false
|
|
3232
|
-
};
|
|
3233
|
-
default:
|
|
3234
|
-
return {
|
|
3235
|
-
code: `${target}.innerHTML = ${content}`,
|
|
3236
|
-
needsEvaluator: false,
|
|
3237
|
-
needsLocals: false,
|
|
3238
|
-
needsGlobals: false
|
|
3239
|
-
};
|
|
3240
|
-
}
|
|
3241
|
-
}
|
|
3242
|
-
function compileTrigger(args, target) {
|
|
3243
|
-
if (args.length < 1) return null;
|
|
3244
|
-
const eventName = compileExpression(args[0]);
|
|
3245
|
-
if (!eventName) return null;
|
|
3246
|
-
return {
|
|
3247
|
-
code: `${target}.dispatchEvent(new CustomEvent(${eventName}, { bubbles: true }))`,
|
|
3248
|
-
needsEvaluator: false,
|
|
3249
|
-
needsLocals: false,
|
|
3250
|
-
needsGlobals: false
|
|
3251
|
-
};
|
|
3252
|
-
}
|
|
3253
|
-
function compileWait(args) {
|
|
3254
|
-
if (args.length < 1) return null;
|
|
3255
|
-
const duration = compileExpression(args[0]);
|
|
3256
|
-
if (!duration) return null;
|
|
3257
|
-
return {
|
|
3258
|
-
code: `await new Promise(r => setTimeout(r, ${duration}))`,
|
|
3259
|
-
needsEvaluator: false,
|
|
3260
|
-
needsLocals: false,
|
|
3261
|
-
needsGlobals: false
|
|
3262
|
-
};
|
|
3263
|
-
}
|
|
3264
|
-
function compileExpression(node) {
|
|
3265
|
-
if (!node) return null;
|
|
3266
|
-
switch (node.type) {
|
|
3267
|
-
case "literal": {
|
|
3268
|
-
const litNode = node;
|
|
3269
|
-
return JSON.stringify(litNode.value);
|
|
3270
|
-
}
|
|
3271
|
-
case "identifier": {
|
|
3272
|
-
const idNode = node;
|
|
3273
|
-
const val = idNode.value;
|
|
3274
|
-
if (val === "me" || val === "my") return "m";
|
|
3275
|
-
if (val === "you") return "y";
|
|
3276
|
-
if (val === "it") return "it";
|
|
3277
|
-
if (val === "event") return "e";
|
|
3278
|
-
if (val === "body") return "document.body";
|
|
3279
|
-
if (val === "document") return "document";
|
|
3280
|
-
if (val === "window") return "window";
|
|
3281
|
-
return val;
|
|
3282
|
-
}
|
|
3283
|
-
case "variable": {
|
|
3284
|
-
const varNode = node;
|
|
3285
|
-
const name = varNode.name.slice(1);
|
|
3286
|
-
return varNode.scope === "local" ? `L.${name}` : `G.${name}`;
|
|
3287
|
-
}
|
|
3288
|
-
case "selector": {
|
|
3289
|
-
const selNode = node;
|
|
3290
|
-
const sanitized = sanitizeSelector(selNode.value);
|
|
3291
|
-
return `document.querySelector('${sanitized}')`;
|
|
3292
|
-
}
|
|
3293
|
-
case "possessive": {
|
|
3294
|
-
const possNode = node;
|
|
3295
|
-
const obj = compileExpression(possNode.object);
|
|
3296
|
-
const prop = possNode.property;
|
|
3297
|
-
if (!obj) return null;
|
|
3298
|
-
if (prop.startsWith("*")) {
|
|
3299
|
-
return `${obj}.style.${prop.slice(1)}`;
|
|
3300
|
-
}
|
|
3301
|
-
if (prop === "values") {
|
|
3302
|
-
return `(function(el){if(el instanceof HTMLFormElement)return new FormData(el);var fd=new FormData();el.querySelectorAll('input,select,textarea').forEach(function(i){var n=i.getAttribute('name');if(n&&'value'in i)fd.append(n,i.value)});return fd})(${obj})`;
|
|
3303
|
-
}
|
|
3304
|
-
return `${obj}.${prop}`;
|
|
3305
|
-
}
|
|
3306
|
-
case "member": {
|
|
3307
|
-
const memNode = node;
|
|
3308
|
-
const obj = compileExpression(memNode.object);
|
|
3309
|
-
const prop = typeof memNode.property === "string" ? memNode.property : null;
|
|
3310
|
-
if (!obj || !prop) return null;
|
|
3311
|
-
if (prop.startsWith("*")) {
|
|
3312
|
-
return `${obj}.style.${prop.slice(1)}`;
|
|
3313
|
-
}
|
|
3314
|
-
return `${obj}.${prop}`;
|
|
3315
|
-
}
|
|
3316
|
-
case "binary": {
|
|
3317
|
-
const binNode = node;
|
|
3318
|
-
const left = compileExpression(binNode.left);
|
|
3319
|
-
const right = compileExpression(binNode.right);
|
|
3320
|
-
if (!left || !right) return null;
|
|
3321
|
-
const op = binNode.operator;
|
|
3322
|
-
switch (op) {
|
|
3323
|
-
case "+":
|
|
3324
|
-
case "-":
|
|
3325
|
-
case "*":
|
|
3326
|
-
case "/":
|
|
3327
|
-
case "%":
|
|
3328
|
-
return `(${left} ${op} ${right})`;
|
|
3329
|
-
case "==":
|
|
3330
|
-
case "is":
|
|
3331
|
-
return `(${left} == ${right})`;
|
|
3332
|
-
case "!=":
|
|
3333
|
-
case "is not":
|
|
3334
|
-
return `(${left} != ${right})`;
|
|
3335
|
-
case "<":
|
|
3336
|
-
case ">":
|
|
3337
|
-
case "<=":
|
|
3338
|
-
case ">=":
|
|
3339
|
-
return `(${left} ${op} ${right})`;
|
|
3340
|
-
case "and":
|
|
3341
|
-
case "&&":
|
|
3342
|
-
return `(${left} && ${right})`;
|
|
3343
|
-
case "or":
|
|
3344
|
-
case "||":
|
|
3345
|
-
return `(${left} || ${right})`;
|
|
3346
|
-
case "has": {
|
|
3347
|
-
const rightSel = binNode.right;
|
|
3348
|
-
const className = rightSel.value?.slice(1) || "";
|
|
3349
|
-
const sanitizedClass = sanitizeClassName(className);
|
|
3350
|
-
if (!sanitizedClass) return null;
|
|
3351
|
-
return `${left}.classList.contains('${sanitizedClass}')`;
|
|
3352
|
-
}
|
|
3353
|
-
default:
|
|
3354
|
-
return null;
|
|
3355
|
-
}
|
|
3356
|
-
}
|
|
3357
|
-
case "call": {
|
|
3358
|
-
const callNode = node;
|
|
3359
|
-
const callee = callNode.callee;
|
|
3360
|
-
const args = (callNode.args || []).map(compileExpression);
|
|
3361
|
-
if (args.some((a) => a === null)) return null;
|
|
3362
|
-
if (callee.type === "member" || callee.type === "possessive") {
|
|
3363
|
-
const memCallee = callee;
|
|
3364
|
-
const obj = compileExpression(memCallee.object);
|
|
3365
|
-
const prop = typeof memCallee.property === "string" ? memCallee.property : null;
|
|
3366
|
-
if (!obj || !prop) return null;
|
|
3367
|
-
return `${obj}.${prop}(${args.join(", ")})`;
|
|
3368
|
-
}
|
|
3369
|
-
const fn = compileExpression(callee);
|
|
3370
|
-
if (!fn) return null;
|
|
3371
|
-
return `${fn}(${args.join(", ")})`;
|
|
3372
|
-
}
|
|
3373
|
-
case "positional": {
|
|
3374
|
-
const posNode = node;
|
|
3375
|
-
const position = posNode.position;
|
|
3376
|
-
const target = posNode.target;
|
|
3377
|
-
switch (position) {
|
|
3378
|
-
case "first":
|
|
3379
|
-
if (target?.type === "selector") {
|
|
3380
|
-
const selNode = target;
|
|
3381
|
-
const sanitized = sanitizeSelector(selNode.value);
|
|
3382
|
-
return `document.querySelector('${sanitized}')`;
|
|
3383
|
-
}
|
|
3384
|
-
return null;
|
|
3385
|
-
// Arrays need runtime
|
|
3386
|
-
case "last":
|
|
3387
|
-
if (target?.type === "selector") {
|
|
3388
|
-
const selNode = target;
|
|
3389
|
-
const sanitized = sanitizeSelector(selNode.value);
|
|
3390
|
-
return `(()=>{const e=document.querySelectorAll('${sanitized}');return e[e.length-1]})()`;
|
|
3391
|
-
}
|
|
3392
|
-
return null;
|
|
3393
|
-
// Arrays need runtime
|
|
3394
|
-
case "next":
|
|
3395
|
-
return "m.nextElementSibling";
|
|
3396
|
-
case "previous":
|
|
3397
|
-
return "m.previousElementSibling";
|
|
3398
|
-
case "closest":
|
|
3399
|
-
if (target?.type === "selector") {
|
|
3400
|
-
const selNode = target;
|
|
3401
|
-
const sanitized = sanitizeSelector(selNode.value);
|
|
3402
|
-
return `m.closest('${sanitized}')`;
|
|
3403
|
-
}
|
|
3404
|
-
return null;
|
|
3405
|
-
case "parent":
|
|
3406
|
-
return "m.parentElement";
|
|
3407
|
-
default:
|
|
3408
|
-
return null;
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
3411
|
-
default:
|
|
3412
|
-
return null;
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
function compileTarget(target) {
|
|
3416
|
-
if (target.type === "identifier") {
|
|
3417
|
-
const idNode = target;
|
|
3418
|
-
if (idNode.value === "me" || idNode.value === "my") return "m";
|
|
3419
|
-
if (idNode.value === "you") return "y";
|
|
3420
|
-
}
|
|
3421
|
-
if (target.type === "selector") {
|
|
3422
|
-
const selNode = target;
|
|
3423
|
-
const sanitized = sanitizeSelector(selNode.value);
|
|
3424
|
-
return `document.querySelectorAll('${sanitized}')`;
|
|
3425
|
-
}
|
|
3426
|
-
const compiled = compileExpression(target);
|
|
3427
|
-
return compiled || "m";
|
|
3428
|
-
}
|
|
3429
|
-
function extractClassName(node) {
|
|
3430
|
-
if (!node) return null;
|
|
3431
|
-
if (node.type === "selector") {
|
|
3432
|
-
const selNode = node;
|
|
3433
|
-
const val = selNode.value;
|
|
3434
|
-
const rawClass = val.startsWith(".") ? val.slice(1) : val;
|
|
3435
|
-
return sanitizeClassName(rawClass);
|
|
3436
|
-
}
|
|
3437
|
-
if (node.type === "literal" || node.type === "string") {
|
|
3438
|
-
const litNode = node;
|
|
3439
|
-
const val = litNode.value;
|
|
3440
|
-
if (typeof val === "string") {
|
|
3441
|
-
const rawClass = val.startsWith(".") ? val.slice(1) : val;
|
|
3442
|
-
return sanitizeClassName(rawClass);
|
|
3443
|
-
}
|
|
3444
|
-
}
|
|
3445
|
-
if (node.type === "identifier") {
|
|
3446
|
-
const idNode = node;
|
|
3447
|
-
return sanitizeClassName(idNode.value);
|
|
3448
|
-
}
|
|
3449
|
-
return null;
|
|
3450
|
-
}
|
|
3451
|
-
|
|
3452
|
-
// src/compiled-generator.ts
|
|
3453
|
-
function generateSourceMapTable(handlers) {
|
|
3454
|
-
if (handlers.length === 0) return "";
|
|
3455
|
-
const lines = [
|
|
3456
|
-
" *",
|
|
3457
|
-
" * Handler Source Map:",
|
|
3458
|
-
" * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"
|
|
3459
|
-
];
|
|
3460
|
-
for (const h of handlers) {
|
|
3461
|
-
const original = h.original.replace(/\n/g, " ").slice(0, 40);
|
|
3462
|
-
const truncated = original.length < h.original.length ? original + "..." : original;
|
|
3463
|
-
lines.push(` * \u2502 ${h.id.padEnd(20)} \u2190 ${truncated.padEnd(40)} \u2502`);
|
|
3464
|
-
}
|
|
3465
|
-
lines.push(" * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
3466
|
-
lines.push(" *");
|
|
3467
|
-
return lines.join("\n");
|
|
3468
|
-
}
|
|
3469
|
-
function generateCompiledBundle(options) {
|
|
3470
|
-
const {
|
|
3471
|
-
handlers,
|
|
3472
|
-
needsLocals,
|
|
3473
|
-
needsGlobals,
|
|
3474
|
-
globalName = "hyperfixi",
|
|
3475
|
-
htmx = false,
|
|
3476
|
-
debug = false
|
|
3477
|
-
} = options;
|
|
3478
|
-
const handlerEntries = handlers.map((h) => {
|
|
3479
|
-
const isAsync = h.code.includes("await");
|
|
3480
|
-
const fn = isAsync ? `async(m,e,y)=>{${h.code}}` : `(m,e,y)=>{${h.code}}`;
|
|
3481
|
-
if (debug) {
|
|
3482
|
-
const escapedOriginal = h.original.replace(/\*/g, "\\*").replace(/\n/g, " ");
|
|
3483
|
-
return `
|
|
3484
|
-
/* ${escapedOriginal} */
|
|
3485
|
-
${h.id}:${fn}`;
|
|
3486
|
-
}
|
|
3487
|
-
return `${h.id}:${fn}`;
|
|
3488
|
-
});
|
|
3489
|
-
const registrations = handlers.map((h) => {
|
|
3490
|
-
const modsCode = generateModifiersCode(h);
|
|
3491
|
-
return ` case '${h.id}': r(el,'${h.event}',H.${h.id}${modsCode}); break;`;
|
|
3492
|
-
});
|
|
3493
|
-
const localsCode = needsLocals ? "const L={};" : "";
|
|
3494
|
-
const globalsCode = needsGlobals ? "const G={};" : "";
|
|
3495
|
-
const sourceMapTable = debug ? generateSourceMapTable(handlers) : "";
|
|
3496
|
-
return `/**
|
|
3497
|
-
* HyperFixi Compiled Bundle (Auto-Generated)
|
|
3498
|
-
*
|
|
3499
|
-
* Pre-compiled hyperscript - no runtime parser needed!
|
|
3500
|
-
* Handlers: ${handlers.length}
|
|
3501
|
-
*
|
|
3502
|
-
* DO NOT EDIT - Regenerate with build.
|
|
3503
|
-
${sourceMapTable} */
|
|
3504
|
-
|
|
3505
|
-
${localsCode}${globalsCode}
|
|
3506
|
-
const H={${handlerEntries.join(",")}};
|
|
2081
|
+
import { api, boot, register, everything } from '@hyperfixi/engine';
|
|
3507
2082
|
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
}
|
|
2083
|
+
register(...everything);
|
|
2084
|
+
Object.assign(api, {
|
|
2085
|
+
bundle: { generator: '@hyperfixi/vite-plugin', modules: ['everything'], commands: [], blocks: [], languages: [] },
|
|
2086
|
+
});
|
|
3513
2087
|
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
${registrations.join("\n")}
|
|
3518
|
-
}
|
|
3519
|
-
});
|
|
3520
|
-
}
|
|
3521
|
-
|
|
3522
|
-
${htmx ? `document.addEventListener('htmx:afterSettle',e=>init(e.detail?.target));` : ""}
|
|
3523
|
-
|
|
3524
|
-
const api={
|
|
3525
|
-
version:'1.0.0-compiled',
|
|
3526
|
-
commands:${JSON.stringify(handlers.map((h) => h.id))},
|
|
3527
|
-
init,
|
|
3528
|
-
process:init,
|
|
3529
|
-
};
|
|
3530
|
-
|
|
3531
|
-
if(typeof window!=='undefined'){
|
|
3532
|
-
window.${globalName}=api;
|
|
3533
|
-
document.readyState==='loading'
|
|
3534
|
-
?document.addEventListener('DOMContentLoaded',()=>init())
|
|
3535
|
-
:init();
|
|
2088
|
+
if (typeof window !== 'undefined') {
|
|
2089
|
+
window.hyperfixi = api;
|
|
2090
|
+
boot();
|
|
3536
2091
|
}
|
|
3537
2092
|
|
|
3538
2093
|
export default api;
|
|
3539
|
-
export{api
|
|
2094
|
+
export { api };
|
|
3540
2095
|
`;
|
|
3541
|
-
}
|
|
3542
|
-
function generateModifiersCode(h) {
|
|
3543
|
-
const mods = [];
|
|
3544
|
-
if (h.modifiers.prevent) mods.push("p:1");
|
|
3545
|
-
if (h.modifiers.stop) mods.push("s:1");
|
|
3546
|
-
if (h.modifiers.once) mods.push("o:1");
|
|
3547
|
-
if (h.modifiers.debounce) mods.push(`d:${h.modifiers.debounce}`);
|
|
3548
|
-
if (h.modifiers.throttle) mods.push(`t:${h.modifiers.throttle}`);
|
|
3549
|
-
if (mods.length === 0) return "";
|
|
3550
|
-
return `,{${mods.join(",")}}`;
|
|
3551
|
-
}
|
|
3552
|
-
function hasModifiers(handlers) {
|
|
3553
|
-
return handlers.some(
|
|
3554
|
-
(h) => h.modifiers.prevent || h.modifiers.stop || h.modifiers.once || h.modifiers.debounce || h.modifiers.throttle
|
|
3555
|
-
);
|
|
3556
|
-
}
|
|
3557
|
-
function hasOnce(handlers) {
|
|
3558
|
-
return handlers.some((h) => h.modifiers.once);
|
|
3559
|
-
}
|
|
3560
|
-
function generateModifierWrappers(handlers) {
|
|
3561
|
-
const lines = [];
|
|
3562
|
-
if (handlers.some((h) => h.modifiers.prevent || h.modifiers.stop)) {
|
|
3563
|
-
lines.push(
|
|
3564
|
-
` if(m?.p||m?.s){const _h=h;h=e=>{m.p&&e.preventDefault();m.s&&e.stopPropagation();_h(e.currentTarget,e,e.target)};}`
|
|
3565
|
-
);
|
|
3566
|
-
}
|
|
3567
|
-
if (handlers.some((h) => h.modifiers.debounce)) {
|
|
3568
|
-
lines.push(
|
|
3569
|
-
` if(m?.d){let t;const _h=h;h=e=>{clearTimeout(t);t=setTimeout(()=>_h(e.currentTarget,e,e.target),m.d)};}`
|
|
3570
|
-
);
|
|
3571
|
-
}
|
|
3572
|
-
if (handlers.some((h) => h.modifiers.throttle)) {
|
|
3573
|
-
lines.push(
|
|
3574
|
-
` if(m?.t){let l=0;const _h=h;h=e=>{const n=Date.now();if(n-l>=m.t){l=n;_h(e.currentTarget,e,e.target)}};}`
|
|
3575
|
-
);
|
|
3576
|
-
}
|
|
3577
|
-
return lines.join("\n");
|
|
3578
|
-
}
|
|
3579
|
-
|
|
3580
|
-
// src/html-transformer.ts
|
|
3581
|
-
function transformHTML(html, handlerMap, fallbackScripts) {
|
|
3582
|
-
let modified = false;
|
|
3583
|
-
const fallbacks = [];
|
|
3584
|
-
const patterns = [
|
|
3585
|
-
/(\s)_\s*=\s*"([^"]+)"/g,
|
|
3586
|
-
// _="..."
|
|
3587
|
-
/(\s)_\s*=\s*'([^']+)'/g,
|
|
3588
|
-
// _='...'
|
|
3589
|
-
/(\s)_\s*=\s*`([^`]+)`/g
|
|
3590
|
-
// _=`...`
|
|
3591
|
-
];
|
|
3592
|
-
let result = html;
|
|
3593
|
-
for (const pattern of patterns) {
|
|
3594
|
-
result = result.replace(pattern, (match, whitespace, script) => {
|
|
3595
|
-
const handlerId = handlerMap.get(script);
|
|
3596
|
-
if (handlerId) {
|
|
3597
|
-
modified = true;
|
|
3598
|
-
return `${whitespace}data-h="${handlerId}"`;
|
|
3599
|
-
}
|
|
3600
|
-
if (fallbackScripts.has(script)) {
|
|
3601
|
-
fallbacks.push(script);
|
|
3602
|
-
return match;
|
|
3603
|
-
}
|
|
3604
|
-
fallbacks.push(script);
|
|
3605
|
-
return match;
|
|
3606
|
-
});
|
|
3607
|
-
}
|
|
3608
|
-
return {
|
|
3609
|
-
code: result,
|
|
3610
|
-
modified,
|
|
3611
|
-
fallbacks
|
|
3612
|
-
};
|
|
3613
|
-
}
|
|
3614
|
-
function extractScripts(html) {
|
|
3615
|
-
const scripts = [];
|
|
3616
|
-
const patterns = [/_\s*=\s*"([^"]+)"/g, /_\s*=\s*'([^']+)'/g, /_\s*=\s*`([^`]+)`/g];
|
|
3617
|
-
for (const pattern of patterns) {
|
|
3618
|
-
let match;
|
|
3619
|
-
while (match = pattern.exec(html)) {
|
|
3620
|
-
scripts.push(match[1]);
|
|
3621
|
-
}
|
|
3622
2096
|
}
|
|
3623
|
-
|
|
3624
|
-
}
|
|
2097
|
+
};
|
|
3625
2098
|
|
|
3626
2099
|
// src/server-bridge-integration.ts
|
|
3627
2100
|
import { resolve, join } from "path";
|
|
@@ -3925,10 +2398,15 @@ function computeUsageHash(usage) {
|
|
|
3925
2398
|
usage.htmx.needsReactivity
|
|
3926
2399
|
].map((f) => f ? "1" : "0").join("") : "none";
|
|
3927
2400
|
const reactivity = `${usage.needsReactivity ? 1 : 0}${usage.needsBindToProperty ? 1 : 0}`;
|
|
3928
|
-
|
|
2401
|
+
const extras = `${usage.needsConstruct ? 1 : 0}${usage.needsCookies ? 1 : 0}`;
|
|
2402
|
+
return `${commands}|${blocks}|${usage.positional}|${languages}|${htmx}|${reactivity}|${extras}`;
|
|
3929
2403
|
}
|
|
3930
2404
|
function hyperfixi(options = {}) {
|
|
3931
|
-
|
|
2405
|
+
if (options.mode === "compile") {
|
|
2406
|
+
console.warn(
|
|
2407
|
+
`[hyperfixi] mode: "compile" was removed in 4.0 (it compiled with @hyperfixi/core's parser); building the bundle on @hyperfixi/engine instead.`
|
|
2408
|
+
);
|
|
2409
|
+
}
|
|
3932
2410
|
const scanner = new Scanner(options);
|
|
3933
2411
|
const aggregator = new Aggregator();
|
|
3934
2412
|
const generator = new Generator(options);
|
|
@@ -3938,11 +2416,6 @@ function hyperfixi(options = {}) {
|
|
|
3938
2416
|
let cachedBundle = null;
|
|
3939
2417
|
let lastUsageHash = "";
|
|
3940
2418
|
let isDev = false;
|
|
3941
|
-
const compiledHandlers = [];
|
|
3942
|
-
const handlerMap = /* @__PURE__ */ new Map();
|
|
3943
|
-
const fallbackScripts = /* @__PURE__ */ new Set();
|
|
3944
|
-
let needsLocals = false;
|
|
3945
|
-
let needsGlobals = false;
|
|
3946
2419
|
function invalidateVirtualModule() {
|
|
3947
2420
|
if (!server) return;
|
|
3948
2421
|
const mod = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_MODULE_ID);
|
|
@@ -3954,32 +2427,6 @@ function hyperfixi(options = {}) {
|
|
|
3954
2427
|
}
|
|
3955
2428
|
}
|
|
3956
2429
|
}
|
|
3957
|
-
function compileScript(script) {
|
|
3958
|
-
if (handlerMap.has(script)) {
|
|
3959
|
-
return handlerMap.get(script);
|
|
3960
|
-
}
|
|
3961
|
-
if (fallbackScripts.has(script)) {
|
|
3962
|
-
return null;
|
|
3963
|
-
}
|
|
3964
|
-
const handler = compile(script);
|
|
3965
|
-
if (handler) {
|
|
3966
|
-
compiledHandlers.push(handler);
|
|
3967
|
-
handlerMap.set(script, handler.id);
|
|
3968
|
-
if (handler.needsEvaluator) {
|
|
3969
|
-
if (handler.code.includes("L.")) needsLocals = true;
|
|
3970
|
-
if (handler.code.includes("G.")) needsGlobals = true;
|
|
3971
|
-
}
|
|
3972
|
-
if (options.debug) {
|
|
3973
|
-
console.log(`[hyperfixi] Compiled: "${script}" -> ${handler.id}`);
|
|
3974
|
-
}
|
|
3975
|
-
return handler.id;
|
|
3976
|
-
}
|
|
3977
|
-
fallbackScripts.add(script);
|
|
3978
|
-
if (options.debug) {
|
|
3979
|
-
console.log(`[hyperfixi] Fallback (not compilable): "${script}"`);
|
|
3980
|
-
}
|
|
3981
|
-
return null;
|
|
3982
|
-
}
|
|
3983
2430
|
function generateInterpretBundle() {
|
|
3984
2431
|
const usage = aggregator.getUsage();
|
|
3985
2432
|
const usageHash = computeUsageHash(usage);
|
|
@@ -3998,30 +2445,7 @@ function hyperfixi(options = {}) {
|
|
|
3998
2445
|
}
|
|
3999
2446
|
return cachedBundle;
|
|
4000
2447
|
}
|
|
4001
|
-
function generateCompiledBundleCode() {
|
|
4002
|
-
if (fallbackScripts.size > 0) {
|
|
4003
|
-
if (options.debug) {
|
|
4004
|
-
console.log(`[hyperfixi] ${fallbackScripts.size} scripts need interpreter fallback`);
|
|
4005
|
-
}
|
|
4006
|
-
return generateInterpretBundle();
|
|
4007
|
-
}
|
|
4008
|
-
const bundle = generateCompiledBundle({
|
|
4009
|
-
handlers: compiledHandlers,
|
|
4010
|
-
needsLocals,
|
|
4011
|
-
needsGlobals,
|
|
4012
|
-
globalName: options.globalName,
|
|
4013
|
-
htmx: options.htmx,
|
|
4014
|
-
debug: options.debug
|
|
4015
|
-
});
|
|
4016
|
-
if (options.debug) {
|
|
4017
|
-
console.log(`[hyperfixi] Compiled bundle: ${compiledHandlers.length} handlers`);
|
|
4018
|
-
}
|
|
4019
|
-
return bundle;
|
|
4020
|
-
}
|
|
4021
2448
|
function generateBundle() {
|
|
4022
|
-
if (mode === "compile") {
|
|
4023
|
-
return generateCompiledBundleCode();
|
|
4024
|
-
}
|
|
4025
2449
|
return generateInterpretBundle();
|
|
4026
2450
|
}
|
|
4027
2451
|
return {
|
|
@@ -4099,20 +2523,6 @@ function hyperfixi(options = {}) {
|
|
|
4099
2523
|
if (!scanner.shouldScan(id)) {
|
|
4100
2524
|
return null;
|
|
4101
2525
|
}
|
|
4102
|
-
if (mode === "compile" && !isDev) {
|
|
4103
|
-
const scripts = extractScripts(code);
|
|
4104
|
-
for (const script of scripts) {
|
|
4105
|
-
compileScript(script);
|
|
4106
|
-
}
|
|
4107
|
-
const result = transformHTML(code, handlerMap, fallbackScripts);
|
|
4108
|
-
if (result.modified) {
|
|
4109
|
-
if (options.debug) {
|
|
4110
|
-
console.log(`[hyperfixi] Transformed: ${id.split("/").pop()}`);
|
|
4111
|
-
}
|
|
4112
|
-
return { code: result.code, map: null };
|
|
4113
|
-
}
|
|
4114
|
-
return null;
|
|
4115
|
-
}
|
|
4116
2526
|
const usage = scanner.scan(code, id);
|
|
4117
2527
|
const changed = aggregator.add(id, usage);
|
|
4118
2528
|
if (domainScanner && domainAggregator && domainScanner.hasAnyDomainUsage(code)) {
|
|
@@ -4166,17 +2576,6 @@ function hyperfixi(options = {}) {
|
|
|
4166
2576
|
*/
|
|
4167
2577
|
async buildStart() {
|
|
4168
2578
|
if (!isDev) {
|
|
4169
|
-
if (mode === "compile") {
|
|
4170
|
-
resetCompiler();
|
|
4171
|
-
compiledHandlers.length = 0;
|
|
4172
|
-
handlerMap.clear();
|
|
4173
|
-
fallbackScripts.clear();
|
|
4174
|
-
needsLocals = false;
|
|
4175
|
-
needsGlobals = false;
|
|
4176
|
-
if (options.debug) {
|
|
4177
|
-
console.log("[hyperfixi] Compile mode: ready for build");
|
|
4178
|
-
}
|
|
4179
|
-
}
|
|
4180
2579
|
const cwd = process.cwd();
|
|
4181
2580
|
if (options.debug) {
|
|
4182
2581
|
console.log("[hyperfixi] Scanning project for hyperscript usage...");
|
|
@@ -4202,22 +2601,6 @@ function hyperfixi(options = {}) {
|
|
|
4202
2601
|
console.log("[hyperfixi] Domain build scan:", domainSummary);
|
|
4203
2602
|
}
|
|
4204
2603
|
}
|
|
4205
|
-
if (mode === "compile") {
|
|
4206
|
-
const usage = aggregator.getUsage();
|
|
4207
|
-
if (usage.detectedLanguages.size > 0) {
|
|
4208
|
-
const aliases = getMultilingualCommandAliases(
|
|
4209
|
-
usage.detectedLanguages
|
|
4210
|
-
);
|
|
4211
|
-
if (Object.keys(aliases).length > 0) {
|
|
4212
|
-
setMultilingualAliases(aliases);
|
|
4213
|
-
if (options.debug) {
|
|
4214
|
-
console.log(
|
|
4215
|
-
`[hyperfixi] Compile mode: configured ${Object.keys(aliases).length} multilingual aliases`
|
|
4216
|
-
);
|
|
4217
|
-
}
|
|
4218
|
-
}
|
|
4219
|
-
}
|
|
4220
|
-
}
|
|
4221
2604
|
if (options.debug) {
|
|
4222
2605
|
const summary = aggregator.getSummary();
|
|
4223
2606
|
console.log(`[hyperfixi] Found ${summary.fileCount} files with hyperscript:`, {
|
|
@@ -4241,7 +2624,6 @@ export {
|
|
|
4241
2624
|
REGIONS,
|
|
4242
2625
|
SUPPORTED_LANGUAGES,
|
|
4243
2626
|
clearCustomKeywords,
|
|
4244
|
-
clearSemanticParser,
|
|
4245
2627
|
computeUsageHash,
|
|
4246
2628
|
index_default as default,
|
|
4247
2629
|
descriptorToScanRule,
|
|
@@ -4249,10 +2631,8 @@ export {
|
|
|
4249
2631
|
getAllLanguageCodes,
|
|
4250
2632
|
getKeywordsForLanguage,
|
|
4251
2633
|
getOptimalRegion,
|
|
4252
|
-
hasSemanticParser,
|
|
4253
2634
|
hyperfixi,
|
|
4254
2635
|
isNonLatinLanguage,
|
|
4255
|
-
registerCustomKeywords
|
|
4256
|
-
setSemanticParser
|
|
2636
|
+
registerCustomKeywords
|
|
4257
2637
|
};
|
|
4258
2638
|
//# sourceMappingURL=index.js.map
|