@fictjs/compiler 0.15.0 → 0.17.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/index.cjs +876 -64
- package/dist/index.d.cts +393 -1
- package/dist/index.d.ts +393 -1
- package/dist/index.js +874 -64
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3059,7 +3059,7 @@ var require_identifier = __commonJS({
|
|
|
3059
3059
|
value: true
|
|
3060
3060
|
});
|
|
3061
3061
|
exports.isIdentifierChar = isIdentifierChar;
|
|
3062
|
-
exports.isIdentifierName =
|
|
3062
|
+
exports.isIdentifierName = isIdentifierName2;
|
|
3063
3063
|
exports.isIdentifierStart = isIdentifierStart;
|
|
3064
3064
|
var nonASCIIidentifierStartChars = "\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u0870-\u0887\u0889-\u088F\u08A0-\u08C9\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C5C\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDC-\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u1711\u171F-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4C\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C8A\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7DC\uA7F1-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC";
|
|
3065
3065
|
var nonASCIIidentifierChars = "\xB7\u0300-\u036F\u0387\u0483-\u0487\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u0669\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u06F0-\u06F9\u0711\u0730-\u074A\u07A6-\u07B0\u07C0-\u07C9\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0897-\u089F\u08CA-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0966-\u096F\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09E6-\u09EF\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A66-\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AE6-\u0AEF\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B55-\u0B57\u0B62\u0B63\u0B66-\u0B6F\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0BE6-\u0BEF\u0C00-\u0C04\u0C3C\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0CE6-\u0CEF\u0CF3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D66-\u0D6F\u0D81-\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0E50-\u0E59\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0ED0-\u0ED9\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1040-\u1049\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F-\u109D\u135D-\u135F\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u17E0-\u17E9\u180B-\u180D\u180F-\u1819\u18A9\u1920-\u192B\u1930-\u193B\u1946-\u194F\u19D0-\u19DA\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AB0-\u1ABD\u1ABF-\u1ADD\u1AE0-\u1AEB\u1B00-\u1B04\u1B34-\u1B44\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BB0-\u1BB9\u1BE6-\u1BF3\u1C24-\u1C37\u1C40-\u1C49\u1C50-\u1C59\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DFF\u200C\u200D\u203F\u2040\u2054\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\u30FB\uA620-\uA629\uA66F\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA82C\uA880\uA881\uA8B4-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F1\uA8FF-\uA909\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9D0-\uA9D9\uA9E5\uA9F0-\uA9F9\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA50-\uAA59\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uABF0-\uABF9\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFF10-\uFF19\uFF3F\uFF65";
|
|
@@ -3100,7 +3100,7 @@ var require_identifier = __commonJS({
|
|
|
3100
3100
|
}
|
|
3101
3101
|
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
|
|
3102
3102
|
}
|
|
3103
|
-
function
|
|
3103
|
+
function isIdentifierName2(name) {
|
|
3104
3104
|
let isFirst = true;
|
|
3105
3105
|
for (let i = 0; i < name.length; i++) {
|
|
3106
3106
|
let cp = name.charCodeAt(i);
|
|
@@ -17073,6 +17073,37 @@ function clearModuleMetadata(options) {
|
|
|
17073
17073
|
}
|
|
17074
17074
|
|
|
17075
17075
|
// src/validation.ts
|
|
17076
|
+
var DiagnosticCode = /* @__PURE__ */ ((DiagnosticCode2) => {
|
|
17077
|
+
DiagnosticCode2["FICT_P001"] = "FICT-P001";
|
|
17078
|
+
DiagnosticCode2["FICT_P002"] = "FICT-P002";
|
|
17079
|
+
DiagnosticCode2["FICT_P003"] = "FICT-P003";
|
|
17080
|
+
DiagnosticCode2["FICT_P004"] = "FICT-P004";
|
|
17081
|
+
DiagnosticCode2["FICT_P005"] = "FICT-P005";
|
|
17082
|
+
DiagnosticCode2["FICT_S001"] = "FICT-S001";
|
|
17083
|
+
DiagnosticCode2["FICT_S002"] = "FICT-S002";
|
|
17084
|
+
DiagnosticCode2["FICT_E001"] = "FICT-E001";
|
|
17085
|
+
DiagnosticCode2["FICT_E002"] = "FICT-E002";
|
|
17086
|
+
DiagnosticCode2["FICT_E003"] = "FICT-E003";
|
|
17087
|
+
DiagnosticCode2["FICT_M001"] = "FICT-M001";
|
|
17088
|
+
DiagnosticCode2["FICT_M002"] = "FICT-M002";
|
|
17089
|
+
DiagnosticCode2["FICT_M003"] = "FICT-M003";
|
|
17090
|
+
DiagnosticCode2["FICT_C001"] = "FICT-C001";
|
|
17091
|
+
DiagnosticCode2["FICT_C002"] = "FICT-C002";
|
|
17092
|
+
DiagnosticCode2["FICT_C003"] = "FICT-C003";
|
|
17093
|
+
DiagnosticCode2["FICT_C004"] = "FICT-C004";
|
|
17094
|
+
DiagnosticCode2["FICT_J001"] = "FICT-J001";
|
|
17095
|
+
DiagnosticCode2["FICT_J002"] = "FICT-J002";
|
|
17096
|
+
DiagnosticCode2["FICT_J003"] = "FICT-J003";
|
|
17097
|
+
DiagnosticCode2["FICT_R001"] = "FICT-R001";
|
|
17098
|
+
DiagnosticCode2["FICT_R002"] = "FICT-R002";
|
|
17099
|
+
DiagnosticCode2["FICT_R003"] = "FICT-R003";
|
|
17100
|
+
DiagnosticCode2["FICT_R004"] = "FICT-R004";
|
|
17101
|
+
DiagnosticCode2["FICT_R005"] = "FICT-R005";
|
|
17102
|
+
DiagnosticCode2["FICT_X001"] = "FICT-X001";
|
|
17103
|
+
DiagnosticCode2["FICT_X002"] = "FICT-X002";
|
|
17104
|
+
DiagnosticCode2["FICT_X003"] = "FICT-X003";
|
|
17105
|
+
return DiagnosticCode2;
|
|
17106
|
+
})(DiagnosticCode || {});
|
|
17076
17107
|
var DiagnosticMessages = {
|
|
17077
17108
|
["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
|
|
17078
17109
|
["FICT-P002" /* FICT_P002 */]: "Array rest in props destructuring falls back to non-reactive binding.",
|
|
@@ -17160,6 +17191,16 @@ function reportDiagnostic(ctx, code, node, context) {
|
|
|
17160
17191
|
});
|
|
17161
17192
|
}
|
|
17162
17193
|
}
|
|
17194
|
+
function getAllDiagnosticCodes() {
|
|
17195
|
+
return Object.values(DiagnosticCode);
|
|
17196
|
+
}
|
|
17197
|
+
function getDiagnosticInfo(code) {
|
|
17198
|
+
return {
|
|
17199
|
+
code,
|
|
17200
|
+
severity: DiagnosticSeverities[code],
|
|
17201
|
+
message: DiagnosticMessages[code]
|
|
17202
|
+
};
|
|
17203
|
+
}
|
|
17163
17204
|
|
|
17164
17205
|
// src/ir/ssa.ts
|
|
17165
17206
|
function enterSSA(program) {
|
|
@@ -18880,6 +18921,22 @@ function structurizeBlockUntilJoin(ctx, blockId, joinBlock) {
|
|
|
18880
18921
|
if (branchNode) nodes.push(branchNode);
|
|
18881
18922
|
break;
|
|
18882
18923
|
}
|
|
18924
|
+
case "Switch": {
|
|
18925
|
+
nodes.push(structurizeSwitch(ctx, block, term));
|
|
18926
|
+
break;
|
|
18927
|
+
}
|
|
18928
|
+
case "ForOf": {
|
|
18929
|
+
nodes.push(structurizeForOf(ctx, block, term));
|
|
18930
|
+
break;
|
|
18931
|
+
}
|
|
18932
|
+
case "ForIn": {
|
|
18933
|
+
nodes.push(structurizeForIn(ctx, block, term));
|
|
18934
|
+
break;
|
|
18935
|
+
}
|
|
18936
|
+
case "Try": {
|
|
18937
|
+
nodes.push(structurizeTry(ctx, block, term));
|
|
18938
|
+
break;
|
|
18939
|
+
}
|
|
18883
18940
|
case "Break":
|
|
18884
18941
|
nodes.push({ kind: "break", label: term.label });
|
|
18885
18942
|
break;
|
|
@@ -19014,7 +19071,9 @@ function isSwitchCaseTerminated(node) {
|
|
|
19014
19071
|
}
|
|
19015
19072
|
}
|
|
19016
19073
|
function structurizeForOf(ctx, block, term) {
|
|
19074
|
+
ctx.reservedBlocks.add(term.exit);
|
|
19017
19075
|
const body = structurizeBlock(ctx, term.body);
|
|
19076
|
+
ctx.reservedBlocks.delete(term.exit);
|
|
19018
19077
|
const exit = !ctx.emitted.has(term.exit) ? structurizeBlock(ctx, term.exit) : null;
|
|
19019
19078
|
const forOfNode = {
|
|
19020
19079
|
kind: "forOf",
|
|
@@ -19030,7 +19089,9 @@ function structurizeForOf(ctx, block, term) {
|
|
|
19030
19089
|
return forOfNode;
|
|
19031
19090
|
}
|
|
19032
19091
|
function structurizeForIn(ctx, block, term) {
|
|
19092
|
+
ctx.reservedBlocks.add(term.exit);
|
|
19033
19093
|
const body = structurizeBlock(ctx, term.body);
|
|
19094
|
+
ctx.reservedBlocks.delete(term.exit);
|
|
19034
19095
|
const exit = !ctx.emitted.has(term.exit) ? structurizeBlock(ctx, term.exit) : null;
|
|
19035
19096
|
const forInNode = {
|
|
19036
19097
|
kind: "forIn",
|
|
@@ -24252,34 +24313,138 @@ function extractKeyFromAttributes(attributes) {
|
|
|
24252
24313
|
}
|
|
24253
24314
|
return void 0;
|
|
24254
24315
|
}
|
|
24316
|
+
function collectReturnedJSXFromExpression(expression, returned) {
|
|
24317
|
+
if (expression.kind === "JSXElement") {
|
|
24318
|
+
returned.push(expression);
|
|
24319
|
+
return;
|
|
24320
|
+
}
|
|
24321
|
+
if (expression.kind === "ConditionalExpression") {
|
|
24322
|
+
collectReturnedJSXFromExpression(expression.consequent, returned);
|
|
24323
|
+
collectReturnedJSXFromExpression(expression.alternate, returned);
|
|
24324
|
+
return;
|
|
24325
|
+
}
|
|
24326
|
+
if (expression.kind === "LogicalExpression") {
|
|
24327
|
+
collectReturnedJSXFromExpression(expression.left, returned);
|
|
24328
|
+
collectReturnedJSXFromExpression(expression.right, returned);
|
|
24329
|
+
return;
|
|
24330
|
+
}
|
|
24331
|
+
if (expression.kind === "SequenceExpression") {
|
|
24332
|
+
const tail = expression.expressions[expression.expressions.length - 1];
|
|
24333
|
+
if (tail) collectReturnedJSXFromExpression(tail, returned);
|
|
24334
|
+
}
|
|
24335
|
+
}
|
|
24336
|
+
function extractKeyExpressionFromReturnedExpression(expression) {
|
|
24337
|
+
if (expression.kind === "JSXElement") {
|
|
24338
|
+
return extractKeyFromAttributes(expression.attributes);
|
|
24339
|
+
}
|
|
24340
|
+
if (expression.kind === "ConditionalExpression") {
|
|
24341
|
+
const consequentKey = extractKeyExpressionFromReturnedExpression(expression.consequent);
|
|
24342
|
+
const alternateKey = extractKeyExpressionFromReturnedExpression(expression.alternate);
|
|
24343
|
+
if (!consequentKey || !alternateKey) return void 0;
|
|
24344
|
+
return {
|
|
24345
|
+
kind: "ConditionalExpression",
|
|
24346
|
+
test: expression.test,
|
|
24347
|
+
consequent: consequentKey,
|
|
24348
|
+
alternate: alternateKey,
|
|
24349
|
+
loc: expression.loc
|
|
24350
|
+
};
|
|
24351
|
+
}
|
|
24352
|
+
if (expression.kind === "SequenceExpression") {
|
|
24353
|
+
const tail = expression.expressions[expression.expressions.length - 1];
|
|
24354
|
+
return tail ? extractKeyExpressionFromReturnedExpression(tail) : void 0;
|
|
24355
|
+
}
|
|
24356
|
+
return void 0;
|
|
24357
|
+
}
|
|
24358
|
+
function getReturnedKeyExpressionsFromCallback(callback) {
|
|
24359
|
+
const returned = [];
|
|
24360
|
+
if (callback.kind === "ArrowFunction") {
|
|
24361
|
+
if (callback.isExpression && !Array.isArray(callback.body)) {
|
|
24362
|
+
const keyExpr = extractKeyExpressionFromReturnedExpression(callback.body);
|
|
24363
|
+
if (keyExpr) returned.push(keyExpr);
|
|
24364
|
+
return returned;
|
|
24365
|
+
}
|
|
24366
|
+
if (Array.isArray(callback.body)) {
|
|
24367
|
+
for (const block of callback.body) {
|
|
24368
|
+
const term = block.terminator;
|
|
24369
|
+
if (term.kind !== "Return" || !term.argument) continue;
|
|
24370
|
+
const keyExpr = extractKeyExpressionFromReturnedExpression(term.argument);
|
|
24371
|
+
if (keyExpr) returned.push(keyExpr);
|
|
24372
|
+
}
|
|
24373
|
+
}
|
|
24374
|
+
return returned;
|
|
24375
|
+
}
|
|
24376
|
+
if (callback.kind === "FunctionExpression") {
|
|
24377
|
+
for (const block of callback.body ?? []) {
|
|
24378
|
+
const term = block.terminator;
|
|
24379
|
+
if (term.kind !== "Return" || !term.argument) continue;
|
|
24380
|
+
const keyExpr = extractKeyExpressionFromReturnedExpression(term.argument);
|
|
24381
|
+
if (keyExpr) returned.push(keyExpr);
|
|
24382
|
+
}
|
|
24383
|
+
}
|
|
24384
|
+
return returned;
|
|
24385
|
+
}
|
|
24255
24386
|
function getReturnedJSXFromCallback(callback) {
|
|
24387
|
+
const returned = [];
|
|
24256
24388
|
if (callback.kind === "ArrowFunction") {
|
|
24257
|
-
if (callback.isExpression && !Array.isArray(callback.body)
|
|
24258
|
-
|
|
24389
|
+
if (callback.isExpression && !Array.isArray(callback.body)) {
|
|
24390
|
+
collectReturnedJSXFromExpression(callback.body, returned);
|
|
24391
|
+
return returned;
|
|
24259
24392
|
}
|
|
24260
24393
|
if (Array.isArray(callback.body)) {
|
|
24261
24394
|
for (const block of callback.body) {
|
|
24262
24395
|
const term = block.terminator;
|
|
24263
|
-
if (term.kind === "Return" && term.argument
|
|
24264
|
-
|
|
24396
|
+
if (term.kind === "Return" && term.argument) {
|
|
24397
|
+
collectReturnedJSXFromExpression(term.argument, returned);
|
|
24265
24398
|
}
|
|
24266
24399
|
}
|
|
24267
24400
|
}
|
|
24401
|
+
return returned;
|
|
24268
24402
|
}
|
|
24269
24403
|
if (callback.kind === "FunctionExpression") {
|
|
24270
24404
|
for (const block of callback.body ?? []) {
|
|
24271
24405
|
const term = block.terminator;
|
|
24272
|
-
if (term.kind === "Return" && term.argument
|
|
24273
|
-
|
|
24406
|
+
if (term.kind === "Return" && term.argument) {
|
|
24407
|
+
collectReturnedJSXFromExpression(term.argument, returned);
|
|
24274
24408
|
}
|
|
24275
24409
|
}
|
|
24276
24410
|
}
|
|
24277
|
-
return
|
|
24411
|
+
return returned;
|
|
24412
|
+
}
|
|
24413
|
+
function keyExpressionSignature(expression) {
|
|
24414
|
+
try {
|
|
24415
|
+
return JSON.stringify(expression, (key, value) => {
|
|
24416
|
+
if (key === "loc") return void 0;
|
|
24417
|
+
if (typeof value === "bigint") return `__bigint:${value.toString()}`;
|
|
24418
|
+
return value;
|
|
24419
|
+
}) ?? "";
|
|
24420
|
+
} catch {
|
|
24421
|
+
return "";
|
|
24422
|
+
}
|
|
24278
24423
|
}
|
|
24279
24424
|
function extractKeyFromMapCallback(callback) {
|
|
24280
|
-
const
|
|
24281
|
-
if (
|
|
24282
|
-
|
|
24425
|
+
const returnedKeyExpressions = getReturnedKeyExpressionsFromCallback(callback);
|
|
24426
|
+
if (returnedKeyExpressions.length === 1) {
|
|
24427
|
+
return returnedKeyExpressions[0];
|
|
24428
|
+
}
|
|
24429
|
+
if (returnedKeyExpressions.length > 1) {
|
|
24430
|
+
const [firstKey2, ...restKeys2] = returnedKeyExpressions;
|
|
24431
|
+
const firstSignature2 = keyExpressionSignature(firstKey2);
|
|
24432
|
+
if (firstSignature2 && restKeys2.every((keyExpr) => keyExpressionSignature(keyExpr) === firstSignature2)) {
|
|
24433
|
+
return firstKey2;
|
|
24434
|
+
}
|
|
24435
|
+
}
|
|
24436
|
+
const returned = getReturnedJSXFromCallback(callback);
|
|
24437
|
+
if (returned.length === 0) return void 0;
|
|
24438
|
+
const keyExpressions = returned.map((jsx) => extractKeyFromAttributes(jsx.attributes));
|
|
24439
|
+
if (keyExpressions.some((expr) => !expr)) return void 0;
|
|
24440
|
+
const [firstKey, ...restKeys] = keyExpressions;
|
|
24441
|
+
const firstSignature = keyExpressionSignature(firstKey);
|
|
24442
|
+
if (!firstSignature) return void 0;
|
|
24443
|
+
const allBranchesSameKey = restKeys.every(
|
|
24444
|
+
(keyExpr) => keyExpressionSignature(keyExpr) === firstSignature
|
|
24445
|
+
);
|
|
24446
|
+
if (!allBranchesSameKey) return void 0;
|
|
24447
|
+
return firstKey;
|
|
24283
24448
|
}
|
|
24284
24449
|
|
|
24285
24450
|
// src/ir/codegen-overrides.ts
|
|
@@ -24884,6 +25049,15 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24884
25049
|
ctx.inListRender = true;
|
|
24885
25050
|
let callbackExpr = ops.lowerExpression(mapCallback, ctx);
|
|
24886
25051
|
ctx.inListRender = prevInListRender;
|
|
25052
|
+
const shouldDeferOptionalCallbackEvaluation = isOptional && !t4.isArrowFunctionExpression(callbackExpr) && !t4.isFunctionExpression(callbackExpr);
|
|
25053
|
+
let deferredCallbackId = null;
|
|
25054
|
+
let deferredCallbackInitId = null;
|
|
25055
|
+
let deferredItemsId = null;
|
|
25056
|
+
if (shouldDeferOptionalCallbackEvaluation) {
|
|
25057
|
+
deferredCallbackId = ops.genTemp(ctx, "mapCb");
|
|
25058
|
+
deferredCallbackInitId = ops.genTemp(ctx, "mapCbReady");
|
|
25059
|
+
deferredItemsId = ops.genTemp(ctx, "mapItems");
|
|
25060
|
+
}
|
|
24887
25061
|
const capturedKeyParamName = ctx.listKeyParamName;
|
|
24888
25062
|
ctx.listKeyExpr = prevListKeyExpr;
|
|
24889
25063
|
ctx.listItemParamName = prevListItemParamName;
|
|
@@ -24983,7 +25157,7 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24983
25157
|
],
|
|
24984
25158
|
keyExprAst
|
|
24985
25159
|
);
|
|
24986
|
-
const hasIndexParam = (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
|
|
25160
|
+
const hasIndexParam = shouldDeferOptionalCallbackEvaluation || (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
|
|
24987
25161
|
if (canConstifyKey && (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr))) {
|
|
24988
25162
|
const newParams = [...callbackExpr.params];
|
|
24989
25163
|
while (newParams.length < 2) {
|
|
@@ -25003,25 +25177,131 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
25003
25177
|
}
|
|
25004
25178
|
}
|
|
25005
25179
|
statements.push(...hoistedStatements);
|
|
25180
|
+
if (shouldDeferOptionalCallbackEvaluation) {
|
|
25181
|
+
statements.push(
|
|
25182
|
+
t4.variableDeclaration("let", [
|
|
25183
|
+
t4.variableDeclarator(t4.cloneNode(deferredCallbackId, true))
|
|
25184
|
+
]),
|
|
25185
|
+
t4.variableDeclaration("let", [
|
|
25186
|
+
t4.variableDeclarator(t4.cloneNode(deferredCallbackInitId, true), t4.booleanLiteral(false))
|
|
25187
|
+
])
|
|
25188
|
+
);
|
|
25189
|
+
}
|
|
25190
|
+
const getItemsExpr = shouldDeferOptionalCallbackEvaluation ? t4.arrowFunctionExpression(
|
|
25191
|
+
[],
|
|
25192
|
+
t4.blockStatement([
|
|
25193
|
+
t4.variableDeclaration("const", [
|
|
25194
|
+
t4.variableDeclarator(
|
|
25195
|
+
t4.cloneNode(deferredItemsId, true),
|
|
25196
|
+
t4.cloneNode(arrayExprBase, true)
|
|
25197
|
+
)
|
|
25198
|
+
]),
|
|
25199
|
+
t4.ifStatement(
|
|
25200
|
+
t4.binaryExpression("==", t4.cloneNode(deferredItemsId, true), t4.nullLiteral()),
|
|
25201
|
+
t4.blockStatement([t4.returnStatement(t4.arrayExpression([]))])
|
|
25202
|
+
),
|
|
25203
|
+
t4.ifStatement(
|
|
25204
|
+
t4.unaryExpression("!", t4.cloneNode(deferredCallbackInitId, true)),
|
|
25205
|
+
t4.blockStatement([
|
|
25206
|
+
t4.expressionStatement(
|
|
25207
|
+
t4.assignmentExpression(
|
|
25208
|
+
"=",
|
|
25209
|
+
t4.cloneNode(deferredCallbackId, true),
|
|
25210
|
+
t4.cloneNode(callbackExpr, true)
|
|
25211
|
+
)
|
|
25212
|
+
),
|
|
25213
|
+
t4.expressionStatement(
|
|
25214
|
+
t4.assignmentExpression(
|
|
25215
|
+
"=",
|
|
25216
|
+
t4.cloneNode(deferredCallbackInitId, true),
|
|
25217
|
+
t4.booleanLiteral(true)
|
|
25218
|
+
)
|
|
25219
|
+
)
|
|
25220
|
+
])
|
|
25221
|
+
),
|
|
25222
|
+
t4.returnStatement(t4.cloneNode(deferredItemsId, true))
|
|
25223
|
+
])
|
|
25224
|
+
) : t4.arrowFunctionExpression([], arrayExpr);
|
|
25225
|
+
const renderExpr = shouldDeferOptionalCallbackEvaluation ? t4.arrowFunctionExpression(
|
|
25226
|
+
[t4.identifier("__item"), t4.identifier("__index"), t4.identifier("__key")],
|
|
25227
|
+
t4.callExpression(t4.cloneNode(deferredCallbackId, true), [
|
|
25228
|
+
t4.identifier("__item"),
|
|
25229
|
+
t4.identifier("__index"),
|
|
25230
|
+
t4.identifier("__key")
|
|
25231
|
+
])
|
|
25232
|
+
) : callbackExpr;
|
|
25006
25233
|
listCall = t4.callExpression(t4.identifier(RUNTIME_ALIASES.keyedList), [
|
|
25007
|
-
|
|
25234
|
+
getItemsExpr,
|
|
25008
25235
|
keyFn,
|
|
25009
|
-
|
|
25236
|
+
renderExpr,
|
|
25010
25237
|
t4.booleanLiteral(hasIndexParam)
|
|
25011
25238
|
]);
|
|
25012
25239
|
} else {
|
|
25013
25240
|
statements.push(...hoistedStatements);
|
|
25241
|
+
if (shouldDeferOptionalCallbackEvaluation) {
|
|
25242
|
+
statements.push(
|
|
25243
|
+
t4.variableDeclaration("let", [
|
|
25244
|
+
t4.variableDeclarator(t4.cloneNode(deferredCallbackId, true))
|
|
25245
|
+
]),
|
|
25246
|
+
t4.variableDeclaration("let", [
|
|
25247
|
+
t4.variableDeclarator(t4.cloneNode(deferredCallbackInitId, true), t4.booleanLiteral(false))
|
|
25248
|
+
])
|
|
25249
|
+
);
|
|
25250
|
+
}
|
|
25014
25251
|
const itemParamName = t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr) ? t4.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : "__item" : "__item";
|
|
25015
25252
|
const indexParamName = t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr) ? t4.isIdentifier(callbackExpr.params[1]) ? callbackExpr.params[1].name : "__index" : "__index";
|
|
25016
|
-
const hasIndexParam = (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
|
|
25253
|
+
const hasIndexParam = shouldDeferOptionalCallbackEvaluation || (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
|
|
25254
|
+
const getItemsExpr = shouldDeferOptionalCallbackEvaluation ? t4.arrowFunctionExpression(
|
|
25255
|
+
[],
|
|
25256
|
+
t4.blockStatement([
|
|
25257
|
+
t4.variableDeclaration("const", [
|
|
25258
|
+
t4.variableDeclarator(
|
|
25259
|
+
t4.cloneNode(deferredItemsId, true),
|
|
25260
|
+
t4.cloneNode(arrayExprBase, true)
|
|
25261
|
+
)
|
|
25262
|
+
]),
|
|
25263
|
+
t4.ifStatement(
|
|
25264
|
+
t4.binaryExpression("==", t4.cloneNode(deferredItemsId, true), t4.nullLiteral()),
|
|
25265
|
+
t4.blockStatement([t4.returnStatement(t4.arrayExpression([]))])
|
|
25266
|
+
),
|
|
25267
|
+
t4.ifStatement(
|
|
25268
|
+
t4.unaryExpression("!", t4.cloneNode(deferredCallbackInitId, true)),
|
|
25269
|
+
t4.blockStatement([
|
|
25270
|
+
t4.expressionStatement(
|
|
25271
|
+
t4.assignmentExpression(
|
|
25272
|
+
"=",
|
|
25273
|
+
t4.cloneNode(deferredCallbackId, true),
|
|
25274
|
+
t4.cloneNode(callbackExpr, true)
|
|
25275
|
+
)
|
|
25276
|
+
),
|
|
25277
|
+
t4.expressionStatement(
|
|
25278
|
+
t4.assignmentExpression(
|
|
25279
|
+
"=",
|
|
25280
|
+
t4.cloneNode(deferredCallbackInitId, true),
|
|
25281
|
+
t4.booleanLiteral(true)
|
|
25282
|
+
)
|
|
25283
|
+
)
|
|
25284
|
+
])
|
|
25285
|
+
),
|
|
25286
|
+
t4.returnStatement(t4.cloneNode(deferredItemsId, true))
|
|
25287
|
+
])
|
|
25288
|
+
) : t4.arrowFunctionExpression([], arrayExpr);
|
|
25289
|
+
const renderExpr = shouldDeferOptionalCallbackEvaluation ? t4.arrowFunctionExpression(
|
|
25290
|
+
[t4.identifier("__item"), t4.identifier("__index"), t4.identifier("__key")],
|
|
25291
|
+
t4.callExpression(t4.cloneNode(deferredCallbackId, true), [
|
|
25292
|
+
t4.identifier("__item"),
|
|
25293
|
+
t4.identifier("__index"),
|
|
25294
|
+
t4.identifier("__key")
|
|
25295
|
+
])
|
|
25296
|
+
) : callbackExpr;
|
|
25017
25297
|
const keyFn = t4.arrowFunctionExpression(
|
|
25018
25298
|
[t4.identifier(itemParamName), t4.identifier(indexParamName)],
|
|
25019
25299
|
t4.identifier(indexParamName)
|
|
25020
25300
|
);
|
|
25021
25301
|
listCall = t4.callExpression(t4.identifier(RUNTIME_ALIASES.keyedList), [
|
|
25022
|
-
|
|
25302
|
+
getItemsExpr,
|
|
25023
25303
|
keyFn,
|
|
25024
|
-
|
|
25304
|
+
renderExpr,
|
|
25025
25305
|
t4.booleanLiteral(hasIndexParam)
|
|
25026
25306
|
]);
|
|
25027
25307
|
}
|
|
@@ -25484,6 +25764,10 @@ function registerResumableComponent(componentName, ctx) {
|
|
|
25484
25764
|
const hostParam = t4.identifier("host");
|
|
25485
25765
|
const snapshotId = t4.identifier("snapshot");
|
|
25486
25766
|
const ctxId = t4.identifier("ctx");
|
|
25767
|
+
const runtimeModuleUrlExpr = t4.memberExpression(
|
|
25768
|
+
t4.metaProperty(t4.identifier("import"), t4.identifier("meta")),
|
|
25769
|
+
t4.identifier("url")
|
|
25770
|
+
);
|
|
25487
25771
|
ctx.helpersUsed.add("getSSRScope");
|
|
25488
25772
|
ctx.helpersUsed.add("ensureScope");
|
|
25489
25773
|
ctx.helpersUsed.add("prepareContext");
|
|
@@ -25557,7 +25841,10 @@ function registerResumableComponent(componentName, ctx) {
|
|
|
25557
25841
|
ctx.helpersUsed.add("registerResume");
|
|
25558
25842
|
const registerCall = t4.expressionStatement(
|
|
25559
25843
|
t4.callExpression(t4.identifier(RUNTIME_ALIASES.registerResume), [
|
|
25560
|
-
t4.
|
|
25844
|
+
t4.callExpression(t4.identifier(RUNTIME_ALIASES.qrl), [
|
|
25845
|
+
runtimeModuleUrlExpr,
|
|
25846
|
+
t4.stringLiteral(resumeExport)
|
|
25847
|
+
]),
|
|
25561
25848
|
resumeFnId
|
|
25562
25849
|
])
|
|
25563
25850
|
);
|
|
@@ -27347,18 +27634,8 @@ function lowerExpressionImpl(expr, ctx, valueUsed = true) {
|
|
|
27347
27634
|
blocks,
|
|
27348
27635
|
meta: { fromExpression: true }
|
|
27349
27636
|
};
|
|
27350
|
-
const cfg = analyzeCFG(fn.blocks);
|
|
27351
|
-
const hasLoop = cfg.loopHeaders.size > 0 || cfg.backEdges.size > 0;
|
|
27352
27637
|
const { node, diagnostics } = structurizeCFGWithDiagnostics(fn);
|
|
27353
|
-
const structured = node.kind === "stateMachine"
|
|
27354
|
-
kind: "stateMachine",
|
|
27355
|
-
blocks: fn.blocks.map((block) => ({
|
|
27356
|
-
blockId: block.id,
|
|
27357
|
-
instructions: block.instructions,
|
|
27358
|
-
terminator: block.terminator
|
|
27359
|
-
})),
|
|
27360
|
-
entryBlock: fn.blocks[0]?.id ?? 0
|
|
27361
|
-
} : diagnostics.isComplete ? node : {
|
|
27638
|
+
const structured = node.kind === "stateMachine" ? node : diagnostics.isComplete ? node : {
|
|
27362
27639
|
kind: "stateMachine",
|
|
27363
27640
|
blocks: fn.blocks.map((block) => ({
|
|
27364
27641
|
blockId: block.id,
|
|
@@ -33920,6 +34197,506 @@ function getRootIdentifier(expr, t4) {
|
|
|
33920
34197
|
return null;
|
|
33921
34198
|
}
|
|
33922
34199
|
|
|
34200
|
+
// src/tooling/analyze.ts
|
|
34201
|
+
import { parseSync, transformSync } from "@babel/core";
|
|
34202
|
+
|
|
34203
|
+
// src/tooling/trace-infer.ts
|
|
34204
|
+
var TRACE_REGEX_ESCAPES = /[.*+?^${}()|[\]\\]/g;
|
|
34205
|
+
var IDENTIFIER_NAME = /^[A-Za-z_$][\w$]*$/;
|
|
34206
|
+
function isIdentifierName(name) {
|
|
34207
|
+
return IDENTIFIER_NAME.test(name);
|
|
34208
|
+
}
|
|
34209
|
+
function lineContainsIdentifier(lineText, identifier2) {
|
|
34210
|
+
const pattern = new RegExp(`\\b${identifier2.replace(TRACE_REGEX_ESCAPES, "\\$&")}\\b`);
|
|
34211
|
+
return pattern.test(lineText);
|
|
34212
|
+
}
|
|
34213
|
+
function lineContainsAnyIdentifier(lineText, identifiers) {
|
|
34214
|
+
for (const id of identifiers) {
|
|
34215
|
+
if (lineContainsIdentifier(lineText, id)) return true;
|
|
34216
|
+
}
|
|
34217
|
+
return false;
|
|
34218
|
+
}
|
|
34219
|
+
function pushTraceMarker(markersByLine, line, marker) {
|
|
34220
|
+
const markers = markersByLine.get(line);
|
|
34221
|
+
if (!markers) {
|
|
34222
|
+
markersByLine.set(line, [marker]);
|
|
34223
|
+
return;
|
|
34224
|
+
}
|
|
34225
|
+
const duplicate = markers.some(
|
|
34226
|
+
(existing) => existing.kind === marker.kind && existing.label === marker.label
|
|
34227
|
+
);
|
|
34228
|
+
if (!duplicate) markers.push(marker);
|
|
34229
|
+
}
|
|
34230
|
+
function inferReactiveLocalNames(startLine, endLine, sourceLines, baseReactiveNames) {
|
|
34231
|
+
const reactiveNames = new Set(baseReactiveNames);
|
|
34232
|
+
const declarationLines = [];
|
|
34233
|
+
const declarationPattern = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(.+?)(?:;)?$/;
|
|
34234
|
+
for (let line = startLine; line <= endLine; line++) {
|
|
34235
|
+
const text = (sourceLines[line - 1] ?? "").trim();
|
|
34236
|
+
if (!text) continue;
|
|
34237
|
+
const withoutComment = text.replace(/\/\/.*$/, "").trim();
|
|
34238
|
+
if (!withoutComment) continue;
|
|
34239
|
+
const match = withoutComment.match(declarationPattern);
|
|
34240
|
+
if (!match) continue;
|
|
34241
|
+
const name = match[1];
|
|
34242
|
+
const expression = match[2];
|
|
34243
|
+
if (!name || !expression) continue;
|
|
34244
|
+
declarationLines.push({ name, expression });
|
|
34245
|
+
}
|
|
34246
|
+
let changed = true;
|
|
34247
|
+
while (changed) {
|
|
34248
|
+
changed = false;
|
|
34249
|
+
for (const declaration of declarationLines) {
|
|
34250
|
+
if (reactiveNames.has(declaration.name)) continue;
|
|
34251
|
+
if (!lineContainsAnyIdentifier(declaration.expression, reactiveNames)) continue;
|
|
34252
|
+
reactiveNames.add(declaration.name);
|
|
34253
|
+
changed = true;
|
|
34254
|
+
}
|
|
34255
|
+
}
|
|
34256
|
+
return reactiveNames;
|
|
34257
|
+
}
|
|
34258
|
+
function isStateCallInstruction(instr) {
|
|
34259
|
+
if (instr.kind !== "Assign") return false;
|
|
34260
|
+
const value = instr.value;
|
|
34261
|
+
return value.kind === "CallExpression" && value.callee.kind === "Identifier" && value.callee.name === "$state";
|
|
34262
|
+
}
|
|
34263
|
+
function collectStateDeclNames(fn) {
|
|
34264
|
+
const result = [];
|
|
34265
|
+
for (const block of fn.blocks) {
|
|
34266
|
+
for (const instr of block.instructions) {
|
|
34267
|
+
if (!isStateCallInstruction(instr) || !instr.loc) continue;
|
|
34268
|
+
const name = deSSAVarName(instr.target.name);
|
|
34269
|
+
if (!isIdentifierName(name)) continue;
|
|
34270
|
+
result.push({ name, line: instr.loc.start.line });
|
|
34271
|
+
}
|
|
34272
|
+
}
|
|
34273
|
+
return result;
|
|
34274
|
+
}
|
|
34275
|
+
function expressionContainsEffectCall(instr) {
|
|
34276
|
+
const value = instr.kind === "Assign" || instr.kind === "Expression" ? instr.value : null;
|
|
34277
|
+
if (!value || !instr.loc) return null;
|
|
34278
|
+
let found = false;
|
|
34279
|
+
walkExpression(value, (expr) => {
|
|
34280
|
+
if (expr.kind === "CallExpression" && expr.callee.kind === "Identifier" && deSSAVarName(expr.callee.name) === "$effect") {
|
|
34281
|
+
found = true;
|
|
34282
|
+
}
|
|
34283
|
+
});
|
|
34284
|
+
return found ? instr.loc.start.line : null;
|
|
34285
|
+
}
|
|
34286
|
+
function flattenRegions2(regions) {
|
|
34287
|
+
if (!regions || regions.length === 0) return [];
|
|
34288
|
+
const result = [];
|
|
34289
|
+
const visit = (region) => {
|
|
34290
|
+
result.push(region);
|
|
34291
|
+
region.children?.forEach((child) => visit(child));
|
|
34292
|
+
};
|
|
34293
|
+
regions.forEach((region) => visit(region));
|
|
34294
|
+
return result;
|
|
34295
|
+
}
|
|
34296
|
+
function findContainingRegion2(line, flatRegions) {
|
|
34297
|
+
let best;
|
|
34298
|
+
for (const region of flatRegions) {
|
|
34299
|
+
if (region.startLine === void 0 || region.endLine === void 0 || line < region.startLine || line > region.endLine) {
|
|
34300
|
+
continue;
|
|
34301
|
+
}
|
|
34302
|
+
const bestSpan = best && best.startLine !== void 0 && best.endLine !== void 0 ? best.endLine - best.startLine : Number.POSITIVE_INFINITY;
|
|
34303
|
+
const span = region.endLine - region.startLine;
|
|
34304
|
+
if (span <= bestSpan) best = region;
|
|
34305
|
+
}
|
|
34306
|
+
return best;
|
|
34307
|
+
}
|
|
34308
|
+
function inferTraceMarkersForComponent(input) {
|
|
34309
|
+
const { fn, sourceLines, startLine, endLine, verbosity, regions } = input;
|
|
34310
|
+
const markersByLine = /* @__PURE__ */ new Map();
|
|
34311
|
+
pushTraceMarker(markersByLine, startLine, {
|
|
34312
|
+
kind: "once",
|
|
34313
|
+
label: "Component setup runs on mount"
|
|
34314
|
+
});
|
|
34315
|
+
const stateDecls = collectStateDeclNames(fn);
|
|
34316
|
+
const reactiveNames = inferReactiveLocalNames(
|
|
34317
|
+
startLine,
|
|
34318
|
+
endLine,
|
|
34319
|
+
sourceLines,
|
|
34320
|
+
stateDecls.map((item) => item.name)
|
|
34321
|
+
);
|
|
34322
|
+
for (const stateDecl of stateDecls) {
|
|
34323
|
+
pushTraceMarker(markersByLine, stateDecl.line, {
|
|
34324
|
+
kind: "once",
|
|
34325
|
+
label: "Signal initialization runs once"
|
|
34326
|
+
});
|
|
34327
|
+
}
|
|
34328
|
+
for (const block of fn.blocks) {
|
|
34329
|
+
for (const instr of block.instructions) {
|
|
34330
|
+
const line = expressionContainsEffectCall(instr);
|
|
34331
|
+
if (!line || line < startLine || line > endLine) continue;
|
|
34332
|
+
pushTraceMarker(markersByLine, line, {
|
|
34333
|
+
kind: "effect",
|
|
34334
|
+
label: "Effect reruns when dependencies change"
|
|
34335
|
+
});
|
|
34336
|
+
}
|
|
34337
|
+
}
|
|
34338
|
+
const flatRegions = flattenRegions2(regions);
|
|
34339
|
+
for (let line = startLine; line <= endLine; line++) {
|
|
34340
|
+
const lineText = sourceLines[line - 1] ?? "";
|
|
34341
|
+
if (!lineText) continue;
|
|
34342
|
+
const hasReactiveName = lineContainsAnyIdentifier(lineText, reactiveNames);
|
|
34343
|
+
if (hasReactiveName && /\{[^}]*\b[A-Za-z_$][\w$]*\b[^}]*\}/.test(lineText)) {
|
|
34344
|
+
pushTraceMarker(markersByLine, line, {
|
|
34345
|
+
kind: "reactive",
|
|
34346
|
+
label: "JSX expression updates with reactive values"
|
|
34347
|
+
});
|
|
34348
|
+
}
|
|
34349
|
+
if (hasReactiveName && /\bconsole\.(?:log|debug|info|warn|error)\s*\(/.test(lineText)) {
|
|
34350
|
+
pushTraceMarker(markersByLine, line, {
|
|
34351
|
+
kind: "reactive",
|
|
34352
|
+
label: "Statement reruns when reactive values change"
|
|
34353
|
+
});
|
|
34354
|
+
}
|
|
34355
|
+
if (/\b(?:\$effect|effect)\s*\(/.test(lineText)) {
|
|
34356
|
+
pushTraceMarker(markersByLine, line, {
|
|
34357
|
+
kind: "effect",
|
|
34358
|
+
label: "Effect callback executes reactively"
|
|
34359
|
+
});
|
|
34360
|
+
}
|
|
34361
|
+
if (verbosity === "verbose" && !hasReactiveName && /\{[^}]*\}/.test(lineText)) {
|
|
34362
|
+
pushTraceMarker(markersByLine, line, {
|
|
34363
|
+
kind: "once",
|
|
34364
|
+
label: "JSX expression runs during setup only"
|
|
34365
|
+
});
|
|
34366
|
+
}
|
|
34367
|
+
if (/\bconsole\.(?:log|debug|info|warn|error)\s*\(/.test(lineText) && !hasReactiveName && line !== startLine) {
|
|
34368
|
+
pushTraceMarker(markersByLine, line, {
|
|
34369
|
+
kind: "once",
|
|
34370
|
+
label: "Statement runs only during setup"
|
|
34371
|
+
});
|
|
34372
|
+
}
|
|
34373
|
+
const containingRegion = findContainingRegion2(line, flatRegions);
|
|
34374
|
+
if (!containingRegion) continue;
|
|
34375
|
+
const markers = markersByLine.get(line);
|
|
34376
|
+
if (!markers) continue;
|
|
34377
|
+
for (const marker of markers) {
|
|
34378
|
+
marker.regionId = containingRegion.id;
|
|
34379
|
+
marker.deps = containingRegion.dependencies;
|
|
34380
|
+
}
|
|
34381
|
+
}
|
|
34382
|
+
return [...markersByLine.entries()].sort((a, b) => a[0] - b[0]).map(([line, markers]) => ({ line, markers }));
|
|
34383
|
+
}
|
|
34384
|
+
|
|
34385
|
+
// src/tooling/analyze.ts
|
|
34386
|
+
function mergeLoc(a, b) {
|
|
34387
|
+
if (!a) return b ?? null;
|
|
34388
|
+
if (!b) return a;
|
|
34389
|
+
const start = b.start.line < a.start.line || b.start.line === a.start.line && b.start.column < a.start.column ? b.start : a.start;
|
|
34390
|
+
const end = b.end.line > a.end.line || b.end.line === a.end.line && b.end.column > a.end.column ? b.end : a.end;
|
|
34391
|
+
return {
|
|
34392
|
+
start,
|
|
34393
|
+
end,
|
|
34394
|
+
filename: a.filename ?? b.filename,
|
|
34395
|
+
identifierName: a.identifierName ?? b.identifierName
|
|
34396
|
+
};
|
|
34397
|
+
}
|
|
34398
|
+
function expressionContainsMacroCall(expr, macroName) {
|
|
34399
|
+
let found = false;
|
|
34400
|
+
const visit = (value) => {
|
|
34401
|
+
if (found) return;
|
|
34402
|
+
if (value.kind === "CallExpression" && value.callee.kind === "Identifier" && deSSAVarName(value.callee.name) === macroName) {
|
|
34403
|
+
found = true;
|
|
34404
|
+
return;
|
|
34405
|
+
}
|
|
34406
|
+
switch (value.kind) {
|
|
34407
|
+
case "CallExpression":
|
|
34408
|
+
case "OptionalCallExpression":
|
|
34409
|
+
visit(value.callee);
|
|
34410
|
+
value.arguments.forEach((arg) => visit(arg));
|
|
34411
|
+
return;
|
|
34412
|
+
case "MemberExpression":
|
|
34413
|
+
case "OptionalMemberExpression":
|
|
34414
|
+
visit(value.object);
|
|
34415
|
+
if (value.computed) visit(value.property);
|
|
34416
|
+
return;
|
|
34417
|
+
case "BinaryExpression":
|
|
34418
|
+
case "LogicalExpression":
|
|
34419
|
+
visit(value.left);
|
|
34420
|
+
visit(value.right);
|
|
34421
|
+
return;
|
|
34422
|
+
case "UnaryExpression":
|
|
34423
|
+
case "AwaitExpression":
|
|
34424
|
+
case "UpdateExpression":
|
|
34425
|
+
case "SpreadElement":
|
|
34426
|
+
visit(value.argument);
|
|
34427
|
+
return;
|
|
34428
|
+
case "ConditionalExpression":
|
|
34429
|
+
visit(value.test);
|
|
34430
|
+
visit(value.consequent);
|
|
34431
|
+
visit(value.alternate);
|
|
34432
|
+
return;
|
|
34433
|
+
case "ArrayExpression":
|
|
34434
|
+
value.elements.forEach((el) => visit(el));
|
|
34435
|
+
return;
|
|
34436
|
+
case "ObjectExpression":
|
|
34437
|
+
value.properties.forEach((prop) => {
|
|
34438
|
+
if (prop.kind === "SpreadElement") {
|
|
34439
|
+
visit(prop.argument);
|
|
34440
|
+
return;
|
|
34441
|
+
}
|
|
34442
|
+
if (prop.computed) visit(prop.key);
|
|
34443
|
+
visit(prop.value);
|
|
34444
|
+
});
|
|
34445
|
+
return;
|
|
34446
|
+
case "TemplateLiteral":
|
|
34447
|
+
value.expressions.forEach((item) => visit(item));
|
|
34448
|
+
return;
|
|
34449
|
+
case "AssignmentExpression":
|
|
34450
|
+
visit(value.left);
|
|
34451
|
+
visit(value.right);
|
|
34452
|
+
return;
|
|
34453
|
+
case "SequenceExpression":
|
|
34454
|
+
value.expressions.forEach((item) => visit(item));
|
|
34455
|
+
return;
|
|
34456
|
+
case "YieldExpression":
|
|
34457
|
+
if (value.argument) visit(value.argument);
|
|
34458
|
+
return;
|
|
34459
|
+
case "TaggedTemplateExpression":
|
|
34460
|
+
visit(value.tag);
|
|
34461
|
+
value.quasi.expressions.forEach((item) => visit(item));
|
|
34462
|
+
return;
|
|
34463
|
+
case "ImportExpression":
|
|
34464
|
+
visit(value.source);
|
|
34465
|
+
return;
|
|
34466
|
+
case "ArrowFunction":
|
|
34467
|
+
if (Array.isArray(value.body)) {
|
|
34468
|
+
value.body.forEach((block) => {
|
|
34469
|
+
block.instructions.forEach((instr) => {
|
|
34470
|
+
if (instr.kind === "Assign" || instr.kind === "Expression") {
|
|
34471
|
+
visit(instr.value);
|
|
34472
|
+
}
|
|
34473
|
+
});
|
|
34474
|
+
});
|
|
34475
|
+
} else {
|
|
34476
|
+
visit(value.body);
|
|
34477
|
+
}
|
|
34478
|
+
return;
|
|
34479
|
+
case "FunctionExpression":
|
|
34480
|
+
value.body.forEach((block) => {
|
|
34481
|
+
block.instructions.forEach((instr) => {
|
|
34482
|
+
if (instr.kind === "Assign" || instr.kind === "Expression") {
|
|
34483
|
+
visit(instr.value);
|
|
34484
|
+
}
|
|
34485
|
+
});
|
|
34486
|
+
});
|
|
34487
|
+
return;
|
|
34488
|
+
case "JSXElement":
|
|
34489
|
+
if (typeof value.tagName !== "string") visit(value.tagName);
|
|
34490
|
+
value.attributes.forEach((attr) => {
|
|
34491
|
+
if (attr.isSpread && attr.spreadExpr) {
|
|
34492
|
+
visit(attr.spreadExpr);
|
|
34493
|
+
} else if (attr.value) {
|
|
34494
|
+
visit(attr.value);
|
|
34495
|
+
}
|
|
34496
|
+
});
|
|
34497
|
+
value.children.forEach((child) => {
|
|
34498
|
+
if (child.kind === "expression") visit(child.value);
|
|
34499
|
+
if (child.kind === "element") visit(child.value);
|
|
34500
|
+
});
|
|
34501
|
+
return;
|
|
34502
|
+
case "Identifier":
|
|
34503
|
+
case "Literal":
|
|
34504
|
+
case "MetaProperty":
|
|
34505
|
+
case "NewExpression":
|
|
34506
|
+
case "ClassExpression":
|
|
34507
|
+
case "ThisExpression":
|
|
34508
|
+
case "SuperExpression":
|
|
34509
|
+
if (value.kind === "NewExpression") {
|
|
34510
|
+
visit(value.callee);
|
|
34511
|
+
value.arguments.forEach((arg) => visit(arg));
|
|
34512
|
+
}
|
|
34513
|
+
if (value.kind === "ClassExpression" && value.superClass) visit(value.superClass);
|
|
34514
|
+
return;
|
|
34515
|
+
default:
|
|
34516
|
+
return;
|
|
34517
|
+
}
|
|
34518
|
+
};
|
|
34519
|
+
visit(expr);
|
|
34520
|
+
return found;
|
|
34521
|
+
}
|
|
34522
|
+
function instructionContainsMacroCall(instruction, macroName) {
|
|
34523
|
+
if (instruction.kind !== "Assign" && instruction.kind !== "Expression") return false;
|
|
34524
|
+
return expressionContainsMacroCall(instruction.value, macroName);
|
|
34525
|
+
}
|
|
34526
|
+
function functionUsesMacro(fn, macroName) {
|
|
34527
|
+
for (const block of fn.blocks) {
|
|
34528
|
+
for (const instruction of block.instructions) {
|
|
34529
|
+
if (instructionContainsMacroCall(instruction, macroName)) return true;
|
|
34530
|
+
}
|
|
34531
|
+
const term = block.terminator;
|
|
34532
|
+
if ("argument" in term && term.argument && expressionContainsMacroCall(term.argument, macroName)) {
|
|
34533
|
+
return true;
|
|
34534
|
+
}
|
|
34535
|
+
if (term.kind === "Branch" && expressionContainsMacroCall(term.test, macroName)) {
|
|
34536
|
+
return true;
|
|
34537
|
+
}
|
|
34538
|
+
if (term.kind === "Switch") {
|
|
34539
|
+
if (expressionContainsMacroCall(term.discriminant, macroName)) return true;
|
|
34540
|
+
if (term.cases.some((entry) => entry.test && expressionContainsMacroCall(entry.test, macroName))) {
|
|
34541
|
+
return true;
|
|
34542
|
+
}
|
|
34543
|
+
}
|
|
34544
|
+
}
|
|
34545
|
+
return false;
|
|
34546
|
+
}
|
|
34547
|
+
function computeRegionLoc(region, fn) {
|
|
34548
|
+
let loc = null;
|
|
34549
|
+
for (const instruction of region.instructions) {
|
|
34550
|
+
loc = mergeLoc(loc, instruction.loc);
|
|
34551
|
+
}
|
|
34552
|
+
for (const blockId of region.blocks) {
|
|
34553
|
+
const block = fn.blocks.find((entry) => entry.id === blockId);
|
|
34554
|
+
if (!block) continue;
|
|
34555
|
+
loc = mergeLoc(loc, block.terminator.loc);
|
|
34556
|
+
}
|
|
34557
|
+
return loc;
|
|
34558
|
+
}
|
|
34559
|
+
function regionToSerializable(region, fn) {
|
|
34560
|
+
const loc = computeRegionLoc(region, fn);
|
|
34561
|
+
return {
|
|
34562
|
+
id: region.id,
|
|
34563
|
+
startLine: loc?.start.line,
|
|
34564
|
+
startColumn: loc?.start.column,
|
|
34565
|
+
endLine: loc?.end.line,
|
|
34566
|
+
endColumn: loc?.end.column,
|
|
34567
|
+
dependencies: [...region.dependencies].map(deSSAVarName),
|
|
34568
|
+
declarations: [...region.declarations].map(deSSAVarName),
|
|
34569
|
+
hasControlFlow: region.hasControlFlow,
|
|
34570
|
+
hasReactiveWrites: region.declarations.size > 0,
|
|
34571
|
+
children: region.children.map((child) => regionToSerializable(child, fn))
|
|
34572
|
+
};
|
|
34573
|
+
}
|
|
34574
|
+
function warningSeverity(code) {
|
|
34575
|
+
const diagnosticCodes = new Set(getAllDiagnosticCodes());
|
|
34576
|
+
if (!diagnosticCodes.has(code)) return "warning" /* Warning */;
|
|
34577
|
+
return getDiagnosticInfo(code).severity;
|
|
34578
|
+
}
|
|
34579
|
+
function normalizeWarningToDiagnostic(warning) {
|
|
34580
|
+
return {
|
|
34581
|
+
code: warning.code,
|
|
34582
|
+
message: warning.message,
|
|
34583
|
+
severity: warningSeverity(warning.code),
|
|
34584
|
+
line: warning.line,
|
|
34585
|
+
column: warning.column
|
|
34586
|
+
};
|
|
34587
|
+
}
|
|
34588
|
+
function normalizeThrownError(error) {
|
|
34589
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
34590
|
+
return {
|
|
34591
|
+
code: "FICT-COMPILE",
|
|
34592
|
+
message,
|
|
34593
|
+
severity: "error" /* Error */,
|
|
34594
|
+
line: 0,
|
|
34595
|
+
column: 0
|
|
34596
|
+
};
|
|
34597
|
+
}
|
|
34598
|
+
function analyzeDiagnostics(code, fileName, options) {
|
|
34599
|
+
const warnings = [];
|
|
34600
|
+
const pluginOptions = {
|
|
34601
|
+
dev: true,
|
|
34602
|
+
filename: fileName,
|
|
34603
|
+
emitModuleMetadata: false,
|
|
34604
|
+
strictGuarantee: false,
|
|
34605
|
+
warningLevels: {
|
|
34606
|
+
...options.compilerOptions?.warningLevels ?? {},
|
|
34607
|
+
"FICT-R004": "warn"
|
|
34608
|
+
},
|
|
34609
|
+
...options.compilerOptions,
|
|
34610
|
+
onWarn: (warning) => warnings.push(warning)
|
|
34611
|
+
};
|
|
34612
|
+
try {
|
|
34613
|
+
transformSync(code, {
|
|
34614
|
+
filename: fileName,
|
|
34615
|
+
configFile: false,
|
|
34616
|
+
babelrc: false,
|
|
34617
|
+
sourceType: "module",
|
|
34618
|
+
parserOpts: {
|
|
34619
|
+
sourceType: "module",
|
|
34620
|
+
plugins: ["typescript", "jsx"],
|
|
34621
|
+
allowReturnOutsideFunction: true
|
|
34622
|
+
},
|
|
34623
|
+
plugins: [[index_default, pluginOptions]],
|
|
34624
|
+
generatorOpts: {
|
|
34625
|
+
compact: false
|
|
34626
|
+
}
|
|
34627
|
+
});
|
|
34628
|
+
} catch (error) {
|
|
34629
|
+
return [...warnings.map(normalizeWarningToDiagnostic), normalizeThrownError(error)];
|
|
34630
|
+
}
|
|
34631
|
+
return warnings.map(normalizeWarningToDiagnostic);
|
|
34632
|
+
}
|
|
34633
|
+
function shouldIncludeFunction(fn) {
|
|
34634
|
+
return functionContainsJSX(fn) || functionUsesMacro(fn, "$state") || functionUsesMacro(fn, "$effect");
|
|
34635
|
+
}
|
|
34636
|
+
function parseFileAst(code, fileName) {
|
|
34637
|
+
const ast = parseSync(code, {
|
|
34638
|
+
filename: fileName,
|
|
34639
|
+
sourceType: "module",
|
|
34640
|
+
parserOpts: {
|
|
34641
|
+
sourceType: "module",
|
|
34642
|
+
plugins: ["typescript", "jsx"],
|
|
34643
|
+
allowReturnOutsideFunction: true
|
|
34644
|
+
}
|
|
34645
|
+
});
|
|
34646
|
+
if (!ast || ast.type !== "File") {
|
|
34647
|
+
throw new Error("Failed to parse source file for Fict analysis.");
|
|
34648
|
+
}
|
|
34649
|
+
return ast;
|
|
34650
|
+
}
|
|
34651
|
+
function analyzeFictFile(code, fileName, options = {}) {
|
|
34652
|
+
const includeRegions = options.includeRegions ?? true;
|
|
34653
|
+
const includeDiagnostics = options.includeDiagnostics ?? true;
|
|
34654
|
+
const verbosity = options.verbosity ?? "minimal";
|
|
34655
|
+
const ast = parseFileAst(code, fileName);
|
|
34656
|
+
const hir = buildHIR(
|
|
34657
|
+
ast,
|
|
34658
|
+
{
|
|
34659
|
+
state: /* @__PURE__ */ new Set(["$state"]),
|
|
34660
|
+
effect: /* @__PURE__ */ new Set(["$effect"])
|
|
34661
|
+
},
|
|
34662
|
+
{
|
|
34663
|
+
dev: true,
|
|
34664
|
+
fileName
|
|
34665
|
+
}
|
|
34666
|
+
);
|
|
34667
|
+
const sourceLines = code.split(/\r?\n/);
|
|
34668
|
+
const components = [];
|
|
34669
|
+
for (const fn of hir.functions) {
|
|
34670
|
+
if (!fn.loc || !shouldIncludeFunction(fn)) continue;
|
|
34671
|
+
const startLine = fn.loc.start.line;
|
|
34672
|
+
const endLine = fn.loc.end.line;
|
|
34673
|
+
const scopeResult = analyzeReactiveScopesWithSSA(fn);
|
|
34674
|
+
const regionResult = generateRegions(fn, scopeResult);
|
|
34675
|
+
const regions = includeRegions ? regionResult.topLevelRegions.map((region) => regionToSerializable(region, fn)) : void 0;
|
|
34676
|
+
const trace = inferTraceMarkersForComponent({
|
|
34677
|
+
fn,
|
|
34678
|
+
sourceLines,
|
|
34679
|
+
startLine,
|
|
34680
|
+
endLine,
|
|
34681
|
+
verbosity,
|
|
34682
|
+
regions
|
|
34683
|
+
});
|
|
34684
|
+
components.push({
|
|
34685
|
+
name: fn.name ?? "<anonymous>",
|
|
34686
|
+
startLine,
|
|
34687
|
+
endLine,
|
|
34688
|
+
trace,
|
|
34689
|
+
regions
|
|
34690
|
+
});
|
|
34691
|
+
}
|
|
34692
|
+
const diagnostics = includeDiagnostics ? analyzeDiagnostics(code, fileName, options) : [];
|
|
34693
|
+
return {
|
|
34694
|
+
fileName,
|
|
34695
|
+
components,
|
|
34696
|
+
diagnostics
|
|
34697
|
+
};
|
|
34698
|
+
}
|
|
34699
|
+
|
|
33923
34700
|
// src/index.ts
|
|
33924
34701
|
function stripMacroImports(path2, t4) {
|
|
33925
34702
|
path2.traverse({
|
|
@@ -34813,46 +35590,77 @@ function createHIREntrypointVisitor(t4, options) {
|
|
|
34813
35590
|
path2.traverse({
|
|
34814
35591
|
JSXExpressionContainer(exprPath) {
|
|
34815
35592
|
const expr = exprPath.node.expression;
|
|
34816
|
-
if (!t4.isCallExpression(expr)) return;
|
|
34817
|
-
if (!t4.isMemberExpression(expr.callee) || !t4.isIdentifier(expr.callee.property, { name: "map" })) {
|
|
35593
|
+
if (!t4.isCallExpression(expr) && !t4.isOptionalCallExpression(expr)) return;
|
|
35594
|
+
if (!t4.isMemberExpression(expr.callee) && !t4.isOptionalMemberExpression(expr.callee) || !t4.isIdentifier(expr.callee.property, { name: "map" })) {
|
|
34818
35595
|
return;
|
|
34819
35596
|
}
|
|
34820
|
-
const
|
|
34821
|
-
if (!
|
|
34822
|
-
const
|
|
34823
|
-
|
|
34824
|
-
|
|
34825
|
-
const ret = fn.body.body.find((stmt) => t4.isReturnStatement(stmt));
|
|
34826
|
-
if (ret && t4.isReturnStatement(ret) && ret.argument && (t4.isJSXElement(ret.argument) || t4.isJSXFragment(ret.argument))) {
|
|
34827
|
-
return ret.argument;
|
|
34828
|
-
}
|
|
34829
|
-
}
|
|
34830
|
-
return null;
|
|
34831
|
-
};
|
|
34832
|
-
const jsx = getReturnedJsx(cb);
|
|
34833
|
-
if (!jsx) return;
|
|
34834
|
-
if (t4.isJSXFragment(jsx)) {
|
|
34835
|
-
warn({
|
|
34836
|
-
code: "FICT-J002",
|
|
34837
|
-
message: "Missing key prop in list rendering.",
|
|
34838
|
-
fileName,
|
|
34839
|
-
line: expr.loc?.start.line ?? 0,
|
|
34840
|
-
column: expr.loc ? expr.loc.start.column + 1 : 0
|
|
34841
|
-
});
|
|
35597
|
+
const callExprPath = exprPath.get("expression");
|
|
35598
|
+
if (!callExprPath.isCallExpression() && !callExprPath.isOptionalCallExpression()) return;
|
|
35599
|
+
const argPaths = callExprPath.get("arguments");
|
|
35600
|
+
const cbPath = Array.isArray(argPaths) ? argPaths[0] : void 0;
|
|
35601
|
+
if (!cbPath || !cbPath.isArrowFunctionExpression() && !cbPath.isFunctionExpression()) {
|
|
34842
35602
|
return;
|
|
34843
35603
|
}
|
|
34844
|
-
|
|
34845
|
-
|
|
34846
|
-
|
|
34847
|
-
|
|
34848
|
-
|
|
34849
|
-
|
|
35604
|
+
const getReturnedJsx = (fnPath) => {
|
|
35605
|
+
const collectReturnedJsxFromExpression = (node, returned2) => {
|
|
35606
|
+
if (!node) return;
|
|
35607
|
+
if (t4.isJSXElement(node) || t4.isJSXFragment(node)) {
|
|
35608
|
+
returned2.push(node);
|
|
35609
|
+
return;
|
|
35610
|
+
}
|
|
35611
|
+
if (t4.isConditionalExpression(node)) {
|
|
35612
|
+
collectReturnedJsxFromExpression(node.consequent, returned2);
|
|
35613
|
+
collectReturnedJsxFromExpression(node.alternate, returned2);
|
|
35614
|
+
return;
|
|
35615
|
+
}
|
|
35616
|
+
if (t4.isLogicalExpression(node)) {
|
|
35617
|
+
collectReturnedJsxFromExpression(node.left, returned2);
|
|
35618
|
+
collectReturnedJsxFromExpression(node.right, returned2);
|
|
35619
|
+
return;
|
|
35620
|
+
}
|
|
35621
|
+
if (t4.isSequenceExpression(node)) {
|
|
35622
|
+
const tail = node.expressions[node.expressions.length - 1];
|
|
35623
|
+
collectReturnedJsxFromExpression(tail, returned2);
|
|
35624
|
+
return;
|
|
35625
|
+
}
|
|
35626
|
+
if (t4.isParenthesizedExpression(node)) {
|
|
35627
|
+
collectReturnedJsxFromExpression(node.expression, returned2);
|
|
35628
|
+
return;
|
|
35629
|
+
}
|
|
35630
|
+
if (t4.isTSAsExpression(node) || t4.isTSTypeAssertion(node) || t4.isTSNonNullExpression(node) || t4.isTSSatisfiesExpression(node) || t4.isTypeCastExpression(node)) {
|
|
35631
|
+
collectReturnedJsxFromExpression(node.expression, returned2);
|
|
35632
|
+
}
|
|
35633
|
+
};
|
|
35634
|
+
const fn = fnPath.node;
|
|
35635
|
+
const returned = [];
|
|
35636
|
+
if (!t4.isBlockStatement(fn.body)) {
|
|
35637
|
+
collectReturnedJsxFromExpression(fn.body, returned);
|
|
35638
|
+
return returned;
|
|
34850
35639
|
}
|
|
34851
|
-
|
|
34852
|
-
|
|
35640
|
+
fnPath.get("body").traverse({
|
|
35641
|
+
Function(innerFnPath) {
|
|
35642
|
+
innerFnPath.skip();
|
|
35643
|
+
},
|
|
35644
|
+
ReturnStatement(retPath) {
|
|
35645
|
+
collectReturnedJsxFromExpression(retPath.node.argument, returned);
|
|
35646
|
+
}
|
|
35647
|
+
});
|
|
35648
|
+
return returned;
|
|
35649
|
+
};
|
|
35650
|
+
const returnedJsx = getReturnedJsx(cbPath);
|
|
35651
|
+
if (returnedJsx.length === 0) return;
|
|
35652
|
+
const hasMissingKeyBranch = returnedJsx.some((jsx) => {
|
|
35653
|
+
if (t4.isJSXFragment(jsx)) return true;
|
|
35654
|
+
let hasKey = false;
|
|
35655
|
+
for (const attr of jsx.openingElement.attributes) {
|
|
35656
|
+
if (t4.isJSXAttribute(attr) && t4.isJSXIdentifier(attr.name, { name: "key" })) {
|
|
35657
|
+
hasKey = true;
|
|
35658
|
+
break;
|
|
35659
|
+
}
|
|
34853
35660
|
}
|
|
34854
|
-
|
|
34855
|
-
|
|
35661
|
+
return !hasKey;
|
|
35662
|
+
});
|
|
35663
|
+
if (!hasMissingKeyBranch) return;
|
|
34856
35664
|
warn({
|
|
34857
35665
|
code: "FICT-J002",
|
|
34858
35666
|
message: "Missing key prop in list rendering.",
|
|
@@ -35414,9 +36222,11 @@ var createFictPlugin = declare(
|
|
|
35414
36222
|
);
|
|
35415
36223
|
var index_default = createFictPlugin;
|
|
35416
36224
|
export {
|
|
36225
|
+
analyzeFictFile,
|
|
35417
36226
|
clearModuleMetadata,
|
|
35418
36227
|
createFictPlugin,
|
|
35419
36228
|
index_default as default,
|
|
36229
|
+
inferTraceMarkersForComponent,
|
|
35420
36230
|
resolveModuleMetadata,
|
|
35421
36231
|
setModuleMetadata
|
|
35422
36232
|
};
|