@lokascript/compilation-service 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ODJIDVMN.js → chunk-JGAJAREK.js} +5 -118
- package/dist/chunk-JGAJAREK.js.map +1 -0
- package/dist/{chunk-JDOSUTCM.js → chunk-UQULNKOC.js} +2 -2
- package/dist/{core-parser-adapter-VCJB52SO-MDHRIVZ7.js → core-parser-adapter-VCJB52SO-5HK2TL6Q.js} +2 -2
- package/dist/{dist-JOIDNRL3.js → dist-KBC4YRQJ.js} +923 -253
- package/dist/dist-KBC4YRQJ.js.map +1 -0
- package/dist/{dist-ICUX26U7.js → dist-SWJWTU4Z.js} +550 -13
- package/dist/dist-SWJWTU4Z.js.map +1 -0
- package/dist/http.cjs +1473 -381
- package/dist/http.cjs.map +1 -1
- package/dist/http.d.cts +2 -1
- package/dist/http.d.ts +2 -1
- package/dist/http.js +1 -1
- package/dist/index.cjs +1478 -383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -23
- package/dist/index.d.ts +4 -23
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/{service-891L1MYk.d.cts → service-qk1aChG9.d.cts} +6 -25
- package/dist/{service-891L1MYk.d.ts → service-qk1aChG9.d.ts} +6 -25
- package/package.json +3 -1
- package/dist/chunk-ODJIDVMN.js.map +0 -1
- package/dist/dist-ICUX26U7.js.map +0 -1
- package/dist/dist-JOIDNRL3.js.map +0 -1
- /package/dist/{chunk-JDOSUTCM.js.map → chunk-UQULNKOC.js.map} +0 -0
- /package/dist/{core-parser-adapter-VCJB52SO-MDHRIVZ7.js.map → core-parser-adapter-VCJB52SO-5HK2TL6Q.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CoreParserAdapter,
|
|
3
3
|
createCoreParserAdapter
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UQULNKOC.js";
|
|
5
5
|
import {
|
|
6
6
|
SemanticParserAdapter,
|
|
7
7
|
createSemanticAdapter
|
|
@@ -9,6 +9,11 @@ import {
|
|
|
9
9
|
import "./chunk-HMLY7DHA.js";
|
|
10
10
|
|
|
11
11
|
// ../aot-compiler/dist/index.js
|
|
12
|
+
import {
|
|
13
|
+
isExplicitSyntax,
|
|
14
|
+
parseExplicit,
|
|
15
|
+
fromProtocolJSON
|
|
16
|
+
} from "@lokascript/framework";
|
|
12
17
|
var DEFAULT_OPTIONS = {
|
|
13
18
|
attributeNames: ["_", "data-hs", "data-hyperscript"],
|
|
14
19
|
includeScriptTags: true,
|
|
@@ -683,6 +688,166 @@ function analyze(ast) {
|
|
|
683
688
|
const analyzer = new Analyzer();
|
|
684
689
|
return analyzer.analyze(ast);
|
|
685
690
|
}
|
|
691
|
+
var CLASS_COMMANDS = /* @__PURE__ */ new Set(["add", "remove", "toggle"]);
|
|
692
|
+
function extractClassOp(node) {
|
|
693
|
+
if (node.type !== "command") return null;
|
|
694
|
+
const cmd = node;
|
|
695
|
+
if (!CLASS_COMMANDS.has(cmd.name)) return null;
|
|
696
|
+
const args = cmd.args ?? [];
|
|
697
|
+
if (args.length === 0) return null;
|
|
698
|
+
const arg = args[0];
|
|
699
|
+
if (arg.type !== "selector") return null;
|
|
700
|
+
const selector = arg.value;
|
|
701
|
+
if (!selector.startsWith(".")) return null;
|
|
702
|
+
const className = selector.slice(1);
|
|
703
|
+
if (!className) return null;
|
|
704
|
+
return {
|
|
705
|
+
command: cmd.name,
|
|
706
|
+
className,
|
|
707
|
+
hasExplicitTarget: !!cmd.target
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function isSameTarget(a, b) {
|
|
711
|
+
if (a.type !== "command" || b.type !== "command") return false;
|
|
712
|
+
const cmdA = a;
|
|
713
|
+
const cmdB = b;
|
|
714
|
+
if (!cmdA.target && !cmdB.target) return true;
|
|
715
|
+
if (cmdA.target && cmdB.target) {
|
|
716
|
+
return getTargetKey(cmdA.target) === getTargetKey(cmdB.target);
|
|
717
|
+
}
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
function getTargetKey(target) {
|
|
721
|
+
if (target.type === "selector") {
|
|
722
|
+
return `selector:${target.value}`;
|
|
723
|
+
}
|
|
724
|
+
if (target.type === "identifier") {
|
|
725
|
+
return `identifier:${target.value}`;
|
|
726
|
+
}
|
|
727
|
+
return null;
|
|
728
|
+
}
|
|
729
|
+
function resolveTarget(cmd) {
|
|
730
|
+
if (!cmd.target) return "_ctx.me";
|
|
731
|
+
if (cmd.target.type === "selector") {
|
|
732
|
+
const sel = cmd.target.value;
|
|
733
|
+
if (sel.startsWith("#") && !sel.includes(" ") && !sel.includes(".")) {
|
|
734
|
+
return `document.getElementById('${sel.slice(1)}')`;
|
|
735
|
+
}
|
|
736
|
+
return `document.querySelector('${sel}')`;
|
|
737
|
+
}
|
|
738
|
+
if (cmd.target.type === "identifier") {
|
|
739
|
+
const val = cmd.target.value;
|
|
740
|
+
if (val === "me") return "_ctx.me";
|
|
741
|
+
return val;
|
|
742
|
+
}
|
|
743
|
+
return "_ctx.me";
|
|
744
|
+
}
|
|
745
|
+
function createBatchNode(run) {
|
|
746
|
+
const adds = [];
|
|
747
|
+
const removes = [];
|
|
748
|
+
const toggles = [];
|
|
749
|
+
for (const node of run) {
|
|
750
|
+
const op = extractClassOp(node);
|
|
751
|
+
switch (op.command) {
|
|
752
|
+
case "add":
|
|
753
|
+
adds.push(op.className);
|
|
754
|
+
break;
|
|
755
|
+
case "remove":
|
|
756
|
+
removes.push(op.className);
|
|
757
|
+
break;
|
|
758
|
+
case "toggle":
|
|
759
|
+
toggles.push(op.className);
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
const target = resolveTarget(run[0]);
|
|
764
|
+
return {
|
|
765
|
+
type: "batchedClassOps",
|
|
766
|
+
target,
|
|
767
|
+
adds,
|
|
768
|
+
removes,
|
|
769
|
+
toggles
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
function batchBody(nodes) {
|
|
773
|
+
const result = [];
|
|
774
|
+
let currentRun = [];
|
|
775
|
+
function flushRun() {
|
|
776
|
+
if (currentRun.length >= 2) {
|
|
777
|
+
result.push(createBatchNode(currentRun));
|
|
778
|
+
} else if (currentRun.length === 1) {
|
|
779
|
+
result.push(currentRun[0]);
|
|
780
|
+
}
|
|
781
|
+
currentRun = [];
|
|
782
|
+
}
|
|
783
|
+
for (const node of nodes) {
|
|
784
|
+
const op = extractClassOp(node);
|
|
785
|
+
if (op) {
|
|
786
|
+
if (currentRun.length > 0 && isSameTarget(currentRun[0], node)) {
|
|
787
|
+
currentRun.push(node);
|
|
788
|
+
} else {
|
|
789
|
+
flushRun();
|
|
790
|
+
currentRun = [node];
|
|
791
|
+
}
|
|
792
|
+
} else {
|
|
793
|
+
flushRun();
|
|
794
|
+
result.push(node);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
flushRun();
|
|
798
|
+
return result;
|
|
799
|
+
}
|
|
800
|
+
function walkAndBatch(node) {
|
|
801
|
+
switch (node.type) {
|
|
802
|
+
case "event": {
|
|
803
|
+
const event = node;
|
|
804
|
+
if (event.body && event.body.length > 0) {
|
|
805
|
+
return { ...event, body: batchBody(event.body).map(walkAndBatch) };
|
|
806
|
+
}
|
|
807
|
+
return node;
|
|
808
|
+
}
|
|
809
|
+
case "if": {
|
|
810
|
+
const ifNode = node;
|
|
811
|
+
const result = { ...ifNode };
|
|
812
|
+
result.thenBranch = batchBody(ifNode.thenBranch).map(walkAndBatch);
|
|
813
|
+
if (ifNode.elseBranch) {
|
|
814
|
+
result.elseBranch = batchBody(ifNode.elseBranch).map(walkAndBatch);
|
|
815
|
+
}
|
|
816
|
+
if (ifNode.elseIfBranches) {
|
|
817
|
+
result.elseIfBranches = ifNode.elseIfBranches.map((branch) => ({
|
|
818
|
+
condition: branch.condition,
|
|
819
|
+
body: batchBody(branch.body).map(walkAndBatch)
|
|
820
|
+
}));
|
|
821
|
+
}
|
|
822
|
+
return result;
|
|
823
|
+
}
|
|
824
|
+
case "repeat": {
|
|
825
|
+
const repeat = node;
|
|
826
|
+
return { ...repeat, body: batchBody(repeat.body).map(walkAndBatch) };
|
|
827
|
+
}
|
|
828
|
+
case "foreach": {
|
|
829
|
+
const forEach = node;
|
|
830
|
+
return { ...forEach, body: batchBody(forEach.body).map(walkAndBatch) };
|
|
831
|
+
}
|
|
832
|
+
case "while": {
|
|
833
|
+
const whileNode = node;
|
|
834
|
+
return { ...whileNode, body: batchBody(whileNode.body).map(walkAndBatch) };
|
|
835
|
+
}
|
|
836
|
+
default:
|
|
837
|
+
return node;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
var ClassBatchingPass = class {
|
|
841
|
+
constructor() {
|
|
842
|
+
this.name = "class-batching";
|
|
843
|
+
}
|
|
844
|
+
shouldRun(analysis) {
|
|
845
|
+
return analysis.commandsUsed.has("add") || analysis.commandsUsed.has("remove") || analysis.commandsUsed.has("toggle");
|
|
846
|
+
}
|
|
847
|
+
transform(ast, _analysis) {
|
|
848
|
+
return walkAndBatch(ast);
|
|
849
|
+
}
|
|
850
|
+
};
|
|
686
851
|
var ConstantFoldingPass = class {
|
|
687
852
|
constructor() {
|
|
688
853
|
this.name = "constant-folding";
|
|
@@ -1007,6 +1172,7 @@ var OptimizationPipeline = class {
|
|
|
1007
1172
|
new ConstantFoldingPass(),
|
|
1008
1173
|
new SelectorCachingPass(),
|
|
1009
1174
|
new DeadCodeEliminationPass(),
|
|
1175
|
+
new ClassBatchingPass(),
|
|
1010
1176
|
new LoopUnrollingPass()
|
|
1011
1177
|
];
|
|
1012
1178
|
}
|
|
@@ -1039,12 +1205,184 @@ var OptimizationPipeline = class {
|
|
|
1039
1205
|
}
|
|
1040
1206
|
};
|
|
1041
1207
|
function createOptimizer() {
|
|
1042
|
-
return new OptimizationPipeline();
|
|
1208
|
+
return /* @__PURE__ */ new OptimizationPipeline();
|
|
1043
1209
|
}
|
|
1044
1210
|
function optimize(ast, analysis, level = 2) {
|
|
1045
1211
|
const pipeline = new OptimizationPipeline();
|
|
1046
1212
|
return pipeline.optimize(ast, analysis, level);
|
|
1047
1213
|
}
|
|
1214
|
+
function classifyCommand(node) {
|
|
1215
|
+
if (node.type !== "command") return null;
|
|
1216
|
+
const cmd = node;
|
|
1217
|
+
switch (cmd.name) {
|
|
1218
|
+
case "add":
|
|
1219
|
+
return classifyAddCommand(cmd);
|
|
1220
|
+
case "remove":
|
|
1221
|
+
return classifyRemoveCommand(cmd);
|
|
1222
|
+
case "put":
|
|
1223
|
+
return classifyPutCommand(cmd);
|
|
1224
|
+
case "set":
|
|
1225
|
+
return classifySetCommand(cmd);
|
|
1226
|
+
default:
|
|
1227
|
+
return null;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
function getIdTarget(cmd) {
|
|
1231
|
+
if (!cmd.target) return null;
|
|
1232
|
+
if (cmd.target.type !== "selector") return null;
|
|
1233
|
+
const sel = cmd.target.value;
|
|
1234
|
+
if (!sel.startsWith("#")) return null;
|
|
1235
|
+
return sel.slice(1);
|
|
1236
|
+
}
|
|
1237
|
+
function classifyAddCommand(cmd) {
|
|
1238
|
+
const targetId = getIdTarget(cmd);
|
|
1239
|
+
if (!targetId) return null;
|
|
1240
|
+
const args = cmd.args ?? [];
|
|
1241
|
+
if (args.length === 0) return null;
|
|
1242
|
+
const arg = args[0];
|
|
1243
|
+
if (arg.type !== "selector") return null;
|
|
1244
|
+
const val = arg.value;
|
|
1245
|
+
if (!val.startsWith(".")) return null;
|
|
1246
|
+
return { type: "addClass", targetId, value: val.slice(1) };
|
|
1247
|
+
}
|
|
1248
|
+
function classifyRemoveCommand(cmd) {
|
|
1249
|
+
const targetId = getIdTarget(cmd);
|
|
1250
|
+
if (!targetId) return null;
|
|
1251
|
+
const args = cmd.args ?? [];
|
|
1252
|
+
if (args.length === 0) return null;
|
|
1253
|
+
const arg = args[0];
|
|
1254
|
+
if (arg.type !== "selector") return null;
|
|
1255
|
+
const val = arg.value;
|
|
1256
|
+
if (!val.startsWith(".")) return null;
|
|
1257
|
+
return { type: "removeClass", targetId, value: val.slice(1) };
|
|
1258
|
+
}
|
|
1259
|
+
function classifyPutCommand(cmd) {
|
|
1260
|
+
const targetId = getIdTarget(cmd);
|
|
1261
|
+
if (!targetId) return null;
|
|
1262
|
+
const args = cmd.args ?? [];
|
|
1263
|
+
if (args.length === 0) return null;
|
|
1264
|
+
const arg = args[0];
|
|
1265
|
+
if (arg.type !== "literal") return null;
|
|
1266
|
+
const val = arg.value;
|
|
1267
|
+
if (typeof val !== "string") return null;
|
|
1268
|
+
return { type: "putContent", targetId, value: val };
|
|
1269
|
+
}
|
|
1270
|
+
function classifySetCommand(cmd) {
|
|
1271
|
+
const targetId = getIdTarget(cmd);
|
|
1272
|
+
if (!targetId) return null;
|
|
1273
|
+
const args = cmd.args ?? [];
|
|
1274
|
+
if (args.length < 2) return null;
|
|
1275
|
+
const attrArg = args[0];
|
|
1276
|
+
if (attrArg.type !== "identifier") return null;
|
|
1277
|
+
const attrValue = attrArg.value;
|
|
1278
|
+
if (!attrValue || !attrValue.startsWith("@")) return null;
|
|
1279
|
+
const attrName = attrValue.slice(1);
|
|
1280
|
+
const valArg = args[1];
|
|
1281
|
+
if (valArg.type !== "literal") return null;
|
|
1282
|
+
const val = valArg.value;
|
|
1283
|
+
if (typeof val !== "string" && typeof val !== "number") return null;
|
|
1284
|
+
return { type: "setAttribute", targetId, value: String(val), attrName };
|
|
1285
|
+
}
|
|
1286
|
+
function classifyInitCommands(commands) {
|
|
1287
|
+
const pure = [];
|
|
1288
|
+
const impure = [];
|
|
1289
|
+
for (let i = 0; i < commands.length; i++) {
|
|
1290
|
+
const classified = classifyCommand(commands[i]);
|
|
1291
|
+
if (classified) {
|
|
1292
|
+
pure.push({ index: i, command: classified });
|
|
1293
|
+
} else {
|
|
1294
|
+
impure.push({ index: i, node: commands[i] });
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
return { pure, impure };
|
|
1298
|
+
}
|
|
1299
|
+
function applyPureCommand(html, cmd) {
|
|
1300
|
+
switch (cmd.type) {
|
|
1301
|
+
case "addClass":
|
|
1302
|
+
return addClassToElement(html, cmd.targetId, cmd.value);
|
|
1303
|
+
case "removeClass":
|
|
1304
|
+
return removeClassFromElement(html, cmd.targetId, cmd.value);
|
|
1305
|
+
case "putContent":
|
|
1306
|
+
return putContentIntoElement(html, cmd.targetId, cmd.value);
|
|
1307
|
+
case "setAttribute":
|
|
1308
|
+
return setAttributeOnElement(html, cmd.targetId, cmd.attrName, cmd.value);
|
|
1309
|
+
default:
|
|
1310
|
+
return html;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
function transformElementById(html, id, transform) {
|
|
1314
|
+
const idPattern = new RegExp(`(<[^>]*\\bid=["']${escapeRegExp(id)}["'][^>]*>)`, "i");
|
|
1315
|
+
const match = html.match(idPattern);
|
|
1316
|
+
if (!match) return html;
|
|
1317
|
+
return html.replace(match[1], transform(match[1]));
|
|
1318
|
+
}
|
|
1319
|
+
function addClassToElement(html, id, className) {
|
|
1320
|
+
return transformElementById(html, id, (tag) => {
|
|
1321
|
+
const classMatch = tag.match(/\bclass=["']([^"']*)["']/i);
|
|
1322
|
+
if (classMatch) {
|
|
1323
|
+
const existing = classMatch[1];
|
|
1324
|
+
const classes = existing.split(/\s+/).filter(Boolean);
|
|
1325
|
+
if (!classes.includes(className)) {
|
|
1326
|
+
classes.push(className);
|
|
1327
|
+
}
|
|
1328
|
+
return tag.replace(classMatch[0], `class="${classes.join(" ")}"`);
|
|
1329
|
+
}
|
|
1330
|
+
return tag.replace(/>$/, ` class="${className}">`);
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
function removeClassFromElement(html, id, className) {
|
|
1334
|
+
return transformElementById(html, id, (tag) => {
|
|
1335
|
+
const classMatch = tag.match(/\bclass=["']([^"']*)["']/i);
|
|
1336
|
+
if (!classMatch) return tag;
|
|
1337
|
+
const classes = classMatch[1].split(/\s+/).filter((c) => c !== className);
|
|
1338
|
+
if (classes.length === 0) {
|
|
1339
|
+
return tag.replace(classMatch[0], "").replace(/\s+>/, ">");
|
|
1340
|
+
}
|
|
1341
|
+
return tag.replace(classMatch[0], `class="${classes.join(" ")}"`);
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
function putContentIntoElement(html, id, content) {
|
|
1345
|
+
const idPattern = new RegExp(
|
|
1346
|
+
`(<[a-zA-Z][^>]*\\bid=["']${escapeRegExp(id)}["'][^>]*>)((?:(?!<\\/[a-zA-Z]).)*?)(<\\/[a-zA-Z][^>]*>)`,
|
|
1347
|
+
"is"
|
|
1348
|
+
);
|
|
1349
|
+
const match = html.match(idPattern);
|
|
1350
|
+
if (!match) return html;
|
|
1351
|
+
return html.replace(match[0], `${match[1]}${escapeHtml(content)}${match[3]}`);
|
|
1352
|
+
}
|
|
1353
|
+
function setAttributeOnElement(html, id, attrName, value) {
|
|
1354
|
+
return transformElementById(html, id, (tag) => {
|
|
1355
|
+
const attrPattern = new RegExp(`\\b${escapeRegExp(attrName)}=["'][^"']*["']`, "i");
|
|
1356
|
+
const attrMatch = tag.match(attrPattern);
|
|
1357
|
+
if (attrMatch) {
|
|
1358
|
+
return tag.replace(attrMatch[0], `${attrName}="${escapeHtml(value)}"`);
|
|
1359
|
+
}
|
|
1360
|
+
return tag.replace(/>$/, ` ${attrName}="${escapeHtml(value)}">`);
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
function escapeRegExp(str) {
|
|
1364
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1365
|
+
}
|
|
1366
|
+
function escapeHtml(str) {
|
|
1367
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1368
|
+
}
|
|
1369
|
+
function preRenderInitBlock(html, initCommands) {
|
|
1370
|
+
const { pure, impure } = classifyInitCommands(initCommands);
|
|
1371
|
+
let modifiedHtml = html;
|
|
1372
|
+
let preRenderedCount = 0;
|
|
1373
|
+
for (const { command } of pure) {
|
|
1374
|
+
const before = modifiedHtml;
|
|
1375
|
+
modifiedHtml = applyPureCommand(modifiedHtml, command);
|
|
1376
|
+
if (modifiedHtml !== before) {
|
|
1377
|
+
preRenderedCount++;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
return {
|
|
1381
|
+
html: modifiedHtml,
|
|
1382
|
+
remainingInitCommands: impure.map((i) => i.node),
|
|
1383
|
+
preRenderedCount
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1048
1386
|
function sanitizeClassName(name) {
|
|
1049
1387
|
if (!/^-?[a-zA-Z_][a-zA-Z0-9_-]*$/.test(name)) {
|
|
1050
1388
|
return null;
|
|
@@ -2918,6 +3256,22 @@ var EventHandlerCodegen = class {
|
|
|
2918
3256
|
const nested = node;
|
|
2919
3257
|
return this.generateBody(nested.body ?? []);
|
|
2920
3258
|
}
|
|
3259
|
+
case "batchedClassOps": {
|
|
3260
|
+
const batch = node;
|
|
3261
|
+
const lines = [];
|
|
3262
|
+
if (batch.adds.length > 0) {
|
|
3263
|
+
lines.push(`${batch.target}.classList.add(${batch.adds.map((c) => `'${c}'`).join(", ")})`);
|
|
3264
|
+
}
|
|
3265
|
+
if (batch.removes.length > 0) {
|
|
3266
|
+
lines.push(
|
|
3267
|
+
`${batch.target}.classList.remove(${batch.removes.map((c) => `'${c}'`).join(", ")})`
|
|
3268
|
+
);
|
|
3269
|
+
}
|
|
3270
|
+
for (const t of batch.toggles) {
|
|
3271
|
+
lines.push(`${batch.target}.classList.toggle('${t}')`);
|
|
3272
|
+
}
|
|
3273
|
+
return lines.join(";\n");
|
|
3274
|
+
}
|
|
2921
3275
|
default:
|
|
2922
3276
|
return null;
|
|
2923
3277
|
}
|
|
@@ -3165,10 +3519,40 @@ var AOTCompiler = class {
|
|
|
3165
3519
|
// ===========================================================================
|
|
3166
3520
|
/**
|
|
3167
3521
|
* Parse a hyperscript string to AST.
|
|
3522
|
+
* Supports natural language, explicit bracket syntax, and JSON input.
|
|
3168
3523
|
*/
|
|
3169
3524
|
parse(code, options = {}) {
|
|
3170
3525
|
const { language = "en", confidenceThreshold = 0.7, debug = false } = options;
|
|
3171
3526
|
let ast = null;
|
|
3527
|
+
if (isExplicitSyntax(code)) {
|
|
3528
|
+
try {
|
|
3529
|
+
const node = parseExplicit(code);
|
|
3530
|
+
ast = this.semanticNodeToAOT(node);
|
|
3531
|
+
if (debug) {
|
|
3532
|
+
console.log(`[aot] Parsed explicit syntax: "${code}"`);
|
|
3533
|
+
}
|
|
3534
|
+
} catch (error) {
|
|
3535
|
+
if (debug) {
|
|
3536
|
+
console.log(`[aot] Explicit parse error for "${code}":`, error);
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
if (ast) return this.ensureEventHandler(ast);
|
|
3540
|
+
}
|
|
3541
|
+
if (this.looksLikeJSON(code)) {
|
|
3542
|
+
try {
|
|
3543
|
+
const json = JSON.parse(code.trim());
|
|
3544
|
+
const node = fromProtocolJSON(json);
|
|
3545
|
+
ast = this.semanticNodeToAOT(node);
|
|
3546
|
+
if (debug) {
|
|
3547
|
+
console.log(`[aot] Parsed JSON input: "${code.slice(0, 80)}..."`);
|
|
3548
|
+
}
|
|
3549
|
+
} catch (error) {
|
|
3550
|
+
if (debug) {
|
|
3551
|
+
console.log(`[aot] JSON parse error for "${code.slice(0, 80)}":`, error);
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3554
|
+
if (ast) return this.ensureEventHandler(ast);
|
|
3555
|
+
}
|
|
3172
3556
|
if (language !== "en" && this.semanticParser?.supportsLanguage(language)) {
|
|
3173
3557
|
const result = this.semanticParser.analyze(code, language);
|
|
3174
3558
|
if (result.node && result.confidence >= confidenceThreshold) {
|
|
@@ -3195,15 +3579,7 @@ var AOTCompiler = class {
|
|
|
3195
3579
|
if (!ast) {
|
|
3196
3580
|
ast = this.createSimpleAST(code);
|
|
3197
3581
|
}
|
|
3198
|
-
|
|
3199
|
-
ast = {
|
|
3200
|
-
type: "event",
|
|
3201
|
-
event: "click",
|
|
3202
|
-
modifiers: {},
|
|
3203
|
-
body: [ast]
|
|
3204
|
-
};
|
|
3205
|
-
}
|
|
3206
|
-
return ast;
|
|
3582
|
+
return this.ensureEventHandler(ast);
|
|
3207
3583
|
}
|
|
3208
3584
|
/**
|
|
3209
3585
|
* Create a simple AST from code (for testing without full parser).
|
|
@@ -3368,6 +3744,86 @@ var AOTCompiler = class {
|
|
|
3368
3744
|
return { type: "identifier", value: trimmed };
|
|
3369
3745
|
}
|
|
3370
3746
|
// ===========================================================================
|
|
3747
|
+
// EXPLICIT / JSON INPUT HELPERS
|
|
3748
|
+
// ===========================================================================
|
|
3749
|
+
/**
|
|
3750
|
+
* Check if input looks like JSON (LLM JSON format).
|
|
3751
|
+
*/
|
|
3752
|
+
looksLikeJSON(code) {
|
|
3753
|
+
const trimmed = code.trim();
|
|
3754
|
+
return trimmed.startsWith("{") && trimmed.includes('"action"');
|
|
3755
|
+
}
|
|
3756
|
+
/**
|
|
3757
|
+
* Ensure top-level node is always an event handler.
|
|
3758
|
+
* The codegen pipeline (EventHandlerCodegen) requires this.
|
|
3759
|
+
*/
|
|
3760
|
+
ensureEventHandler(ast) {
|
|
3761
|
+
if (ast && ast.type !== "event") {
|
|
3762
|
+
return {
|
|
3763
|
+
type: "event",
|
|
3764
|
+
event: "click",
|
|
3765
|
+
modifiers: {},
|
|
3766
|
+
body: [ast]
|
|
3767
|
+
};
|
|
3768
|
+
}
|
|
3769
|
+
return ast;
|
|
3770
|
+
}
|
|
3771
|
+
/**
|
|
3772
|
+
* Convert a framework SemanticNode to an AOT ASTNode.
|
|
3773
|
+
* Handles the simple cases produced by explicit/JSON parsing.
|
|
3774
|
+
*/
|
|
3775
|
+
semanticNodeToAOT(node) {
|
|
3776
|
+
if (node.kind === "event-handler") {
|
|
3777
|
+
const eh = node;
|
|
3778
|
+
const eventValue = eh.roles.get("event");
|
|
3779
|
+
const eventName = eventValue && "value" in eventValue ? String(eventValue.value) : "click";
|
|
3780
|
+
return {
|
|
3781
|
+
type: "event",
|
|
3782
|
+
event: eventName,
|
|
3783
|
+
modifiers: {},
|
|
3784
|
+
body: (eh.body ?? []).map((child) => this.semanticNodeToAOT(child))
|
|
3785
|
+
};
|
|
3786
|
+
}
|
|
3787
|
+
const roles = {};
|
|
3788
|
+
const args = [];
|
|
3789
|
+
for (const [roleName, value] of node.roles) {
|
|
3790
|
+
const astValue = this.semanticValueToAOT(value);
|
|
3791
|
+
roles[roleName] = astValue;
|
|
3792
|
+
args.push(astValue);
|
|
3793
|
+
}
|
|
3794
|
+
return {
|
|
3795
|
+
type: "command",
|
|
3796
|
+
name: node.action,
|
|
3797
|
+
args,
|
|
3798
|
+
roles
|
|
3799
|
+
};
|
|
3800
|
+
}
|
|
3801
|
+
/**
|
|
3802
|
+
* Convert a SemanticValue to an ASTNode.
|
|
3803
|
+
*/
|
|
3804
|
+
semanticValueToAOT(value) {
|
|
3805
|
+
switch (value.type) {
|
|
3806
|
+
case "selector":
|
|
3807
|
+
return { type: "selector", value: value.value };
|
|
3808
|
+
case "reference":
|
|
3809
|
+
return { type: "identifier", value: value.value };
|
|
3810
|
+
case "literal": {
|
|
3811
|
+
const lit = value;
|
|
3812
|
+
if (lit.dataType === "duration") {
|
|
3813
|
+
const str = String(lit.value);
|
|
3814
|
+
const match = /^(\d+(?:\.\d+)?)(ms|s)$/.exec(str);
|
|
3815
|
+
if (match) {
|
|
3816
|
+
const ms = match[2] === "s" ? parseFloat(match[1]) * 1e3 : parseFloat(match[1]);
|
|
3817
|
+
return { type: "literal", value: ms };
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
return { type: "literal", value: lit.value };
|
|
3821
|
+
}
|
|
3822
|
+
default:
|
|
3823
|
+
return { type: "literal", value: String(value.value ?? "") };
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
// ===========================================================================
|
|
3371
3827
|
// ANALYSIS
|
|
3372
3828
|
// ===========================================================================
|
|
3373
3829
|
/**
|
|
@@ -3377,6 +3833,63 @@ var AOTCompiler = class {
|
|
|
3377
3833
|
return this.analyzer.analyze(ast);
|
|
3378
3834
|
}
|
|
3379
3835
|
// ===========================================================================
|
|
3836
|
+
// INIT PRE-RENDERING
|
|
3837
|
+
// ===========================================================================
|
|
3838
|
+
/**
|
|
3839
|
+
* Pre-render pure init block commands into an HTML template at build time.
|
|
3840
|
+
*
|
|
3841
|
+
* Analyzes init block commands for purity (static DOM writes with literal
|
|
3842
|
+
* values targeting #id selectors) and applies them directly to the HTML.
|
|
3843
|
+
* Impure commands are preserved for normal runtime execution.
|
|
3844
|
+
*
|
|
3845
|
+
* @param html - The HTML template string
|
|
3846
|
+
* @param initCommands - Parsed commands from an init block
|
|
3847
|
+
* @returns Modified HTML, remaining impure commands, and count of pre-rendered commands
|
|
3848
|
+
*/
|
|
3849
|
+
preRenderInit(html, initCommands) {
|
|
3850
|
+
return preRenderInitBlock(html, initCommands);
|
|
3851
|
+
}
|
|
3852
|
+
/**
|
|
3853
|
+
* Extract init blocks from HTML, pre-render pure commands, and return modified HTML.
|
|
3854
|
+
* This is a higher-level convenience that combines extraction, parsing, and pre-rendering.
|
|
3855
|
+
*
|
|
3856
|
+
* @param html - The HTML template string
|
|
3857
|
+
* @param options - Compile options (language, etc.)
|
|
3858
|
+
* @returns Modified HTML with pre-rendered init effects and compilation results
|
|
3859
|
+
*/
|
|
3860
|
+
preRenderInitBlocks(html, options = {}) {
|
|
3861
|
+
const scripts = this.extract(html, "template.html");
|
|
3862
|
+
let modifiedHtml = html;
|
|
3863
|
+
let totalPreRendered = 0;
|
|
3864
|
+
const remainingScripts = [];
|
|
3865
|
+
for (const script of scripts) {
|
|
3866
|
+
const ast = this.parse(script.code, {
|
|
3867
|
+
...options,
|
|
3868
|
+
language: script.language ?? options.language ?? "en"
|
|
3869
|
+
});
|
|
3870
|
+
if (!ast) {
|
|
3871
|
+
remainingScripts.push(script);
|
|
3872
|
+
continue;
|
|
3873
|
+
}
|
|
3874
|
+
const eventNode = ast;
|
|
3875
|
+
if (eventNode.type === "event" && eventNode.event === "init" && eventNode.body) {
|
|
3876
|
+
const result = preRenderInitBlock(modifiedHtml, eventNode.body);
|
|
3877
|
+
modifiedHtml = result.html;
|
|
3878
|
+
totalPreRendered += result.preRenderedCount;
|
|
3879
|
+
if (result.remainingInitCommands.length > 0) {
|
|
3880
|
+
remainingScripts.push(script);
|
|
3881
|
+
}
|
|
3882
|
+
} else {
|
|
3883
|
+
remainingScripts.push(script);
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
return {
|
|
3887
|
+
html: modifiedHtml,
|
|
3888
|
+
preRenderedCount: totalPreRendered,
|
|
3889
|
+
remainingScripts
|
|
3890
|
+
};
|
|
3891
|
+
}
|
|
3892
|
+
// ===========================================================================
|
|
3380
3893
|
// COMPILATION
|
|
3381
3894
|
// ===========================================================================
|
|
3382
3895
|
/**
|
|
@@ -3499,6 +4012,30 @@ var AOTCompiler = class {
|
|
|
3499
4012
|
}
|
|
3500
4013
|
};
|
|
3501
4014
|
}
|
|
4015
|
+
/**
|
|
4016
|
+
* Compile explicit bracket syntax or LLM JSON to JavaScript.
|
|
4017
|
+
* Uses the framework IR directly — no semantic or traditional parser needed.
|
|
4018
|
+
*/
|
|
4019
|
+
compileExplicit(code, options = {}) {
|
|
4020
|
+
try {
|
|
4021
|
+
const ast = isExplicitSyntax(code) ? this.semanticNodeToAOT(parseExplicit(code)) : this.semanticNodeToAOT(fromProtocolJSON(JSON.parse(code.trim())));
|
|
4022
|
+
return this.compileAST(ast, options);
|
|
4023
|
+
} catch (error) {
|
|
4024
|
+
return {
|
|
4025
|
+
success: false,
|
|
4026
|
+
errors: [error instanceof Error ? error.message : String(error)],
|
|
4027
|
+
warnings: [],
|
|
4028
|
+
metadata: {
|
|
4029
|
+
handlerId: "",
|
|
4030
|
+
parserUsed: "traditional",
|
|
4031
|
+
commandsUsed: [],
|
|
4032
|
+
optimizationsApplied: [],
|
|
4033
|
+
needsRuntime: false,
|
|
4034
|
+
runtimeHelpers: []
|
|
4035
|
+
}
|
|
4036
|
+
};
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
3502
4039
|
/**
|
|
3503
4040
|
* Compile multiple extracted scripts.
|
|
3504
4041
|
*/
|
|
@@ -3734,7 +4271,7 @@ async function compileHyperscript(code, options) {
|
|
|
3734
4271
|
async function createMultilingualCompiler() {
|
|
3735
4272
|
const compiler = new AOTCompiler();
|
|
3736
4273
|
try {
|
|
3737
|
-
const { createCoreParserAdapter: createCoreParserAdapter2 } = await import("./core-parser-adapter-VCJB52SO-
|
|
4274
|
+
const { createCoreParserAdapter: createCoreParserAdapter2 } = await import("./core-parser-adapter-VCJB52SO-5HK2TL6Q.js");
|
|
3738
4275
|
compiler.setParser(await createCoreParserAdapter2());
|
|
3739
4276
|
} catch {
|
|
3740
4277
|
}
|
|
@@ -3787,4 +4324,4 @@ export {
|
|
|
3787
4324
|
sanitizeSelector,
|
|
3788
4325
|
scanFiles
|
|
3789
4326
|
};
|
|
3790
|
-
//# sourceMappingURL=dist-
|
|
4327
|
+
//# sourceMappingURL=dist-SWJWTU4Z.js.map
|