@barefootjs/mojolicious 0.18.3 → 0.18.4
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/expr/emitters.d.ts.map +1 -1
- package/dist/adapter/expr/operand.d.ts +6 -17
- package/dist/adapter/expr/operand.d.ts.map +1 -1
- package/dist/adapter/index.js +16 -17
- package/dist/build.js +16 -17
- package/dist/index.js +16 -22
- package/dist/render-divergences.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/adapter/expr/emitters.ts +26 -6
- package/src/adapter/expr/operand.ts +6 -27
- package/src/render-divergences.ts +0 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emitters.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/emitters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"emitters.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/emitters.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,28 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* EP template adapter.
|
|
2
|
+
* Index-access lowering for the Mojolicious EP template adapter.
|
|
4
3
|
*
|
|
5
4
|
* Extracted from `mojo-adapter.ts` (domain-module refactor, issue #2018
|
|
6
|
-
* track D). Pure
|
|
5
|
+
* track D). Pure function over `ParsedExpr` — it takes an `isStringName`
|
|
7
6
|
* predicate (supplied by the emitter from adapter state) rather than reading
|
|
8
7
|
* adapter instance state directly.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* integration, issue #2018 track D). `emitIndexAccessPerl` stays Mojo-specific
|
|
9
|
+
* The string-typed-operand classifier that used to live here (marked
|
|
10
|
+
* SHARED CANDIDATE) was promoted to `@barefootjs/jsx` as
|
|
11
|
+
* `isStringTypedOperand` (#2176); `emitIndexAccessPerl` stays Mojo-specific
|
|
14
12
|
* (Perl's `->[]` vs `->{}` split has no Kolon equivalent).
|
|
15
13
|
*/
|
|
16
|
-
import type
|
|
17
|
-
/**
|
|
18
|
-
* Whether a comparison operand is string-typed, so JS `===`/`!==` against it
|
|
19
|
-
* must lower to Perl `eq`/`ne` instead of numeric `==`/`!=` (#1672). Covers a
|
|
20
|
-
* string literal, a string-signal getter call (`sel()`), and a string prop
|
|
21
|
-
* access (`props.x`). `isStringName` reports whether a getter/prop name is
|
|
22
|
-
* known-string. Loop-element fields (`t.id`) on untyped arrays have no known
|
|
23
|
-
* type and stay undetected — a separate, narrower gap.
|
|
24
|
-
*/
|
|
25
|
-
export declare function isStringTypedOperand(expr: ParsedExpr, isStringName: (n: string) => boolean): boolean;
|
|
14
|
+
import { type ParsedExpr } from '@barefootjs/jsx';
|
|
26
15
|
/**
|
|
27
16
|
* Lower `arr[index]` to a Perl deref. Perl distinguishes array
|
|
28
17
|
* (`->[$i]`) from hash (`->{$k}`) access, which JS's single `[]` does
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operand.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/operand.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"operand.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/operand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEvE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,EAC/B,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,GACnC,MAAM,CAKR"}
|
package/dist/adapter/index.js
CHANGED
|
@@ -325,6 +325,9 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
325
325
|
|
|
326
326
|
// src/adapter/expr/emitters.ts
|
|
327
327
|
import {
|
|
328
|
+
groupBinaryOperand,
|
|
329
|
+
isStringTypedOperand as isStringTypedOperand2,
|
|
330
|
+
isStringConcatBinary,
|
|
328
331
|
emitParsedExpr,
|
|
329
332
|
identifierPath,
|
|
330
333
|
matchSearchParamsMethodCall,
|
|
@@ -333,17 +336,7 @@ import {
|
|
|
333
336
|
} from "@barefootjs/jsx";
|
|
334
337
|
|
|
335
338
|
// src/adapter/expr/operand.ts
|
|
336
|
-
|
|
337
|
-
if (expr.kind === "literal" && expr.literalType === "string")
|
|
338
|
-
return true;
|
|
339
|
-
if (expr.kind === "call" && expr.callee.kind === "identifier" && expr.args.length === 0) {
|
|
340
|
-
return isStringName(expr.callee.name);
|
|
341
|
-
}
|
|
342
|
-
if (expr.kind === "member" && expr.object.kind === "identifier" && expr.object.name === "props") {
|
|
343
|
-
return isStringName(expr.property);
|
|
344
|
-
}
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
339
|
+
import { isStringTypedOperand } from "@barefootjs/jsx";
|
|
347
340
|
function emitIndexAccessPerl(object, index, emit, isStringName) {
|
|
348
341
|
const i = emit(index);
|
|
349
342
|
return isStringTypedOperand(index, isStringName) ? `${emit(object)}->{${i}}` : `${emit(object)}->[${i}]`;
|
|
@@ -414,9 +407,9 @@ class MojoFilterEmitter {
|
|
|
414
407
|
return arg;
|
|
415
408
|
}
|
|
416
409
|
binary(op, left, right, emit) {
|
|
417
|
-
const l = emit(left);
|
|
418
|
-
const r = emit(right);
|
|
419
|
-
const isStr = (e) =>
|
|
410
|
+
const l = groupBinaryOperand(left, emit(left));
|
|
411
|
+
const r = groupBinaryOperand(right, emit(right));
|
|
412
|
+
const isStr = (e) => isStringTypedOperand2(e, this.isStringName);
|
|
420
413
|
const stringCmp = isStr(left) || isStr(right);
|
|
421
414
|
if ((op === "===" || op === "==") && stringCmp) {
|
|
422
415
|
return `${l} eq ${r}`;
|
|
@@ -424,6 +417,9 @@ class MojoFilterEmitter {
|
|
|
424
417
|
if ((op === "!==" || op === "!=") && stringCmp) {
|
|
425
418
|
return `${l} ne ${r}`;
|
|
426
419
|
}
|
|
420
|
+
if (isStringConcatBinary(op, left, right, this.isStringName)) {
|
|
421
|
+
return `${l} . ${r}`;
|
|
422
|
+
}
|
|
427
423
|
const opMap = {
|
|
428
424
|
"===": "==",
|
|
429
425
|
"!==": "!=",
|
|
@@ -567,9 +563,9 @@ class MojoTopLevelEmitter {
|
|
|
567
563
|
return arg;
|
|
568
564
|
}
|
|
569
565
|
binary(op, left, right, emit) {
|
|
570
|
-
const l = emit(left);
|
|
571
|
-
const r = emit(right);
|
|
572
|
-
const isStr = (e) =>
|
|
566
|
+
const l = groupBinaryOperand(left, emit(left));
|
|
567
|
+
const r = groupBinaryOperand(right, emit(right));
|
|
568
|
+
const isStr = (e) => isStringTypedOperand2(e, (n) => this.ctx._isStringValueName(n));
|
|
573
569
|
const stringCmp = isStr(left) || isStr(right);
|
|
574
570
|
if ((op === "===" || op === "==") && stringCmp) {
|
|
575
571
|
return `${l} eq ${r}`;
|
|
@@ -577,6 +573,9 @@ class MojoTopLevelEmitter {
|
|
|
577
573
|
if ((op === "!==" || op === "!=") && stringCmp) {
|
|
578
574
|
return `${l} ne ${r}`;
|
|
579
575
|
}
|
|
576
|
+
if (isStringConcatBinary(op, left, right, (n) => this.ctx._isStringValueName(n))) {
|
|
577
|
+
return `${l} . ${r}`;
|
|
578
|
+
}
|
|
580
579
|
const opMap = {
|
|
581
580
|
"===": "==",
|
|
582
581
|
"!==": "!=",
|
package/dist/build.js
CHANGED
|
@@ -325,6 +325,9 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
325
325
|
|
|
326
326
|
// src/adapter/expr/emitters.ts
|
|
327
327
|
import {
|
|
328
|
+
groupBinaryOperand,
|
|
329
|
+
isStringTypedOperand as isStringTypedOperand2,
|
|
330
|
+
isStringConcatBinary,
|
|
328
331
|
emitParsedExpr,
|
|
329
332
|
identifierPath,
|
|
330
333
|
matchSearchParamsMethodCall,
|
|
@@ -333,17 +336,7 @@ import {
|
|
|
333
336
|
} from "@barefootjs/jsx";
|
|
334
337
|
|
|
335
338
|
// src/adapter/expr/operand.ts
|
|
336
|
-
|
|
337
|
-
if (expr.kind === "literal" && expr.literalType === "string")
|
|
338
|
-
return true;
|
|
339
|
-
if (expr.kind === "call" && expr.callee.kind === "identifier" && expr.args.length === 0) {
|
|
340
|
-
return isStringName(expr.callee.name);
|
|
341
|
-
}
|
|
342
|
-
if (expr.kind === "member" && expr.object.kind === "identifier" && expr.object.name === "props") {
|
|
343
|
-
return isStringName(expr.property);
|
|
344
|
-
}
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
339
|
+
import { isStringTypedOperand } from "@barefootjs/jsx";
|
|
347
340
|
function emitIndexAccessPerl(object, index, emit, isStringName) {
|
|
348
341
|
const i = emit(index);
|
|
349
342
|
return isStringTypedOperand(index, isStringName) ? `${emit(object)}->{${i}}` : `${emit(object)}->[${i}]`;
|
|
@@ -414,9 +407,9 @@ class MojoFilterEmitter {
|
|
|
414
407
|
return arg;
|
|
415
408
|
}
|
|
416
409
|
binary(op, left, right, emit) {
|
|
417
|
-
const l = emit(left);
|
|
418
|
-
const r = emit(right);
|
|
419
|
-
const isStr = (e) =>
|
|
410
|
+
const l = groupBinaryOperand(left, emit(left));
|
|
411
|
+
const r = groupBinaryOperand(right, emit(right));
|
|
412
|
+
const isStr = (e) => isStringTypedOperand2(e, this.isStringName);
|
|
420
413
|
const stringCmp = isStr(left) || isStr(right);
|
|
421
414
|
if ((op === "===" || op === "==") && stringCmp) {
|
|
422
415
|
return `${l} eq ${r}`;
|
|
@@ -424,6 +417,9 @@ class MojoFilterEmitter {
|
|
|
424
417
|
if ((op === "!==" || op === "!=") && stringCmp) {
|
|
425
418
|
return `${l} ne ${r}`;
|
|
426
419
|
}
|
|
420
|
+
if (isStringConcatBinary(op, left, right, this.isStringName)) {
|
|
421
|
+
return `${l} . ${r}`;
|
|
422
|
+
}
|
|
427
423
|
const opMap = {
|
|
428
424
|
"===": "==",
|
|
429
425
|
"!==": "!=",
|
|
@@ -567,9 +563,9 @@ class MojoTopLevelEmitter {
|
|
|
567
563
|
return arg;
|
|
568
564
|
}
|
|
569
565
|
binary(op, left, right, emit) {
|
|
570
|
-
const l = emit(left);
|
|
571
|
-
const r = emit(right);
|
|
572
|
-
const isStr = (e) =>
|
|
566
|
+
const l = groupBinaryOperand(left, emit(left));
|
|
567
|
+
const r = groupBinaryOperand(right, emit(right));
|
|
568
|
+
const isStr = (e) => isStringTypedOperand2(e, (n) => this.ctx._isStringValueName(n));
|
|
573
569
|
const stringCmp = isStr(left) || isStr(right);
|
|
574
570
|
if ((op === "===" || op === "==") && stringCmp) {
|
|
575
571
|
return `${l} eq ${r}`;
|
|
@@ -577,6 +573,9 @@ class MojoTopLevelEmitter {
|
|
|
577
573
|
if ((op === "!==" || op === "!=") && stringCmp) {
|
|
578
574
|
return `${l} ne ${r}`;
|
|
579
575
|
}
|
|
576
|
+
if (isStringConcatBinary(op, left, right, (n) => this.ctx._isStringValueName(n))) {
|
|
577
|
+
return `${l} . ${r}`;
|
|
578
|
+
}
|
|
580
579
|
const opMap = {
|
|
581
580
|
"===": "==",
|
|
582
581
|
"!==": "!=",
|
package/dist/index.js
CHANGED
|
@@ -325,6 +325,9 @@ function renderFlatMethod(recv, depth, emit) {
|
|
|
325
325
|
|
|
326
326
|
// src/adapter/expr/emitters.ts
|
|
327
327
|
import {
|
|
328
|
+
groupBinaryOperand,
|
|
329
|
+
isStringTypedOperand as isStringTypedOperand2,
|
|
330
|
+
isStringConcatBinary,
|
|
328
331
|
emitParsedExpr,
|
|
329
332
|
identifierPath,
|
|
330
333
|
matchSearchParamsMethodCall,
|
|
@@ -333,17 +336,7 @@ import {
|
|
|
333
336
|
} from "@barefootjs/jsx";
|
|
334
337
|
|
|
335
338
|
// src/adapter/expr/operand.ts
|
|
336
|
-
|
|
337
|
-
if (expr.kind === "literal" && expr.literalType === "string")
|
|
338
|
-
return true;
|
|
339
|
-
if (expr.kind === "call" && expr.callee.kind === "identifier" && expr.args.length === 0) {
|
|
340
|
-
return isStringName(expr.callee.name);
|
|
341
|
-
}
|
|
342
|
-
if (expr.kind === "member" && expr.object.kind === "identifier" && expr.object.name === "props") {
|
|
343
|
-
return isStringName(expr.property);
|
|
344
|
-
}
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
339
|
+
import { isStringTypedOperand } from "@barefootjs/jsx";
|
|
347
340
|
function emitIndexAccessPerl(object, index, emit, isStringName) {
|
|
348
341
|
const i = emit(index);
|
|
349
342
|
return isStringTypedOperand(index, isStringName) ? `${emit(object)}->{${i}}` : `${emit(object)}->[${i}]`;
|
|
@@ -414,9 +407,9 @@ class MojoFilterEmitter {
|
|
|
414
407
|
return arg;
|
|
415
408
|
}
|
|
416
409
|
binary(op, left, right, emit) {
|
|
417
|
-
const l = emit(left);
|
|
418
|
-
const r = emit(right);
|
|
419
|
-
const isStr = (e) =>
|
|
410
|
+
const l = groupBinaryOperand(left, emit(left));
|
|
411
|
+
const r = groupBinaryOperand(right, emit(right));
|
|
412
|
+
const isStr = (e) => isStringTypedOperand2(e, this.isStringName);
|
|
420
413
|
const stringCmp = isStr(left) || isStr(right);
|
|
421
414
|
if ((op === "===" || op === "==") && stringCmp) {
|
|
422
415
|
return `${l} eq ${r}`;
|
|
@@ -424,6 +417,9 @@ class MojoFilterEmitter {
|
|
|
424
417
|
if ((op === "!==" || op === "!=") && stringCmp) {
|
|
425
418
|
return `${l} ne ${r}`;
|
|
426
419
|
}
|
|
420
|
+
if (isStringConcatBinary(op, left, right, this.isStringName)) {
|
|
421
|
+
return `${l} . ${r}`;
|
|
422
|
+
}
|
|
427
423
|
const opMap = {
|
|
428
424
|
"===": "==",
|
|
429
425
|
"!==": "!=",
|
|
@@ -567,9 +563,9 @@ class MojoTopLevelEmitter {
|
|
|
567
563
|
return arg;
|
|
568
564
|
}
|
|
569
565
|
binary(op, left, right, emit) {
|
|
570
|
-
const l = emit(left);
|
|
571
|
-
const r = emit(right);
|
|
572
|
-
const isStr = (e) =>
|
|
566
|
+
const l = groupBinaryOperand(left, emit(left));
|
|
567
|
+
const r = groupBinaryOperand(right, emit(right));
|
|
568
|
+
const isStr = (e) => isStringTypedOperand2(e, (n) => this.ctx._isStringValueName(n));
|
|
573
569
|
const stringCmp = isStr(left) || isStr(right);
|
|
574
570
|
if ((op === "===" || op === "==") && stringCmp) {
|
|
575
571
|
return `${l} eq ${r}`;
|
|
@@ -577,6 +573,9 @@ class MojoTopLevelEmitter {
|
|
|
577
573
|
if ((op === "!==" || op === "!=") && stringCmp) {
|
|
578
574
|
return `${l} ne ${r}`;
|
|
579
575
|
}
|
|
576
|
+
if (isStringConcatBinary(op, left, right, (n) => this.ctx._isStringValueName(n))) {
|
|
577
|
+
return `${l} . ${r}`;
|
|
578
|
+
}
|
|
580
579
|
const opMap = {
|
|
581
580
|
"===": "==",
|
|
582
581
|
"!==": "!=",
|
|
@@ -1806,16 +1805,11 @@ var conformancePins = {
|
|
|
1806
1805
|
};
|
|
1807
1806
|
// src/render-divergences.ts
|
|
1808
1807
|
var renderDivergences = {
|
|
1809
|
-
"arithmetic-text": "`(count() + 2) * 3` renders 10 instead of 18 — the parenthesised sub-expression loses its grouping (silent wrong arithmetic)",
|
|
1810
|
-
"string-concat-plus": "`'Hello, ' + name` renders \"0\" — Perl's numeric `+` coerces the strings; JS string-concat `+` needs Perl's `.`",
|
|
1811
1808
|
"string-length-text": "`.length` on a STRING prop diverges (array-length lowering misapplied to a scalar)",
|
|
1812
1809
|
"number-tofixed": "the literal `¥` in template text reaches the output as U+FFFD — a UTF-8 encoding gap for non-ASCII literal text adjacent to a dynamic slot",
|
|
1813
1810
|
"html-entity-text": "`©` in JSX literal text: Hono decodes to `©`, this adapter re-emits the raw entity — same DOM, different bytes",
|
|
1814
1811
|
"math-methods": "Math.min/max/abs over a signal render empty (only Math.floor is in the template-primitive registry)",
|
|
1815
|
-
"boolean-attr-literals": 'camelCase boolean alias `readOnly`: Hono SSRs `readOnly="true"`, this adapter emits bare presence',
|
|
1816
|
-
"camelcase-attributes": "`htmlFor` is not lowered to `for` (Hono maps it)",
|
|
1817
1812
|
"static-attr-escape": 'static attribute values are not HTML-escaped (`title="Fish & Chips"` emitted raw; Hono escapes)',
|
|
1818
|
-
"svg-icon": "SVG camelCase presentation attrs (`strokeWidth`, `strokeLinecap`) pass through unmapped; Hono lowers to kebab-case",
|
|
1819
1813
|
"object-entries-map": "`Object.entries(prop).map(([k, v]) => …)` renders an EMPTY list — the object-shaped prop silently produces zero iterations",
|
|
1820
1814
|
"nested-loop-outer-binding": "nested-loop inner items carry `data-key` where the reference emits the depth-suffixed `data-key-1`",
|
|
1821
1815
|
"jsx-element-prop": "a JSX element passed as a NON-children prop renders an empty slot — the element value is silently dropped",
|
|
@@ -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,iBAqB/B,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/mojolicious",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.4",
|
|
4
4
|
"description": "Mojolicious EP template adapter for BarefootJS - generates .html.ep files from IR",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"directory": "packages/adapter-mojolicious"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@barefootjs/shared": "0.18.
|
|
55
|
+
"@barefootjs/shared": "0.18.4"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@barefootjs/jsx": ">=0.2.0",
|
|
@@ -60,6 +60,6 @@
|
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
63
|
-
"@barefootjs/jsx": "0.18.
|
|
63
|
+
"@barefootjs/jsx": "0.18.4"
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
* adapter only through the narrow `MojoEmitContext` seam.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { groupBinaryOperand,
|
|
15
|
+
isStringTypedOperand,
|
|
16
|
+
isStringConcatBinary,
|
|
15
17
|
type ParsedExprEmitter,
|
|
16
18
|
type HigherOrderMethod,
|
|
17
19
|
type ArrayMethod,
|
|
@@ -29,7 +31,7 @@ import {
|
|
|
29
31
|
|
|
30
32
|
import type { MojoEmitContext } from '../emit-context.ts'
|
|
31
33
|
import { MOJO_TEMPLATE_PRIMITIVES } from '../lib/constants.ts'
|
|
32
|
-
import { emitIndexAccessPerl
|
|
34
|
+
import { emitIndexAccessPerl } from './operand.ts'
|
|
33
35
|
import {
|
|
34
36
|
renderArrayMethod,
|
|
35
37
|
renderSortMethod,
|
|
@@ -141,8 +143,11 @@ export class MojoFilterEmitter implements ParsedExprEmitter {
|
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
binary(op: string, left: ParsedExpr, right: ParsedExpr, emit: (e: ParsedExpr) => string): string {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
// Preserve source grouping: a compound operand re-emitted as infix
|
|
147
|
+
// text is otherwise re-parsed under THIS language's precedence —
|
|
148
|
+
// `(count() + 2) * 3` would silently become `count + 2 * 3` (#2173).
|
|
149
|
+
const l = groupBinaryOperand(left, emit(left))
|
|
150
|
+
const r = groupBinaryOperand(right, emit(right))
|
|
146
151
|
// String equality: `eq`/`ne` when EITHER operand is string-typed — a string
|
|
147
152
|
// literal, a string signal getter, or a string prop. Numeric `==`/`!=`
|
|
148
153
|
// would coerce both sides to 0 and match unrelated non-numeric strings (#1672).
|
|
@@ -154,6 +159,12 @@ export class MojoFilterEmitter implements ParsedExprEmitter {
|
|
|
154
159
|
if ((op === '!==' || op === '!=') && stringCmp) {
|
|
155
160
|
return `${l} ne ${r}`
|
|
156
161
|
}
|
|
162
|
+
// JS `+` with a string-typed operand is CONCATENATION, not addition —
|
|
163
|
+
// Perl's numeric `+` coerces `'Hello, ' + $name` to 0 (#2176). Lower
|
|
164
|
+
// to Perl's `.` concat operator.
|
|
165
|
+
if (isStringConcatBinary(op, left, right, this.isStringName)) {
|
|
166
|
+
return `${l} . ${r}`
|
|
167
|
+
}
|
|
157
168
|
const opMap: Record<string, string> = {
|
|
158
169
|
'===': '==', '!==': '!=', '>': '>', '<': '<', '>=': '>=', '<=': '<=',
|
|
159
170
|
'+': '+', '-': '-', '*': '*', '/': '/',
|
|
@@ -389,8 +400,11 @@ export class MojoTopLevelEmitter implements ParsedExprEmitter {
|
|
|
389
400
|
}
|
|
390
401
|
|
|
391
402
|
binary(op: string, left: ParsedExpr, right: ParsedExpr, emit: (e: ParsedExpr) => string): string {
|
|
392
|
-
|
|
393
|
-
|
|
403
|
+
// Preserve source grouping: a compound operand re-emitted as infix
|
|
404
|
+
// text is otherwise re-parsed under THIS language's precedence —
|
|
405
|
+
// `(count() + 2) * 3` would silently become `count + 2 * 3` (#2173).
|
|
406
|
+
const l = groupBinaryOperand(left, emit(left))
|
|
407
|
+
const r = groupBinaryOperand(right, emit(right))
|
|
394
408
|
// String equality: `eq`/`ne` when EITHER operand is string-typed — a string
|
|
395
409
|
// literal (`role() === 'admin'`), a string signal getter (`sel()`), or a
|
|
396
410
|
// string prop (`props.x`). Falling back to numeric `==`/`!=` would make
|
|
@@ -404,6 +418,12 @@ export class MojoTopLevelEmitter implements ParsedExprEmitter {
|
|
|
404
418
|
if ((op === '!==' || op === '!=') && stringCmp) {
|
|
405
419
|
return `${l} ne ${r}`
|
|
406
420
|
}
|
|
421
|
+
// JS `+` with a string-typed operand is CONCATENATION, not addition —
|
|
422
|
+
// Perl's numeric `+` coerces `'Hello, ' + $name` to 0 (#2176). Lower
|
|
423
|
+
// to Perl's `.` concat operator.
|
|
424
|
+
if (isStringConcatBinary(op, left, right, n => this.ctx._isStringValueName(n))) {
|
|
425
|
+
return `${l} . ${r}`
|
|
426
|
+
}
|
|
407
427
|
const opMap: Record<string, string> = {
|
|
408
428
|
'===': '==', '!==': '!=', '>': '>', '<': '<', '>=': '>=', '<=': '<=',
|
|
409
429
|
'+': '+', '-': '-', '*': '*',
|
|
@@ -1,39 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* EP template adapter.
|
|
2
|
+
* Index-access lowering for the Mojolicious EP template adapter.
|
|
4
3
|
*
|
|
5
4
|
* Extracted from `mojo-adapter.ts` (domain-module refactor, issue #2018
|
|
6
|
-
* track D). Pure
|
|
5
|
+
* track D). Pure function over `ParsedExpr` — it takes an `isStringName`
|
|
7
6
|
* predicate (supplied by the emitter from adapter state) rather than reading
|
|
8
7
|
* adapter instance state directly.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* integration, issue #2018 track D). `emitIndexAccessPerl` stays Mojo-specific
|
|
9
|
+
* The string-typed-operand classifier that used to live here (marked
|
|
10
|
+
* SHARED CANDIDATE) was promoted to `@barefootjs/jsx` as
|
|
11
|
+
* `isStringTypedOperand` (#2176); `emitIndexAccessPerl` stays Mojo-specific
|
|
14
12
|
* (Perl's `->[]` vs `->{}` split has no Kolon equivalent).
|
|
15
13
|
*/
|
|
16
14
|
|
|
17
|
-
import type
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Whether a comparison operand is string-typed, so JS `===`/`!==` against it
|
|
21
|
-
* must lower to Perl `eq`/`ne` instead of numeric `==`/`!=` (#1672). Covers a
|
|
22
|
-
* string literal, a string-signal getter call (`sel()`), and a string prop
|
|
23
|
-
* access (`props.x`). `isStringName` reports whether a getter/prop name is
|
|
24
|
-
* known-string. Loop-element fields (`t.id`) on untyped arrays have no known
|
|
25
|
-
* type and stay undetected — a separate, narrower gap.
|
|
26
|
-
*/
|
|
27
|
-
export function isStringTypedOperand(expr: ParsedExpr, isStringName: (n: string) => boolean): boolean {
|
|
28
|
-
if (expr.kind === 'literal' && expr.literalType === 'string') return true
|
|
29
|
-
if (expr.kind === 'call' && expr.callee.kind === 'identifier' && expr.args.length === 0) {
|
|
30
|
-
return isStringName(expr.callee.name)
|
|
31
|
-
}
|
|
32
|
-
if (expr.kind === 'member' && expr.object.kind === 'identifier' && expr.object.name === 'props') {
|
|
33
|
-
return isStringName(expr.property)
|
|
34
|
-
}
|
|
35
|
-
return false
|
|
36
|
-
}
|
|
15
|
+
import { isStringTypedOperand, type ParsedExpr } from '@barefootjs/jsx'
|
|
37
16
|
|
|
38
17
|
/**
|
|
39
18
|
* Lower `arr[index]` to a Perl deref. Perl distinguishes array
|
|
@@ -15,10 +15,6 @@
|
|
|
15
15
|
import type { RenderDivergences } from '@barefootjs/jsx'
|
|
16
16
|
|
|
17
17
|
export const renderDivergences: RenderDivergences = {
|
|
18
|
-
'arithmetic-text':
|
|
19
|
-
'`(count() + 2) * 3` renders 10 instead of 18 — the parenthesised sub-expression loses its grouping (silent wrong arithmetic)',
|
|
20
|
-
'string-concat-plus':
|
|
21
|
-
"`'Hello, ' + name` renders \"0\" — Perl's numeric `+` coerces the strings; JS string-concat `+` needs Perl's `.`",
|
|
22
18
|
'string-length-text':
|
|
23
19
|
'`.length` on a STRING prop diverges (array-length lowering misapplied to a scalar)',
|
|
24
20
|
'number-tofixed':
|
|
@@ -27,14 +23,8 @@ export const renderDivergences: RenderDivergences = {
|
|
|
27
23
|
'`©` in JSX literal text: Hono decodes to `©`, this adapter re-emits the raw entity — same DOM, different bytes',
|
|
28
24
|
'math-methods':
|
|
29
25
|
'Math.min/max/abs over a signal render empty (only Math.floor is in the template-primitive registry)',
|
|
30
|
-
'boolean-attr-literals':
|
|
31
|
-
'camelCase boolean alias `readOnly`: Hono SSRs `readOnly="true"`, this adapter emits bare presence',
|
|
32
|
-
'camelcase-attributes':
|
|
33
|
-
'`htmlFor` is not lowered to `for` (Hono maps it)',
|
|
34
26
|
'static-attr-escape':
|
|
35
27
|
'static attribute values are not HTML-escaped (`title="Fish & Chips"` emitted raw; Hono escapes)',
|
|
36
|
-
'svg-icon':
|
|
37
|
-
'SVG camelCase presentation attrs (`strokeWidth`, `strokeLinecap`) pass through unmapped; Hono lowers to kebab-case',
|
|
38
28
|
'object-entries-map':
|
|
39
29
|
'`Object.entries(prop).map(([k, v]) => …)` renders an EMPTY list — the object-shaped prop silently produces zero iterations',
|
|
40
30
|
'nested-loop-outer-binding':
|