feat: flatten conditionals and loops into parent scope

This commit is contained in:
Michael Rawlings 2021-07-02 19:32:12 -07:00
parent 96fbeaf260
commit f97a8262b9
No known key found for this signature in database
GPG Key ID: B9088328804D407C
21 changed files with 349 additions and 415 deletions

View File

@ -6,9 +6,9 @@
{
"name": "*",
"individual": {
"min": 10252,
"gzip": 4379,
"brotli": 3991
"min": 9959,
"gzip": 4316,
"brotli": 3947
}
}
]

View File

@ -5,74 +5,94 @@ import {
Scope,
createScope,
getEmptyScope,
set,
destroyScope,
read,
runWithScope
runWithScope,
write
} from "./scope";
import { NodeType } from "./dom";
export type Conditional = (
| {
scope: Scope;
renderer: Renderer;
}
| {
scope: undefined;
renderer: undefined;
}
) & {
___referenceNode: Comment | Element;
___context: typeof Context;
___getFirstNode: () => Node;
___getLastNode: () => Node;
};
export function conditional(referenceNode: Comment | Element): Conditional {
return {
scope: undefined,
renderer: undefined,
___referenceNode: referenceNode,
___context: Context,
___getFirstNode: getFirstNodeConditional,
___getLastNode: getLastNodeConditional
};
const enum ConditionalIndex {
REFERENCE_NODE = 0,
SCOPE = 1,
RENDERER = 2,
CONTEXT = 3
}
type Conditional = {
[ConditionalIndex.REFERENCE_NODE]: Element | Comment;
[ConditionalIndex.SCOPE]: Scope;
[ConditionalIndex.RENDERER]: Renderer;
[ConditionalIndex.CONTEXT]: typeof Context;
};
export function runInBranch(
conditionalIndex: number,
branch: Renderer,
fn: () => void
) {
const cond = read(conditionalIndex) as Conditional;
if (cond.renderer === branch) {
runWithScope(fn, 0, cond.scope!);
if (read(conditionalIndex + ConditionalIndex.RENDERER) === branch) {
runWithScope(
fn,
0,
read(conditionalIndex + ConditionalIndex.SCOPE) as Scope
);
return 1;
}
}
export function getConditionalFirstNode(
this: Scope,
conditionalIndex: number = this.___startNode as number,
last?: boolean
) {
const scope = this[conditionalIndex + ConditionalIndex.SCOPE] as Scope;
return scope
? scope[last ? "___getLastNode" : "___getFirstNode"]()
: (this[conditionalIndex + ConditionalIndex.REFERENCE_NODE] as Comment);
}
export function getConditionalLastNode(this: Scope) {
return getConditionalFirstNode.call(this, this.___endNode as number, true);
}
export function setConditionalRenderer(
conditionalIndex: number,
newRenderer: Renderer | undefined
) {
const conditonal = read(conditionalIndex) as Conditional;
if (conditonal.renderer !== (conditonal.renderer = newRenderer)) {
if (read(conditionalIndex + ConditionalIndex.RENDERER) !== newRenderer) {
write(conditionalIndex + ConditionalIndex.RENDERER, newRenderer);
let newScope: Scope;
let prevScope = conditonal.scope!;
let prevScope = read<Conditional, ConditionalIndex.SCOPE>(
conditionalIndex + ConditionalIndex.SCOPE
);
if (newRenderer) {
setContext(conditonal.___context);
newScope = conditonal.scope = createScope(
newRenderer.___size,
newRenderer.___domMethods!
setContext(
read(conditionalIndex + ConditionalIndex.CONTEXT) as typeof Context
);
write(
conditionalIndex + ConditionalIndex.SCOPE,
(newScope = createScope(
newRenderer.___size,
newRenderer.___domMethods!
))
);
initRenderer(newRenderer, newScope);
prevScope =
prevScope || getEmptyScope(conditonal.___referenceNode as Comment);
prevScope ||
getEmptyScope(
read<Conditional, ConditionalIndex.REFERENCE_NODE>(
conditionalIndex + ConditionalIndex.REFERENCE_NODE
) as Comment
);
setContext(null);
} else {
newScope = getEmptyScope(conditonal.___referenceNode as Comment);
conditonal.scope = undefined;
newScope = getEmptyScope(
read<Conditional, ConditionalIndex.REFERENCE_NODE>(
conditionalIndex + ConditionalIndex.REFERENCE_NODE
) as Comment
);
write(conditionalIndex + ConditionalIndex.SCOPE, undefined);
}
newScope.___insertBefore(
@ -87,128 +107,118 @@ export function setConditionalRendererOnlyChild(
conditionalIndex: number,
newRenderer: Renderer | undefined
) {
const conditonal = read(conditionalIndex) as Conditional;
if (conditonal.renderer !== (conditonal.renderer = newRenderer)) {
(conditonal.___referenceNode as Element).textContent = "";
if (read(conditionalIndex + ConditionalIndex.RENDERER) !== newRenderer) {
write(conditionalIndex + ConditionalIndex.RENDERER, newRenderer);
const referenceNode = read<Conditional, ConditionalIndex.REFERENCE_NODE>(
conditionalIndex + ConditionalIndex.REFERENCE_NODE
) as Element;
referenceNode.textContent = "";
if (newRenderer) {
setContext(conditonal.___context);
const newScope = (conditonal.scope = createScope(
newRenderer.___size,
newRenderer.___domMethods!
));
setContext(
read(conditionalIndex + ConditionalIndex.CONTEXT) as typeof Context
);
let newScope: Scope;
write(
conditionalIndex + ConditionalIndex.SCOPE,
(newScope = createScope(
newRenderer.___size,
newRenderer.___domMethods!
))
);
initRenderer(newRenderer, newScope);
newScope.___insertBefore(conditonal.___referenceNode as Element, null);
newScope.___insertBefore(referenceNode, null);
setContext(null);
}
}
}
function getFirstNodeConditional(this: Conditional) {
return this.scope
? this.scope.___getFirstNode()
: (this.___referenceNode as Comment);
}
function getLastNodeConditional(this: Conditional) {
return this.scope
? this.scope.___getLastNode()
: (this.___referenceNode as Comment);
}
const emptyMarkerMap = new Map();
const emptyMarkerArray = [getEmptyScope()];
emptyMarkerMap.set(Symbol("empty"), getEmptyScope());
const emptyMap = new Map();
const emptyArray = [];
export type Loop = {
___scopeMap: Map<unknown, Scope>;
___scopeArray: Scope[];
___referenceNode: Comment | Element;
___referenceIsMarker: boolean;
___renderer: Renderer;
___keyFn: undefined | ((item: unknown, index: number) => unknown);
___context: typeof Context;
___getFirstNode: () => Node;
___getLastNode: () => Node;
[Symbol.iterator]: () => IterableIterator<Scope>;
};
export function loop(
referenceNode: Comment | Element,
renderer: Renderer,
keyFn: (item: unknown) => unknown
): Loop {
const referenceIsMarker = referenceNode.nodeType === NodeType.Comment;
return {
___scopeMap: referenceIsMarker ? emptyMarkerMap : emptyMap,
___scopeArray: referenceIsMarker ? emptyMarkerArray : emptyArray,
___referenceNode: referenceNode,
___referenceIsMarker: referenceIsMarker,
___renderer: renderer,
___keyFn: keyFn,
___context: Context,
___getFirstNode: getFirstNodeLoop,
___getLastNode: getLastNodeLoop,
[Symbol.iterator]: loopIterator
};
const enum LoopIndex {
REFERENCE_NODE = 0,
SCOPE_MAP = 1,
SCOPE_ARRAY = 2,
CONTEXT = 3
}
type Loop = {
[LoopIndex.REFERENCE_NODE]: Element | Comment;
[LoopIndex.SCOPE_MAP]: Map<unknown, Scope>;
[LoopIndex.SCOPE_ARRAY]: Scope[];
[LoopIndex.CONTEXT]: typeof Context;
};
export function runForEach(loopIndex: number, fn: () => void) {
for (const scope of (read(loopIndex) as Loop).___scopeArray) {
for (const scope of read<Loop, LoopIndex.SCOPE_ARRAY>(
loopIndex + LoopIndex.SCOPE_ARRAY
)) {
runWithScope(fn, 0, scope);
}
}
function loopIterator(this: Loop) {
return (this.___scopeArray === emptyMarkerArray
? emptyArray
: this.___scopeArray
).values();
export function getLoopFirstNode(
this: Scope,
loopIndex: number = this.___startNode as number,
last?: boolean
) {
const scopes = this[loopIndex + LoopIndex.SCOPE_ARRAY] as Scope[];
return scopes === emptyMarkerArray
? (this[loopIndex + LoopIndex.REFERENCE_NODE] as Comment)
: scopes[last ? scopes.length - 1 : 0][
last ? "___getLastNode" : "___getFirstNode"
]();
}
function getFirstNodeLoop(this: Loop) {
return this.___scopeArray[0].___getFirstNode();
export function getLoopLastNode(this: Scope) {
return getLoopFirstNode.call(this, this.___endNode as number, true);
}
function getLastNodeLoop(this: Loop) {
return this.___scopeArray[this.___scopeArray.length - 1].___getLastNode();
}
export function setLoopOf(loopIndex: number, newValues: unknown[]) {
const loop = read(loopIndex) as Loop;
export function setLoopOf(
loopIndex: number,
newValues: unknown[],
renderer: Renderer,
keyFn?: (item: unknown) => unknown
) {
let newMap: Map<unknown, Scope>;
let newArray: Scope[];
const len = newValues.length;
const oldMap = loop.___scopeMap;
const oldArray = loop.___scopeArray;
const referenceNode = read<Loop, LoopIndex.REFERENCE_NODE>(
loopIndex + LoopIndex.REFERENCE_NODE
);
const referenceIsMarker = referenceNode.nodeType === 8; /* Comment */
const oldMap =
read<Loop, LoopIndex.SCOPE_MAP>(loopIndex + LoopIndex.SCOPE_MAP) ||
(referenceIsMarker ? emptyMarkerMap : emptyMap);
const oldArray =
read<Loop, LoopIndex.SCOPE_ARRAY>(loopIndex + LoopIndex.SCOPE_ARRAY) ||
(referenceIsMarker ? emptyMarkerArray : emptyArray);
let inserts = 0;
let moves = 0;
const referenceIsMarker = loop.___referenceIsMarker;
let afterReference: Node | null;
let parentNode: Node & ParentNode;
if (len > 0) {
newMap = new Map();
setContext(loop.___context);
setContext(read(loopIndex + LoopIndex.CONTEXT) as typeof Context);
for (let index = 0; index < len; index++) {
const item = newValues[index];
const key = loop.___keyFn ? loop.___keyFn(item, index) : "" + index;
const key = keyFn ? keyFn(item) : index;
let childScope = oldMap.get(key);
if (!childScope) {
childScope = createScope(
loop.___renderer.___size,
loop.___renderer.___domMethods!
);
childScope = createScope(renderer.___size, renderer.___domMethods!);
childScope[0] = item;
childScope[1] = index;
initRenderer(loop.___renderer, childScope);
initRenderer(renderer, childScope);
inserts++;
} else {
if (childScope[1] !== index) moves++;
set(childScope, 0, item);
set(childScope, 1, index);
write(0, item, childScope, 0);
write(1, index, childScope, 0);
}
newMap.set(key, childScope);
}
@ -218,16 +228,16 @@ export function setLoopOf(loopIndex: number, newValues: unknown[]) {
if (referenceIsMarker) {
newMap = emptyMarkerMap;
newArray = emptyMarkerArray;
getEmptyScope(loop.___referenceNode as Comment);
getEmptyScope(referenceNode as Comment);
} else {
if (loop.___renderer.___hasUserEffects) {
if (renderer.___hasUserEffects) {
for (let i = 0; i < oldArray.length; i++) {
destroyScope(oldArray[i]);
}
}
loop.___referenceNode.textContent = "";
loop.___scopeMap = emptyMap;
loop.___scopeArray = emptyArray;
referenceNode.textContent = "";
write(loopIndex + LoopIndex.SCOPE_MAP, emptyMap);
write(loopIndex + LoopIndex.SCOPE_ARRAY, emptyArray);
return;
}
}
@ -235,28 +245,29 @@ export function setLoopOf(loopIndex: number, newValues: unknown[]) {
if (inserts || moves || len !== oldArray.length) {
if (referenceIsMarker) {
if (oldMap === emptyMarkerMap) {
getEmptyScope(loop.___referenceNode as Comment);
getEmptyScope(referenceNode as Comment);
}
const oldLastChild = oldArray[oldArray.length - 1];
afterReference = oldLastChild.___getAfterNode();
parentNode = oldLastChild.___getParentNode();
} else {
afterReference = null;
parentNode = loop.___referenceNode as Element;
parentNode = referenceNode as Element;
}
reconcile(parentNode, oldArray, newArray!, afterReference);
}
loop.___scopeArray = newArray!;
loop.___scopeMap = newMap!;
write(loopIndex + LoopIndex.SCOPE_MAP, newMap);
write(loopIndex + LoopIndex.SCOPE_ARRAY, newArray);
}
export function setLoopFromTo(
loopIndex: number,
from: number,
to: number,
step: number
step: number,
renderer: Renderer
) {
const range: number[] = [];
@ -264,9 +275,21 @@ export function setLoopFromTo(
range.push(i);
}
setLoopOf(loopIndex, range);
setLoopOf(loopIndex, range, renderer, keyFromTo);
}
export function setLoopIn(loopIndex: number, object: Record<string, unknown>) {
setLoopOf(loopIndex, Object.entries(object));
function keyFromTo(item: unknown) {
return item;
}
export function setLoopIn(
loopIndex: number,
object: Record<string, unknown>,
renderer: Renderer
) {
setLoopOf(loopIndex, Object.entries(object), renderer, keyIn);
}
function keyIn(item: [string, unknown]) {
return item[0];
}

View File

@ -1,6 +1,5 @@
import { Conditional, Loop } from "./control-flow";
import { Renderer } from "./renderer";
import { onDestroy, Scope, bind, read, write } from "./scope";
import { onDestroy, Scope, read, write } from "./scope";
export const enum NodeType {
Element = 1,
@ -66,7 +65,7 @@ export const staticNodeMethods = {
// }
// };
export const staticFragmentMethods = {
export const fragmentMethods = {
...staticNodeMethods,
___insertBefore(parent, nextSibling) {
let current: Node = this.___getFirstNode();
@ -88,30 +87,6 @@ export const staticFragmentMethods = {
}
} as DOMMethods;
export const dynamicStartFragmentMethods = {
...staticFragmentMethods,
___getFirstNode() {
return (this.___startNode as Conditional | Loop).___getFirstNode();
}
} as DOMMethods;
export const dynamicEndFragmentMethods = {
...staticFragmentMethods,
___getLastNode() {
return (this.___endNode as Conditional | Loop).___getLastNode();
}
} as DOMMethods;
export const dynamicFragmentMethods = {
...staticFragmentMethods,
___getFirstNode() {
return (this.___startNode as Conditional | Loop).___getFirstNode();
},
___getLastNode() {
return (this.___endNode as Conditional | Loop).___getLastNode();
}
} as DOMMethods;
export function isDocumentFragment(node: Node): node is DocumentFragment {
return node.nodeType === NodeType.DocumentFragment;
}

View File

@ -1,14 +1,14 @@
export {
Conditional,
Loop,
conditional,
setConditionalRenderer,
setConditionalRendererOnlyChild,
getConditionalFirstNode,
getConditionalLastNode,
runInBranch,
loop,
setLoopOf,
setLoopFromTo,
setLoopIn,
getLoopFirstNode,
getLoopLastNode,
runForEach
} from "./control-flow";
@ -21,8 +21,7 @@ export {
props,
dynamicTag,
staticNodeMethods,
staticFragmentMethods,
dynamicFragmentMethods,
fragmentMethods,
userEffect
} from "./dom";

View File

@ -1,5 +1,4 @@
import { Conditional, Loop } from "./control-flow";
import { DOMMethods } from "./dom";
import { DOMMethods, staticNodeMethods } from "./dom";
import { createScope, Scope, cleanScopes, runWithScope } from "./scope";
import { WalkCodes, detachedWalk } from "./walker";
@ -19,7 +18,9 @@ export type Renderer = {
___hasUserEffects: 0 | 1;
___sourceNode: Node | undefined;
___domMethods: DOMMethods | undefined;
___dynamicStartNodeMethod: ((this: Scope) => Node & ChildNode) | undefined;
___dynamicStartNodeOffset: number | undefined;
___dynamicEndNodeMethod: ((this: Scope) => Node & ChildNode) | undefined;
___dynamicEndNodeOffset: number | undefined;
};
@ -47,15 +48,13 @@ export function initRenderer(renderer: Renderer, scope: Scope) {
scope.___endNode =
dom.nodeType === NodeType.DocumentFragment ? dom.lastChild! : dom;
detachedWalk(scope.___startNode, renderer, scope);
if (renderer.___dynamicStartNodeOffset !== undefined) {
scope.___startNode = scope[renderer.___dynamicStartNodeOffset] as
| Conditional
| Loop;
if (renderer.___dynamicStartNodeMethod) {
scope.___getFirstNode = renderer.___dynamicStartNodeMethod;
scope.___startNode = renderer.___dynamicStartNodeOffset!;
}
if (renderer.___dynamicEndNodeOffset !== undefined) {
scope.___endNode = scope[renderer.___dynamicEndNodeOffset] as
| Conditional
| Loop;
if (renderer.___dynamicEndNodeMethod) {
scope.___getLastNode = renderer.___dynamicEndNodeMethod;
scope.___endNode = renderer.___dynamicEndNodeOffset!;
}
return dom;
}
@ -66,9 +65,11 @@ export function createRenderFn<I extends Input>(
hydrate?: HydrateFn,
size?: number,
dynamicInput?: DynamicInputFn<I>,
domMethods?: DOMMethods,
hasUserEffects?: 0 | 1,
domMethods?: DOMMethods,
dynamicStartNodeMethod?: (this: Scope) => Node & ChildNode,
dynamicStartNodeOffset?: number,
dynamicEndNodeMethod?: (this: Scope) => Node & ChildNode,
dynamicEndNodeOffset?: number
) {
const renderer = createRenderer(
@ -76,9 +77,11 @@ export function createRenderFn<I extends Input>(
walks,
hydrate,
size,
domMethods,
hasUserEffects,
domMethods,
dynamicStartNodeMethod,
dynamicStartNodeOffset,
dynamicEndNodeMethod,
dynamicEndNodeOffset
);
return (input: I): RenderResult => {
@ -104,10 +107,12 @@ export function createRenderer<H extends HydrateFn>(
template: string,
walks?: string,
hydrate?: H,
size?: number,
domMethods?: DOMMethods,
hasUserEffects?: 0 | 1,
size = 0,
hasUserEffects: 0 | 1 = 0,
domMethods: DOMMethods = staticNodeMethods,
dynamicStartNodeMethod?: (this: Scope) => Node & ChildNode,
dynamicStartNodeOffset?: number,
dynamicEndNodeMethod?: (this: Scope) => Node & ChildNode,
dynamicEndNodeOffset?: number
): Renderer {
return {
@ -115,11 +120,13 @@ export function createRenderer<H extends HydrateFn>(
___walks: walks,
___hydrate: hydrate,
___clone: _clone,
___size: size || 0,
___hasUserEffects: hasUserEffects || 0,
___size: size,
___hasUserEffects: hasUserEffects,
___sourceNode: undefined,
___domMethods: domMethods,
___dynamicStartNodeMethod: dynamicStartNodeMethod,
___dynamicStartNodeOffset: dynamicStartNodeOffset,
___dynamicEndNodeMethod: dynamicEndNodeMethod,
___dynamicEndNodeOffset: dynamicEndNodeOffset
};
}

View File

@ -1,4 +1,3 @@
import { Conditional, Loop } from "./control-flow";
import { DOMMethods, staticNodeMethods } from "./dom";
import { setQueued } from "./queue";
@ -12,8 +11,8 @@ export type Scope = unknown[] &
DOMMethods & {
___parentScope: Scope | undefined;
___parentOffset: number | undefined;
___startNode: Conditional | Loop | Node | undefined;
___endNode: Conditional | Loop | Node | undefined;
___startNode: Node | number | undefined;
___endNode: Node | number | undefined;
___dirty: Record<number, true> | true | undefined;
___cleanup: Set<number | Scope> | undefined;
};

View File

@ -50,7 +50,7 @@ export function walkMany(scope: Scope, offset: number, count: number) {
export let walk = walkNormal;
// TODO: in some cases (including hydrate) we may get an existing node
// ideally we wouldn't create the newNode unless it was actually needed
function walkNormal<T extends Node>(newNode?: T) {
function walkNormal() {
if ("MARKO_DEBUG" && !currentWalks) {
throw new Error("Missing encoded walk string");
}
@ -83,7 +83,7 @@ function walkNormal<T extends Node>(newNode?: T) {
if ("MARKO_DEBUG" && extendedWalk === undefined) {
throw new Error("Extended walk was not enabled");
}
return extendedWalk(value, newNode);
return extendedWalk(value);
}
}
}
@ -93,8 +93,8 @@ export function enableExtendedWalk() {
}
let extendedWalk: typeof actualExtendedWalk;
function actualExtendedWalk<T extends Node>(value: number, newNode?: T) {
newNode = newNode || ((document.createTextNode("") as unknown) as T);
function actualExtendedWalk(value: number) {
const newNode = document.createTextNode("");
const current = walker.currentNode;
if (value === WalkCodes.Inside) {

View File

@ -1,8 +1,6 @@
import {
on,
walk,
conditional,
Conditional,
register,
createRenderer,
createRenderFn,
@ -10,7 +8,6 @@ import {
data,
queue,
ensureDelegated,
staticNodeMethods,
write,
read,
bind,
@ -29,18 +26,18 @@ export const inputs = [{}, click] as const;
const enum Index {
BUTTON = 0,
COMMENT = 1,
SHOW = 2,
MESSAGE = 3,
CONDITIONAL = 4
SHOW = 1,
MESSAGE = 2,
COMMENT = 3,
CONDITIONAL = 3
}
type scope = {
[Index.BUTTON]: HTMLButtonElement;
[Index.COMMENT]: Comment;
[Index.SHOW]: boolean;
[Index.MESSAGE]: string;
[Index.CONDITIONAL]: Conditional;
[Index.COMMENT]: Comment;
[Index.CONDITIONAL]: Comment;
};
// <let/show = true/>
@ -63,7 +60,7 @@ export const hydrate = register("", () => {
queue(execShowMessage);
})
);
write(Index.CONDITIONAL, conditional(walk() as Comment));
write(Index.COMMENT, walk());
execShowMessage();
});
@ -100,6 +97,5 @@ const branch0 = createRenderer(
() => {
write(Branch0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);

View File

@ -1,13 +1,10 @@
import {
walk,
data,
loop,
setLoopFromTo,
Loop,
createRenderer,
createRenderFn,
isDirty,
staticNodeMethods,
write,
read,
runForEach
@ -35,19 +32,19 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
DIV = 0,
INPUT_FROM = 1,
INPUT_TO = 2,
INPUT_STEP = 3,
LOOP = 4
INPUT_FROM = 0,
INPUT_TO = 1,
INPUT_STEP = 2,
DIV = 3,
LOOP = 3
}
type scope = {
[Index.DIV]: HTMLDivElement;
[Index.INPUT_FROM]: Input["from"];
[Index.INPUT_TO]: Input["to"];
[Index.INPUT_STEP]: Input["step"];
[Index.LOOP]: Loop;
[Index.DIV]: HTMLDivElement;
[Index.LOOP]: HTMLDivElement;
};
// <div>
@ -59,10 +56,7 @@ type scope = {
export const template = `<div></div>`;
export const walks = get + over(1);
export const hydrate = () => {
write(
Index.LOOP,
loop(walk() as Comment, iter0, i => i)
);
write(Index.DIV, walk());
};
export const execInputFromToStep = () => {
@ -70,7 +64,8 @@ export const execInputFromToStep = () => {
Index.LOOP,
read<scope, Index.INPUT_FROM>(Index.INPUT_FROM),
read<scope, Index.INPUT_TO>(Index.INPUT_TO),
read<scope, Index.INPUT_STEP>(Index.INPUT_STEP)
read<scope, Index.INPUT_STEP>(Index.INPUT_STEP),
iter0
);
runForEach(Index.LOOP, iter0_execItem);
};
@ -99,8 +94,7 @@ const iter0 = createRenderer(
() => {
write(Iter0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);
const iter0_execItem = () => {

View File

@ -1,15 +1,12 @@
import {
walk,
data,
loop,
read,
write,
setLoopIn,
Loop,
createRenderer,
createRenderFn,
isDirty,
staticNodeMethods,
runForEach
} from "../../../../src/dom/index";
import { over, get, next } from "../../utils/walks";
@ -37,15 +34,15 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
DIV = 0,
INPUT_CHILDREN = 1,
LOOP = 2
INPUT_CHILDREN = 0,
DIV = 1,
LOOP = 1
}
type scope = {
[Index.DIV]: HTMLDivElement;
[Index.INPUT_CHILDREN]: Input["children"];
[Index.LOOP]: Loop;
[Index.DIV]: HTMLDivElement;
[Index.LOOP]: HTMLDivElement;
};
// <div>
@ -57,16 +54,14 @@ type scope = {
export const template = `<div></div>`;
export const walks = get + over(1);
export const hydrate = () => {
write(
Index.LOOP,
loop(walk() as HTMLDivElement, iter0, item => item[0])
);
write(Index.DIV, walk());
};
export const execInputChildren = () => {
setLoopIn(
Index.LOOP,
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN)
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN),
iter0
);
runForEach(Index.LOOP, iter0_execItem);
};
@ -103,8 +98,7 @@ const iter0 = createRenderer(
() => {
write(Iter0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);
const iter0_execItem = () => {

View File

@ -1,16 +1,13 @@
import {
walk,
data,
loop,
read,
write,
setLoopOf,
Loop,
createRenderer,
createRenderFn,
isDirty,
runForEach,
staticNodeMethods
runForEach
} from "../../../../src/dom/index";
import { next, over, get } from "../../utils/walks";
@ -55,15 +52,15 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
DIV = 0,
INPUT_CHILDREN = 1,
LOOP = 2
INPUT_CHILDREN = 0,
DIV = 1,
LOOP = 1
}
type scope = {
[Index.DIV]: HTMLDivElement;
[Index.INPUT_CHILDREN]: Input["children"];
[Index.LOOP]: Loop;
[Index.DIV]: HTMLDivElement;
[Index.LOOP]: HTMLDivElement;
};
// <div>
@ -75,20 +72,15 @@ type scope = {
export const template = `<div></div>`;
export const walks = get + over(1);
export const hydrate = () => {
write(
Index.LOOP,
loop(
walk() as HTMLDivElement,
iter0,
i => "" + (i as Input["children"][number]).id
)
);
write(Index.DIV, walk());
};
export const execInputChildren = () => {
setLoopOf(
Index.LOOP,
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN)
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN),
iter0,
i => "" + (i as Input["children"][number]).id
);
runForEach(Index.LOOP, iter0_execItem);
};
@ -122,8 +114,7 @@ const iter0 = createRenderer(
() => {
write(Iter0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);
const iter0_execItem = () => {

View File

@ -1,14 +1,11 @@
import {
walk,
data,
loop,
read,
write,
setLoopOf,
Loop,
createRenderer,
createRenderFn,
staticNodeMethods,
isDirty,
runForEach
} from "../../../../src/dom/index";
@ -55,15 +52,15 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
DIV = 0,
INPUT_CHILDREN = 1,
LOOP = 2
INPUT_CHILDREN = 0,
DIV = 1,
LOOP = 1
}
type scope = {
[Index.DIV]: HTMLDivElement;
[Index.INPUT_CHILDREN]: Input["children"];
[Index.LOOP]: Loop;
[Index.DIV]: HTMLDivElement;
[Index.LOOP]: HTMLDivElement;
};
// <div>
@ -75,20 +72,15 @@ type scope = {
export const template = `<div></div>`;
export const walks = get + over(1);
export const hydrate = () => {
write(
Index.LOOP,
loop(
walk() as HTMLDivElement,
iter0,
i => "" + (i as Input["children"][number]).id
)
);
write(Index.DIV, walk());
};
export const execInputChildren = () => {
setLoopOf(
Index.LOOP,
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN)
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN),
iter0,
i => "" + (i as Input["children"][number]).id
);
runForEach(Index.LOOP, iter0_execItem);
};
@ -122,8 +114,7 @@ const iter0 = createRenderer(
() => {
write(Iter0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);
const iter0_execItem = () => {

View File

@ -1,15 +1,12 @@
import {
walk,
data,
loop,
read,
write,
setLoopOf,
Loop,
isDirty,
createRenderer,
createRenderFn,
staticNodeMethods,
runForEach
} from "../../../../src/dom/index";
import { next, over, get } from "../../utils/walks";
@ -55,15 +52,15 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
COMMENT = 0,
INPUT_CHILDREN = 1,
LOOP = 2
INPUT_CHILDREN = 0,
COMMENT = 1,
LOOP = 1
}
type scope = {
[Index.COMMENT]: Comment;
[Index.INPUT_CHILDREN]: Input["children"];
[Index.LOOP]: Loop;
[Index.COMMENT]: Comment;
[Index.LOOP]: Comment;
};
// <for|child| of=input.children by(c) { return c.id }>
@ -73,20 +70,15 @@ type scope = {
export const template = `<!>`;
export const walks = get + over(1);
export const hydrate = () => {
write(
Index.LOOP,
loop(
walk() as Comment,
iter0,
i => "" + (i as Input["children"][number]).id
)
);
write(Index.COMMENT, walk());
};
export const execInputChildren = () => {
setLoopOf(
Index.LOOP,
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN)
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN),
iter0,
i => "" + (i as Input["children"][number]).id
);
runForEach(Index.LOOP, iter0_execItem);
};
@ -120,8 +112,7 @@ const iter0 = createRenderer(
() => {
write(Iter0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);
const iter0_execItem = () => {

View File

@ -1,15 +1,12 @@
import {
walk,
data,
loop,
read,
write,
setLoopOf,
Loop,
isDirty,
createRenderer,
createRenderFn,
staticNodeMethods,
runForEach
} from "../../../../src/dom/index";
import { get, next } from "../../utils/walks";
@ -60,15 +57,15 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
DIV = 0,
INPUT_CHILDREN = 1,
LOOP = 2
INPUT_CHILDREN = 0,
DIV = 1,
LOOP = 1
}
type scope = {
[Index.DIV]: HTMLDivElement;
[Index.INPUT_CHILDREN]: Input["children"];
[Index.LOOP]: Loop;
[Index.DIV]: HTMLDivElement;
[Index.LOOP]: HTMLDivElement;
};
// <div>
@ -80,20 +77,15 @@ type scope = {
export const template = `<div></div>`;
export const walks = get + next(1);
export const hydrate = () => {
write(
Index.LOOP,
loop(
walk() as HTMLDivElement,
iter0,
i => "" + (i as Input["children"][number]).id
)
);
write(Index.DIV, walk());
};
export const execInputChildren = () => {
setLoopOf(
Index.LOOP,
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN)
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN),
iter0,
i => "" + (i as Input["children"][number]).id
);
runForEach(Index.LOOP, iter0_execItem);
};
@ -127,8 +119,7 @@ const iter0 = createRenderer(
() => {
write(Iter0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);
const iter0_execItem = () => {

View File

@ -1,15 +1,12 @@
import {
walk,
data,
loop,
read,
write,
isDirty,
setLoopOf,
Loop,
createRenderer,
createRenderFn,
staticNodeMethods,
runForEach
} from "../../../../src/dom/index";
import { get, next } from "../../utils/walks";
@ -56,15 +53,15 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
DIV = 0,
INPUT_CHILDREN = 1,
LOOP = 2
INPUT_CHILDREN = 0,
DIV = 1,
LOOP = 1
}
type scope = {
[Index.DIV]: HTMLDivElement;
[Index.INPUT_CHILDREN]: Input["children"];
[Index.LOOP]: Loop;
[Index.DIV]: HTMLDivElement;
[Index.LOOP]: HTMLDivElement;
};
// <div>
@ -76,20 +73,15 @@ type scope = {
export const template = `<div></div>`;
export const walks = get + next(1);
export const hydrate = () => {
write(
Index.LOOP,
loop(
walk() as HTMLDivElement,
iter0,
i => "" + (i as Input["children"][number]).id
)
);
write(Index.DIV, walk());
};
export const execInputChildren = () => {
setLoopOf(
Index.LOOP,
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN)
read<scope, Index.INPUT_CHILDREN>(Index.INPUT_CHILDREN),
iter0,
i => "" + (i as Input["children"][number]).id
);
runForEach(Index.LOOP, iter0_execItem);
};
@ -123,8 +115,7 @@ const iter0 = createRenderer(
() => {
write(Iter0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);
const iter0_execItem = () => {

View File

@ -4,12 +4,9 @@ import {
read,
write,
readInOwner,
conditional,
setConditionalRenderer,
Conditional,
createRenderer,
createRenderFn,
staticNodeMethods,
runInBranch
} from "../../../../src/dom/index";
import { next, get, over } from "../../utils/walks";
@ -32,17 +29,17 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
COMMENT = 0,
INPUT_VISIBLE = 1,
INPUT_VALUE = 2,
CONDITIONAL = 3
INPUT_VISIBLE = 0,
INPUT_VALUE = 1,
COMMENT = 2,
CONDITIONAL = 2
}
type scope = {
[Index.COMMENT]: Comment;
[Index.INPUT_VISIBLE]: Input["visible"];
[Index.INPUT_VALUE]: Input["value"];
[Index.CONDITIONAL]: Conditional;
[Index.COMMENT]: Comment;
[Index.CONDITIONAL]: Comment;
};
// <div>
@ -54,7 +51,7 @@ type scope = {
export const template = `<div><!></div>`;
export const walks = next(1) + get + over(1);
export const hydrate = () => {
write(Index.CONDITIONAL, conditional(walk() as Comment));
write(Index.COMMENT, walk());
};
export const execInputValue = () => {
@ -92,6 +89,5 @@ const branch0 = createRenderer(
() => {
write(Branch0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);

View File

@ -1,14 +1,11 @@
import {
walk,
data,
conditional,
setConditionalRenderer,
Conditional,
write,
read,
createRenderer,
createRenderFn,
staticNodeMethods,
readInOwner,
runInBranch
} from "../../../../src/dom/index";
@ -30,15 +27,15 @@ export const inputs = [
];
const enum Index {
COMMENT = 0,
INPUT_VALUE = 1,
CONDITIONAL = 2
INPUT_VALUE = 0,
COMMENT = 1,
CONDITIONAL = 1
}
type scope = {
[Index.COMMENT]: Comment;
[Index.INPUT_VALUE]: typeof inputs[number]["value"];
[Index.CONDITIONAL]: Conditional;
[Index.COMMENT]: Comment;
[Index.CONDITIONAL]: Comment;
};
// <div>
@ -52,7 +49,7 @@ type scope = {
export const template = `<div><!><span></span><span></span></div>`;
export const walks = next(1) + get + over(3);
export const hydrate = () => {
write(Index.CONDITIONAL, conditional(walk() as Comment));
write(Index.COMMENT, walk());
};
export const execInputValue = () => {
@ -89,6 +86,5 @@ const branch0 = createRenderer(
() => {
write(Branch0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);

View File

@ -1,14 +1,11 @@
import {
walk,
data,
conditional,
setConditionalRenderer,
Conditional,
read,
write,
createRenderer,
createRenderFn,
staticNodeMethods,
readInOwner,
runInBranch
} from "../../../../src/dom/index";
@ -30,15 +27,15 @@ export const inputs = [
];
const enum Index {
COMMENT = 0,
INPUT_VALUE = 1,
CONDITIONAL = 2
INPUT_VALUE = 0,
COMMENT = 1,
CONDITIONAL = 1
}
type scope = {
[Index.COMMENT]: Comment;
[Index.INPUT_VALUE]: typeof inputs[number]["value"];
[Index.CONDITIONAL]: Conditional;
[Index.COMMENT]: Comment;
[Index.CONDITIONAL]: Comment;
};
// <div>
@ -52,7 +49,7 @@ type scope = {
export const template = `<div><span></span><span></span><!></div>`;
export const walks = next(3) + get + over(1);
export const hydrate = () => {
write(Index.CONDITIONAL, conditional(walk() as Comment));
write(Index.CONDITIONAL, walk());
};
export const execInputValue = () => {
@ -89,6 +86,5 @@ const branch0 = createRenderer(
() => {
write(Branch0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);

View File

@ -1,14 +1,11 @@
import {
walk,
data,
conditional,
setConditionalRenderer,
Conditional,
read,
write,
createRenderer,
createRenderFn,
staticNodeMethods,
readInOwner,
runInBranch
} from "../../../../src/dom/index";
@ -30,15 +27,15 @@ export const inputs = [
];
const enum Index {
COMMENT = 0,
INPUT_VALUE = 1,
CONDITIONAL = 2
INPUT_VALUE = 0,
COMMENT = 1,
CONDITIONAL = 1
}
type scope = {
[Index.COMMENT]: Comment;
[Index.INPUT_VALUE]: typeof inputs[number]["value"];
[Index.CONDITIONAL]: Conditional;
[Index.COMMENT]: Comment;
[Index.CONDITIONAL]: Comment;
};
// <div>
@ -52,7 +49,7 @@ type scope = {
export const template = `<div><span></span><!><span></span></div>`;
export const walks = next(2) + get + over(2);
export const hydrate = () => {
write(Index.CONDITIONAL, conditional(walk() as Comment));
write(Index.COMMENT, walk());
};
export const execInputValue = () => {
@ -89,6 +86,5 @@ const branch0 = createRenderer(
() => {
write(Branch0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);

View File

@ -1,13 +1,12 @@
import {
walk,
data,
conditional,
setConditionalRenderer,
Conditional,
createRenderer,
createRenderFn,
staticNodeMethods,
dynamicFragmentMethods,
fragmentMethods,
getConditionalFirstNode,
getConditionalLastNode,
write,
isDirty,
read,
@ -48,17 +47,19 @@ export const inputs = [
type Input = typeof inputs[number];
const enum Index {
INPUT_SHOW = 1,
INPUT_VALUE1 = 2,
INPUT_VALUE2 = 3,
CONDITIONAL = 4
INPUT_SHOW = 0,
INPUT_VALUE1 = 1,
INPUT_VALUE2 = 2,
COMMENT = 3,
CONDITIONAL = 3
}
type scope = {
[Index.INPUT_SHOW]: Input["show"];
[Index.INPUT_VALUE1]: Input["value1"];
[Index.INPUT_VALUE2]: Input["value2"];
[Index.CONDITIONAL]: Conditional;
[Index.COMMENT]: Comment;
[Index.CONDITIONAL]: Comment;
};
// <div>
@ -71,7 +72,7 @@ type scope = {
export const template = `<div><!></div>`;
export const walks = next(1) + get + over(1);
export const hydrate = () => {
write(Index.CONDITIONAL, conditional(walk() as Comment));
write(Index.COMMENT, walk());
};
export const execInputShowValue1Value2 = () => {
@ -87,17 +88,17 @@ export const execInputShowValue1Value2 = () => {
const execInputShowValue1Value2Branch0 = () => {
if (isDirtyInOwner(Index.INPUT_SHOW) || isDirtyInOwner(Index.INPUT_VALUE1)) {
setConditionalRenderer(
Branch0Index.COND1,
Branch0Index.CONDITIONAL1,
readInOwner(Index.INPUT_VALUE1) ? branch0_0 : undefined
);
runInBranch(Branch0Index.COND1, branch0_0, execInputValue1Branch0_0);
runInBranch(Branch0Index.CONDITIONAL1, branch0_0, execInputValue1Branch0_0);
}
if (isDirtyInOwner(Index.INPUT_SHOW) || isDirtyInOwner(Index.INPUT_VALUE2)) {
setConditionalRenderer(
Branch0Index.COND2,
Branch0Index.CONDITIONAL2,
readInOwner(Index.INPUT_VALUE2) ? branch0_1 : undefined
);
runInBranch(Branch0Index.COND2, branch0_1, execInputValue2Branch0_1);
runInBranch(Branch0Index.CONDITIONAL2, branch0_1, execInputValue2Branch0_1);
}
};
@ -119,31 +120,42 @@ export const execDynamicInput = (input: Input) => {
export default createRenderFn(template, walks, hydrate, 0, execDynamicInput);
const enum Branch0Index {
COND1 = 0,
COND2 = 1
COMMENT1 = 0,
CONDITIONAL1 = 0,
COMMENT2 = 4,
CONDITIONAL2 = 4
}
type Branch0Scope = [Conditional, Conditional];
type Branch0Scope = {
[Branch0Index.COMMENT1]: Comment;
[Branch0Index.CONDITIONAL1]: Comment;
[Branch0Index.COMMENT2]: Comment;
[Branch0Index.CONDITIONAL2]: Comment;
};
const branch0 = createRenderer(
"<!><!>",
get + over(1) + get + over(1),
() => {
write(Branch0Index.COND1, conditional(walk() as Comment));
write(Branch0Index.COND2, conditional(walk() as Comment));
write(Branch0Index.COMMENT1, walk());
write(Branch0Index.COMMENT2, walk());
},
0,
dynamicFragmentMethods,
0,
fragmentMethods,
getConditionalFirstNode,
0,
1
getConditionalLastNode,
4
);
const enum Branch0_0Index {
TEXT = 0
}
type Branch0_0Scope = [Text];
type Branch0_0Scope = {
[Branch0_0Index.TEXT]: Text;
};
const branch0_0 = createRenderer(
"<span> </span>",
@ -151,15 +163,16 @@ const branch0_0 = createRenderer(
() => {
write(Branch0_0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);
const enum Branch0_1Index {
TEXT = 0
}
type Branch0_1Scope = [Text];
type Branch0_1Scope = {
[Branch0_1Index.TEXT]: Text;
};
// OPTIMIZATION: these two branches have the same renderer arguments
// so they could share the same renderer instance
@ -169,6 +182,5 @@ const branch0_1 = createRenderer(
() => {
write(Branch0_1Index.TEXT, walk());
},
0,
staticNodeMethods
0
);

View File

@ -1,12 +1,9 @@
import {
walk,
data,
conditional,
setConditionalRendererOnlyChild,
Conditional,
createRenderer,
createRenderFn,
staticNodeMethods,
read,
write,
readInOwner,
@ -30,15 +27,15 @@ export const inputs = [
];
const enum Index {
DIV = 0,
INPUT_VALUE = 1,
CONDITIONAL = 2
INPUT_VALUE = 0,
DIV = 1,
CONDITIONAL = 1
}
type scope = {
[Index.DIV]: HTMLDivElement;
[Index.INPUT_VALUE]: typeof inputs[number]["value"];
[Index.CONDITIONAL]: Conditional;
[Index.DIV]: HTMLDivElement;
[Index.CONDITIONAL]: HTMLDivElement;
};
// <div>
@ -50,7 +47,7 @@ type scope = {
export const template = `<div></div>`;
export const walks = get + over(1);
export const hydrate = () => {
write(Index.CONDITIONAL, conditional(walk() as HTMLDivElement));
write(Index.DIV, walk());
};
export const execInputValue = () => {
@ -87,6 +84,5 @@ const branch0 = createRenderer(
() => {
write(Branch0Index.TEXT, walk());
},
0,
staticNodeMethods
0
);