diff --git a/packages/code-generator/src/generator/ProjectBuilder.ts b/packages/code-generator/src/generator/ProjectBuilder.ts index ec1c897b6..34211d0e5 100644 --- a/packages/code-generator/src/generator/ProjectBuilder.ts +++ b/packages/code-generator/src/generator/ProjectBuilder.ts @@ -24,8 +24,8 @@ interface IModuleInfo { function getDirFromRoot(root: IResultDir, path: string[]): IResultDir { let current: IResultDir = root; - path.forEach(p => { - const exist = current.dirs.find(d => d.name === p); + path.forEach((p) => { + const exist = current.dirs.find((d) => d.name === p); if (exist) { current = exist; } else { @@ -57,7 +57,7 @@ export class ProjectBuilder implements IProjectBuilder { this.postProcessors = postProcessors; } - public async generateProject(schema: IProjectSchema | string): Promise { + async generateProject(schema: IProjectSchema | string): Promise { // Init const schemaParser: ISchemaParser = new SchemaParser(); const builders = this.createModuleBuilders(); @@ -76,7 +76,7 @@ export class ProjectBuilder implements IProjectBuilder { // components // pages const containerBuildResult: IModuleInfo[] = await Promise.all( - parseResult.containers.map(async containerInfo => { + parseResult.containers.map(async (containerInfo) => { let builder: IModuleBuilder; let path: string[]; if (containerInfo.containerType === 'Page') { @@ -100,9 +100,7 @@ export class ProjectBuilder implements IProjectBuilder { // router if (parseResult.globalRouter && builders.router) { - const { files } = await builders.router.generateModule( - parseResult.globalRouter, - ); + const { files } = await builders.router.generateModule(parseResult.globalRouter); buildResult.push({ path: this.template.slots.router.path, @@ -112,9 +110,7 @@ export class ProjectBuilder implements IProjectBuilder { // entry if (parseResult.project && builders.entry) { - const { files } = await builders.entry.generateModule( - parseResult.project, - ); + const { files } = await builders.entry.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.entry.path, @@ -122,14 +118,8 @@ export class ProjectBuilder implements IProjectBuilder { }); } // constants? - if ( - parseResult.project && - builders.constants && - this.template.slots.constants - ) { - const { files } = await builders.constants.generateModule( - parseResult.project, - ); + if (parseResult.project && builders.constants && this.template.slots.constants) { + const { files } = await builders.constants.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.constants.path, @@ -137,14 +127,8 @@ export class ProjectBuilder implements IProjectBuilder { }); } // utils? - if ( - parseResult.globalUtils && - builders.utils && - this.template.slots.utils - ) { - const { files } = await builders.utils.generateModule( - parseResult.globalUtils, - ); + if (parseResult.globalUtils && builders.utils && this.template.slots.utils) { + const { files } = await builders.utils.generateModule(parseResult.globalUtils); buildResult.push({ path: this.template.slots.utils.path, @@ -153,9 +137,7 @@ export class ProjectBuilder implements IProjectBuilder { } // i18n? if (parseResult.globalI18n && builders.i18n && this.template.slots.i18n) { - const { files } = await builders.i18n.generateModule( - parseResult.globalI18n, - ); + const { files } = await builders.i18n.generateModule(parseResult.globalI18n); buildResult.push({ path: this.template.slots.i18n.path, @@ -164,9 +146,7 @@ export class ProjectBuilder implements IProjectBuilder { } // globalStyle if (parseResult.project && builders.globalStyle) { - const { files } = await builders.globalStyle.generateModule( - parseResult.project, - ); + const { files } = await builders.globalStyle.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.globalStyle.path, @@ -175,9 +155,7 @@ export class ProjectBuilder implements IProjectBuilder { } // htmlEntry if (parseResult.project && builders.htmlEntry) { - const { files } = await builders.htmlEntry.generateModule( - parseResult.project, - ); + const { files } = await builders.htmlEntry.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.htmlEntry.path, @@ -186,9 +164,7 @@ export class ProjectBuilder implements IProjectBuilder { } // packageJSON if (parseResult.project && builders.packageJSON) { - const { files } = await builders.packageJSON.generateModule( - parseResult.project, - ); + const { files } = await builders.packageJSON.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.packageJSON.path, @@ -199,14 +175,14 @@ export class ProjectBuilder implements IProjectBuilder { // Post Process // Combine Modules - buildResult.forEach(moduleInfo => { + buildResult.forEach((moduleInfo) => { let targetDir = getDirFromRoot(projectRoot, moduleInfo.path); if (moduleInfo.moduleName) { const dir = new ResultDir(moduleInfo.moduleName); targetDir.addDirectory(dir); targetDir = dir; } - moduleInfo.files.forEach(file => targetDir.addFile(file)); + moduleInfo.files.forEach((file) => targetDir.addFile(file)); }); return projectRoot; @@ -215,7 +191,7 @@ export class ProjectBuilder implements IProjectBuilder { private createModuleBuilders(): Record { const builders: Record = {}; - Object.keys(this.plugins).forEach(pluginName => { + Object.keys(this.plugins).forEach((pluginName) => { if (this.plugins[pluginName].length > 0) { const options: { mainFileName?: string } = {}; if (this.template.slots[pluginName] && this.template.slots[pluginName].fileName) { diff --git a/packages/code-generator/src/plugins/common/esmodule.ts b/packages/code-generator/src/plugins/common/esmodule.ts index 50f315e52..2fbff2fed 100644 --- a/packages/code-generator/src/plugins/common/esmodule.ts +++ b/packages/code-generator/src/plugins/common/esmodule.ts @@ -15,6 +15,8 @@ import { IWithDependency, } from '../../types'; +import { isValidIdentifier } from '../../utils/validate'; + function groupDepsByPack(deps: IDependency[]): Record { const depMap: Record = {}; @@ -25,48 +27,53 @@ function groupDepsByPack(deps: IDependency[]): Record { depMap[pkg].push(dep); }; - deps.forEach(dep => { + // TODO: main 这个信息到底怎么用,是不是外部包不需要使用? + // deps.forEach(dep => { + // if (dep.dependencyType === DependencyType.Internal) { + // addDep( + // `${(dep as IInternalDependency).moduleName}${`/${dep.main}` || ''}`, + // dep, + // ); + // } else { + // addDep(`${(dep as IExternalDependency).package}${`/${dep.main}` || ''}`, dep); + // } + // }); + + deps.forEach((dep) => { if (dep.dependencyType === DependencyType.Internal) { - addDep( - `${(dep as IInternalDependency).moduleName}${`/${dep.main}` || ''}`, - dep, - ); + addDep(`${(dep as IInternalDependency).moduleName}`, dep); } else { - addDep(`${(dep as IExternalDependency).package}${`/${dep.main}` || ''}`, dep); + addDep(`${(dep as IExternalDependency).package}`, dep); } }); return depMap; } -function buildPackageImport( - pkg: string, - deps: IDependency[], - targetFileType: string, -): ICodeChunk[] { +function buildPackageImport(pkg: string, deps: IDependency[], targetFileType: string): ICodeChunk[] { const chunks: ICodeChunk[] = []; - let defaultImport: string = ''; - let defaultImportAs: string = ''; + let defaultImport = ''; + let defaultImportAs = ''; const imports: Record = {}; - deps.forEach(dep => { + deps.forEach((dep) => { const srcName = dep.exportName; let targetName = dep.importName || dep.exportName; - if (dep.subName) { - return; - } if (dep.subName) { - chunks.push({ - type: ChunkType.STRING, - fileType: targetFileType, - name: COMMON_CHUNK_NAME.FileVarDefine, - content: `const ${targetName} = ${srcName}.${dep.subName};`, - linkAfter: [ - COMMON_CHUNK_NAME.ExternalDepsImport, - COMMON_CHUNK_NAME.InternalDepsImport, - ], - }); + if (targetName !== `${srcName}.${dep.subName}`) { + if (!isValidIdentifier(targetName)) { + throw new CodeGeneratorError(`Invalid Identifier [${targetName}]`); + } + + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.FileVarDefine, + content: `const ${targetName} = ${srcName}.${dep.subName};`, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport], + }); + } targetName = srcName; } @@ -74,18 +81,14 @@ function buildPackageImport( if (dep.destructuring) { imports[srcName] = targetName; } else if (defaultImport) { - throw new CodeGeneratorError( - `[${pkg}] has more than one default export.`, - ); + throw new CodeGeneratorError(`[${pkg}] has more than one default export.`); } else { defaultImport = srcName; defaultImportAs = targetName; } }); - const items = Object.keys(imports).map(src => - src === imports[src] ? src : `${src} as ${imports[src]}`, - ); + const items = Object.keys(imports).map((src) => (src === imports[src] ? src : `${src} as ${imports[src]}`)); const statementL = ['import']; if (defaultImport) { @@ -125,7 +128,7 @@ function buildPackageImport( type PluginConfig = { fileType: string; -} +}; const pluginFactory: BuilderComponentPluginFactory = (config?: PluginConfig) => { const cfg: PluginConfig = { @@ -143,9 +146,9 @@ const pluginFactory: BuilderComponentPluginFactory = (config?: Plu if (ir && ir.deps && ir.deps.length > 0) { const packs = groupDepsByPack(ir.deps); - Object.keys(packs).forEach(pkg => { + Object.keys(packs).forEach((pkg) => { const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType); - next.chunks.push.apply(next.chunks, chunks); + next.chunks.push(...chunks); }); } diff --git a/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts b/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts index d1951d8e2..000355b7d 100644 --- a/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts +++ b/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts @@ -1,28 +1,23 @@ import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; import { REACT_CHUNK_NAME } from './const'; -import { - getFuncExprBody, - transformFuncExpr2MethodMember, -} from '../../../utils/jsExpression'; +import { generateFunction } from '../../../utils/jsExpression'; import { BuilderComponentPlugin, BuilderComponentPluginFactory, ChunkType, - CodeGeneratorError, FileType, ICodeChunk, ICodeStruct, IContainerInfo, - IJSExpression, } from '../../../types'; type PluginConfig = { fileType: string; exportNameMapping: Record; normalizeNameMapping: Record; -} +}; const pluginFactory: BuilderComponentPluginFactory = (config?) => { const cfg: PluginConfig = { @@ -41,7 +36,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => if (ir.lifeCycles) { const lifeCycles = ir.lifeCycles; - const chunks = Object.keys(lifeCycles).map(lifeCycleName => { + const chunks = Object.keys(lifeCycles).map((lifeCycleName) => { const normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName; const exportName = cfg.exportNameMapping[lifeCycleName] || lifeCycleName; if (normalizeName === 'constructor') { @@ -49,9 +44,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => type: ChunkType.STRING, fileType: cfg.fileType, name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, - content: getFuncExprBody( - (lifeCycles[lifeCycleName] as IJSExpression).value, - ), + content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }), linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]], }; } @@ -60,9 +53,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => type: ChunkType.STRING, fileType: cfg.fileType, name: REACT_CHUNK_NAME.ClassRenderPre, - content: getFuncExprBody( - (lifeCycles[lifeCycleName] as IJSExpression).value, - ), + content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }), linkAfter: [REACT_CHUNK_NAME.ClassRenderStart], }; } @@ -71,15 +62,12 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => type: ChunkType.STRING, fileType: cfg.fileType, name: CLASS_DEFINE_CHUNK_NAME.InsMethod, - content: transformFuncExpr2MethodMember( - exportName, - (lifeCycles[lifeCycleName] as IJSExpression).value, - ), + content: generateFunction(lifeCycles[lifeCycleName], { name: exportName, isMember: true }), linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], }; }); - next.chunks.push.apply(next.chunks, chunks); + next.chunks.push(...chunks); } return next; diff --git a/packages/code-generator/src/plugins/component/react/containerMethod.ts b/packages/code-generator/src/plugins/component/react/containerMethod.ts index 9bba467da..148f2cffd 100644 --- a/packages/code-generator/src/plugins/component/react/containerMethod.ts +++ b/packages/code-generator/src/plugins/component/react/containerMethod.ts @@ -1,6 +1,6 @@ import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; -import { transformFuncExpr2MethodMember } from '../../../utils/jsExpression'; +import { generateFunction } from '../../../utils/jsExpression'; import { BuilderComponentPlugin, @@ -10,12 +10,11 @@ import { ICodeChunk, ICodeStruct, IContainerInfo, - IJSExpression, } from '../../../types'; type PluginConfig = { fileType: string; -} +}; const pluginFactory: BuilderComponentPluginFactory = (config?) => { const cfg: PluginConfig = { @@ -32,18 +31,15 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => if (ir.methods) { const methods = ir.methods; - const chunks = Object.keys(methods).map(methodName => ({ + const chunks = Object.keys(methods).map((methodName) => ({ type: ChunkType.STRING, fileType: cfg.fileType, name: CLASS_DEFINE_CHUNK_NAME.InsMethod, - content: transformFuncExpr2MethodMember( - methodName, - (methods[methodName] as IJSExpression).value, - ), + content: generateFunction(methods[methodName], { name: methodName, isMember: true }), linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], })); - next.chunks.push.apply(next.chunks, chunks); + next.chunks.push(...chunks); } return next; diff --git a/packages/code-generator/src/solutions/icejs.ts b/packages/code-generator/src/solutions/icejs.ts index 66a865cbe..b1a35052e 100644 --- a/packages/code-generator/src/solutions/icejs.ts +++ b/packages/code-generator/src/solutions/icejs.ts @@ -59,6 +59,7 @@ export default function createIceJsProjectBuilder(): IProjectBuilder { Component: 'div', Page: 'div', Block: 'div', + // Box: 'div', }, }), css(), @@ -72,6 +73,6 @@ export default function createIceJsProjectBuilder(): IProjectBuilder { htmlEntry: [icejs.plugins.entryHtml()], packageJSON: [icejs.plugins.packageJSON()], }, - postProcessors: [prettier()], + postProcessors: [prettier()], // prettier() }); } diff --git a/packages/code-generator/src/types/schema.ts b/packages/code-generator/src/types/schema.ts index 68226e8ab..8ce54afa3 100644 --- a/packages/code-generator/src/types/schema.ts +++ b/packages/code-generator/src/types/schema.ts @@ -13,18 +13,36 @@ export interface IJSExpression { [extConfigName: string]: any; } +/** + * 搭建基础协议 - 函数定义 + * + * @export + * @interface IJSFunction + */ +export interface IJSFunction { + type: 'JSFunction'; + value: string; + [extConfigName: string]: any; +} + +/** + * 搭建基础协议 - 函数定义 + * + * @export + * @interface IJSSlot + */ +export interface IJSSlot { + type: 'JSSlot'; + value: IComponentNodeItem; + [extConfigName: string]: any; +} + // JSON 基本类型 export interface IJSONObject { [key: string]: JSONValue; } -export type JSONValue = - | boolean - | string - | number - | null - | JSONArray - | IJSONObject; +export type JSONValue = boolean | string | number | null | JSONArray | IJSONObject; export type JSONArray = JSONValue[]; export type CompositeArray = CompositeValue[]; @@ -33,11 +51,7 @@ export interface ICompositeObject { } // 复合类型 -export type CompositeValue = - | JSONValue - | IJSExpression - | CompositeArray - | ICompositeObject; +export type CompositeValue = JSONValue | IJSExpression | IJSFunction | IJSSlot | CompositeArray | ICompositeObject; /** * 搭建基础协议 - 多语言描述 @@ -136,8 +150,8 @@ export interface IContainerNodeItem extends IComponentNodeItem { * • componentWillUnmount() * • componentDidCatch(error, info) */ - lifeCycles?: Record; // 生命周期Hook方法 - methods?: Record; // 自定义方法设置 + lifeCycles?: Record; // 生命周期Hook方法 + methods?: Record; // 自定义方法设置 dataSource?: { list: IDataSourceConfig[]; }; // 异步数据源配置 @@ -154,9 +168,9 @@ export interface IDataSourceConfig { id: string; // 数据请求ID标识 isInit: boolean; // 是否为初始数据 支持表达式 值为true时,将在组件初始化渲染时自动发送当前数据请求 type: string; // 数据请求类型 'fetch' | 'mtop' | 'jsonp' | 'custom' - requestHandler?: IJSExpression; // 自定义扩展的外部请求处理器 仅type='custom'时生效 + requestHandler?: IJSExpression | IJSFunction; // 自定义扩展的外部请求处理器 仅type='custom'时生效 options?: IFetchOptions; // 请求参数配置 每种请求类型对应不同参数 - dataHandler?: IJSExpression; // 数据结果处理函数,形如:(data, err) => Object + dataHandler?: IJSExpression | IJSFunction; // 数据结果处理函数,形如:(data, err) => Object } /** diff --git a/packages/code-generator/src/utils/compositeType.ts b/packages/code-generator/src/utils/compositeType.ts index b62b2afe3..8c9011512 100644 --- a/packages/code-generator/src/utils/compositeType.ts +++ b/packages/code-generator/src/utils/compositeType.ts @@ -1,5 +1,5 @@ import { CompositeArray, CompositeValue, ICompositeObject } from '../types'; -import { generateExpression, isJsExpression } from './jsExpression'; +import { generateExpression, generateFunction, isJsExpression, isJsFunction } from './jsExpression'; type CustomHandler = (data: unknown) => string; interface CustomHandlerSet { @@ -11,18 +11,12 @@ interface CustomHandlerSet { expression?: CustomHandler; } -function generateArray( - value: CompositeArray, - handlers: CustomHandlerSet = {}, -): string { - const body = value.map(v => generateUnknownType(v, handlers)).join(','); +function generateArray(value: CompositeArray, handlers: CustomHandlerSet = {}): string { + const body = value.map((v) => generateUnknownType(v, handlers)).join(','); return `[${body}]`; } -function generateObject( - value: ICompositeObject, - handlers: CustomHandlerSet = {}, -): string { +function generateObject(value: ICompositeObject, handlers: CustomHandlerSet = {}): string { if (isJsExpression(value)) { if (handlers.expression) { return handlers.expression(value); @@ -30,8 +24,12 @@ function generateObject( return generateExpression(value); } + if (isJsFunction(value)) { + return generateFunction(value, { isArrow: true }); + } + const body = Object.keys(value) - .map(key => { + .map((key) => { const v = generateUnknownType(value[key], handlers); return `${key}: ${v}`; }) @@ -40,10 +38,7 @@ function generateObject( return `{${body}}`; } -export function generateUnknownType( - value: CompositeValue, - handlers: CustomHandlerSet = {}, -): string { +export function generateUnknownType(value: CompositeValue, handlers: CustomHandlerSet = {}): string { if (Array.isArray(value)) { if (handlers.array) { return handlers.array(value); @@ -67,10 +62,7 @@ export function generateUnknownType( return `${value}`; } -export function generateCompositeType( - value: CompositeValue, - handlers: CustomHandlerSet = {}, -): [boolean, string] { +export function generateCompositeType(value: CompositeValue, handlers: CustomHandlerSet = {}): [boolean, string] { const result = generateUnknownType(value, handlers); if (result.substr(0, 1) === "'" && result.substr(-1, 1) === "'") { diff --git a/packages/code-generator/src/utils/jsExpression.ts b/packages/code-generator/src/utils/jsExpression.ts index 9c8541692..d975228ee 100644 --- a/packages/code-generator/src/utils/jsExpression.ts +++ b/packages/code-generator/src/utils/jsExpression.ts @@ -1,39 +1,6 @@ -import traverse from '@babel/traverse'; -import * as parser from '@babel/parser'; -import { CodeGeneratorError, IJSExpression } from '../types'; - -let count = 0; - -function test(functionBody: string) { - console.log(functionBody); - console.log('---->'); - try { - const parseResult = parser.parse(functionBody); - // console.log(JSON.stringify(parseResult)); - traverse(parseResult, { - enter(path) { - console.log('path: ', JSON.stringify(path)); - } - }); - - if (count === 0) { - count++; - - test('this.aaa && this.bbb'); - } - } catch (error) { - // console.log('Error'); - console.log(error.message); - } - console.log('====================='); -} - -export function transformFuncExpr2MethodMember( - methodName: string, - functionBody: string, -): string { - // test(functionBody); +import { CodeGeneratorError, IJSExpression, IJSFunction } from '../types'; +export function transformFuncExpr2MethodMember(methodName: string, functionBody: string): string { const args = getFuncExprArguments(functionBody); const body = getFuncExprBody(functionBody); @@ -66,20 +33,60 @@ export function getFuncExprBody(functionBody: string) { return body; } -export function generateExpression(value: any): string { - if (value && (value as IJSExpression).type === 'JSExpression') { - // test((value as IJSExpression).value); +export function getArrowFunction(functionBody: string) { + const args = getFuncExprArguments(functionBody); + const body = getFuncExprBody(functionBody); + return `(${args}) => { ${body} }`; +} + +export function isJsExpression(value: unknown): boolean { + return value && typeof value === 'object' && (value as IJSExpression).type === 'JSExpression'; +} + +export function isJsFunction(value: unknown): boolean { + return value && typeof value === 'object' && (value as IJSFunction).type === 'JSFunction'; +} + +export function isJsCode(value: unknown): boolean { + return isJsExpression(value) || isJsFunction(value); +} + +export function generateExpression(value: any): string { + if (isJsExpression(value)) { return (value as IJSExpression).value || 'null'; } throw new CodeGeneratorError('Not a JSExpression'); } -export function isJsExpression(value: any): boolean { - return ( - value && - typeof value === 'object' && - (value as IJSExpression).type === 'JSExpression' - ); +export function generateFunction( + value: any, + config: { + name?: string; + isMember?: boolean; + isBlock?: boolean; + isArrow?: boolean; + } = { + name: undefined, + isMember: false, + isBlock: false, + isArrow: false, + }, +) { + if (isJsCode(value)) { + const functionCfg = value as IJSFunction; + if (config.isMember) { + return transformFuncExpr2MethodMember(config.name || '', functionCfg.value); + } + if (config.isBlock) { + return getFuncExprBody(functionCfg.value); + } + if (config.isArrow) { + return getArrowFunction(functionCfg.value); + } + return functionCfg.value; + } + + throw new CodeGeneratorError('Not a JSFunction or JSExpression'); } diff --git a/packages/code-generator/src/utils/nodeToJSX.ts b/packages/code-generator/src/utils/nodeToJSX.ts index 050d64f9d..ef6b4617e 100644 --- a/packages/code-generator/src/utils/nodeToJSX.ts +++ b/packages/code-generator/src/utils/nodeToJSX.ts @@ -11,7 +11,7 @@ import { INodeGeneratorConfig, } from '../types'; import { generateCompositeType } from './compositeType'; -import { generateExpression } from './jsExpression'; +import { generateExpression, isJsExpression } from './jsExpression'; // tslint:disable-next-line: no-empty const noop = () => []; @@ -24,7 +24,7 @@ export function handleChildren( children: ChildNodeType, handlers: HandlerSet, options?: { - rerun?: boolean, + rerun?: boolean; }, ): T[] { const opt = { @@ -34,13 +34,11 @@ export function handleChildren( if (Array.isArray(children)) { const list: ChildNodeItem[] = children as ChildNodeItem[]; - return list - .map(child => handleChildren(child, handlers, opt)) - .reduce((p, c) => p.concat(c), []); + return list.map((child) => handleChildren(child, handlers, opt)).reduce((p, c) => p.concat(c), []); } else if (typeof children === 'string') { const handler = handlers.string || handlers.common || noop; return handler(children as string); - } else if ((children as IJSExpression).type === 'JSExpression') { + } else if (isJsExpression(children)) { const handler = handlers.expression || handlers.common || noop; return handler(children as IJSExpression); } else { @@ -59,19 +57,19 @@ export function generateAttr(attrName: string, attrValue: any): CodePiece[] { return []; } const [isString, valueStr] = generateCompositeType(attrValue); - return [{ - value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`, - type: PIECE_TYPE.ATTR, - }]; + return [ + { + value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`, + type: PIECE_TYPE.ATTR, + }, + ]; } export function generateAttrs(nodeItem: IComponentNodeItem): CodePiece[] { const { props } = nodeItem; let pieces: CodePiece[] = []; - Object.keys(props).forEach((propName: string) => - pieces = pieces.concat(generateAttr(propName, props[propName])), - ); + Object.keys(props).forEach((propName: string) => (pieces = pieces.concat(generateAttr(propName, props[propName])))); return pieces; } @@ -98,8 +96,8 @@ export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[] if (nodeItem.loop && nodeItem.loopArgs) { let loopDataExp; - if ((nodeItem.loop as IJSExpression).type === 'JSExpression') { - loopDataExp = `(${(nodeItem.loop as IJSExpression).value})`; + if (isJsExpression(nodeItem.loop)) { + loopDataExp = `(${generateExpression(nodeItem.loop)})`; } else { loopDataExp = JSON.stringify(nodeItem.loop); } @@ -141,29 +139,29 @@ export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[] } export function linkPieces(pieces: CodePiece[]): string { - if (pieces.filter(p => p.type === PIECE_TYPE.TAG).length !== 1) { + if (pieces.filter((p) => p.type === PIECE_TYPE.TAG).length !== 1) { throw new CodeGeneratorError('One node only need one tag define'); } - const tagName = pieces.filter(p => p.type === PIECE_TYPE.TAG)[0].value; + const tagName = pieces.filter((p) => p.type === PIECE_TYPE.TAG)[0].value; const beforeParts = pieces - .filter(p => p.type === PIECE_TYPE.BEFORE) - .map(p => p.value) + .filter((p) => p.type === PIECE_TYPE.BEFORE) + .map((p) => p.value) .join(''); const afterParts = pieces - .filter(p => p.type === PIECE_TYPE.AFTER) - .map(p => p.value) + .filter((p) => p.type === PIECE_TYPE.AFTER) + .map((p) => p.value) .join(''); const childrenParts = pieces - .filter(p => p.type === PIECE_TYPE.CHILDREN) - .map(p => p.value) + .filter((p) => p.type === PIECE_TYPE.CHILDREN) + .map((p) => p.value) .join(''); let attrsParts = pieces - .filter(p => p.type === PIECE_TYPE.ATTR) - .map(p => p.value) + .filter((p) => p.type === PIECE_TYPE.ATTR) + .map((p) => p.value) .join(' '); attrsParts = !!attrsParts ? ` ${attrsParts}` : ''; @@ -188,16 +186,18 @@ export function createNodeGenerator( const generateNode = (nodeItem: IComponentNodeItem): string => { let pieces: CodePiece[] = []; - plugins.forEach(p => { + plugins.forEach((p) => { pieces = pieces.concat(p(nodeItem)); }); pieces = pieces.concat(generateBasicNode(nodeItem, nodeTypeMapping)); pieces = pieces.concat(generateAttrs(nodeItem)); if (nodeItem.children && (nodeItem.children as unknown[]).length > 0) { - pieces = pieces.concat(handleChildren(nodeItem.children, handlers).map(l => ({ - type: PIECE_TYPE.CHILDREN, - value: l, - }))); + pieces = pieces.concat( + handleChildren(nodeItem.children, handlers).map((l) => ({ + type: PIECE_TYPE.CHILDREN, + value: l, + })), + ); } return linkPieces(pieces); @@ -211,10 +211,12 @@ export function createNodeGenerator( export const generateString = (input: string) => [input]; export function createReactNodeGenerator(cfg?: INodeGeneratorConfig) { - return createNodeGenerator({ - string: generateString, - expression: (input) => [generateExpression(input)], - }, [ - generateReactCtrlLine, - ], cfg); + return createNodeGenerator( + { + string: generateString, + expression: (input) => [generateExpression(input)], + }, + [generateReactCtrlLine], + cfg, + ); } diff --git a/packages/code-generator/src/utils/validate.ts b/packages/code-generator/src/utils/validate.ts new file mode 100644 index 000000000..118d21ad4 --- /dev/null +++ b/packages/code-generator/src/utils/validate.ts @@ -0,0 +1,3 @@ +export const isValidIdentifier = (name: string) => { + return /^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/.test(name); +};