Skip to content
This repository was archived by the owner on May 19, 2023. It is now read-only.

Commit c70e563

Browse files
authored
Merge pull request #110 from aidenybai/staging
2 parents f16625b + f7532bc commit c70e563

File tree

5 files changed

+28
-17
lines changed

5 files changed

+28
-17
lines changed

src/component.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
/* istanbul ignore next */
1+
/* istanbul ignore file */
2+
23
import { Directives, DirectiveProps, Watchers, State, ASTNode } from './models/structs';
34

45
import { directives } from './core/directive';

src/core/directives/for.ts

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* istanbul ignore file */
22

33
import { DIRECTIVE_PREFIX } from '../../models/generics';
4-
import { DirectiveProps } from '../../models/structs';
4+
import { ASTNode, DirectiveProps } from '../../models/structs';
55

66
import compile from '../../core/compile';
77
import render from '../../core/render';
@@ -15,9 +15,9 @@ import computeExpression from '../utils/computeExpression';
1515
// This directive is size-based, not content-based, since everything is compiled and rerendered
1616

1717
export const forDirective = ({ el, data, state, node }: DirectiveProps): void => {
18-
const marker = getElementCustomProp(el, 'component');
19-
20-
setElementCustomProp(el, 'component', true);
18+
const originalAST = getElementCustomProp(el, 'component');
19+
// Initial compilation
20+
if (!originalAST) setElementCustomProp(el, 'component', compile(el, state));
2121

2222
const forLoopRE = /\s+(?:in|of)\s+/gim;
2323
const [expression, target] = data.value.split(forLoopRE);
@@ -26,7 +26,6 @@ export const forDirective = ({ el, data, state, node }: DirectiveProps): void =>
2626
// Try to grab by property, else compute it if it's a custom array
2727
const currArray =
2828
(state[target?.trim()] as unknown[]) ?? computeExpression(target?.trim(), el, true)(state);
29-
const ast = compile(el, state);
3029

3130
const template = getElementCustomProp(el, '__for_template');
3231
if (el.innerHTML.trim() === template) el.innerHTML = '';
@@ -66,13 +65,16 @@ export const forDirective = ({ el, data, state, node }: DirectiveProps): void =>
6665
el.appendChild(isTable ? fragment.firstElementChild.firstElementChild : fragment);
6766
}
6867
}
68+
setElementCustomProp(el, 'component', compile(el, state));
6969
}
7070

71-
if (!marker) {
71+
if (!originalAST) {
7272
// Deps recompiled because child nodes may have additional deps
73-
adjustDeps(ast, data.deps, node!, 'for');
73+
adjustDeps(getElementCustomProp(el, 'component') as ASTNode[], data.deps, node!, 'for');
7474
el.removeAttribute(`${DIRECTIVE_PREFIX}for`);
7575
}
7676

77-
render(compile(el, state, true), directives, state, node!.deps);
77+
// Only recompile if there is no increase/decrease in array size, else use the original AST
78+
const ast = arrayDiff === 0 ? (originalAST as ASTNode[]) : compile(el, state, true);
79+
render(ast, directives, state, node!.deps);
7880
};

src/core/render.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const render = (
1515

1616
concurrent(function* () {
1717
for (const node of ast) {
18+
yield;
1819
const isStatic = node.type === ASTNodeType.STATIC;
1920
if (isStatic) node.type = ASTNodeType.NULL;
2021

src/core/utils/__test__/computeExpression.spec.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,27 @@ describe('.compute', () => {
44
it('should use key-based retrieval during computation', () => {
55
const el = document.createElement('div');
66

7-
expect(computeExpression('count', el)({ count: 0 })).toEqual(0);
7+
expect(computeExpression('count', el, true, {}, ['count'])({ count: 0 })).toEqual(0);
88
});
99

1010
it('should compute correctly', () => {
1111
const el = document.createElement('div');
12-
expect(computeExpression('count + 1', el)({ count: 0 })).toEqual(1);
12+
expect(computeExpression('count + 1', el, true, {}, ['count'])({ count: 0 })).toEqual(1);
1313
});
1414

1515
it('should not return the value', () => {
1616
const el = document.createElement('div');
17-
expect(computeExpression('count + 1', el, false)({ count: 0 })).toEqual(undefined);
17+
expect(computeExpression('count + 1', el, false, {}, ['count'])({ count: 0 })).toEqual(
18+
undefined
19+
);
1820
});
1921

2022
it('should emit and access an event', () => {
2123
const el = document.createElement('div');
2224

2325
expect(
2426
// @ts-expect-error: 'foo' cannot be passed as an Event, but good enough for our use case
25-
computeExpression(`$emit('customEvent', $el); return $event`, el, false)({}, 'foo')
27+
computeExpression(`$emit('customEvent', $el); return $event`, el, false, {}, [])({}, 'foo')
2628
).toEqual('foo');
2729
});
2830
});

src/core/utils/computeExpression.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,20 @@ export const computeExpression = (
77
el?: HTMLElement,
88
returnable = true,
99
refs: Refs = {},
10-
deps: string[] = []
10+
deps?: string[]
1111
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1212
): ((state: UnknownKV, event?: Event) => any) => {
1313
// This dynamically appends `$state.` to the front of standalone props, allowing the
1414
// user to write less and us to compile and run faster without with() {}
1515
let formattedExpression = `${returnable ? `return ${expression}` : expression}`;
16-
deps.forEach((dep) => {
17-
formattedExpression = formattedExpression.replace(expressionPropRE(dep), `$state.${dep}`);
18-
});
16+
if (deps) {
17+
deps.forEach((dep) => {
18+
formattedExpression = formattedExpression.replace(expressionPropRE(dep), `$state.${dep}`);
19+
});
20+
} else {
21+
formattedExpression = `with($state){${formattedExpression}}`;
22+
}
23+
1924
return (state: UnknownKV, event?: Event) => {
2025
try {
2126
const value = state[expression];

0 commit comments

Comments
 (0)