@barefootjs/mojolicious 0.18.5 → 0.18.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/dist/adapter/index.js +79 -6
- package/dist/adapter/lib/static-value.d.ts +17 -0
- package/dist/adapter/lib/static-value.d.ts.map +1 -0
- package/dist/adapter/mojo-adapter.d.ts +15 -0
- package/dist/adapter/mojo-adapter.d.ts.map +1 -1
- package/dist/adapter/props/prop-classes.d.ts +23 -6
- package/dist/adapter/props/prop-classes.d.ts.map +1 -1
- package/dist/build.js +79 -6
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +81 -15
- package/dist/render-divergences.d.ts.map +1 -1
- package/dist/test-render.d.ts +0 -5
- package/dist/test-render.d.ts.map +1 -1
- package/lib/BarefootJS/Backend/Mojo.pm +1 -1
- package/lib/Mojolicious/Plugin/BarefootJS/DevReload.pm +1 -1
- package/lib/Mojolicious/Plugin/BarefootJS.pm +1 -1
- package/package.json +3 -3
- package/src/__tests__/mojo-adapter.test.ts +165 -4
- package/src/adapter/lib/static-value.ts +47 -0
- package/src/adapter/mojo-adapter.ts +77 -5
- package/src/adapter/props/prop-classes.ts +27 -6
- package/src/conformance-pins.ts +26 -28
- package/src/render-divergences.ts +6 -1
- package/src/test-render.ts +16 -210
- package/src/__tests__/evaluate-signal-init.test.ts +0 -35
package/dist/adapter/index.js
CHANGED
|
@@ -19,7 +19,12 @@ import {
|
|
|
19
19
|
queryHrefArgs,
|
|
20
20
|
isValidHelperId,
|
|
21
21
|
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
22
|
-
isLowerableLoopDestructure
|
|
22
|
+
isLowerableLoopDestructure,
|
|
23
|
+
isDangerousInnerHtmlAttr,
|
|
24
|
+
resolveDangerousInnerHtml,
|
|
25
|
+
dangerousInnerHtmlMetacharViolation,
|
|
26
|
+
dangerousInnerHtmlDiagnostic,
|
|
27
|
+
resolveStaticLoopSource
|
|
23
28
|
} from "@barefootjs/jsx";
|
|
24
29
|
|
|
25
30
|
// src/adapter/boolean-result.ts
|
|
@@ -338,6 +343,42 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
338
343
|
return `bf->flat(${recv}, ${d})`;
|
|
339
344
|
}
|
|
340
345
|
|
|
346
|
+
// src/adapter/lib/static-value.ts
|
|
347
|
+
function escapePerlSingleQuote2(s) {
|
|
348
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
349
|
+
}
|
|
350
|
+
function staticValueToPerl(value) {
|
|
351
|
+
if (value === null || value === undefined)
|
|
352
|
+
return "undef";
|
|
353
|
+
if (typeof value === "boolean")
|
|
354
|
+
return null;
|
|
355
|
+
if (typeof value === "number")
|
|
356
|
+
return String(value);
|
|
357
|
+
if (typeof value === "string")
|
|
358
|
+
return `'${escapePerlSingleQuote2(value)}'`;
|
|
359
|
+
if (Array.isArray(value)) {
|
|
360
|
+
const items = [];
|
|
361
|
+
for (const el of value) {
|
|
362
|
+
const serialized = staticValueToPerl(el);
|
|
363
|
+
if (serialized === null)
|
|
364
|
+
return null;
|
|
365
|
+
items.push(serialized);
|
|
366
|
+
}
|
|
367
|
+
return `[${items.join(", ")}]`;
|
|
368
|
+
}
|
|
369
|
+
if (typeof value === "object") {
|
|
370
|
+
const entries = [];
|
|
371
|
+
for (const [key, val] of Object.entries(value)) {
|
|
372
|
+
const serialized = staticValueToPerl(val);
|
|
373
|
+
if (serialized === null)
|
|
374
|
+
return null;
|
|
375
|
+
entries.push(`${perlHashKey(key)} => ${serialized}`);
|
|
376
|
+
}
|
|
377
|
+
return `{ ${entries.join(", ")} }`;
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
|
|
341
382
|
// src/adapter/expr/emitters.ts
|
|
342
383
|
import {
|
|
343
384
|
groupBinaryOperand,
|
|
@@ -934,6 +975,9 @@ function generateDerivedMemoSeed(ctx, ir) {
|
|
|
934
975
|
` : "";
|
|
935
976
|
}
|
|
936
977
|
|
|
978
|
+
// src/adapter/props/prop-classes.ts
|
|
979
|
+
import { collectLoopBoundNames } from "@barefootjs/jsx";
|
|
980
|
+
|
|
937
981
|
// src/adapter/value/parsed-literal.ts
|
|
938
982
|
function isStringTypeInfo(type) {
|
|
939
983
|
return type?.kind === "primitive" && type.primitive === "string";
|
|
@@ -970,6 +1014,12 @@ function collectStringValueNames(ir) {
|
|
|
970
1014
|
if (isStringTypeInfo(p.type))
|
|
971
1015
|
names.add(p.name);
|
|
972
1016
|
}
|
|
1017
|
+
for (const c of ir.metadata.localConstants) {
|
|
1018
|
+
if (isStringTypeInfo(c.type ?? undefined) || isBareStringLiteral(c.value))
|
|
1019
|
+
names.add(c.name);
|
|
1020
|
+
}
|
|
1021
|
+
for (const bound of collectLoopBoundNames(ir))
|
|
1022
|
+
names.delete(bound);
|
|
973
1023
|
return names;
|
|
974
1024
|
}
|
|
975
1025
|
|
|
@@ -1200,7 +1250,8 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1200
1250
|
renderElement(element) {
|
|
1201
1251
|
const tag = element.tag;
|
|
1202
1252
|
const attrs = this.renderAttributes(element);
|
|
1203
|
-
const
|
|
1253
|
+
const dangerousHtml = this.renderDangerousInnerHtml(element);
|
|
1254
|
+
const children = dangerousHtml !== null ? dangerousHtml : this.renderChildren(element.children);
|
|
1204
1255
|
let hydrationAttrs = "";
|
|
1205
1256
|
if (element.needsScope) {
|
|
1206
1257
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
@@ -1235,6 +1286,22 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1235
1286
|
}
|
|
1236
1287
|
return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
|
|
1237
1288
|
}
|
|
1289
|
+
renderDangerousInnerHtml(element) {
|
|
1290
|
+
const resolution = resolveDangerousInnerHtml(element);
|
|
1291
|
+
if (!resolution)
|
|
1292
|
+
return null;
|
|
1293
|
+
if (resolution.kind === "dynamic") {
|
|
1294
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
1295
|
+
return "";
|
|
1296
|
+
}
|
|
1297
|
+
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
1298
|
+
if (violation) {
|
|
1299
|
+
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
1300
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(`{ __html: ${JSON.stringify(resolution.html)} }`, attr.loc, violation));
|
|
1301
|
+
return "";
|
|
1302
|
+
}
|
|
1303
|
+
return resolution.html;
|
|
1304
|
+
}
|
|
1238
1305
|
renderExpression(expr) {
|
|
1239
1306
|
if (expr.clientOnly) {
|
|
1240
1307
|
if (expr.slotId) {
|
|
@@ -1242,7 +1309,7 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1242
1309
|
}
|
|
1243
1310
|
return "";
|
|
1244
1311
|
}
|
|
1245
|
-
const perlExpr = this.convertExpressionToPerl(expr.expr);
|
|
1312
|
+
const perlExpr = this.convertExpressionToPerl(expr.expr, expr.parsed);
|
|
1246
1313
|
if (expr.slotId) {
|
|
1247
1314
|
return `<%== bf->text_start("${expr.slotId}") %><%= ${perlExpr} %><%== bf->text_end %>`;
|
|
1248
1315
|
}
|
|
@@ -1334,8 +1401,12 @@ ${whenTrue}
|
|
|
1334
1401
|
}
|
|
1335
1402
|
});
|
|
1336
1403
|
}
|
|
1404
|
+
const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
|
|
1405
|
+
isNameShadowed: (name) => this.loopBoundNames.has(name)
|
|
1406
|
+
});
|
|
1407
|
+
const staticArray = staticItems !== null ? staticValueToPerl(staticItems) : null;
|
|
1337
1408
|
const arrayName = loop.array.trim();
|
|
1338
|
-
if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
1409
|
+
if (staticArray === null && /^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
1339
1410
|
const arrayConst = (this.localConstants ?? []).find((c) => c.name === arrayName);
|
|
1340
1411
|
if (arrayConst && !arrayConst.isModule && this.resolveLiteralConst(arrayName) === null) {
|
|
1341
1412
|
this.errors.push({
|
|
@@ -1349,7 +1420,7 @@ ${whenTrue}
|
|
|
1349
1420
|
});
|
|
1350
1421
|
}
|
|
1351
1422
|
}
|
|
1352
|
-
const rawArray = this.convertExpressionToPerl(loop.array);
|
|
1423
|
+
const rawArray = staticArray ?? this.convertExpressionToPerl(loop.array);
|
|
1353
1424
|
let sortedHoist = null;
|
|
1354
1425
|
let array = rawArray;
|
|
1355
1426
|
if (loop.sortComparator) {
|
|
@@ -1612,7 +1683,7 @@ ${children}`;
|
|
|
1612
1683
|
if (ternaryHashref !== null) {
|
|
1613
1684
|
return `<%== bf->spread_attrs(${ternaryHashref}) %>`;
|
|
1614
1685
|
}
|
|
1615
|
-
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
|
|
1686
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed) && !this.loopBoundNames.has(trimmed)) {
|
|
1616
1687
|
const localConst = this.localConstants.find((c) => c.name === trimmed && !c.isModule);
|
|
1617
1688
|
if (localConst?.value !== undefined) {
|
|
1618
1689
|
const initTrimmed = localConst.value.trim();
|
|
@@ -1648,6 +1719,8 @@ ${children}`;
|
|
|
1648
1719
|
for (const attr of element.attrs) {
|
|
1649
1720
|
if (attr.clientOnly)
|
|
1650
1721
|
continue;
|
|
1722
|
+
if (isDangerousInnerHtmlAttr(attr))
|
|
1723
|
+
continue;
|
|
1651
1724
|
let attrName;
|
|
1652
1725
|
if (attr.name === "className")
|
|
1653
1726
|
attrName = "class";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize a compile-time-evaluated JS value (`@barefootjs/jsx`'s
|
|
3
|
+
* `evaluateStaticLiteral`/`resolveStaticLoopSource`, #2208) into a native
|
|
4
|
+
* Perl literal. Used to inline a fully-static loop source (an inline array
|
|
5
|
+
* literal, or a function-scope local const with a static initializer)
|
|
6
|
+
* directly in the loop-bound expression, rather than requiring a bound
|
|
7
|
+
* template variable.
|
|
8
|
+
*
|
|
9
|
+
* Booleans deliberately return `null` (defer to the caller's BF101
|
|
10
|
+
* refusal) rather than baking `1`/`''` — Perl has no boolean literal, and
|
|
11
|
+
* that would diverge from JS's `String(true) === "true"` at render.
|
|
12
|
+
*
|
|
13
|
+
* Returns `null` for a value this adapter can't represent as a literal —
|
|
14
|
+
* the caller falls back to its existing BF101 refusal instead of guessing.
|
|
15
|
+
*/
|
|
16
|
+
export declare function staticValueToPerl(value: unknown): string | null;
|
|
17
|
+
//# sourceMappingURL=static-value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-value.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/static-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAwB/D"}
|
|
@@ -165,6 +165,14 @@ export declare class MojoAdapter extends BaseAdapter implements IRNodeEmitter<Mo
|
|
|
165
165
|
* quoted string literal (`const totalPages = 5`, #1897 pagination) —
|
|
166
166
|
* function-scope consts never reach the per-render stash, so a bare
|
|
167
167
|
* `$totalPages` faults under strict mode.
|
|
168
|
+
*
|
|
169
|
+
* The `loopBoundNames` guard also covers the #2221 hazard (a loop
|
|
170
|
+
* callback's own param shadowing this outer const's name): unlike the
|
|
171
|
+
* Twig-family adapters' coarse, whole-component `collectLoopBoundNames(ir)`
|
|
172
|
+
* static set, this adapter's `loopBoundNames` is a LIVE ref-counted map
|
|
173
|
+
* `renderLoop` populates/depopulates as it descends/ascends into each
|
|
174
|
+
* loop body (#1749) — so it's already scope-precise for this call site;
|
|
175
|
+
* no separate `staticLoopSourceBoundNames`-style field is needed here.
|
|
168
176
|
*/
|
|
169
177
|
private resolveLiteralConst;
|
|
170
178
|
private resolveStaticRecordLiteral;
|
|
@@ -218,6 +226,13 @@ export declare class MojoAdapter extends BaseAdapter implements IRNodeEmitter<Mo
|
|
|
218
226
|
private isClientOnlyContextIdentifier;
|
|
219
227
|
emitAsync(node: IRAsync, _ctx: MojoRenderCtx, _emit: EmitIRNode<MojoRenderCtx>): string;
|
|
220
228
|
renderElement(element: IRElement): string;
|
|
229
|
+
/**
|
|
230
|
+
* `dangerouslySetInnerHTML={{ __html: '...' }}` (#2207) — see the Blade
|
|
231
|
+
* adapter's identical helper for the full rationale. `null` means the
|
|
232
|
+
* attribute is absent (caller falls through to normal `renderChildren`);
|
|
233
|
+
* a non-`null` string (possibly `''`) replaces the children outright.
|
|
234
|
+
*/
|
|
235
|
+
private renderDangerousInnerHtml;
|
|
221
236
|
renderExpression(expr: IRExpression): string;
|
|
222
237
|
renderConditional(cond: IRConditional): string;
|
|
223
238
|
private renderNodeOrNull;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mojo-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/mojo-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,WAAW,EAEX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EAMP,yBAAyB,EAE1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EAClB,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"mojo-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/mojo-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,WAAW,EAEX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EAMP,yBAAyB,EAE1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EAClB,KAAK,UAAU,EA8BhB,MAAM,iBAAiB,CAAA;AAKxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AA8BnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAuCxD,qBAAa,WAAY,SAAQ,WAAY,YAAW,aAAa,CAAC,aAAa,CAAC;IAClF,IAAI,SAAgB;IACpB,SAAS,SAAa;IACtB,qBAAqB,UAAO;IAG5B,kBAAkB,EAAG,cAAc,CAAS;IAE5C;;;;;;;;;;;OAWG;IACH,kBAAkB,EAAE,yBAAyB,CAA0B;IAEvE,OAAO,CAAC,aAAa,CAAa;IAClC;;;;wCAIoC;IACpC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAiB;IAC/B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB,CAAI;IAC/B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,iBAAiB,CAAyB;IAClD;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB,CAAyB;IAClD;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAAyB;IACjD;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB,CAAyB;IAEpD;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB,CAAwB;IACjD;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB,CAAiC;IAC3D;;;;;;OAMG;IACH,OAAO,CAAC,cAAc,CAAmC;IACzD;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc,CAAiC;IACvD;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,qBAAqB,CAAyB;IAEtD,YAAY,OAAO,GAAE,kBAAuB,EAM3C;IAED,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,aAAa,CAsFzE;IAGD;;;;;OAKG;IACH;;;;;OAKG;IACH;;;;;OAKG;IACH,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAO3C;IAED;;;;OAIG;IACH,8BAA8B,CAC5B,IAAI,EAAE,MAAM,GACX;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAgBlD;IAED;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,0BAA0B;IASlC,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,2BAA2B;IAmBnC;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/B;IAMD,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAE1F;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7B;IAED,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEzC;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAElG;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAEpF;IAED,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAE9F;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAE5F;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAElG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAc5F;IAED,sEAAsE;IACtE,OAAO,CAAC,iBAAiB;IAkBzB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,yBAAyB;IAoBjC;;;;;;;OAOG;IACH,OAAO,CAAC,6BAA6B;IAMrC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAEtF;IAMD,aAAa,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAsCxC;IAED;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAoBhC,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAoB3C;IAMD,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAsC7C;IAED,OAAO,CAAC,gBAAgB;IAOxB;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAcnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoS/B;IAMD;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CA0CpC;IAED,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAwEzC;IAED,OAAO,CAAC,sBAAsB,CAAI;IAElC;+DAC2D;IAC3D,OAAO,CAAC,kBAAkB,CAAI;IAE9B,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,UAAU;IAIT,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAgB1C;IAMD;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAqNlC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAmB3B,8EAA8E;IAC9E,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,gBAAgB;IA0CxB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAIjD;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAMD;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAkC5B,OAAO,CAAC,iCAAiC;IAmCzC;;;;;;;OAOG;IACH,OAAO,CAAC,gCAAgC;IAmBxC;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,+BAA+B;IA8BvC;;;;;;;OAOG;IACH,OAAO,KAAK,OAAO,GAUlB;IAED;;;;;OAKG;IACH,OAAO,KAAK,SAAS,GAQpB;IAED,sEAAsE;IACtE,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,CAAC,uBAAuB;IAgF/B;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAI9B;;;;OAIG;IACH;4EACwE;IACxE,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,gBAAgB;IAcxB,iFAAiF;IACjF,OAAO,CAAC,2BAA2B;CAGpC;AAED,eAAO,MAAM,WAAW,aAAoB,CAAA"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* prop/name sets the adapter consults during lowering. Mirror of the Go
|
|
7
7
|
* adapter's `props/prop-types.ts`. No adapter instance state.
|
|
8
8
|
*/
|
|
9
|
-
import type
|
|
9
|
+
import { type ComponentIR } from '@barefootjs/jsx';
|
|
10
10
|
/**
|
|
11
11
|
* (#1971) SSR-resolvable context-value names: props, signal getters, memos.
|
|
12
12
|
* A `<Ctx.Provider value>` member NOT in this set is a client-only function
|
|
@@ -38,11 +38,28 @@ export declare function collectBooleanTypedProps(ir: ComponentIR): Set<string>;
|
|
|
38
38
|
*/
|
|
39
39
|
export declare function collectNullableOptionalProps(ir: ComponentIR): Set<string>;
|
|
40
40
|
/**
|
|
41
|
-
* String-typed signals
|
|
42
|
-
* to `eq`/`ne` (#1672)
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
41
|
+
* String-typed signals, props, and same-file local consts, so equality
|
|
42
|
+
* comparisons against them lower to `eq`/`ne` (#1672) and `+` concatenation
|
|
43
|
+
* against them lowers to Perl's `.` instead of numeric `+` (#2163, #2212 —
|
|
44
|
+
* `isStringConcatBinary`/`isStringTypedOperand` in `@barefootjs/jsx`, which
|
|
45
|
+
* now also recognizes a bare identifier operand, not just a prop/getter/
|
|
46
|
+
* literal). A signal is string-typed when its inferred type is `string`
|
|
47
|
+
* (the analyzer infers this from a string-literal initial value) or,
|
|
48
|
+
* defensively, when its initial value is a bare string literal; a prop or
|
|
49
|
+
* local const when its annotated (or inferred) type is `string`.
|
|
50
|
+
*
|
|
51
|
+
* Excludes any name bound as a `.map()`/`.filter()` loop callback's item
|
|
52
|
+
* or index parameter ANYWHERE in the component (Fable review, #2212): the
|
|
53
|
+
* lookup below is a flat, scope-blind `Set<string>` with no notion of a
|
|
54
|
+
* loop param shadowing an outer string-typed binding of the same name
|
|
55
|
+
* (`items.map((name) => 1 + name)` inside a component that also has a
|
|
56
|
+
* string `name` prop) — left unguarded, that shadowed `name` would be
|
|
57
|
+
* misdetected as string-typed and `1 + name` would silently lower to `.`
|
|
58
|
+
* instead of staying numeric `+`. Subtracting loop-bound names is coarse
|
|
59
|
+
* (it also suppresses a genuinely non-shadowed same-named string
|
|
60
|
+
* elsewhere in the component) but safe: the suppressed case just falls
|
|
61
|
+
* back to today's numeric `+` — the same, already-accepted residual as an
|
|
62
|
+
* unresolvable operand — never silently-wrong output.
|
|
46
63
|
*/
|
|
47
64
|
export declare function collectStringValueNames(ir: ComponentIR): Set<string>;
|
|
48
65
|
//# sourceMappingURL=prop-classes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prop-classes.d.ts","sourceRoot":"","sources":["../../../src/adapter/props/prop-classes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"prop-classes.d.ts","sourceRoot":"","sources":["../../../src/adapter/props/prop-classes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAyB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGzE;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAMrE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAMrE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAWzE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAepE"}
|
package/dist/build.js
CHANGED
|
@@ -19,7 +19,12 @@ import {
|
|
|
19
19
|
queryHrefArgs,
|
|
20
20
|
isValidHelperId,
|
|
21
21
|
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
22
|
-
isLowerableLoopDestructure
|
|
22
|
+
isLowerableLoopDestructure,
|
|
23
|
+
isDangerousInnerHtmlAttr,
|
|
24
|
+
resolveDangerousInnerHtml,
|
|
25
|
+
dangerousInnerHtmlMetacharViolation,
|
|
26
|
+
dangerousInnerHtmlDiagnostic,
|
|
27
|
+
resolveStaticLoopSource
|
|
23
28
|
} from "@barefootjs/jsx";
|
|
24
29
|
|
|
25
30
|
// src/adapter/boolean-result.ts
|
|
@@ -338,6 +343,42 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
338
343
|
return `bf->flat(${recv}, ${d})`;
|
|
339
344
|
}
|
|
340
345
|
|
|
346
|
+
// src/adapter/lib/static-value.ts
|
|
347
|
+
function escapePerlSingleQuote2(s) {
|
|
348
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
349
|
+
}
|
|
350
|
+
function staticValueToPerl(value) {
|
|
351
|
+
if (value === null || value === undefined)
|
|
352
|
+
return "undef";
|
|
353
|
+
if (typeof value === "boolean")
|
|
354
|
+
return null;
|
|
355
|
+
if (typeof value === "number")
|
|
356
|
+
return String(value);
|
|
357
|
+
if (typeof value === "string")
|
|
358
|
+
return `'${escapePerlSingleQuote2(value)}'`;
|
|
359
|
+
if (Array.isArray(value)) {
|
|
360
|
+
const items = [];
|
|
361
|
+
for (const el of value) {
|
|
362
|
+
const serialized = staticValueToPerl(el);
|
|
363
|
+
if (serialized === null)
|
|
364
|
+
return null;
|
|
365
|
+
items.push(serialized);
|
|
366
|
+
}
|
|
367
|
+
return `[${items.join(", ")}]`;
|
|
368
|
+
}
|
|
369
|
+
if (typeof value === "object") {
|
|
370
|
+
const entries = [];
|
|
371
|
+
for (const [key, val] of Object.entries(value)) {
|
|
372
|
+
const serialized = staticValueToPerl(val);
|
|
373
|
+
if (serialized === null)
|
|
374
|
+
return null;
|
|
375
|
+
entries.push(`${perlHashKey(key)} => ${serialized}`);
|
|
376
|
+
}
|
|
377
|
+
return `{ ${entries.join(", ")} }`;
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
|
|
341
382
|
// src/adapter/expr/emitters.ts
|
|
342
383
|
import {
|
|
343
384
|
groupBinaryOperand,
|
|
@@ -934,6 +975,9 @@ function generateDerivedMemoSeed(ctx, ir) {
|
|
|
934
975
|
` : "";
|
|
935
976
|
}
|
|
936
977
|
|
|
978
|
+
// src/adapter/props/prop-classes.ts
|
|
979
|
+
import { collectLoopBoundNames } from "@barefootjs/jsx";
|
|
980
|
+
|
|
937
981
|
// src/adapter/value/parsed-literal.ts
|
|
938
982
|
function isStringTypeInfo(type) {
|
|
939
983
|
return type?.kind === "primitive" && type.primitive === "string";
|
|
@@ -970,6 +1014,12 @@ function collectStringValueNames(ir) {
|
|
|
970
1014
|
if (isStringTypeInfo(p.type))
|
|
971
1015
|
names.add(p.name);
|
|
972
1016
|
}
|
|
1017
|
+
for (const c of ir.metadata.localConstants) {
|
|
1018
|
+
if (isStringTypeInfo(c.type ?? undefined) || isBareStringLiteral(c.value))
|
|
1019
|
+
names.add(c.name);
|
|
1020
|
+
}
|
|
1021
|
+
for (const bound of collectLoopBoundNames(ir))
|
|
1022
|
+
names.delete(bound);
|
|
973
1023
|
return names;
|
|
974
1024
|
}
|
|
975
1025
|
|
|
@@ -1200,7 +1250,8 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1200
1250
|
renderElement(element) {
|
|
1201
1251
|
const tag = element.tag;
|
|
1202
1252
|
const attrs = this.renderAttributes(element);
|
|
1203
|
-
const
|
|
1253
|
+
const dangerousHtml = this.renderDangerousInnerHtml(element);
|
|
1254
|
+
const children = dangerousHtml !== null ? dangerousHtml : this.renderChildren(element.children);
|
|
1204
1255
|
let hydrationAttrs = "";
|
|
1205
1256
|
if (element.needsScope) {
|
|
1206
1257
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
@@ -1235,6 +1286,22 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1235
1286
|
}
|
|
1236
1287
|
return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
|
|
1237
1288
|
}
|
|
1289
|
+
renderDangerousInnerHtml(element) {
|
|
1290
|
+
const resolution = resolveDangerousInnerHtml(element);
|
|
1291
|
+
if (!resolution)
|
|
1292
|
+
return null;
|
|
1293
|
+
if (resolution.kind === "dynamic") {
|
|
1294
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
1295
|
+
return "";
|
|
1296
|
+
}
|
|
1297
|
+
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
1298
|
+
if (violation) {
|
|
1299
|
+
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
1300
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(`{ __html: ${JSON.stringify(resolution.html)} }`, attr.loc, violation));
|
|
1301
|
+
return "";
|
|
1302
|
+
}
|
|
1303
|
+
return resolution.html;
|
|
1304
|
+
}
|
|
1238
1305
|
renderExpression(expr) {
|
|
1239
1306
|
if (expr.clientOnly) {
|
|
1240
1307
|
if (expr.slotId) {
|
|
@@ -1242,7 +1309,7 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1242
1309
|
}
|
|
1243
1310
|
return "";
|
|
1244
1311
|
}
|
|
1245
|
-
const perlExpr = this.convertExpressionToPerl(expr.expr);
|
|
1312
|
+
const perlExpr = this.convertExpressionToPerl(expr.expr, expr.parsed);
|
|
1246
1313
|
if (expr.slotId) {
|
|
1247
1314
|
return `<%== bf->text_start("${expr.slotId}") %><%= ${perlExpr} %><%== bf->text_end %>`;
|
|
1248
1315
|
}
|
|
@@ -1334,8 +1401,12 @@ ${whenTrue}
|
|
|
1334
1401
|
}
|
|
1335
1402
|
});
|
|
1336
1403
|
}
|
|
1404
|
+
const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
|
|
1405
|
+
isNameShadowed: (name) => this.loopBoundNames.has(name)
|
|
1406
|
+
});
|
|
1407
|
+
const staticArray = staticItems !== null ? staticValueToPerl(staticItems) : null;
|
|
1337
1408
|
const arrayName = loop.array.trim();
|
|
1338
|
-
if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
1409
|
+
if (staticArray === null && /^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
1339
1410
|
const arrayConst = (this.localConstants ?? []).find((c) => c.name === arrayName);
|
|
1340
1411
|
if (arrayConst && !arrayConst.isModule && this.resolveLiteralConst(arrayName) === null) {
|
|
1341
1412
|
this.errors.push({
|
|
@@ -1349,7 +1420,7 @@ ${whenTrue}
|
|
|
1349
1420
|
});
|
|
1350
1421
|
}
|
|
1351
1422
|
}
|
|
1352
|
-
const rawArray = this.convertExpressionToPerl(loop.array);
|
|
1423
|
+
const rawArray = staticArray ?? this.convertExpressionToPerl(loop.array);
|
|
1353
1424
|
let sortedHoist = null;
|
|
1354
1425
|
let array = rawArray;
|
|
1355
1426
|
if (loop.sortComparator) {
|
|
@@ -1612,7 +1683,7 @@ ${children}`;
|
|
|
1612
1683
|
if (ternaryHashref !== null) {
|
|
1613
1684
|
return `<%== bf->spread_attrs(${ternaryHashref}) %>`;
|
|
1614
1685
|
}
|
|
1615
|
-
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
|
|
1686
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed) && !this.loopBoundNames.has(trimmed)) {
|
|
1616
1687
|
const localConst = this.localConstants.find((c) => c.name === trimmed && !c.isModule);
|
|
1617
1688
|
if (localConst?.value !== undefined) {
|
|
1618
1689
|
const initTrimmed = localConst.value.trim();
|
|
@@ -1648,6 +1719,8 @@ ${children}`;
|
|
|
1648
1719
|
for (const attr of element.attrs) {
|
|
1649
1720
|
if (attr.clientOnly)
|
|
1650
1721
|
continue;
|
|
1722
|
+
if (isDangerousInnerHtmlAttr(attr))
|
|
1723
|
+
continue;
|
|
1651
1724
|
let attrName;
|
|
1652
1725
|
if (attr.name === "className")
|
|
1653
1726
|
attrName = "class";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eAmI7B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,12 @@ import {
|
|
|
19
19
|
queryHrefArgs,
|
|
20
20
|
isValidHelperId,
|
|
21
21
|
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
22
|
-
isLowerableLoopDestructure
|
|
22
|
+
isLowerableLoopDestructure,
|
|
23
|
+
isDangerousInnerHtmlAttr,
|
|
24
|
+
resolveDangerousInnerHtml,
|
|
25
|
+
dangerousInnerHtmlMetacharViolation,
|
|
26
|
+
dangerousInnerHtmlDiagnostic,
|
|
27
|
+
resolveStaticLoopSource
|
|
23
28
|
} from "@barefootjs/jsx";
|
|
24
29
|
|
|
25
30
|
// src/adapter/boolean-result.ts
|
|
@@ -338,6 +343,42 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
338
343
|
return `bf->flat(${recv}, ${d})`;
|
|
339
344
|
}
|
|
340
345
|
|
|
346
|
+
// src/adapter/lib/static-value.ts
|
|
347
|
+
function escapePerlSingleQuote2(s) {
|
|
348
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
349
|
+
}
|
|
350
|
+
function staticValueToPerl(value) {
|
|
351
|
+
if (value === null || value === undefined)
|
|
352
|
+
return "undef";
|
|
353
|
+
if (typeof value === "boolean")
|
|
354
|
+
return null;
|
|
355
|
+
if (typeof value === "number")
|
|
356
|
+
return String(value);
|
|
357
|
+
if (typeof value === "string")
|
|
358
|
+
return `'${escapePerlSingleQuote2(value)}'`;
|
|
359
|
+
if (Array.isArray(value)) {
|
|
360
|
+
const items = [];
|
|
361
|
+
for (const el of value) {
|
|
362
|
+
const serialized = staticValueToPerl(el);
|
|
363
|
+
if (serialized === null)
|
|
364
|
+
return null;
|
|
365
|
+
items.push(serialized);
|
|
366
|
+
}
|
|
367
|
+
return `[${items.join(", ")}]`;
|
|
368
|
+
}
|
|
369
|
+
if (typeof value === "object") {
|
|
370
|
+
const entries = [];
|
|
371
|
+
for (const [key, val] of Object.entries(value)) {
|
|
372
|
+
const serialized = staticValueToPerl(val);
|
|
373
|
+
if (serialized === null)
|
|
374
|
+
return null;
|
|
375
|
+
entries.push(`${perlHashKey(key)} => ${serialized}`);
|
|
376
|
+
}
|
|
377
|
+
return `{ ${entries.join(", ")} }`;
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
|
|
341
382
|
// src/adapter/expr/emitters.ts
|
|
342
383
|
import {
|
|
343
384
|
groupBinaryOperand,
|
|
@@ -934,6 +975,9 @@ function generateDerivedMemoSeed(ctx, ir) {
|
|
|
934
975
|
` : "";
|
|
935
976
|
}
|
|
936
977
|
|
|
978
|
+
// src/adapter/props/prop-classes.ts
|
|
979
|
+
import { collectLoopBoundNames } from "@barefootjs/jsx";
|
|
980
|
+
|
|
937
981
|
// src/adapter/value/parsed-literal.ts
|
|
938
982
|
function isStringTypeInfo(type) {
|
|
939
983
|
return type?.kind === "primitive" && type.primitive === "string";
|
|
@@ -970,6 +1014,12 @@ function collectStringValueNames(ir) {
|
|
|
970
1014
|
if (isStringTypeInfo(p.type))
|
|
971
1015
|
names.add(p.name);
|
|
972
1016
|
}
|
|
1017
|
+
for (const c of ir.metadata.localConstants) {
|
|
1018
|
+
if (isStringTypeInfo(c.type ?? undefined) || isBareStringLiteral(c.value))
|
|
1019
|
+
names.add(c.name);
|
|
1020
|
+
}
|
|
1021
|
+
for (const bound of collectLoopBoundNames(ir))
|
|
1022
|
+
names.delete(bound);
|
|
973
1023
|
return names;
|
|
974
1024
|
}
|
|
975
1025
|
|
|
@@ -1200,7 +1250,8 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1200
1250
|
renderElement(element) {
|
|
1201
1251
|
const tag = element.tag;
|
|
1202
1252
|
const attrs = this.renderAttributes(element);
|
|
1203
|
-
const
|
|
1253
|
+
const dangerousHtml = this.renderDangerousInnerHtml(element);
|
|
1254
|
+
const children = dangerousHtml !== null ? dangerousHtml : this.renderChildren(element.children);
|
|
1204
1255
|
let hydrationAttrs = "";
|
|
1205
1256
|
if (element.needsScope) {
|
|
1206
1257
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
@@ -1235,6 +1286,22 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1235
1286
|
}
|
|
1236
1287
|
return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
|
|
1237
1288
|
}
|
|
1289
|
+
renderDangerousInnerHtml(element) {
|
|
1290
|
+
const resolution = resolveDangerousInnerHtml(element);
|
|
1291
|
+
if (!resolution)
|
|
1292
|
+
return null;
|
|
1293
|
+
if (resolution.kind === "dynamic") {
|
|
1294
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
1295
|
+
return "";
|
|
1296
|
+
}
|
|
1297
|
+
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
1298
|
+
if (violation) {
|
|
1299
|
+
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
1300
|
+
this.errors.push(dangerousInnerHtmlDiagnostic(`{ __html: ${JSON.stringify(resolution.html)} }`, attr.loc, violation));
|
|
1301
|
+
return "";
|
|
1302
|
+
}
|
|
1303
|
+
return resolution.html;
|
|
1304
|
+
}
|
|
1238
1305
|
renderExpression(expr) {
|
|
1239
1306
|
if (expr.clientOnly) {
|
|
1240
1307
|
if (expr.slotId) {
|
|
@@ -1242,7 +1309,7 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1242
1309
|
}
|
|
1243
1310
|
return "";
|
|
1244
1311
|
}
|
|
1245
|
-
const perlExpr = this.convertExpressionToPerl(expr.expr);
|
|
1312
|
+
const perlExpr = this.convertExpressionToPerl(expr.expr, expr.parsed);
|
|
1246
1313
|
if (expr.slotId) {
|
|
1247
1314
|
return `<%== bf->text_start("${expr.slotId}") %><%= ${perlExpr} %><%== bf->text_end %>`;
|
|
1248
1315
|
}
|
|
@@ -1334,8 +1401,12 @@ ${whenTrue}
|
|
|
1334
1401
|
}
|
|
1335
1402
|
});
|
|
1336
1403
|
}
|
|
1404
|
+
const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
|
|
1405
|
+
isNameShadowed: (name) => this.loopBoundNames.has(name)
|
|
1406
|
+
});
|
|
1407
|
+
const staticArray = staticItems !== null ? staticValueToPerl(staticItems) : null;
|
|
1337
1408
|
const arrayName = loop.array.trim();
|
|
1338
|
-
if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
1409
|
+
if (staticArray === null && /^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
1339
1410
|
const arrayConst = (this.localConstants ?? []).find((c) => c.name === arrayName);
|
|
1340
1411
|
if (arrayConst && !arrayConst.isModule && this.resolveLiteralConst(arrayName) === null) {
|
|
1341
1412
|
this.errors.push({
|
|
@@ -1349,7 +1420,7 @@ ${whenTrue}
|
|
|
1349
1420
|
});
|
|
1350
1421
|
}
|
|
1351
1422
|
}
|
|
1352
|
-
const rawArray = this.convertExpressionToPerl(loop.array);
|
|
1423
|
+
const rawArray = staticArray ?? this.convertExpressionToPerl(loop.array);
|
|
1353
1424
|
let sortedHoist = null;
|
|
1354
1425
|
let array = rawArray;
|
|
1355
1426
|
if (loop.sortComparator) {
|
|
@@ -1612,7 +1683,7 @@ ${children}`;
|
|
|
1612
1683
|
if (ternaryHashref !== null) {
|
|
1613
1684
|
return `<%== bf->spread_attrs(${ternaryHashref}) %>`;
|
|
1614
1685
|
}
|
|
1615
|
-
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
|
|
1686
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed) && !this.loopBoundNames.has(trimmed)) {
|
|
1616
1687
|
const localConst = this.localConstants.find((c) => c.name === trimmed && !c.isModule);
|
|
1617
1688
|
if (localConst?.value !== undefined) {
|
|
1618
1689
|
const initTrimmed = localConst.value.trim();
|
|
@@ -1648,6 +1719,8 @@ ${children}`;
|
|
|
1648
1719
|
for (const attr of element.attrs) {
|
|
1649
1720
|
if (attr.clientOnly)
|
|
1650
1721
|
continue;
|
|
1722
|
+
if (isDangerousInnerHtmlAttr(attr))
|
|
1723
|
+
continue;
|
|
1651
1724
|
let attrName;
|
|
1652
1725
|
if (attr.name === "className")
|
|
1653
1726
|
attrName = "class";
|
|
@@ -1832,19 +1905,12 @@ Options:
|
|
|
1832
1905
|
var mojoAdapter = new MojoAdapter;
|
|
1833
1906
|
// src/conformance-pins.ts
|
|
1834
1907
|
var conformancePins = {
|
|
1835
|
-
"static-array-children": [{ code: "BF103", severity: "error" }],
|
|
1836
|
-
"todo-app": [{ code: "BF103", severity: "error" }],
|
|
1837
|
-
"todo-app-ssr": [{ code: "BF103", severity: "error" }],
|
|
1838
1908
|
"static-array-from-props": [{ code: "BF101", severity: "error" }],
|
|
1839
|
-
"static-array-from-props-with-component": [
|
|
1840
|
-
{ code: "BF103", severity: "error" },
|
|
1841
|
-
{ code: "BF101", severity: "error" }
|
|
1842
|
-
],
|
|
1909
|
+
"static-array-from-props-with-component": [{ code: "BF101", severity: "error" }],
|
|
1843
1910
|
"filter-nested-find-predicate": [
|
|
1844
1911
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
|
|
1845
1912
|
],
|
|
1846
|
-
"
|
|
1847
|
-
"dangerous-inner-html": [{ code: "BF101", severity: "error" }]
|
|
1913
|
+
"dangerous-inner-html-dynamic": [{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2215" }]
|
|
1848
1914
|
};
|
|
1849
1915
|
// src/render-divergences.ts
|
|
1850
1916
|
var renderDivergences = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAK/B,CAAA"}
|
package/dist/test-render.d.ts
CHANGED
|
@@ -42,9 +42,4 @@ export interface RenderOptions {
|
|
|
42
42
|
componentName?: string;
|
|
43
43
|
}
|
|
44
44
|
export declare function renderMojoComponent(options: RenderOptions): Promise<string>;
|
|
45
|
-
/**
|
|
46
|
-
* Evaluate a signal initializer expression using provided props.
|
|
47
|
-
* Handles patterns like: props.initial ?? 0, props.value, literal values.
|
|
48
|
-
*/
|
|
49
|
-
export declare function evaluateSignalInit(expr: string, props?: Record<string, unknown>): unknown;
|
|
50
45
|
//# sourceMappingURL=test-render.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-render.d.ts","sourceRoot":"","sources":["../src/test-render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAKxE;AAkCD,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,OAAO,EAAE,OAAO,iBAAiB,EAAE,eAAe,CAAA;IAClD,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"test-render.d.ts","sourceRoot":"","sources":["../src/test-render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAKxE;AAkCD,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,OAAO,EAAE,OAAO,iBAAiB,EAAE,eAAe,CAAA;IAClD,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAoOjF"}
|