diff --git a/packages/code-generator/demo/demo.js b/packages/code-generator/demo/demo.js
new file mode 100644
index 000000000..91e145de9
--- /dev/null
+++ b/packages/code-generator/demo/demo.js
@@ -0,0 +1,53 @@
+const fs = require('fs');
+const CodeGenerator = require('../lib').default;
+
+function flatFiles(rootName, dir) {
+ const dirRoot = rootName ? `${rootName}/${dir.name}` : dir.name;
+ const files = dir.files.map(file => ({
+ name: `${dirRoot}/${file.name}.${file.ext}`,
+ content: file.content,
+ ext: '',
+ }));
+ const filesInSub = dir.dirs.map(subDir => flatFiles(`${dirRoot}`, subDir));
+ const result = files.concat.apply(files, filesInSub);
+
+ return result;
+}
+
+function displayResultInConsole(root, fileName) {
+ const files = flatFiles('.', root);
+ files.forEach(file => {
+ if (!fileName || fileName === file.name) {
+ console.log(`========== ${file.name} Start ==========`);
+ console.log(file.content);
+ console.log(`========== ${file.name} End ==========`);
+ }
+ });
+}
+
+async function writeResultToDisk(root, path) {
+ const publisher = CodeGenerator.publishers.disk();
+
+ return publisher.publish({
+ project: root,
+ outputPath: path,
+ projectSlug: 'demo-project',
+ createProjectFolder: true,
+ });
+}
+
+function main() {
+ const schemaJson = fs.readFileSync('./demo/sampleSchema.json', { encoding: 'utf8' });
+ const createIceJsProjectBuilder = CodeGenerator.solutions.icejs;
+ const builder = createIceJsProjectBuilder();
+
+ builder.generateProject(schemaJson).then(result => {
+ displayResultInConsole(result);
+ writeResultToDisk(result, 'output/lowcodeDemo').then(response =>
+ console.log('Write to disk: ', JSON.stringify(response)),
+ );
+ return result;
+ });
+}
+
+main();
diff --git a/packages/code-generator/demo/sampleSchema.json b/packages/code-generator/demo/sampleSchema.json
new file mode 100644
index 000000000..079289fac
--- /dev/null
+++ b/packages/code-generator/demo/sampleSchema.json
@@ -0,0 +1,243 @@
+{
+ "version": "1.0.0",
+ "componentsMap": [
+ {
+ "componentName": "Button",
+ "package": "@alifd/next",
+ "version": "1.19.18",
+ "destructuring": true,
+ "exportName": "Button"
+ },
+ {
+ "componentName": "Button.Group",
+ "package": "@alifd/next",
+ "version": "1.19.18",
+ "destructuring": true,
+ "exportName": "Button",
+ "subName": "Group"
+ },
+ {
+ "componentName": "Input",
+ "package": "@alifd/next",
+ "version": "1.19.18",
+ "destructuring": true,
+ "exportName": "Input"
+ },
+ {
+ "componentName": "Form",
+ "package": "@alifd/next",
+ "version": "1.19.18",
+ "destructuring": true,
+ "exportName": "Form"
+ },
+ {
+ "componentName": "Form.Item",
+ "package": "@alifd/next",
+ "version": "1.19.18",
+ "destructuring": true,
+ "exportName": "Form",
+ "subName": "Item"
+ },
+ {
+ "componentName": "NumberPicker",
+ "package": "@alifd/next",
+ "version": "1.19.18",
+ "destructuring": true,
+ "exportName": "NumberPicker"
+ },
+ {
+ "componentName": "Select",
+ "package": "@alifd/next",
+ "version": "1.19.18",
+ "destructuring": true,
+ "exportName": "Select"
+ }
+ ],
+ "componentsTree": [
+ {
+ "componentName": "Page",
+ "id": "node$1",
+ "meta": {
+ "title": "测试",
+ "router": "/"
+ },
+ "props": {
+ "ref": "outterView",
+ "autoLoading": true
+ },
+ "fileName": "test",
+ "state": {
+ "text": "outter"
+ },
+ "lifeCycles": {
+ "componentDidMount": {
+ "type": "JSExpression",
+ "value": "function() { this.utils.request(this.props.url); }"
+ }
+ },
+ "children": [
+ {
+ "componentName": "Form",
+ "id": "node$2",
+ "props": {
+ "labelCol": {
+ "type": "JSExpression",
+ "value": "this.state.colNum"
+ },
+ "style": {},
+ "ref": "testForm"
+ },
+ "children": [
+ {
+ "componentName": "Form.Item",
+ "id": "node$3",
+ "props": {
+ "label": "姓名:",
+ "name": "name",
+ "initValue": "李雷"
+ },
+ "children": [
+ {
+ "componentName": "Input",
+ "id": "node$4",
+ "props": {
+ "placeholder": "请输入",
+ "size": "medium",
+ "style": {
+ "width": 320
+ }
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node$5",
+ "props": {
+ "label": "年龄:",
+ "name": "age",
+ "initValue": "22"
+ },
+ "children": [
+ {
+ "componentName": "NumberPicker",
+ "id": "node$6",
+ "props": {
+ "size": "medium",
+ "type": "normal"
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node$7",
+ "props": {
+ "label": "职业:",
+ "name": "profession"
+ },
+ "children": [
+ {
+ "componentName": "Select",
+ "id": "node$8",
+ "props": {
+ "dataSource": [
+ {
+ "label": "教师",
+ "value": "t"
+ },
+ {
+ "label": "医生",
+ "value": "d"
+ },
+ {
+ "label": "歌手",
+ "value": "s"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Div",
+ "id": "node$9",
+ "props": {
+ "style": {
+ "textAlign": "center"
+ }
+ },
+ "children": [
+ {
+ "componentName": "Button.Group",
+ "id": "node$a",
+ "props": {},
+ "children": [
+ {
+ "componentName": "Button",
+ "id": "node$b",
+ "props": {
+ "type": "primary",
+ "style": {
+ "margin": "0 5px 0 5px"
+ },
+ "htmlType": "submit"
+ },
+ "children": [
+ "提交"
+ ]
+ },
+ {
+ "componentName": "Button",
+ "id": "node$d",
+ "props": {
+ "type": "normal",
+ "style": {
+ "margin": "0 5px 0 5px"
+ },
+ "htmlType": "reset"
+ },
+ "children": [
+ "重置"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "constants": {
+ "ENV": "prod",
+ "DOMAIN": "xxx.alibaba-inc.com"
+ },
+ "css": "body {font-size: 12px;} .table { width: 100px;}",
+ "config": {
+ "sdkVersion": "1.0.3",
+ "historyMode": "hash",
+ "targetRootID": "J_Container",
+ "layout": {
+ "componentName": "BasicLayout",
+ "props": {
+ "logo": "...",
+ "name": "测试网站"
+ }
+ },
+ "theme": {
+ "package": "@alife/theme-fusion",
+ "version": "^0.1.0",
+ "primary": "#ff9966"
+ }
+ },
+ "meta": {
+ "name": "demo应用",
+ "git_group": "appGroup",
+ "project_name": "app_demo",
+ "description": "这是一个测试应用",
+ "spma": "spa23d",
+ "creator": "月飞"
+ }
+}
diff --git a/packages/code-generator/package.json b/packages/code-generator/package.json
index af7a4e06c..3bffb2689 100644
--- a/packages/code-generator/package.json
+++ b/packages/code-generator/package.json
@@ -8,17 +8,24 @@
],
"scripts": {
"build": "rimraf lib && tsc",
- "demo": "ts-node -r tsconfig-paths/register ./src/demo/main.ts",
- "test": "ava"
+ "demo": "node ./demo/demo.js",
+ "test": "ava",
+ "template": "node ./tools/createTemplate.js"
},
"dependencies": {
"@ali/am-eslint-config": "*",
+ "@ali/my-prettier": "^1.0.0",
+ "@babel/generator": "^7.9.5",
+ "@babel/parser": "^7.9.4",
+ "@babel/traverse": "^7.9.5",
+ "@babel/types": "^7.9.5",
"@types/prettier": "^1.19.1",
"change-case": "^3.1.0",
"prettier": "^2.0.2",
"short-uuid": "^3.1.1"
},
"devDependencies": {
+ "@types/babel__traverse": "^7.0.10",
"ava": "^1.0.1",
"rimraf": "^3.0.2",
"ts-loader": "^6.2.2",
diff --git a/packages/code-generator/src/@types/ali__my-prettier/index.d.ts b/packages/code-generator/src/@types/ali__my-prettier/index.d.ts
new file mode 100644
index 000000000..d21a2b18a
--- /dev/null
+++ b/packages/code-generator/src/@types/ali__my-prettier/index.d.ts
@@ -0,0 +1,6 @@
+///
+
+declare module '@ali/my-prettier' {
+ function format(text: string, type: string): string;
+ export default format;
+}
diff --git a/packages/code-generator/src/const/generator.ts b/packages/code-generator/src/const/generator.ts
index 329adfee5..9028b9226 100644
--- a/packages/code-generator/src/const/generator.ts
+++ b/packages/code-generator/src/const/generator.ts
@@ -8,6 +8,107 @@ export const COMMON_CHUNK_NAME = {
StyleDepsImport: 'CommonStyleDepsImport',
StyleCssContent: 'CommonStyleCssContent',
HtmlContent: 'CommonHtmlContent',
+ CustomContent: 'CommonCustomContent',
};
+export const CLASS_DEFINE_CHUNK_NAME = {
+ Start: 'CommonClassDefineStart',
+ ConstructorStart: 'CommonClassDefineConstructorStart',
+ ConstructorContent: 'CommonClassDefineConstructorContent',
+ ConstructorEnd: 'CommonClassDefineConstructorEnd',
+ StaticVar: 'CommonClassDefineStaticVar',
+ StaticMethod: 'CommonClassDefineStaticMethod',
+ InsVar: 'CommonClassDefineInsVar',
+ InsVarMethod: 'CommonClassDefineInsVarMethod',
+ InsMethod: 'CommonClassDefineInsMethod',
+ End: 'CommonClassDefineEnd',
+};
+
+export const DEFAULT_LINK_AFTER = {
+ [COMMON_CHUNK_NAME.ExternalDepsImport]: [],
+ [COMMON_CHUNK_NAME.InternalDepsImport]: [COMMON_CHUNK_NAME.ExternalDepsImport],
+ [COMMON_CHUNK_NAME.FileVarDefine]: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ ],
+ [COMMON_CHUNK_NAME.FileUtilDefine]: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.Start]: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.ConstructorStart]: [
+ CLASS_DEFINE_CHUNK_NAME.Start,
+ CLASS_DEFINE_CHUNK_NAME.StaticVar,
+ CLASS_DEFINE_CHUNK_NAME.StaticMethod,
+ CLASS_DEFINE_CHUNK_NAME.InsVar,
+ CLASS_DEFINE_CHUNK_NAME.InsVarMethod,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.ConstructorContent]: [
+ CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]: [
+ CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
+ CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.StaticVar]: [
+ CLASS_DEFINE_CHUNK_NAME.Start,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.StaticMethod]: [
+ CLASS_DEFINE_CHUNK_NAME.Start,
+ CLASS_DEFINE_CHUNK_NAME.StaticVar,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.InsVar]: [
+ CLASS_DEFINE_CHUNK_NAME.Start,
+ CLASS_DEFINE_CHUNK_NAME.StaticVar,
+ CLASS_DEFINE_CHUNK_NAME.StaticMethod,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.InsVarMethod]: [
+ CLASS_DEFINE_CHUNK_NAME.Start,
+ CLASS_DEFINE_CHUNK_NAME.StaticVar,
+ CLASS_DEFINE_CHUNK_NAME.StaticMethod,
+ CLASS_DEFINE_CHUNK_NAME.InsVar,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.InsMethod]: [
+ CLASS_DEFINE_CHUNK_NAME.Start,
+ CLASS_DEFINE_CHUNK_NAME.StaticVar,
+ CLASS_DEFINE_CHUNK_NAME.StaticMethod,
+ CLASS_DEFINE_CHUNK_NAME.InsVar,
+ CLASS_DEFINE_CHUNK_NAME.InsVarMethod,
+ CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,
+ ],
+ [CLASS_DEFINE_CHUNK_NAME.End]: [
+ CLASS_DEFINE_CHUNK_NAME.Start,
+ CLASS_DEFINE_CHUNK_NAME.StaticVar,
+ CLASS_DEFINE_CHUNK_NAME.StaticMethod,
+ CLASS_DEFINE_CHUNK_NAME.InsVar,
+ CLASS_DEFINE_CHUNK_NAME.InsVarMethod,
+ CLASS_DEFINE_CHUNK_NAME.InsMethod,
+ CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,
+ ],
+ [COMMON_CHUNK_NAME.FileMainContent]: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ CLASS_DEFINE_CHUNK_NAME.End,
+ ],
+ [COMMON_CHUNK_NAME.FileExport]: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ CLASS_DEFINE_CHUNK_NAME.End,
+ COMMON_CHUNK_NAME.FileMainContent,
+ ],
+ [COMMON_CHUNK_NAME.StyleDepsImport]: [],
+ [COMMON_CHUNK_NAME.StyleCssContent]: [COMMON_CHUNK_NAME.StyleDepsImport],
+ [COMMON_CHUNK_NAME.HtmlContent]: [],
+}
+
export const COMMON_SUB_MODULE_NAME = 'index';
diff --git a/packages/code-generator/src/demo/main.ts b/packages/code-generator/src/demo/main.ts
deleted file mode 100644
index e0d341ef4..000000000
--- a/packages/code-generator/src/demo/main.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { IResultDir, IResultFile } from '../types';
-
-import CodeGenerator from '../index';
-import { createDiskPublisher } from '../publisher/disk';
-import demoSchema from './simpleDemo';
-
-function flatFiles(rootName: string | null, dir: IResultDir): IResultFile[] {
- const dirRoot: string = rootName ? `${rootName}/${dir.name}` : dir.name;
- const files: IResultFile[] = dir.files.map(file => ({
- name: `${dirRoot}/${file.name}.${file.ext}`,
- content: file.content,
- ext: '',
- }));
- const filesInSub = dir.dirs.map(subDir => flatFiles(`${dirRoot}`, subDir));
- const result: IResultFile[] = files.concat.apply(files, filesInSub);
-
- return result;
-}
-
-function displayResultInConsole(root: IResultDir, fileName?: string): void {
- const files = flatFiles('.', root);
- files.forEach(file => {
- if (!fileName || fileName === file.name) {
- console.log(`========== ${file.name} Start ==========`);
- console.log(file.content);
- console.log(`========== ${file.name} End ==========`);
- }
- });
-}
-
-async function writeResultToDisk(root: IResultDir, path: string): Promise {
- const publisher = createDiskPublisher();
-
- return publisher.publish({
- project: root,
- outputPath: path,
- projectSlug: 'demo-project',
- createProjectFolder: true,
- });
-}
-
-function main() {
- const createIceJsProjectBuilder = CodeGenerator.solutions.icejs;
- const builder = createIceJsProjectBuilder();
- builder.generateProject(demoSchema).then(result => {
- // displayResultInConsole(result, '././src/routes.js');
- writeResultToDisk(result, '/Users/armslave/lowcodeDemo').then(response =>
- console.log('Write to disk: ', JSON.stringify(response)),
- );
- });
-}
-
-main();
diff --git a/packages/code-generator/src/demo/simpleDemo.ts b/packages/code-generator/src/demo/simpleDemo.ts
deleted file mode 100644
index 2e1f28a76..000000000
--- a/packages/code-generator/src/demo/simpleDemo.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-import { IProjectSchema } from '../types';
-
-const demoData: IProjectSchema = {
- version: '1.0.0',
- componentsMap: [
- {
- componentName: 'Button',
- package: '@alifd/next',
- version: '1.19.18',
- destructuring: true,
- exportName: 'Button',
- },
- {
- componentName: 'Button.Group',
- package: '@alifd/next',
- version: '1.19.18',
- destructuring: true,
- exportName: 'Button',
- subName: 'Group',
- },
- {
- componentName: 'Input',
- package: '@alifd/next',
- version: '1.19.18',
- destructuring: true,
- exportName: 'Input',
- },
- {
- componentName: 'Form',
- package: '@alifd/next',
- version: '1.19.18',
- destructuring: true,
- exportName: 'Form',
- },
- {
- componentName: 'Form.Item',
- package: '@alifd/next',
- version: '1.19.18',
- destructuring: true,
- exportName: 'Form',
- subName: 'Item',
- },
- {
- componentName: 'NumberPicker',
- package: '@alifd/next',
- version: '1.19.18',
- destructuring: true,
- exportName: 'NumberPicker',
- },
- {
- componentName: 'Select',
- package: '@alifd/next',
- version: '1.19.18',
- destructuring: true,
- exportName: 'Select',
- },
- ],
- componentsTree: [
- {
- componentName: 'Page',
- id: 'node_1',
- meta: {
- title: '测试',
- router: '/',
- },
- props: {
- ref: 'outterView',
- autoLoading: true,
- },
- fileName: 'test',
- state: {
- text: 'outter',
- },
- children: [
- {
- componentName: 'Form',
- id: 'node_2',
- props: {
- labelCol: 4,
- style: {},
- ref: 'testForm',
- },
- children: [
- {
- componentName: 'Form.Item',
- id: 'node_3',
- props: {
- label: '姓名:',
- name: 'name',
- initValue: '李雷',
- },
- children: [
- {
- componentName: 'Input',
- id: 'node_4',
- props: {
- placeholder: '请输入',
- size: 'medium',
- style: {
- width: 320,
- },
- },
- },
- ],
- },
- {
- componentName: 'Form.Item',
- id: 'node_5',
- props: {
- label: '年龄:',
- name: 'age',
- initValue: '22',
- },
- children: [
- {
- componentName: 'NumberPicker',
- id: 'node_6',
- props: {
- size: 'medium',
- type: 'normal',
- },
- },
- ],
- },
- {
- componentName: 'Form.Item',
- id: 'node_7',
- props: {
- label: '职业:',
- name: 'profession',
- },
- children: [
- {
- componentName: 'Select',
- id: 'node_8',
- props: {
- dataSource: [
- {
- label: '教师',
- value: 't',
- },
- {
- label: '医生',
- value: 'd',
- },
- {
- label: '歌手',
- value: 's',
- },
- ],
- },
- },
- ],
- },
- {
- componentName: 'Div',
- id: 'node_9',
- props: {
- style: {
- textAlign: 'center',
- },
- },
- children: [
- {
- componentName: 'Button.Group',
- id: 'node_a',
- props: {},
- children: [
- {
- componentName: 'Button',
- id: 'node_b',
- props: {
- type: 'primary',
- style: {
- margin: '0 5px 0 5px',
- },
- htmlType: 'submit',
- },
- children: ['提交'],
- },
- {
- componentName: 'Button',
- id: 'node_d',
- props: {
- type: 'normal',
- style: {
- margin: '0 5px 0 5px',
- },
- htmlType: 'reset',
- },
- children: ['重置'],
- },
- ],
- },
- ],
- },
- ],
- },
- ],
- },
- ],
- constants: {
- ENV: 'prod',
- DOMAIN: 'xxx.alibaba-inc.com',
- },
- css: 'body {font-size: 12px;} .table { width: 100px;}',
- config: {
- sdkVersion: '1.0.3',
- historyMode: 'hash',
- targetRootID: 'J_Container',
- layout: {
- componentName: 'BasicLayout',
- props: {
- logo: '...',
- name: '测试网站',
- },
- },
- theme: {
- package: '@alife/theme-fusion',
- version: '^0.1.0',
- primary: '#ff9966',
- },
- },
- meta: {
- name: 'demo应用',
- git_group: 'appGroup',
- project_name: 'app_demo',
- description: '这是一个测试应用',
- spma: 'spa23d',
- creator: '月飞',
- },
-};
-
-export default demoData;
diff --git a/packages/code-generator/src/generator/CodeBuilder.ts b/packages/code-generator/src/generator/CodeBuilder.ts
index 1e5c3c999..ad7f33622 100644
--- a/packages/code-generator/src/generator/CodeBuilder.ts
+++ b/packages/code-generator/src/generator/CodeBuilder.ts
@@ -62,10 +62,12 @@ export default class Builder implements ICodeBuilder {
}
unprocessedChunks.splice(indexToRemove, 1);
- unprocessedChunks.forEach(
- // remove the processed chunk from all the linkAfter arrays from the remaining chunks
- ch => (ch.linkAfter = ch.linkAfter.filter(after => after !== name)),
- );
+ if (!unprocessedChunks.some(ch => ch.name === name)) {
+ unprocessedChunks.forEach(
+ // remove the processed chunk from all the linkAfter arrays from the remaining chunks
+ ch => (ch.linkAfter = ch.linkAfter.filter(after => after !== name)),
+ );
+ }
}
return resultingString.join('\n');
diff --git a/packages/code-generator/src/generator/ModuleBuilder.ts b/packages/code-generator/src/generator/ModuleBuilder.ts
index 8115f0def..991ffedec 100644
--- a/packages/code-generator/src/generator/ModuleBuilder.ts
+++ b/packages/code-generator/src/generator/ModuleBuilder.ts
@@ -1,18 +1,24 @@
import {
BuilderComponentPlugin,
CodeGeneratorError,
+ IBasicSchema,
ICodeChunk,
ICompiledModule,
IModuleBuilder,
+ IParseResult,
+ IResultDir,
IResultFile,
+ ISchemaParser,
PostProcessor,
} from '../types';
import { COMMON_SUB_MODULE_NAME } from '../const/generator';
+import SchemaParser from '../parser/SchemaParser';
import ChunkBuilder from './ChunkBuilder';
import CodeBuilder from './CodeBuilder';
+import ResultDir from '../model/ResultDir';
import ResultFile from '../model/ResultFile';
export function createModuleBuilder(
@@ -66,6 +72,20 @@ export function createModuleBuilder(
};
};
+ const generateModuleCode = async (schema: IBasicSchema | string): Promise => {
+ // Init
+ const schemaParser: ISchemaParser = new SchemaParser();
+ const parseResult: IParseResult = schemaParser.parse(schema);
+
+ const containerInfo = parseResult.containers[0];
+ const { files } = await generateModule(containerInfo);
+
+ const dir = new ResultDir(containerInfo.moduleName);
+ files.forEach(file => dir.addFile(file));
+
+ return dir;
+ }
+
const linkCodeChunks = (
chunks: Record,
fileName: string,
@@ -88,6 +108,7 @@ export function createModuleBuilder(
return {
generateModule,
+ generateModuleCode,
linkCodeChunks,
addPlugin: chunkGenerator.addPlugin.bind(chunkGenerator),
};
diff --git a/packages/code-generator/src/generator/ProjectBuilder.ts b/packages/code-generator/src/generator/ProjectBuilder.ts
index ada2e47fd..ec1c897b6 100644
--- a/packages/code-generator/src/generator/ProjectBuilder.ts
+++ b/packages/code-generator/src/generator/ProjectBuilder.ts
@@ -57,8 +57,8 @@ export class ProjectBuilder implements IProjectBuilder {
this.postProcessors = postProcessors;
}
- public async generateProject(schema: IProjectSchema): Promise {
- // Init working parts
+ public async generateProject(schema: IProjectSchema | string): Promise {
+ // Init
const schemaParser: ISchemaParser = new SchemaParser();
const builders = this.createModuleBuilders();
const projectRoot = this.template.generateTemplate();
@@ -90,7 +90,7 @@ export class ProjectBuilder implements IProjectBuilder {
const { files } = await builder.generateModule(containerInfo);
return {
- moduleName: containerInfo.fileName,
+ moduleName: containerInfo.moduleName,
path,
files,
};
@@ -215,61 +215,19 @@ export class ProjectBuilder implements IProjectBuilder {
private createModuleBuilders(): Record {
const builders: Record = {};
- builders.components = createModuleBuilder({
- plugins: this.plugins.components,
- postProcessors: this.postProcessors,
+ 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) {
+ options.mainFileName = this.template.slots[pluginName].fileName;
+ }
+ builders[pluginName] = createModuleBuilder({
+ plugins: this.plugins[pluginName],
+ postProcessors: this.postProcessors,
+ ...options,
+ });
+ }
});
- builders.pages = createModuleBuilder({
- plugins: this.plugins.pages,
- postProcessors: this.postProcessors,
- });
- builders.router = createModuleBuilder({
- plugins: this.plugins.router,
- mainFileName: this.template.slots.router.fileName,
- postProcessors: this.postProcessors,
- });
- builders.entry = createModuleBuilder({
- plugins: this.plugins.entry,
- mainFileName: this.template.slots.entry.fileName,
- postProcessors: this.postProcessors,
- });
- builders.globalStyle = createModuleBuilder({
- plugins: this.plugins.globalStyle,
- mainFileName: this.template.slots.globalStyle.fileName,
- postProcessors: this.postProcessors,
- });
- builders.htmlEntry = createModuleBuilder({
- plugins: this.plugins.htmlEntry,
- mainFileName: this.template.slots.htmlEntry.fileName,
- postProcessors: this.postProcessors,
- });
- builders.packageJSON = createModuleBuilder({
- plugins: this.plugins.packageJSON,
- mainFileName: this.template.slots.packageJSON.fileName,
- postProcessors: this.postProcessors,
- });
-
- if (this.template.slots.constants && this.plugins.constants) {
- builders.constants = createModuleBuilder({
- plugins: this.plugins.constants,
- mainFileName: this.template.slots.constants.fileName,
- postProcessors: this.postProcessors,
- });
- }
- if (this.template.slots.utils && this.plugins.utils) {
- builders.utils = createModuleBuilder({
- plugins: this.plugins.utils,
- mainFileName: this.template.slots.utils.fileName,
- postProcessors: this.postProcessors,
- });
- }
- if (this.template.slots.i18n && this.plugins.i18n) {
- builders.i18n = createModuleBuilder({
- plugins: this.plugins.i18n,
- mainFileName: this.template.slots.i18n.fileName,
- postProcessors: this.postProcessors,
- });
- }
return builders;
}
diff --git a/packages/code-generator/src/index.ts b/packages/code-generator/src/index.ts
index a0af2ba95..9de9c1538 100644
--- a/packages/code-generator/src/index.ts
+++ b/packages/code-generator/src/index.ts
@@ -3,17 +3,78 @@
*
*/
import { createProjectBuilder } from './generator/ProjectBuilder';
+import { createModuleBuilder } from './generator/ModuleBuilder';
import { createDiskPublisher } from './publisher/disk';
import createIceJsProjectBuilder from './solutions/icejs';
+import createRecoreProjectBuilder from './solutions/recore';
+
+// 引入说明
+import { REACT_CHUNK_NAME } from './plugins/component/react/const';
+
+// 引入通用插件组
+import esmodule from './plugins/common/esmodule';
+import requireUtils from './plugins/common/requireUtils';
+import containerClass from './plugins/component/react/containerClass';
+import containerDataSource from './plugins/component/react/containerDataSource';
+import containerInitState from './plugins/component/react/containerInitState';
+import containerInjectUtils from './plugins/component/react/containerInjectUtils';
+import containerLifeCycle from './plugins/component/react/containerLifeCycle';
+import containerMethod from './plugins/component/react/containerMethod';
+import jsx from './plugins/component/react/jsx';
+import reactCommonDeps from './plugins/component/react/reactCommonDeps';
+import css from './plugins/component/style/css';
+import constants from './plugins/project/constants';
+import i18n from './plugins/project/i18n';
+import utils from './plugins/project/utils';
+
+// 引入常用工具
+import * as utilsCommon from './utils/common';
+import * as utilsCompositeType from './utils/compositeType';
+import * as utilsJsExpression from './utils/jsExpression';
+import * as utilsNodeToJSX from './utils/nodeToJSX';
+import * as utilsTemplateHelper from './utils/templateHelper';
export * from './types';
export default {
createProjectBuilder,
+ createModuleBuilder,
solutions: {
icejs: createIceJsProjectBuilder,
+ recore: createRecoreProjectBuilder,
},
publishers: {
disk: createDiskPublisher,
},
+ plugins: {
+ common: {
+ esmodule,
+ requireUtils,
+ },
+ react: {
+ containerClass,
+ containerDataSource,
+ containerInitState,
+ containerInjectUtils,
+ containerLifeCycle,
+ containerMethod,
+ jsx,
+ reactCommonDeps,
+ },
+ style: {
+ css,
+ },
+ project: {
+ constants,
+ i18n,
+ utils,
+ },
+ },
+ utils: {
+ common: utilsCommon,
+ compositeType: utilsCompositeType,
+ jsExpression: utilsJsExpression,
+ nodeToJSX: utilsNodeToJSX,
+ templateHelper: utilsTemplateHelper,
+ },
};
diff --git a/packages/code-generator/src/parser/SchemaParser.ts b/packages/code-generator/src/parser/SchemaParser.ts
index 4288d894b..d6b679ff0 100644
--- a/packages/code-generator/src/parser/SchemaParser.ts
+++ b/packages/code-generator/src/parser/SchemaParser.ts
@@ -5,7 +5,7 @@
import { SUPPORT_SCHEMA_VERSION_LIST } from '../const';
-import { handleChildren } from '../utils/children';
+import { handleChildren } from '../utils/nodeToJSX';
import {
ChildNodeType,
@@ -28,7 +28,8 @@ import {
const defaultContainer: IContainerInfo = {
containerType: 'Component',
- componentName: 'Index',
+ componentName: 'Component',
+ moduleName: 'Index',
fileName: 'Index',
css: '',
props: {},
@@ -45,12 +46,23 @@ class SchemaParser implements ISchemaParser {
return true;
}
- public parse(schema: IProjectSchema): IParseResult {
+ public parse(schemaSrc: IProjectSchema | string): IParseResult {
// TODO: collect utils depends in JSExpression
const compDeps: Record = {};
const internalDeps: Record = {};
let utilsDeps: IExternalDependency[] = [];
+ let schema: IProjectSchema;
+ if (typeof schemaSrc === 'string') {
+ try {
+ schema = JSON.parse(schemaSrc);
+ } catch (error) {
+ throw new CodeGeneratorError(`Parse schema failed: ${error.message || 'unknown reason'}`);
+ }
+ } else {
+ schema = schemaSrc;
+ }
+
// 解析三方组件依赖
schema.componentsMap.forEach(info => {
info.dependencyType = DependencyType.External;
@@ -78,7 +90,7 @@ class SchemaParser implements ISchemaParser {
const container: IContainerInfo = {
...subRoot,
containerType: subRoot.componentName,
- componentName: subRoot.fileName,
+ moduleName: subRoot.fileName, // TODO: 驼峰化名称
};
return container;
});
@@ -104,9 +116,9 @@ class SchemaParser implements ISchemaParser {
const dep: IInternalDependency = {
type,
- moduleName: container.componentName,
+ moduleName: container.moduleName,
destructuring: false,
- exportName: container.componentName,
+ exportName: container.moduleName,
dependencyType: DependencyType.Internal,
};
@@ -131,9 +143,15 @@ class SchemaParser implements ISchemaParser {
.filter(container => container.containerType === 'Page')
.map(page => {
const meta = page.meta as IPageMeta;
+ if (meta) {
+ return {
+ path: meta.router,
+ componentName: page.moduleName,
+ };
+ }
return {
- path: meta.router,
- componentName: page.componentName,
+ path: '',
+ componentName: page.moduleName,
};
});
diff --git a/packages/code-generator/src/plugins/common/esmodule.ts b/packages/code-generator/src/plugins/common/esmodule.ts
index 7043a4aa9..316ed5821 100644
--- a/packages/code-generator/src/plugins/common/esmodule.ts
+++ b/packages/code-generator/src/plugins/common/esmodule.ts
@@ -2,6 +2,7 @@ import { COMMON_CHUNK_NAME } from '../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
CodeGeneratorError,
DependencyType,
@@ -41,7 +42,7 @@ function groupDepsByPack(deps: IDependency[]): Record {
function buildPackageImport(
pkg: string,
deps: IDependency[],
- isJSX: boolean,
+ targetFileType: string,
): ICodeChunk[] {
const chunks: ICodeChunk[] = [];
let defaultImport: string = '';
@@ -58,7 +59,7 @@ function buildPackageImport(
if (dep.subName) {
chunks.push({
type: ChunkType.STRING,
- fileType: isJSX ? FileType.JSX : FileType.JS,
+ fileType: targetFileType,
name: COMMON_CHUNK_NAME.FileVarDefine,
content: `const ${targetName} = ${srcName}.${dep.subName};`,
linkAfter: [
@@ -103,7 +104,7 @@ function buildPackageImport(
statementL.push(`'@/${(deps[0] as IInternalDependency).type}/${pkg}';`);
chunks.push({
type: ChunkType.STRING,
- fileType: isJSX ? FileType.JSX : FileType.JS,
+ fileType: targetFileType,
name: COMMON_CHUNK_NAME.InternalDepsImport,
content: statementL.join(' '),
linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
@@ -112,7 +113,7 @@ function buildPackageImport(
statementL.push(`'${pkg}';`);
chunks.push({
type: ChunkType.STRING,
- fileType: isJSX ? FileType.JSX : FileType.JS,
+ fileType: targetFileType,
name: COMMON_CHUNK_NAME.ExternalDepsImport,
content: statementL.join(' '),
linkAfter: [],
@@ -122,25 +123,36 @@ function buildPackageImport(
return chunks;
}
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+type PluginConfig = {
+ fileType: string;
+}
+
+const pluginFactory: BuilderComponentPluginFactory = (config?: PluginConfig) => {
+ const cfg: PluginConfig = {
+ fileType: FileType.JS,
+ ...config,
};
- const isJSX = next.chunks.some(chunk => chunk.fileType === FileType.JSX);
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
- const ir = next.ir as IWithDependency;
+ const ir = next.ir as IWithDependency;
- if (ir && ir.deps && ir.deps.length > 0) {
- const packs = groupDepsByPack(ir.deps);
+ if (ir && ir.deps && ir.deps.length > 0) {
+ const packs = groupDepsByPack(ir.deps);
- Object.keys(packs).forEach(pkg => {
- const chunks = buildPackageImport(pkg, packs[pkg], isJSX);
- next.chunks.push.apply(next.chunks, chunks);
- });
- }
+ Object.keys(packs).forEach(pkg => {
+ const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType);
+ next.chunks.push.apply(next.chunks, chunks);
+ });
+ }
- return next;
+ return next;
+ };
+
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/common/requireUtils.ts b/packages/code-generator/src/plugins/common/requireUtils.ts
index d5b4747b9..9da850a4c 100644
--- a/packages/code-generator/src/plugins/common/requireUtils.ts
+++ b/packages/code-generator/src/plugins/common/requireUtils.ts
@@ -2,26 +2,30 @@ import { COMMON_CHUNK_NAME } from '../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
} from '../../types';
// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: COMMON_CHUNK_NAME.InternalDepsImport,
+ content: `import * from 'react';`,
+ linkAfter: [],
+ });
+
+ return next;
};
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: COMMON_CHUNK_NAME.InternalDepsImport,
- content: `import * from 'react';`,
- linkAfter: [],
- });
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/react/const.ts b/packages/code-generator/src/plugins/component/react/const.ts
index 0aa8b9c30..629466827 100644
--- a/packages/code-generator/src/plugins/component/react/const.ts
+++ b/packages/code-generator/src/plugins/component/react/const.ts
@@ -1,15 +1,8 @@
export const REACT_CHUNK_NAME = {
- ClassStart: 'ReactComponentClassDefineStart',
- ClassEnd: 'ReactComponentClassDefineEnd',
- ClassLifeCycle: 'ReactComponentClassMemberLifeCycle',
- ClassMethod: 'ReactComponentClassMemberMethod',
ClassRenderStart: 'ReactComponentClassRenderStart',
ClassRenderPre: 'ReactComponentClassRenderPre',
ClassRenderEnd: 'ReactComponentClassRenderEnd',
ClassRenderJSX: 'ReactComponentClassRenderJSX',
- ClassConstructorStart: 'ReactComponentClassConstructorStart',
- ClassConstructorEnd: 'ReactComponentClassConstructorEnd',
- ClassConstructorContent: 'ReactComponentClassConstructorContent',
ClassDidMountStart: 'ReactComponentClassDidMountStart',
ClassDidMountEnd: 'ReactComponentClassDidMountEnd',
ClassDidMountContent: 'ReactComponentClassDidMountContent',
diff --git a/packages/code-generator/src/plugins/component/react/containerClass.ts b/packages/code-generator/src/plugins/component/react/containerClass.ts
index ddf1ef337..7ca5e685f 100644
--- a/packages/code-generator/src/plugins/component/react/containerClass.ts
+++ b/packages/code-generator/src/plugins/component/react/containerClass.ts
@@ -1,101 +1,104 @@
-import { COMMON_CHUNK_NAME } from '../../../const/generator';
+import { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';
import { REACT_CHUNK_NAME } from './const';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IContainerInfo,
} from '../../../types';
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IContainerInfo;
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: CLASS_DEFINE_CHUNK_NAME.Start,
+ content: `class ${ir.moduleName} extends React.Component {`,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ ],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: CLASS_DEFINE_CHUNK_NAME.End,
+ content: `}`,
+ linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start, REACT_CHUNK_NAME.ClassRenderEnd],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
+ content: 'constructor(props, context) { super(props); ',
+ linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,
+ content: '}',
+ linkAfter: [
+ CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
+ CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
+ ],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: REACT_CHUNK_NAME.ClassRenderStart,
+ content: 'render() {',
+ linkAfter: [
+ CLASS_DEFINE_CHUNK_NAME.Start,
+ CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,
+ CLASS_DEFINE_CHUNK_NAME.InsMethod,
+ ],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: REACT_CHUNK_NAME.ClassRenderEnd,
+ content: '}',
+ linkAfter: [
+ REACT_CHUNK_NAME.ClassRenderStart,
+ REACT_CHUNK_NAME.ClassRenderPre,
+ REACT_CHUNK_NAME.ClassRenderJSX,
+ ],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: COMMON_CHUNK_NAME.FileExport,
+ content: `export default ${ir.moduleName};`,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ CLASS_DEFINE_CHUNK_NAME.End,
+ ],
+ });
+
+ return next;
};
-
- const ir = next.ir as IContainerInfo;
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassStart,
- content: `class ${ir.componentName} extends React.Component {`,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileUtilDefine,
- ],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassEnd,
- content: `}`,
- linkAfter: [REACT_CHUNK_NAME.ClassStart, REACT_CHUNK_NAME.ClassRenderEnd],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassConstructorStart,
- content: 'constructor(props, context) { super(props); ',
- linkAfter: [REACT_CHUNK_NAME.ClassStart],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassConstructorEnd,
- content: '}',
- linkAfter: [
- REACT_CHUNK_NAME.ClassConstructorStart,
- REACT_CHUNK_NAME.ClassConstructorContent,
- ],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassRenderStart,
- content: 'render() {',
- linkAfter: [
- REACT_CHUNK_NAME.ClassStart,
- REACT_CHUNK_NAME.ClassConstructorEnd,
- REACT_CHUNK_NAME.ClassLifeCycle,
- REACT_CHUNK_NAME.ClassMethod,
- ],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassRenderEnd,
- content: '}',
- linkAfter: [
- REACT_CHUNK_NAME.ClassRenderStart,
- REACT_CHUNK_NAME.ClassRenderPre,
- REACT_CHUNK_NAME.ClassRenderJSX,
- ],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: COMMON_CHUNK_NAME.FileExport,
- content: `export default ${ir.componentName};`,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileUtilDefine,
- REACT_CHUNK_NAME.ClassEnd,
- ],
- });
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/react/containerDataSource.ts b/packages/code-generator/src/plugins/component/react/containerDataSource.ts
index c71859a21..72d7efd6b 100644
--- a/packages/code-generator/src/plugins/component/react/containerDataSource.ts
+++ b/packages/code-generator/src/plugins/component/react/containerDataSource.ts
@@ -1,39 +1,52 @@
-import { REACT_CHUNK_NAME } from './const';
+import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';
-import { generateCompositeType } from '../../utils/compositeType';
+import { generateCompositeType } from '../../../utils/compositeType';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IContainerInfo,
} from '../../../types';
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+type PluginConfig = {
+ fileType: string;
+}
+
+const pluginFactory: BuilderComponentPluginFactory = (config?) => {
+ const cfg: PluginConfig = {
+ fileType: FileType.JSX,
+ ...config,
};
- const ir = next.ir as IContainerInfo;
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
- if (ir.state) {
- const state = ir.state;
- const fields = Object.keys(state).map(stateName => {
- const [isString, value] = generateCompositeType(state[stateName]);
- return `${stateName}: ${isString ? `'${value}'` : value},`;
- });
+ const ir = next.ir as IContainerInfo;
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassConstructorContent,
- content: `this.state = { ${fields.join('')} };`,
- linkAfter: [REACT_CHUNK_NAME.ClassConstructorStart],
- });
- }
+ if (ir.state) {
+ const state = ir.state;
+ const fields = Object.keys(state).map(stateName => {
+ const [isString, value] = generateCompositeType(state[stateName]);
+ return `${stateName}: ${isString ? `'${value}'` : value},`;
+ });
- return next;
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: cfg.fileType,
+ name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
+ content: `this.state = { ${fields.join('')} };`,
+ linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart],
+ });
+ }
+
+ return next;
+ };
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/react/containerInitState.ts b/packages/code-generator/src/plugins/component/react/containerInitState.ts
index c71859a21..50984c961 100644
--- a/packages/code-generator/src/plugins/component/react/containerInitState.ts
+++ b/packages/code-generator/src/plugins/component/react/containerInitState.ts
@@ -1,39 +1,64 @@
-import { REACT_CHUNK_NAME } from './const';
+import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
-import { generateCompositeType } from '../../utils/compositeType';
+import { generateCompositeType } from '../../../utils/compositeType';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IContainerInfo,
} from '../../../types';
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+type PluginConfig = {
+ fileType: string;
+ implementType: 'inConstructor' | 'insMember' | 'hooks';
+}
+
+const pluginFactory: BuilderComponentPluginFactory = (config?) => {
+ const cfg: PluginConfig = {
+ fileType: FileType.JSX,
+ implementType: 'inConstructor',
+ ...config,
};
- const ir = next.ir as IContainerInfo;
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
- if (ir.state) {
- const state = ir.state;
- const fields = Object.keys(state).map(stateName => {
- const [isString, value] = generateCompositeType(state[stateName]);
- return `${stateName}: ${isString ? `'${value}'` : value},`;
- });
+ const ir = next.ir as IContainerInfo;
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassConstructorContent,
- content: `this.state = { ${fields.join('')} };`,
- linkAfter: [REACT_CHUNK_NAME.ClassConstructorStart],
- });
- }
+ if (ir.state) {
+ const state = ir.state;
+ const fields = Object.keys(state).map(stateName => {
+ const [isString, value] = generateCompositeType(state[stateName]);
+ return `${stateName}: ${isString ? `'${value}'` : value},`;
+ });
- return next;
+ if (cfg.implementType === 'inConstructor') {
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: cfg.fileType,
+ name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
+ content: `this.state = { ${fields.join('')} };`,
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]],
+ });
+ } else if (cfg.implementType === 'insMember') {
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: cfg.fileType,
+ name: CLASS_DEFINE_CHUNK_NAME.InsVar,
+ content: `state = { ${fields.join('')} };`,
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],
+ });
+ }
+ }
+
+ return next;
+ };
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts b/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts
index a6670230a..8cded167b 100644
--- a/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts
+++ b/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts
@@ -1,26 +1,39 @@
-import { REACT_CHUNK_NAME } from './const';
+import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
} from '../../../types';
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+type PluginConfig = {
+ fileType: string;
+}
+
+const pluginFactory: BuilderComponentPluginFactory = (config?) => {
+ const cfg: PluginConfig = {
+ fileType: FileType.JSX,
+ ...config,
};
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassConstructorContent,
- content: `this.utils = utils;`,
- linkAfter: [REACT_CHUNK_NAME.ClassConstructorStart],
- });
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
- return next;
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: cfg.fileType,
+ name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
+ content: `this.utils = utils;`,
+ linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart],
+ });
+
+ return next;
+ };
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts b/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts
index 3e83e659a..d1951d8e2 100644
--- a/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts
+++ b/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts
@@ -1,12 +1,14 @@
+import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
import { REACT_CHUNK_NAME } from './const';
import {
getFuncExprBody,
transformFuncExpr2MethodMember,
-} from '../../utils/jsExpression';
+} from '../../../utils/jsExpression';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
CodeGeneratorError,
FileType,
@@ -16,66 +18,73 @@ import {
IJSExpression,
} from '../../../types';
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+type PluginConfig = {
+ fileType: string;
+ exportNameMapping: Record;
+ normalizeNameMapping: Record;
+}
+
+const pluginFactory: BuilderComponentPluginFactory = (config?) => {
+ const cfg: PluginConfig = {
+ fileType: FileType.JSX,
+ exportNameMapping: {},
+ normalizeNameMapping: {},
+ ...config,
};
- const ir = next.ir as IContainerInfo;
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IContainerInfo;
+
+ if (ir.lifeCycles) {
+ const lifeCycles = ir.lifeCycles;
+ const chunks = Object.keys(lifeCycles).map(lifeCycleName => {
+ const normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName;
+ const exportName = cfg.exportNameMapping[lifeCycleName] || lifeCycleName;
+ if (normalizeName === 'constructor') {
+ return {
+ type: ChunkType.STRING,
+ fileType: cfg.fileType,
+ name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent,
+ content: getFuncExprBody(
+ (lifeCycles[lifeCycleName] as IJSExpression).value,
+ ),
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]],
+ };
+ }
+ if (normalizeName === 'render') {
+ return {
+ type: ChunkType.STRING,
+ fileType: cfg.fileType,
+ name: REACT_CHUNK_NAME.ClassRenderPre,
+ content: getFuncExprBody(
+ (lifeCycles[lifeCycleName] as IJSExpression).value,
+ ),
+ linkAfter: [REACT_CHUNK_NAME.ClassRenderStart],
+ };
+ }
- if (ir.lifeCycles) {
- const lifeCycles = ir.lifeCycles;
- const chunks = Object.keys(lifeCycles).map(lifeCycleName => {
- if (lifeCycleName === 'constructor') {
return {
type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassConstructorContent,
- content: getFuncExprBody(
- (lifeCycles[lifeCycleName] as IJSExpression).value,
- ),
- linkAfter: [REACT_CHUNK_NAME.ClassConstructorStart],
- };
- }
- if (lifeCycleName === 'render') {
- return {
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassRenderPre,
- content: getFuncExprBody(
- (lifeCycles[lifeCycleName] as IJSExpression).value,
- ),
- linkAfter: [REACT_CHUNK_NAME.ClassRenderStart],
- };
- }
- if (
- lifeCycleName === 'componentDidMount' ||
- lifeCycleName === 'componentDidUpdate' ||
- lifeCycleName === 'componentWillUnmount' ||
- lifeCycleName === 'componentDidCatch'
- ) {
- return {
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassLifeCycle,
+ fileType: cfg.fileType,
+ name: CLASS_DEFINE_CHUNK_NAME.InsMethod,
content: transformFuncExpr2MethodMember(
- lifeCycleName,
+ exportName,
(lifeCycles[lifeCycleName] as IJSExpression).value,
),
- linkAfter: [
- REACT_CHUNK_NAME.ClassStart,
- REACT_CHUNK_NAME.ClassConstructorEnd,
- ],
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
};
- }
+ });
- throw new CodeGeneratorError('Unknown life cycle method name');
- });
+ next.chunks.push.apply(next.chunks, chunks);
+ }
- next.chunks.push.apply(next.chunks, chunks);
- }
-
- return next;
+ return next;
+ };
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/react/containerMethod.ts b/packages/code-generator/src/plugins/component/react/containerMethod.ts
index cff01d9ce..9bba467da 100644
--- a/packages/code-generator/src/plugins/component/react/containerMethod.ts
+++ b/packages/code-generator/src/plugins/component/react/containerMethod.ts
@@ -1,9 +1,10 @@
-import { REACT_CHUNK_NAME } from './const';
+import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
-import { transformFuncExpr2MethodMember } from '../../utils/jsExpression';
+import { transformFuncExpr2MethodMember } from '../../../utils/jsExpression';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeChunk,
@@ -12,34 +13,42 @@ import {
IJSExpression,
} from '../../../types';
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+type PluginConfig = {
+ fileType: string;
+}
+
+const pluginFactory: BuilderComponentPluginFactory = (config?) => {
+ const cfg: PluginConfig = {
+ fileType: FileType.JSX,
+ ...config,
};
- const ir = next.ir as IContainerInfo;
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
- if (ir.methods) {
- const methods = ir.methods;
- const chunks = Object.keys(methods).map(methodName => ({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassMethod,
- content: transformFuncExpr2MethodMember(
- methodName,
- (methods[methodName] as IJSExpression).value,
- ),
- linkAfter: [
- REACT_CHUNK_NAME.ClassStart,
- REACT_CHUNK_NAME.ClassConstructorEnd,
- REACT_CHUNK_NAME.ClassLifeCycle,
- ],
- }));
+ const ir = next.ir as IContainerInfo;
- next.chunks.push.apply(next.chunks, chunks);
- }
+ if (ir.methods) {
+ const methods = ir.methods;
+ 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,
+ ),
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]],
+ }));
- return next;
+ next.chunks.push.apply(next.chunks, chunks);
+ }
+
+ return next;
+ };
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/react/jsx.ts b/packages/code-generator/src/plugins/component/react/jsx.ts
index 3e5162353..bb6b8f383 100644
--- a/packages/code-generator/src/plugins/component/react/jsx.ts
+++ b/packages/code-generator/src/plugins/component/react/jsx.ts
@@ -1,149 +1,50 @@
import {
BuilderComponentPlugin,
- ChildNodeItem,
- ChildNodeType,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
- IComponentNodeItem,
IContainerInfo,
- IInlineStyle,
- IJSExpression,
} from '../../../types';
-import { handleChildren } from '../../../utils/children';
-import { generateCompositeType } from '../../utils/compositeType';
import { REACT_CHUNK_NAME } from './const';
-function generateInlineStyle(style: IInlineStyle): string | null {
- const attrLines = Object.keys(style).map((cssAttribute: string) => {
- const [isString, valueStr] = generateCompositeType(style[cssAttribute]);
- const valuePart = isString ? `'${valueStr}'` : valueStr;
- return `${cssAttribute}: ${valuePart},`;
- });
+import { createReactNodeGenerator } from '../../../utils/nodeToJSX';
- if (attrLines.length === 0) {
- return null;
- }
-
- return `{ ${attrLines.join('')} }`;
+type PluginConfig = {
+ fileType: string;
}
-function generateAttr(attrName: string, attrValue: any): string {
- if (attrName === 'initValue' || attrName === 'labelCol') {
- return '';
- }
- const [isString, valueStr] = generateCompositeType(attrValue);
- return `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`;
-}
-
-function mapNodeName(src: string): string {
- if (src === 'Div') {
- return 'div';
- }
- return src;
-}
-
-function generateNode(nodeItem: IComponentNodeItem): string {
- const codePieces: string[] = [];
- let propLines: string[] = [];
- const { className, style, ...props } = nodeItem.props;
-
- codePieces.push(`<${mapNodeName(nodeItem.componentName)}`);
- if (className) {
- propLines.push(`className="${className}"`);
- }
- if (style) {
- const inlineStyle = generateInlineStyle(style);
- if (inlineStyle !== null) {
- propLines.push(`style={${inlineStyle}}`);
- }
- }
-
- propLines = propLines.concat(
- Object.keys(props).map((propName: string) =>
- generateAttr(propName, props[propName]),
- ),
- );
- codePieces.push(` ${propLines.join(' ')} `);
-
- if (nodeItem.children && (nodeItem.children as unknown[]).length > 0) {
- codePieces.push('>');
- const childrenLines = generateChildren(nodeItem.children);
- codePieces.push.apply(codePieces, childrenLines);
- codePieces.push(`${mapNodeName(nodeItem.componentName)}>`);
- } else {
- codePieces.push('/>');
- }
-
- if (nodeItem.loop && nodeItem.loopArgs) {
- let loopDataExp;
- if ((nodeItem.loop as IJSExpression).type === 'JSExpression') {
- loopDataExp = `(${(nodeItem.loop as IJSExpression).value})`;
- } else {
- loopDataExp = JSON.stringify(nodeItem.loop);
- }
- codePieces.unshift(
- `${loopDataExp}.map((${nodeItem.loopArgs[0]}, ${nodeItem.loopArgs[1]}) => (`,
- );
- codePieces.push('))');
- }
-
- if (nodeItem.condition) {
- codePieces.unshift(`(${generateCompositeType(nodeItem.condition)}) && (`);
- codePieces.push(')');
- }
-
- if (nodeItem.condition || (nodeItem.loop && nodeItem.loopArgs)) {
- codePieces.unshift('{');
- codePieces.push('}');
- }
-
- return codePieces.join('');
-}
-
-function generateChildren(children: ChildNodeType): string[] {
- return handleChildren(children, {
- // TODO: 如果容器直接只有一个 字符串 children 呢?
- string: (input: string) => [input],
- expression: (input: IJSExpression) => [`{${input.value}}`],
- node: (input: IComponentNodeItem) => [generateNode(input)],
- });
-}
-
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = (config?) => {
+ const cfg: PluginConfig = {
+ fileType: FileType.JSX,
+ ...config,
};
- const ir = next.ir as IContainerInfo;
+ const generator = createReactNodeGenerator();
- let jsxContent: string;
- if (!ir.children || (ir.children as unknown[]).length === 0) {
- jsxContent = 'null';
- } else {
- const childrenCode = generateChildren(ir.children);
- if (childrenCode.length === 1) {
- jsxContent = `(${childrenCode[0]})`;
- } else {
- jsxContent = `(${childrenCode.join(
- '',
- )})`;
- }
- }
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: REACT_CHUNK_NAME.ClassRenderJSX,
- content: `return ${jsxContent};`,
- linkAfter: [
- REACT_CHUNK_NAME.ClassRenderStart,
- REACT_CHUNK_NAME.ClassRenderPre,
- ],
- });
+ const ir = next.ir as IContainerInfo;
+ const jsxContent = generator(ir);
- return next;
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: cfg.fileType,
+ name: REACT_CHUNK_NAME.ClassRenderJSX,
+ content: `return ${jsxContent};`,
+ linkAfter: [
+ REACT_CHUNK_NAME.ClassRenderStart,
+ REACT_CHUNK_NAME.ClassRenderPre,
+ ],
+ });
+
+ return next;
+ };
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts b/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts
index 38936fc68..2e75a5b7e 100644
--- a/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts
+++ b/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts
@@ -2,27 +2,30 @@ import { COMMON_CHUNK_NAME } from '../../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IContainerInfo,
} from '../../../types';
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JSX,
+ name: COMMON_CHUNK_NAME.ExternalDepsImport,
+ content: `import React from 'react';`,
+ linkAfter: [],
+ });
+
+ return next;
};
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: COMMON_CHUNK_NAME.ExternalDepsImport,
- content: `import React from 'react';`,
- linkAfter: [],
- });
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/recore/const.ts b/packages/code-generator/src/plugins/component/recore/const.ts
new file mode 100644
index 000000000..b848f42aa
--- /dev/null
+++ b/packages/code-generator/src/plugins/component/recore/const.ts
@@ -0,0 +1,3 @@
+export const RECORE_CHUNK_NAME = {
+
+};
diff --git a/packages/code-generator/src/plugins/component/recore/pageDataSource.ts b/packages/code-generator/src/plugins/component/recore/pageDataSource.ts
new file mode 100644
index 000000000..87d496aaf
--- /dev/null
+++ b/packages/code-generator/src/plugins/component/recore/pageDataSource.ts
@@ -0,0 +1,67 @@
+import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
+
+import {
+ BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
+ ChunkType,
+ FileType,
+ ICodeStruct,
+ IContainerInfo,
+ IJSExpression,
+ CompositeValue,
+} from '../../../types';
+
+import { generateCompositeType, handleStringValueDefault } from '../../../utils/compositeType';
+import { generateExpression } from '../../../utils/jsExpression';
+
+function packJsExpression(exp: unknown): string {
+ const expression = exp as IJSExpression;
+ const funcStr = generateExpression(expression);
+ return `function() { return (${funcStr}); }`;
+}
+
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IContainerInfo;
+ if (ir.dataSource) {
+ const { dataSource } = ir;
+ const {
+ list,
+ ...rest
+ } = dataSource;
+
+ let attrs: string[] = [];
+
+ const extConfigs = Object.keys(rest).map(extConfigName => {
+ const value = (rest as Record)[extConfigName];
+ const [isString, valueStr] = generateCompositeType(value);
+ return `${extConfigName}: ${isString ? `'${valueStr}'` : valueStr}`;
+ });
+
+ attrs = [...attrs, ...extConfigs];
+
+ const listProp = handleStringValueDefault(generateCompositeType(list as unknown as CompositeValue, {
+ expression: packJsExpression,
+ }));
+
+ attrs.push(`list: ${listProp}`);
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: CLASS_DEFINE_CHUNK_NAME.InsVar,
+ content: `dataSourceOptions = { ${attrs.join(',\n')} };`,
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],
+ });
+ }
+
+ return next;
+ };
+ return plugin;
+};
+
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/recore/pageFrame.ts b/packages/code-generator/src/plugins/component/recore/pageFrame.ts
new file mode 100644
index 000000000..e302a64bc
--- /dev/null
+++ b/packages/code-generator/src/plugins/component/recore/pageFrame.ts
@@ -0,0 +1,81 @@
+import { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
+
+import {
+ BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
+ ChunkType,
+ FileType,
+ ICodeStruct,
+ IContainerInfo,
+} from '../../../types';
+
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IContainerInfo;
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: COMMON_CHUNK_NAME.ExternalDepsImport,
+ content: `import { BaseController } from '@ali/recore-renderer';`,
+ linkAfter: [],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: CLASS_DEFINE_CHUNK_NAME.Start,
+ content: `class ${ir.moduleName} extends BaseController {`,
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.Start]],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: CLASS_DEFINE_CHUNK_NAME.End,
+ content: `}`,
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End]],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: CLASS_DEFINE_CHUNK_NAME.ConstructorStart,
+ content: 'init() {',
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd,
+ content: '}',
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: CLASS_DEFINE_CHUNK_NAME.InsVar,
+ content: 'globalProps = (window as any)?.g_config?.globalProps || {};',
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: COMMON_CHUNK_NAME.FileExport,
+ content: `export default ${ir.moduleName};`,
+ linkAfter: [...DEFAULT_LINK_AFTER[COMMON_CHUNK_NAME.FileExport]],
+ });
+
+ return next;
+ };
+ return plugin;
+};
+
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/recore/pageStyle.ts b/packages/code-generator/src/plugins/component/recore/pageStyle.ts
new file mode 100644
index 000000000..fc8ca41b5
--- /dev/null
+++ b/packages/code-generator/src/plugins/component/recore/pageStyle.ts
@@ -0,0 +1,35 @@
+import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
+
+import {
+ BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
+ ChunkType,
+ ICodeStruct,
+ FileType,
+ IContainerInfo,
+} from '../../../types';
+
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IContainerInfo;
+
+ if (ir.css) {
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.TS,
+ name: CLASS_DEFINE_CHUNK_NAME.StaticVar,
+ content: `static cssText = '${ir.css.replace(/\'/g, '\\\'')}';`,
+ linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.StaticVar]],
+ });
+ }
+
+ return next;
+ };
+ return plugin;
+};
+
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/recore/pageVmBody.ts b/packages/code-generator/src/plugins/component/recore/pageVmBody.ts
new file mode 100644
index 000000000..8660ad195
--- /dev/null
+++ b/packages/code-generator/src/plugins/component/recore/pageVmBody.ts
@@ -0,0 +1,82 @@
+import {
+ BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
+ ChunkType,
+ ICodeStruct,
+ IContainerInfo,
+ IComponentNodeItem,
+ CodePiece,
+ PIECE_TYPE,
+} from '../../../types';
+import { COMMON_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator';
+
+import { createNodeGenerator, generateString } from '../../../utils/nodeToJSX';
+import { generateExpression } from '../../../utils/jsExpression';
+import { generateCompositeType, handleStringValueDefault } from '../../../utils/compositeType';
+
+const generateGlobalProps = (nodeItem: IComponentNodeItem): CodePiece[] => {
+ return [{
+ value: `{...globalProps.${nodeItem.componentName}}`,
+ type: PIECE_TYPE.ATTR,
+ }];
+};
+
+const generateCtrlLine = (nodeItem: IComponentNodeItem): CodePiece[] => {
+ const pieces: CodePiece[] = [];
+
+ if (nodeItem.loop && nodeItem.loopArgs) {
+ const loopDataExp = handleStringValueDefault(generateCompositeType(nodeItem.loop));
+ pieces.push({
+ type: PIECE_TYPE.ATTR,
+ value: `x-for={${loopDataExp}}`,
+ });
+
+ pieces.push({
+ type: PIECE_TYPE.ATTR,
+ value: `x-each="${nodeItem.loopArgs[0]},${nodeItem.loopArgs[1]}"`,
+ });
+ }
+
+ if (nodeItem.condition) {
+ const conditionExp = handleStringValueDefault(generateCompositeType(nodeItem.condition));
+ pieces.push({
+ type: PIECE_TYPE.ATTR,
+ value: `x-if={${conditionExp}}`,
+ });
+ }
+
+ return pieces;
+};
+
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const generator = createNodeGenerator({
+ string: generateString,
+ expression: (input) => [generateExpression(input)],
+ }, [
+ generateGlobalProps,
+ generateCtrlLine,
+ ]);
+
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IContainerInfo;
+
+ const vxContent = generator(ir);
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: 'vx',
+ name: COMMON_CHUNK_NAME.CustomContent,
+ content: vxContent,
+ linkAfter: [],
+ });
+
+ return next;
+ };
+ return plugin;
+};
+
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/recore/pageVmHeader.ts b/packages/code-generator/src/plugins/component/recore/pageVmHeader.ts
new file mode 100644
index 000000000..6ef8ac44f
--- /dev/null
+++ b/packages/code-generator/src/plugins/component/recore/pageVmHeader.ts
@@ -0,0 +1,29 @@
+import { COMMON_CHUNK_NAME } from '../../../const/generator';
+
+import {
+ BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
+ ChunkType,
+ ICodeStruct,
+} from '../../../types';
+
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: 'vx',
+ name: COMMON_CHUNK_NAME.CustomContent,
+ content: ``,
+ linkAfter: [],
+ });
+
+ return next;
+ };
+ return plugin;
+};
+
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/component/style/css.ts b/packages/code-generator/src/plugins/component/style/css.ts
index c4ce2160e..a2e8b46f0 100644
--- a/packages/code-generator/src/plugins/component/style/css.ts
+++ b/packages/code-generator/src/plugins/component/style/css.ts
@@ -2,36 +2,51 @@ import { COMMON_CHUNK_NAME } from '../../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IContainerInfo,
} from '../../../types';
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+type PluginConfig = {
+ fileType: string;
+ moduleFileType: string;
+}
+
+const pluginFactory: BuilderComponentPluginFactory = (config?) => {
+ const cfg: PluginConfig = {
+ fileType: FileType.CSS,
+ moduleFileType: FileType.JSX,
+ ...config,
};
- const ir = next.ir as IContainerInfo;
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.CSS,
- name: COMMON_CHUNK_NAME.StyleCssContent,
- content: ir.css,
- linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
- });
+ const ir = next.ir as IContainerInfo;
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JSX,
- name: COMMON_CHUNK_NAME.InternalDepsImport,
- content: `import './index.css';`,
- linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
- });
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: cfg.fileType,
+ name: COMMON_CHUNK_NAME.StyleCssContent,
+ content: ir.css,
+ linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
+ });
- return next;
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: cfg.moduleFileType,
+ name: COMMON_CHUNK_NAME.InternalDepsImport,
+ content: `import './index.${cfg.fileType}';`,
+ linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
+ });
+
+ return next;
+ };
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/project/constants.ts b/packages/code-generator/src/plugins/project/constants.ts
index 7be166d3d..5c02e9711 100644
--- a/packages/code-generator/src/plugins/project/constants.ts
+++ b/packages/code-generator/src/plugins/project/constants.ts
@@ -1,54 +1,57 @@
import { COMMON_CHUNK_NAME } from '../../const/generator';
-import { generateCompositeType } from '../../plugins/utils/compositeType';
+import { generateCompositeType } from '../../utils/compositeType';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IProjectInfo,
} from '../../types';
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IProjectInfo;
+ if (ir.constants) {
+ const [, constantStr] = generateCompositeType(ir.constants);
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileVarDefine,
+ content: `
+ const constantConfig = ${constantStr};
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ ],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileExport,
+ content: `
+ export default constantConfig;
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ COMMON_CHUNK_NAME.FileMainContent,
+ ],
+ });
+ }
+
+ return next;
};
-
- const ir = next.ir as IProjectInfo;
- if (ir.constants) {
- const [, constantStr] = generateCompositeType(ir.constants);
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileVarDefine,
- content: `
- const constantConfig = ${constantStr};
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- ],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileExport,
- content: `
- export default constantConfig;
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileUtilDefine,
- COMMON_CHUNK_NAME.FileMainContent,
- ],
- });
- }
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts b/packages/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts
index f32d9abed..0cf3918a7 100644
--- a/packages/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts
+++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts
@@ -2,54 +2,57 @@ import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IProjectInfo,
} from '../../../../../types';
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IProjectInfo;
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.ExternalDepsImport,
+ content: `
+ import { createApp } from 'ice';
+ `,
+ linkAfter: [],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileMainContent,
+ content: `
+ const appConfig = {
+ app: {
+ rootId: '${ir.config.targetRootID}',
+ },
+ router: {
+ type: '${ir.config.historyMode}',
+ },
+ };
+ createApp(appConfig);
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ ],
+ });
+
+ return next;
};
-
- const ir = next.ir as IProjectInfo;
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.ExternalDepsImport,
- content: `
- import { createApp } from 'ice';
- `,
- linkAfter: [],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileMainContent,
- content: `
- const appConfig = {
- app: {
- rootId: '${ir.config.targetRootID}',
- },
- router: {
- type: '${ir.config.historyMode}',
- },
- };
- createApp(appConfig);
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileUtilDefine,
- ],
- });
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts b/packages/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts
index 6ceebc04a..a0ca3cdf1 100644
--- a/packages/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts
+++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts
@@ -2,42 +2,45 @@ import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IProjectInfo,
} from '../../../../../types';
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IProjectInfo;
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.HTML,
+ name: COMMON_CHUNK_NAME.HtmlContent,
+ content: `
+
+
+
+
+
+
+ ${ir.meta.name}
+
+
+
+
+
+ `,
+ linkAfter: [],
+ });
+
+ return next;
};
-
- const ir = next.ir as IProjectInfo;
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.HTML,
- name: COMMON_CHUNK_NAME.HtmlContent,
- content: `
-
-
-
-
-
-
- ${ir.meta.name}
-
-
-
-
-
- `,
- linkAfter: [],
- });
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts b/packages/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts
index 3e083c1f1..3daaeecdc 100644
--- a/packages/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts
+++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts
@@ -2,52 +2,55 @@ import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IProjectInfo,
} from '../../../../../types';
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IProjectInfo;
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.SCSS,
+ name: COMMON_CHUNK_NAME.StyleDepsImport,
+ content: `
+ // 引入默认全局样式
+ @import '@alifd/next/reset.scss';
+ `,
+ linkAfter: [],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.SCSS,
+ name: COMMON_CHUNK_NAME.StyleCssContent,
+ content: `
+ body {
+ -webkit-font-smoothing: antialiased;
+ }
+ `,
+ linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.SCSS,
+ name: COMMON_CHUNK_NAME.StyleCssContent,
+ content: ir.css || '',
+ linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
+ });
+
+ return next;
};
-
- const ir = next.ir as IProjectInfo;
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.SCSS,
- name: COMMON_CHUNK_NAME.StyleDepsImport,
- content: `
- // 引入默认全局样式
- @import '@alifd/next/reset.scss';
- `,
- linkAfter: [],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.SCSS,
- name: COMMON_CHUNK_NAME.StyleCssContent,
- content: `
- body {
- -webkit-font-smoothing: antialiased;
- }
- `,
- linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.SCSS,
- name: COMMON_CHUNK_NAME.StyleCssContent,
- content: ir.css || '',
- linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
- });
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts b/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts
index 0e4c48805..a79dc3481 100644
--- a/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts
+++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts
@@ -2,6 +2,7 @@ import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
@@ -20,67 +21,69 @@ interface IIceJsPackageJSON extends IPackageJSON {
originTemplate: string;
}
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IProjectInfo;
+
+ const packageJson: IIceJsPackageJSON = {
+ name: '@alifd/scaffold-lite-js',
+ version: '0.1.5',
+ description: '轻量级模板,使用 JavaScript,仅包含基础的 Layout。',
+ dependencies: {
+ moment: '^2.24.0',
+ react: '^16.4.1',
+ 'react-dom': '^16.4.1',
+ '@alifd/theme-design-pro': '^0.x',
+ },
+ devDependencies: {
+ '@ice/spec': '^1.0.0',
+ 'build-plugin-fusion': '^0.1.0',
+ 'build-plugin-moment-locales': '^0.1.0',
+ eslint: '^6.0.1',
+ 'ice.js': '^1.0.0',
+ stylelint: '^13.2.0',
+ '@ali/build-plugin-ice-def': '^0.1.0',
+ },
+ scripts: {
+ start: 'icejs start',
+ build: 'icejs build',
+ lint: 'npm run eslint && npm run stylelint',
+ eslint: 'eslint --cache --ext .js,.jsx ./',
+ stylelint: 'stylelint ./**/*.scss',
+ },
+ ideMode: {
+ name: 'ice-react',
+ },
+ iceworks: {
+ type: 'react',
+ adapter: 'adapter-react-v3',
+ },
+ engines: {
+ node: '>=8.0.0',
+ },
+ repository: {
+ type: 'git',
+ url: 'http://gitlab.alibaba-inc.com/msd/leak-scan/tree/master',
+ },
+ private: true,
+ originTemplate: '@alifd/scaffold-lite-js',
+ };
+
+ next.chunks.push({
+ type: ChunkType.JSON,
+ fileType: FileType.JSON,
+ name: COMMON_CHUNK_NAME.FileMainContent,
+ content: packageJson,
+ linkAfter: [],
+ });
+
+ return next;
};
-
- const ir = next.ir as IProjectInfo;
-
- const packageJson: IIceJsPackageJSON = {
- name: '@alifd/scaffold-lite-js',
- version: '0.1.5',
- description: '轻量级模板,使用 JavaScript,仅包含基础的 Layout。',
- dependencies: {
- moment: '^2.24.0',
- react: '^16.4.1',
- 'react-dom': '^16.4.1',
- '@alifd/theme-design-pro': '^0.x',
- },
- devDependencies: {
- '@ice/spec': '^1.0.0',
- 'build-plugin-fusion': '^0.1.0',
- 'build-plugin-moment-locales': '^0.1.0',
- eslint: '^6.0.1',
- 'ice.js': '^1.0.0',
- stylelint: '^13.2.0',
- '@ali/build-plugin-ice-def': '^0.1.0',
- },
- scripts: {
- start: 'icejs start',
- build: 'icejs build',
- lint: 'npm run eslint && npm run stylelint',
- eslint: 'eslint --cache --ext .js,.jsx ./',
- stylelint: 'stylelint ./**/*.scss',
- },
- ideMode: {
- name: 'ice-react',
- },
- iceworks: {
- type: 'react',
- adapter: 'adapter-react-v3',
- },
- engines: {
- node: '>=8.0.0',
- },
- repository: {
- type: 'git',
- url: 'http://gitlab.alibaba-inc.com/msd/leak-scan/tree/master',
- },
- private: true,
- originTemplate: '@alifd/scaffold-lite-js',
- };
-
- next.chunks.push({
- type: ChunkType.JSON,
- fileType: FileType.JSON,
- name: COMMON_CHUNK_NAME.FileMainContent,
- content: packageJson,
- linkAfter: [],
- });
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts b/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts
index b2c9c0805..b4f2d718f 100644
--- a/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts
+++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts
@@ -2,78 +2,81 @@ import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IRouterInfo,
} from '../../../../../types';
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IRouterInfo;
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.InternalDepsImport,
+ content: `
+ import BasicLayout from '@/layouts/BasicLayout';
+ `,
+ linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileVarDefine,
+ content: `
+ const routerConfig = [
+ {
+ path: '/',
+ component: BasicLayout,
+ children: [
+ ${ir.routes
+ .map(
+ route => `
+ {
+ path: '${route.path}',
+ component: ${route.componentName},
+ }
+ `,
+ )
+ .join(',')}
+ ],
+ },
+ ];
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ ],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileExport,
+ content: `
+ export default routerConfig;
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileMainContent,
+ ],
+ });
+
+ return next;
};
-
- const ir = next.ir as IRouterInfo;
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.InternalDepsImport,
- content: `
- import BasicLayout from '@/layouts/BasicLayout';
- `,
- linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileVarDefine,
- content: `
- const routerConfig = [
- {
- path: '/',
- component: BasicLayout,
- children: [
- ${ir.routes
- .map(
- route => `
- {
- path: '${route.path}',
- component: ${route.componentName},
- }
- `,
- )
- .join(',')}
- ],
- },
- ];
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileUtilDefine,
- ],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileExport,
- content: `
- export default routerConfig;
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileUtilDefine,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileMainContent,
- ],
- });
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/index.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/index.ts
index 2a1f3a285..d048bd389 100644
--- a/packages/code-generator/src/plugins/project/framework/icejs/template/index.ts
+++ b/packages/code-generator/src/plugins/project/framework/icejs/template/index.ts
@@ -2,8 +2,8 @@ import ResultDir from '../../../../../model/ResultDir';
import {
IProjectTemplate,
IResultDir,
- IResultFile,
} from '../../../../../types';
+import { runFileGenerator } from '../../../../../utils/templateHelper';
import file12 from './files/abc.json';
import file11 from './files/build.json';
@@ -26,29 +26,6 @@ import file3 from './files/stylelintignore';
import file2 from './files/stylelintrc.js';
import file1 from './files/tsconfig.json';
-type FuncFileGenerator = () => [string[], IResultFile];
-
-function insertFile(root: IResultDir, path: string[], file: IResultFile) {
- let current: IResultDir = root;
- path.forEach(pathNode => {
- const dir = current.dirs.find(d => d.name === pathNode);
- if (dir) {
- current = dir;
- } else {
- const newDir = new ResultDir(pathNode);
- current.addDirectory(newDir);
- current = newDir;
- }
- });
-
- current.addFile(file);
-}
-
-function runFileGenerator(root: IResultDir, fun: FuncFileGenerator) {
- const [path, file] = fun();
- insertFile(root, path, file);
-}
-
const icejsTemplate: IProjectTemplate = {
slots: {
components: {
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/.editorconfig.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/.editorconfig.ts
new file mode 100644
index 000000000..737b32b80
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/.editorconfig.ts
@@ -0,0 +1,32 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ '.editorconfig',
+ '',
+ `
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Tab indentation
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 2
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+ `,
+ );
+
+ return [[], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/.eslintignore.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/.eslintignore.ts
new file mode 100644
index 000000000..42c1be15c
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/.eslintignore.ts
@@ -0,0 +1,26 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ '.eslintignore',
+ '',
+ `
+.idea
+.vscode
+.theia
+.recore
+build/
+.*
+~*
+node_modules
+
+packages/solution
+
+ `,
+ );
+
+ return [[], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/.gitignore.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/.gitignore.ts
new file mode 100644
index 000000000..fd89e80eb
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/.gitignore.ts
@@ -0,0 +1,57 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ '.gitignore',
+ '',
+ `
+node_modules/
+coverage/
+build/
+dist/
+.idea/
+.vscode/
+.theia/
+.recore/
+.Trash-*/
+~*
+package-lock.json
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+
+# Logs and databases #
+######################
+*.log
+*.sql
+*.sqlite
+
+# OS generated files #
+######################
+.DS_Store
+ *.swp
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+ `,
+ );
+
+ return [[], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/.prettierrc.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/.prettierrc.ts
new file mode 100644
index 000000000..19cd24fbc
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/.prettierrc.ts
@@ -0,0 +1,22 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ '.prettierrc',
+ '',
+ `
+{
+ "semi": true,
+ "singleQuote": true,
+ "printWidth": 120,
+ "trailingComma": "all"
+}
+
+ `,
+ );
+
+ return [[], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/README.md.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/README.md.ts
new file mode 100644
index 000000000..f90fd7d87
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/README.md.ts
@@ -0,0 +1,35 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'README',
+ 'md',
+ `
+# runtime-code
+
+乐高接出码模块测试项目
+
+
+## 安装运行
+
+\`\`\`bash
+# install dependencies
+tnpm install
+
+# serve with hot reload at localhost:8080
+npm start
+
+# test projects
+npm test
+
+# local build
+npm run build
+\`\`\`
+
+ `,
+ );
+
+ return [[], file];
+}
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/abc.json.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/abc.json.ts
new file mode 100644
index 000000000..b7523b5f9
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/abc.json.ts
@@ -0,0 +1,28 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'abc',
+ 'json',
+ `
+{
+ "name": "test",
+ "assets": {
+ "type": "command",
+ "command": {
+ "cmd": [
+ "tnpm ii",
+ "tnpm run build"
+ ]
+ }
+ }
+}
+
+ `,
+ );
+
+ return [[], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/build.json.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/build.json.ts
new file mode 100644
index 000000000..08c1ab78a
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/build.json.ts
@@ -0,0 +1,32 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'build',
+ 'json',
+ `
+{
+ "entry": "src/index",
+ "alias": {
+ "@": "./src"
+ },
+ "publicPath": "./",
+ "outputAssetsPath": {
+ "js": "",
+ "css": ""
+ },
+ "plugins": [
+ "build-plugin-react-app",
+ "@ali/build-plugin-recore-lowcode"
+ ],
+ "externals": { "react": "window.React", "react-dom": "window.ReactDOM", "@ali/recore": "window.Recore" }
+}
+
+ `,
+ );
+
+ return [[], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/package.json.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/package.json.ts
new file mode 100644
index 000000000..d8da2daaa
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/package.json.ts
@@ -0,0 +1,66 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'package',
+ 'json',
+ `
+{
+ "name": "test",
+ "version": "1.0.0",
+ "description": "test",
+ "scripts": {
+ "start": "build-scripts start",
+ "build": "build-scripts build",
+ "test": "build-scripts test"
+ },
+ "engines": {
+ "node": ">= 8.9.0",
+ "npm": ">=6.1.0"
+ },
+ "dependencies": {
+ "@ali/lowcode-runtime": "^0.8.0",
+ "@ali/recore": "^1.6.10",
+ "@ali/recore-renderer": "^0.0.3",
+ "@ali/vc-block": "^3.0.3-beta.1",
+ "@ali/vc-deep": "1.2.38",
+ "@ali/vc-div": "^1.0.1",
+ "@ali/vc-page": "^1.0.5",
+ "@ali/vc-shell": "1.3.1",
+ "@ali/vc-slot": "^2.0.1",
+ "@ali/vc-text": "^4.0.1",
+ "@ali/vu-dataSource": "^1.0.4",
+ "@ali/vu-formatter": "^2.0.0",
+ "@ali/vu-fusion": "^2.0.1-beta.0",
+ "@ali/vu-legao-builtin": "^1.4.0-beta.2",
+ "@ali/vu-toolkit": "^1.0.5",
+ "react": "^16"
+ },
+ "devDependencies": {
+ "@ali/build-plugin-recore-lowcode": "^0.0.3",
+ "@ali/recore-lowcode-loader": "^0.0.4",
+ "@alib/build-scripts": "^0.1.0",
+ "@types/node": "^7",
+ "@types/react": "^16",
+ "build-plugin-react-app": "^1.0.15",
+ "eslint": "^6.5.1",
+ "prettier": "^1.18.2",
+ "tslib": "^1.9.3",
+ "typescript": "^3.1.3"
+ },
+ "lint-staged": {
+ "./src/**/*.{ts,tsx}": [
+ "tslint --fix",
+ "git add"
+ ]
+ }
+}
+
+ `,
+ );
+
+ return [[], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/public/index.html.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/public/index.html.ts
new file mode 100644
index 000000000..af229a7e0
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/public/index.html.ts
@@ -0,0 +1,51 @@
+
+import ResultFile from '../../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'index',
+ 'html',
+ `
+
+
+
+
+
+
+ lowcode-runtime-test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ );
+
+ return [['public'], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/app.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/app.ts.ts
new file mode 100644
index 000000000..784662e28
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/app.ts.ts
@@ -0,0 +1,77 @@
+
+import ResultFile from '../../../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'app',
+ 'ts',
+ `
+export default {
+ "sdkVersion": "1.0.3",
+ "history": "hash", // 浏览器路由:brower 哈希路由:hash
+ "containerId": "app",
+ "layout": {
+ "componentName": "BasicLayout",
+ "props": {
+ "navConfig": {
+ "showLanguageChange": true,
+ "data": [
+ {
+ "hidden": false,
+ "navUuid": "FORM-CP5669B1-3AW9DCLHZAY8EIY6WE6X1-GFZM3V1K-6",
+ "children": [],
+ "icon": "",
+ "targetNew": false,
+ "title": "测试基础表格",
+ "inner": true,
+ "relateUuid": "FORM-CP5669B1-3AW9DCLHZAY8EIY6WE6X1-GFZM3V1K-6",
+ "slug": "qihfg"
+ },
+ {
+ "hidden": false,
+ "navUuid": "FORM-CP5669B1-8AW9XCUT4PCH15SMDWUM3-ZPQP3V1K-1",
+ "children": [],
+ "icon": "",
+ "targetNew": false,
+ "title": "测试查询表格",
+ "inner": true,
+ "relateUuid": "zqhej",
+ "slug": "zqhej"
+ }
+ ],
+ "systemLink": "/my_dev_center_code/0.1.0",
+ "appName": "乐高转码demo",
+ "isFoldHorizontal": "n",
+ "showAppTitle": true,
+ "isFold": "n",
+ "searchBarType": "icon",
+ "singletons": {},
+ "navTheme": "default",
+ "type": "top_side_fold",
+ "navStyle": "orange",
+ "layout": "auto",
+ "bgColor": "white",
+ "languageChangeUrl": "/common/account/changeAccountLanguage.json",
+ "showSearch": "n",
+ "openSubMode": false,
+ "showCrumb": true,
+ "isFixed": "y",
+ "showIcon": false,
+ "showNav": true
+ }
+ },
+ },
+ "theme": {
+ "package": "@alife/theme-fusion",
+ "version": "^0.1.0"
+ },
+ "compDependencies": []
+}
+
+ `,
+ );
+
+ return [['src','config'], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/components.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/components.ts.ts
new file mode 100644
index 000000000..c894e92aa
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/components.ts.ts
@@ -0,0 +1,43 @@
+
+import ResultFile from '../../../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'components',
+ 'ts',
+ `
+/**
+ * 乐高组件
+ */
+import Div from '@ali/vc-div/build/view';
+import Text from '@ali/vc-text/build/view';
+import Slot from '@ali/vc-slot/build/view';
+import Deep from '@ali/vc-deep/build/view';
+import Page from '@ali/vc-page/build/view';
+import Block from '@ali/vc-block/build/view';
+
+const components = [Div, Text, Slot, Deep, Page, Block];
+const componentsMap = {
+};
+
+const processComponents = (deps) => {
+ deps.forEach((dep) => {
+ if (Array.isArray(dep)) {
+ processComponents(dep);
+ } else {
+ componentsMap[dep.displayName] = dep;
+ }
+ });
+};
+
+processComponents(components);
+
+export default componentsMap;
+
+ `,
+ );
+
+ return [['src','config'], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/utils.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/utils.ts.ts
new file mode 100644
index 000000000..84237ae1d
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/utils.ts.ts
@@ -0,0 +1,29 @@
+
+import ResultFile from '../../../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'utils',
+ 'ts',
+ `
+import toolkit from '@ali/vu-toolkit';
+import fusion from '@ali/vu-fusion';
+import dataSource from '@ali/vu-dataSource';
+import legaoBuiltin from '@ali/vu-legao-builtin';
+import formatter from '@ali/vu-formatter';
+
+export default {
+ ...toolkit,
+ ...fusion,
+ legaoBuiltin,
+ dataSource,
+ formatter
+}
+
+ `,
+ );
+
+ return [['src','config'], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/index.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/index.ts.ts
new file mode 100644
index 000000000..979b85a20
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/index.ts.ts
@@ -0,0 +1,101 @@
+
+import ResultFile from '../../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'index',
+ 'ts',
+ `
+import { app } from '@ali/lowcode-runtime';
+import { ReactProvider } from '@ali/lowcode-runtime';
+import Shell from '@ali/vc-shell';
+import StaticRender from './plugins/provider';
+import Router from '@/router';
+import appConfig from '@/config/app';
+import components from '@/config/components';
+import utils from '@/config/utils';
+
+// 定制加载应用配置的逻辑
+class StaticRender extends ReactProvider {
+ // 初始化时调用,如可以在这里注入全局API
+ init() {
+ const gConfig = (window as any).g_config || {};
+ const LeGao = {
+ __ctx__: {},
+ createContext: (cfg: any) => {
+ const { schema } = cfg || {};
+ // 1. 根据参数拉取schema
+ if (schema && typeof schema === 'string') {
+ this.setHomePage(schema);
+ }
+ const { isSectionalRender, autoRender } = gConfig || {};
+ if (isSectionalRender && !autoRender) {
+ // 2. 渲染
+ this.setSectionalRender();
+ this.ready();
+ }
+ const provider = this;
+ class Context {
+ get utils() {
+ return provider.getUtils();
+ }
+ get components() {
+ return provider.getComponents();
+ }
+ }
+ const ctx = new Context();
+ (LeGao.__ctx__ as any)[this.getContainerId()] = ctx;
+ return ctx;
+ },
+ getContext: (id: string) => {
+ if (!id) {
+ for (id in LeGao.__ctx__) {
+ return (LeGao.__ctx__ as any)[id];
+ }
+ }
+ return (LeGao.__ctx__ as any)[id];
+ }
+ };
+ (window as any).LeGao = LeGao;
+ if (gConfig.index) {
+ this.setHomePage(gConfig.index);
+ }
+ if (gConfig.isSectionalRender) {
+ this.setSectionalRender();
+ if (!gConfig.autoRender) {
+ return;
+ }
+ }
+ this.ready();
+ }
+
+ // 定制获取、处理应用配置(组件、插件、路由模式、布局等)的逻辑
+ getAppData() {
+ return {
+ ...appConfig,
+ components,
+ utils: utils,
+ }
+ }
+
+ getRouterView() {
+ return Router;
+ }
+}
+
+// 注册布局组件,可注册多个
+app.registerLayout(Shell, {
+ componentName: 'BasicLayout',
+});
+
+app.registerProvider(StaticRender);
+
+app.run();
+
+ `,
+ );
+
+ return [['src'], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/router.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/router.ts.ts
new file mode 100644
index 000000000..78d1fff61
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/router.ts.ts
@@ -0,0 +1,21 @@
+
+import ResultFile from '../../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'router',
+ 'ts',
+ `
+export default {
+ baseDir: './pages',
+ exact: true,
+ routes: [
+ { main: './page_index', path: '/' },
+ ],
+};
+ `,
+ );
+
+ return [['src'], file];
+}
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/tsconfig.json.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/tsconfig.json.ts
new file mode 100644
index 000000000..c30c3e46b
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/tsconfig.json.ts
@@ -0,0 +1,53 @@
+
+import ResultFile from '../../../../../../model/ResultFile';
+import { IResultFile } from '../../../../../../types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ 'tsconfig',
+ 'json',
+ `
+{
+ "compilerOptions": {
+ "lib": ["es2015", "dom"],
+ // Target latest version of ECMAScript.
+ "target": "esnext",
+ // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.
+ "module": "esnext",
+ // Search under node_modules for non-relative imports.
+ "moduleResolution": "node",
+ // Process & infer types from .js files.
+ "allowJs": true,
+ // Report errors in .js files.
+ "checkJs": false,
+ // Don't emit; allow Babel to transform files.
+ "noEmit": true,
+ // Enable strictest settings like strictNullChecks & noImplicitAny.
+ "strict": true,
+ // Allow default imports from modules with no default export. This does not affect code emit, just typechecking.
+ "allowSyntheticDefaultImports": true,
+ // Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.
+ "esModuleInterop": true,
+ // Specify JSX code generation: 'preserve', 'react-native', or 'react'.
+ "jsx": "preserve",
+ // Import emit helpers (e.g. __extends, __rest, etc..) from tslib
+ "importHelpers": true,
+ // Enables experimental support for ES7 decorators.
+ "experimentalDecorators": true,
+ // Generates corresponding .map file.
+ "sourceMap": true,
+ // Disallow inconsistently-cased references to the same file.
+ "forceConsistentCasingInFileNames": true,
+ // Allow json import
+ "resolveJsonModule": true,
+ // skip type checking of declaration files
+ "skipLibCheck": true,
+ }
+}
+
+ `,
+ );
+
+ return [[], file];
+}
+
\ No newline at end of file
diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/index.ts b/packages/code-generator/src/plugins/project/framework/recore/template/index.ts
new file mode 100644
index 000000000..1fd9565b9
--- /dev/null
+++ b/packages/code-generator/src/plugins/project/framework/recore/template/index.ts
@@ -0,0 +1,54 @@
+import ResultDir from '../../../../../model/ResultDir';
+import {
+ IProjectTemplate,
+ IResultDir,
+} from '../../../../../types';
+import { runFileGenerator } from '../../../../../utils/templateHelper';
+
+import file1 from './files/abc.json';
+import file2 from './files/build.json';
+import file3 from './files/.editorconfig';
+import file4 from './files/.eslintignore';
+import file5 from './files/.gitignore';
+import file6 from './files/.prettierrc';
+import file7 from './files/README.md';
+import file8 from './files/package.json';
+import file9 from './files/public/index.html';
+import file10 from './files/src/index.ts';
+import file11 from './files/src/router.ts';
+import file13 from './files/src/config/app.ts';
+import file14 from './files/src/config/components.ts';
+import file15 from './files/src/config/utils.ts';
+import file16 from './files/tsconfig.json';
+
+const icejsTemplate: IProjectTemplate = {
+ slots: {
+ pages: {
+ path: ['src', 'pages'],
+ },
+ },
+
+ generateTemplate(): IResultDir {
+ const root = new ResultDir('.');
+
+ runFileGenerator(root, file1);
+ runFileGenerator(root, file2);
+ runFileGenerator(root, file3);
+ runFileGenerator(root, file4);
+ runFileGenerator(root, file5);
+ runFileGenerator(root, file6);
+ runFileGenerator(root, file7);
+ runFileGenerator(root, file8);
+ runFileGenerator(root, file9);
+ runFileGenerator(root, file10);
+ runFileGenerator(root, file11);
+ runFileGenerator(root, file13);
+ runFileGenerator(root, file14);
+ runFileGenerator(root, file15);
+ runFileGenerator(root, file16);
+
+ return root;
+ },
+};
+
+export default icejsTemplate;
diff --git a/packages/code-generator/src/plugins/project/i18n.ts b/packages/code-generator/src/plugins/project/i18n.ts
index 14b9ef773..cada1fd96 100644
--- a/packages/code-generator/src/plugins/project/i18n.ts
+++ b/packages/code-generator/src/plugins/project/i18n.ts
@@ -1,66 +1,69 @@
import { COMMON_CHUNK_NAME } from '../../const/generator';
-import { generateCompositeType } from '../../plugins/utils/compositeType';
+import { generateCompositeType } from '../../utils/compositeType';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IProjectInfo,
} from '../../types';
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
+
+ const ir = next.ir as IProjectInfo;
+ if (ir.i18n) {
+ const [, i18nStr] = generateCompositeType(ir.i18n);
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileMainContent,
+ content: `
+ const i18nConfig = ${i18nStr};
+ let locale = 'en_US';
+
+ const changeLocale = (target) => {
+ locale = target;
+ };
+
+ const i18n = key => i18nConfig && i18nConfig[locale] && i18nConfig[locale][key] || '';
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ ],
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileExport,
+ content: `
+ export {
+ changeLocale,
+ i18n,
+ };
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ COMMON_CHUNK_NAME.FileMainContent,
+ ],
+ });
+ }
+
+ return next;
};
-
- const ir = next.ir as IProjectInfo;
- if (ir.i18n) {
- const [, i18nStr] = generateCompositeType(ir.i18n);
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileMainContent,
- content: `
- const i18nConfig = ${i18nStr};
- let locale = 'en_US';
-
- const changeLocale = (target) => {
- locale = target;
- };
-
- const i18n = key => i18nConfig && i18nConfig[locale] && i18nConfig[locale][key] || '';
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileUtilDefine,
- ],
- });
-
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileExport,
- content: `
- export {
- changeLocale,
- i18n,
- };
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileUtilDefine,
- COMMON_CHUNK_NAME.FileMainContent,
- ],
- });
- }
-
- return next;
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/project/utils.ts b/packages/code-generator/src/plugins/project/utils.ts
index f40ba41e2..32e7c5d17 100644
--- a/packages/code-generator/src/plugins/project/utils.ts
+++ b/packages/code-generator/src/plugins/project/utils.ts
@@ -2,59 +2,28 @@ import { COMMON_CHUNK_NAME } from '../../const/generator';
import {
BuilderComponentPlugin,
+ BuilderComponentPluginFactory,
ChunkType,
FileType,
ICodeStruct,
IUtilInfo,
} from '../../types';
-// TODO: How to merge this logic to common deps
-const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
- const next: ICodeStruct = {
- ...pre,
- };
+const pluginFactory: BuilderComponentPluginFactory = () => {
+ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
+ const next: ICodeStruct = {
+ ...pre,
+ };
- const ir = next.ir as IUtilInfo;
-
- if (ir.utils) {
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileExport,
- content: `
- export default {
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileUtilDefine,
- COMMON_CHUNK_NAME.FileMainContent,
- ],
- });
-
- ir.utils.forEach(util => {
- if (util.type === 'function') {
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileVarDefine,
- content: `
- const ${util.name} = ${util.content};
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- ],
- });
- }
+ const ir = next.ir as IUtilInfo;
+ if (ir.utils) {
next.chunks.push({
type: ChunkType.STRING,
fileType: FileType.JS,
name: COMMON_CHUNK_NAME.FileExport,
content: `
- ${util.name},
+ export default {
`,
linkAfter: [
COMMON_CHUNK_NAME.ExternalDepsImport,
@@ -64,26 +33,60 @@ const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
COMMON_CHUNK_NAME.FileMainContent,
],
});
- });
- next.chunks.push({
- type: ChunkType.STRING,
- fileType: FileType.JS,
- name: COMMON_CHUNK_NAME.FileExport,
- content: `
- };
- `,
- linkAfter: [
- COMMON_CHUNK_NAME.ExternalDepsImport,
- COMMON_CHUNK_NAME.InternalDepsImport,
- COMMON_CHUNK_NAME.FileVarDefine,
- COMMON_CHUNK_NAME.FileUtilDefine,
- COMMON_CHUNK_NAME.FileMainContent,
- ],
- });
- }
+ ir.utils.forEach(util => {
+ if (util.type === 'function') {
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileVarDefine,
+ content: `
+ const ${util.name} = ${util.content};
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ ],
+ });
+ }
- return next;
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileExport,
+ content: `
+ ${util.name},
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ COMMON_CHUNK_NAME.FileMainContent,
+ ],
+ });
+ });
+
+ next.chunks.push({
+ type: ChunkType.STRING,
+ fileType: FileType.JS,
+ name: COMMON_CHUNK_NAME.FileExport,
+ content: `
+ };
+ `,
+ linkAfter: [
+ COMMON_CHUNK_NAME.ExternalDepsImport,
+ COMMON_CHUNK_NAME.InternalDepsImport,
+ COMMON_CHUNK_NAME.FileVarDefine,
+ COMMON_CHUNK_NAME.FileUtilDefine,
+ COMMON_CHUNK_NAME.FileMainContent,
+ ],
+ });
+ }
+
+ return next;
+ };
+ return plugin;
};
-export default plugin;
+export default pluginFactory;
diff --git a/packages/code-generator/src/plugins/utils/compositeType.ts b/packages/code-generator/src/plugins/utils/compositeType.ts
deleted file mode 100644
index 2e102fcac..000000000
--- a/packages/code-generator/src/plugins/utils/compositeType.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { CompositeArray, CompositeValue, ICompositeObject } from '../../types';
-import { generateValue, isJsExpression } from './jsExpression';
-
-function generateArray(value: CompositeArray): string {
- const body = value.map(v => generateUnknownType(v)).join(',');
- return `[${body}]`;
-}
-
-function generateObject(value: ICompositeObject): string {
- if (isJsExpression(value)) {
- return generateValue(value);
- }
-
- const body = Object.keys(value)
- .map(key => {
- const v = generateUnknownType(value[key]);
- return `${key}: ${v}`;
- })
- .join(',');
-
- return `{${body}}`;
-}
-
-function generateUnknownType(value: CompositeValue): string {
- if (Array.isArray(value)) {
- return generateArray(value as CompositeArray);
- } else if (typeof value === 'object') {
- return generateObject(value as ICompositeObject);
- } else if (typeof value === 'string') {
- return `'${value}'`;
- }
- return `${value}`;
-}
-
-export function generateCompositeType(
- value: CompositeValue,
-): [boolean, string] {
- const result = generateUnknownType(value);
-
- if (result.substr(0, 1) === "'" && result.substr(-1, 1) === "'") {
- return [true, result.substring(1, result.length - 1)];
- }
-
- return [false, result];
-}
diff --git a/packages/code-generator/src/plugins/utils/jsExpression.ts b/packages/code-generator/src/plugins/utils/jsExpression.ts
deleted file mode 100644
index eda1883bc..000000000
--- a/packages/code-generator/src/plugins/utils/jsExpression.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { CodeGeneratorError, IJSExpression } from '../../types';
-
-export function transformFuncExpr2MethodMember(
- methodName: string,
- functionBody: string,
-): string {
- if (functionBody.indexOf('function') < 8) {
- return functionBody.replace('function', methodName);
- }
- return functionBody;
-}
-
-export function getFuncExprBody(functionBody: string) {
- const start = functionBody.indexOf('{');
- const end = functionBody.lastIndexOf('}');
-
- if (start < 0 || end < 0 || end < start) {
- throw new CodeGeneratorError('JSExpression has no valid body.');
- }
-
- const body = functionBody.slice(start + 1, end);
- return body;
-}
-
-export function generateValue(value: any): string {
- if (value && (value as IJSExpression).type === 'JSExpression') {
- return (value as IJSExpression).value;
- }
-
- throw new CodeGeneratorError('Not a JSExpression');
-}
-
-export function isJsExpression(value: any): boolean {
- return (
- value &&
- typeof value === 'object' &&
- (value as IJSExpression).type === 'JSExpression'
- );
-}
diff --git a/packages/code-generator/src/postprocessor/prettier/index.ts b/packages/code-generator/src/postprocessor/prettier/index.ts
index 947c535c2..519c2db5d 100644
--- a/packages/code-generator/src/postprocessor/prettier/index.ts
+++ b/packages/code-generator/src/postprocessor/prettier/index.ts
@@ -1,22 +1,42 @@
import prettier from 'prettier';
+import mypretter from '@ali/my-prettier';
-import { PostProcessor } from '../../types';
+import { PostProcessor, PostProcessorFactory } from '../../types';
const PARSERS = ['css', 'scss', 'less', 'json', 'html', 'vue'];
-const codePrettier: PostProcessor = (content: string, fileType: string) => {
- let parser: prettier.BuiltInParserName;
- if (fileType === 'js' || fileType === 'jsx') {
- parser = 'babel';
- } else if (PARSERS.indexOf(fileType) >= 0) {
- parser = fileType as prettier.BuiltInParserName;
- } else {
- return content;
- }
+interface ProcessorConfig {
+ customFileTypeParser: Record;
+}
- return prettier.format(content, {
- parser,
- });
+const factory: PostProcessorFactory = (config?: ProcessorConfig) => {
+ const cfg: ProcessorConfig = {
+ customFileTypeParser: {},
+ ...config,
+ };
+
+ const codePrettier: PostProcessor = (content: string, fileType: string) => {
+ let parser: prettier.BuiltInParserName;
+ if (fileType === 'js' || fileType === 'jsx') {
+ parser = 'babel';
+ } else if (fileType === 'ts' || fileType === 'tsx') {
+ parser = 'typescript';
+ } else if (PARSERS.indexOf(fileType) >= 0) {
+ parser = fileType as prettier.BuiltInParserName;
+ } else if (cfg.customFileTypeParser[fileType]){
+ parser = cfg.customFileTypeParser[fileType] as prettier.BuiltInParserName;
+ } else if (fileType === 'vx') {
+ return mypretter(content, fileType);
+ } else {
+ return content;
+ }
+
+ return prettier.format(content, {
+ parser,
+ });
+ };
+
+ return codePrettier;
};
-export default codePrettier;
+export default factory;
diff --git a/packages/code-generator/src/solutions/icejs.ts b/packages/code-generator/src/solutions/icejs.ts
index 10fe842c4..62a514008 100644
--- a/packages/code-generator/src/solutions/icejs.ts
+++ b/packages/code-generator/src/solutions/icejs.ts
@@ -28,36 +28,40 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
template,
plugins: {
components: [
- reactCommonDeps,
- esmodule,
- containerClass,
- containerInjectUtils,
- containerInitState,
- containerLifeCycle,
- containerMethod,
- jsx,
- css,
+ reactCommonDeps(),
+ esmodule({
+ fileType: 'jsx',
+ }),
+ containerClass(),
+ containerInjectUtils(),
+ containerInitState(),
+ containerLifeCycle(),
+ containerMethod(),
+ jsx(),
+ css(),
],
pages: [
- reactCommonDeps,
- esmodule,
- containerClass,
- containerInjectUtils,
- containerInitState,
- containerLifeCycle,
- containerMethod,
- jsx,
- css,
+ reactCommonDeps(),
+ esmodule({
+ fileType: 'jsx',
+ }),
+ containerClass(),
+ containerInjectUtils(),
+ containerInitState(),
+ containerLifeCycle(),
+ containerMethod(),
+ jsx(),
+ css(),
],
- router: [esmodule, iceJsRouter],
- entry: [iceJsEntry],
- constants: [constants],
- utils: [esmodule, utils],
- i18n: [i18n],
- globalStyle: [iceJsGlobalStyle],
- htmlEntry: [iceJsEntryHtml],
- packageJSON: [iceJsPackageJSON],
+ router: [esmodule(), iceJsRouter()],
+ entry: [iceJsEntry()],
+ constants: [constants()],
+ utils: [esmodule(), utils()],
+ i18n: [i18n()],
+ globalStyle: [iceJsGlobalStyle()],
+ htmlEntry: [iceJsEntryHtml()],
+ packageJSON: [iceJsPackageJSON()],
},
- postProcessors: [prettier],
+ postProcessors: [prettier()],
});
}
diff --git a/packages/code-generator/src/solutions/recore.ts b/packages/code-generator/src/solutions/recore.ts
new file mode 100644
index 000000000..9850f2b3a
--- /dev/null
+++ b/packages/code-generator/src/solutions/recore.ts
@@ -0,0 +1,51 @@
+import { IProjectBuilder } from '../types';
+
+import { createProjectBuilder } from '../generator/ProjectBuilder';
+
+// import esmodule from '../plugins/common/esmodule';
+import containerInitState from '../plugins/component/react/containerInitState';
+import containerLifeCycle from '../plugins/component/react/containerLifeCycle';
+import containerMethod from '../plugins/component/react/containerMethod';
+import pageFrame from '../plugins/component/recore/pageFrame';
+import pageStyle from '../plugins/component/recore/pageStyle';
+import pageVmHeader from '../plugins/component/recore/pageVmHeader';
+import pageVmBody from '../plugins/component/recore/pageVmBody';
+import pageDataSource from '../plugins/component/recore/pageDataSource';
+import template from '../plugins/project/framework/recore/template';
+
+import { prettier } from '../postprocessor';
+
+export default function createRecoreProjectBuilder(): IProjectBuilder {
+ return createProjectBuilder({
+ template,
+ plugins: {
+ pages: [
+ pageFrame(),
+ pageStyle(),
+ containerInitState({
+ fileType: 'ts',
+ implementType: 'insMember',
+ }),
+ containerLifeCycle({
+ fileType: 'ts',
+ exportNameMapping: {
+ constructor: 'init',
+ componentDidMount: 'didMount',
+ willUnmount: 'willUnMount',
+ componentWillUnmount: 'willUnMount',
+ },
+ normalizeNameMapping: {
+ init: 'constructor',
+ },
+ }),
+ containerMethod({
+ fileType: 'ts',
+ }),
+ pageDataSource(),
+ pageVmHeader(),
+ pageVmBody(),
+ ],
+ },
+ postProcessors: [prettier()],
+ });
+}
diff --git a/packages/code-generator/src/types/core.ts b/packages/code-generator/src/types/core.ts
index 804f4f3e6..a370d5641 100644
--- a/packages/code-generator/src/types/core.ts
+++ b/packages/code-generator/src/types/core.ts
@@ -4,6 +4,8 @@ import {
IProjectSchema,
IResultDir,
IResultFile,
+ IComponentNodeItem,
+ IJSExpression,
} from './index';
export enum FileType {
@@ -12,6 +14,8 @@ export enum FileType {
HTML = 'html',
JS = 'js',
JSX = 'jsx',
+ TS = 'ts',
+ TSX = 'tsx',
JSON = 'json',
}
@@ -32,7 +36,7 @@ export type CodeGeneratorFunction = (content: T) => string;
export interface ICodeChunk {
type: ChunkType;
- fileType: FileType;
+ fileType: string;
name: string;
subModule?: string;
content: ChunkContent;
@@ -53,6 +57,8 @@ export type BuilderComponentPlugin = (
initStruct: ICodeStruct,
) => Promise;
+export type BuilderComponentPluginFactory = (config?: T) => BuilderComponentPlugin;
+
export interface IChunkBuilder {
run(
ir: any,
@@ -72,12 +78,13 @@ export interface ICompiledModule {
}
export interface IModuleBuilder {
- generateModule: (input: unknown) => Promise;
- linkCodeChunks: (
+ generateModule(input: unknown): Promise;
+ generateModuleCode(schema: IBasicSchema | string): Promise;
+ linkCodeChunks(
chunks: Record,
fileName: string,
- ) => IResultFile[];
- addPlugin: (plugin: BuilderComponentPlugin) => void;
+ ): IResultFile[];
+ addPlugin(plugin: BuilderComponentPlugin): void;
}
/**
@@ -99,11 +106,11 @@ export interface ICodeGenerator {
export interface ISchemaParser {
validate(schema: IBasicSchema): boolean;
- parse(schema: IBasicSchema): IParseResult;
+ parse(schema: IBasicSchema | string): IParseResult;
}
export interface IProjectTemplate {
- slots: IProjectSlots;
+ slots: Record;
generateTemplate(): IResultDir;
}
@@ -112,39 +119,59 @@ export interface IProjectSlot {
fileName?: string;
}
-export interface IProjectSlots {
- components: IProjectSlot;
- pages: IProjectSlot;
- router: IProjectSlot;
- entry: IProjectSlot;
- constants?: IProjectSlot;
- utils?: IProjectSlot;
- i18n?: IProjectSlot;
- globalStyle: IProjectSlot;
- htmlEntry: IProjectSlot;
- packageJSON: IProjectSlot;
-}
+// export interface IProjectSlots {
+// components: IProjectSlot;
+// pages: IProjectSlot;
+// router: IProjectSlot;
+// entry: IProjectSlot;
+// constants?: IProjectSlot;
+// utils?: IProjectSlot;
+// i18n?: IProjectSlot;
+// globalStyle: IProjectSlot;
+// htmlEntry: IProjectSlot;
+// packageJSON: IProjectSlot;
+// }
export interface IProjectPlugins {
- components: BuilderComponentPlugin[];
- pages: BuilderComponentPlugin[];
- router: BuilderComponentPlugin[];
- entry: BuilderComponentPlugin[];
- constants?: BuilderComponentPlugin[];
- utils?: BuilderComponentPlugin[];
- i18n?: BuilderComponentPlugin[];
- globalStyle: BuilderComponentPlugin[];
- htmlEntry: BuilderComponentPlugin[];
- packageJSON: BuilderComponentPlugin[];
+ [slotName: string]: BuilderComponentPlugin[];
}
export interface IProjectBuilder {
- generateProject(schema: IProjectSchema): Promise;
+ generateProject(schema: IProjectSchema | string): Promise;
}
+export type PostProcessorFactory = (config?: T) => PostProcessor;
export type PostProcessor = (content: string, fileType: string) => string;
// TODO: temp interface, need modify
export interface IPluginOptions {
fileDirDepth: number;
}
+
+export enum PIECE_TYPE {
+ BEFORE = 'NodeCodePieceBefore',
+ TAG = 'NodeCodePieceTag',
+ ATTR = 'NodeCodePieceAttr',
+ CHILDREN = 'NodeCodePieceChildren',
+ AFTER = 'NodeCodePieceAfter',
+};
+
+export interface CodePiece {
+ value: string;
+ type: PIECE_TYPE;
+}
+
+export interface HandlerSet {
+ string?: (input: string) => T[];
+ expression?: (input: IJSExpression) => T[];
+ node?: (input: IComponentNodeItem) => T[];
+ common?: (input: unknown) => T[];
+}
+
+export type ExtGeneratorPlugin = (nodeItem: IComponentNodeItem) => CodePiece[];
+
+// export interface InteratorScope {
+// [$item: string]: string; // $item 默认取值 "item"
+// [$index: string]: string | number; // $index 默认取值 "index"
+// __proto__: BlockInstance;
+// }
diff --git a/packages/code-generator/src/types/intermediate.ts b/packages/code-generator/src/types/intermediate.ts
index 7ac66079a..54142dfa0 100644
--- a/packages/code-generator/src/types/intermediate.ts
+++ b/packages/code-generator/src/types/intermediate.ts
@@ -17,8 +17,8 @@ export interface IParseResult {
}
export interface IContainerInfo extends IContainerNodeItem, IWithDependency {
- componentName: string;
containerType: string;
+ moduleName: string;
}
export interface IWithDependency {
diff --git a/packages/code-generator/src/types/schema.ts b/packages/code-generator/src/types/schema.ts
index f31bdeb09..68226e8ab 100644
--- a/packages/code-generator/src/types/schema.ts
+++ b/packages/code-generator/src/types/schema.ts
@@ -10,6 +10,7 @@ import { IExternalDependency } from './index';
export interface IJSExpression {
type: 'JSExpression';
value: string;
+ [extConfigName: string]: any;
}
// JSON 基本类型
@@ -87,10 +88,6 @@ export interface IUtilItem {
content: IExternalDependency | IJSExpression;
}
-export interface IInlineStyle {
- [cssAttribute: string]: string | number | IJSExpression;
-}
-
export type ChildNodeItem = string | IJSExpression | IComponentNodeItem;
export type ChildNodeType = ChildNodeItem | ChildNodeItem[];
@@ -106,9 +103,7 @@ export interface IComponentNodeItem {
id?: string;
componentName: string; // 组件名称 必填、首字母大写
props: {
- className?: string; // 组件样式类名
- style?: IInlineStyle; // 组件内联样式
- [propName: string]: any; // 业务属性
+ [propName: string]: CompositeValue; // 业务属性
}; // 组件属性对象
condition?: CompositeValue; // 渲染条件
loop?: CompositeValue; // 循环数据
@@ -124,15 +119,12 @@ export interface IComponentNodeItem {
* @extends {IComponentNodeItem}
*/
export interface IContainerNodeItem extends IComponentNodeItem {
- componentName: string; // 'Page' | 'Block' | 'Component' 组件类型 必填、首字母大写
+ componentName: 'Page' | 'Block' | 'Component'; // 'Page' | 'Block' | 'Component' 组件类型 必填、首字母大写
fileName: string; // 文件名称 必填、英文
- defaultProps?: {
- [propName: string]: any; // 业务属性
- };
state?: {
- [stateName: string]: any; // 容器初始数据
+ [stateName: string]: CompositeValue; // 容器初始数据
};
- css: string; // 样式文件 用于描述容器组件内部节点的样式,对应生成一个独立的样式文件,在对应容器组件生成的 .jsx 文件中 import 引入;
+ css?: string; // 样式文件 用于描述容器组件内部节点的样式,对应生成一个独立的样式文件,在对应容器组件生成的 .jsx 文件中 import 引入;
/**
* LifeCycle
* • constructor(props, context)
@@ -144,37 +136,14 @@ export interface IContainerNodeItem extends IComponentNodeItem {
* • componentWillUnmount()
* • componentDidCatch(error, info)
*/
- lifeCycles?: {
- constructor?: IJSExpression;
- render?: IJSExpression;
- componentDidMount?: IJSExpression;
- componentDidUpdate?: IJSExpression;
- componentWillUnmount?: IJSExpression;
- componentDidCatch?: IJSExpression;
- }; // 生命周期Hook方法
- methods?: {
- [methodName: string]: IJSExpression;
- }; // 自定义方法设置
- dataSource?: IDataSource; // 异步数据源配置
+ lifeCycles?: Record; // 生命周期Hook方法
+ methods?: Record; // 自定义方法设置
+ dataSource?: {
+ list: IDataSourceConfig[];
+ }; // 异步数据源配置
meta?: IBasicMeta | IPageMeta;
}
-/**
- * 搭建基础协议 - 数据源
- *
- * @export
- * @interface IDataSource
- */
-export interface IDataSource {
- list: IDataSourceConfig[]; // 成为为单个请求配置
- /**
- * 参数:为dataMap对象,key:数据id, value: 单个请求结果
- * 返回值:数据对象data,将会在渲染引擎和schemaToCode中通过调用this.setState(...)将返回的数据对象生效到state中;
- * 支持返回一个Promise,通过resolve(返回数据),常用于串型发送请求场景,配合this.dataSourceMap[oneRequest.id].load()使用;
- */
- dataHandler?: IJSExpression;
-}
-
/**
* 搭建基础协议 - 数据源单个配置
*
@@ -184,7 +153,7 @@ export interface IDataSource {
export interface IDataSourceConfig {
id: string; // 数据请求ID标识
isInit: boolean; // 是否为初始数据 支持表达式 值为true时,将在组件初始化渲染时自动发送当前数据请求
- type: 'fetch' | 'mtop' | 'jsonp' | 'custom' | 'doServer'; // 数据请求类型
+ type: string; // 数据请求类型 'fetch' | 'mtop' | 'jsonp' | 'custom'
requestHandler?: IJSExpression; // 自定义扩展的外部请求处理器 仅type='custom'时生效
options?: IFetchOptions; // 请求参数配置 每种请求类型对应不同参数
dataHandler?: IJSExpression; // 数据结果处理函数,形如:(data, err) => Object
@@ -197,7 +166,7 @@ export interface IDataSourceConfig {
* @interface IFetchOptions
*/
export interface IFetchOptions {
- uri: string; // 请求地址 支持表达式
+ url: string; // 请求地址 支持表达式
params?: {
// 请求参数
[key: string]: any;
@@ -209,6 +178,7 @@ export interface IFetchOptions {
// 自定义请求头
[key: string]: string;
};
+ [extConfigName: string]: any;
}
export interface IBasicMeta {
@@ -252,4 +222,5 @@ export interface IAppMeta {
description?: string; // 应用描述
spma?: string; // 应用spma A位信息
creator?: string; // author
+ [otherAttrName: string]: any;
}
diff --git a/packages/code-generator/src/utils/children.ts b/packages/code-generator/src/utils/children.ts
deleted file mode 100644
index 2f2d34fda..000000000
--- a/packages/code-generator/src/utils/children.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import {
- ChildNodeItem,
- ChildNodeType,
- IComponentNodeItem,
- IJSExpression,
-} from '../types';
-
-// tslint:disable-next-line: no-empty
-const noop = () => [];
-
-export function handleChildren(
- children: ChildNodeType,
- handlers: {
- string?: (input: string) => T[];
- expression?: (input: IJSExpression) => T[];
- node?: (input: IComponentNodeItem) => T[];
- common?: (input: unknown) => T[];
- },
-): T[] {
- if (Array.isArray(children)) {
- const list: ChildNodeItem[] = children as ChildNodeItem[];
- return list
- .map(child => handleChildren(child, handlers))
- .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') {
- const handler = handlers.expression || handlers.common || noop;
- return handler(children as IJSExpression);
- } else {
- const handler = handlers.node || handlers.common || noop;
- return handler(children as IComponentNodeItem);
- }
-}
diff --git a/packages/code-generator/src/utils/compositeType.ts b/packages/code-generator/src/utils/compositeType.ts
new file mode 100644
index 000000000..b62b2afe3
--- /dev/null
+++ b/packages/code-generator/src/utils/compositeType.ts
@@ -0,0 +1,88 @@
+import { CompositeArray, CompositeValue, ICompositeObject } from '../types';
+import { generateExpression, isJsExpression } from './jsExpression';
+
+type CustomHandler = (data: unknown) => string;
+interface CustomHandlerSet {
+ boolean?: CustomHandler;
+ number?: CustomHandler;
+ string?: CustomHandler;
+ array?: CustomHandler;
+ object?: CustomHandler;
+ expression?: CustomHandler;
+}
+
+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 {
+ if (isJsExpression(value)) {
+ if (handlers.expression) {
+ return handlers.expression(value);
+ }
+ return generateExpression(value);
+ }
+
+ const body = Object.keys(value)
+ .map(key => {
+ const v = generateUnknownType(value[key], handlers);
+ return `${key}: ${v}`;
+ })
+ .join(',\n');
+
+ return `{${body}}`;
+}
+
+export function generateUnknownType(
+ value: CompositeValue,
+ handlers: CustomHandlerSet = {},
+): string {
+ if (Array.isArray(value)) {
+ if (handlers.array) {
+ return handlers.array(value);
+ }
+ return generateArray(value as CompositeArray, handlers);
+ } else if (typeof value === 'object') {
+ if (handlers.object) {
+ return handlers.object(value);
+ }
+ return generateObject(value as ICompositeObject, handlers);
+ } else if (typeof value === 'string') {
+ if (handlers.string) {
+ return handlers.string(value);
+ }
+ return `'${value}'`;
+ } else if (typeof value === 'number' && handlers.number) {
+ return handlers.number(value);
+ } else if (typeof value === 'boolean' && handlers.boolean) {
+ return handlers.boolean(value);
+ }
+ return `${value}`;
+}
+
+export function generateCompositeType(
+ value: CompositeValue,
+ handlers: CustomHandlerSet = {},
+): [boolean, string] {
+ const result = generateUnknownType(value, handlers);
+
+ if (result.substr(0, 1) === "'" && result.substr(-1, 1) === "'") {
+ return [true, result.substring(1, result.length - 1)];
+ }
+
+ return [false, result];
+}
+
+export function handleStringValueDefault([isString, result]: [boolean, string]) {
+ if (isString) {
+ return `'${result}'`;
+ }
+ return result;
+}
diff --git a/packages/code-generator/src/utils/jsExpression.ts b/packages/code-generator/src/utils/jsExpression.ts
new file mode 100644
index 000000000..9c8541692
--- /dev/null
+++ b/packages/code-generator/src/utils/jsExpression.ts
@@ -0,0 +1,85 @@
+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);
+
+ const args = getFuncExprArguments(functionBody);
+ const body = getFuncExprBody(functionBody);
+
+ return `${methodName}(${args}) { ${body} }`;
+}
+
+export function getFuncExprArguments(functionBody: string) {
+ const start = functionBody.indexOf('(');
+ const end = functionBody.indexOf(')');
+
+ if (start < 0 || end < 0 || end < start) {
+ throw new CodeGeneratorError('JSExpression has no valid arguments.');
+ }
+
+ const args = functionBody.slice(start + 1, end);
+ return args;
+}
+
+export function getFuncExprBody(functionBody: string) {
+ const start = functionBody.indexOf('{');
+ const end = functionBody.lastIndexOf('}');
+
+ // test(functionBody);
+
+ if (start < 0 || end < 0 || end < start) {
+ throw new CodeGeneratorError('JSExpression has no valid body.');
+ }
+
+ const body = functionBody.slice(start + 1, end);
+ return body;
+}
+
+export function generateExpression(value: any): string {
+ if (value && (value as IJSExpression).type === 'JSExpression') {
+ // test((value as IJSExpression).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'
+ );
+}
diff --git a/packages/code-generator/src/utils/nodeToJSX.ts b/packages/code-generator/src/utils/nodeToJSX.ts
new file mode 100644
index 000000000..a60351202
--- /dev/null
+++ b/packages/code-generator/src/utils/nodeToJSX.ts
@@ -0,0 +1,191 @@
+import {
+ ChildNodeType,
+ IComponentNodeItem,
+ IJSExpression,
+ ChildNodeItem,
+ CodeGeneratorError,
+ PIECE_TYPE,
+ CodePiece,
+ HandlerSet,
+ ExtGeneratorPlugin,
+} from '../types';
+import { generateCompositeType } from './compositeType';
+import { generateExpression } from './jsExpression';
+
+// tslint:disable-next-line: no-empty
+const noop = () => [];
+
+export function handleChildren(
+ children: ChildNodeType,
+ handlers: HandlerSet,
+): T[] {
+ if (Array.isArray(children)) {
+ const list: ChildNodeItem[] = children as ChildNodeItem[];
+ return list
+ .map(child => handleChildren(child, handlers))
+ .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') {
+ const handler = handlers.expression || handlers.common || noop;
+ return handler(children as IJSExpression);
+ } else {
+ const handler = handlers.node || handlers.common || noop;
+ return handler(children as IComponentNodeItem);
+ }
+}
+
+export function generateAttr(attrName: string, attrValue: any): CodePiece[] {
+ if (attrName === 'initValue' || attrName === 'labelCol') {
+ return [];
+ }
+ const [isString, valueStr] = generateCompositeType(attrValue);
+ 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])),
+ );
+
+ return pieces;
+}
+
+export function mapNodeName(src: string): string {
+ if (src === 'Div') {
+ return 'div';
+ }
+ return src;
+}
+
+export function generateBasicNode(nodeItem: IComponentNodeItem): CodePiece[] {
+ const pieces: CodePiece[] = [];
+ pieces.push({
+ value: mapNodeName(nodeItem.componentName),
+ type: PIECE_TYPE.TAG,
+ });
+
+ return pieces;
+}
+
+export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[] {
+ const pieces: CodePiece[] = [];
+
+ if (nodeItem.loop && nodeItem.loopArgs) {
+ let loopDataExp;
+ if ((nodeItem.loop as IJSExpression).type === 'JSExpression') {
+ loopDataExp = `(${(nodeItem.loop as IJSExpression).value})`;
+ } else {
+ loopDataExp = JSON.stringify(nodeItem.loop);
+ }
+ pieces.unshift({
+ value: `${loopDataExp}.map((${nodeItem.loopArgs[0]}, ${nodeItem.loopArgs[1]}) => (`,
+ type: PIECE_TYPE.BEFORE,
+ });
+ pieces.push({
+ value: '))',
+ type: PIECE_TYPE.AFTER,
+ });
+ }
+
+ if (nodeItem.condition) {
+ pieces.unshift({
+ value: `(${generateCompositeType(nodeItem.condition)}) && (`,
+ type: PIECE_TYPE.BEFORE,
+ });
+ pieces.push({
+ value: ')',
+ type: PIECE_TYPE.AFTER,
+ });
+ }
+
+ if (nodeItem.condition || (nodeItem.loop && nodeItem.loopArgs)) {
+ pieces.unshift({
+ value: '{',
+ type: PIECE_TYPE.BEFORE,
+ });
+ pieces.push({
+ value: '}',
+ type: PIECE_TYPE.AFTER,
+ });
+ }
+
+ return pieces;
+}
+
+export function linkPieces(pieces: CodePiece[]): string {
+ 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 beforeParts = pieces
+ .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)
+ .join('');
+
+ const childrenParts = pieces
+ .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)
+ .join(' ');
+
+ attrsParts = !!attrsParts ? ` ${attrsParts}` : '';
+
+ if (childrenParts) {
+ return `${beforeParts}<${tagName}${attrsParts}>${childrenParts}${tagName}>${afterParts}`;
+ }
+
+ return `${beforeParts}<${tagName}${attrsParts} />${afterParts}`;
+}
+
+export function createNodeGenerator(handlers: HandlerSet, plugins: ExtGeneratorPlugin[]) {
+ const generateNode = (nodeItem: IComponentNodeItem): string => {
+ let pieces: CodePiece[] = [];
+
+ plugins.forEach(p => {
+ pieces = pieces.concat(p(nodeItem));
+ });
+ pieces = pieces.concat(generateBasicNode(nodeItem));
+ 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,
+ })));
+ }
+
+ return linkPieces(pieces);
+ };
+
+ handlers.node = (input: IComponentNodeItem) => [generateNode(input)];
+
+ return generateNode;
+}
+
+export const generateString = (input: string) => [input];
+
+export function createReactNodeGenerator() {
+ return createNodeGenerator({
+ string: generateString,
+ expression: (input) => [generateExpression(input)],
+ }, [
+ generateReactCtrlLine,
+ ]);
+}
diff --git a/packages/code-generator/src/utils/templateHelper.ts b/packages/code-generator/src/utils/templateHelper.ts
new file mode 100644
index 000000000..f1692ad67
--- /dev/null
+++ b/packages/code-generator/src/utils/templateHelper.ts
@@ -0,0 +1,25 @@
+import { IResultFile, IResultDir } from '../types';
+import ResultDir from '../model/ResultDir';
+
+type FuncFileGenerator = () => [string[], IResultFile];
+
+export function insertFile(root: IResultDir, path: string[], file: IResultFile) {
+ let current: IResultDir = root;
+ path.forEach(pathNode => {
+ const dir = current.dirs.find(d => d.name === pathNode);
+ if (dir) {
+ current = dir;
+ } else {
+ const newDir = new ResultDir(pathNode);
+ current.addDirectory(newDir);
+ current = newDir;
+ }
+ });
+
+ current.addFile(file);
+}
+
+export function runFileGenerator(root: IResultDir, fun: FuncFileGenerator) {
+ const [path, file] = fun();
+ insertFile(root, path, file);
+}
diff --git a/packages/code-generator/tools/createTemplate.js b/packages/code-generator/tools/createTemplate.js
new file mode 100644
index 000000000..b7568f7a9
--- /dev/null
+++ b/packages/code-generator/tools/createTemplate.js
@@ -0,0 +1,85 @@
+const fs = require("fs");
+const path = require('path');
+
+console.log(process.argv);
+let root = '';
+const pathArgIndex = process.argv.indexOf('--path');
+if (pathArgIndex >= 0) {
+ root = process.argv[pathArgIndex + 1];
+}
+
+if (!root) {
+ throw new Error('Can\'t find path argument');
+}
+
+function cloneStr(str, times) {
+ let count = times;
+ const arr = [];
+ while(count > 0) {
+ arr.push(str);
+ count -= 1;
+ }
+ return arr.join('');
+}
+
+function createTemplateFile(root, internalPath, fileName) {
+ //不是文件夹,则添加type属性为文件后缀名
+ const fileTypeSrc = path.extname(fileName);
+ const fileType = fileTypeSrc.substring(1);
+ const baseName = path.basename(fileName, fileTypeSrc);
+
+ const filePath = path.join(root, internalPath);
+ const pieces = filePath.split(path.sep);
+ const depPrefix = cloneStr('../', pieces.length - 1);
+ const content = fs.readFileSync(path.join(filePath, fileName), {
+ encoding: 'utf8',
+ });
+ const pathList = (internalPath.split(path.sep) || []).filter(p => !!p);
+ const modulePathStr = JSON.stringify(pathList).replace(/\"/g, '\'');
+
+ const templateContent = `
+import ResultFile from '${depPrefix}model/ResultFile';
+import { IResultFile } from '${depPrefix}types';
+
+export default function getFile(): [string[], IResultFile] {
+ const file = new ResultFile(
+ '${baseName}',
+ '${fileType || ''}',
+ \`
+${content}
+ \`,
+ );
+
+ return [${modulePathStr}, file];
+}
+ `;
+
+ const targetFile = path.join(filePath, `${fileName}.ts`);
+ console.log(`=== Create File: ${targetFile}`);
+ fs.writeFileSync(targetFile, templateContent);
+}
+
+function fileDisplay(root, internalPath) {
+ const dirPath = path.join(root, internalPath);
+ const filesList = fs.readdirSync(dirPath);
+ for(let i = 0; i < filesList.length; i++){
+ //描述此文件/文件夹的对象
+ const fileName = filesList[i];
+ //拼接当前文件的路径(上一层路径+当前file的名字)
+ const filePath = path.join(dirPath, fileName);
+ //根据文件路径获取文件信息,返回一个fs.Stats对象
+ const stats = fs.statSync(filePath);
+ if(stats.isDirectory()){
+ //递归调用
+ fileDisplay(root, path.join(internalPath, fileName));
+ }else{
+ createTemplateFile(root, internalPath, fileName);
+ }
+ }
+}
+
+//调用函数遍历根目录,同时传递 文件夹路径和对应的数组
+//请使用同步读取
+fileDisplay(root, '');
+//读取完毕则写入到txt文件中
+// fs.writeFileSync('./data.txt', JSON.stringify(arr));
diff --git a/packages/code-generator/tsconfig.json b/packages/code-generator/tsconfig.json
index eb8638577..7a6244f14 100644
--- a/packages/code-generator/tsconfig.json
+++ b/packages/code-generator/tsconfig.json
@@ -5,6 +5,7 @@
"lib": [
"es6"
],
+ "module": "commonjs",
"types": ["node"],
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
},
diff --git a/packages/editor-skeleton/src/widget/panel.ts b/packages/editor-skeleton/src/widget/panel.ts
index 6f9010dc0..263db6ae3 100644
--- a/packages/editor-skeleton/src/widget/panel.ts
+++ b/packages/editor-skeleton/src/widget/panel.ts
@@ -154,6 +154,9 @@ export default class Panel implements IWidget {
}
this.emitter.emit('activechange', true);
} else if (this.inited) {
+ if (this.parent?.name && this.name.startsWith(this.parent.name)) {
+ this.inited = false;
+ }
this._actived = false;
this.parent?.unactive(this);
this.emitter.emit('activechange', false);