@adaas/are-html 0.0.22 → 0.0.24
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/browser/index.d.mts +194 -10
- package/dist/browser/index.mjs +696 -245
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/{AreBinding.attribute-doUvtOjc.d.mts → AreBinding.attribute-BWzEIw6H.d.mts} +45 -0
- package/dist/node/{AreBinding.attribute-Bm5LlOyE.d.ts → AreBinding.attribute-GpT-5Qmf.d.ts} +45 -0
- package/dist/node/attributes/AreBinding.attribute.d.mts +1 -1
- package/dist/node/attributes/AreBinding.attribute.d.ts +1 -1
- package/dist/node/attributes/AreDirective.attribute.d.mts +1 -1
- package/dist/node/attributes/AreDirective.attribute.d.ts +1 -1
- package/dist/node/attributes/AreEvent.attribute.d.mts +1 -1
- package/dist/node/attributes/AreEvent.attribute.d.ts +1 -1
- package/dist/node/attributes/AreStatic.attribute.d.mts +1 -1
- package/dist/node/attributes/AreStatic.attribute.d.ts +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.mts +18 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.ts +18 -1
- package/dist/node/directives/AreDirectiveFor.directive.js +57 -9
- package/dist/node/directives/AreDirectiveFor.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.mjs +57 -9
- package/dist/node/directives/AreDirectiveFor.directive.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveIf.directive.d.mts +18 -2
- package/dist/node/directives/AreDirectiveIf.directive.d.ts +18 -2
- package/dist/node/directives/AreDirectiveIf.directive.js +29 -6
- package/dist/node/directives/AreDirectiveIf.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveIf.directive.mjs +29 -6
- package/dist/node/directives/AreDirectiveIf.directive.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveShow.directive.d.mts +1 -1
- package/dist/node/directives/AreDirectiveShow.directive.d.ts +1 -1
- package/dist/node/engine/AreHTML.compiler.d.mts +4 -2
- package/dist/node/engine/AreHTML.compiler.d.ts +4 -2
- package/dist/node/engine/AreHTML.compiler.js +11 -4
- package/dist/node/engine/AreHTML.compiler.js.map +1 -1
- package/dist/node/engine/AreHTML.compiler.mjs +11 -4
- package/dist/node/engine/AreHTML.compiler.mjs.map +1 -1
- package/dist/node/engine/AreHTML.constants.d.mts +33 -1
- package/dist/node/engine/AreHTML.constants.d.ts +33 -1
- package/dist/node/engine/AreHTML.constants.js +166 -0
- package/dist/node/engine/AreHTML.constants.js.map +1 -1
- package/dist/node/engine/AreHTML.constants.mjs +165 -1
- package/dist/node/engine/AreHTML.constants.mjs.map +1 -1
- package/dist/node/engine/AreHTML.context.d.mts +66 -0
- package/dist/node/engine/AreHTML.context.d.ts +66 -0
- package/dist/node/engine/AreHTML.context.js +98 -0
- package/dist/node/engine/AreHTML.context.js.map +1 -1
- package/dist/node/engine/AreHTML.context.mjs +98 -0
- package/dist/node/engine/AreHTML.context.mjs.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.d.mts +3 -0
- package/dist/node/engine/AreHTML.interpreter.d.ts +3 -0
- package/dist/node/engine/AreHTML.interpreter.js +66 -10
- package/dist/node/engine/AreHTML.interpreter.js.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.mjs +66 -10
- package/dist/node/engine/AreHTML.interpreter.mjs.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.d.mts +1 -8
- package/dist/node/engine/AreHTML.lifecycle.d.ts +1 -8
- package/dist/node/engine/AreHTML.lifecycle.js +29 -44
- package/dist/node/engine/AreHTML.lifecycle.js.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.mjs +29 -44
- package/dist/node/engine/AreHTML.lifecycle.mjs.map +1 -1
- package/dist/node/engine/AreHTML.tokenizer.d.mts +1 -1
- package/dist/node/engine/AreHTML.tokenizer.d.ts +1 -1
- package/dist/node/engine/AreHTML.tokenizer.js +7 -1
- package/dist/node/engine/AreHTML.tokenizer.js.map +1 -1
- package/dist/node/engine/AreHTML.tokenizer.mjs +7 -1
- package/dist/node/engine/AreHTML.tokenizer.mjs.map +1 -1
- package/dist/node/engine/AreHTML.transformer.d.mts +1 -1
- package/dist/node/engine/AreHTML.transformer.d.ts +1 -1
- package/dist/node/index.d.mts +4 -3
- package/dist/node/index.d.ts +4 -3
- package/dist/node/index.js +7 -0
- package/dist/node/index.mjs +1 -0
- package/dist/node/instructions/AddStaticHTML.instruction.d.mts +8 -0
- package/dist/node/instructions/AddStaticHTML.instruction.d.ts +8 -0
- package/dist/node/instructions/AddStaticHTML.instruction.js +31 -0
- package/dist/node/instructions/AddStaticHTML.instruction.js.map +1 -0
- package/dist/node/instructions/AddStaticHTML.instruction.mjs +24 -0
- package/dist/node/instructions/AddStaticHTML.instruction.mjs.map +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.d.mts +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.d.ts +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.js +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.js.map +1 -1
- package/dist/node/instructions/AreHTML.instructions.constants.mjs +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.mjs.map +1 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.mts +9 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.ts +9 -1
- package/dist/node/lib/AreDirective/AreDirective.component.d.mts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.component.d.ts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.types.d.mts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.types.d.ts +1 -1
- package/dist/node/lib/AreHTML/AreHTML.tokenizer.d.mts +1 -1
- package/dist/node/lib/AreHTML/AreHTML.tokenizer.d.ts +1 -1
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.d.mts +1 -1
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.d.ts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.d.mts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.d.ts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.js +51 -0
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.js.map +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.mjs +51 -0
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.mjs.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.js.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.mjs.map +1 -1
- package/dist/node/nodes/AreComment.d.mts +1 -1
- package/dist/node/nodes/AreComment.d.ts +1 -1
- package/dist/node/nodes/AreComponent.d.mts +1 -1
- package/dist/node/nodes/AreComponent.d.ts +1 -1
- package/dist/node/nodes/AreInterpolation.d.mts +1 -1
- package/dist/node/nodes/AreInterpolation.d.ts +1 -1
- package/dist/node/nodes/AreRoot.d.mts +1 -1
- package/dist/node/nodes/AreRoot.d.ts +1 -1
- package/dist/node/nodes/AreText.d.mts +1 -1
- package/dist/node/nodes/AreText.d.ts +1 -1
- package/examples/dashboard/concept.ts +1 -1
- package/examples/dashboard/dist/index.html +1 -1
- package/examples/dashboard/dist/{mqh9ryml-xat335.js → mqiw5sqa-ypckmj.js} +403 -57
- package/examples/for-perf/dist/index.html +1 -1
- package/examples/for-perf/dist/{mqh9ryfo-6a8d0o.js → mqp8i2py-vltsx0.js} +3030 -2474
- package/examples/lazy-loading/README.md +76 -0
- package/examples/lazy-loading/concept.ts +55 -0
- package/examples/lazy-loading/containers/UI.container.ts +215 -0
- package/examples/lazy-loading/dist/app.js +3803 -0
- package/examples/{for-perf/dist/mqh9ryfq-4pf5cv.js → lazy-loading/dist/chunks/chunk-6K72IBO4.js} +2708 -5476
- package/examples/lazy-loading/dist/index.html +36 -0
- package/examples/lazy-loading/dist/lazy/about-page.js +59 -0
- package/examples/lazy-loading/dist/lazy/reports-page.js +65 -0
- package/examples/lazy-loading/dist/lazy/settings-page.js +54 -0
- package/examples/lazy-loading/public/index.html +36 -0
- package/examples/lazy-loading/src/components/AppShell.component.ts +44 -0
- package/examples/lazy-loading/src/components/HomePage.component.ts +59 -0
- package/examples/lazy-loading/src/components/LazyOutlet.component.ts +108 -0
- package/examples/lazy-loading/src/components/NavBar.component.ts +98 -0
- package/examples/lazy-loading/src/concept.ts +116 -0
- package/examples/lazy-loading/src/lazy/AboutPage.component.ts +54 -0
- package/examples/lazy-loading/src/lazy/ReportsPage.component.ts +56 -0
- package/examples/lazy-loading/src/lazy/SettingsPage.component.ts +45 -0
- package/examples/lazy-loading/src/runtime/ComponentManifest.fragment.ts +61 -0
- package/examples/lazy-loading/src/runtime/LazyComponentResolver.fragment.ts +77 -0
- package/examples/os-desktop/README.md +91 -0
- package/examples/os-desktop/concept.ts +54 -0
- package/examples/os-desktop/containers/OS.container.ts +198 -0
- package/examples/os-desktop/containers/apps/AppBackend.ts +29 -0
- package/examples/os-desktop/containers/apps/GanttApp.backend.ts +56 -0
- package/examples/os-desktop/containers/apps/MarketingApp.backend.ts +68 -0
- package/examples/os-desktop/dist/app.js +4410 -0
- package/examples/os-desktop/dist/apps/gantt/app.js +271 -0
- package/examples/os-desktop/dist/apps/marketing/app.js +346 -0
- package/examples/{for-perf/dist/mqh9ryde-m243t8.js → os-desktop/dist/chunks/chunk-6K72IBO4.js} +2708 -5476
- package/examples/os-desktop/dist/chunks/chunk-EIIGUL6N.js +30 -0
- package/examples/os-desktop/dist/chunks/chunk-WOH7L5UR.js +30 -0
- package/examples/os-desktop/dist/index.html +33 -0
- package/examples/os-desktop/public/index.html +33 -0
- package/examples/os-desktop/src/apps/gantt/GanttApp.component.ts +41 -0
- package/examples/os-desktop/src/apps/gantt/GanttChart.component.ts +126 -0
- package/examples/os-desktop/src/apps/gantt/GanttStore.ts +47 -0
- package/examples/os-desktop/src/apps/gantt/GanttToolbar.component.ts +73 -0
- package/examples/os-desktop/src/apps/gantt/index.ts +13 -0
- package/examples/os-desktop/src/apps/marketing/MarketingApp.component.ts +53 -0
- package/examples/os-desktop/src/apps/marketing/MarketingStore.ts +34 -0
- package/examples/os-desktop/src/apps/marketing/PostEditor.component.ts +153 -0
- package/examples/os-desktop/src/apps/marketing/PostPreview.component.ts +110 -0
- package/examples/os-desktop/src/apps/marketing/index.ts +16 -0
- package/examples/os-desktop/src/concept.ts +126 -0
- package/examples/os-desktop/src/os/AppStage.component.ts +112 -0
- package/examples/os-desktop/src/os/AppWindow.component.ts +102 -0
- package/examples/os-desktop/src/os/Desktop.component.ts +106 -0
- package/examples/os-desktop/src/os/Dock.component.ts +174 -0
- package/examples/os-desktop/src/os/Hud.component.ts +83 -0
- package/examples/os-desktop/src/os/Launchpad.component.ts +191 -0
- package/examples/os-desktop/src/os/MenuBar.component.ts +156 -0
- package/examples/os-desktop/src/runtime/AppComponentResolver.fragment.ts +121 -0
- package/examples/os-desktop/src/runtime/AppRegistry.fragment.ts +104 -0
- package/examples/os-desktop/src/signals/MouseState.signal.ts +34 -0
- package/examples/os-desktop/src/signals/OSRoute.signal.ts +37 -0
- package/examples/os-desktop/src/signals/SelectionState.signal.ts +34 -0
- package/examples/signal-routing/dist/index.html +1 -1
- package/examples/signal-routing/dist/{mqh9ryc9-dkcbkx.js → mqp8hgce-4d6rh0.js} +3196 -2640
- package/package.json +13 -9
- package/src/directives/AreDirectiveFor.directive.ts +99 -16
- package/src/directives/AreDirectiveIf.directive.ts +33 -4
- package/src/engine/AreHTML.compiler.ts +25 -2
- package/src/engine/AreHTML.constants.ts +142 -0
- package/src/engine/AreHTML.context.ts +112 -0
- package/src/engine/AreHTML.interpreter.ts +114 -13
- package/src/engine/AreHTML.lifecycle.ts +81 -74
- package/src/engine/AreHTML.tokenizer.ts +30 -1
- package/src/index.ts +1 -0
- package/src/instructions/AddStaticHTML.instruction.ts +23 -0
- package/src/instructions/AreHTML.instructions.constants.ts +1 -0
- package/src/instructions/AreHTML.instructions.types.ts +9 -0
- package/src/lib/AreHTMLNode/AreHTMLNode.ts +74 -0
- package/src/lib/AreRoot/AreRoot.component.ts +3 -3
- package/tests/PropPropagation.test.ts +181 -0
- package/tests/StaticIsland.test.ts +115 -0
- package/tests/jest.setup.ts +11 -0
|
@@ -7,6 +7,7 @@ import { AddCommentInstruction } from '@adaas/are-html/instructions/AddComment.i
|
|
|
7
7
|
import { AreDirectiveContext } from '@adaas/are-html/directive/AreDirective.context';
|
|
8
8
|
import { A_Frame } from '@adaas/a-frame/core';
|
|
9
9
|
import { AreSchedulerHelper } from '@adaas/are-html/helpers/AreScheduler.helper';
|
|
10
|
+
import { AreHTMLEngineContext } from '@adaas/are-html/context';
|
|
10
11
|
|
|
11
12
|
let AreDirectiveFor = class extends AreDirective {
|
|
12
13
|
transform(attribute, scope, store, scene, logger, ...args) {
|
|
@@ -21,7 +22,8 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
21
22
|
node.init();
|
|
22
23
|
attribute.template = forTemplate;
|
|
23
24
|
const { key, index, arrayExpr } = this.parseExpression(attribute.content);
|
|
24
|
-
const
|
|
25
|
+
const contextScope = attribute.owner.scope.resolve(AreDirectiveContext)?.scope || {};
|
|
26
|
+
const array = this.resolveArray(store, arrayExpr, attribute.content, contextScope);
|
|
25
27
|
attribute.value = array;
|
|
26
28
|
for (let i = 0; i < array.length; i++) {
|
|
27
29
|
this.spawnItemNode(attribute.template, attribute.owner, key, index, array[i], i);
|
|
@@ -55,8 +57,9 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
55
57
|
*/
|
|
56
58
|
performUpdate(attribute, store, scene, state) {
|
|
57
59
|
const { key, index, arrayExpr, trackExpr } = this.parseExpression(attribute.content);
|
|
58
|
-
const newArray = this.resolveArray(store, arrayExpr, attribute.content);
|
|
59
60
|
const owner = attribute.owner;
|
|
61
|
+
const contextScope = owner.scope.resolve(AreDirectiveContext)?.scope || {};
|
|
62
|
+
const newArray = this.resolveArray(store, arrayExpr, attribute.content, contextScope);
|
|
60
63
|
const currentChildren = [...owner.children];
|
|
61
64
|
attribute.value = newArray;
|
|
62
65
|
const attached = this.isAttached(owner);
|
|
@@ -71,12 +74,16 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
71
74
|
remaining.add(child);
|
|
72
75
|
}
|
|
73
76
|
const toCreate = [];
|
|
77
|
+
const finalByKey = /* @__PURE__ */ new Map();
|
|
78
|
+
const orderedKeys = new Array(newArray.length);
|
|
74
79
|
for (let i = 0; i < newArray.length; i++) {
|
|
75
80
|
const item = newArray[i];
|
|
76
81
|
const k = computeKey(item, i);
|
|
82
|
+
orderedKeys[i] = k;
|
|
77
83
|
const existing = childByKey.get(k);
|
|
78
84
|
if (existing) {
|
|
79
85
|
remaining.delete(existing);
|
|
86
|
+
finalByKey.set(k, existing);
|
|
80
87
|
let directiveContext = existing.scope.resolveFlat(AreDirectiveContext);
|
|
81
88
|
if (!directiveContext) {
|
|
82
89
|
directiveContext = new AreDirectiveContext(existing.aseid);
|
|
@@ -88,7 +95,7 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
88
95
|
[index || "index"]: i
|
|
89
96
|
};
|
|
90
97
|
} else {
|
|
91
|
-
toCreate.push({ item, idx: i });
|
|
98
|
+
toCreate.push({ item, idx: i, key: k });
|
|
92
99
|
}
|
|
93
100
|
}
|
|
94
101
|
for (const child of remaining) {
|
|
@@ -97,12 +104,14 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
97
104
|
}
|
|
98
105
|
const createItem = (desc) => {
|
|
99
106
|
const child = this.spawnItemNode(attribute.template, owner, key, index, desc.item, desc.idx);
|
|
107
|
+
finalByKey.set(desc.key, child);
|
|
100
108
|
child.transform();
|
|
101
109
|
child.compile();
|
|
102
110
|
if (attached) child.mount();
|
|
103
111
|
};
|
|
104
112
|
if (toCreate.length <= AreDirectiveFor.SYNC_THRESHOLD) {
|
|
105
113
|
for (const desc of toCreate) createItem(desc);
|
|
114
|
+
if (attached) this.reconcileOrder(owner, orderedKeys, finalByKey);
|
|
106
115
|
return this.finishUpdate(attribute, store, scene, state);
|
|
107
116
|
}
|
|
108
117
|
state.running = true;
|
|
@@ -125,10 +134,39 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
125
134
|
AreSchedulerHelper.scheduleMacrotask(() => resolve(processChunk()));
|
|
126
135
|
});
|
|
127
136
|
}
|
|
137
|
+
if (attached) this.reconcileOrder(owner, orderedKeys, finalByKey);
|
|
128
138
|
return this.finishUpdate(attribute, store, scene, state);
|
|
129
139
|
};
|
|
130
140
|
return processChunk();
|
|
131
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Repositions the item nodes' DOM elements so the rendered order matches the
|
|
144
|
+
* source array order. The keyed diff (steps 1–4) reuses existing nodes in
|
|
145
|
+
* place and mounts new ones at the end; without this pass a `prepend` or
|
|
146
|
+
* `shuffle` would leave reused rows where they were and pile new rows at the
|
|
147
|
+
* bottom. We walk the desired order RIGHT-TO-LEFT, keeping a `ref` pointer to
|
|
148
|
+
* the element each item must precede (starting at the `$for` anchor comment),
|
|
149
|
+
* and only call `insertBefore` when an element is not already in position —
|
|
150
|
+
* so a plain `append` (already-correct order) performs ZERO DOM moves.
|
|
151
|
+
*/
|
|
152
|
+
reconcileOrder(owner, orderedKeys, finalByKey) {
|
|
153
|
+
const context = owner.scope.resolve(AreHTMLEngineContext);
|
|
154
|
+
if (!context) return;
|
|
155
|
+
const anchor = context.getNodeElement(owner);
|
|
156
|
+
if (!anchor || !anchor.parentNode) return;
|
|
157
|
+
const parent = anchor.parentNode;
|
|
158
|
+
let ref = anchor;
|
|
159
|
+
for (let i = orderedKeys.length - 1; i >= 0; i--) {
|
|
160
|
+
const node = finalByKey.get(orderedKeys[i]);
|
|
161
|
+
if (!node) continue;
|
|
162
|
+
const element = context.getNodeElement(node);
|
|
163
|
+
if (!element || element.parentNode !== parent) continue;
|
|
164
|
+
if (element.nextSibling !== ref) {
|
|
165
|
+
parent.insertBefore(element, ref);
|
|
166
|
+
}
|
|
167
|
+
ref = element;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
132
170
|
/**
|
|
133
171
|
* Completes an update pass. If another update() arrived while a chunked
|
|
134
172
|
* render was streaming, run exactly one more pass now from the latest store
|
|
@@ -219,13 +257,23 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
219
257
|
* Supports both plain key lookups and function-call expressions:
|
|
220
258
|
* items → store.get('items')
|
|
221
259
|
* filter(items) → store.get('filter')(store.get('items'))
|
|
260
|
+
*
|
|
261
|
+
* `contextScope` carries item-scoped variables introduced by an enclosing
|
|
262
|
+
* directive (e.g. the `row` of an outer `$for`). It is consulted BEFORE the
|
|
263
|
+
* store so a nested `$for="cell in row.cells"` resolves `row` from the
|
|
264
|
+
* parent iteration instead of looking for a (non-existent) top-level store
|
|
265
|
+
* key. Leading identifiers not present in the context fall back to the store.
|
|
222
266
|
*/
|
|
223
|
-
resolveArray(store, arrayExpr, fullContent) {
|
|
267
|
+
resolveArray(store, arrayExpr, fullContent, contextScope = {}) {
|
|
268
|
+
const getRoot = (rawKey) => {
|
|
269
|
+
const k = rawKey.replace(/\?$/, "");
|
|
270
|
+
return k in contextScope ? contextScope[k] : store.get(k);
|
|
271
|
+
};
|
|
224
272
|
let result;
|
|
225
273
|
const callMatch = arrayExpr.match(/^([^(]+)\((.+)\)$/);
|
|
226
274
|
if (callMatch) {
|
|
227
275
|
const fnName = callMatch[1].trim();
|
|
228
|
-
const fn =
|
|
276
|
+
const fn = getRoot(fnName);
|
|
229
277
|
if (typeof fn !== "function")
|
|
230
278
|
throw new AreCompilerError({
|
|
231
279
|
title: 'Invalid "for" Directive Function',
|
|
@@ -239,25 +287,25 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
239
287
|
const stripped = arg.replace(/\?$/, "");
|
|
240
288
|
if (stripped.includes(".")) {
|
|
241
289
|
const parts = stripped.split(".").map((p) => p.replace(/\?$/, ""));
|
|
242
|
-
let val =
|
|
290
|
+
let val = getRoot(parts[0]);
|
|
243
291
|
for (let j = 1; j < parts.length; j++) {
|
|
244
292
|
if (val == null) return void 0;
|
|
245
293
|
val = val[parts[j]];
|
|
246
294
|
}
|
|
247
295
|
return val ?? void 0;
|
|
248
296
|
}
|
|
249
|
-
return
|
|
297
|
+
return getRoot(stripped);
|
|
250
298
|
});
|
|
251
299
|
result = fn(...resolvedArgs);
|
|
252
300
|
} else if (arrayExpr.includes(".")) {
|
|
253
301
|
const parts = arrayExpr.split(".").map((p) => p.replace(/\?$/, ""));
|
|
254
|
-
result =
|
|
302
|
+
result = getRoot(parts[0]);
|
|
255
303
|
for (let i = 1; i < parts.length; i++) {
|
|
256
304
|
if (result == null) break;
|
|
257
305
|
result = result[parts[i]];
|
|
258
306
|
}
|
|
259
307
|
} else {
|
|
260
|
-
result =
|
|
308
|
+
result = getRoot(arrayExpr);
|
|
261
309
|
}
|
|
262
310
|
if (result == null) return [];
|
|
263
311
|
if (!Array.isArray(result))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/directives/AreDirectiveFor.directive.ts"],"names":[],"mappings":"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","file":"AreDirectiveFor.directive.mjs","sourcesContent":["import { A_Caller, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreCompilerError, AreScene, AreStore } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AddCommentInstruction } from \"@adaas/are-html/instructions/AddComment.instruction\";\nimport { AreHTMLNode } from \"@adaas/are-html/node\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\nimport { AreSchedulerHelper } from \"@adaas/are-html/helpers/AreScheduler.helper\";\n\n\ntype AreForExpression = {\n key: string;\n index: string | undefined;\n arrayExpr: string;\n /** Optional `track <expr>` clause, e.g. `track row.id` */\n trackExpr: string | undefined;\n};\n\n/**\n * Per-`$for` reentrancy state used to serialize chunked (async) renders.\n * Keyed by the directive attribute instance (one per `$for` in the template).\n */\ntype AreForRenderState = { running: boolean; pending: boolean };\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $for directive. Iterates over an array expression resolved from the store and renders a cloned template fragment per item, managing per-item subscopes and comment-node anchors. Supports keyed diffing via an optional track clause to minimise DOM mutations on collection updates.'\n})\n@AreDirective.Priority(1)\nexport class AreDirectiveFor extends AreDirective {\n\n /**\n * Lists whose number of NEW item nodes is at or below this threshold render\n * fully synchronously — byte-for-byte the previous behavior. Typical UIs\n * (menus, small tables) are therefore completely unaffected; only genuinely\n * large lists pay the (tiny) scheduling cost to keep the main thread responsive.\n */\n private static readonly SYNC_THRESHOLD = 100;\n\n /**\n * Per-chunk time budget (ms). During a large-list render we mount item nodes\n * until this much time has elapsed, then yield to the browser so it can paint\n * and process input before the next chunk. ~16ms targets one animation frame.\n */\n private static readonly CHUNK_BUDGET_MS = 16;\n\n /**\n * Per-attribute serialization state. A new update() that arrives while a\n * chunked render of the SAME `$for` is still in flight does NOT start a second\n * concurrent pass (which could interleave mutations on the shared children\n * list); instead it marks `pending` and the in-flight run re-runs once more\n * with the latest data when it finishes. This guarantees the children list is\n * only ever mutated by one pass at a time and the final state always reflects\n * the most recent store value.\n */\n private static readonly renderState = new WeakMap<object, AreForRenderState>();\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Scope) scope: A_Scope,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n\n logger.debug(`[Transform] directive $FOR for <${attribute.owner.aseid.toString()}>`)\n\n const node = attribute.owner;\n\n /**\n * Transfer the original node's scope (with all registered attributes and children)\n * to the template clone, and give the owner node a fresh empty scope.\n * This mirrors the $if directive's approach, making the owner a lightweight\n * group container whose sole visible presence is a comment placeholder.\n */\n const forTemplate = node.cloneWithScope();\n\n /**\n * Remove the $for attribute from the template so iterative clones do not\n * re-trigger this directive during their own transform phase.\n * Re-register it on the owner so the reactive compile/update pipeline keeps working.\n */\n const forAttr = forTemplate.attributes.find(d => d.name === attribute.name);\n\n if (forAttr) {\n forTemplate.scope.deregister(forAttr);\n node.scope.register(forAttr);\n }\n\n /**\n * Re-initialize the owner node with its fresh scope so it becomes a valid\n * group container that will own the generated item nodes as children.\n */\n node.init();\n\n /**\n * Store the template for use in compile and update.\n */\n attribute.template = forTemplate;\n\n\n /**\n * Parse the $for expression and evaluate the source array.\n */\n const { key, index, arrayExpr } = this.parseExpression(attribute.content);\n const array = this.resolveArray(store, arrayExpr, attribute.content);\n\n attribute.value = array;\n\n /**\n * For each item in the array, spawn a clone of the template with the\n * item's store values pre-set and its scene activated.\n *\n * The children are added to the owner node before the main compiler's\n * children iteration loop runs, so the main cycle will compile them —\n * no explicit child.compile() call is needed here.\n */\n for (let i = 0; i < array.length; i++) {\n this.spawnItemNode(attribute.template!, attribute.owner, key, index, array[i], i);\n }\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Replace the group node's default host declaration with a comment placeholder\n * so the owner element itself does not render as a DOM element — the item nodes\n * render as its children instead.\n */\n const hostInstruction = scene.host!;\n const commentIdentifier = ` --- for: ${attribute.template!.id} --- `;\n const declaration = new AddCommentInstruction({ content: commentIdentifier });\n\n scene.setHost(declaration);\n scene.planBefore(declaration, hostInstruction);\n scene.unPlan(hostInstruction);\n }\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void | Promise<void> {\n /**\n * Serialize chunked renders per `$for`. If a previous large-list render\n * is still streaming item nodes across macrotasks, do NOT start a second\n * concurrent pass — that would interleave two diffs over the same shared\n * children list (and leave half-compiled item nodes that the next diff\n * would wrongly \"reuse\"). Mark a pass as pending instead; the in-flight\n * run re-diffs once more from the latest store value when it completes.\n */\n let state = AreDirectiveFor.renderState.get(attribute);\n if (!state) {\n state = { running: false, pending: false };\n AreDirectiveFor.renderState.set(attribute, state);\n }\n if (state.running) {\n state.pending = true;\n return;\n }\n\n return this.performUpdate(attribute, store, scene, state);\n }\n\n /**\n * Core of the `$for` update: re-diff the source array against the current\n * children, reconcile reused/removed items, then mount the new ones (small\n * lists synchronously, large lists time-sliced). Never called while another\n * pass for the same `$for` is in flight (see `update`).\n */\n private performUpdate(\n attribute: AreDirectiveAttribute,\n store: AreStore,\n scene: AreScene,\n state: AreForRenderState,\n ): void | Promise<void> {\n /**\n * Re-evaluate the source array.\n */\n const { key, index, arrayExpr, trackExpr } = this.parseExpression(attribute.content);\n const newArray = this.resolveArray(store, arrayExpr, attribute.content);\n\n const owner = attribute.owner;\n const currentChildren = [...owner.children] as AreHTMLNode[];\n\n attribute.value = newArray;\n\n /**\n * Is this `$for`'s subtree currently rendered into the DOM?\n *\n * A `$for` can update while its subtree is detached — e.g. it lives\n * inside a `$if` whose condition is currently false (the documented\n * `<div $if><x $for></div>` nesting). The directive still receives the\n * store change and re-diffs, but it must NOT mount/unmount item nodes\n * directly while detached: the `$for` anchor (and its ancestors) are\n * not in the DOM, so the interpreter's mount-point walk would fall\n * through to the nearest *mounted* ancestor (the `$if` comment in the\n * grandparent) and HOIST the items out of their intended container.\n * When the ancestor `$if` later activates, its mount cascade applies\n * the already-compiled item instructions in the correct place.\n *\n * Detached === any ancestor scene is inactive (regular nodes default\n * to an active scene; only structural directives deactivate one).\n */\n const attached = this.isAttached(owner);\n\n const computeKey = this.makeKeyFn(key, index, trackExpr);\n\n // ── 1. Index existing children by stable key ────────────────────────\n const childByKey = new Map<any, AreHTMLNode>();\n const remaining = new Set<AreHTMLNode>();\n\n for (let i = 0; i < currentChildren.length; i++) {\n const child = currentChildren[i];\n const ctx = child.scope.resolveFlat(AreDirectiveContext);\n const k = ctx ? computeKey(ctx.scope[key], ctx.scope[index || 'index']) : Symbol('orphan');\n childByKey.set(k, child);\n remaining.add(child);\n }\n\n // ── 2. Walk desired list; reuse existing or record items to create ──\n // NOTE: new item nodes are NOT spawned here. Spawning (cloneWithScope +\n // subtree init + scene activation) is the dominant cost of a large\n // render, so it is deferred into the time-sliced loop below alongside\n // transform/compile/mount. Existing (keyed) children are reconciled in\n // place synchronously — that is cheap and keeps reused rows stable.\n const toCreate: Array<{ item: any; idx: number }> = [];\n\n for (let i = 0; i < newArray.length; i++) {\n const item = newArray[i];\n const k = computeKey(item, i);\n const existing = childByKey.get(k);\n\n if (existing) {\n remaining.delete(existing);\n\n let directiveContext = existing.scope.resolveFlat(AreDirectiveContext);\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(existing.aseid);\n existing.scope.register(directiveContext);\n }\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n };\n } else {\n toCreate.push({ item, idx: i });\n }\n }\n\n // ── 3. Unmount + detach removed children ─────────────────────────────\n for (const child of remaining) {\n // Only revert DOM if the subtree is live; a detached subtree's item\n // nodes were never mounted (see `attached` rationale above), so\n // unmounting them is a no-op at best and risks reverting stale state.\n if (attached) child.unmount();\n owner.removeChild(child);\n }\n\n // ── 4. Create + mount the new item nodes. ───────────────────────────\n // `spawnItemNode` appends to `owner.children` immediately, so iterating\n // `toCreate` in source order preserves list order (reused children keep\n // their positions, new rows are appended in order) — identical to the\n // previous synchronous behavior.\n const createItem = (desc: { item: any; idx: number }) => {\n const child = this.spawnItemNode(attribute.template!, owner, key, index, desc.item, desc.idx);\n child.transform();\n child.compile();\n // While detached, stop after compile: the item's instructions are\n // planned and the ancestor `$if`'s mount cascade will apply them in\n // the correct container once the condition becomes truthy. Mounting\n // here would hoist the item to the nearest mounted ancestor.\n if (attached) child.mount();\n };\n\n // Small lists → fully synchronous, identical to the previous behavior.\n if (toCreate.length <= AreDirectiveFor.SYNC_THRESHOLD) {\n for (const desc of toCreate) createItem(desc);\n return this.finishUpdate(attribute, store, scene, state);\n }\n\n // Large lists → time-sliced render. Create item nodes until the frame\n // budget elapses, then yield to the browser (zero-delay macrotask) so\n // it can paint and stay responsive instead of blocking for the whole\n // batch. The `state.running` flag (see `update`) prevents any other\n // update() for this `$for` from interleaving while we stream.\n state.running = true;\n let cursor = 0;\n\n const processChunk = (): void | Promise<void> => {\n try {\n const start = AreSchedulerHelper.now();\n while (cursor < toCreate.length) {\n createItem(toCreate[cursor]);\n cursor++;\n if (AreSchedulerHelper.now() - start >= AreDirectiveFor.CHUNK_BUDGET_MS) break;\n }\n } catch (error) {\n // Never leave the `$for` wedged in the running state on failure,\n // or every future update would be silently deferred forever.\n state.running = false;\n state.pending = false;\n throw error;\n }\n\n if (cursor < toCreate.length) {\n return new Promise<void>(resolve => {\n AreSchedulerHelper.scheduleMacrotask(() => resolve(processChunk()));\n });\n }\n\n return this.finishUpdate(attribute, store, scene, state);\n };\n\n return processChunk();\n }\n\n /**\n * Completes an update pass. If another update() arrived while a chunked\n * render was streaming, run exactly one more pass now from the latest store\n * value so the final DOM always reflects the most recent data.\n */\n private finishUpdate(\n attribute: AreDirectiveAttribute,\n store: AreStore,\n scene: AreScene,\n state: AreForRenderState,\n ): void | Promise<void> {\n state.running = false;\n if (state.pending) {\n state.pending = false;\n return this.performUpdate(attribute, store, scene, state);\n }\n }\n\n\n /**\n * Walks the node's ancestor chain (inclusive) and reports whether the\n * whole path is currently active — i.e. the subtree is actually rendered\n * into the DOM. A single inactive ancestor scene (e.g. a `$if` whose\n * condition is false) means the subtree is detached.\n */\n private isAttached(node: AreHTMLNode): boolean {\n let current: AreHTMLNode | undefined = node;\n while (current) {\n if (current.scene?.isInactive) return false;\n current = current.parent as AreHTMLNode | undefined;\n }\n return true;\n }\n\n\n // ─────────────────────────────────────────────────────────────────────────────\n // ── Helpers ──────────────────────────────────────────────────────────────────\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Build a key-function that derives a stable identity from each item.\n * If the user provided a `track <expr>` clause, evaluate it as a path on\n * the item; otherwise fall back to the item identity (reference equality).\n */\n private makeKeyFn(key: string, index: string | undefined, trackExpr: string | undefined): (item: any, i: number) => any {\n if (!trackExpr) {\n return (item, i) => item ?? i;\n }\n\n // Strip any leading `key.` so users can write `track row.id`.\n const path = trackExpr.startsWith(key + '.') ? trackExpr.slice(key.length + 1) : trackExpr;\n\n return (item, i) => {\n if (item == null) return i;\n if (path === key || path === '$index') return path === '$index' ? i : item;\n\n // dotted path lookup\n const parts = path.split('.');\n let v: any = item;\n for (const p of parts) {\n if (v == null) return i;\n v = v[p];\n }\n return v ?? i;\n };\n }\n\n /**\n * Parses the $for expression string into its constituent parts.\n *\n * Supported formats:\n * item in items\n * item, index in items\n * (item, index) in items\n * item in filter(items)\n * item, index in filter(items, 'active')\n * item in items track item.id\n * (item, i) in items track item.id\n */\n private parseExpression(content: string): AreForExpression {\n // Strip optional `track <expr>` suffix first.\n let trackExpr: string | undefined;\n const trackIdx = content.search(/\\s+track\\s+/);\n let body = content;\n if (trackIdx !== -1) {\n const m = content.slice(trackIdx).match(/\\s+track\\s+(.+)$/);\n if (m) {\n trackExpr = m[1].trim();\n body = content.slice(0, trackIdx).trim();\n }\n }\n\n const inIndex = body.lastIndexOf(' in ');\n const keyAndIndex = body.slice(0, inIndex).trim().replace(/^\\(|\\)$/g, '');\n const arrayExpr = body.slice(inIndex + 4).trim();\n const keyParts = keyAndIndex.split(',').map(p => p.trim());\n\n return {\n key: keyParts[0],\n index: keyParts[1] || undefined,\n arrayExpr,\n trackExpr,\n };\n }\n\n /**\n * Resolves the array expression against the store.\n * Supports both plain key lookups and function-call expressions:\n * items → store.get('items')\n * filter(items) → store.get('filter')(store.get('items'))\n */\n private resolveArray(store: AreStore, arrayExpr: string, fullContent: string): any[] {\n let result: any;\n const callMatch = arrayExpr.match(/^([^(]+)\\((.+)\\)$/);\n\n if (callMatch) {\n const fnName = callMatch[1].trim();\n const fn = store.get(fnName as any);\n\n if (typeof fn !== 'function')\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Function',\n description: `The expression \"${fnName}\" in the \"for\" directive does not resolve to a function in the store. Received: ${typeof fn}`,\n });\n\n const rawArgs = callMatch[2].split(',').map(a => a.trim());\n const resolvedArgs = rawArgs.map(arg => {\n if (arg.startsWith(\"'\") && arg.endsWith(\"'\")) return arg.slice(1, -1);\n if (arg.startsWith('\"') && arg.endsWith('\"')) return arg.slice(1, -1);\n if (!isNaN(Number(arg))) return Number(arg);\n // Dotted-path / optional-chain: e.g. `record?.embedding` or `record.data`\n const stripped = arg.replace(/\\?$/, '');\n if (stripped.includes('.')) {\n const parts = stripped.split('.').map(p => p.replace(/\\?$/, ''));\n let val: any = store.get(parts[0] as any);\n for (let j = 1; j < parts.length; j++) {\n if (val == null) return undefined;\n val = val[parts[j]];\n }\n return val ?? undefined;\n }\n return store.get(stripped as any);\n });\n\n result = (fn as Function)(...resolvedArgs);\n } else if (arrayExpr.includes('.')) {\n // dotted-path lookup: e.g. \"list.items\" or \"record?.keywords\"\n // Strip optional-chaining `?` suffix from each segment so that\n // `record?.keywords` resolves the same as `record.keywords`.\n const parts = arrayExpr.split('.').map(p => p.replace(/\\?$/, ''));\n result = store.get(parts[0] as any);\n for (let i = 1; i < parts.length; i++) {\n if (result == null) break;\n result = result[parts[i]];\n }\n } else {\n result = store.get(arrayExpr.replace(/\\?$/, '') as any);\n }\n\n // null / undefined from optional-chaining expressions (e.g. `record?.keywords`)\n // means the source object is not yet loaded — treat as empty array so the\n // directive initialises gracefully and fills in when the store updates.\n if (result == null) return [];\n\n if (!Array.isArray(result))\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Value',\n description: `The \"for\" directive expects an array but got ${typeof result}. Expression: \"${fullContent}\". Received: ${JSON.stringify(result)}`,\n });\n\n return result;\n }\n\n /**\n * Creates a single item node from the template, registers it as a child of\n * the owner, initialises it, injects item-scoped store values, and activates\n * its scene so the mount/compile cycle will include it.\n *\n * NOTE: This method does NOT call compile() or mount() — the caller is\n * responsible for doing so when the main lifecycle cycle won't cover it\n * (i.e. during update, but not during the initial compile phase).\n */\n private spawnItemNode(\n template: AreHTMLNode,\n owner: AreHTMLNode,\n key: string,\n index: string | undefined,\n item: any,\n i: number,\n ): AreHTMLNode {\n const itemNode = template.clone() as AreHTMLNode;\n\n owner.addChild(itemNode);\n\n const queue = [itemNode];\n\n while (queue.length > 0) {\n const current = queue.shift()!\n\n current.init();\n\n queue.push(...current.children as AreHTMLNode[]);\n }\n\n /**\n * Resolve or create a directive context for the item node. This is needed to hold the item-specific store values (e.g. the \"item\" and \"index\" in a \"for\" loop) that the template's bindings will reference during compile and update. The context is shared among all clones of the same template, but that's fine because each clone gets its own scope values assigned here.\n */\n let directiveContext = itemNode.scope.resolveFlat(AreDirectiveContext);\n\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(itemNode.aseid);\n itemNode.scope.register(directiveContext);\n }\n\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n }\n\n itemNode.scene.activate();\n\n return itemNode;\n }\n}"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/AreDirectiveFor.directive.ts"],"names":[],"mappings":"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","file":"AreDirectiveFor.directive.mjs","sourcesContent":["import { A_Caller, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreCompilerError, AreScene, AreStore } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AddCommentInstruction } from \"@adaas/are-html/instructions/AddComment.instruction\";\nimport { AreHTMLNode } from \"@adaas/are-html/node\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\nimport { AreSchedulerHelper } from \"@adaas/are-html/helpers/AreScheduler.helper\";\nimport { AreHTMLEngineContext } from \"@adaas/are-html/context\";\n\n\ntype AreForExpression = {\n key: string;\n index: string | undefined;\n arrayExpr: string;\n /** Optional `track <expr>` clause, e.g. `track row.id` */\n trackExpr: string | undefined;\n};\n\n/**\n * Per-`$for` reentrancy state used to serialize chunked (async) renders.\n * Keyed by the directive attribute instance (one per `$for` in the template).\n */\ntype AreForRenderState = { running: boolean; pending: boolean };\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $for directive. Iterates over an array expression resolved from the store and renders a cloned template fragment per item, managing per-item subscopes and comment-node anchors. Supports keyed diffing via an optional track clause to minimise DOM mutations on collection updates.'\n})\n@AreDirective.Priority(1)\nexport class AreDirectiveFor extends AreDirective {\n\n /**\n * Lists whose number of NEW item nodes is at or below this threshold render\n * fully synchronously — byte-for-byte the previous behavior. Typical UIs\n * (menus, small tables) are therefore completely unaffected; only genuinely\n * large lists pay the (tiny) scheduling cost to keep the main thread responsive.\n */\n private static readonly SYNC_THRESHOLD = 100;\n\n /**\n * Per-chunk time budget (ms). During a large-list render we mount item nodes\n * until this much time has elapsed, then yield to the browser so it can paint\n * and process input before the next chunk. ~16ms targets one animation frame.\n */\n private static readonly CHUNK_BUDGET_MS = 16;\n\n /**\n * Per-attribute serialization state. A new update() that arrives while a\n * chunked render of the SAME `$for` is still in flight does NOT start a second\n * concurrent pass (which could interleave mutations on the shared children\n * list); instead it marks `pending` and the in-flight run re-runs once more\n * with the latest data when it finishes. This guarantees the children list is\n * only ever mutated by one pass at a time and the final state always reflects\n * the most recent store value.\n */\n private static readonly renderState = new WeakMap<object, AreForRenderState>();\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Scope) scope: A_Scope,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n\n logger.debug(`[Transform] directive $FOR for <${attribute.owner.aseid.toString()}>`)\n\n const node = attribute.owner;\n\n /**\n * Transfer the original node's scope (with all registered attributes and children)\n * to the template clone, and give the owner node a fresh empty scope.\n * This mirrors the $if directive's approach, making the owner a lightweight\n * group container whose sole visible presence is a comment placeholder.\n */\n const forTemplate = node.cloneWithScope();\n\n /**\n * Remove the $for attribute from the template so iterative clones do not\n * re-trigger this directive during their own transform phase.\n * Re-register it on the owner so the reactive compile/update pipeline keeps working.\n */\n const forAttr = forTemplate.attributes.find(d => d.name === attribute.name);\n\n if (forAttr) {\n forTemplate.scope.deregister(forAttr);\n node.scope.register(forAttr);\n }\n\n /**\n * Re-initialize the owner node with its fresh scope so it becomes a valid\n * group container that will own the generated item nodes as children.\n */\n node.init();\n\n /**\n * Store the template for use in compile and update.\n */\n attribute.template = forTemplate;\n\n\n /**\n * Parse the $for expression and evaluate the source array.\n */\n const { key, index, arrayExpr } = this.parseExpression(attribute.content);\n // Item-scoped variables from an enclosing directive (e.g. the `row` of an\n // outer `$for`) so a nested `$for=\"cell in row.cells\"` resolves correctly.\n // Use resolve() (not resolveFlat) so the ENCLOSING item's context — which\n // lives on an ancestor scope, not on this directive's own node — is found.\n const contextScope = attribute.owner.scope.resolve(AreDirectiveContext)?.scope || {};\n const array = this.resolveArray(store, arrayExpr, attribute.content, contextScope);\n\n attribute.value = array;\n\n /**\n * For each item in the array, spawn a clone of the template with the\n * item's store values pre-set and its scene activated.\n *\n * The children are added to the owner node before the main compiler's\n * children iteration loop runs, so the main cycle will compile them —\n * no explicit child.compile() call is needed here.\n */\n for (let i = 0; i < array.length; i++) {\n this.spawnItemNode(attribute.template!, attribute.owner, key, index, array[i], i);\n }\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Replace the group node's default host declaration with a comment placeholder\n * so the owner element itself does not render as a DOM element — the item nodes\n * render as its children instead.\n */\n const hostInstruction = scene.host!;\n const commentIdentifier = ` --- for: ${attribute.template!.id} --- `;\n const declaration = new AddCommentInstruction({ content: commentIdentifier });\n\n scene.setHost(declaration);\n scene.planBefore(declaration, hostInstruction);\n scene.unPlan(hostInstruction);\n }\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void | Promise<void> {\n /**\n * Serialize chunked renders per `$for`. If a previous large-list render\n * is still streaming item nodes across macrotasks, do NOT start a second\n * concurrent pass — that would interleave two diffs over the same shared\n * children list (and leave half-compiled item nodes that the next diff\n * would wrongly \"reuse\"). Mark a pass as pending instead; the in-flight\n * run re-diffs once more from the latest store value when it completes.\n */\n let state = AreDirectiveFor.renderState.get(attribute);\n if (!state) {\n state = { running: false, pending: false };\n AreDirectiveFor.renderState.set(attribute, state);\n }\n if (state.running) {\n state.pending = true;\n return;\n }\n\n return this.performUpdate(attribute, store, scene, state);\n }\n\n /**\n * Core of the `$for` update: re-diff the source array against the current\n * children, reconcile reused/removed items, then mount the new ones (small\n * lists synchronously, large lists time-sliced). Never called while another\n * pass for the same `$for` is in flight (see `update`).\n */\n private performUpdate(\n attribute: AreDirectiveAttribute,\n store: AreStore,\n scene: AreScene,\n state: AreForRenderState,\n ): void | Promise<void> {\n /**\n * Re-evaluate the source array.\n */\n const { key, index, arrayExpr, trackExpr } = this.parseExpression(attribute.content);\n const owner = attribute.owner;\n // Item-scoped variables from an enclosing directive (see transform()).\n // resolve() walks ancestor scopes to find the enclosing item's context.\n const contextScope = owner.scope.resolve(AreDirectiveContext)?.scope || {};\n const newArray = this.resolveArray(store, arrayExpr, attribute.content, contextScope);\n\n const currentChildren = [...owner.children] as AreHTMLNode[];\n\n attribute.value = newArray;\n\n /**\n * Is this `$for`'s subtree currently rendered into the DOM?\n *\n * A `$for` can update while its subtree is detached — e.g. it lives\n * inside a `$if` whose condition is currently false (the documented\n * `<div $if><x $for></div>` nesting). The directive still receives the\n * store change and re-diffs, but it must NOT mount/unmount item nodes\n * directly while detached: the `$for` anchor (and its ancestors) are\n * not in the DOM, so the interpreter's mount-point walk would fall\n * through to the nearest *mounted* ancestor (the `$if` comment in the\n * grandparent) and HOIST the items out of their intended container.\n * When the ancestor `$if` later activates, its mount cascade applies\n * the already-compiled item instructions in the correct place.\n *\n * Detached === any ancestor scene is inactive (regular nodes default\n * to an active scene; only structural directives deactivate one).\n */\n const attached = this.isAttached(owner);\n\n const computeKey = this.makeKeyFn(key, index, trackExpr);\n\n // ── 1. Index existing children by stable key ────────────────────────\n const childByKey = new Map<any, AreHTMLNode>();\n const remaining = new Set<AreHTMLNode>();\n\n for (let i = 0; i < currentChildren.length; i++) {\n const child = currentChildren[i];\n const ctx = child.scope.resolveFlat(AreDirectiveContext);\n const k = ctx ? computeKey(ctx.scope[key], ctx.scope[index || 'index']) : Symbol('orphan');\n childByKey.set(k, child);\n remaining.add(child);\n }\n\n // ── 2. Walk desired list; reuse existing or record items to create ──\n // NOTE: new item nodes are NOT spawned here. Spawning (cloneWithScope +\n // subtree init + scene activation) is the dominant cost of a large\n // render, so it is deferred into the time-sliced loop below alongside\n // transform/compile/mount. Existing (keyed) children are reconciled in\n // place synchronously — that is cheap and keeps reused rows stable.\n const toCreate: Array<{ item: any; idx: number; key: any }> = [];\n\n // Final identity → node map covering BOTH reused and newly created item\n // nodes, plus the desired key order. After all items are mounted these\n // drive the DOM reorder pass (step 5) so the rendered order always\n // matches the source array — making prepend / shuffle / arbitrary\n // reorders move existing rows instead of only appending at the end.\n const finalByKey = new Map<any, AreHTMLNode>();\n const orderedKeys: any[] = new Array(newArray.length);\n\n for (let i = 0; i < newArray.length; i++) {\n const item = newArray[i];\n const k = computeKey(item, i);\n orderedKeys[i] = k;\n const existing = childByKey.get(k);\n\n if (existing) {\n remaining.delete(existing);\n finalByKey.set(k, existing);\n\n let directiveContext = existing.scope.resolveFlat(AreDirectiveContext);\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(existing.aseid);\n existing.scope.register(directiveContext);\n }\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n };\n } else {\n toCreate.push({ item, idx: i, key: k });\n }\n }\n\n // ── 3. Unmount + detach removed children ─────────────────────────────\n for (const child of remaining) {\n // Only revert DOM if the subtree is live; a detached subtree's item\n // nodes were never mounted (see `attached` rationale above), so\n // unmounting them is a no-op at best and risks reverting stale state.\n if (attached) child.unmount();\n owner.removeChild(child);\n }\n\n // ── 4. Create + mount the new item nodes. ───────────────────────────\n // `spawnItemNode` appends to `owner.children` immediately; new rows are\n // therefore mounted at the end (just before the anchor comment). The\n // reorder pass (step 5) then moves any out-of-position node so the final\n // DOM order matches the source array.\n const createItem = (desc: { item: any; idx: number; key: any }) => {\n const child = this.spawnItemNode(attribute.template!, owner, key, index, desc.item, desc.idx);\n finalByKey.set(desc.key, child);\n child.transform();\n child.compile();\n // While detached, stop after compile: the item's instructions are\n // planned and the ancestor `$if`'s mount cascade will apply them in\n // the correct container once the condition becomes truthy. Mounting\n // here would hoist the item to the nearest mounted ancestor.\n if (attached) child.mount();\n };\n\n // Small lists → fully synchronous, identical to the previous behavior.\n if (toCreate.length <= AreDirectiveFor.SYNC_THRESHOLD) {\n for (const desc of toCreate) createItem(desc);\n // ── 5. Reorder live DOM to match the source array order ──────────\n if (attached) this.reconcileOrder(owner, orderedKeys, finalByKey);\n return this.finishUpdate(attribute, store, scene, state);\n }\n\n // Large lists → time-sliced render. Create item nodes until the frame\n // budget elapses, then yield to the browser (zero-delay macrotask) so\n // it can paint and stay responsive instead of blocking for the whole\n // batch. The `state.running` flag (see `update`) prevents any other\n // update() for this `$for` from interleaving while we stream.\n state.running = true;\n let cursor = 0;\n\n const processChunk = (): void | Promise<void> => {\n try {\n const start = AreSchedulerHelper.now();\n while (cursor < toCreate.length) {\n createItem(toCreate[cursor]);\n cursor++;\n if (AreSchedulerHelper.now() - start >= AreDirectiveFor.CHUNK_BUDGET_MS) break;\n }\n } catch (error) {\n // Never leave the `$for` wedged in the running state on failure,\n // or every future update would be silently deferred forever.\n state.running = false;\n state.pending = false;\n throw error;\n }\n\n if (cursor < toCreate.length) {\n return new Promise<void>(resolve => {\n AreSchedulerHelper.scheduleMacrotask(() => resolve(processChunk()));\n });\n }\n\n // ── 5. Reorder live DOM to match the source array order ──────────\n if (attached) this.reconcileOrder(owner, orderedKeys, finalByKey);\n return this.finishUpdate(attribute, store, scene, state);\n };\n\n return processChunk();\n }\n\n /**\n * Repositions the item nodes' DOM elements so the rendered order matches the\n * source array order. The keyed diff (steps 1–4) reuses existing nodes in\n * place and mounts new ones at the end; without this pass a `prepend` or\n * `shuffle` would leave reused rows where they were and pile new rows at the\n * bottom. We walk the desired order RIGHT-TO-LEFT, keeping a `ref` pointer to\n * the element each item must precede (starting at the `$for` anchor comment),\n * and only call `insertBefore` when an element is not already in position —\n * so a plain `append` (already-correct order) performs ZERO DOM moves.\n */\n private reconcileOrder(\n owner: AreHTMLNode,\n orderedKeys: any[],\n finalByKey: Map<any, AreHTMLNode>,\n ): void {\n const context = owner.scope.resolve<AreHTMLEngineContext>(AreHTMLEngineContext);\n if (!context) return;\n\n const anchor = context.getNodeElement(owner);\n if (!anchor || !anchor.parentNode) return;\n\n const parent = anchor.parentNode;\n let ref: Node = anchor;\n\n for (let i = orderedKeys.length - 1; i >= 0; i--) {\n const node = finalByKey.get(orderedKeys[i]);\n if (!node) continue;\n\n const element = context.getNodeElement(node);\n // Element may be missing if the item is still detached/unmounted.\n if (!element || element.parentNode !== parent) continue;\n\n // Already immediately before `ref` — no move needed.\n if (element.nextSibling !== ref) {\n parent.insertBefore(element, ref);\n }\n ref = element;\n }\n }\n\n\n /**\n * Completes an update pass. If another update() arrived while a chunked\n * render was streaming, run exactly one more pass now from the latest store\n * value so the final DOM always reflects the most recent data.\n */\n private finishUpdate(\n attribute: AreDirectiveAttribute,\n store: AreStore,\n scene: AreScene,\n state: AreForRenderState,\n ): void | Promise<void> {\n state.running = false;\n if (state.pending) {\n state.pending = false;\n return this.performUpdate(attribute, store, scene, state);\n }\n }\n\n\n /**\n * Walks the node's ancestor chain (inclusive) and reports whether the\n * whole path is currently active — i.e. the subtree is actually rendered\n * into the DOM. A single inactive ancestor scene (e.g. a `$if` whose\n * condition is false) means the subtree is detached.\n */\n private isAttached(node: AreHTMLNode): boolean {\n let current: AreHTMLNode | undefined = node;\n while (current) {\n if (current.scene?.isInactive) return false;\n current = current.parent as AreHTMLNode | undefined;\n }\n return true;\n }\n\n\n // ─────────────────────────────────────────────────────────────────────────────\n // ── Helpers ──────────────────────────────────────────────────────────────────\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Build a key-function that derives a stable identity from each item.\n * If the user provided a `track <expr>` clause, evaluate it as a path on\n * the item; otherwise fall back to the item identity (reference equality).\n */\n private makeKeyFn(key: string, index: string | undefined, trackExpr: string | undefined): (item: any, i: number) => any {\n if (!trackExpr) {\n return (item, i) => item ?? i;\n }\n\n // Strip any leading `key.` so users can write `track row.id`.\n const path = trackExpr.startsWith(key + '.') ? trackExpr.slice(key.length + 1) : trackExpr;\n\n return (item, i) => {\n if (item == null) return i;\n if (path === key || path === '$index') return path === '$index' ? i : item;\n\n // dotted path lookup\n const parts = path.split('.');\n let v: any = item;\n for (const p of parts) {\n if (v == null) return i;\n v = v[p];\n }\n return v ?? i;\n };\n }\n\n /**\n * Parses the $for expression string into its constituent parts.\n *\n * Supported formats:\n * item in items\n * item, index in items\n * (item, index) in items\n * item in filter(items)\n * item, index in filter(items, 'active')\n * item in items track item.id\n * (item, i) in items track item.id\n */\n private parseExpression(content: string): AreForExpression {\n // Strip optional `track <expr>` suffix first.\n let trackExpr: string | undefined;\n const trackIdx = content.search(/\\s+track\\s+/);\n let body = content;\n if (trackIdx !== -1) {\n const m = content.slice(trackIdx).match(/\\s+track\\s+(.+)$/);\n if (m) {\n trackExpr = m[1].trim();\n body = content.slice(0, trackIdx).trim();\n }\n }\n\n const inIndex = body.lastIndexOf(' in ');\n const keyAndIndex = body.slice(0, inIndex).trim().replace(/^\\(|\\)$/g, '');\n const arrayExpr = body.slice(inIndex + 4).trim();\n const keyParts = keyAndIndex.split(',').map(p => p.trim());\n\n return {\n key: keyParts[0],\n index: keyParts[1] || undefined,\n arrayExpr,\n trackExpr,\n };\n }\n\n /**\n * Resolves the array expression against the store.\n * Supports both plain key lookups and function-call expressions:\n * items → store.get('items')\n * filter(items) → store.get('filter')(store.get('items'))\n *\n * `contextScope` carries item-scoped variables introduced by an enclosing\n * directive (e.g. the `row` of an outer `$for`). It is consulted BEFORE the\n * store so a nested `$for=\"cell in row.cells\"` resolves `row` from the\n * parent iteration instead of looking for a (non-existent) top-level store\n * key. Leading identifiers not present in the context fall back to the store.\n */\n private resolveArray(\n store: AreStore,\n arrayExpr: string,\n fullContent: string,\n contextScope: Record<string, any> = {},\n ): any[] {\n // Resolve a leading identifier from the directive context first, then\n // the store — mirrors how bindings/interpolations evaluate scoped vars.\n const getRoot = (rawKey: string): any => {\n const k = rawKey.replace(/\\?$/, '');\n return (k in contextScope) ? contextScope[k] : store.get(k as any);\n };\n\n let result: any;\n const callMatch = arrayExpr.match(/^([^(]+)\\((.+)\\)$/);\n\n if (callMatch) {\n const fnName = callMatch[1].trim();\n const fn = getRoot(fnName);\n\n if (typeof fn !== 'function')\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Function',\n description: `The expression \"${fnName}\" in the \"for\" directive does not resolve to a function in the store. Received: ${typeof fn}`,\n });\n\n const rawArgs = callMatch[2].split(',').map(a => a.trim());\n const resolvedArgs = rawArgs.map(arg => {\n if (arg.startsWith(\"'\") && arg.endsWith(\"'\")) return arg.slice(1, -1);\n if (arg.startsWith('\"') && arg.endsWith('\"')) return arg.slice(1, -1);\n if (!isNaN(Number(arg))) return Number(arg);\n // Dotted-path / optional-chain: e.g. `record?.embedding` or `record.data`\n const stripped = arg.replace(/\\?$/, '');\n if (stripped.includes('.')) {\n const parts = stripped.split('.').map(p => p.replace(/\\?$/, ''));\n let val: any = getRoot(parts[0]);\n for (let j = 1; j < parts.length; j++) {\n if (val == null) return undefined;\n val = val[parts[j]];\n }\n return val ?? undefined;\n }\n return getRoot(stripped);\n });\n\n result = (fn as Function)(...resolvedArgs);\n } else if (arrayExpr.includes('.')) {\n // dotted-path lookup: e.g. \"list.items\" or \"record?.keywords\"\n // Strip optional-chaining `?` suffix from each segment so that\n // `record?.keywords` resolves the same as `record.keywords`.\n const parts = arrayExpr.split('.').map(p => p.replace(/\\?$/, ''));\n result = getRoot(parts[0]);\n for (let i = 1; i < parts.length; i++) {\n if (result == null) break;\n result = result[parts[i]];\n }\n } else {\n result = getRoot(arrayExpr);\n }\n\n // null / undefined from optional-chaining expressions (e.g. `record?.keywords`)\n // means the source object is not yet loaded — treat as empty array so the\n // directive initialises gracefully and fills in when the store updates.\n if (result == null) return [];\n\n if (!Array.isArray(result))\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Value',\n description: `The \"for\" directive expects an array but got ${typeof result}. Expression: \"${fullContent}\". Received: ${JSON.stringify(result)}`,\n });\n\n return result;\n }\n\n /**\n * Creates a single item node from the template, registers it as a child of\n * the owner, initialises it, injects item-scoped store values, and activates\n * its scene so the mount/compile cycle will include it.\n *\n * NOTE: This method does NOT call compile() or mount() — the caller is\n * responsible for doing so when the main lifecycle cycle won't cover it\n * (i.e. during update, but not during the initial compile phase).\n */\n private spawnItemNode(\n template: AreHTMLNode,\n owner: AreHTMLNode,\n key: string,\n index: string | undefined,\n item: any,\n i: number,\n ): AreHTMLNode {\n const itemNode = template.clone() as AreHTMLNode;\n\n owner.addChild(itemNode);\n\n const queue = [itemNode];\n\n while (queue.length > 0) {\n const current = queue.shift()!\n\n current.init();\n\n queue.push(...current.children as AreHTMLNode[]);\n }\n\n /**\n * Resolve or create a directive context for the item node. This is needed to hold the item-specific store values (e.g. the \"item\" and \"index\" in a \"for\" loop) that the template's bindings will reference during compile and update. The context is shared among all clones of the same template, but that's fine because each clone gets its own scope values assigned here.\n */\n let directiveContext = itemNode.scope.resolveFlat(AreDirectiveContext);\n\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(itemNode.aseid);\n itemNode.scope.register(directiveContext);\n }\n\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n }\n\n itemNode.scene.activate();\n\n return itemNode;\n }\n}"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A_Scope } from '@adaas/a-concept';
|
|
2
2
|
import { A_Logger } from '@adaas/a-utils/a-logger';
|
|
3
|
-
import { a as AreDirective, b as AreDirectiveAttribute } from '../AreBinding.attribute-
|
|
3
|
+
import { a as AreDirective, b as AreDirectiveAttribute } from '../AreBinding.attribute-BWzEIw6H.mjs';
|
|
4
4
|
import { AreStore, AreScene, AreSyntax } from '@adaas/are';
|
|
5
5
|
import { AreDirectiveContext } from '../lib/AreDirective/AreDirective.context.mjs';
|
|
6
6
|
import '../lib/AreStyle/AreStyle.context.mjs';
|
|
@@ -27,7 +27,23 @@ import '@adaas/a-utils/a-execution';
|
|
|
27
27
|
declare class AreDirectiveIf extends AreDirective {
|
|
28
28
|
transform(attribute: AreDirectiveAttribute, scope: A_Scope, store: AreStore, scene: AreScene, logger: A_Logger, ...args: any[]): void;
|
|
29
29
|
compile(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, syntax: AreSyntax, directiveContext?: AreDirectiveContext, ...args: any[]): void;
|
|
30
|
-
update(attribute: AreDirectiveAttribute, store: AreStore, scope: A_Scope, syntax: AreSyntax, scene: AreScene, ...args: any[]): void;
|
|
30
|
+
update(attribute: AreDirectiveAttribute, store: AreStore, scope: A_Scope, syntax: AreSyntax, scene: AreScene, directiveContext?: AreDirectiveContext, ...args: any[]): void;
|
|
31
|
+
/**
|
|
32
|
+
* Evaluates the `$if` condition defensively.
|
|
33
|
+
*
|
|
34
|
+
* A condition can reference data that is momentarily unavailable — most
|
|
35
|
+
* commonly a nested `$if` (e.g. `$if="selected.fields.length"`) living
|
|
36
|
+
* inside a parent `$if="selected"` whose object has just become `null`.
|
|
37
|
+
* Because the nested directive is still subscribed to the store, its
|
|
38
|
+
* update fires on that same change and the raw expression would throw
|
|
39
|
+
* `Cannot read properties of null`, crashing the whole update pipeline.
|
|
40
|
+
*
|
|
41
|
+
* Treating an evaluation error as `false` is the correct contract for a
|
|
42
|
+
* conditional: if the condition cannot be resolved, the subtree simply
|
|
43
|
+
* stays hidden until the referenced data is present again (at which point
|
|
44
|
+
* the parent `$if` re-activates and re-evaluates this one).
|
|
45
|
+
*/
|
|
46
|
+
private evaluateCondition;
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
export { AreDirectiveIf };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A_Scope } from '@adaas/a-concept';
|
|
2
2
|
import { A_Logger } from '@adaas/a-utils/a-logger';
|
|
3
|
-
import { a as AreDirective, b as AreDirectiveAttribute } from '../AreBinding.attribute-
|
|
3
|
+
import { a as AreDirective, b as AreDirectiveAttribute } from '../AreBinding.attribute-GpT-5Qmf.js';
|
|
4
4
|
import { AreStore, AreScene, AreSyntax } from '@adaas/are';
|
|
5
5
|
import { AreDirectiveContext } from '../lib/AreDirective/AreDirective.context.js';
|
|
6
6
|
import '../lib/AreStyle/AreStyle.context.js';
|
|
@@ -27,7 +27,23 @@ import '@adaas/a-utils/a-execution';
|
|
|
27
27
|
declare class AreDirectiveIf extends AreDirective {
|
|
28
28
|
transform(attribute: AreDirectiveAttribute, scope: A_Scope, store: AreStore, scene: AreScene, logger: A_Logger, ...args: any[]): void;
|
|
29
29
|
compile(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, syntax: AreSyntax, directiveContext?: AreDirectiveContext, ...args: any[]): void;
|
|
30
|
-
update(attribute: AreDirectiveAttribute, store: AreStore, scope: A_Scope, syntax: AreSyntax, scene: AreScene, ...args: any[]): void;
|
|
30
|
+
update(attribute: AreDirectiveAttribute, store: AreStore, scope: A_Scope, syntax: AreSyntax, scene: AreScene, directiveContext?: AreDirectiveContext, ...args: any[]): void;
|
|
31
|
+
/**
|
|
32
|
+
* Evaluates the `$if` condition defensively.
|
|
33
|
+
*
|
|
34
|
+
* A condition can reference data that is momentarily unavailable — most
|
|
35
|
+
* commonly a nested `$if` (e.g. `$if="selected.fields.length"`) living
|
|
36
|
+
* inside a parent `$if="selected"` whose object has just become `null`.
|
|
37
|
+
* Because the nested directive is still subscribed to the store, its
|
|
38
|
+
* update fires on that same change and the raw expression would throw
|
|
39
|
+
* `Cannot read properties of null`, crashing the whole update pipeline.
|
|
40
|
+
*
|
|
41
|
+
* Treating an evaluation error as `false` is the correct contract for a
|
|
42
|
+
* conditional: if the condition cannot be resolved, the subtree simply
|
|
43
|
+
* stays hidden until the referenced data is present again (at which point
|
|
44
|
+
* the parent `$if` re-activates and re-evaluates this one).
|
|
45
|
+
*/
|
|
46
|
+
private evaluateCondition;
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
export { AreDirectiveIf };
|
|
@@ -35,9 +35,7 @@ exports.AreDirectiveIf = class AreDirectiveIf extends AreDirective_component.Are
|
|
|
35
35
|
attribute.template = ifTemplate;
|
|
36
36
|
}
|
|
37
37
|
compile(attribute, store, scene, syntax, directiveContext, ...args) {
|
|
38
|
-
attribute.value =
|
|
39
|
-
...directiveContext?.scope || {}
|
|
40
|
-
});
|
|
38
|
+
attribute.value = this.evaluateCondition(syntax, attribute, store, directiveContext);
|
|
41
39
|
const hostInstruction = scene.host;
|
|
42
40
|
const commentIdentifier = ` --- if: ${attribute.template.id} --- `;
|
|
43
41
|
const declaration = new AddComment_instruction.AddCommentInstruction({ content: commentIdentifier });
|
|
@@ -49,9 +47,9 @@ exports.AreDirectiveIf = class AreDirectiveIf extends AreDirective_component.Are
|
|
|
49
47
|
else
|
|
50
48
|
attribute.template.scene.deactivate();
|
|
51
49
|
}
|
|
52
|
-
update(attribute, store, scope, syntax, scene, ...args) {
|
|
50
|
+
update(attribute, store, scope, syntax, scene, directiveContext, ...args) {
|
|
53
51
|
const previous = !!attribute.value;
|
|
54
|
-
const next =
|
|
52
|
+
const next = this.evaluateCondition(syntax, attribute, store, directiveContext);
|
|
55
53
|
attribute.value = next;
|
|
56
54
|
if (previous === next) return;
|
|
57
55
|
if (next) {
|
|
@@ -62,6 +60,30 @@ exports.AreDirectiveIf = class AreDirectiveIf extends AreDirective_component.Are
|
|
|
62
60
|
attribute.template.scene.deactivate();
|
|
63
61
|
}
|
|
64
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Evaluates the `$if` condition defensively.
|
|
65
|
+
*
|
|
66
|
+
* A condition can reference data that is momentarily unavailable — most
|
|
67
|
+
* commonly a nested `$if` (e.g. `$if="selected.fields.length"`) living
|
|
68
|
+
* inside a parent `$if="selected"` whose object has just become `null`.
|
|
69
|
+
* Because the nested directive is still subscribed to the store, its
|
|
70
|
+
* update fires on that same change and the raw expression would throw
|
|
71
|
+
* `Cannot read properties of null`, crashing the whole update pipeline.
|
|
72
|
+
*
|
|
73
|
+
* Treating an evaluation error as `false` is the correct contract for a
|
|
74
|
+
* conditional: if the condition cannot be resolved, the subtree simply
|
|
75
|
+
* stays hidden until the referenced data is present again (at which point
|
|
76
|
+
* the parent `$if` re-activates and re-evaluates this one).
|
|
77
|
+
*/
|
|
78
|
+
evaluateCondition(syntax, attribute, store, directiveContext) {
|
|
79
|
+
try {
|
|
80
|
+
return !!syntax.evaluate(attribute.content, store, {
|
|
81
|
+
...directiveContext?.scope || {}
|
|
82
|
+
});
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
65
87
|
};
|
|
66
88
|
__decorateClass([
|
|
67
89
|
AreDirective_component.AreDirective.Transform,
|
|
@@ -85,7 +107,8 @@ __decorateClass([
|
|
|
85
107
|
__decorateParam(1, aConcept.A_Inject(are.AreStore)),
|
|
86
108
|
__decorateParam(2, aConcept.A_Inject(aConcept.A_Scope)),
|
|
87
109
|
__decorateParam(3, aConcept.A_Inject(are.AreSyntax)),
|
|
88
|
-
__decorateParam(4, aConcept.A_Inject(are.AreScene))
|
|
110
|
+
__decorateParam(4, aConcept.A_Inject(are.AreScene)),
|
|
111
|
+
__decorateParam(5, aConcept.A_Inject(AreDirective_context.AreDirectiveContext))
|
|
89
112
|
], exports.AreDirectiveIf.prototype, "update", 1);
|
|
90
113
|
exports.AreDirectiveIf = __decorateClass([
|
|
91
114
|
core.A_Frame.Define({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/directives/AreDirectiveIf.directive.ts"],"names":["AreDirectiveIf","AreDirective","AddCommentInstruction","A_Caller","A_Scope","AreStore","AreScene","A_Logger","AreSyntax","AreDirectiveContext","A_Frame"],"mappings":"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","file":"AreDirectiveIf.directive.js","sourcesContent":["import { A_Caller, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreScene, AreStore, AreSyntax } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AddCommentInstruction } from \"@adaas/are-html/instructions/AddComment.instruction\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\n\n\n\n/**\n * `$if` directive — conditionally renders a node based on an expression.\n *\n * ⚠️ Known limitation: do NOT use `$if` and `$for` on the SAME element.\n * Doing so produces duplicated DOM on toggle because the two directives\n * share an owner node and clone its scope independently. Wrap one in a\n * parent element instead, e.g.:\n *\n * <div $if=\"visible\">\n * <li $for=\"item in items\">{{item.name}}</li>\n * </div>\n *\n * or\n *\n * <ul $for=\"item in items\">\n * <li $if=\"item.visible\">{{item.name}}</li>\n * </ul>\n */\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $if directive. Conditionally renders a subtree based on a store expression. Replaces the target element with a stable comment anchor when the condition is false and restores the fully rendered subtree when it becomes true, preventing any leaking of the host element between states.'\n})\n@AreDirective.Priority(2)\nexport class AreDirectiveIf extends AreDirective {\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Scope) scope: A_Scope,\n\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n logger.debug(`[Transform] directive $IF for <${attribute.owner.aseid.toString()}>`)\n\n const node = attribute.owner;\n\n /**\n * We have to keep this node as a group node, and copy all data into the child node that would be actual node. \n */\n const ifTemplate = node.cloneWithScope();\n\n const ifAttr = ifTemplate.attributes.find(d => d.name === attribute.name);\n\n if (ifAttr) {\n ifTemplate.scope.deregister(ifAttr);\n node.scope.register(ifAttr);\n }\n\n node.init();\n\n node.addChild(ifTemplate);\n\n /**\n * Resolve or create a directive context for the item node. This is needed to hold the item-specific store values (e.g. the \"item\" and \"index\" in a \"for\" loop) that the template's bindings will reference during compile and update. The context is shared among all clones of the same template, but that's fine because each clone gets its own scope values assigned here.\n */\n // let directiveContext = ifTemplate.scope.resolveFlat(AreDirectiveContext);\n\n // if (!directiveContext) {\n // directiveContext = new AreDirectiveContext(ifTemplate.aseid);\n // ifTemplate.scope.register(directiveContext);\n // }\n\n ifTemplate.scene.deactivate();\n\n attribute.template = ifTemplate;\n\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(AreSyntax) syntax: AreSyntax,\n\n @A_Inject(AreDirectiveContext) directiveContext?: AreDirectiveContext,\n ...args: any[]\n ): void {\n /**\n * 1. Extract the value from the store based on the attribute content\n * (which is the path to the value in the store)\n */\n attribute.value = syntax.evaluate(attribute.content, store, {\n ...(directiveContext?.scope || {}),\n });\n\n /**\n * 2. If the value is falsy, remove the node from the scene by planning a RemoveElement instruction.\n * If the value is truthy, ensure the node is in the scene by planning an AddElement instruction if it's not already planned.\n */\n const hostInstruction = scene.host!;\n const commentIdentifier = ` --- if: ${attribute.template!.id} --- `;\n const declaration = new AddCommentInstruction({ content: commentIdentifier })\n\n scene.setHost(declaration);\n scene.planBefore(declaration, hostInstruction);\n scene.unPlan(hostInstruction);\n\n if (attribute.value)\n attribute.template!.scene.activate();\n else\n attribute.template!.scene.deactivate();\n }\n\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(A_Scope) scope: A_Scope,\n @A_Inject(AreSyntax) syntax: AreSyntax,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * 1. Extract the value from the store based on the attribute content\n * (which is the path to the value in the store)\n */\n const previous = !!attribute.value;\n const next = !!syntax.evaluate(attribute.content, store);\n attribute.value = next;\n\n // Skip when truthiness has not changed — avoids redundant mount/unmount.\n if (previous === next) return;\n\n if (next) {\n attribute.template!.scene.activate();\n attribute.template!.mount();\n } else {\n attribute.template!.unmount();\n attribute.template!.scene.deactivate();\n }\n }\n\n}"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/AreDirectiveIf.directive.ts"],"names":["AreDirectiveIf","AreDirective","AddCommentInstruction","A_Caller","A_Scope","AreStore","AreScene","A_Logger","AreSyntax","AreDirectiveContext","A_Frame"],"mappings":"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","file":"AreDirectiveIf.directive.js","sourcesContent":["import { A_Caller, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreScene, AreStore, AreSyntax } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AddCommentInstruction } from \"@adaas/are-html/instructions/AddComment.instruction\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\n\n\n\n/**\n * `$if` directive — conditionally renders a node based on an expression.\n *\n * ⚠️ Known limitation: do NOT use `$if` and `$for` on the SAME element.\n * Doing so produces duplicated DOM on toggle because the two directives\n * share an owner node and clone its scope independently. Wrap one in a\n * parent element instead, e.g.:\n *\n * <div $if=\"visible\">\n * <li $for=\"item in items\">{{item.name}}</li>\n * </div>\n *\n * or\n *\n * <ul $for=\"item in items\">\n * <li $if=\"item.visible\">{{item.name}}</li>\n * </ul>\n */\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $if directive. Conditionally renders a subtree based on a store expression. Replaces the target element with a stable comment anchor when the condition is false and restores the fully rendered subtree when it becomes true, preventing any leaking of the host element between states.'\n})\n@AreDirective.Priority(2)\nexport class AreDirectiveIf extends AreDirective {\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Scope) scope: A_Scope,\n\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n logger.debug(`[Transform] directive $IF for <${attribute.owner.aseid.toString()}>`)\n\n const node = attribute.owner;\n\n /**\n * We have to keep this node as a group node, and copy all data into the child node that would be actual node. \n */\n const ifTemplate = node.cloneWithScope();\n\n const ifAttr = ifTemplate.attributes.find(d => d.name === attribute.name);\n\n if (ifAttr) {\n ifTemplate.scope.deregister(ifAttr);\n node.scope.register(ifAttr);\n }\n\n node.init();\n\n node.addChild(ifTemplate);\n\n /**\n * Resolve or create a directive context for the item node. This is needed to hold the item-specific store values (e.g. the \"item\" and \"index\" in a \"for\" loop) that the template's bindings will reference during compile and update. The context is shared among all clones of the same template, but that's fine because each clone gets its own scope values assigned here.\n */\n // let directiveContext = ifTemplate.scope.resolveFlat(AreDirectiveContext);\n\n // if (!directiveContext) {\n // directiveContext = new AreDirectiveContext(ifTemplate.aseid);\n // ifTemplate.scope.register(directiveContext);\n // }\n\n ifTemplate.scene.deactivate();\n\n attribute.template = ifTemplate;\n\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(AreSyntax) syntax: AreSyntax,\n\n @A_Inject(AreDirectiveContext) directiveContext?: AreDirectiveContext,\n ...args: any[]\n ): void {\n /**\n * 1. Extract the value from the store based on the attribute content\n * (which is the path to the value in the store)\n */\n attribute.value = this.evaluateCondition(syntax, attribute, store, directiveContext);\n\n /**\n * 2. If the value is falsy, remove the node from the scene by planning a RemoveElement instruction.\n * If the value is truthy, ensure the node is in the scene by planning an AddElement instruction if it's not already planned.\n */\n const hostInstruction = scene.host!;\n const commentIdentifier = ` --- if: ${attribute.template!.id} --- `;\n const declaration = new AddCommentInstruction({ content: commentIdentifier })\n\n scene.setHost(declaration);\n scene.planBefore(declaration, hostInstruction);\n scene.unPlan(hostInstruction);\n\n if (attribute.value)\n attribute.template!.scene.activate();\n else\n attribute.template!.scene.deactivate();\n }\n\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(A_Scope) scope: A_Scope,\n @A_Inject(AreSyntax) syntax: AreSyntax,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(AreDirectiveContext) directiveContext?: AreDirectiveContext,\n ...args: any[]\n ): void {\n /**\n * 1. Extract the value from the store based on the attribute content\n * (which is the path to the value in the store)\n */\n const previous = !!attribute.value;\n const next = this.evaluateCondition(syntax, attribute, store, directiveContext);\n attribute.value = next;\n\n // Skip when truthiness has not changed — avoids redundant mount/unmount.\n if (previous === next) return;\n\n if (next) {\n attribute.template!.scene.activate();\n attribute.template!.mount();\n } else {\n attribute.template!.unmount();\n attribute.template!.scene.deactivate();\n }\n }\n\n /**\n * Evaluates the `$if` condition defensively.\n *\n * A condition can reference data that is momentarily unavailable — most\n * commonly a nested `$if` (e.g. `$if=\"selected.fields.length\"`) living\n * inside a parent `$if=\"selected\"` whose object has just become `null`.\n * Because the nested directive is still subscribed to the store, its\n * update fires on that same change and the raw expression would throw\n * `Cannot read properties of null`, crashing the whole update pipeline.\n *\n * Treating an evaluation error as `false` is the correct contract for a\n * conditional: if the condition cannot be resolved, the subtree simply\n * stays hidden until the referenced data is present again (at which point\n * the parent `$if` re-activates and re-evaluates this one).\n */\n private evaluateCondition(\n syntax: AreSyntax,\n attribute: AreDirectiveAttribute,\n store: AreStore,\n directiveContext?: AreDirectiveContext,\n ): boolean {\n try {\n return !!syntax.evaluate(attribute.content, store, {\n ...(directiveContext?.scope || {}),\n });\n } catch {\n return false;\n }\n }\n\n}"]}
|
|
@@ -23,9 +23,7 @@ let AreDirectiveIf = class extends AreDirective {
|
|
|
23
23
|
attribute.template = ifTemplate;
|
|
24
24
|
}
|
|
25
25
|
compile(attribute, store, scene, syntax, directiveContext, ...args) {
|
|
26
|
-
attribute.value =
|
|
27
|
-
...directiveContext?.scope || {}
|
|
28
|
-
});
|
|
26
|
+
attribute.value = this.evaluateCondition(syntax, attribute, store, directiveContext);
|
|
29
27
|
const hostInstruction = scene.host;
|
|
30
28
|
const commentIdentifier = ` --- if: ${attribute.template.id} --- `;
|
|
31
29
|
const declaration = new AddCommentInstruction({ content: commentIdentifier });
|
|
@@ -37,9 +35,9 @@ let AreDirectiveIf = class extends AreDirective {
|
|
|
37
35
|
else
|
|
38
36
|
attribute.template.scene.deactivate();
|
|
39
37
|
}
|
|
40
|
-
update(attribute, store, scope, syntax, scene, ...args) {
|
|
38
|
+
update(attribute, store, scope, syntax, scene, directiveContext, ...args) {
|
|
41
39
|
const previous = !!attribute.value;
|
|
42
|
-
const next =
|
|
40
|
+
const next = this.evaluateCondition(syntax, attribute, store, directiveContext);
|
|
43
41
|
attribute.value = next;
|
|
44
42
|
if (previous === next) return;
|
|
45
43
|
if (next) {
|
|
@@ -50,6 +48,30 @@ let AreDirectiveIf = class extends AreDirective {
|
|
|
50
48
|
attribute.template.scene.deactivate();
|
|
51
49
|
}
|
|
52
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Evaluates the `$if` condition defensively.
|
|
53
|
+
*
|
|
54
|
+
* A condition can reference data that is momentarily unavailable — most
|
|
55
|
+
* commonly a nested `$if` (e.g. `$if="selected.fields.length"`) living
|
|
56
|
+
* inside a parent `$if="selected"` whose object has just become `null`.
|
|
57
|
+
* Because the nested directive is still subscribed to the store, its
|
|
58
|
+
* update fires on that same change and the raw expression would throw
|
|
59
|
+
* `Cannot read properties of null`, crashing the whole update pipeline.
|
|
60
|
+
*
|
|
61
|
+
* Treating an evaluation error as `false` is the correct contract for a
|
|
62
|
+
* conditional: if the condition cannot be resolved, the subtree simply
|
|
63
|
+
* stays hidden until the referenced data is present again (at which point
|
|
64
|
+
* the parent `$if` re-activates and re-evaluates this one).
|
|
65
|
+
*/
|
|
66
|
+
evaluateCondition(syntax, attribute, store, directiveContext) {
|
|
67
|
+
try {
|
|
68
|
+
return !!syntax.evaluate(attribute.content, store, {
|
|
69
|
+
...directiveContext?.scope || {}
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
53
75
|
};
|
|
54
76
|
__decorateClass([
|
|
55
77
|
AreDirective.Transform,
|
|
@@ -73,7 +95,8 @@ __decorateClass([
|
|
|
73
95
|
__decorateParam(1, A_Inject(AreStore)),
|
|
74
96
|
__decorateParam(2, A_Inject(A_Scope)),
|
|
75
97
|
__decorateParam(3, A_Inject(AreSyntax)),
|
|
76
|
-
__decorateParam(4, A_Inject(AreScene))
|
|
98
|
+
__decorateParam(4, A_Inject(AreScene)),
|
|
99
|
+
__decorateParam(5, A_Inject(AreDirectiveContext))
|
|
77
100
|
], AreDirectiveIf.prototype, "update", 1);
|
|
78
101
|
AreDirectiveIf = __decorateClass([
|
|
79
102
|
A_Frame.Define({
|