@fictjs/compiler 0.15.0 → 0.16.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 +847 -52
- package/dist/index.d.cts +393 -1
- package/dist/index.d.ts +393 -1
- package/dist/index.js +845 -52
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -3065,7 +3065,7 @@ var require_identifier = __commonJS({
|
|
|
3065
3065
|
value: true
|
|
3066
3066
|
});
|
|
3067
3067
|
exports2.isIdentifierChar = isIdentifierChar;
|
|
3068
|
-
exports2.isIdentifierName =
|
|
3068
|
+
exports2.isIdentifierName = isIdentifierName2;
|
|
3069
3069
|
exports2.isIdentifierStart = isIdentifierStart;
|
|
3070
3070
|
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";
|
|
3071
3071
|
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";
|
|
@@ -3106,7 +3106,7 @@ var require_identifier = __commonJS({
|
|
|
3106
3106
|
}
|
|
3107
3107
|
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
|
|
3108
3108
|
}
|
|
3109
|
-
function
|
|
3109
|
+
function isIdentifierName2(name) {
|
|
3110
3110
|
let isFirst = true;
|
|
3111
3111
|
for (let i = 0; i < name.length; i++) {
|
|
3112
3112
|
let cp = name.charCodeAt(i);
|
|
@@ -14098,9 +14098,11 @@ var require_lib3 = __commonJS({
|
|
|
14098
14098
|
// src/index.ts
|
|
14099
14099
|
var index_exports = {};
|
|
14100
14100
|
__export(index_exports, {
|
|
14101
|
+
analyzeFictFile: () => analyzeFictFile,
|
|
14101
14102
|
clearModuleMetadata: () => clearModuleMetadata,
|
|
14102
14103
|
createFictPlugin: () => createFictPlugin,
|
|
14103
14104
|
default: () => index_default,
|
|
14105
|
+
inferTraceMarkersForComponent: () => inferTraceMarkersForComponent,
|
|
14104
14106
|
resolveModuleMetadata: () => resolveModuleMetadata,
|
|
14105
14107
|
setModuleMetadata: () => setModuleMetadata
|
|
14106
14108
|
});
|
|
@@ -17088,6 +17090,37 @@ function clearModuleMetadata(options) {
|
|
|
17088
17090
|
}
|
|
17089
17091
|
|
|
17090
17092
|
// src/validation.ts
|
|
17093
|
+
var DiagnosticCode = /* @__PURE__ */ ((DiagnosticCode2) => {
|
|
17094
|
+
DiagnosticCode2["FICT_P001"] = "FICT-P001";
|
|
17095
|
+
DiagnosticCode2["FICT_P002"] = "FICT-P002";
|
|
17096
|
+
DiagnosticCode2["FICT_P003"] = "FICT-P003";
|
|
17097
|
+
DiagnosticCode2["FICT_P004"] = "FICT-P004";
|
|
17098
|
+
DiagnosticCode2["FICT_P005"] = "FICT-P005";
|
|
17099
|
+
DiagnosticCode2["FICT_S001"] = "FICT-S001";
|
|
17100
|
+
DiagnosticCode2["FICT_S002"] = "FICT-S002";
|
|
17101
|
+
DiagnosticCode2["FICT_E001"] = "FICT-E001";
|
|
17102
|
+
DiagnosticCode2["FICT_E002"] = "FICT-E002";
|
|
17103
|
+
DiagnosticCode2["FICT_E003"] = "FICT-E003";
|
|
17104
|
+
DiagnosticCode2["FICT_M001"] = "FICT-M001";
|
|
17105
|
+
DiagnosticCode2["FICT_M002"] = "FICT-M002";
|
|
17106
|
+
DiagnosticCode2["FICT_M003"] = "FICT-M003";
|
|
17107
|
+
DiagnosticCode2["FICT_C001"] = "FICT-C001";
|
|
17108
|
+
DiagnosticCode2["FICT_C002"] = "FICT-C002";
|
|
17109
|
+
DiagnosticCode2["FICT_C003"] = "FICT-C003";
|
|
17110
|
+
DiagnosticCode2["FICT_C004"] = "FICT-C004";
|
|
17111
|
+
DiagnosticCode2["FICT_J001"] = "FICT-J001";
|
|
17112
|
+
DiagnosticCode2["FICT_J002"] = "FICT-J002";
|
|
17113
|
+
DiagnosticCode2["FICT_J003"] = "FICT-J003";
|
|
17114
|
+
DiagnosticCode2["FICT_R001"] = "FICT-R001";
|
|
17115
|
+
DiagnosticCode2["FICT_R002"] = "FICT-R002";
|
|
17116
|
+
DiagnosticCode2["FICT_R003"] = "FICT-R003";
|
|
17117
|
+
DiagnosticCode2["FICT_R004"] = "FICT-R004";
|
|
17118
|
+
DiagnosticCode2["FICT_R005"] = "FICT-R005";
|
|
17119
|
+
DiagnosticCode2["FICT_X001"] = "FICT-X001";
|
|
17120
|
+
DiagnosticCode2["FICT_X002"] = "FICT-X002";
|
|
17121
|
+
DiagnosticCode2["FICT_X003"] = "FICT-X003";
|
|
17122
|
+
return DiagnosticCode2;
|
|
17123
|
+
})(DiagnosticCode || {});
|
|
17091
17124
|
var DiagnosticMessages = {
|
|
17092
17125
|
["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
|
|
17093
17126
|
["FICT-P002" /* FICT_P002 */]: "Array rest in props destructuring falls back to non-reactive binding.",
|
|
@@ -17175,6 +17208,16 @@ function reportDiagnostic(ctx, code, node, context) {
|
|
|
17175
17208
|
});
|
|
17176
17209
|
}
|
|
17177
17210
|
}
|
|
17211
|
+
function getAllDiagnosticCodes() {
|
|
17212
|
+
return Object.values(DiagnosticCode);
|
|
17213
|
+
}
|
|
17214
|
+
function getDiagnosticInfo(code) {
|
|
17215
|
+
return {
|
|
17216
|
+
code,
|
|
17217
|
+
severity: DiagnosticSeverities[code],
|
|
17218
|
+
message: DiagnosticMessages[code]
|
|
17219
|
+
};
|
|
17220
|
+
}
|
|
17178
17221
|
|
|
17179
17222
|
// src/ir/ssa.ts
|
|
17180
17223
|
function enterSSA(program) {
|
|
@@ -24267,34 +24310,138 @@ function extractKeyFromAttributes(attributes) {
|
|
|
24267
24310
|
}
|
|
24268
24311
|
return void 0;
|
|
24269
24312
|
}
|
|
24313
|
+
function collectReturnedJSXFromExpression(expression, returned) {
|
|
24314
|
+
if (expression.kind === "JSXElement") {
|
|
24315
|
+
returned.push(expression);
|
|
24316
|
+
return;
|
|
24317
|
+
}
|
|
24318
|
+
if (expression.kind === "ConditionalExpression") {
|
|
24319
|
+
collectReturnedJSXFromExpression(expression.consequent, returned);
|
|
24320
|
+
collectReturnedJSXFromExpression(expression.alternate, returned);
|
|
24321
|
+
return;
|
|
24322
|
+
}
|
|
24323
|
+
if (expression.kind === "LogicalExpression") {
|
|
24324
|
+
collectReturnedJSXFromExpression(expression.left, returned);
|
|
24325
|
+
collectReturnedJSXFromExpression(expression.right, returned);
|
|
24326
|
+
return;
|
|
24327
|
+
}
|
|
24328
|
+
if (expression.kind === "SequenceExpression") {
|
|
24329
|
+
const tail = expression.expressions[expression.expressions.length - 1];
|
|
24330
|
+
if (tail) collectReturnedJSXFromExpression(tail, returned);
|
|
24331
|
+
}
|
|
24332
|
+
}
|
|
24333
|
+
function extractKeyExpressionFromReturnedExpression(expression) {
|
|
24334
|
+
if (expression.kind === "JSXElement") {
|
|
24335
|
+
return extractKeyFromAttributes(expression.attributes);
|
|
24336
|
+
}
|
|
24337
|
+
if (expression.kind === "ConditionalExpression") {
|
|
24338
|
+
const consequentKey = extractKeyExpressionFromReturnedExpression(expression.consequent);
|
|
24339
|
+
const alternateKey = extractKeyExpressionFromReturnedExpression(expression.alternate);
|
|
24340
|
+
if (!consequentKey || !alternateKey) return void 0;
|
|
24341
|
+
return {
|
|
24342
|
+
kind: "ConditionalExpression",
|
|
24343
|
+
test: expression.test,
|
|
24344
|
+
consequent: consequentKey,
|
|
24345
|
+
alternate: alternateKey,
|
|
24346
|
+
loc: expression.loc
|
|
24347
|
+
};
|
|
24348
|
+
}
|
|
24349
|
+
if (expression.kind === "SequenceExpression") {
|
|
24350
|
+
const tail = expression.expressions[expression.expressions.length - 1];
|
|
24351
|
+
return tail ? extractKeyExpressionFromReturnedExpression(tail) : void 0;
|
|
24352
|
+
}
|
|
24353
|
+
return void 0;
|
|
24354
|
+
}
|
|
24355
|
+
function getReturnedKeyExpressionsFromCallback(callback) {
|
|
24356
|
+
const returned = [];
|
|
24357
|
+
if (callback.kind === "ArrowFunction") {
|
|
24358
|
+
if (callback.isExpression && !Array.isArray(callback.body)) {
|
|
24359
|
+
const keyExpr = extractKeyExpressionFromReturnedExpression(callback.body);
|
|
24360
|
+
if (keyExpr) returned.push(keyExpr);
|
|
24361
|
+
return returned;
|
|
24362
|
+
}
|
|
24363
|
+
if (Array.isArray(callback.body)) {
|
|
24364
|
+
for (const block of callback.body) {
|
|
24365
|
+
const term = block.terminator;
|
|
24366
|
+
if (term.kind !== "Return" || !term.argument) continue;
|
|
24367
|
+
const keyExpr = extractKeyExpressionFromReturnedExpression(term.argument);
|
|
24368
|
+
if (keyExpr) returned.push(keyExpr);
|
|
24369
|
+
}
|
|
24370
|
+
}
|
|
24371
|
+
return returned;
|
|
24372
|
+
}
|
|
24373
|
+
if (callback.kind === "FunctionExpression") {
|
|
24374
|
+
for (const block of callback.body ?? []) {
|
|
24375
|
+
const term = block.terminator;
|
|
24376
|
+
if (term.kind !== "Return" || !term.argument) continue;
|
|
24377
|
+
const keyExpr = extractKeyExpressionFromReturnedExpression(term.argument);
|
|
24378
|
+
if (keyExpr) returned.push(keyExpr);
|
|
24379
|
+
}
|
|
24380
|
+
}
|
|
24381
|
+
return returned;
|
|
24382
|
+
}
|
|
24270
24383
|
function getReturnedJSXFromCallback(callback) {
|
|
24384
|
+
const returned = [];
|
|
24271
24385
|
if (callback.kind === "ArrowFunction") {
|
|
24272
|
-
if (callback.isExpression && !Array.isArray(callback.body)
|
|
24273
|
-
|
|
24386
|
+
if (callback.isExpression && !Array.isArray(callback.body)) {
|
|
24387
|
+
collectReturnedJSXFromExpression(callback.body, returned);
|
|
24388
|
+
return returned;
|
|
24274
24389
|
}
|
|
24275
24390
|
if (Array.isArray(callback.body)) {
|
|
24276
24391
|
for (const block of callback.body) {
|
|
24277
24392
|
const term = block.terminator;
|
|
24278
|
-
if (term.kind === "Return" && term.argument
|
|
24279
|
-
|
|
24393
|
+
if (term.kind === "Return" && term.argument) {
|
|
24394
|
+
collectReturnedJSXFromExpression(term.argument, returned);
|
|
24280
24395
|
}
|
|
24281
24396
|
}
|
|
24282
24397
|
}
|
|
24398
|
+
return returned;
|
|
24283
24399
|
}
|
|
24284
24400
|
if (callback.kind === "FunctionExpression") {
|
|
24285
24401
|
for (const block of callback.body ?? []) {
|
|
24286
24402
|
const term = block.terminator;
|
|
24287
|
-
if (term.kind === "Return" && term.argument
|
|
24288
|
-
|
|
24403
|
+
if (term.kind === "Return" && term.argument) {
|
|
24404
|
+
collectReturnedJSXFromExpression(term.argument, returned);
|
|
24289
24405
|
}
|
|
24290
24406
|
}
|
|
24291
24407
|
}
|
|
24292
|
-
return
|
|
24408
|
+
return returned;
|
|
24409
|
+
}
|
|
24410
|
+
function keyExpressionSignature(expression) {
|
|
24411
|
+
try {
|
|
24412
|
+
return JSON.stringify(expression, (key, value) => {
|
|
24413
|
+
if (key === "loc") return void 0;
|
|
24414
|
+
if (typeof value === "bigint") return `__bigint:${value.toString()}`;
|
|
24415
|
+
return value;
|
|
24416
|
+
}) ?? "";
|
|
24417
|
+
} catch {
|
|
24418
|
+
return "";
|
|
24419
|
+
}
|
|
24293
24420
|
}
|
|
24294
24421
|
function extractKeyFromMapCallback(callback) {
|
|
24295
|
-
const
|
|
24296
|
-
if (
|
|
24297
|
-
|
|
24422
|
+
const returnedKeyExpressions = getReturnedKeyExpressionsFromCallback(callback);
|
|
24423
|
+
if (returnedKeyExpressions.length === 1) {
|
|
24424
|
+
return returnedKeyExpressions[0];
|
|
24425
|
+
}
|
|
24426
|
+
if (returnedKeyExpressions.length > 1) {
|
|
24427
|
+
const [firstKey2, ...restKeys2] = returnedKeyExpressions;
|
|
24428
|
+
const firstSignature2 = keyExpressionSignature(firstKey2);
|
|
24429
|
+
if (firstSignature2 && restKeys2.every((keyExpr) => keyExpressionSignature(keyExpr) === firstSignature2)) {
|
|
24430
|
+
return firstKey2;
|
|
24431
|
+
}
|
|
24432
|
+
}
|
|
24433
|
+
const returned = getReturnedJSXFromCallback(callback);
|
|
24434
|
+
if (returned.length === 0) return void 0;
|
|
24435
|
+
const keyExpressions = returned.map((jsx) => extractKeyFromAttributes(jsx.attributes));
|
|
24436
|
+
if (keyExpressions.some((expr) => !expr)) return void 0;
|
|
24437
|
+
const [firstKey, ...restKeys] = keyExpressions;
|
|
24438
|
+
const firstSignature = keyExpressionSignature(firstKey);
|
|
24439
|
+
if (!firstSignature) return void 0;
|
|
24440
|
+
const allBranchesSameKey = restKeys.every(
|
|
24441
|
+
(keyExpr) => keyExpressionSignature(keyExpr) === firstSignature
|
|
24442
|
+
);
|
|
24443
|
+
if (!allBranchesSameKey) return void 0;
|
|
24444
|
+
return firstKey;
|
|
24298
24445
|
}
|
|
24299
24446
|
|
|
24300
24447
|
// src/ir/codegen-overrides.ts
|
|
@@ -24899,6 +25046,15 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24899
25046
|
ctx.inListRender = true;
|
|
24900
25047
|
let callbackExpr = ops.lowerExpression(mapCallback, ctx);
|
|
24901
25048
|
ctx.inListRender = prevInListRender;
|
|
25049
|
+
const shouldDeferOptionalCallbackEvaluation = isOptional && !t4.isArrowFunctionExpression(callbackExpr) && !t4.isFunctionExpression(callbackExpr);
|
|
25050
|
+
let deferredCallbackId = null;
|
|
25051
|
+
let deferredCallbackInitId = null;
|
|
25052
|
+
let deferredItemsId = null;
|
|
25053
|
+
if (shouldDeferOptionalCallbackEvaluation) {
|
|
25054
|
+
deferredCallbackId = ops.genTemp(ctx, "mapCb");
|
|
25055
|
+
deferredCallbackInitId = ops.genTemp(ctx, "mapCbReady");
|
|
25056
|
+
deferredItemsId = ops.genTemp(ctx, "mapItems");
|
|
25057
|
+
}
|
|
24902
25058
|
const capturedKeyParamName = ctx.listKeyParamName;
|
|
24903
25059
|
ctx.listKeyExpr = prevListKeyExpr;
|
|
24904
25060
|
ctx.listItemParamName = prevListItemParamName;
|
|
@@ -24998,7 +25154,7 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24998
25154
|
],
|
|
24999
25155
|
keyExprAst
|
|
25000
25156
|
);
|
|
25001
|
-
const hasIndexParam = (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
|
|
25157
|
+
const hasIndexParam = shouldDeferOptionalCallbackEvaluation || (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
|
|
25002
25158
|
if (canConstifyKey && (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr))) {
|
|
25003
25159
|
const newParams = [...callbackExpr.params];
|
|
25004
25160
|
while (newParams.length < 2) {
|
|
@@ -25018,25 +25174,131 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
25018
25174
|
}
|
|
25019
25175
|
}
|
|
25020
25176
|
statements.push(...hoistedStatements);
|
|
25177
|
+
if (shouldDeferOptionalCallbackEvaluation) {
|
|
25178
|
+
statements.push(
|
|
25179
|
+
t4.variableDeclaration("let", [
|
|
25180
|
+
t4.variableDeclarator(t4.cloneNode(deferredCallbackId, true))
|
|
25181
|
+
]),
|
|
25182
|
+
t4.variableDeclaration("let", [
|
|
25183
|
+
t4.variableDeclarator(t4.cloneNode(deferredCallbackInitId, true), t4.booleanLiteral(false))
|
|
25184
|
+
])
|
|
25185
|
+
);
|
|
25186
|
+
}
|
|
25187
|
+
const getItemsExpr = shouldDeferOptionalCallbackEvaluation ? t4.arrowFunctionExpression(
|
|
25188
|
+
[],
|
|
25189
|
+
t4.blockStatement([
|
|
25190
|
+
t4.variableDeclaration("const", [
|
|
25191
|
+
t4.variableDeclarator(
|
|
25192
|
+
t4.cloneNode(deferredItemsId, true),
|
|
25193
|
+
t4.cloneNode(arrayExprBase, true)
|
|
25194
|
+
)
|
|
25195
|
+
]),
|
|
25196
|
+
t4.ifStatement(
|
|
25197
|
+
t4.binaryExpression("==", t4.cloneNode(deferredItemsId, true), t4.nullLiteral()),
|
|
25198
|
+
t4.blockStatement([t4.returnStatement(t4.arrayExpression([]))])
|
|
25199
|
+
),
|
|
25200
|
+
t4.ifStatement(
|
|
25201
|
+
t4.unaryExpression("!", t4.cloneNode(deferredCallbackInitId, true)),
|
|
25202
|
+
t4.blockStatement([
|
|
25203
|
+
t4.expressionStatement(
|
|
25204
|
+
t4.assignmentExpression(
|
|
25205
|
+
"=",
|
|
25206
|
+
t4.cloneNode(deferredCallbackId, true),
|
|
25207
|
+
t4.cloneNode(callbackExpr, true)
|
|
25208
|
+
)
|
|
25209
|
+
),
|
|
25210
|
+
t4.expressionStatement(
|
|
25211
|
+
t4.assignmentExpression(
|
|
25212
|
+
"=",
|
|
25213
|
+
t4.cloneNode(deferredCallbackInitId, true),
|
|
25214
|
+
t4.booleanLiteral(true)
|
|
25215
|
+
)
|
|
25216
|
+
)
|
|
25217
|
+
])
|
|
25218
|
+
),
|
|
25219
|
+
t4.returnStatement(t4.cloneNode(deferredItemsId, true))
|
|
25220
|
+
])
|
|
25221
|
+
) : t4.arrowFunctionExpression([], arrayExpr);
|
|
25222
|
+
const renderExpr = shouldDeferOptionalCallbackEvaluation ? t4.arrowFunctionExpression(
|
|
25223
|
+
[t4.identifier("__item"), t4.identifier("__index"), t4.identifier("__key")],
|
|
25224
|
+
t4.callExpression(t4.cloneNode(deferredCallbackId, true), [
|
|
25225
|
+
t4.identifier("__item"),
|
|
25226
|
+
t4.identifier("__index"),
|
|
25227
|
+
t4.identifier("__key")
|
|
25228
|
+
])
|
|
25229
|
+
) : callbackExpr;
|
|
25021
25230
|
listCall = t4.callExpression(t4.identifier(RUNTIME_ALIASES.keyedList), [
|
|
25022
|
-
|
|
25231
|
+
getItemsExpr,
|
|
25023
25232
|
keyFn,
|
|
25024
|
-
|
|
25233
|
+
renderExpr,
|
|
25025
25234
|
t4.booleanLiteral(hasIndexParam)
|
|
25026
25235
|
]);
|
|
25027
25236
|
} else {
|
|
25028
25237
|
statements.push(...hoistedStatements);
|
|
25238
|
+
if (shouldDeferOptionalCallbackEvaluation) {
|
|
25239
|
+
statements.push(
|
|
25240
|
+
t4.variableDeclaration("let", [
|
|
25241
|
+
t4.variableDeclarator(t4.cloneNode(deferredCallbackId, true))
|
|
25242
|
+
]),
|
|
25243
|
+
t4.variableDeclaration("let", [
|
|
25244
|
+
t4.variableDeclarator(t4.cloneNode(deferredCallbackInitId, true), t4.booleanLiteral(false))
|
|
25245
|
+
])
|
|
25246
|
+
);
|
|
25247
|
+
}
|
|
25029
25248
|
const itemParamName = t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr) ? t4.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : "__item" : "__item";
|
|
25030
25249
|
const indexParamName = t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr) ? t4.isIdentifier(callbackExpr.params[1]) ? callbackExpr.params[1].name : "__index" : "__index";
|
|
25031
|
-
const hasIndexParam = (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
|
|
25250
|
+
const hasIndexParam = shouldDeferOptionalCallbackEvaluation || (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
|
|
25251
|
+
const getItemsExpr = shouldDeferOptionalCallbackEvaluation ? t4.arrowFunctionExpression(
|
|
25252
|
+
[],
|
|
25253
|
+
t4.blockStatement([
|
|
25254
|
+
t4.variableDeclaration("const", [
|
|
25255
|
+
t4.variableDeclarator(
|
|
25256
|
+
t4.cloneNode(deferredItemsId, true),
|
|
25257
|
+
t4.cloneNode(arrayExprBase, true)
|
|
25258
|
+
)
|
|
25259
|
+
]),
|
|
25260
|
+
t4.ifStatement(
|
|
25261
|
+
t4.binaryExpression("==", t4.cloneNode(deferredItemsId, true), t4.nullLiteral()),
|
|
25262
|
+
t4.blockStatement([t4.returnStatement(t4.arrayExpression([]))])
|
|
25263
|
+
),
|
|
25264
|
+
t4.ifStatement(
|
|
25265
|
+
t4.unaryExpression("!", t4.cloneNode(deferredCallbackInitId, true)),
|
|
25266
|
+
t4.blockStatement([
|
|
25267
|
+
t4.expressionStatement(
|
|
25268
|
+
t4.assignmentExpression(
|
|
25269
|
+
"=",
|
|
25270
|
+
t4.cloneNode(deferredCallbackId, true),
|
|
25271
|
+
t4.cloneNode(callbackExpr, true)
|
|
25272
|
+
)
|
|
25273
|
+
),
|
|
25274
|
+
t4.expressionStatement(
|
|
25275
|
+
t4.assignmentExpression(
|
|
25276
|
+
"=",
|
|
25277
|
+
t4.cloneNode(deferredCallbackInitId, true),
|
|
25278
|
+
t4.booleanLiteral(true)
|
|
25279
|
+
)
|
|
25280
|
+
)
|
|
25281
|
+
])
|
|
25282
|
+
),
|
|
25283
|
+
t4.returnStatement(t4.cloneNode(deferredItemsId, true))
|
|
25284
|
+
])
|
|
25285
|
+
) : t4.arrowFunctionExpression([], arrayExpr);
|
|
25286
|
+
const renderExpr = shouldDeferOptionalCallbackEvaluation ? t4.arrowFunctionExpression(
|
|
25287
|
+
[t4.identifier("__item"), t4.identifier("__index"), t4.identifier("__key")],
|
|
25288
|
+
t4.callExpression(t4.cloneNode(deferredCallbackId, true), [
|
|
25289
|
+
t4.identifier("__item"),
|
|
25290
|
+
t4.identifier("__index"),
|
|
25291
|
+
t4.identifier("__key")
|
|
25292
|
+
])
|
|
25293
|
+
) : callbackExpr;
|
|
25032
25294
|
const keyFn = t4.arrowFunctionExpression(
|
|
25033
25295
|
[t4.identifier(itemParamName), t4.identifier(indexParamName)],
|
|
25034
25296
|
t4.identifier(indexParamName)
|
|
25035
25297
|
);
|
|
25036
25298
|
listCall = t4.callExpression(t4.identifier(RUNTIME_ALIASES.keyedList), [
|
|
25037
|
-
|
|
25299
|
+
getItemsExpr,
|
|
25038
25300
|
keyFn,
|
|
25039
|
-
|
|
25301
|
+
renderExpr,
|
|
25040
25302
|
t4.booleanLiteral(hasIndexParam)
|
|
25041
25303
|
]);
|
|
25042
25304
|
}
|
|
@@ -33935,6 +34197,506 @@ function getRootIdentifier(expr, t4) {
|
|
|
33935
34197
|
return null;
|
|
33936
34198
|
}
|
|
33937
34199
|
|
|
34200
|
+
// src/tooling/analyze.ts
|
|
34201
|
+
var import_core2 = require("@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
|
+
(0, import_core2.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 = (0, import_core2.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
|
+
|
|
33938
34700
|
// src/index.ts
|
|
33939
34701
|
function stripMacroImports(path2, t4) {
|
|
33940
34702
|
path2.traverse({
|
|
@@ -34828,46 +35590,77 @@ function createHIREntrypointVisitor(t4, options) {
|
|
|
34828
35590
|
path2.traverse({
|
|
34829
35591
|
JSXExpressionContainer(exprPath) {
|
|
34830
35592
|
const expr = exprPath.node.expression;
|
|
34831
|
-
if (!t4.isCallExpression(expr)) return;
|
|
34832
|
-
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" })) {
|
|
34833
35595
|
return;
|
|
34834
35596
|
}
|
|
34835
|
-
const
|
|
34836
|
-
if (!
|
|
34837
|
-
const
|
|
34838
|
-
|
|
34839
|
-
|
|
34840
|
-
const ret = fn.body.body.find((stmt) => t4.isReturnStatement(stmt));
|
|
34841
|
-
if (ret && t4.isReturnStatement(ret) && ret.argument && (t4.isJSXElement(ret.argument) || t4.isJSXFragment(ret.argument))) {
|
|
34842
|
-
return ret.argument;
|
|
34843
|
-
}
|
|
34844
|
-
}
|
|
34845
|
-
return null;
|
|
34846
|
-
};
|
|
34847
|
-
const jsx = getReturnedJsx(cb);
|
|
34848
|
-
if (!jsx) return;
|
|
34849
|
-
if (t4.isJSXFragment(jsx)) {
|
|
34850
|
-
warn({
|
|
34851
|
-
code: "FICT-J002",
|
|
34852
|
-
message: "Missing key prop in list rendering.",
|
|
34853
|
-
fileName,
|
|
34854
|
-
line: expr.loc?.start.line ?? 0,
|
|
34855
|
-
column: expr.loc ? expr.loc.start.column + 1 : 0
|
|
34856
|
-
});
|
|
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()) {
|
|
34857
35602
|
return;
|
|
34858
35603
|
}
|
|
34859
|
-
|
|
34860
|
-
|
|
34861
|
-
|
|
34862
|
-
|
|
34863
|
-
|
|
34864
|
-
|
|
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;
|
|
34865
35639
|
}
|
|
34866
|
-
|
|
34867
|
-
|
|
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
|
+
}
|
|
34868
35660
|
}
|
|
34869
|
-
|
|
34870
|
-
|
|
35661
|
+
return !hasKey;
|
|
35662
|
+
});
|
|
35663
|
+
if (!hasMissingKeyBranch) return;
|
|
34871
35664
|
warn({
|
|
34872
35665
|
code: "FICT-J002",
|
|
34873
35666
|
message: "Missing key prop in list rendering.",
|
|
@@ -35430,8 +36223,10 @@ var createFictPlugin = (0, import_helper_plugin_utils.declare)(
|
|
|
35430
36223
|
var index_default = createFictPlugin;
|
|
35431
36224
|
// Annotate the CommonJS export names for ESM import in node:
|
|
35432
36225
|
0 && (module.exports = {
|
|
36226
|
+
analyzeFictFile,
|
|
35433
36227
|
clearModuleMetadata,
|
|
35434
36228
|
createFictPlugin,
|
|
36229
|
+
inferTraceMarkersForComponent,
|
|
35435
36230
|
resolveModuleMetadata,
|
|
35436
36231
|
setModuleMetadata
|
|
35437
36232
|
});
|