From be4456f2255f2cacec0b90c44d1555cc943a7e88 Mon Sep 17 00:00:00 2001 From: Hoikan <30694822+HoikanChan@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:58:26 +0800 Subject: [PATCH] feat: viewNode as child --- .../src/analyze/functionalMacroAnalyze.ts | 78 +++++++++++++++++ .../src/analyze/index.ts | 40 +++++---- .../src/analyze/lifeCycleAnalyze.ts | 49 ----------- .../src/analyze/nodeFactory.ts | 57 +++++-------- .../src/analyze/propertiesAnalyze.ts | 10 ++- .../src/analyze/types.ts | 84 ++++++++----------- .../src/analyze/viewAnalyze.ts | 5 +- .../src/analyze/watchAnalyze.ts | 55 ------------ .../test/analyze/lifeCycle.test.ts | 6 +- .../test/analyze/properties.test.ts | 40 ++++----- .../test/analyze/watchAnalyze.test.ts | 5 +- 11 files changed, 186 insertions(+), 243 deletions(-) create mode 100644 packages/transpiler/babel-inula-next-core/src/analyze/functionalMacroAnalyze.ts delete mode 100644 packages/transpiler/babel-inula-next-core/src/analyze/lifeCycleAnalyze.ts delete mode 100644 packages/transpiler/babel-inula-next-core/src/analyze/watchAnalyze.ts diff --git a/packages/transpiler/babel-inula-next-core/src/analyze/functionalMacroAnalyze.ts b/packages/transpiler/babel-inula-next-core/src/analyze/functionalMacroAnalyze.ts new file mode 100644 index 00000000..cd428a71 --- /dev/null +++ b/packages/transpiler/babel-inula-next-core/src/analyze/functionalMacroAnalyze.ts @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * openInula is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +import { NodePath } from '@babel/core'; +import { LifeCycle, Visitor } from './types'; +import { addLifecycle, addWatch } from './nodeFactory'; +import * as t from '@babel/types'; +import { ON_MOUNT, ON_UNMOUNT, WATCH, WILL_MOUNT, WILL_UNMOUNT } from '../constants'; +import { extractFnFromMacro, getFnBody } from '../utils'; + +function isLifeCycleName(name: string): name is LifeCycle { + return [WILL_MOUNT, ON_MOUNT, WILL_UNMOUNT, ON_UNMOUNT].includes(name); +} +/** + * Analyze the functional macro in the function component + * 1. lifecycle + * 1. willMount + * 2. onMount + * 3. willUnMount + * 4. onUnmount + * 2. watch + */ +export function functionalMacroAnalyze(): Visitor { + return { + ExpressionStatement(path: NodePath, ctx) { + const expression = path.get('expression'); + if (expression.isCallExpression()) { + const callee = expression.get('callee'); + if (callee.isIdentifier()) { + const calleeName = callee.node.name; + // lifecycle + if (isLifeCycleName(calleeName)) { + const fnNode = extractFnFromMacro(expression, calleeName); + addLifecycle(ctx.current, calleeName, getFnBody(fnNode).node); + return; + } + + // watch + if (calleeName === WATCH) { + const fnNode = extractFnFromMacro(expression, WATCH); + const deps = getWatchDeps(expression); + addWatch(ctx.current, fnNode, deps); + return; + } + } + } + + ctx.unhandledNode.push(path.node); + }, + }; +} + +function getWatchDeps(callExpression: NodePath) { + const args = callExpression.get('arguments'); + if (!args[1]) { + return null; + } + + let deps: null | NodePath = null; + if (args[1].isArrayExpression()) { + deps = args[1]; + } else { + console.error('watch deps should be an array expression'); + } + return deps; +} diff --git a/packages/transpiler/babel-inula-next-core/src/analyze/index.ts b/packages/transpiler/babel-inula-next-core/src/analyze/index.ts index b6d690e6..5374263d 100644 --- a/packages/transpiler/babel-inula-next-core/src/analyze/index.ts +++ b/packages/transpiler/babel-inula-next-core/src/analyze/index.ts @@ -1,11 +1,14 @@ import { type types as t, type NodePath } from '@babel/core'; import { propsAnalyze } from './propsAnalyze'; import { AnalyzeContext, Analyzer, ComponentNode, CondNode, Visitor } from './types'; -import { createComponentNode } from './nodeFactory'; +import { addLifecycle, createComponentNode } from './nodeFactory'; import { propertiesAnalyze } from './propertiesAnalyze'; -import { lifeCycleAnalyze } from './lifeCycleAnalyze'; +import { functionalMacroAnalyze } from './functionalMacroAnalyze'; import { getFnBody } from '../utils'; -const builtinAnalyzers = [propsAnalyze, propertiesAnalyze, lifeCycleAnalyze]; +import { viewAnalyze } from './viewAnalyze'; +import { WILL_MOUNT } from '../constants'; +import { types } from '../babelTypes'; +const builtinAnalyzers = [propsAnalyze, propertiesAnalyze, functionalMacroAnalyze, viewAnalyze]; export function isCondNode(node: any): node is CondNode { return node && node.type === 'cond'; @@ -13,22 +16,7 @@ export function isCondNode(node: any): node is CondNode { function mergeVisitor(...visitors: Analyzer[]): Visitor { return visitors.reduce>((acc, cur) => { - const visitor = cur(); - const visitorKeys = Object.keys(visitor) as (keyof Visitor)[]; - for (const key of visitorKeys) { - if (acc[key]) { - // if already exist, merge the visitor function - const original = acc[key]!; - acc[key] = (path: any, ctx) => { - original(path, ctx); - visitor[key]?.(path, ctx); - }; - } else { - // @ts-expect-error key is a valid key, no idea why it's not working - acc[key] = visitor[key]; - } - } - return acc; + return { ...acc, ...cur() }; }, {}); } @@ -45,6 +33,7 @@ export function analyzeFnComp( current: componentNode, htmlTags, analyzers, + unhandledNode: [], traverse: (path: NodePath, ctx: AnalyzeContext) => { path.traverse(visitor, ctx); }, @@ -71,14 +60,23 @@ export function analyzeFnComp( const type = p.node.type; - // TODO: More type safe way to handle this - visitor[type]?.(p as unknown as any, context); + const visit = visitor[type]; + if (visit) { + // TODO: More type safe way to handle this + visit(p as unknown as any, context); + } else { + context.unhandledNode.push(p.node); + } if (p.isReturnStatement()) { visitor.ReturnStatement?.(p, context); break; } } + + if (context.unhandledNode.length) { + addLifecycle(componentNode, WILL_MOUNT, types.blockStatement(context.unhandledNode)); + } } /** * The process of analyzing the component diff --git a/packages/transpiler/babel-inula-next-core/src/analyze/lifeCycleAnalyze.ts b/packages/transpiler/babel-inula-next-core/src/analyze/lifeCycleAnalyze.ts deleted file mode 100644 index 8151e847..00000000 --- a/packages/transpiler/babel-inula-next-core/src/analyze/lifeCycleAnalyze.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2024 Huawei Technologies Co.,Ltd. - * - * openInula is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * - * http://license.coscl.org.cn/MulanPSL2 - * - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -import { NodePath } from '@babel/core'; -import { LifeCycle, Visitor } from './types'; -import { addLifecycle } from './nodeFactory'; -import * as t from '@babel/types'; -import { ON_MOUNT, ON_UNMOUNT, WILL_MOUNT, WILL_UNMOUNT } from '../constants'; -import { extractFnFromMacro, getFnBody } from '../utils'; - -function isLifeCycleName(name: string): name is LifeCycle { - return [WILL_MOUNT, ON_MOUNT, WILL_UNMOUNT, ON_UNMOUNT].includes(name); -} -/** - * Analyze the lifeCycle in the function component - * 1. willMount - * 2. onMount - * 3. willUnMount - * 4. onUnmount - */ -export function lifeCycleAnalyze(): Visitor { - return { - ExpressionStatement(path: NodePath, ctx) { - const expression = path.get('expression'); - if (expression.isCallExpression()) { - const callee = expression.get('callee'); - if (callee.isIdentifier()) { - const lifeCycleName = callee.node.name; - if (isLifeCycleName(lifeCycleName)) { - const fnNode = extractFnFromMacro(expression, lifeCycleName); - addLifecycle(ctx.current, lifeCycleName, getFnBody(fnNode)); - } - } - } - }, - }; -} diff --git a/packages/transpiler/babel-inula-next-core/src/analyze/nodeFactory.ts b/packages/transpiler/babel-inula-next-core/src/analyze/nodeFactory.ts index 36dd5c93..289ba84b 100644 --- a/packages/transpiler/babel-inula-next-core/src/analyze/nodeFactory.ts +++ b/packages/transpiler/babel-inula-next-core/src/analyze/nodeFactory.ts @@ -14,12 +14,13 @@ */ import { NodePath, type types as t } from '@babel/core'; -import { Branch, ComponentNode, CondNode, InulaNode, JSX, JSXNode, LifeCycle, SubCompNode } from './types'; +import { ComponentNode, FunctionalExpression, LifeCycle, ViewNode } from './types'; import { PropType } from '../constants'; +import { ViewParticle } from '@openinula/reactivity-parser'; export function createComponentNode( name: string, - fnNode: NodePath, + fnNode: NodePath, parent?: ComponentNode ): ComponentNode { const comp: ComponentNode = { @@ -27,12 +28,12 @@ export function createComponentNode( name, props: [], child: undefined, - properties: [], + variables: [], dependencyMap: {}, reactiveMap: {}, lifecycle: {}, parent, - // fnBody, + fnNode, get availableProps() { return comp.props .map(({ name, nestedProps, alias }) => { @@ -41,11 +42,11 @@ export function createComponentNode( }) .flat(); }, - get ownAvailableProperties() { - return [...comp.properties.filter(p => !p.isMethod).map(({ name }) => name), ...comp.availableProps]; + get ownAvailableVariables() { + return [...comp.variables.filter(p => p.type === 'reactive').map(({ name }) => name), ...comp.availableProps]; }, - get availableProperties() { - return [...comp.ownAvailableProperties, ...(comp.parent ? comp.parent.availableProperties : [])]; + get availableVariables() { + return [...comp.ownAvailableVariables, ...(comp.parent ? comp.parent.availableVariables : [])]; }, }; @@ -53,15 +54,15 @@ export function createComponentNode( } export function addProperty(comp: ComponentNode, name: string, value: t.Expression | null, isComputed: boolean) { - comp.properties.push({ name, value, isComputed, isMethod: false }); + comp.variables.push({ name, value, isComputed, type: 'reactive' }); } -export function addMethod(comp: ComponentNode, name: string, value: t.Expression | null) { - comp.properties.push({ name, value, isComputed: false, isMethod: true }); +export function addMethod(comp: ComponentNode, name: string, value: FunctionalExpression) { + comp.variables.push({ name, value, type: 'method' }); } -export function addSubComponent(comp: ComponentNode, subComp: ComponentNode, isComputed: boolean) { - comp.properties.push({ name: subComp.name, value: subComp, isSubComp: true, isComputed, isMethod: false }); +export function addSubComponent(comp: ComponentNode, subComp: ComponentNode) { + comp.variables.push({ name: subComp.name, value: subComp, type: 'subComp' }); } export function addProp( @@ -76,7 +77,7 @@ export function addProp( comp.props.push({ name: key, type, default: defaultVal, alias, nestedProps, nestedRelationship }); } -export function addLifecycle(comp: ComponentNode, lifeCycle: LifeCycle, block: NodePath) { +export function addLifecycle(comp: ComponentNode, lifeCycle: LifeCycle, block: t.BlockStatement) { const compLifecycle = comp.lifecycle; if (!compLifecycle[lifeCycle]) { compLifecycle[lifeCycle] = []; @@ -96,28 +97,10 @@ export function addWatch( comp.watch.push({ callback, deps }); } -export function createJSXNode(parent: ComponentNode, content: NodePath): JSXNode { - return { - type: 'jsx', - parent, - child: content, - }; -} - -export function createCondNode(parent: ComponentNode, child: InulaNode, branches: Branch[]): CondNode { - return { - type: 'cond', - branches, - child, - parent, - }; -} - -export function createSubCompNode(name: string, parent: ComponentNode, child: JSX): SubCompNode { - return { - type: 'subComp', - name, - parent, - child, +export function setViewChild(comp: ComponentNode, view: ViewParticle[], usedPropertySet: Set) { + const viewNode: ViewNode = { + content: view, + usedPropertySet, }; + comp.child = viewNode; } diff --git a/packages/transpiler/babel-inula-next-core/src/analyze/propertiesAnalyze.ts b/packages/transpiler/babel-inula-next-core/src/analyze/propertiesAnalyze.ts index 32e0ea81..083548c1 100644 --- a/packages/transpiler/babel-inula-next-core/src/analyze/propertiesAnalyze.ts +++ b/packages/transpiler/babel-inula-next-core/src/analyze/propertiesAnalyze.ts @@ -14,7 +14,7 @@ */ import { AnalyzeContext, Visitor } from './types'; -import { addMethod, addProperty, createComponentNode } from './nodeFactory'; +import { addMethod, addProperty, addSubComponent, createComponentNode } from './nodeFactory'; import { isValidPath } from './utils'; import { type types as t, type NodePath } from '@babel/core'; import { reactivityFuncNames } from '../const'; @@ -45,11 +45,12 @@ export function propertiesAnalyze(): Visitor { const init = declaration.get('init'); let deps: string[] | null = null; if (isValidPath(init)) { - // the property is a method + // handle the method if (init.isArrowFunctionExpression() || init.isFunctionExpression()) { addMethod(ctx.current, id.node.name, init.node); return; } + // handle the sub component // Should like Component(() => {}) if ( init.isCallExpression() && @@ -64,9 +65,10 @@ export function propertiesAnalyze(): Visitor { analyzeFnComp(fnNode, subComponent, ctx); deps = getDependenciesFromNode(id.node.name, init, ctx); - addProperty(ctx.current, id.node.name, subComponent, !!deps?.length); + addSubComponent(ctx.current, subComponent); return; } + deps = getDependenciesFromNode(id.node.name, init, ctx); } addProperty(ctx.current, id.node.name, init.node || null, !!deps?.length); @@ -111,7 +113,7 @@ function getDependenciesFromNode( const propertyKey = innerPath.node.name; if (isAssignmentExpressionLeft(innerPath) || isAssignmentFunction(innerPath)) { assignDeps.add(propertyKey); - } else if (current.availableProperties.includes(propertyKey)) { + } else if (current.availableVariables.includes(propertyKey)) { deps.add(propertyKey); } }; diff --git a/packages/transpiler/babel-inula-next-core/src/analyze/types.ts b/packages/transpiler/babel-inula-next-core/src/analyze/types.ts index c1988d9e..56bd4b1d 100644 --- a/packages/transpiler/babel-inula-next-core/src/analyze/types.ts +++ b/packages/transpiler/babel-inula-next-core/src/analyze/types.ts @@ -14,32 +14,36 @@ */ import { type NodePath, types as t } from '@babel/core'; -import { Node } from '@babel/traverse'; import { ON_MOUNT, ON_UNMOUNT, PropType, WILL_MOUNT, WILL_UNMOUNT } from '../constants'; +import { ViewParticle } from '@openinula/reactivity-parser'; -// --- Node shape --- -export type InulaNode = ComponentNode | CondNode | JSXNode; -export type JSX = t.JSXElement | t.JSXFragment; export type LifeCycle = typeof WILL_MOUNT | typeof ON_MOUNT | typeof WILL_UNMOUNT | typeof ON_UNMOUNT; -type defaultVal = any | null; type Bitmap = number; -interface BaseProperty { + +export type FunctionalExpression = t.FunctionExpression | t.ArrowFunctionExpression; +interface BaseVariable { name: string; value: V; - // need a flag for computed to gen a getter - // watch is a static computed - isComputed: boolean; - isMethod: boolean; } -interface Property extends BaseProperty { +export interface ReactiveVariable extends BaseVariable { + type: 'reactive'; // indicate the value is a state or computed or watch listeners?: string[]; bitmap?: Bitmap; + // need a flag for computed to gen a getter + // watch is a static computed + isComputed: boolean; } -interface SubCompProperty extends BaseProperty { - isSubComp: true; + +export interface MethodVariable extends BaseVariable { + type: 'method'; } -interface Prop { +export interface SubCompVariable extends BaseVariable { + type: 'subComp'; +} + +export type Variable = ReactiveVariable | MethodVariable | SubCompVariable; +export interface Prop { name: string; type: PropType; alias: string | null; @@ -51,66 +55,45 @@ export interface ComponentNode { type: 'comp'; name: string; props: Prop[]; - // A properties could be a state or computed - properties: (Property | SubCompProperty)[]; + // The variables defined in the component + variables: Variable[]; /** * The available props for the component, including the nested props */ availableProps: string[]; /** - * The available properties for the component + * The available variables and props owned by the component */ - ownAvailableProperties: string[]; - availableProperties: string[]; + ownAvailableVariables: string[]; + /** + * The available variables and props for the component and its parent + */ + availableVariables: string[]; /** * The map to find the dependencies */ dependencyMap: { [key: string]: string[]; }; - child?: InulaNode; + child?: ComponentNode | ViewNode; parent?: ComponentNode; /** * The function body of the fn component code */ - fnBody: NodePath[]; + fnNode: NodePath; /** * The map to find the state */ reactiveMap: Record; - lifecycle: Partial[]>>; + lifecycle: Partial>; watch?: { deps: NodePath | null; callback: NodePath | NodePath; }[]; } - -export interface SubCompNode { - type: 'subComp'; - name: string; - parent: ComponentNode; - child: JSX; -} - -export interface JSXNode { - type: 'jsx'; - parent: ComponentNode; - child: NodePath; -} - -export interface CondNode { - type: 'cond'; - branches: Branch[]; - parent: ComponentNode; - /** - * The default branch - */ - child: InulaNode; -} - -export interface Branch { - conditions: NodePath[]; - content: InulaNode; +export interface ViewNode { + content: ViewParticle[]; + usedPropertySet: Set; } export interface AnalyzeContext { @@ -119,10 +102,11 @@ export interface AnalyzeContext { analyzers: Analyzer[]; htmlTags: string[]; traverse: (p: NodePath, ctx: AnalyzeContext) => void; + unhandledNode: t.Statement[]; } export type Visitor = { - [Type in Node['type']]?: (path: NodePath>, state: S) => void; + [Type in t.Statement['type']]?: (path: NodePath>, state: S) => void; } & { Prop?: (path: NodePath, state: S) => void; }; diff --git a/packages/transpiler/babel-inula-next-core/src/analyze/viewAnalyze.ts b/packages/transpiler/babel-inula-next-core/src/analyze/viewAnalyze.ts index ed76b9ba..24a59271 100644 --- a/packages/transpiler/babel-inula-next-core/src/analyze/viewAnalyze.ts +++ b/packages/transpiler/babel-inula-next-core/src/analyze/viewAnalyze.ts @@ -19,6 +19,7 @@ import { parseView as parseJSX } from 'jsx-view-parser'; import { getBabelApi } from '../babelTypes'; import { parseReactivity } from '@openinula/reactivity-parser'; import { reactivityFuncNames } from '../const'; +import { setViewChild } from './nodeFactory'; /** * Analyze the watch in the function component @@ -35,10 +36,12 @@ export function viewAnalyze(): Visitor { }); const [viewParticles, usedPropertySet] = parseReactivity(viewUnits, { babelApi: getBabelApi(), - availableProperties: current.availableProperties, + availableProperties: current.availableVariables, dependencyMap: current.dependencyMap, reactivityFuncNames, }); + + setViewChild(current, viewParticles, usedPropertySet); } }, }; diff --git a/packages/transpiler/babel-inula-next-core/src/analyze/watchAnalyze.ts b/packages/transpiler/babel-inula-next-core/src/analyze/watchAnalyze.ts deleted file mode 100644 index 1e05cf23..00000000 --- a/packages/transpiler/babel-inula-next-core/src/analyze/watchAnalyze.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2024 Huawei Technologies Co.,Ltd. - * - * openInula is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * - * http://license.coscl.org.cn/MulanPSL2 - * - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -import { NodePath } from '@babel/core'; -import { Visitor } from './types'; -import { addWatch } from './nodeFactory'; -import * as t from '@babel/types'; -import { WATCH } from '../constants'; -import { extractFnFromMacro } from '../utils'; - -/** - * Analyze the watch in the function component - */ -export function watchAnalyze(): Visitor { - return { - ExpressionStatement(path: NodePath, ctx) { - const callExpression = path.get('expression'); - if (callExpression.isCallExpression()) { - const callee = callExpression.get('callee'); - if (callee.isIdentifier() && callee.node.name === WATCH) { - const fnNode = extractFnFromMacro(callExpression, WATCH); - const deps = getWatchDeps(callExpression); - addWatch(ctx.current, fnNode, deps); - } - } - }, - }; -} - -function getWatchDeps(callExpression: NodePath) { - const args = callExpression.get('arguments'); - if (!args[1]) { - return null; - } - - let deps: null | NodePath = null; - if (args[1].isArrayExpression()) { - deps = args[1]; - } else { - console.error('watch deps should be an array expression'); - } - return deps; -} diff --git a/packages/transpiler/babel-inula-next-core/test/analyze/lifeCycle.test.ts b/packages/transpiler/babel-inula-next-core/test/analyze/lifeCycle.test.ts index f063342b..62c28ba0 100644 --- a/packages/transpiler/babel-inula-next-core/test/analyze/lifeCycle.test.ts +++ b/packages/transpiler/babel-inula-next-core/test/analyze/lifeCycle.test.ts @@ -15,12 +15,12 @@ import { describe, expect, it } from 'vitest'; import { genCode, mockAnalyze } from '../mock'; -import { lifeCycleAnalyze } from '../../src/analyze/lifeCycleAnalyze'; +import { functionalMacroAnalyze } from '../../src/analyze/functionalMacroAnalyze'; import { types } from '../../src/babelTypes'; import { type NodePath, type types as t } from '@babel/core'; -const analyze = (code: string) => mockAnalyze(code, [lifeCycleAnalyze]); -const combine = (body: NodePath[]) => types.program(body.map(path => path.node)); +const analyze = (code: string) => mockAnalyze(code, [functionalMacroAnalyze]); +const combine = (body: t.Statement[]) => types.program(body); describe('analyze lifeCycle', () => { it('should collect will mount', () => { diff --git a/packages/transpiler/babel-inula-next-core/test/analyze/properties.test.ts b/packages/transpiler/babel-inula-next-core/test/analyze/properties.test.ts index 224528a5..c0704ae6 100644 --- a/packages/transpiler/babel-inula-next-core/test/analyze/properties.test.ts +++ b/packages/transpiler/babel-inula-next-core/test/analyze/properties.test.ts @@ -29,7 +29,7 @@ describe('analyze properties', () => { let bar = 1; }) `); - expect(root.properties.length).toBe(2); + expect(root.variables.length).toBe(2); }); describe('state dependency', () => { @@ -40,11 +40,11 @@ describe('analyze properties', () => { let bar = foo; }) `); - expect(root.properties.length).toBe(2); - expect(root.properties[0].isComputed).toBe(false); - expect(genCode(root.properties[0].value)).toBe('1'); - expect(root.properties[1].isComputed).toBe(true); - expect(genCode(root.properties[1].value)).toBe('foo'); + expect(root.variables.length).toBe(2); + expect(root.variables[0].isComputed).toBe(false); + expect(genCode(root.variables[0].value)).toBe('1'); + expect(root.variables[1].isComputed).toBe(true); + expect(genCode(root.variables[1].value)).toBe('foo'); expect(root.dependencyMap).toEqual({ bar: ['foo'] }); }); @@ -57,9 +57,9 @@ describe('analyze properties', () => { let bar = { foo: foo ? a : b }; }) `); - expect(root.properties.length).toBe(4); - expect(root.properties[3].isComputed).toBe(true); - expect(genCode(root.properties[3].value)).toMatchInlineSnapshot(` + expect(root.variables.length).toBe(4); + expect(root.variables[3].isComputed).toBe(true); + expect(genCode(root.variables[3].value)).toMatchInlineSnapshot(` "{ foo: foo ? a : b }" @@ -73,8 +73,8 @@ describe('analyze properties', () => { let bar = foo; }) `); - expect(root.properties.length).toBe(1); - expect(root.properties[0].isComputed).toBe(true); + expect(root.variables.length).toBe(1); + expect(root.variables[0].isComputed).toBe(true); expect(root.dependencyMap).toEqual({ bar: ['foo'] }); }); @@ -84,8 +84,8 @@ describe('analyze properties', () => { let bar = [foo1, first, last]; }) `); - expect(root.properties.length).toBe(1); - expect(root.properties[0].isComputed).toBe(true); + expect(root.variables.length).toBe(1); + expect(root.variables[0].isComputed).toBe(true); expect(root.dependencyMap).toEqual({ bar: ['foo1', 'first', 'last'] }); }); @@ -96,8 +96,8 @@ describe('analyze properties', () => { let bar = cond ? count : window.innerWidth; }) `); - expect(root.properties.length).toBe(1); - expect(root.properties[0].isComputed).toBe(false); + expect(root.variables.length).toBe(1); + expect(root.variables[0].isComputed).toBe(false); expect(root.dependencyMap).toEqual({}); }); }); @@ -112,9 +112,9 @@ describe('analyze properties', () => { }); }) `); - expect(root.properties.length).toBe(2); + expect(root.variables.length).toBe(2); expect(root.dependencyMap).toEqual({ Sub: ['foo'] }); - expect((root.properties[1].value as ComponentNode).dependencyMap).toMatchInlineSnapshot(` + expect((root.variables[1].value as ComponentNode).dependencyMap).toMatchInlineSnapshot(` { "bar": [ "foo", @@ -135,9 +135,9 @@ describe('analyze properties', () => { function onInput() {} }) `); - expect(root.properties.map(p => p.name)).toEqual(['foo', 'onClick', 'onHover', 'onInput']); - expect(root.properties[1].isMethod).toBe(true); - expect(root.properties[2].isMethod).toBe(true); + expect(root.variables.map(p => p.name)).toEqual(['foo', 'onClick', 'onHover', 'onInput']); + expect(root.variables[1].type).toBe('method'); + expect(root.variables[2].type).toBe('method'); expect(root.dependencyMap).toMatchInlineSnapshot('{}'); }); }); diff --git a/packages/transpiler/babel-inula-next-core/test/analyze/watchAnalyze.test.ts b/packages/transpiler/babel-inula-next-core/test/analyze/watchAnalyze.test.ts index ea38ca80..36f436b6 100644 --- a/packages/transpiler/babel-inula-next-core/test/analyze/watchAnalyze.test.ts +++ b/packages/transpiler/babel-inula-next-core/test/analyze/watchAnalyze.test.ts @@ -1,9 +1,8 @@ -import { propsAnalyze } from '../../src/analyze/propsAnalyze'; -import { watchAnalyze } from '../../src/analyze/watchAnalyze'; +import { functionalMacroAnalyze } from '../../src/analyze/functionalMacroAnalyze'; import { genCode, mockAnalyze } from '../mock'; import { describe, expect, it } from 'vitest'; -const analyze = (code: string) => mockAnalyze(code, [watchAnalyze]); +const analyze = (code: string) => mockAnalyze(code, [functionalMacroAnalyze]); describe('watchAnalyze', () => { it('should analyze watch expressions', () => {