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