@pyreon/compiler 0.12.5 → 0.12.7
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/lib/analysis/index.js.html +1 -1
- package/lib/index.js +162 -12
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/jsx.ts +224 -20
- package/src/tests/jsx.test.ts +119 -0
|
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
|
|
|
5386
5386
|
</script>
|
|
5387
5387
|
<script>
|
|
5388
5388
|
/*<!--*/
|
|
5389
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"5e8656db-1","name":"jsx.ts"},{"uid":"5e8656db-3","name":"project-scanner.ts"},{"uid":"5e8656db-5","name":"react-intercept.ts"},{"uid":"5e8656db-7","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"5e8656db-1":{"renderedLength":34317,"gzipLength":9205,"brotliLength":0,"metaUid":"5e8656db-0"},"5e8656db-3":{"renderedLength":4762,"gzipLength":1730,"brotliLength":0,"metaUid":"5e8656db-2"},"5e8656db-5":{"renderedLength":27692,"gzipLength":6920,"brotliLength":0,"metaUid":"5e8656db-4"},"5e8656db-7":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"5e8656db-6"}},"nodeMetas":{"5e8656db-0":{"id":"/src/jsx.ts","moduleParts":{"index.js":"5e8656db-1"},"imported":[{"uid":"5e8656db-8"}],"importedBy":[{"uid":"5e8656db-6"}]},"5e8656db-2":{"id":"/src/project-scanner.ts","moduleParts":{"index.js":"5e8656db-3"},"imported":[{"uid":"5e8656db-9"},{"uid":"5e8656db-10"}],"importedBy":[{"uid":"5e8656db-6"}]},"5e8656db-4":{"id":"/src/react-intercept.ts","moduleParts":{"index.js":"5e8656db-5"},"imported":[{"uid":"5e8656db-8"}],"importedBy":[{"uid":"5e8656db-6"}]},"5e8656db-6":{"id":"/src/index.ts","moduleParts":{"index.js":"5e8656db-7"},"imported":[{"uid":"5e8656db-0"},{"uid":"5e8656db-2"},{"uid":"5e8656db-4"}],"importedBy":[],"isEntry":true},"5e8656db-8":{"id":"typescript","moduleParts":{},"imported":[],"importedBy":[{"uid":"5e8656db-0"},{"uid":"5e8656db-4"}]},"5e8656db-9":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"5e8656db-2"}]},"5e8656db-10":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"5e8656db-2"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
|
|
5390
5390
|
|
|
5391
5391
|
const run = () => {
|
|
5392
5392
|
const width = window.innerWidth;
|
package/lib/index.js
CHANGED
|
@@ -105,10 +105,11 @@ function transformJSX(code, filename = "input.tsx") {
|
|
|
105
105
|
function wrap(expr) {
|
|
106
106
|
const start = expr.getStart(sf);
|
|
107
107
|
const end = expr.getEnd();
|
|
108
|
+
const exprText = inlineVarsInText(code.slice(start, end));
|
|
108
109
|
replacements.push({
|
|
109
110
|
start,
|
|
110
111
|
end,
|
|
111
|
-
text: `() => ${
|
|
112
|
+
text: `() => ${exprText}`
|
|
112
113
|
});
|
|
113
114
|
}
|
|
114
115
|
/** Try to hoist or wrap an expression, pushing a replacement if needed. */
|
|
@@ -179,7 +180,7 @@ function transformJSX(code, filename = "input.tsx") {
|
|
|
179
180
|
replacements.push({
|
|
180
181
|
start,
|
|
181
182
|
end,
|
|
182
|
-
text: `_rp(() => ${code.slice(start, end)})`
|
|
183
|
+
text: `_rp(() => ${inlineVarsInText(code.slice(start, end))})`
|
|
183
184
|
});
|
|
184
185
|
needsRpImport = true;
|
|
185
186
|
}
|
|
@@ -204,6 +205,161 @@ function transformJSX(code, filename = "input.tsx") {
|
|
|
204
205
|
}
|
|
205
206
|
ts.forEachChild(expr, walk);
|
|
206
207
|
}
|
|
208
|
+
/** Names that refer to the props object or splitProps results. */
|
|
209
|
+
const propsNames = /* @__PURE__ */ new Set();
|
|
210
|
+
/** Map of variable name → source text of the original expression. */
|
|
211
|
+
const propDerivedVars = /* @__PURE__ */ new Map();
|
|
212
|
+
/** Check if an expression reads from a tracked props-like object. */
|
|
213
|
+
function readsFromProps(node) {
|
|
214
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) return propsNames.has(node.expression.text);
|
|
215
|
+
if (ts.isElementAccessExpression(node) && ts.isIdentifier(node.expression)) return propsNames.has(node.expression.text);
|
|
216
|
+
let found = false;
|
|
217
|
+
ts.forEachChild(node, (child) => {
|
|
218
|
+
if (found) return;
|
|
219
|
+
if (readsFromProps(child)) found = true;
|
|
220
|
+
});
|
|
221
|
+
return found;
|
|
222
|
+
}
|
|
223
|
+
/** Pre-pass: scan a function body for prop-derived variable declarations.
|
|
224
|
+
* callbackDepth tracks nesting inside callback arguments (map, filter, etc.)
|
|
225
|
+
* to avoid tracking variables declared inside callbacks as prop-derived. */
|
|
226
|
+
let _callbackDepth = 0;
|
|
227
|
+
function scanForPropDerivedVars(node) {
|
|
228
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
|
|
229
|
+
const parent = node.parent;
|
|
230
|
+
if (parent && ts.isCallExpression(parent) && parent.arguments.includes(node)) {
|
|
231
|
+
_callbackDepth++;
|
|
232
|
+
ts.forEachChild(node, scanForPropDerivedVars);
|
|
233
|
+
_callbackDepth--;
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if ((ts.isFunctionDeclaration(node) || ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && node.parameters.length > 0) {
|
|
238
|
+
const parent = node.parent;
|
|
239
|
+
if (parent && ts.isCallExpression(parent) && parent.arguments.includes(node)) {
|
|
240
|
+
ts.forEachChild(node, scanForPropDerivedVars);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const firstParam = node.parameters[0];
|
|
244
|
+
if (ts.isIdentifier(firstParam.name)) {
|
|
245
|
+
let hasJSX = false;
|
|
246
|
+
ts.forEachChild(node, function checkJSX(n) {
|
|
247
|
+
if (hasJSX) return;
|
|
248
|
+
if (ts.isJsxElement(n) || ts.isJsxSelfClosingElement(n) || ts.isJsxFragment(n)) {
|
|
249
|
+
hasJSX = true;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
ts.forEachChild(n, checkJSX);
|
|
253
|
+
});
|
|
254
|
+
if (hasJSX) propsNames.add(firstParam.name.text);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (ts.isVariableStatement(node)) for (const decl of node.declarationList.declarations) {
|
|
258
|
+
if (ts.isArrayBindingPattern(decl.name) && decl.initializer && ts.isCallExpression(decl.initializer)) {
|
|
259
|
+
const callee = decl.initializer.expression;
|
|
260
|
+
if (ts.isIdentifier(callee) && callee.text === "splitProps") {
|
|
261
|
+
for (const el of decl.name.elements) if (ts.isBindingElement(el) && ts.isIdentifier(el.name)) propsNames.add(el.name.text);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (!(node.declarationList.flags & ts.NodeFlags.Const)) continue;
|
|
265
|
+
if (_callbackDepth > 0) continue;
|
|
266
|
+
if (ts.isIdentifier(decl.name) && decl.initializer) {
|
|
267
|
+
if (readsFromProps(decl.initializer)) {
|
|
268
|
+
const varName = decl.name.text;
|
|
269
|
+
const exprText = code.slice(decl.initializer.getStart(sf), decl.initializer.getEnd());
|
|
270
|
+
propDerivedVars.set(varName, exprText);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
ts.forEachChild(node, scanForPropDerivedVars);
|
|
275
|
+
}
|
|
276
|
+
scanForPropDerivedVars(sf);
|
|
277
|
+
let changed = true;
|
|
278
|
+
while (changed) {
|
|
279
|
+
changed = false;
|
|
280
|
+
sf.forEachChild(function scanTransitive(node) {
|
|
281
|
+
if (!ts.isVariableStatement(node)) {
|
|
282
|
+
ts.forEachChild(node, scanTransitive);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
for (const decl of node.declarationList.declarations) {
|
|
286
|
+
if (!ts.isIdentifier(decl.name) || !decl.initializer) continue;
|
|
287
|
+
const varName = decl.name.text;
|
|
288
|
+
if (propDerivedVars.has(varName)) continue;
|
|
289
|
+
if (node.declarationList.flags & ts.NodeFlags.Let) continue;
|
|
290
|
+
let usesPropVar = false;
|
|
291
|
+
ts.forEachChild(decl.initializer, function check(n) {
|
|
292
|
+
if (usesPropVar) return;
|
|
293
|
+
if (ts.isIdentifier(n) && propDerivedVars.has(n.text)) {
|
|
294
|
+
const parent = n.parent;
|
|
295
|
+
if (parent && ts.isPropertyAccessExpression(parent) && parent.name === n) return;
|
|
296
|
+
usesPropVar = true;
|
|
297
|
+
}
|
|
298
|
+
ts.forEachChild(n, check);
|
|
299
|
+
});
|
|
300
|
+
if (usesPropVar) {
|
|
301
|
+
const exprText = code.slice(decl.initializer.getStart(sf), decl.initializer.getEnd());
|
|
302
|
+
propDerivedVars.set(varName, exprText);
|
|
303
|
+
changed = true;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
for (const [varName, expr] of propDerivedVars) {
|
|
309
|
+
let resolved = expr;
|
|
310
|
+
for (const [depName, depExpr] of propDerivedVars) {
|
|
311
|
+
if (depName === varName) continue;
|
|
312
|
+
const re = new RegExp(`(?<![.\\w])${depName}(?![\\w:=])`, "g");
|
|
313
|
+
if (re.test(resolved)) resolved = resolved.replace(re, `(${depExpr})`);
|
|
314
|
+
}
|
|
315
|
+
if (resolved !== expr) propDerivedVars.set(varName, resolved);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Enhanced dynamic check — combines containsCall with props awareness.
|
|
319
|
+
* Returns true if an expression is reactive (contains signal calls,
|
|
320
|
+
* accesses props members, or references prop-derived variables).
|
|
321
|
+
*/
|
|
322
|
+
/**
|
|
323
|
+
* Replace prop-derived variable names in a source text with their original expressions.
|
|
324
|
+
* Simple regex-based replacement — safe because variable names are identifiers.
|
|
325
|
+
*/
|
|
326
|
+
function inlineVarsInText(text) {
|
|
327
|
+
if (propDerivedVars.size === 0) return text;
|
|
328
|
+
let result = text;
|
|
329
|
+
for (const [varName, expr] of propDerivedVars) {
|
|
330
|
+
const re = new RegExp(`(?<![.\\w])${varName}(?![\\w:=])`, "g");
|
|
331
|
+
result = result.replace(re, `(${expr})`);
|
|
332
|
+
}
|
|
333
|
+
return result;
|
|
334
|
+
}
|
|
335
|
+
function isDynamic(node) {
|
|
336
|
+
if (containsCall(node)) return true;
|
|
337
|
+
return accessesProps(node);
|
|
338
|
+
}
|
|
339
|
+
/** Check if an expression accesses a tracked props object or a prop-derived variable. */
|
|
340
|
+
function accessesProps(node) {
|
|
341
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
|
|
342
|
+
if (propsNames.has(node.expression.text)) return true;
|
|
343
|
+
}
|
|
344
|
+
if (ts.isIdentifier(node) && propDerivedVars.has(node.text)) {
|
|
345
|
+
const parent = node.parent;
|
|
346
|
+
if (parent && ts.isPropertyAccessExpression(parent) && parent.name === node) return false;
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
let found = false;
|
|
350
|
+
ts.forEachChild(node, (child) => {
|
|
351
|
+
if (found) return;
|
|
352
|
+
if (ts.isArrowFunction(child) || ts.isFunctionExpression(child)) return;
|
|
353
|
+
if (accessesProps(child)) found = true;
|
|
354
|
+
});
|
|
355
|
+
return found;
|
|
356
|
+
}
|
|
357
|
+
function shouldWrap(node) {
|
|
358
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) return false;
|
|
359
|
+
if (isStatic(node)) return false;
|
|
360
|
+
if (ts.isCallExpression(node) && isPureStaticCall(node)) return false;
|
|
361
|
+
return isDynamic(node);
|
|
362
|
+
}
|
|
207
363
|
function walk(node) {
|
|
208
364
|
if (ts.isJsxElement(node) && tryTemplateEmit(node)) return;
|
|
209
365
|
if (ts.isJsxSelfClosingElement(node) || ts.isJsxElement(node)) checkForWarnings(node);
|
|
@@ -387,7 +543,7 @@ function transformJSX(code, filename = "input.tsx") {
|
|
|
387
543
|
};
|
|
388
544
|
return {
|
|
389
545
|
expr: sliceExpr(exprNode),
|
|
390
|
-
isReactive:
|
|
546
|
+
isReactive: isDynamic(exprNode)
|
|
391
547
|
};
|
|
392
548
|
}
|
|
393
549
|
/** Build a setter expression for an attribute. */
|
|
@@ -448,7 +604,7 @@ function transformJSX(code, filename = "input.tsx") {
|
|
|
448
604
|
if (ts.isJsxSpreadAttribute(attr)) {
|
|
449
605
|
const expr = sliceExpr(attr.expression);
|
|
450
606
|
needsApplyPropsImport = true;
|
|
451
|
-
if (
|
|
607
|
+
if (isDynamic(attr.expression)) reactiveBindExprs.push(`_applyProps(${varName}, ${expr})`);
|
|
452
608
|
else bindLines.push(`_applyProps(${varName}, ${expr})`);
|
|
453
609
|
return "";
|
|
454
610
|
}
|
|
@@ -478,7 +634,7 @@ function transformJSX(code, filename = "input.tsx") {
|
|
|
478
634
|
} else {
|
|
479
635
|
needsBindImportGlobal = true;
|
|
480
636
|
const d = nextDisp();
|
|
481
|
-
bindLines.push(`const ${d} = _bind(() => { ${tVar}.data = ${expr} })`);
|
|
637
|
+
bindLines.push(`const ${d} = _bind(() => { ${tVar}.data = ${inlineVarsInText(expr)} })`);
|
|
482
638
|
}
|
|
483
639
|
return needsPlaceholder ? "<!>" : "";
|
|
484
640
|
}
|
|
@@ -543,7 +699,7 @@ function transformJSX(code, filename = "input.tsx") {
|
|
|
543
699
|
if (reactiveBindExprs.length > 0) {
|
|
544
700
|
needsBindImportGlobal = true;
|
|
545
701
|
const combinedName = nextDisp();
|
|
546
|
-
const combinedBody = reactiveBindExprs.join("; ");
|
|
702
|
+
const combinedBody = reactiveBindExprs.map(inlineVarsInText).join("; ");
|
|
547
703
|
bindLines.push(`const ${combinedName} = _bind(() => { ${combinedBody} })`);
|
|
548
704
|
}
|
|
549
705
|
if (bindLines.length === 0 && disposerNames.length === 0) return `_tpl("${escaped}", () => null)`;
|
|
@@ -740,12 +896,6 @@ function isPureStaticCall(node) {
|
|
|
740
896
|
if (!PURE_CALLS.has(name)) return false;
|
|
741
897
|
return node.arguments.every((arg) => !ts.isSpreadElement(arg) && isStatic(arg));
|
|
742
898
|
}
|
|
743
|
-
function shouldWrap(node) {
|
|
744
|
-
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) return false;
|
|
745
|
-
if (isStatic(node)) return false;
|
|
746
|
-
if (ts.isCallExpression(node) && isPureStaticCall(node)) return false;
|
|
747
|
-
return containsCall(node);
|
|
748
|
-
}
|
|
749
899
|
function containsCall(node) {
|
|
750
900
|
if (ts.isCallExpression(node)) {
|
|
751
901
|
if (isPureStaticCall(node)) return false;
|