feat: sub component
This commit is contained in:
parent
5427f13880
commit
f15b7d1a14
|
@ -5,9 +5,7 @@ import { createComponentNode } from './nodeFactory';
|
|||
import { propertiesAnalyze } from './propertiesAnalyze';
|
||||
import { lifeCycleAnalyze } from './lifeCycleAnalyze';
|
||||
import { getFnBody } from '../utils';
|
||||
|
||||
const builtinAnalyzers = [propsAnalyze, propertiesAnalyze, lifeCycleAnalyze];
|
||||
let analyzers: Analyzer[] = builtinAnalyzers;
|
||||
|
||||
export function isCondNode(node: any): node is CondNode {
|
||||
return node && node.type === 'cond';
|
||||
|
@ -36,16 +34,17 @@ function mergeVisitor(...visitors: Analyzer[]): Visitor {
|
|||
|
||||
// walk through the function component body
|
||||
export function analyzeFnComp(
|
||||
types: typeof t,
|
||||
fnNode: NodePath<t.FunctionExpression | t.ArrowFunctionExpression>,
|
||||
componentNode: ComponentNode,
|
||||
{ htmlTags, analyzers }: { analyzers: Analyzer[]; htmlTags: string[] },
|
||||
level = 0
|
||||
) {
|
||||
const visitor = mergeVisitor(...analyzers);
|
||||
const context: AnalyzeContext = {
|
||||
level,
|
||||
t: types,
|
||||
current: componentNode,
|
||||
htmlTags,
|
||||
analyzers,
|
||||
traverse: (path: NodePath<t.Statement>, ctx: AnalyzeContext) => {
|
||||
path.traverse(visitor, ctx);
|
||||
},
|
||||
|
@ -94,17 +93,14 @@ export function analyzeFnComp(
|
|||
* @param customAnalyzers
|
||||
*/
|
||||
export function analyze(
|
||||
types: typeof t,
|
||||
fnName: string,
|
||||
path: NodePath<t.FunctionExpression | t.ArrowFunctionExpression>,
|
||||
customAnalyzers?: Analyzer[]
|
||||
options: { customAnalyzers?: Analyzer[]; htmlTags: string[] }
|
||||
) {
|
||||
if (customAnalyzers) {
|
||||
analyzers = customAnalyzers;
|
||||
}
|
||||
const analyzers = options?.customAnalyzers ? options.customAnalyzers : builtinAnalyzers;
|
||||
|
||||
const root = createComponentNode(fnName, path);
|
||||
analyzeFnComp(types, path, root);
|
||||
analyzeFnComp(path, root, { analyzers, htmlTags: options.htmlTags });
|
||||
|
||||
return root;
|
||||
}
|
||||
|
|
|
@ -27,45 +27,43 @@ export function createComponentNode(
|
|||
name,
|
||||
props: [],
|
||||
child: undefined,
|
||||
subComponents: [],
|
||||
properties: [],
|
||||
dependencyMap: {},
|
||||
reactiveMap: {},
|
||||
lifecycle: {},
|
||||
parent,
|
||||
// fnBody,
|
||||
get availableProperties() {
|
||||
return comp.properties
|
||||
.filter(({ isMethod }) => !isMethod)
|
||||
.map(({ name }) => name)
|
||||
.concat(
|
||||
comp.props
|
||||
get availableProps() {
|
||||
return comp.props
|
||||
.map(({ name, nestedProps, alias }) => {
|
||||
const nested = nestedProps ? nestedProps.map(name => name) : [];
|
||||
return [alias ? alias : name, ...nested];
|
||||
})
|
||||
.flat()
|
||||
);
|
||||
.flat();
|
||||
},
|
||||
get ownAvailableProperties() {
|
||||
return [...comp.properties.filter(p => !p.isMethod).map(({ name }) => name), ...comp.availableProps];
|
||||
},
|
||||
get availableProperties() {
|
||||
return [...comp.ownAvailableProperties, ...(comp.parent ? comp.parent.availableProperties : [])];
|
||||
},
|
||||
};
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
export function addProperty(
|
||||
comp: ComponentNode,
|
||||
name: string,
|
||||
value: t.Expression | null,
|
||||
isComputed: boolean,
|
||||
isMethod = false
|
||||
) {
|
||||
comp.properties.push({ name, value, isComputed, isMethod });
|
||||
export function addProperty(comp: ComponentNode, name: string, value: t.Expression | null, isComputed: boolean) {
|
||||
comp.properties.push({ name, value, isComputed, isMethod: false });
|
||||
}
|
||||
|
||||
export function addMethod(comp: ComponentNode, name: string, value: t.Expression | null) {
|
||||
comp.properties.push({ name, value, isComputed: false, isMethod: true });
|
||||
}
|
||||
|
||||
export function addSubComponent(comp: ComponentNode, subComp: ComponentNode, isComputed: boolean) {
|
||||
comp.properties.push({ name: subComp.name, value: subComp, isSubComp: true, isComputed, isMethod: false });
|
||||
}
|
||||
|
||||
export function addProp(
|
||||
comp: ComponentNode,
|
||||
type: PropType,
|
||||
|
|
|
@ -14,12 +14,19 @@
|
|||
*/
|
||||
|
||||
import { AnalyzeContext, Visitor } from './types';
|
||||
import { addLifecycle, addMethod, addProperty } from './nodeFactory';
|
||||
import { addMethod, addProperty, createComponentNode } from './nodeFactory';
|
||||
import { isValidPath } from './utils';
|
||||
import { type types as t, type NodePath } from '@babel/core';
|
||||
import { reactivityFuncNames } from '../const';
|
||||
import { types } from '../babelTypes';
|
||||
import { COMPONENT } from '../constants';
|
||||
import { analyzeFnComp } from '.';
|
||||
|
||||
/**
|
||||
* collect all properties and methods from the node
|
||||
* and analyze the dependencies of the properties
|
||||
* @returns
|
||||
*/
|
||||
export function propertiesAnalyze(): Visitor {
|
||||
return {
|
||||
VariableDeclaration(path: NodePath<t.VariableDeclaration>, ctx) {
|
||||
|
@ -38,10 +45,28 @@ export function propertiesAnalyze(): Visitor {
|
|||
const init = declaration.get('init');
|
||||
let deps: string[] | null = null;
|
||||
if (isValidPath(init)) {
|
||||
// the property is a method
|
||||
if (init.isArrowFunctionExpression() || init.isFunctionExpression()) {
|
||||
addMethod(ctx.current, id.node.name, init.node);
|
||||
return;
|
||||
}
|
||||
// Should like Component(() => {})
|
||||
if (
|
||||
init.isCallExpression() &&
|
||||
init.get('callee').isIdentifier() &&
|
||||
(init.get('callee').node as t.Identifier).name === COMPONENT &&
|
||||
(init.get('arguments')[0].isFunctionExpression() || init.get('arguments')[0].isArrowFunctionExpression())
|
||||
) {
|
||||
const fnNode = init.get('arguments')[0] as
|
||||
| NodePath<t.ArrowFunctionExpression>
|
||||
| NodePath<t.FunctionExpression>;
|
||||
const subComponent = createComponentNode(id.node.name, fnNode, ctx.current);
|
||||
|
||||
analyzeFnComp(fnNode, subComponent, ctx);
|
||||
deps = getDependenciesFromNode(id.node.name, init, ctx);
|
||||
addProperty(ctx.current, id.node.name, subComponent, !!deps?.length);
|
||||
return;
|
||||
}
|
||||
deps = getDependenciesFromNode(id.node.name, init, ctx);
|
||||
}
|
||||
addProperty(ctx.current, id.node.name, init.node || null, !!deps?.length);
|
||||
|
|
|
@ -3,64 +3,6 @@ import { AnalyzeContext, Visitor } from './types';
|
|||
import { addProp } from './nodeFactory';
|
||||
import { PropType } from '../constants';
|
||||
import { types } from '../babelTypes';
|
||||
function analyzeSingleProp(
|
||||
value: t.ObjectProperty['value'],
|
||||
key: string,
|
||||
path: NodePath<t.ObjectProperty>,
|
||||
{ t, current }: AnalyzeContext
|
||||
) {
|
||||
let defaultVal: t.Expression | null = null;
|
||||
let alias: string | null = null;
|
||||
const nestedProps: string[] | null = [];
|
||||
let nestedRelationship: t.ObjectPattern | t.ArrayPattern | null = null;
|
||||
if (t.isIdentifier(value)) {
|
||||
// 1. handle alias without default value
|
||||
// handle alias without default value
|
||||
if (key !== value.name) {
|
||||
alias = value.name;
|
||||
}
|
||||
} else if (t.isAssignmentPattern(value)) {
|
||||
// 2. handle default value case
|
||||
const assignedName = value.left;
|
||||
defaultVal = value.right;
|
||||
if (t.isIdentifier(assignedName)) {
|
||||
if (assignedName.name !== key) {
|
||||
// handle alias in default value case
|
||||
alias = assignedName.name;
|
||||
}
|
||||
} else {
|
||||
throw Error(`Unsupported assignment type in object destructuring: ${assignedName.type}`);
|
||||
}
|
||||
} else if (t.isObjectPattern(value) || t.isArrayPattern(value)) {
|
||||
// 3. nested destructuring
|
||||
// we should collect the identifier that can be used in the function body as the prop
|
||||
// e.g. function ({prop1, prop2: [p20X, {p211, p212: p212X}]}
|
||||
// we should collect prop1, p20X, p211, p212X
|
||||
path.get('value').traverse({
|
||||
Identifier(path) {
|
||||
// judge if the identifier is a prop
|
||||
// 1. is the key of the object property and doesn't have alias
|
||||
// 2. is the item of the array pattern and doesn't have alias
|
||||
// 3. is alias of the object property
|
||||
const parentPath = path.parentPath;
|
||||
if (parentPath.isObjectProperty() && path.parentKey === 'value') {
|
||||
// collect alias of the object property
|
||||
nestedProps.push(path.node.name);
|
||||
} else if (
|
||||
parentPath.isArrayPattern() ||
|
||||
parentPath.isObjectPattern() ||
|
||||
parentPath.isRestElement() ||
|
||||
(parentPath.isAssignmentPattern() && path.key === 'left')
|
||||
) {
|
||||
// collect the key of the object property or the item of the array pattern
|
||||
nestedProps.push(path.node.name);
|
||||
}
|
||||
},
|
||||
});
|
||||
nestedRelationship = value;
|
||||
}
|
||||
addProp(current, PropType.SINGLE, key, defaultVal, alias, nestedProps, nestedRelationship);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze the props deconstructing in the function component
|
||||
|
@ -104,3 +46,62 @@ export function propsAnalyze(): Visitor {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
function analyzeSingleProp(
|
||||
value: t.ObjectProperty['value'],
|
||||
key: string,
|
||||
path: NodePath<t.ObjectProperty>,
|
||||
{ current }: AnalyzeContext
|
||||
) {
|
||||
let defaultVal: t.Expression | null = null;
|
||||
let alias: string | null = null;
|
||||
const nestedProps: string[] | null = [];
|
||||
let nestedRelationship: t.ObjectPattern | t.ArrayPattern | null = null;
|
||||
if (types.isIdentifier(value)) {
|
||||
// 1. handle alias without default value
|
||||
// handle alias without default value
|
||||
if (key !== value.name) {
|
||||
alias = value.name;
|
||||
}
|
||||
} else if (types.isAssignmentPattern(value)) {
|
||||
// 2. handle default value case
|
||||
const assignedName = value.left;
|
||||
defaultVal = value.right;
|
||||
if (types.isIdentifier(assignedName)) {
|
||||
if (assignedName.name !== key) {
|
||||
// handle alias in default value case
|
||||
alias = assignedName.name;
|
||||
}
|
||||
} else {
|
||||
throw Error(`Unsupported assignment type in object destructuring: ${assignedName.type}`);
|
||||
}
|
||||
} else if (types.isObjectPattern(value) || types.isArrayPattern(value)) {
|
||||
// 3. nested destructuring
|
||||
// we should collect the identifier that can be used in the function body as the prop
|
||||
// e.g. function ({prop1, prop2: [p20X, {p211, p212: p212X}]}
|
||||
// we should collect prop1, p20X, p211, p212X
|
||||
path.get('value').traverse({
|
||||
Identifier(path) {
|
||||
// judge if the identifier is a prop
|
||||
// 1. is the key of the object property and doesn't have alias
|
||||
// 2. is the item of the array pattern and doesn't have alias
|
||||
// 3. is alias of the object property
|
||||
const parentPath = path.parentPath;
|
||||
if (parentPath.isObjectProperty() && path.parentKey === 'value') {
|
||||
// collect alias of the object property
|
||||
nestedProps.push(path.node.name);
|
||||
} else if (
|
||||
parentPath.isArrayPattern() ||
|
||||
parentPath.isObjectPattern() ||
|
||||
parentPath.isRestElement() ||
|
||||
(parentPath.isAssignmentPattern() && path.key === 'left')
|
||||
) {
|
||||
// collect the key of the object property or the item of the array pattern
|
||||
nestedProps.push(path.node.name);
|
||||
}
|
||||
},
|
||||
});
|
||||
nestedRelationship = value;
|
||||
}
|
||||
addProp(current, PropType.SINGLE, key, defaultVal, alias, nestedProps, nestedRelationship);
|
||||
}
|
||||
|
|
|
@ -23,17 +23,22 @@ 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 Property {
|
||||
interface BaseProperty<V> {
|
||||
name: string;
|
||||
value: t.Expression | null;
|
||||
// indicate the value is a state or computed or watch
|
||||
listeners?: string[];
|
||||
bitmap?: Bitmap;
|
||||
value: V;
|
||||
// need a flag for computed to gen a getter
|
||||
// watch is a static computed
|
||||
isComputed: boolean;
|
||||
isMethod: boolean;
|
||||
}
|
||||
interface Property extends BaseProperty<t.Expression | null> {
|
||||
// indicate the value is a state or computed or watch
|
||||
listeners?: string[];
|
||||
bitmap?: Bitmap;
|
||||
}
|
||||
interface SubCompProperty extends BaseProperty<ComponentNode> {
|
||||
isSubComp: true;
|
||||
}
|
||||
interface Prop {
|
||||
name: string;
|
||||
type: PropType;
|
||||
|
@ -47,7 +52,15 @@ export interface ComponentNode {
|
|||
name: string;
|
||||
props: Prop[];
|
||||
// A properties could be a state or computed
|
||||
properties: Property[];
|
||||
properties: (Property | SubCompProperty)[];
|
||||
/**
|
||||
* The available props for the component, including the nested props
|
||||
*/
|
||||
availableProps: string[];
|
||||
/**
|
||||
* The available properties for the component
|
||||
*/
|
||||
ownAvailableProperties: string[];
|
||||
availableProperties: string[];
|
||||
/**
|
||||
* The map to find the dependencies
|
||||
|
@ -56,7 +69,6 @@ export interface ComponentNode {
|
|||
[key: string]: string[];
|
||||
};
|
||||
child?: InulaNode;
|
||||
subComponents?: ComponentNode[];
|
||||
parent?: ComponentNode;
|
||||
/**
|
||||
* The function body of the fn component code
|
||||
|
@ -103,8 +115,9 @@ export interface Branch {
|
|||
|
||||
export interface AnalyzeContext {
|
||||
level: number;
|
||||
t: typeof t;
|
||||
current: ComponentNode;
|
||||
analyzers: Analyzer[];
|
||||
htmlTags: string[];
|
||||
traverse: (p: NodePath<t.Statement>, ctx: AnalyzeContext) => void;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 { Visitor } from './types';
|
||||
import { type types as t, type NodePath } from '@babel/core';
|
||||
import { parseView as parseJSX } from 'jsx-view-parser';
|
||||
import { getBabelApi } from '../babelTypes';
|
||||
import { parseReactivity } from '@openinula/reactivity-parser';
|
||||
import { reactivityFuncNames } from '../const';
|
||||
|
||||
/**
|
||||
* Analyze the watch in the function component
|
||||
*/
|
||||
export function viewAnalyze(): Visitor {
|
||||
return {
|
||||
ReturnStatement(path: NodePath<t.ReturnStatement>, { htmlTags, current }) {
|
||||
const returnNode = path.get('argument');
|
||||
if (returnNode.isJSXElement() || returnNode.isJSXFragment()) {
|
||||
const viewUnits = parseJSX(returnNode.node, {
|
||||
babelApi: getBabelApi(),
|
||||
htmlTags,
|
||||
parseTemplate: false,
|
||||
});
|
||||
const [viewParticles, usedPropertySet] = parseReactivity(viewUnits, {
|
||||
babelApi: getBabelApi(),
|
||||
availableProperties: current.availableProperties,
|
||||
dependencyMap: current.dependencyMap,
|
||||
reactivityFuncNames,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,8 +1,17 @@
|
|||
import { type types as t } from '@babel/core';
|
||||
import type babel from '@babel/core';
|
||||
let _t: null | typeof types = null;
|
||||
let babelApi: typeof babel | null = null;
|
||||
export const register = (api: typeof babel) => {
|
||||
babelApi = api;
|
||||
_t = api.types;
|
||||
};
|
||||
|
||||
export const register = (types: typeof t) => {
|
||||
_t = types;
|
||||
export const getBabelApi = (): typeof babel => {
|
||||
if (!babelApi) {
|
||||
throw new Error('Please call register() before using the babel api');
|
||||
}
|
||||
return babelApi;
|
||||
};
|
||||
|
||||
export const types = new Proxy(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type babel from '@babel/core';
|
||||
import { type PluginObj } from '@babel/core';
|
||||
import { type DLightOption } from './types';
|
||||
import { defaultAttributeMap } from './const';
|
||||
import { defaultAttributeMap, defaultHTMLTags } from './const';
|
||||
import { analyze } from './analyze';
|
||||
import { NodePath, type types as t } from '@babel/core';
|
||||
import { COMPONENT } from './constants';
|
||||
|
@ -14,11 +14,18 @@ export default function (api: typeof babel, options: DLightOption): PluginObj {
|
|||
files = '**/*.{js,ts,jsx,tsx}',
|
||||
excludeFiles = '**/{dist,node_modules,lib}/*',
|
||||
enableDevTools = false,
|
||||
htmlTags = defaultHtmlTags => defaultHtmlTags,
|
||||
customHtmlTags = defaultHtmlTags => defaultHtmlTags,
|
||||
attributeMap = defaultAttributeMap,
|
||||
} = options;
|
||||
|
||||
register(types);
|
||||
const htmlTags =
|
||||
typeof customHtmlTags === 'function'
|
||||
? customHtmlTags(defaultHTMLTags)
|
||||
: customHtmlTags.includes('*')
|
||||
? [...new Set([...defaultHTMLTags, ...customHtmlTags])].filter(tag => tag !== '*')
|
||||
: customHtmlTags;
|
||||
|
||||
register(api);
|
||||
return {
|
||||
visitor: {
|
||||
Program: {
|
||||
|
@ -45,7 +52,9 @@ export default function (api: typeof babel, options: DLightOption): PluginObj {
|
|||
console.error('Component macro must be assigned to a variable');
|
||||
}
|
||||
}
|
||||
const root = analyze(types, name, componentNode);
|
||||
const root = analyze(name, componentNode, {
|
||||
htmlTags,
|
||||
});
|
||||
// The sub path has been visited, so we just skip
|
||||
path.skip();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import { describe, expect, it } from 'vitest';
|
|||
import { genCode, mockAnalyze } from '../mock';
|
||||
import { propertiesAnalyze } from '../../src/analyze/propertiesAnalyze';
|
||||
import { propsAnalyze } from '../../src/analyze/propsAnalyze';
|
||||
import { ComponentNode } from '../../src/analyze/types';
|
||||
|
||||
const analyze = (code: string) => mockAnalyze(code, [propsAnalyze, propertiesAnalyze]);
|
||||
|
||||
|
@ -101,6 +102,28 @@ describe('analyze properties', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('subComponent', () => {
|
||||
it('should analyze dependency from subComponent', () => {
|
||||
const root = analyze(`
|
||||
Component(() => {
|
||||
let foo = 1;
|
||||
const Sub = Component(() => {
|
||||
let bar = foo;
|
||||
});
|
||||
})
|
||||
`);
|
||||
expect(root.properties.length).toBe(2);
|
||||
expect(root.dependencyMap).toEqual({ Sub: ['foo'] });
|
||||
expect((root.properties[1].value as ComponentNode).dependencyMap).toMatchInlineSnapshot(`
|
||||
{
|
||||
"bar": [
|
||||
"foo",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should collect method', () => {
|
||||
const root = analyze(`
|
||||
Component(() => {
|
||||
|
@ -115,6 +138,6 @@ describe('analyze properties', () => {
|
|||
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.dependencyMap).toMatchInlineSnapshot(`{}`);
|
||||
expect(root.dependencyMap).toMatchInlineSnapshot('{}');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { propertiesAnalyze } from '../../src/analyze/propertiesAnalyze';
|
||||
import { propsAnalyze } from '../../src/analyze/propsAnalyze';
|
||||
import { viewAnalyze } from '../../src/analyze/viewAnalyze';
|
||||
import { genCode, mockAnalyze } from '../mock';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
const analyze = (code: string) => mockAnalyze(code, [propsAnalyze, propertiesAnalyze, viewAnalyze]);
|
||||
|
||||
describe('watchAnalyze', () => {
|
||||
it('should analyze watch expressions', () => {
|
||||
const root = analyze(/*js*/ `
|
||||
Comp(({name}) => {
|
||||
let count = 11
|
||||
return <div className={name}>{count}</div>
|
||||
})
|
||||
`);
|
||||
expect(true).toHaveLength(1);
|
||||
});
|
||||
});
|
|
@ -14,12 +14,13 @@
|
|||
*/
|
||||
|
||||
import { Analyzer, ComponentNode, InulaNode } from '../src/analyze/types';
|
||||
import babel, { type PluginObj, transform as transformWithBabel } from '@babel/core';
|
||||
import { type PluginObj, transform as transformWithBabel } from '@babel/core';
|
||||
import syntaxJSX from '@babel/plugin-syntax-jsx';
|
||||
import { analyze } from '../src/analyze';
|
||||
import generate from '@babel/generator';
|
||||
import * as t from '@babel/types';
|
||||
import { register } from '../src/babelTypes';
|
||||
import { defaultHTMLTags } from '../src/const';
|
||||
|
||||
export function mockAnalyze(code: string, analyzers?: Analyzer[]): ComponentNode {
|
||||
let root: ComponentNode | null = null;
|
||||
|
@ -27,17 +28,17 @@ export function mockAnalyze(code: string, analyzers?: Analyzer[]): ComponentNode
|
|||
plugins: [
|
||||
syntaxJSX.default ?? syntaxJSX,
|
||||
function (api): PluginObj {
|
||||
register(api.types);
|
||||
register(api);
|
||||
return {
|
||||
visitor: {
|
||||
FunctionExpression: path => {
|
||||
root = analyze(api.types, 'test', path, analyzers);
|
||||
root = analyze('test', path, { customAnalyzers: analyzers, htmlTags: defaultHTMLTags });
|
||||
if (root) {
|
||||
path.skip();
|
||||
}
|
||||
},
|
||||
ArrowFunctionExpression: path => {
|
||||
root = analyze(api.types, 'test', path, analyzers);
|
||||
root = analyze('test', path, { customAnalyzers: analyzers, htmlTags: defaultHTMLTags });
|
||||
if (root) {
|
||||
path.skip();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue