Skip to content

Commit

Permalink
fix: mark children as read-only
Browse files Browse the repository at this point in the history
  • Loading branch information
nolanlawson committed Dec 7, 2021
1 parent 1ddbe4a commit a933dea
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 24 deletions.
28 changes: 22 additions & 6 deletions packages/@lwc/engine-core/src/3rdparty/snabbdom/snabbdom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ function isVNode(vnode: any): vnode is VNode {
return vnode != null;
}

function createKeyToOldIdx(children: VNodes, beginIdx: number, endIdx: number): KeyToIndexMap {
function createKeyToOldIdx(
children: Readonly<VNodes>,
beginIdx: number,
endIdx: number
): KeyToIndexMap {
const map: KeyToIndexMap = {};
let j: number, key: Key | undefined, ch;
// TODO [#1637]: simplify this by assuming that all vnodes has keys
Expand All @@ -50,7 +54,7 @@ function createKeyToOldIdx(children: VNodes, beginIdx: number, endIdx: number):
function addVnodes(
parentElm: Node,
before: Node | null,
vnodes: VNodes,
vnodes: Readonly<VNodes>,
startIdx: number,
endIdx: number
) {
Expand All @@ -63,7 +67,12 @@ function addVnodes(
}
}

function removeVnodes(parentElm: Node, vnodes: VNodes, startIdx: number, endIdx: number): void {
function removeVnodes(
parentElm: Node,
vnodes: Readonly<VNodes>,
startIdx: number,
endIdx: number
): void {
for (; startIdx <= endIdx; ++startIdx) {
const ch = vnodes[startIdx];
// text nodes do not have logic associated to them
Expand All @@ -73,7 +82,11 @@ function removeVnodes(parentElm: Node, vnodes: VNodes, startIdx: number, endIdx:
}
}

export function updateDynamicChildren(parentElm: Node, oldCh: VNodes, newCh: VNodes) {
export function updateDynamicChildren(
parentElm: Node,
oldCh: Readonly<VNodes>,
newCh: Readonly<VNodes>
) {
let oldStartIdx = 0;
let newStartIdx = 0;
let oldEndIdx = oldCh.length - 1;
Expand Down Expand Up @@ -139,7 +152,6 @@ export function updateDynamicChildren(parentElm: Node, oldCh: VNodes, newCh: VNo
newStartVnode.hook.insert(newStartVnode, parentElm, oldStartVnode.elm!);
} else {
patchVnode(elmToMove, newStartVnode);
oldCh[idxInOld] = undefined as any;
newStartVnode.hook.move(elmToMove, parentElm, oldStartVnode.elm!);
}
}
Expand All @@ -164,7 +176,11 @@ export function updateDynamicChildren(parentElm: Node, oldCh: VNodes, newCh: VNo
}
}

export function updateStaticChildren(parentElm: Node, oldCh: VNodes, newCh: VNodes) {
export function updateStaticChildren(
parentElm: Node,
oldCh: Readonly<VNodes>,
newCh: Readonly<VNodes>
) {
const oldChLength = oldCh.length;
const newChLength = newCh.length;

Expand Down
10 changes: 5 additions & 5 deletions packages/@lwc/engine-core/src/3rdparty/snabbdom/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export type VNodes = Array<VNode | null>;

export interface VNode {
sel: string | undefined;
data: VNodeData;
children: VNodes | undefined;
data: Readonly<VNodeData>;
children: Readonly<VNodes> | undefined;
elm: Node | undefined;
parentElm?: Element;
text: string | undefined;
Expand All @@ -33,8 +33,8 @@ export interface VNode {

export interface VElement extends VNode {
sel: string;
data: VElementData;
children: VNodes;
data: Readonly<VElementData>;
children: Readonly<VNodes>;
elm: Element | undefined;
text: undefined;
key: Key;
Expand All @@ -44,7 +44,7 @@ export interface VCustomElement extends VElement {
mode: 'closed' | 'open';
ctor: any;
// copy of the last allocated children.
aChildren?: VNodes;
aChildren?: Readonly<VNodes>;
}

export interface VText extends VNode {
Expand Down
10 changes: 5 additions & 5 deletions packages/@lwc/engine-core/src/framework/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ function addVNodeToChildLWC(vnode: VCustomElement) {
}

// [h]tml node
function h(sel: string, data: VElementData, children: VNodes): VElement {
function h(sel: string, data: Readonly<VElementData>, children: Readonly<VNodes>): VElement {
const vmBeingRendered = getVMBeingRendered()!;
if (process.env.NODE_ENV !== 'production') {
assert.isTrue(isString(sel), `h() 1st argument sel must be a string.`);
Expand Down Expand Up @@ -432,10 +432,10 @@ function ti(value: any): number {
// [s]lot element node
function s(
slotName: string,
data: VElementData,
children: VNodes,
data: Readonly<VElementData>,
children: Readonly<VNodes>,
slotset: SlotSet | undefined
): VElement | VNodes {
): VElement | Readonly<VNodes> {
if (process.env.NODE_ENV !== 'production') {
assert.isTrue(isString(slotName), `s() 1st argument slotName must be a string.`);
assert.isTrue(isObject(data), `s() 2nd argument data must be an object.`);
Expand Down Expand Up @@ -814,7 +814,7 @@ function dc(
* - children that are produced by iteration
*
*/
function sc(vnodes: VNodes): VNodes {
function sc(vnodes: Readonly<VNodes>): Readonly<VNodes> {
if (process.env.NODE_ENV !== 'production') {
assert.isTrue(isArray(vnodes), 'sc() api can only work with arrays.');
}
Expand Down
12 changes: 8 additions & 4 deletions packages/@lwc/engine-core/src/framework/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,11 @@ function throwHydrationError() {
assert.fail('Server rendered elements do not match client side generated elements');
}

export function hydrateChildrenHook(elmChildren: NodeListOf<ChildNode>, children: VNodes, vm?: VM) {
export function hydrateChildrenHook(
elmChildren: Readonly<NodeListOf<ChildNode>>,
children: Readonly<VNodes>,
vm?: VM
) {
if (process.env.NODE_ENV !== 'production') {
const filteredVNodes = ArrayFilter.call(children, (vnode) => !!vnode);

Expand Down Expand Up @@ -463,14 +467,14 @@ export function removeElmHook(vnode: VElement) {
}

// Using a WeakMap instead of a WeakSet because this one works in IE11 :(
const FromIteration: WeakMap<VNodes, 1> = new WeakMap();
const FromIteration: WeakMap<Readonly<VNodes>, 1> = new WeakMap();

// dynamic children means it was generated by an iteration
// in a template, and will require a more complex diffing algo.
export function markAsDynamicChildren(children: VNodes) {
export function markAsDynamicChildren(children: Readonly<VNodes>) {
FromIteration.set(children, 1);
}

export function hasDynamicChildren(children: VNodes): boolean {
export function hasDynamicChildren(children: Readonly<VNodes>): boolean {
return FromIteration.has(children);
}
8 changes: 4 additions & 4 deletions packages/@lwc/engine-core/src/framework/vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ export interface VM<N = HostNode, E = HostElement> {
/** The component connection state. */
state: VMState;
/** The list of VNodes associated with the shadow tree. */
children: VNodes;
children: Readonly<VNodes>;
/** The list of adopted children VNodes. */
aChildren: VNodes;
aChildren: Readonly<VNodes>;
/** The list of custom elements VNodes currently rendered in the shadow tree. We keep track of
* those elements to efficiently unmount them when the parent component is disconnected without
* having to traverse the VNode tree. */
Expand Down Expand Up @@ -634,7 +634,7 @@ function runLightChildNodesDisconnectedCallback(vm: VM) {
* custom element itself will trigger the removal of anything slotted or anything
* defined on its shadow.
*/
function recursivelyDisconnectChildren(vnodes: VNodes) {
function recursivelyDisconnectChildren(vnodes: Readonly<VNodes>) {
for (let i = 0, len = vnodes.length; i < len; i += 1) {
const vnode: VCustomElement | VNode | null = vnodes[i];
if (!isNull(vnode) && isArray(vnode.children) && !isUndefined(vnode.elm)) {
Expand Down Expand Up @@ -699,7 +699,7 @@ function getErrorBoundaryVM(vm: VM): VM | undefined {
// slow path routine
// NOTE: we should probably more this routine to the synthetic shadow folder
// and get the allocation to be cached by in the elm instead of in the VM
export function allocateInSlot(vm: VM, children: VNodes) {
export function allocateInSlot(vm: VM, children: Readonly<VNodes>) {
const { cmpSlots: oldSlots } = vm;
const cmpSlots = (vm.cmpSlots = create(null));
for (let i = 0, len = children.length; i < len; i += 1) {
Expand Down

0 comments on commit a933dea

Please sign in to comment.