@barefootjs/mojolicious 0.6.0 → 0.6.1
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 +37 -0
- package/dist/adapter/mojo-adapter.d.ts.map +1 -1
- package/dist/build.js +37 -0
- package/dist/index.js +37 -0
- package/lib/BarefootJS.pm +122 -0
- package/package.json +3 -3
- package/src/__tests__/mojo-adapter.test.ts +101 -6
- package/src/adapter/mojo-adapter.ts +83 -1
package/dist/adapter/index.js
CHANGED
|
@@ -884,6 +884,25 @@ function renderSortMethod(recv, c) {
|
|
|
884
884
|
});
|
|
885
885
|
return `bf->sort(${recv}, { keys => [${keyHashes.join(", ")}] })`;
|
|
886
886
|
}
|
|
887
|
+
function renderReduceMethod(recv, op, direction) {
|
|
888
|
+
const keyEntry = op.key.kind === "self" ? `key_kind => 'self'` : `key_kind => 'field', key => '${op.key.field}'`;
|
|
889
|
+
const init = op.type === "string" ? `'${op.init.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'` : op.init;
|
|
890
|
+
return `bf->reduce(${recv}, { op => '${op.op}', ${keyEntry}, type => '${op.type}', init => ${init}, direction => '${direction}' })`;
|
|
891
|
+
}
|
|
892
|
+
function renderFlatMethod(recv, depth) {
|
|
893
|
+
const d = depth === "infinity" ? -1 : depth;
|
|
894
|
+
return `bf->flat(${recv}, ${d})`;
|
|
895
|
+
}
|
|
896
|
+
function renderFlatMapMethod(recv, op) {
|
|
897
|
+
const proj = op.projection;
|
|
898
|
+
if (proj.kind === "tuple") {
|
|
899
|
+
const specs = proj.elements.map((l) => l.kind === "self" ? `['self', '']` : `['field', '${l.field}']`).join(", ");
|
|
900
|
+
return `bf->flat_map_tuple(${recv}, ${specs})`;
|
|
901
|
+
}
|
|
902
|
+
if (proj.kind === "self")
|
|
903
|
+
return `bf->flat_map(${recv}, 'self', '')`;
|
|
904
|
+
return `bf->flat_map(${recv}, 'field', '${proj.field}')`;
|
|
905
|
+
}
|
|
887
906
|
function isStringTypeInfo(type) {
|
|
888
907
|
return type?.kind === "primitive" && type.primitive === "string";
|
|
889
908
|
}
|
|
@@ -1008,6 +1027,15 @@ class MojoFilterEmitter {
|
|
|
1008
1027
|
sortMethod(_method, object, comparator, emit) {
|
|
1009
1028
|
return renderSortMethod(emit(object), comparator);
|
|
1010
1029
|
}
|
|
1030
|
+
reduceMethod(method, object, reduceOp, emit) {
|
|
1031
|
+
return renderReduceMethod(emit(object), reduceOp, method === "reduceRight" ? "right" : "left");
|
|
1032
|
+
}
|
|
1033
|
+
flatMethod(object, depth, emit) {
|
|
1034
|
+
return renderFlatMethod(emit(object), depth);
|
|
1035
|
+
}
|
|
1036
|
+
flatMapMethod(object, op, emit) {
|
|
1037
|
+
return renderFlatMapMethod(emit(object), op);
|
|
1038
|
+
}
|
|
1011
1039
|
conditional(_test, _consequent, _alternate) {
|
|
1012
1040
|
return "1";
|
|
1013
1041
|
}
|
|
@@ -1129,6 +1157,15 @@ class MojoTopLevelEmitter {
|
|
|
1129
1157
|
sortMethod(_method, object, comparator, emit) {
|
|
1130
1158
|
return renderSortMethod(emit(object), comparator);
|
|
1131
1159
|
}
|
|
1160
|
+
reduceMethod(method, object, reduceOp, emit) {
|
|
1161
|
+
return renderReduceMethod(emit(object), reduceOp, method === "reduceRight" ? "right" : "left");
|
|
1162
|
+
}
|
|
1163
|
+
flatMethod(object, depth, emit) {
|
|
1164
|
+
return renderFlatMethod(emit(object), depth);
|
|
1165
|
+
}
|
|
1166
|
+
flatMapMethod(object, op, emit) {
|
|
1167
|
+
return renderFlatMapMethod(emit(object), op);
|
|
1168
|
+
}
|
|
1132
1169
|
conditional(test, consequent, alternate, emit) {
|
|
1133
1170
|
return `(${emit(test)} ? ${emit(consequent)} : ${emit(alternate)})`;
|
|
1134
1171
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mojo-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/mojo-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,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,EAC1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAM3B,KAAK,aAAa,EAClB,KAAK,UAAU,EAUhB,MAAM,iBAAiB,CAAA;AAGxB;;;;;;GAMG;AACH,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;AAC1C,OAAO,KAAK,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"mojo-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/mojo-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/build.js
CHANGED
|
@@ -884,6 +884,25 @@ function renderSortMethod(recv, c) {
|
|
|
884
884
|
});
|
|
885
885
|
return `bf->sort(${recv}, { keys => [${keyHashes.join(", ")}] })`;
|
|
886
886
|
}
|
|
887
|
+
function renderReduceMethod(recv, op, direction) {
|
|
888
|
+
const keyEntry = op.key.kind === "self" ? `key_kind => 'self'` : `key_kind => 'field', key => '${op.key.field}'`;
|
|
889
|
+
const init = op.type === "string" ? `'${op.init.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'` : op.init;
|
|
890
|
+
return `bf->reduce(${recv}, { op => '${op.op}', ${keyEntry}, type => '${op.type}', init => ${init}, direction => '${direction}' })`;
|
|
891
|
+
}
|
|
892
|
+
function renderFlatMethod(recv, depth) {
|
|
893
|
+
const d = depth === "infinity" ? -1 : depth;
|
|
894
|
+
return `bf->flat(${recv}, ${d})`;
|
|
895
|
+
}
|
|
896
|
+
function renderFlatMapMethod(recv, op) {
|
|
897
|
+
const proj = op.projection;
|
|
898
|
+
if (proj.kind === "tuple") {
|
|
899
|
+
const specs = proj.elements.map((l) => l.kind === "self" ? `['self', '']` : `['field', '${l.field}']`).join(", ");
|
|
900
|
+
return `bf->flat_map_tuple(${recv}, ${specs})`;
|
|
901
|
+
}
|
|
902
|
+
if (proj.kind === "self")
|
|
903
|
+
return `bf->flat_map(${recv}, 'self', '')`;
|
|
904
|
+
return `bf->flat_map(${recv}, 'field', '${proj.field}')`;
|
|
905
|
+
}
|
|
887
906
|
function isStringTypeInfo(type) {
|
|
888
907
|
return type?.kind === "primitive" && type.primitive === "string";
|
|
889
908
|
}
|
|
@@ -1008,6 +1027,15 @@ class MojoFilterEmitter {
|
|
|
1008
1027
|
sortMethod(_method, object, comparator, emit) {
|
|
1009
1028
|
return renderSortMethod(emit(object), comparator);
|
|
1010
1029
|
}
|
|
1030
|
+
reduceMethod(method, object, reduceOp, emit) {
|
|
1031
|
+
return renderReduceMethod(emit(object), reduceOp, method === "reduceRight" ? "right" : "left");
|
|
1032
|
+
}
|
|
1033
|
+
flatMethod(object, depth, emit) {
|
|
1034
|
+
return renderFlatMethod(emit(object), depth);
|
|
1035
|
+
}
|
|
1036
|
+
flatMapMethod(object, op, emit) {
|
|
1037
|
+
return renderFlatMapMethod(emit(object), op);
|
|
1038
|
+
}
|
|
1011
1039
|
conditional(_test, _consequent, _alternate) {
|
|
1012
1040
|
return "1";
|
|
1013
1041
|
}
|
|
@@ -1129,6 +1157,15 @@ class MojoTopLevelEmitter {
|
|
|
1129
1157
|
sortMethod(_method, object, comparator, emit) {
|
|
1130
1158
|
return renderSortMethod(emit(object), comparator);
|
|
1131
1159
|
}
|
|
1160
|
+
reduceMethod(method, object, reduceOp, emit) {
|
|
1161
|
+
return renderReduceMethod(emit(object), reduceOp, method === "reduceRight" ? "right" : "left");
|
|
1162
|
+
}
|
|
1163
|
+
flatMethod(object, depth, emit) {
|
|
1164
|
+
return renderFlatMethod(emit(object), depth);
|
|
1165
|
+
}
|
|
1166
|
+
flatMapMethod(object, op, emit) {
|
|
1167
|
+
return renderFlatMapMethod(emit(object), op);
|
|
1168
|
+
}
|
|
1132
1169
|
conditional(test, consequent, alternate, emit) {
|
|
1133
1170
|
return `(${emit(test)} ? ${emit(consequent)} : ${emit(alternate)})`;
|
|
1134
1171
|
}
|
package/dist/index.js
CHANGED
|
@@ -884,6 +884,25 @@ function renderSortMethod(recv, c) {
|
|
|
884
884
|
});
|
|
885
885
|
return `bf->sort(${recv}, { keys => [${keyHashes.join(", ")}] })`;
|
|
886
886
|
}
|
|
887
|
+
function renderReduceMethod(recv, op, direction) {
|
|
888
|
+
const keyEntry = op.key.kind === "self" ? `key_kind => 'self'` : `key_kind => 'field', key => '${op.key.field}'`;
|
|
889
|
+
const init = op.type === "string" ? `'${op.init.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'` : op.init;
|
|
890
|
+
return `bf->reduce(${recv}, { op => '${op.op}', ${keyEntry}, type => '${op.type}', init => ${init}, direction => '${direction}' })`;
|
|
891
|
+
}
|
|
892
|
+
function renderFlatMethod(recv, depth) {
|
|
893
|
+
const d = depth === "infinity" ? -1 : depth;
|
|
894
|
+
return `bf->flat(${recv}, ${d})`;
|
|
895
|
+
}
|
|
896
|
+
function renderFlatMapMethod(recv, op) {
|
|
897
|
+
const proj = op.projection;
|
|
898
|
+
if (proj.kind === "tuple") {
|
|
899
|
+
const specs = proj.elements.map((l) => l.kind === "self" ? `['self', '']` : `['field', '${l.field}']`).join(", ");
|
|
900
|
+
return `bf->flat_map_tuple(${recv}, ${specs})`;
|
|
901
|
+
}
|
|
902
|
+
if (proj.kind === "self")
|
|
903
|
+
return `bf->flat_map(${recv}, 'self', '')`;
|
|
904
|
+
return `bf->flat_map(${recv}, 'field', '${proj.field}')`;
|
|
905
|
+
}
|
|
887
906
|
function isStringTypeInfo(type) {
|
|
888
907
|
return type?.kind === "primitive" && type.primitive === "string";
|
|
889
908
|
}
|
|
@@ -1008,6 +1027,15 @@ class MojoFilterEmitter {
|
|
|
1008
1027
|
sortMethod(_method, object, comparator, emit) {
|
|
1009
1028
|
return renderSortMethod(emit(object), comparator);
|
|
1010
1029
|
}
|
|
1030
|
+
reduceMethod(method, object, reduceOp, emit) {
|
|
1031
|
+
return renderReduceMethod(emit(object), reduceOp, method === "reduceRight" ? "right" : "left");
|
|
1032
|
+
}
|
|
1033
|
+
flatMethod(object, depth, emit) {
|
|
1034
|
+
return renderFlatMethod(emit(object), depth);
|
|
1035
|
+
}
|
|
1036
|
+
flatMapMethod(object, op, emit) {
|
|
1037
|
+
return renderFlatMapMethod(emit(object), op);
|
|
1038
|
+
}
|
|
1011
1039
|
conditional(_test, _consequent, _alternate) {
|
|
1012
1040
|
return "1";
|
|
1013
1041
|
}
|
|
@@ -1129,6 +1157,15 @@ class MojoTopLevelEmitter {
|
|
|
1129
1157
|
sortMethod(_method, object, comparator, emit) {
|
|
1130
1158
|
return renderSortMethod(emit(object), comparator);
|
|
1131
1159
|
}
|
|
1160
|
+
reduceMethod(method, object, reduceOp, emit) {
|
|
1161
|
+
return renderReduceMethod(emit(object), reduceOp, method === "reduceRight" ? "right" : "left");
|
|
1162
|
+
}
|
|
1163
|
+
flatMethod(object, depth, emit) {
|
|
1164
|
+
return renderFlatMethod(emit(object), depth);
|
|
1165
|
+
}
|
|
1166
|
+
flatMapMethod(object, op, emit) {
|
|
1167
|
+
return renderFlatMapMethod(emit(object), op);
|
|
1168
|
+
}
|
|
1132
1169
|
conditional(test, consequent, alternate, emit) {
|
|
1133
1170
|
return `(${emit(test)} ? ${emit(consequent)} : ${emit(alternate)})`;
|
|
1134
1171
|
}
|
package/lib/BarefootJS.pm
CHANGED
|
@@ -508,6 +508,71 @@ sub reverse ($self, $recv) {
|
|
|
508
508
|
return [ reverse @$recv ];
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
+
# `Array.prototype.flat(depth?)` (#1448 Tier C) — flatten nested ARRAY
|
|
512
|
+
# refs `$depth` levels deep. A `$depth` of -1 is the `Infinity` sentinel
|
|
513
|
+
# (flatten fully); 0 returns a shallow copy. Non-ARRAY elements are kept
|
|
514
|
+
# as-is (JS only flattens nested arrays). Non-ARRAY receiver → [].
|
|
515
|
+
sub flat ($self, $recv, $depth = 1) {
|
|
516
|
+
return [] unless ref($recv) eq 'ARRAY';
|
|
517
|
+
my @out;
|
|
518
|
+
for my $el (@$recv) {
|
|
519
|
+
if ($depth != 0 && ref($el) eq 'ARRAY') {
|
|
520
|
+
my $next = $depth > 0 ? $depth - 1 : $depth;
|
|
521
|
+
push @out, @{ $self->flat($el, $next) };
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
push @out, $el;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return \@out;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
# `Array.prototype.flatMap(fn)` value-returning field projection
|
|
531
|
+
# (#1448 Tier C) — map each element through a self / field projection,
|
|
532
|
+
# then flatten one level. `field` reads a HASH-ref key (the raw JS prop
|
|
533
|
+
# name, as `bf->reduce` does); a projected non-ARRAY value is kept as-is
|
|
534
|
+
# (flatMap = map + flat(1)). Non-ARRAY receiver → [].
|
|
535
|
+
sub flat_map ($self, $recv, $key_kind, $key) {
|
|
536
|
+
return [] unless ref($recv) eq 'ARRAY';
|
|
537
|
+
my @projected;
|
|
538
|
+
for my $el (@$recv) {
|
|
539
|
+
if ($key_kind eq 'field') {
|
|
540
|
+
# JS `i => i.field` on a non-object yields `undefined`, not the
|
|
541
|
+
# element itself — push `undef` so a scalar element doesn't leak
|
|
542
|
+
# into the output (matches Go's `getFieldValue` returning nil).
|
|
543
|
+
push @projected, ref($el) eq 'HASH' ? $el->{$key} : undef;
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
push @projected, $el;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return $self->flat(\@projected, 1);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
# `Array.prototype.flatMap(i => [i.a, i.b])` — array-literal tuple
|
|
553
|
+
# projection (#1448 Tier C). Each `@specs` entry is a [kind, key] arrayref
|
|
554
|
+
# (['self', ''] or ['field', 'a']). For each element, every leaf's value
|
|
555
|
+
# is appended in order. flat(1) removes only the literal wrapper, so an
|
|
556
|
+
# array-valued leaf is appended verbatim (no spread) — i.e. just append
|
|
557
|
+
# each leaf. A non-HASH element under a `field` leaf yields undef (JS
|
|
558
|
+
# `i.field` on a non-object). Non-ARRAY receiver → [].
|
|
559
|
+
sub flat_map_tuple ($self, $recv, @specs) {
|
|
560
|
+
return [] unless ref($recv) eq 'ARRAY';
|
|
561
|
+
my @out;
|
|
562
|
+
for my $el (@$recv) {
|
|
563
|
+
for my $spec (@specs) {
|
|
564
|
+
my ($kind, $key) = @$spec;
|
|
565
|
+
if ($kind eq 'field') {
|
|
566
|
+
push @out, ref($el) eq 'HASH' ? $el->{$key} : undef;
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
push @out, $el;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return \@out;
|
|
574
|
+
}
|
|
575
|
+
|
|
511
576
|
# `String.prototype.trim()` — strip leading + trailing whitespace.
|
|
512
577
|
# JS's `String.prototype.trim` matches `\s` in the Unicode sense
|
|
513
578
|
# (any whitespace including non-breaking space U+00A0); Perl's `\s`
|
|
@@ -782,6 +847,63 @@ sub _compare_sort_key ($av, $bv, $compare_type) {
|
|
|
782
847
|
return ($av // 0) <=> ($bv // 0); # numeric
|
|
783
848
|
}
|
|
784
849
|
|
|
850
|
+
# Fold an array into a scalar via the arithmetic-fold catalogue
|
|
851
|
+
# (#1448 Tier C). Mirrors Go's `bf_reduce` and JS `reduce(fn, init)` /
|
|
852
|
+
# `reduceRight(fn, init)` for the shapes `(acc, x) => acc <op> x` /
|
|
853
|
+
# `(acc, x) => acc <op> x.field`:
|
|
854
|
+
#
|
|
855
|
+
# bf->reduce($recv, {
|
|
856
|
+
# op => '+' | '*',
|
|
857
|
+
# key_kind => 'self' | 'field',
|
|
858
|
+
# key => '<field>', # when key_kind eq 'field'
|
|
859
|
+
# type => 'numeric' | 'string',
|
|
860
|
+
# init => <seed>, # number, or string for concat
|
|
861
|
+
# direction => 'left' | 'right', # 'right' = reduceRight (default 'left')
|
|
862
|
+
# })
|
|
863
|
+
#
|
|
864
|
+
# Numeric folds accumulate with `+` / `*` (non-numeric keys coalesce to
|
|
865
|
+
# 0); string folds concatenate via `bf->string` (undef → ''). The init
|
|
866
|
+
# seeds the accumulator, so an empty array returns it unchanged — exactly
|
|
867
|
+
# like JS. `direction => 'right'` folds right-to-left (reduceRight); only
|
|
868
|
+
# observable for string concat, since numeric sum / product commute.
|
|
869
|
+
# Float stringification can diverge from Go's for inexact binary
|
|
870
|
+
# fractions (e.g. 0.1 + 0.2); integer sums — the common case — agree.
|
|
871
|
+
sub reduce ($self, $recv, $opts = {}) {
|
|
872
|
+
my $op = $opts->{op} // '+';
|
|
873
|
+
my $key_kind = $opts->{key_kind} // 'self';
|
|
874
|
+
my $key = $opts->{key} // '';
|
|
875
|
+
my $type = $opts->{type} // 'numeric';
|
|
876
|
+
my $direction = $opts->{direction} // 'left';
|
|
877
|
+
|
|
878
|
+
my @items = ref($recv) eq 'ARRAY' ? @$recv : ();
|
|
879
|
+
# reduceRight folds right-to-left; reversing the snapshot keeps the
|
|
880
|
+
# single forward loop below. Only observable for string concat —
|
|
881
|
+
# numeric sum / product commute. Qualify as CORE::reverse — this
|
|
882
|
+
# package defines `sub reverse` (the `.reverse()` helper), so a bare
|
|
883
|
+
# `reverse` is ambiguous under `use warnings`.
|
|
884
|
+
@items = CORE::reverse(@items) if $direction eq 'right';
|
|
885
|
+
my $project = sub ($item) {
|
|
886
|
+
$key_kind eq 'field' && ref($item) eq 'HASH' ? $item->{$key} : $item;
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
if ($type eq 'string') {
|
|
890
|
+
my $acc = $opts->{init} // '';
|
|
891
|
+
$acc .= $self->string($project->($_)) for @items;
|
|
892
|
+
return $acc;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
my $acc = $opts->{init} // 0;
|
|
896
|
+
for my $item (@items) {
|
|
897
|
+
my $n = $project->($item);
|
|
898
|
+
# Guard `defined` before `looks_like_number` so a missing field
|
|
899
|
+
# (undef) folds as 0 without an "uninitialized value" warning
|
|
900
|
+
# under `use warnings` — matching the `$av // ''` style `sort` uses.
|
|
901
|
+
$n = 0 unless defined $n && looks_like_number($n);
|
|
902
|
+
$op eq '*' ? ($acc *= $n) : ($acc += $n);
|
|
903
|
+
}
|
|
904
|
+
return $acc;
|
|
905
|
+
}
|
|
906
|
+
|
|
785
907
|
# ---------------------------------------------------------------------------
|
|
786
908
|
# JSX intrinsic-element spread (#1407)
|
|
787
909
|
# ---------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/mojolicious",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
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,14 +52,14 @@
|
|
|
52
52
|
"directory": "packages/adapter-mojolicious"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@barefootjs/shared": "0.6.
|
|
55
|
+
"@barefootjs/shared": "0.6.1"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@barefootjs/jsx": ">=0.2.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
62
|
-
"@barefootjs/jsx": "0.6.
|
|
62
|
+
"@barefootjs/jsx": "0.6.1",
|
|
63
63
|
"typescript": "^5.0.0"
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -395,9 +395,16 @@ export function C() {
|
|
|
395
395
|
// The nested-higher-order-in-filter-predicate shape also lowers
|
|
396
396
|
// now (#1443 PR4) — moved to a positive-output test below.
|
|
397
397
|
const cases: { name: string; body: string; needle: string }[] = [
|
|
398
|
-
|
|
398
|
+
// The arithmetic-fold `.reduce(fn, init)` catalogue now lowers
|
|
399
|
+
// (positive-output tests below + the reduce-* conformance
|
|
400
|
+
// fixtures); the no-init form stays refused — JS throws on an
|
|
401
|
+
// empty array there, which a template can't mirror.
|
|
402
|
+
{ name: 'reduce (no init)', body: `<div>{items().reduce((s, x) => s + x)}</div>`, needle: '.reduce(' },
|
|
399
403
|
{ name: 'forEach', body: `<ul>{items().forEach(x => x)}</ul>`, needle: '.forEach(' },
|
|
400
|
-
|
|
404
|
+
// Self / field / field-tuple `.flatMap` now lowers (#1448 Tier C) —
|
|
405
|
+
// even as a loop base — so those moved to positive tests below. A
|
|
406
|
+
// tuple with a non-leaf element (a string literal) stays refused.
|
|
407
|
+
{ name: 'flatMap (literal element)', body: `<div>{items().flatMap(x => [x.tag, "x"])}</div>`, needle: '.flatMap(' },
|
|
401
408
|
]
|
|
402
409
|
|
|
403
410
|
for (const { name, body, needle } of cases) {
|
|
@@ -960,6 +967,12 @@ import { fixture as arrayToSortedFixture } from '../../../adapter-tests/fixtures
|
|
|
960
967
|
import { fixture as arrayEntriesFixture } from '../../../adapter-tests/fixtures/methods/array-entries'
|
|
961
968
|
import { fixture as arrayKeysFixture } from '../../../adapter-tests/fixtures/methods/array-keys'
|
|
962
969
|
import { fixture as arrayValuesFixture } from '../../../adapter-tests/fixtures/methods/array-values'
|
|
970
|
+
// #1448 Tier C — .reduce(fn, init) arithmetic-fold catalogue.
|
|
971
|
+
import { fixture as reduceSumFieldFixture } from '../../../adapter-tests/fixtures/methods/reduce-sum-field'
|
|
972
|
+
import { fixture as reduceSumSelfFixture } from '../../../adapter-tests/fixtures/methods/reduce-sum-self'
|
|
973
|
+
import { fixture as reduceConcatFixture } from '../../../adapter-tests/fixtures/methods/reduce-concat'
|
|
974
|
+
import { fixture as reduceProductFixture } from '../../../adapter-tests/fixtures/methods/reduce-product'
|
|
975
|
+
import { fixture as reduceRightConcatFixture } from '../../../adapter-tests/fixtures/methods/reduce-right-concat'
|
|
963
976
|
|
|
964
977
|
describe('MojoAdapter - #1448 Tier A/B fixture-driven lowering pins', () => {
|
|
965
978
|
const cases = [
|
|
@@ -1020,6 +1033,17 @@ describe('MojoAdapter - #1448 Tier A/B fixture-driven lowering pins', () => {
|
|
|
1020
1033
|
{ fixture: arrayKeysFixture, expect: '% for my $k (0..$#{$items})' },
|
|
1021
1034
|
// .values() → standard for loop (same as plain .map())
|
|
1022
1035
|
{ fixture: arrayValuesFixture, expect: '% my $v = $items->[$_i];' },
|
|
1036
|
+
// #1448 Tier C — .reduce(fn, init) arithmetic fold. The structured
|
|
1037
|
+
// ReduceOp lowers to a single `bf->reduce(...)` call with op /
|
|
1038
|
+
// key / type / init / direction in the options hash. Each shape
|
|
1039
|
+
// exercises one arm: field-numeric sum, self-numeric sum,
|
|
1040
|
+
// string-concat fold, the product (`*`) operator, and the
|
|
1041
|
+
// right-to-left `direction` of reduceRight.
|
|
1042
|
+
{ fixture: reduceSumFieldFixture, expect: `bf->reduce($items, { op => '+', key_kind => 'field', key => 'duration', type => 'numeric', init => 0, direction => 'left' })` },
|
|
1043
|
+
{ fixture: reduceSumSelfFixture, expect: `bf->reduce($nums, { op => '+', key_kind => 'self', type => 'numeric', init => 0, direction => 'left' })` },
|
|
1044
|
+
{ fixture: reduceConcatFixture, expect: `bf->reduce($items, { op => '+', key_kind => 'field', key => 'label', type => 'string', init => '', direction => 'left' })` },
|
|
1045
|
+
{ fixture: reduceProductFixture, expect: `bf->reduce($items, { op => '*', key_kind => 'field', key => 'qty', type => 'numeric', init => 1, direction => 'left' })` },
|
|
1046
|
+
{ fixture: reduceRightConcatFixture, expect: `bf->reduce($items, { op => '+', key_kind => 'field', key => 'label', type => 'string', init => '', direction => 'right' })` },
|
|
1023
1047
|
]
|
|
1024
1048
|
|
|
1025
1049
|
for (const { fixture, expect: expectedHelper } of cases) {
|
|
@@ -1041,6 +1065,73 @@ describe('MojoAdapter - #1448 Tier A/B fixture-driven lowering pins', () => {
|
|
|
1041
1065
|
}
|
|
1042
1066
|
})
|
|
1043
1067
|
|
|
1068
|
+
describe('MojoAdapter - #1448 Tier C .flat(depth?)', () => {
|
|
1069
|
+
function emitFlat(expr: string): string {
|
|
1070
|
+
const a = new MojoAdapter()
|
|
1071
|
+
const ir = compileToIR(`
|
|
1072
|
+
function C({ rows }: { rows: number[][] }) {
|
|
1073
|
+
return <div>{${expr}}</div>
|
|
1074
|
+
}
|
|
1075
|
+
export { C }
|
|
1076
|
+
`, a)
|
|
1077
|
+
return a.generate(ir).template ?? ''
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
test('.flat() emits bf->flat with default depth 1', () => {
|
|
1081
|
+
expect(emitFlat('rows.flat()')).toContain('bf->flat($rows, 1)')
|
|
1082
|
+
})
|
|
1083
|
+
|
|
1084
|
+
test('.flat(2) emits the explicit depth', () => {
|
|
1085
|
+
expect(emitFlat('rows.flat(2)')).toContain('bf->flat($rows, 2)')
|
|
1086
|
+
})
|
|
1087
|
+
|
|
1088
|
+
test('.flat(Infinity) emits the -1 full-depth sentinel', () => {
|
|
1089
|
+
expect(emitFlat('rows.flat(Infinity)')).toContain('bf->flat($rows, -1)')
|
|
1090
|
+
})
|
|
1091
|
+
})
|
|
1092
|
+
|
|
1093
|
+
describe('MojoAdapter - #1448 Tier C .flatMap(field projection)', () => {
|
|
1094
|
+
function emitFlatMap(expr: string): string {
|
|
1095
|
+
const a = new MojoAdapter()
|
|
1096
|
+
const ir = compileToIR(`
|
|
1097
|
+
function C({ rows }: { rows: { a: string; b: string; tags: string[] }[] }) {
|
|
1098
|
+
return <div>{${expr}}</div>
|
|
1099
|
+
}
|
|
1100
|
+
export { C }
|
|
1101
|
+
`, a)
|
|
1102
|
+
return a.generate(ir).template ?? ''
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
test('.flatMap(i => i.field) emits bf->flat_map with the raw field key', () => {
|
|
1106
|
+
expect(emitFlatMap('rows.flatMap(i => i.tags).join(" ")')).toContain(`bf->flat_map($rows, 'field', 'tags')`)
|
|
1107
|
+
})
|
|
1108
|
+
|
|
1109
|
+
test('.flatMap(i => i) emits the self projection', () => {
|
|
1110
|
+
expect(emitFlatMap('rows.flatMap(i => i).join(" ")')).toContain(`bf->flat_map($rows, 'self', '')`)
|
|
1111
|
+
})
|
|
1112
|
+
|
|
1113
|
+
test('.flatMap(i => [i.a, i.b]) emits bf->flat_map_tuple with leaf specs', () => {
|
|
1114
|
+
expect(emitFlatMap('rows.flatMap(i => [i.a, i.b]).join(" ")')).toContain(`bf->flat_map_tuple($rows, ['field', 'a'], ['field', 'b'])`)
|
|
1115
|
+
})
|
|
1116
|
+
|
|
1117
|
+
test('tuple self + field leaves', () => {
|
|
1118
|
+
expect(emitFlatMap('rows.flatMap(i => [i, i.a]).join(" ")')).toContain(`bf->flat_map_tuple($rows, ['self', ''], ['field', 'a'])`)
|
|
1119
|
+
})
|
|
1120
|
+
|
|
1121
|
+
test('field-projection flatMap as a loop base lowers (no BF101)', () => {
|
|
1122
|
+
const a = new MojoAdapter()
|
|
1123
|
+
const ir = compileToIR(`'use client'
|
|
1124
|
+
import { createSignal } from '@barefootjs/client'
|
|
1125
|
+
export function C() {
|
|
1126
|
+
const [items] = createSignal<{ tags: string[] }[]>([])
|
|
1127
|
+
return <ul>{items().flatMap(x => x.tags).map(t => <li key={t}>{t}</li>)}</ul>
|
|
1128
|
+
}`, a)
|
|
1129
|
+
const template = a.generate(ir).template ?? ''
|
|
1130
|
+
expect((a.errors ?? []).filter(e => e.code === 'BF101')).toEqual([])
|
|
1131
|
+
expect(template).toContain(`bf->flat_map($items, 'field', 'tags')`)
|
|
1132
|
+
})
|
|
1133
|
+
})
|
|
1134
|
+
|
|
1044
1135
|
// =============================================================================
|
|
1045
1136
|
// #1448 — `/* @client */` escape hatch for STILL-UNSUPPORTED methods
|
|
1046
1137
|
// =============================================================================
|
|
@@ -1099,10 +1190,14 @@ export function C() {
|
|
|
1099
1190
|
// Perl fragment that must NOT survive into the template (the pre-fix
|
|
1100
1191
|
// silent-footgun output for the string rows).
|
|
1101
1192
|
const unsupported: Array<{ name: string; expr: string; badEmit: string }> = [
|
|
1102
|
-
// Tier C array methods.
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1193
|
+
// Tier C array methods. The arithmetic-fold `.reduce(fn, init)`
|
|
1194
|
+
// catalogue now lowers (pinned in the positive reduce-* fixtures);
|
|
1195
|
+
// the no-initial-value form stays refused — JS throws on an empty
|
|
1196
|
+
// array there, which a template can't mirror.
|
|
1197
|
+
{ name: 'reduce (no init)', expr: `items().reduce((a, b) => a + b.n)`, badEmit: '->{reduce}' },
|
|
1198
|
+
// Self / field / field-tuple `.flatMap` now lowers (#1448 Tier C); a
|
|
1199
|
+
// tuple with a non-leaf element (here a string literal) stays refused.
|
|
1200
|
+
{ name: 'flatMap (literal element)', expr: `items().flatMap(i => [i.name, "x"])`, badEmit: '->{flatMap}' },
|
|
1106
1201
|
// Lowered methods whose MEANINGFUL extra argument isn't lowered yet
|
|
1107
1202
|
// (#1448): the `fromIndex` of `.includes`/`.indexOf`/`.lastIndexOf`
|
|
1108
1203
|
// and the variadic `.concat`. The parser refuses these (silently
|
|
@@ -56,7 +56,7 @@ import { isAriaBooleanAttr, isBooleanResultExpr } from './boolean-result'
|
|
|
56
56
|
* the `IRNodeEmitter` interface.
|
|
57
57
|
*/
|
|
58
58
|
type MojoRenderCtx = Record<string, never>
|
|
59
|
-
import type { ParsedExpr, ParsedStatement, SortComparator, TemplatePart } from '@barefootjs/jsx'
|
|
59
|
+
import type { ParsedExpr, ParsedStatement, SortComparator, ReduceOp, FlatDepth, FlatMapOp, TemplatePart } from '@barefootjs/jsx'
|
|
60
60
|
import { BF_SLOT, BF_COND } from '@barefootjs/shared'
|
|
61
61
|
|
|
62
62
|
interface PrimitiveSpec {
|
|
@@ -1533,6 +1533,64 @@ function renderSortMethod(recv: string, c: SortComparator): string {
|
|
|
1533
1533
|
return `bf->sort(${recv}, { keys => [${keyHashes.join(', ')}] })`
|
|
1534
1534
|
}
|
|
1535
1535
|
|
|
1536
|
+
/**
|
|
1537
|
+
* Render a `.reduce(fn, init)` arithmetic fold (#1448 Tier C) as a
|
|
1538
|
+
* `bf->reduce(...)` call. The structured `ReduceOp` maps to the Perl
|
|
1539
|
+
* helper's options hash:
|
|
1540
|
+
*
|
|
1541
|
+
* bf->reduce($recv, { op => '+', key_kind => 'field', key => 'duration',
|
|
1542
|
+
* type => 'numeric', init => 0 })
|
|
1543
|
+
*
|
|
1544
|
+
* A numeric init passes through as a bare Perl number (`0`, `-1`); a
|
|
1545
|
+
* string init (concat fold) is re-quoted from its literal contents.
|
|
1546
|
+
*/
|
|
1547
|
+
function renderReduceMethod(recv: string, op: ReduceOp, direction: 'left' | 'right'): string {
|
|
1548
|
+
const keyEntry =
|
|
1549
|
+
op.key.kind === 'self'
|
|
1550
|
+
? `key_kind => 'self'`
|
|
1551
|
+
: `key_kind => 'field', key => '${op.key.field}'`
|
|
1552
|
+
// `op.init` is the decoded seed value. A numeric seed is already a
|
|
1553
|
+
// canonical decimal literal Perl reads directly; a concat seed is the
|
|
1554
|
+
// string contents, embedded in a single-quoted Perl literal. The `'`
|
|
1555
|
+
// escape is REQUIRED: a seed decoded from a double-quoted JS literal
|
|
1556
|
+
// (e.g. `"a'b"`) is escape-free yet contains an apostrophe. A literal
|
|
1557
|
+
// backslash can't occur (it would need a `\\` escape, which the parser
|
|
1558
|
+
// refuses), but escaping it too keeps this self-contained.
|
|
1559
|
+
const init =
|
|
1560
|
+
op.type === 'string'
|
|
1561
|
+
? `'${op.init.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`
|
|
1562
|
+
: op.init
|
|
1563
|
+
// `direction` is "left" (reduce) or "right" (reduceRight); the Perl
|
|
1564
|
+
// helper reverses the list for "right". Only observable for concat.
|
|
1565
|
+
return `bf->reduce(${recv}, { op => '${op.op}', ${keyEntry}, type => '${op.type}', init => ${init}, direction => '${direction}' })`
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
// `.flat(depth?)` → `bf->flat($recv, $depth)`. The `Infinity` form lowers
|
|
1569
|
+
// to the `-1` sentinel (flatten fully); a finite depth flattens that many
|
|
1570
|
+
// levels (`0` = shallow copy). See `sub flat` in BarefootJS.pm. (#1448)
|
|
1571
|
+
function renderFlatMethod(recv: string, depth: FlatDepth): string {
|
|
1572
|
+
const d = depth === 'infinity' ? -1 : depth
|
|
1573
|
+
return `bf->flat(${recv}, ${d})`
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
// `.flatMap(i => i)` / `.flatMap(i => i.field)` → `bf->flat_map($recv,
|
|
1577
|
+
// 'self'|'field', 'field')`, and the array-literal tuple form
|
|
1578
|
+
// `i => [i.a, i.b]` → `bf->flat_map_tuple($recv, ['field','a'], ...)`
|
|
1579
|
+
// (one arrayref per leaf). The field key is the raw JS prop name (Perl
|
|
1580
|
+
// hashes are keyed by it), mirroring `bf->reduce`. See `sub flat_map` /
|
|
1581
|
+
// `sub flat_map_tuple` in BarefootJS.pm.
|
|
1582
|
+
function renderFlatMapMethod(recv: string, op: FlatMapOp): string {
|
|
1583
|
+
const proj = op.projection
|
|
1584
|
+
if (proj.kind === 'tuple') {
|
|
1585
|
+
const specs = proj.elements
|
|
1586
|
+
.map(l => (l.kind === 'self' ? `['self', '']` : `['field', '${l.field}']`))
|
|
1587
|
+
.join(', ')
|
|
1588
|
+
return `bf->flat_map_tuple(${recv}, ${specs})`
|
|
1589
|
+
}
|
|
1590
|
+
if (proj.kind === 'self') return `bf->flat_map(${recv}, 'self', '')`
|
|
1591
|
+
return `bf->flat_map(${recv}, 'field', '${proj.field}')`
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1536
1594
|
/** True when `type` is the `string` primitive. */
|
|
1537
1595
|
function isStringTypeInfo(type: TypeInfo | undefined): boolean {
|
|
1538
1596
|
return type?.kind === 'primitive' && type.primitive === 'string'
|
|
@@ -1715,6 +1773,18 @@ class MojoFilterEmitter implements ParsedExprEmitter {
|
|
|
1715
1773
|
return renderSortMethod(emit(object), comparator)
|
|
1716
1774
|
}
|
|
1717
1775
|
|
|
1776
|
+
reduceMethod(method: 'reduce' | 'reduceRight', object: ParsedExpr, reduceOp: ReduceOp, emit: (e: ParsedExpr) => string): string {
|
|
1777
|
+
return renderReduceMethod(emit(object), reduceOp, method === 'reduceRight' ? 'right' : 'left')
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
flatMethod(object: ParsedExpr, depth: FlatDepth, emit: (e: ParsedExpr) => string): string {
|
|
1781
|
+
return renderFlatMethod(emit(object), depth)
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
flatMapMethod(object: ParsedExpr, op: FlatMapOp, emit: (e: ParsedExpr) => string): string {
|
|
1785
|
+
return renderFlatMapMethod(emit(object), op)
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1718
1788
|
conditional(_test: ParsedExpr, _consequent: ParsedExpr, _alternate: ParsedExpr): string {
|
|
1719
1789
|
return '1'
|
|
1720
1790
|
}
|
|
@@ -1896,6 +1966,18 @@ class MojoTopLevelEmitter implements ParsedExprEmitter {
|
|
|
1896
1966
|
return renderSortMethod(emit(object), comparator)
|
|
1897
1967
|
}
|
|
1898
1968
|
|
|
1969
|
+
reduceMethod(method: 'reduce' | 'reduceRight', object: ParsedExpr, reduceOp: ReduceOp, emit: (e: ParsedExpr) => string): string {
|
|
1970
|
+
return renderReduceMethod(emit(object), reduceOp, method === 'reduceRight' ? 'right' : 'left')
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
flatMethod(object: ParsedExpr, depth: FlatDepth, emit: (e: ParsedExpr) => string): string {
|
|
1974
|
+
return renderFlatMethod(emit(object), depth)
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
flatMapMethod(object: ParsedExpr, op: FlatMapOp, emit: (e: ParsedExpr) => string): string {
|
|
1978
|
+
return renderFlatMapMethod(emit(object), op)
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1899
1981
|
conditional(
|
|
1900
1982
|
test: ParsedExpr,
|
|
1901
1983
|
consequent: ParsedExpr,
|