refactor(parse): use bitmap instead of dependency map

This commit is contained in:
Hoikan 2024-05-08 15:56:42 +08:00
parent 0dcad572f3
commit 601381032d
10 changed files with 63 additions and 109 deletions

View File

@ -19,6 +19,7 @@ import { addLifecycle, addWatch } from './nodeFactory';
import { types as t } from '@openinula/babel-api'; import { types as t } from '@openinula/babel-api';
import { ON_MOUNT, ON_UNMOUNT, WATCH, WILL_MOUNT, WILL_UNMOUNT } from '../constants'; import { ON_MOUNT, ON_UNMOUNT, WATCH, WILL_MOUNT, WILL_UNMOUNT } from '../constants';
import { extractFnFromMacro, getFnBody } from '../utils'; import { extractFnFromMacro, getFnBody } from '../utils';
import { getDependenciesFromNode } from './reactive/getDependencies';
function isLifeCycleName(name: string): name is LifeCycle { function isLifeCycleName(name: string): name is LifeCycle {
return [WILL_MOUNT, ON_MOUNT, WILL_UNMOUNT, ON_UNMOUNT].includes(name); return [WILL_MOUNT, ON_MOUNT, WILL_UNMOUNT, ON_UNMOUNT].includes(name);
@ -51,9 +52,9 @@ export function functionalMacroAnalyze(): Visitor {
if (calleeName === WATCH) { if (calleeName === WATCH) {
const fnNode = extractFnFromMacro(expression, WATCH); const fnNode = extractFnFromMacro(expression, WATCH);
const deps = getWatchDeps(expression); const deps = getWatchDeps(expression);
if (!deps) {
// we auto collect the deps from the function body const depBits = getDependenciesFromNode(deps ?? fnNode, ctx);
}
addWatch(ctx.current, fnNode, deps); addWatch(ctx.current, fnNode, deps);
return; return;
} }

View File

@ -14,7 +14,7 @@
*/ */
import { NodePath, type types as t } from '@babel/core'; import { NodePath, type types as t } from '@babel/core';
import { ComponentNode, FunctionalExpression, LifeCycle, ReactiveVariable } from './types'; import type { ComponentNode, FunctionalExpression, LifeCycle, ReactiveVariable, Bitmap } from './types';
import { PropType } from '../constants'; import { PropType } from '../constants';
import { ViewParticle } from '@openinula/reactivity-parser'; import { ViewParticle } from '@openinula/reactivity-parser';
@ -53,7 +53,7 @@ export function addProperty(comp: ComponentNode, name: string, value: t.Expressi
const bitmap = depBits ? depBits | bit : bit; const bitmap = depBits ? depBits | bit : bit;
comp._reactiveBitMap.set(name, bitmap); comp._reactiveBitMap.set(name, bitmap);
comp.variables.push({ name, value, isComputed: !!depBits, type: 'reactive', bitmap, level: comp.level }); comp.variables.push({ name, value, isComputed: !!depBits, type: 'reactive', depMask: bitmap, level: comp.level });
} }
export function addMethod(comp: ComponentNode, name: string, value: FunctionalExpression) { export function addMethod(comp: ComponentNode, name: string, value: FunctionalExpression) {
@ -87,13 +87,13 @@ export function addLifecycle(comp: ComponentNode, lifeCycle: LifeCycle, block: t
export function addWatch( export function addWatch(
comp: ComponentNode, comp: ComponentNode,
callback: NodePath<t.ArrowFunctionExpression> | NodePath<t.FunctionExpression>, callback: NodePath<t.ArrowFunctionExpression> | NodePath<t.FunctionExpression>,
deps: NodePath<t.ArrayExpression> | null depMask: Bitmap
) { ) {
// if watch not exist, create a new one // if watch not exist, create a new one
if (!comp.watch) { if (!comp.watch) {
comp.watch = []; comp.watch = [];
} }
comp.watch.push({ callback, deps }); comp.watch.push({ callback, depMask });
} }
export function setViewChild(comp: ComponentNode, view: ViewParticle[], usedPropertySet: Set<string>) { export function setViewChild(comp: ComponentNode, view: ViewParticle[], usedPropertySet: Set<string>) {

View File

@ -26,14 +26,13 @@ import { reactivityFuncNames } from '../../const';
* @returns * @returns
*/ */
export function getDependenciesFromNode( export function getDependenciesFromNode(
propertyKey: string,
path: NodePath<t.Expression | t.ClassDeclaration>, path: NodePath<t.Expression | t.ClassDeclaration>,
{ current }: AnalyzeContext { current }: AnalyzeContext
) { ) {
// ---- Deps: console.log(count) // ---- Deps: console.log(count)
let depsBit = 0; let depMask = 0;
// ---- Assign deps: count = 1 or count++ // ---- Assign deps: count = 1 or count++
let assignDepBit = 0; let assignDepMask = 0;
const depNodes: Record<string, t.Expression[]> = {}; const depNodes: Record<string, t.Expression[]> = {};
const visitor = (innerPath: NodePath<t.Identifier>) => { const visitor = (innerPath: NodePath<t.Identifier>) => {
@ -42,9 +41,9 @@ export function getDependenciesFromNode(
if (reactiveBitmap !== undefined) { if (reactiveBitmap !== undefined) {
if (isAssignmentExpressionLeft(innerPath) || isAssignmentFunction(innerPath)) { if (isAssignmentExpressionLeft(innerPath) || isAssignmentFunction(innerPath)) {
assignDepBit |= reactiveBitmap; assignDepMask |= reactiveBitmap;
} else { } else {
depsBit |= reactiveBitmap; depMask |= reactiveBitmap;
if (!depNodes[propertyKey]) depNodes[propertyKey] = []; if (!depNodes[propertyKey]) depNodes[propertyKey] = [];
depNodes[propertyKey].push(t.cloneNode(innerPath.node)); depNodes[propertyKey].push(t.cloneNode(innerPath.node));
} }
@ -61,11 +60,11 @@ export function getDependenciesFromNode(
// e.g. { console.log(count); count = 1 } // e.g. { console.log(count); count = 1 }
// this will cause infinite loop // this will cause infinite loop
// so we eliminate "count" from deps // so we eliminate "count" from deps
if (assignDepBit & depsBit) { if (assignDepMask & depMask) {
// TODO: I think we should throw an error here to indicate the user that there is a loop // TODO: I think we should throw an error here to indicate the user that there is a loop
} }
return depsBit; return depMask;
} }
/** /**

View File

@ -15,10 +15,10 @@
import { type NodePath, types as t } from '@babel/core'; import { type NodePath, types as t } from '@babel/core';
import { ON_MOUNT, ON_UNMOUNT, PropType, WILL_MOUNT, WILL_UNMOUNT } from '../constants'; import { ON_MOUNT, ON_UNMOUNT, PropType, WILL_MOUNT, WILL_UNMOUNT } from '../constants';
import { ViewParticle, PrevMap } from '@openinula/reactivity-parser'; import { ViewParticle } from '@openinula/reactivity-parser';
export type LifeCycle = typeof WILL_MOUNT | typeof ON_MOUNT | typeof WILL_UNMOUNT | typeof ON_UNMOUNT; export type LifeCycle = typeof WILL_MOUNT | typeof ON_MOUNT | typeof WILL_UNMOUNT | typeof ON_UNMOUNT;
type Bitmap = number; export type Bitmap = number;
export type FunctionalExpression = t.FunctionExpression | t.ArrowFunctionExpression; export type FunctionalExpression = t.FunctionExpression | t.ArrowFunctionExpression;
@ -37,7 +37,7 @@ export interface ReactiveVariable extends BaseVariable<t.Expression | null> {
* let age = 18; // age's bitmap is 0x0010 * let age = 18; // age's bitmap is 0x0010
* let greeting = `Hello, ${name}`; // greeting's bitmap is 0x0101 * let greeting = `Hello, ${name}`; // greeting's bitmap is 0x0101
*/ */
bitmap: Bitmap; depMask: Bitmap;
// need a flag for computed to gen a getter // need a flag for computed to gen a getter
// watch is a static computed // watch is a static computed
isComputed: boolean; isComputed: boolean;
@ -93,8 +93,7 @@ export interface ComponentNode<Type = 'comp'> {
* The watch fn in the component * The watch fn in the component
*/ */
watch?: { watch?: {
bit: Bitmap; depMask: Bitmap;
deps: NodePath<t.ArrayExpression> | null;
callback: NodePath<t.ArrowFunctionExpression> | NodePath<t.FunctionExpression>; callback: NodePath<t.ArrowFunctionExpression> | NodePath<t.FunctionExpression>;
}[]; }[];
} }

View File

@ -68,7 +68,7 @@ export function variablesAnalyze(): Visitor {
return; return;
} }
depBits = getDependenciesFromNode(id.node.name, init, ctx); depBits = getDependenciesFromNode(init, ctx);
} }
addProperty(ctx.current, id.node.name, init.node || null, depBits); addProperty(ctx.current, id.node.name, init.node || null, depBits);
} }

View File

@ -47,7 +47,7 @@ describe('analyze properties', () => {
const barVar = root.variables[1] as ReactiveVariable; const barVar = root.variables[1] as ReactiveVariable;
expect(barVar.isComputed).toBe(true); expect(barVar.isComputed).toBe(true);
expect(genCode(barVar.value)).toBe('foo'); expect(genCode(barVar.value)).toBe('foo');
expect(barVar.bitmap).toEqual(0b11); expect(barVar.depMask).toEqual(0b11);
}); });
it('should analyze dependency from state in different shape', () => { it('should analyze dependency from state in different shape', () => {
@ -68,7 +68,7 @@ describe('analyze properties', () => {
foo: foo ? a : b foo: foo ? a : b
}" }"
`); `);
expect(barVar.bitmap).toEqual(0b1111); expect(barVar.depMask).toEqual(0b1111);
}); });
// TODO:MOVE TO PROPS PLUGIN TEST // TODO:MOVE TO PROPS PLUGIN TEST
@ -108,7 +108,7 @@ describe('analyze properties', () => {
expect(root.variables.length).toBe(1); expect(root.variables.length).toBe(1);
const barVar = root.variables[0] as ReactiveVariable; const barVar = root.variables[0] as ReactiveVariable;
expect(barVar.isComputed).toBe(false); expect(barVar.isComputed).toBe(false);
expect(barVar.bitmap).toEqual(0b1); expect(barVar.depMask).toEqual(0b1);
}); });
}); });
@ -123,8 +123,8 @@ describe('analyze properties', () => {
}) })
`); `);
expect(root.variables.length).toBe(2); expect(root.variables.length).toBe(2);
expect(root.availableVariables[0].bitmap).toEqual(0b1); expect(root.availableVariables[0].depMask).toEqual(0b1);
expect((root.variables[1] as SubCompVariable).ownAvailableVariables[0].bitmap).toBe(0b11); expect((root.variables[1] as SubCompVariable).ownAvailableVariables[0].depMask).toBe(0b11);
}); });
it('should analyze dependency in parent', () => { it('should analyze dependency in parent', () => {
@ -144,12 +144,12 @@ describe('analyze properties', () => {
`); `);
const sonNode = root.variables[3] as SubCompVariable; const sonNode = root.variables[3] as SubCompVariable;
// Son > middleName // Son > middleName
expect(sonNode.ownAvailableVariables[0].bitmap).toBe(0b1111); expect(sonNode.ownAvailableVariables[0].depMask).toBe(0b1111);
// Son > name // Son > name
expect(sonNode.ownAvailableVariables[1].bitmap).toBe(0b11111); expect(sonNode.ownAvailableVariables[1].depMask).toBe(0b11111);
const grandSonNode = sonNode.variables[2] as SubCompVariable; const grandSonNode = sonNode.variables[2] as SubCompVariable;
// GrandSon > grandSonName // GrandSon > grandSonName
expect(grandSonNode.ownAvailableVariables[0].bitmap).toBe(0b100001); expect(grandSonNode.ownAvailableVariables[0].depMask).toBe(0b100001);
}); });
}); });

View File

@ -1,5 +1,4 @@
import { variablesAnalyze } from '../../src/analyzer/variablesAnalyze'; import { variablesAnalyze } from '../../src/analyzer/variablesAnalyze';
import { propsAnalyze } from '../../src/analyzer/propsAnalyze';
import { ComponentNode } from '../../src/analyzer/types'; import { ComponentNode } from '../../src/analyzer/types';
import { viewAnalyze } from '../../src/analyzer/viewAnalyze'; import { viewAnalyze } from '../../src/analyzer/viewAnalyze';
import { genCode, mockAnalyze } from '../mock'; import { genCode, mockAnalyze } from '../mock';
@ -23,51 +22,27 @@ describe('viewAnalyze', () => {
}); });
`); `);
const div = root.children![0] as any; const div = root.children![0] as any;
expect(div.children[0].content.dependencyIndexArr).toMatchInlineSnapshot(` expect(div.children[0].content.depMask).toEqual(0b11101);
[
4,
3,
2,
0,
]
`);
expect(genCode(div.children[0].content.dependenciesNode)).toMatchInlineSnapshot('"[doubleCount2]"'); expect(genCode(div.children[0].content.dependenciesNode)).toMatchInlineSnapshot('"[doubleCount2]"');
expect(div.props.className.dependencyIndexArr).toMatchInlineSnapshot(` expect(div.props.className.depMask).toEqual(0b111);
[
1,
2,
0,
]
`);
expect(genCode(div.props.className.value)).toMatchInlineSnapshot('"className + count"'); expect(genCode(div.props.className.value)).toMatchInlineSnapshot('"className + count"');
// @ts-expect-error ignore ts here // @ts-expect-error ignore ts here
const InputCompNode = (root.variables[3] as ComponentNode).value; const InputCompNode = root.variables[5] as ComponentNode;
expect(InputCompNode.usedPropertySet).toMatchInlineSnapshot(` expect(InputCompNode.usedPropertySet).toMatchInlineSnapshot(`
Set { Set {
"count", "count",
"doubleCount", "doubleCount",
"name",
} }
`); `);
// it's the {count} // it's the {count}
const inputFirstExp = InputCompNode.children[0].children[0]; const inputFirstExp = InputCompNode.children![0].children[0];
expect(inputFirstExp.content.dependencyIndexArr).toMatchInlineSnapshot(` expect(inputFirstExp.content.depMask).toEqual(0b100000);
[
5,
]
`);
expect(genCode(inputFirstExp.content.dependenciesNode)).toMatchInlineSnapshot('"[count]"'); expect(genCode(inputFirstExp.content.dependenciesNode)).toMatchInlineSnapshot('"[count]"');
// it's the {doubleCount} // it's the {doubleCount}
const inputSecondExp = InputCompNode.children[0].children[1]; const inputSecondExp = InputCompNode.children[0].children[1];
expect(inputSecondExp.content.dependencyIndexArr).toMatchInlineSnapshot(` expect(inputSecondExp.content.depMask).toEqual(0b1101);
[
3,
2,
0,
]
`);
expect(genCode(inputSecondExp.content.dependenciesNode)).toMatchInlineSnapshot('"[doubleCount]"'); expect(genCode(inputSecondExp.content.dependenciesNode)).toMatchInlineSnapshot('"[doubleCount]"');
}); });
}); });

View File

@ -22,9 +22,9 @@ describe('watchAnalyze', () => {
// watch expression // watch expression
}" }"
`); `);
if (!root.watch[0].deps) { if (!root.watch[0].depMask) {
throw new Error('watch deps not found'); throw new Error('watch deps not found');
} }
expect(genCode(root.watch[0].deps.node)).toMatchInlineSnapshot('"[a, b]"'); expect(genCode(root.watch[0].depMask)).toMatchInlineSnapshot('"[a, b]"');
}); });
}); });

View File

@ -240,7 +240,7 @@ export class ReactivityParser {
key: 'value', key: 'value',
path: [...path, idx], path: [...path, idx],
value: child.content, value: child.content,
depsBit: [], depMask: 0,
dependenciesNode: this.t.arrayExpression([]), dependenciesNode: this.t.arrayExpression([]),
dynamic: false, dynamic: false,
}); });
@ -280,7 +280,7 @@ export class ReactivityParser {
* @returns ExpParticle | HTMLParticle * @returns ExpParticle | HTMLParticle
*/ */
private parseHTML(htmlUnit: HTMLUnit): ExpParticle | HTMLParticle { private parseHTML(htmlUnit: HTMLUnit): ExpParticle | HTMLParticle {
const { depsBit, dependenciesNode } = this.getDependencies(htmlUnit.tag); const { depMask, dependenciesNode, dynamic } = this.getDependencies(htmlUnit.tag);
const innerHTMLParticle: HTMLParticle = { const innerHTMLParticle: HTMLParticle = {
type: 'html', type: 'html',
@ -295,6 +295,9 @@ export class ReactivityParser {
innerHTMLParticle.children = htmlUnit.children.map(this.parseViewParticle.bind(this)); innerHTMLParticle.children = htmlUnit.children.map(this.parseViewParticle.bind(this));
// ---- Not a dynamic tag
if (!dynamic) return innerHTMLParticle;
// ---- Dynamic tag, wrap it in an ExpParticle to make the tag reactive // ---- Dynamic tag, wrap it in an ExpParticle to make the tag reactive
const id = this.uid(); const id = this.uid();
return { return {
@ -304,7 +307,7 @@ export class ReactivityParser {
viewPropMap: { viewPropMap: {
[id]: [innerHTMLParticle], [id]: [innerHTMLParticle],
}, },
depsBit, depMask: depMask,
dependenciesNode, dependenciesNode,
}, },
props: {}, props: {},
@ -320,7 +323,7 @@ export class ReactivityParser {
* @returns CompParticle | ExpParticle * @returns CompParticle | ExpParticle
*/ */
private parseComp(compUnit: CompUnit): CompParticle | ExpParticle { private parseComp(compUnit: CompUnit): CompParticle | ExpParticle {
const { depsBit, dependenciesNode } = this.getDependencies(compUnit.tag); const { depMask, dependenciesNode, dynamic } = this.getDependencies(compUnit.tag);
const compParticle: CompParticle = { const compParticle: CompParticle = {
type: 'comp', type: 'comp',
@ -344,7 +347,7 @@ export class ReactivityParser {
viewPropMap: { viewPropMap: {
[id]: [compParticle], [id]: [compParticle],
}, },
depsBit, depMask: depMask,
dependenciesNode, dependenciesNode,
dynamic, dynamic,
}, },
@ -360,7 +363,7 @@ export class ReactivityParser {
* @returns ForParticle * @returns ForParticle
*/ */
private parseFor(forUnit: ForUnit): ForParticle { private parseFor(forUnit: ForUnit): ForParticle {
const { depsBit, dependenciesNode } = this.getDependencies(forUnit.array); const { depMask, dependenciesNode } = this.getDependencies(forUnit.array);
const prevIdentifierDepMap = this.config.identifierDepMap; const prevIdentifierDepMap = this.config.identifierDepMap;
// ---- Find all the identifiers in the key and remove them from the identifierDepMap // ---- Find all the identifiers in the key and remove them from the identifierDepMap
// because once the key is changed, that identifier related dependencies will be changed too, // because once the key is changed, that identifier related dependencies will be changed too,
@ -371,7 +374,7 @@ export class ReactivityParser {
this.config.identifierDepMap = Object.fromEntries( this.config.identifierDepMap = Object.fromEntries(
this.getIdentifiers(this.t.assignmentExpression('=', forUnit.item, this.t.objectExpression([]))) this.getIdentifiers(this.t.assignmentExpression('=', forUnit.item, this.t.objectExpression([])))
.filter(id => !keyDep || id !== keyDep) .filter(id => !keyDep || id !== keyDep)
.map(id => [id, depsBit.map(n => this.availableProperties[n])]) .map(id => [id, depMask.map(n => this.availableProperties[n])])
); );
const forParticle: ForParticle = { const forParticle: ForParticle = {
@ -380,7 +383,7 @@ export class ReactivityParser {
array: { array: {
value: forUnit.array, value: forUnit.array,
dynamic, dynamic,
depsBit, depMask: depMask,
dependenciesNode, dependenciesNode,
}, },
children: forUnit.children.map(this.parseViewParticle.bind(this)), children: forUnit.children.map(this.parseViewParticle.bind(this)),
@ -470,12 +473,14 @@ export class ReactivityParser {
* @returns dependency index array * @returns dependency index array
*/ */
private getDependencies(node: t.Expression | t.Statement): { private getDependencies(node: t.Expression | t.Statement): {
depsBit: number; dynamic: boolean;
depMask: number;
dependenciesNode: t.ArrayExpression; dependenciesNode: t.ArrayExpression;
} { } {
if (this.t.isFunctionExpression(node) || this.t.isArrowFunctionExpression(node)) { if (this.t.isFunctionExpression(node) || this.t.isArrowFunctionExpression(node)) {
return { return {
depsBit: 0, dynamic: false,
depMask: 0,
dependenciesNode: this.t.arrayExpression([]), dependenciesNode: this.t.arrayExpression([]),
}; };
} }
@ -487,7 +492,8 @@ export class ReactivityParser {
const depNodes = [...propertyDepNodes] as t.Expression[]; const depNodes = [...propertyDepNodes] as t.Expression[];
return { return {
depsBit: deps, dynamic: depNodes.length > 0 || !!deps,
depMask: deps,
dependenciesNode: this.t.arrayExpression(depNodes), dependenciesNode: this.t.arrayExpression(depNodes),
}; };
} }
@ -559,10 +565,11 @@ export class ReactivityParser {
*/ */
private getPropertyDependencies(node: t.Expression | t.Statement): [number, t.Node[]] { private getPropertyDependencies(node: t.Expression | t.Statement): [number, t.Node[]] {
// ---- Deps: console.log(count) // ---- Deps: console.log(count)
let depsBit = 0; let depMask = 0;
// ---- Assign deps: count = 1 or count++ // ---- Assign deps: count = 1 or count++
let assignDepBit = 0; let assignDepBit = 0;
const depNodes: Record<string, t.Node[]> = {}; const depNodes: Record<string, t.Node[]> = {};
const deps = new Set<string>();
const wrappedNode = this.valueWrapper(node); const wrappedNode = this.valueWrapper(node);
this.traverse(wrappedNode, { this.traverse(wrappedNode, {
@ -574,7 +581,9 @@ export class ReactivityParser {
if (this.isAssignmentExpressionLeft(innerPath) || this.isAssignmentFunction(innerPath)) { if (this.isAssignmentExpressionLeft(innerPath) || this.isAssignmentFunction(innerPath)) {
assignDepBit |= reactiveBitmap; assignDepBit |= reactiveBitmap;
} else { } else {
depsBit |= reactiveBitmap; depMask |= reactiveBitmap;
deps.add(propertyKey);
if (!depNodes[propertyKey]) depNodes[propertyKey] = []; if (!depNodes[propertyKey]) depNodes[propertyKey] = [];
depNodes[propertyKey].push(this.t.cloneNode(innerPath.node)); depNodes[propertyKey].push(this.t.cloneNode(innerPath.node));
} }
@ -586,7 +595,7 @@ export class ReactivityParser {
// e.g. { console.log(count); count = 1 } // e.g. { console.log(count); count = 1 }
// this will cause infinite loop // this will cause infinite loop
// so we eliminate "count" from deps // so we eliminate "count" from deps
if (assignDepBit & depsBit) { if (assignDepBit & depMask) {
// TODO: I think we should throw an error here to indicate the user that there is a loop // TODO: I think we should throw an error here to indicate the user that there is a loop
} }
@ -597,37 +606,8 @@ export class ReactivityParser {
return idx === i; return idx === i;
}); });
// deps.forEach(this.usedProperties.add.bind(this.usedProperties)); deps.forEach(this.usedProperties.add.bind(this.usedProperties));
return [depsBit, dependencyNodes]; return [depMask, dependencyNodes];
}
private calDependencyIndexArr = (directDepKey: string) => {
// iterate the availableProperties reversely to find the index of the property
// cause the availableProperties is in the order of the code
const chainedDepKeys = this.findDependency(directDepKey);
const depKeyQueue = chainedDepKeys ? [directDepKey, ...chainedDepKeys] : [directDepKey];
depKeyQueue.forEach(this.usedProperties.add.bind(this.usedProperties));
let dep = depKeyQueue.shift();
const result: number[] = [];
for (let i = this.availableProperties.length - 1; i >= 0; i--) {
if (this.availableProperties[i] === dep) {
result.push(i);
dep = depKeyQueue.shift();
}
}
return result;
};
private findDependency(propertyKey: string) {
let currentMap: ReactiveBitMap | undefined = this.reactiveBitMap;
do {
if (currentMap[propertyKey] !== undefined) {
return currentMap[propertyKey];
}
currentMap = currentMap[PrevMap];
} while (currentMap);
return null;
} }
/** /**

View File

@ -4,14 +4,14 @@ import type Babel from '@babel/core';
export interface DependencyValue<T> { export interface DependencyValue<T> {
value: T; value: T;
dynamic: boolean; // to removed dynamic: boolean; // to removed
depsBit: number; // -> bit depMask: number; // -> bit
dependenciesNode: t.ArrayExpression; dependenciesNode: t.ArrayExpression;
} }
export interface DependencyProp { export interface DependencyProp {
value: t.Expression; value: t.Expression;
viewPropMap: Record<string, ViewParticle[]>; viewPropMap: Record<string, ViewParticle[]>;
depsBit: number; depMask: number;
dependenciesNode: t.ArrayExpression; dependenciesNode: t.ArrayExpression;
} }
@ -21,7 +21,7 @@ export interface TemplateProp {
path: number[]; path: number[];
value: t.Expression; value: t.Expression;
dynamic: boolean; dynamic: boolean;
depsBit: number; depMask: number;
dependenciesNode: t.ArrayExpression; dependenciesNode: t.ArrayExpression;
} }