@barefootjs/jsx 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +620 -26
- package/dist/ir-to-client-js/control-flow/plan/branch-loop.d.ts +6 -0
- package/dist/ir-to-client-js/control-flow/plan/branch-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts +2 -1
- package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-insert.d.ts +7 -0
- package/dist/ir-to-client-js/control-flow/plan/build-insert.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts +107 -0
- package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts.map +1 -0
- package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts +9 -1
- package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts +203 -0
- package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts.map +1 -0
- package/dist/ir-to-client-js/control-flow/plan/loop.d.ts +10 -0
- package/dist/ir-to-client-js/control-flow/plan/loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/branch-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts +98 -0
- package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts.map +1 -0
- package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts +5 -0
- package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow.d.ts.map +1 -1
- package/dist/ir-to-client-js/imports.d.ts +2 -2
- package/dist/ir-to-client-js/imports.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +162 -36
- package/src/__tests__/client-js-generation.test.ts +4 -1
- package/src/__tests__/composite-branch-loop.test.ts +12 -3
- package/src/__tests__/conditional-mapArray-key.test.ts +7 -1
- package/src/__tests__/create-selector.test.ts +21 -7
- package/src/__tests__/lazy-row-eligibility.test.ts +692 -0
- package/src/__tests__/loop-branch-bare-expression-reactive-text.test.ts +98 -0
- package/src/__tests__/loop-fallback-wrap.test.ts +31 -12
- package/src/__tests__/loop-hoisted-template.test.ts +10 -6
- package/src/__tests__/static-loop-csr-materialize.test.ts +6 -1
- package/src/ir-to-client-js/collect-elements.ts +48 -13
- package/src/ir-to-client-js/control-flow/plan/branch-loop.ts +6 -0
- package/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts +35 -12
- package/src/ir-to-client-js/control-flow/plan/build-insert.ts +9 -2
- package/src/ir-to-client-js/control-flow/plan/build-lazy-row.ts +305 -0
- package/src/ir-to-client-js/control-flow/plan/build-loop.ts +44 -12
- package/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts +440 -0
- package/src/ir-to-client-js/control-flow/plan/loop.ts +10 -0
- package/src/ir-to-client-js/control-flow/stringify/branch-loop.ts +22 -0
- package/src/ir-to-client-js/control-flow/stringify/lazy-row.ts +478 -0
- package/src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts +6 -1
- package/src/ir-to-client-js/control-flow/stringify/loop.ts +23 -0
- package/src/ir-to-client-js/control-flow.ts +7 -2
- package/src/ir-to-client-js/imports.ts +8 -2
- package/src/jsx-to-ir.ts +18 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Import detection and DOM import management.
|
|
3
3
|
*/
|
|
4
4
|
import type { ComponentIR } from '../types.ts';
|
|
5
|
-
export declare const RUNTIME_IMPORT_CANDIDATES: readonly ['createSignal', 'createMemo', 'createEffect', 'onCleanup', 'onMount', 'hydrate', 'insert', 'getLoopChildren', 'getLoopNodes', 'mapArray', 'mapArrayAnchored', 'patchLeaf', 'createDisposableEffect', 'createComponent', 'renderChild', 'registerComponent', 'registerTemplate', 'initChild', 'upsertChild', 'createPortal', 'provideContext', 'createContext', 'useContext', 'forwardProps', 'applyRestAttrs', 'splitProps', 'spreadAttrs', 'styleToCss', 'escapeAttr', 'escapeText', 'escapeTextOrNode', 'qsa', 'qsaItem', 'qsaChildScope', 'qsaChildScopes', 'upsertChildItem', '__slot', '__bfSlot', '__bfText', 'claimSlots', 'lazySlots', 'beginTurn', 'endTurn', 'date', 'formatDate'];
|
|
5
|
+
export declare const RUNTIME_IMPORT_CANDIDATES: readonly ['createSignal', 'createMemo', 'createEffect', 'onCleanup', 'onMount', 'hydrate', 'insert', 'getLoopChildren', 'getLoopNodes', 'mapArray', 'mapArrayAnchored', 'mapArrayLazy', 'patchLeaf', 'createDisposableEffect', 'createComponent', 'renderChild', 'registerComponent', 'registerTemplate', 'initChild', 'upsertChild', 'createPortal', 'provideContext', 'createContext', 'useContext', 'forwardProps', 'applyRestAttrs', 'splitProps', 'spreadAttrs', 'styleToCss', 'escapeAttr', 'escapeText', 'escapeTextOrNode', 'qsa', 'qsaItem', 'qsaChildScope', 'qsaChildScopes', 'upsertChildItem', '__slot', '__bfSlot', '__bfText', 'claimSlots', 'lazySlots', 'lazyClaimSlots', 'textOrNode', 'beginTurn', 'endTurn', 'date', 'formatDate'];
|
|
6
6
|
/** @deprecated Use RUNTIME_IMPORT_CANDIDATES */
|
|
7
|
-
export declare const DOM_IMPORT_CANDIDATES: readonly ["createSignal", "createMemo", "createEffect", "onCleanup", "onMount", "hydrate", "insert", "getLoopChildren", "getLoopNodes", "mapArray", "mapArrayAnchored", "patchLeaf", "createDisposableEffect", "createComponent", "renderChild", "registerComponent", "registerTemplate", "initChild", "upsertChild", "createPortal", "provideContext", "createContext", "useContext", "forwardProps", "applyRestAttrs", "splitProps", "spreadAttrs", "styleToCss", "escapeAttr", "escapeText", "escapeTextOrNode", "qsa", "qsaItem", "qsaChildScope", "qsaChildScopes", "upsertChildItem", "__slot", "__bfSlot", "__bfText", "claimSlots", "lazySlots", "beginTurn", "endTurn", "date", "formatDate"];
|
|
7
|
+
export declare const DOM_IMPORT_CANDIDATES: readonly ["createSignal", "createMemo", "createEffect", "onCleanup", "onMount", "hydrate", "insert", "getLoopChildren", "getLoopNodes", "mapArray", "mapArrayAnchored", "mapArrayLazy", "patchLeaf", "createDisposableEffect", "createComponent", "renderChild", "registerComponent", "registerTemplate", "initChild", "upsertChild", "createPortal", "provideContext", "createContext", "useContext", "forwardProps", "applyRestAttrs", "splitProps", "spreadAttrs", "styleToCss", "escapeAttr", "escapeText", "escapeTextOrNode", "qsa", "qsaItem", "qsaChildScope", "qsaChildScopes", "upsertChildItem", "__slot", "__bfSlot", "__bfText", "claimSlots", "lazySlots", "lazyClaimSlots", "textOrNode", "beginTurn", "endTurn", "date", "formatDate"];
|
|
8
8
|
export declare const RUNTIME_MODULE = "@barefootjs/client/runtime";
|
|
9
9
|
export declare const IMPORT_PLACEHOLDER = "/* __BAREFOOTJS_DOM_IMPORTS__ */";
|
|
10
10
|
export declare const MODULE_CONSTANTS_PLACEHOLDER = "/* __MODULE_LEVEL_CONSTANTS__ */";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/imports.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAU,MAAM,aAAa,CAAA;AAItD,eAAO,MAAM,yBAAyB,YACpC,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EACpE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,WAAW,EAAE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/imports.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAU,MAAM,aAAa,CAAA;AAItD,eAAO,MAAM,yBAAyB,YACpC,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EACpE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,cAAc,EAAE,WAAW,EAAE,wBAAwB,EAC7I,iBAAiB,EAAE,aAAa,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EACrG,cAAc,EACd,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAC/C,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAC3H,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAUxG,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAEzD,WAAW,EAAE,SAAS,EAItB,MAAM,EAIN,YAAY,CACJ,CAAA;AAEV,gDAAgD;AAChD,eAAO,MAAM,qBAAqB,wtBAA4B,CAAA;AAE9D,eAAO,MAAM,cAAc,+BAA+B,CAAA;AAE1D,eAAO,MAAM,kBAAkB,qCAAqC,CAAA;AACpE,eAAO,MAAM,4BAA4B,qCAAqC,CAAA;AAE9E;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAqB3D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,EAAE,CAiB/D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmCvH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/jsx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "JSX compiler for BarefootJS - transforms JSX to server HTML + client JS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"directory": "packages/jsx"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@barefootjs/shared": "0.
|
|
56
|
+
"@barefootjs/shared": "0.28.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@barefootjs/client": ">=0.2.0",
|
|
@@ -4380,7 +4380,7 @@ export function Example(_p, __bfKey) { return createComponent('Example', _p, __b
|
|
|
4380
4380
|
`;
|
|
4381
4381
|
|
|
4382
4382
|
exports[`docs/core/adapters/hono-adapter.md doc-examples L190 — (no label) 1`] = `
|
|
4383
|
-
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots,
|
|
4383
|
+
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots, mapArrayLazy, textOrNode } from '@barefootjs/client/runtime'
|
|
4384
4384
|
|
|
4385
4385
|
export function initTodoItem(__scope, _p = {}) {
|
|
4386
4386
|
if (!__scope) return
|
|
@@ -4431,11 +4431,32 @@ export function initExample(__scope, _p = {}) {
|
|
|
4431
4431
|
|
|
4432
4432
|
const __tpl_l0 = document.createElement('template')
|
|
4433
4433
|
__tpl_l0.innerHTML = \`<li data-key=""><!--bf:s0--><!--/--></li>\`
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
return
|
|
4434
|
+
const __lzp_l0 = [[0]]
|
|
4435
|
+
const __lzs_l0 = [{ id: 's0', kind: 'text', path: [] }]
|
|
4436
|
+
const __lzsc_l0 = [{ id: 's0', kind: 'text', path: __lzp_l0[0] }]
|
|
4437
|
+
const __lzc_l0 = (__e) => {
|
|
4438
|
+
return [null]
|
|
4439
|
+
}
|
|
4440
|
+
mapArrayLazy(() => items(), _s1, (item) => String(item), {
|
|
4441
|
+
createRow: (__e, __idx) => {
|
|
4442
|
+
const item = () => __e.item
|
|
4443
|
+
const __el = __tpl_l0.content.firstElementChild.cloneNode(true)
|
|
4444
|
+
const __r = __e.refs = [lazySlots(__el, __lzsc_l0)]
|
|
4445
|
+
const __l = __e.last = []
|
|
4446
|
+
{ const __x = item()
|
|
4447
|
+
__r[0]('s0', textOrNode(__x))
|
|
4448
|
+
__l[0] = __x }
|
|
4449
|
+
return __el
|
|
4450
|
+
},
|
|
4451
|
+
applyItem: (__e) => {
|
|
4452
|
+
const item = () => __e.item
|
|
4453
|
+
const __r = __e.refs ?? (__e.refs = __lzc_l0(__e))
|
|
4454
|
+
const __l = __e.last ?? (__e.last = [])
|
|
4455
|
+
const __d = __r[0] ?? (__r[0] = lazySlots(__e.primaryEl, __lzs_l0))
|
|
4456
|
+
{ const __x = item()
|
|
4457
|
+
if (!(0 in __l) || !Object.is(__l[0], __x)) __d('s0', textOrNode(__x))
|
|
4458
|
+
__l[0] = __x }
|
|
4459
|
+
},
|
|
4439
4460
|
}, 'l0')
|
|
4440
4461
|
|
|
4441
4462
|
}
|
|
@@ -4494,7 +4515,7 @@ export function Counter(_p, __bfKey) { return createComponent('Counter', _p, __b
|
|
|
4494
4515
|
`;
|
|
4495
4516
|
|
|
4496
4517
|
exports[`docs/core/adapters/go-template-adapter.md doc-examples L168 — (no label) 1`] = `
|
|
4497
|
-
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots,
|
|
4518
|
+
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots, mapArrayLazy, textOrNode } from '@barefootjs/client/runtime'
|
|
4498
4519
|
|
|
4499
4520
|
export function initTodoItem(__scope, _p = {}) {
|
|
4500
4521
|
if (!__scope) return
|
|
@@ -4545,11 +4566,32 @@ export function initExample(__scope, _p = {}) {
|
|
|
4545
4566
|
|
|
4546
4567
|
const __tpl_l0 = document.createElement('template')
|
|
4547
4568
|
__tpl_l0.innerHTML = \`<li data-key=""><!--bf:s0--><!--/--></li>\`
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
return
|
|
4569
|
+
const __lzp_l0 = [[0]]
|
|
4570
|
+
const __lzs_l0 = [{ id: 's0', kind: 'text', path: [] }]
|
|
4571
|
+
const __lzsc_l0 = [{ id: 's0', kind: 'text', path: __lzp_l0[0] }]
|
|
4572
|
+
const __lzc_l0 = (__e) => {
|
|
4573
|
+
return [null]
|
|
4574
|
+
}
|
|
4575
|
+
mapArrayLazy(() => items(), _s1, (item) => String(item), {
|
|
4576
|
+
createRow: (__e, __idx) => {
|
|
4577
|
+
const item = () => __e.item
|
|
4578
|
+
const __el = __tpl_l0.content.firstElementChild.cloneNode(true)
|
|
4579
|
+
const __r = __e.refs = [lazySlots(__el, __lzsc_l0)]
|
|
4580
|
+
const __l = __e.last = []
|
|
4581
|
+
{ const __x = item()
|
|
4582
|
+
__r[0]('s0', textOrNode(__x))
|
|
4583
|
+
__l[0] = __x }
|
|
4584
|
+
return __el
|
|
4585
|
+
},
|
|
4586
|
+
applyItem: (__e) => {
|
|
4587
|
+
const item = () => __e.item
|
|
4588
|
+
const __r = __e.refs ?? (__e.refs = __lzc_l0(__e))
|
|
4589
|
+
const __l = __e.last ?? (__e.last = [])
|
|
4590
|
+
const __d = __r[0] ?? (__r[0] = lazySlots(__e.primaryEl, __lzs_l0))
|
|
4591
|
+
{ const __x = item()
|
|
4592
|
+
if (!(0 in __l) || !Object.is(__l[0], __x)) __d('s0', textOrNode(__x))
|
|
4593
|
+
__l[0] = __x }
|
|
4594
|
+
},
|
|
4553
4595
|
}, 'l0')
|
|
4554
4596
|
|
|
4555
4597
|
}
|
|
@@ -4559,7 +4601,7 @@ export function Example(_p, __bfKey) { return createComponent('Example', _p, __b
|
|
|
4559
4601
|
`;
|
|
4560
4602
|
|
|
4561
4603
|
exports[`docs/core/adapters/go-template-adapter.md doc-examples L180 — (no label) 1`] = `
|
|
4562
|
-
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots,
|
|
4604
|
+
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots, mapArrayLazy, textOrNode } from '@barefootjs/client/runtime'
|
|
4563
4605
|
|
|
4564
4606
|
export function initTodoItem(__scope, _p = {}) {
|
|
4565
4607
|
if (!__scope) return
|
|
@@ -4610,11 +4652,32 @@ export function initExample(__scope, _p = {}) {
|
|
|
4610
4652
|
|
|
4611
4653
|
const __tpl_l0 = document.createElement('template')
|
|
4612
4654
|
__tpl_l0.innerHTML = \`<li data-key=""><!--bf:s0--><!--/--></li>\`
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
return
|
|
4655
|
+
const __lzp_l0 = [[0]]
|
|
4656
|
+
const __lzs_l0 = [{ id: 's0', kind: 'text', path: [] }]
|
|
4657
|
+
const __lzsc_l0 = [{ id: 's0', kind: 'text', path: __lzp_l0[0] }]
|
|
4658
|
+
const __lzc_l0 = (__e) => {
|
|
4659
|
+
return [null]
|
|
4660
|
+
}
|
|
4661
|
+
mapArrayLazy(() => items().filter(item => item.active), _s1, (item) => String(item.id), {
|
|
4662
|
+
createRow: (__e, __idx) => {
|
|
4663
|
+
const item = () => __e.item
|
|
4664
|
+
const __el = __tpl_l0.content.firstElementChild.cloneNode(true)
|
|
4665
|
+
const __r = __e.refs = [lazySlots(__el, __lzsc_l0)]
|
|
4666
|
+
const __l = __e.last = []
|
|
4667
|
+
{ const __x = item().name
|
|
4668
|
+
__r[0]('s0', textOrNode(__x))
|
|
4669
|
+
__l[0] = __x }
|
|
4670
|
+
return __el
|
|
4671
|
+
},
|
|
4672
|
+
applyItem: (__e) => {
|
|
4673
|
+
const item = () => __e.item
|
|
4674
|
+
const __r = __e.refs ?? (__e.refs = __lzc_l0(__e))
|
|
4675
|
+
const __l = __e.last ?? (__e.last = [])
|
|
4676
|
+
const __d = __r[0] ?? (__r[0] = lazySlots(__e.primaryEl, __lzs_l0))
|
|
4677
|
+
{ const __x = item().name
|
|
4678
|
+
if (!(0 in __l) || !Object.is(__l[0], __x)) __d('s0', textOrNode(__x))
|
|
4679
|
+
__l[0] = __x }
|
|
4680
|
+
},
|
|
4618
4681
|
}, 'l0')
|
|
4619
4682
|
|
|
4620
4683
|
}
|
|
@@ -5032,7 +5095,7 @@ export function StatementExample(_p, __bfKey) { return createComponent('Statemen
|
|
|
5032
5095
|
`;
|
|
5033
5096
|
|
|
5034
5097
|
exports[`docs/core/advanced/compiler-internals.md doc-examples L126 — (no label) 1`] = `
|
|
5035
|
-
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots,
|
|
5098
|
+
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots, mapArrayLazy, textOrNode } from '@barefootjs/client/runtime'
|
|
5036
5099
|
|
|
5037
5100
|
export function initTodoItem(__scope, _p = {}) {
|
|
5038
5101
|
if (!__scope) return
|
|
@@ -5083,11 +5146,32 @@ export function initExample(__scope, _p = {}) {
|
|
|
5083
5146
|
|
|
5084
5147
|
const __tpl_l0 = document.createElement('template')
|
|
5085
5148
|
__tpl_l0.innerHTML = \`<li data-key=""><!--bf:s0--><!--/--></li>\`
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
return
|
|
5149
|
+
const __lzp_l0 = [[0]]
|
|
5150
|
+
const __lzs_l0 = [{ id: 's0', kind: 'text', path: [] }]
|
|
5151
|
+
const __lzsc_l0 = [{ id: 's0', kind: 'text', path: __lzp_l0[0] }]
|
|
5152
|
+
const __lzc_l0 = (__e) => {
|
|
5153
|
+
return [null]
|
|
5154
|
+
}
|
|
5155
|
+
mapArrayLazy(() => todos().filter(t => !t.done).toSorted((a, b) => a.date - b.date), _s1, (t) => String(t.id), {
|
|
5156
|
+
createRow: (__e, __idx) => {
|
|
5157
|
+
const t = () => __e.item
|
|
5158
|
+
const __el = __tpl_l0.content.firstElementChild.cloneNode(true)
|
|
5159
|
+
const __r = __e.refs = [lazySlots(__el, __lzsc_l0)]
|
|
5160
|
+
const __l = __e.last = []
|
|
5161
|
+
{ const __x = t().name
|
|
5162
|
+
__r[0]('s0', textOrNode(__x))
|
|
5163
|
+
__l[0] = __x }
|
|
5164
|
+
return __el
|
|
5165
|
+
},
|
|
5166
|
+
applyItem: (__e) => {
|
|
5167
|
+
const t = () => __e.item
|
|
5168
|
+
const __r = __e.refs ?? (__e.refs = __lzc_l0(__e))
|
|
5169
|
+
const __l = __e.last ?? (__e.last = [])
|
|
5170
|
+
const __d = __r[0] ?? (__r[0] = lazySlots(__e.primaryEl, __lzs_l0))
|
|
5171
|
+
{ const __x = t().name
|
|
5172
|
+
if (!(0 in __l) || !Object.is(__l[0], __x)) __d('s0', textOrNode(__x))
|
|
5173
|
+
__l[0] = __x }
|
|
5174
|
+
},
|
|
5091
5175
|
}, 'l0')
|
|
5092
5176
|
|
|
5093
5177
|
}
|
|
@@ -5159,7 +5243,7 @@ export function StatementExample(_p, __bfKey) { return createComponent('Statemen
|
|
|
5159
5243
|
`;
|
|
5160
5244
|
|
|
5161
5245
|
exports[`docs/core/advanced/performance.md doc-examples L67 — ✅ Stable key — DOM nodes reused when list changes 1`] = `
|
|
5162
|
-
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots,
|
|
5246
|
+
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots, mapArrayLazy, textOrNode } from '@barefootjs/client/runtime'
|
|
5163
5247
|
|
|
5164
5248
|
export function initTodoItem(__scope, _p = {}) {
|
|
5165
5249
|
if (!__scope) return
|
|
@@ -5210,11 +5294,32 @@ export function initExample(__scope, _p = {}) {
|
|
|
5210
5294
|
|
|
5211
5295
|
const __tpl_l0 = document.createElement('template')
|
|
5212
5296
|
__tpl_l0.innerHTML = \`<li data-key=""><!--bf:s0--><!--/--></li>\`
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
return
|
|
5297
|
+
const __lzp_l0 = [[0]]
|
|
5298
|
+
const __lzs_l0 = [{ id: 's0', kind: 'text', path: [] }]
|
|
5299
|
+
const __lzsc_l0 = [{ id: 's0', kind: 'text', path: __lzp_l0[0] }]
|
|
5300
|
+
const __lzc_l0 = (__e) => {
|
|
5301
|
+
return [null]
|
|
5302
|
+
}
|
|
5303
|
+
mapArrayLazy(() => items(), _s1, (item) => String(item.id), {
|
|
5304
|
+
createRow: (__e, __idx) => {
|
|
5305
|
+
const item = () => __e.item
|
|
5306
|
+
const __el = __tpl_l0.content.firstElementChild.cloneNode(true)
|
|
5307
|
+
const __r = __e.refs = [lazySlots(__el, __lzsc_l0)]
|
|
5308
|
+
const __l = __e.last = []
|
|
5309
|
+
{ const __x = item().name
|
|
5310
|
+
__r[0]('s0', textOrNode(__x))
|
|
5311
|
+
__l[0] = __x }
|
|
5312
|
+
return __el
|
|
5313
|
+
},
|
|
5314
|
+
applyItem: (__e) => {
|
|
5315
|
+
const item = () => __e.item
|
|
5316
|
+
const __r = __e.refs ?? (__e.refs = __lzc_l0(__e))
|
|
5317
|
+
const __l = __e.last ?? (__e.last = [])
|
|
5318
|
+
const __d = __r[0] ?? (__r[0] = lazySlots(__e.primaryEl, __lzs_l0))
|
|
5319
|
+
{ const __x = item().name
|
|
5320
|
+
if (!(0 in __l) || !Object.is(__l[0], __x)) __d('s0', textOrNode(__x))
|
|
5321
|
+
__l[0] = __x }
|
|
5322
|
+
},
|
|
5218
5323
|
}, 'l0')
|
|
5219
5324
|
|
|
5220
5325
|
}
|
|
@@ -5224,7 +5329,7 @@ export function Example(_p, __bfKey) { return createComponent('Example', _p, __b
|
|
|
5224
5329
|
`;
|
|
5225
5330
|
|
|
5226
5331
|
exports[`docs/core/advanced/performance.md doc-examples L70 — ❌ Index key — DOM nodes recreated on reorder 1`] = `
|
|
5227
|
-
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots,
|
|
5332
|
+
"import { $, createComponent, createEffect, createSignal, escapeAttr, escapeText, escapeTextOrNode, hydrate, lazySlots, mapArrayLazy, textOrNode } from '@barefootjs/client/runtime'
|
|
5228
5333
|
|
|
5229
5334
|
export function initTodoItem(__scope, _p = {}) {
|
|
5230
5335
|
if (!__scope) return
|
|
@@ -5275,11 +5380,32 @@ export function initExample(__scope, _p = {}) {
|
|
|
5275
5380
|
|
|
5276
5381
|
const __tpl_l0 = document.createElement('template')
|
|
5277
5382
|
__tpl_l0.innerHTML = \`<li data-key=""><!--bf:s0--><!--/--></li>\`
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
return
|
|
5383
|
+
const __lzp_l0 = [[0]]
|
|
5384
|
+
const __lzs_l0 = [{ id: 's0', kind: 'text', path: [] }]
|
|
5385
|
+
const __lzsc_l0 = [{ id: 's0', kind: 'text', path: __lzp_l0[0] }]
|
|
5386
|
+
const __lzc_l0 = (__e) => {
|
|
5387
|
+
return [null]
|
|
5388
|
+
}
|
|
5389
|
+
mapArrayLazy(() => items(), _s1, (item, i) => String(i), {
|
|
5390
|
+
createRow: (__e, i) => {
|
|
5391
|
+
const item = () => __e.item
|
|
5392
|
+
const __el = __tpl_l0.content.firstElementChild.cloneNode(true)
|
|
5393
|
+
const __r = __e.refs = [lazySlots(__el, __lzsc_l0)]
|
|
5394
|
+
const __l = __e.last = []
|
|
5395
|
+
{ const __x = item().name
|
|
5396
|
+
__r[0]('s0', textOrNode(__x))
|
|
5397
|
+
__l[0] = __x }
|
|
5398
|
+
return __el
|
|
5399
|
+
},
|
|
5400
|
+
applyItem: (__e) => {
|
|
5401
|
+
const item = () => __e.item
|
|
5402
|
+
const __r = __e.refs ?? (__e.refs = __lzc_l0(__e))
|
|
5403
|
+
const __l = __e.last ?? (__e.last = [])
|
|
5404
|
+
const __d = __r[0] ?? (__r[0] = lazySlots(__e.primaryEl, __lzs_l0))
|
|
5405
|
+
{ const __x = item().name
|
|
5406
|
+
if (!(0 in __l) || !Object.is(__l[0], __x)) __d('s0', textOrNode(__x))
|
|
5407
|
+
__l[0] = __x }
|
|
5408
|
+
},
|
|
5283
5409
|
}, 'l0')
|
|
5284
5410
|
|
|
5285
5411
|
}
|
|
@@ -2638,7 +2638,10 @@ describe('Client JS generation', () => {
|
|
|
2638
2638
|
const js = result.files.find(f => f.type === 'clientJs')!.content
|
|
2639
2639
|
// The branch arm's mapArray call must live inside a
|
|
2640
2640
|
// createDisposableEffect that is pushed into __disposers.
|
|
2641
|
-
|
|
2641
|
+
// `mapArray(` or `mapArrayLazy(` — a lazy-row-eligible branch loop
|
|
2642
|
+
// (spec/slot-unification.md §9.4) uses the latter and has exactly the
|
|
2643
|
+
// same disposal obligation.
|
|
2644
|
+
expect(js).toMatch(/__disposers\.push\(createDisposableEffect\(\(\)\s*=>\s*\{[\s\S]*?mapArray(Lazy)?\(/)
|
|
2642
2645
|
})
|
|
2643
2646
|
|
|
2644
2647
|
test('nested conditional inside a conditional branch is wrapped in createDisposableEffect', () => {
|
|
@@ -53,7 +53,10 @@ describe('composite loops inside conditional branches (#724)', () => {
|
|
|
53
53
|
const js = clientJs!.content
|
|
54
54
|
|
|
55
55
|
// Should use mapArray inside the branch's bindEvents
|
|
56
|
-
|
|
56
|
+
// `mapArray(` or `mapArrayLazy(` — a lazy-row-eligible branch loop
|
|
57
|
+
// (spec/slot-unification.md §9.4) uses the latter; either satisfies
|
|
58
|
+
// "keyed reconciliation, not a composite/component shape".
|
|
59
|
+
expect(js).toMatch(/\bmapArray(Lazy)?\(/)
|
|
57
60
|
|
|
58
61
|
// After O-1's mode-collapse PR, child component init goes through the
|
|
59
62
|
// runtime `upsertChild` helper instead of an emit-side
|
|
@@ -96,7 +99,10 @@ describe('composite loops inside conditional branches (#724)', () => {
|
|
|
96
99
|
const js = clientJs!.content
|
|
97
100
|
|
|
98
101
|
// Should use mapArray for per-item reactivity
|
|
99
|
-
|
|
102
|
+
// `mapArray(` or `mapArrayLazy(` — a lazy-row-eligible branch loop
|
|
103
|
+
// (spec/slot-unification.md §9.4) uses the latter; either satisfies
|
|
104
|
+
// "keyed reconciliation, not a composite/component shape".
|
|
105
|
+
expect(js).toMatch(/\bmapArray(Lazy)?\(/)
|
|
100
106
|
|
|
101
107
|
// Should NOT use createComponent inside the init body (no child
|
|
102
108
|
// components in this fixture). The CLI also emits a callable shim
|
|
@@ -147,7 +153,10 @@ describe('composite loops inside conditional branches (#724)', () => {
|
|
|
147
153
|
const js = clientJs!.content
|
|
148
154
|
|
|
149
155
|
// Should use mapArray for the loop
|
|
150
|
-
|
|
156
|
+
// `mapArray(` or `mapArrayLazy(` — a lazy-row-eligible branch loop
|
|
157
|
+
// (spec/slot-unification.md §9.4) uses the latter; either satisfies
|
|
158
|
+
// "keyed reconciliation, not a composite/component shape".
|
|
159
|
+
expect(js).toMatch(/\bmapArray(Lazy)?\(/)
|
|
151
160
|
|
|
152
161
|
// Should have event delegation (addEventListener + closest pattern)
|
|
153
162
|
expect(js).toContain(".addEventListener('click', (__bfEvt) => {")
|
|
@@ -29,11 +29,17 @@ function clientJs(source: string, file = 'CondKey.tsx'): string {
|
|
|
29
29
|
return cjs!.content
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Reconciler call sites, whichever family they use. A lazy-row-eligible loop
|
|
34
|
+
* (spec/slot-unification.md §9.4) emits `mapArrayLazy(`; everything else keeps
|
|
35
|
+
* `mapArray(`. The key expression this suite asserts on is the same third
|
|
36
|
+
* argument in both shapes, so match the family, not one member of it.
|
|
37
|
+
*/
|
|
32
38
|
function mapArrayCalls(content: string): string[] {
|
|
33
39
|
return content
|
|
34
40
|
.split('\n')
|
|
35
41
|
.map((ln) => ln.trim())
|
|
36
|
-
.filter((ln) => ln.startsWith('mapArray('))
|
|
42
|
+
.filter((ln) => ln.startsWith('mapArray(') || ln.startsWith('mapArrayLazy('))
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
describe('mapArray key extraction across conditional branches (#1098)', () => {
|
|
@@ -7,9 +7,14 @@
|
|
|
7
7
|
* `isSelected(row.id)` as reactive with no analyzer changes — the callee's
|
|
8
8
|
* type carries the brand, not the call's return type. These tests pin:
|
|
9
9
|
* - the classic js-framework-benchmark row compiles with `isSelected(row.id)`
|
|
10
|
-
* wired
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* wired through the lazy row graph — ZERO emitted per-row effects, the
|
|
11
|
+
* loop-level effect living in `mapArrayLazy` (spec §9). Until §9.3a
|
|
12
|
+
* was lifted this shape was gate-INELIGIBLE (an opaque local whose call
|
|
13
|
+
* is the reactive read could not be primed) and compiled to one per-row
|
|
14
|
+
* `createEffect`; the runtime re-subscribe seam replaced that, so the
|
|
15
|
+
* loop is emitted like any other. Either way it is never
|
|
16
|
+
* the legacy `selected() === row.id` shape, which subscribes every row
|
|
17
|
+
* to the raw signal.
|
|
13
18
|
* - the loop-param accessor wrap applies only to the call ARGUMENT
|
|
14
19
|
* (`row.id` -> `row().id`), leaving the `isSelected` callee untouched
|
|
15
20
|
* - the hoisted skeleton fast path (#2223) still fires for a selector-driven
|
|
@@ -36,7 +41,7 @@ function compile(source: string, filename: string): { clientJs: string; template
|
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
describe('createSelector (perf, #2143 gap 5)', () => {
|
|
39
|
-
test('isSelected(row.id) in a loop body compiles
|
|
44
|
+
test('isSelected(row.id) in a loop body compiles through the lazy row graph', () => {
|
|
40
45
|
const source = `
|
|
41
46
|
'use client'
|
|
42
47
|
import { createSignal, createSelector } from '@barefootjs/client'
|
|
@@ -66,12 +71,21 @@ describe('createSelector (perf, #2143 gap 5)', () => {
|
|
|
66
71
|
// The callee itself is never rewritten to an accessor call.
|
|
67
72
|
expect(clientJs).not.toContain('isSelected()(')
|
|
68
73
|
|
|
69
|
-
//
|
|
70
|
-
//
|
|
74
|
+
// The selector-driven class attribute costs NO emitted effect at all:
|
|
75
|
+
// the loop is lazy-eligible, so its one loop-level effect lives inside
|
|
76
|
+
// `mapArrayLazy` rather than in the emitted row body. It is also never
|
|
77
|
+
// the O(rows) `selected() === row.id` shape.
|
|
71
78
|
const effectCount = (clientJs.match(/createEffect\(/g) ?? []).length
|
|
72
|
-
expect(effectCount).toBe(
|
|
79
|
+
expect(effectCount).toBe(0)
|
|
80
|
+
expect(clientJs).toContain('mapArrayLazy(')
|
|
73
81
|
expect(clientJs).not.toContain('selected() ===')
|
|
74
82
|
|
|
83
|
+
// `isSelected` is an opaque local (its CALL is the reactive read). Nothing
|
|
84
|
+
// in the emission marks that: the runtime's re-subscribe seam applies to
|
|
85
|
+
// every loop-level outer effect, so the compiler has no judgement to
|
|
86
|
+
// encode here (§9.3a).
|
|
87
|
+
expect(clientJs).not.toContain('outerNeedsResubscribe')
|
|
88
|
+
|
|
75
89
|
// The hoisted skeleton fast path (#2223) still fires: a single-line
|
|
76
90
|
// renderItem clones from a once-per-loop template.
|
|
77
91
|
expect(clientJs).toMatch(/const __tpl_\w+ = document\.createElement\('template'\)/)
|