diff --git a/packages/code-generator/src/generator/ProjectBuilder.ts b/packages/code-generator/src/generator/ProjectBuilder.ts index 0538f4b88..26ed4f4d8 100644 --- a/packages/code-generator/src/generator/ProjectBuilder.ts +++ b/packages/code-generator/src/generator/ProjectBuilder.ts @@ -24,8 +24,8 @@ interface IModuleInfo { function getDirFromRoot(root: IResultDir, path: string[]): IResultDir { let current: IResultDir = root; - path.forEach(p => { - const exist = current.dirs.find(d => d.name === p); + path.forEach((p) => { + const exist = current.dirs.find((d) => d.name === p); if (exist) { current = exist; } else { @@ -76,7 +76,7 @@ export class ProjectBuilder implements IProjectBuilder { // components // pages const containerBuildResult: IModuleInfo[] = await Promise.all( - parseResult.containers.map(async containerInfo => { + parseResult.containers.map(async (containerInfo) => { let builder: IModuleBuilder; let path: string[]; if (containerInfo.containerType === 'Page') { @@ -100,9 +100,7 @@ export class ProjectBuilder implements IProjectBuilder { // router if (parseResult.globalRouter && builders.router) { - const { files } = await builders.router.generateModule( - parseResult.globalRouter, - ); + const { files } = await builders.router.generateModule(parseResult.globalRouter); buildResult.push({ path: this.template.slots.router.path, @@ -112,9 +110,7 @@ export class ProjectBuilder implements IProjectBuilder { // entry if (parseResult.project && builders.entry) { - const { files } = await builders.entry.generateModule( - parseResult.project, - ); + const { files } = await builders.entry.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.entry.path, @@ -123,10 +119,8 @@ export class ProjectBuilder implements IProjectBuilder { } // appConfig - if (parseResult.project && builders.appConfig) { - const { files } = await builders.appConfig.generateModule( - parseResult.project, - ); + if (builders.appConfig) { + const { files } = await builders.appConfig.generateModule(parseResult); buildResult.push({ path: this.template.slots.appConfig.path, @@ -135,14 +129,8 @@ export class ProjectBuilder implements IProjectBuilder { } // constants? - if ( - parseResult.project && - builders.constants && - this.template.slots.constants - ) { - const { files } = await builders.constants.generateModule( - parseResult.project, - ); + if (parseResult.project && builders.constants && this.template.slots.constants) { + const { files } = await builders.constants.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.constants.path, @@ -151,14 +139,8 @@ export class ProjectBuilder implements IProjectBuilder { } // utils? - if ( - parseResult.globalUtils && - builders.utils && - this.template.slots.utils - ) { - const { files } = await builders.utils.generateModule( - parseResult.globalUtils, - ); + if (parseResult.globalUtils && builders.utils && this.template.slots.utils) { + const { files } = await builders.utils.generateModule(parseResult.globalUtils); buildResult.push({ path: this.template.slots.utils.path, @@ -168,9 +150,7 @@ export class ProjectBuilder implements IProjectBuilder { // i18n? if (parseResult.globalI18n && builders.i18n && this.template.slots.i18n) { - const { files } = await builders.i18n.generateModule( - parseResult.globalI18n, - ); + const { files } = await builders.i18n.generateModule(parseResult.globalI18n); buildResult.push({ path: this.template.slots.i18n.path, @@ -180,9 +160,7 @@ export class ProjectBuilder implements IProjectBuilder { // globalStyle if (parseResult.project && builders.globalStyle) { - const { files } = await builders.globalStyle.generateModule( - parseResult.project, - ); + const { files } = await builders.globalStyle.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.globalStyle.path, @@ -192,9 +170,7 @@ export class ProjectBuilder implements IProjectBuilder { // htmlEntry if (parseResult.project && builders.htmlEntry) { - const { files } = await builders.htmlEntry.generateModule( - parseResult.project, - ); + const { files } = await builders.htmlEntry.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.htmlEntry.path, @@ -204,9 +180,7 @@ export class ProjectBuilder implements IProjectBuilder { // packageJSON if (parseResult.project && builders.packageJSON) { - const { files } = await builders.packageJSON.generateModule( - parseResult.project, - ); + const { files } = await builders.packageJSON.generateModule(parseResult.project); buildResult.push({ path: this.template.slots.packageJSON.path, @@ -217,14 +191,14 @@ export class ProjectBuilder implements IProjectBuilder { // Post Process // Combine Modules - buildResult.forEach(moduleInfo => { + buildResult.forEach((moduleInfo) => { let targetDir = getDirFromRoot(projectRoot, moduleInfo.path); if (moduleInfo.moduleName) { const dir = new ResultDir(moduleInfo.moduleName); targetDir.addDirectory(dir); targetDir = dir; } - moduleInfo.files.forEach(file => targetDir.addFile(file)); + moduleInfo.files.forEach((file) => targetDir.addFile(file)); }); return projectRoot; @@ -233,7 +207,7 @@ export class ProjectBuilder implements IProjectBuilder { private createModuleBuilders(): Record { const builders: Record = {}; - Object.keys(this.plugins).forEach(pluginName => { + Object.keys(this.plugins).forEach((pluginName) => { if (this.plugins[pluginName].length > 0) { const options: { mainFileName?: string } = {}; if (this.template.slots[pluginName] && this.template.slots[pluginName].fileName) { diff --git a/packages/code-generator/src/parser/SchemaParser.ts b/packages/code-generator/src/parser/SchemaParser.ts index 72e132371..c9b6e16d8 100644 --- a/packages/code-generator/src/parser/SchemaParser.ts +++ b/packages/code-generator/src/parser/SchemaParser.ts @@ -25,6 +25,7 @@ import { IProjectSchema, ISchemaParser, UtilItem, + IRouterInfo, } from '../types'; const defaultContainer: IContainerInfo = { @@ -144,20 +145,21 @@ class SchemaParser implements ISchemaParser { const containersDeps = ([] as IDependency[]).concat(...containers.map((c) => c.deps || [])); // 分析路由配置 - // TODO: 低代码规范里面的路由是咋弄的? - const routes = containers + const routes: IRouterInfo['routes'] = containers .filter((container) => container.containerType === 'Page') .map((page) => { const meta = (page as { meta?: IPageMeta }).meta as IPageMeta; if (meta) { return { path: meta.router, + fileName: page.fileName, componentName: page.moduleName, }; } return { path: '', + fileName: page.fileName, componentName: page.moduleName, }; }); diff --git a/packages/code-generator/src/plugins/project/framework/rax/plugins/appConfig.ts b/packages/code-generator/src/plugins/project/framework/rax/plugins/appConfig.ts index 2d630c407..354e5f93c 100644 --- a/packages/code-generator/src/plugins/project/framework/rax/plugins/appConfig.ts +++ b/packages/code-generator/src/plugins/project/framework/rax/plugins/appConfig.ts @@ -1,3 +1,4 @@ +import changeCase from 'change-case'; import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; import { @@ -6,7 +7,7 @@ import { ChunkType, FileType, ICodeStruct, - IRouterInfo, + IParseResult, } from '../../../../../types'; const pluginFactory: BuilderComponentPluginFactory = () => { @@ -15,23 +16,22 @@ const pluginFactory: BuilderComponentPluginFactory = () => { ...pre, }; - const ir = next.ir as IRouterInfo; + const ir = next.ir as IParseResult; + + const routes = ir.globalRouter?.routes?.map((route) => ({ + path: route.path, + source: `pages/${changeCase.pascalCase(route.fileName)}/index`, + })) || [{ path: '/', source: 'pages/Home/index' }]; - // TODO: 如何生成路由? next.chunks.push({ type: ChunkType.STRING, fileType: FileType.JSON, name: COMMON_CHUNK_NAME.CustomContent, content: ` { - "routes": [ - { - "path": "/", - "source": "pages/Home/index" - } - ], + "routes": ${JSON.stringify(routes, null, 2)}, "window": { - "title": "Rax App Demo" + "title": ${JSON.stringify(ir.project?.meta?.title || ir.project?.meta?.name || '')} } } `, diff --git a/packages/code-generator/src/types/intermediate.ts b/packages/code-generator/src/types/intermediate.ts index c69ace247..42d7fc69a 100644 --- a/packages/code-generator/src/types/intermediate.ts +++ b/packages/code-generator/src/types/intermediate.ts @@ -25,6 +25,7 @@ export interface IUtilInfo extends IWithDependency { export interface IRouterInfo extends IWithDependency { routes: Array<{ path: string; + fileName: string; componentName: string; }>; } diff --git a/packages/code-generator/src/utils/compositeType.ts b/packages/code-generator/src/utils/compositeType.ts index 0993f11c5..d803a1b09 100644 --- a/packages/code-generator/src/utils/compositeType.ts +++ b/packages/code-generator/src/utils/compositeType.ts @@ -108,12 +108,6 @@ export function generateUnknownType(value: CompositeValue, handlers: CustomHandl export function generateCompositeType(value: CompositeValue, handlers: CustomHandlerSet = {}): [boolean, string] { const result = generateUnknownType(value, handlers); - - // TODO:什么场景下会返回这样的字符串?? - 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/utils/nodeToJSX.ts b/packages/code-generator/src/utils/nodeToJSX.ts index 7b5b96c6f..46d992824 100644 --- a/packages/code-generator/src/utils/nodeToJSX.ts +++ b/packages/code-generator/src/utils/nodeToJSX.ts @@ -11,7 +11,7 @@ import { CompositeValue, NodeSchema, } from '../types'; -import { CustomHandlerSet, generateCompositeType } from './compositeType'; +import { CustomHandlerSet, generateCompositeType, generateUnknownType } from './compositeType'; import { generateExpression } from './jsExpression'; // tslint:disable-next-line: no-empty @@ -49,10 +49,18 @@ export function generateAttr( return []; } - const [isString, valueStr] = generateCompositeType(attrValue, customHandlers); + if (typeof attrValue === 'string') { + return [ + { + value: `${attrName}=${JSON.stringify(attrValue)}`, + type: PIECE_TYPE.ATTR, + }, + ]; + } + return [ { - value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`, + value: `${attrName}={${generateUnknownType(attrValue, customHandlers)}}`, type: PIECE_TYPE.ATTR, }, ]; diff --git a/packages/code-generator/test-cases/rax-app/demo1/schema.json5 b/packages/code-generator/test-cases/rax-app/demo1/schema.json5 index 510b70006..1d405aee8 100644 --- a/packages/code-generator/test-cases/rax-app/demo1/schema.json5 +++ b/packages/code-generator/test-cases/rax-app/demo1/schema.json5 @@ -23,6 +23,9 @@ props: {}, lifeCycles: {}, fileName: 'home', + meta: { + router: '/', + }, dataSource: { list: [], }, diff --git a/packages/code-generator/test-cases/rax-app/demo2/schema.json5 b/packages/code-generator/test-cases/rax-app/demo2/schema.json5 index e6ce17b43..5154efdea 100644 --- a/packages/code-generator/test-cases/rax-app/demo2/schema.json5 +++ b/packages/code-generator/test-cases/rax-app/demo2/schema.json5 @@ -35,6 +35,9 @@ { componentName: 'Page', fileName: 'home', + meta: { + router: '/', + }, state: { clickCount: 0, user: { name: '张三', age: 18, avatar: 'https://gw.alicdn.com/tfs/TB1Ui9BMkY2gK0jSZFgXXc5OFXa-50-50.png' }, diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.editorconfig b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.editorconfig new file mode 100644 index 000000000..5760be583 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.editorconfig @@ -0,0 +1,12 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.eslintignore b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.eslintignore new file mode 100644 index 000000000..3b437e614 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.eslintignore @@ -0,0 +1,11 @@ +# 忽略目录 +build/ +tests/ +demo/ + +# node 覆盖率文件 +coverage/ + +# 忽略文件 +**/*-min.js +**/*.min.js diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.eslintrc.js b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.eslintrc.js new file mode 100644 index 000000000..e2a7c5b54 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['rax'], +}; diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.gitignore b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.gitignore new file mode 100644 index 000000000..50a53dace --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/.gitignore @@ -0,0 +1,17 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +*~ +*.swp +*.log + +.DS_Store +.idea/ +.temp/ + +build/ +dist/ +lib/ +coverage/ +node_modules/ + +template.yml diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/README.md b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/README.md new file mode 100644 index 000000000..6eff85d41 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/README.md @@ -0,0 +1,15 @@ +# @ali/rax-component-demo + +## Getting Started + +### `npm run start` + +Runs the app in development mode. + +Open [http://localhost:9999](http://localhost:9999) to view it in the browser. + +The page will reload if you make edits. + +### `npm run build` + +Builds the app for production to the `build` folder. diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/abc.json b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/abc.json new file mode 100644 index 000000000..f9ee40f71 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/abc.json @@ -0,0 +1,7 @@ +{ + "type": "rax", + "builder": "@ali/builder-rax-v1", + "info": { + "raxVersion": "1.x" + } +} diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/build.json b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/build.json new file mode 100644 index 000000000..f3e9b9323 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/build.json @@ -0,0 +1,12 @@ +{ + "inlineStyle": false, + "plugins": [ + [ + "build-plugin-rax-app", + { + "targets": ["web", "miniapp"] + } + ], + "@ali/build-plugin-rax-app-def" + ] +} diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/package.json b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/package.json new file mode 100644 index 000000000..7d41d4764 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/package.json @@ -0,0 +1,35 @@ +{ + "name": "@ali/rax-app-demo", + "private": true, + "version": "1.0.0", + "scripts": { + "build": "rm -f ./dist/miniapp.tar.gz && npm run build:miniapp && cd build/miniapp && tar czf ../../dist/miniapp.tar.gz *", + "build:miniapp": "build-scripts build", + "start": "build-scripts start", + "lint": "eslint --ext .js --ext .jsx ./" + }, + "dependencies": { + "@ali/lowcode-datasource-engine": "^0.1.0", + "universal-env": "^3.2.0", + "rax": "^1.1.0", + "rax-app": "^2.0.0", + "rax-document": "^0.1.0", + "rax-view": "^1.0.0", + "rax-text": "^1.0.0", + "rax-link": "^1.0.0", + "rax-image": "^1.0.0" + }, + "devDependencies": { + "build-plugin-rax-app": "^5.0.0", + "@alib/build-scripts": "^0.1.0", + "@typescript-eslint/eslint-plugin": "^2.11.0", + "@typescript-eslint/parser": "^2.11.0", + "babel-eslint": "^10.0.3", + "eslint": "^6.8.0", + "eslint-config-rax": "^0.1.0", + "eslint-plugin-import": "^2.20.0", + "eslint-plugin-module": "^0.1.0", + "eslint-plugin-react": "^7.18.0", + "@ali/build-plugin-rax-app-def": "^1.0.0" + } +} diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/app.js b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/app.js new file mode 100644 index 000000000..bc474c6e3 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/app.js @@ -0,0 +1,6 @@ +import { runApp } from 'rax-app'; +import appConfig from './app.json'; + +import './global.scss'; + +runApp(appConfig); diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/app.json b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/app.json new file mode 100644 index 000000000..5082c4f9d --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/app.json @@ -0,0 +1,19 @@ +{ + "routes": [ + { + "path": "/", + "source": "pages/Home/index" + }, + { + "path": "/list", + "source": "pages/List/index" + }, + { + "path": "/detail", + "source": "pages/Detail/index" + } + ], + "window": { + "title": "Rax App Demo" + } +} diff --git a/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/document/index.jsx b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/document/index.jsx new file mode 100644 index 000000000..50569a9b6 --- /dev/null +++ b/packages/code-generator/test-cases/rax-app/demo3/expected/demo-project/src/document/index.jsx @@ -0,0 +1,25 @@ +import { createElement } from 'rax'; +import { Root, Style, Script } from 'rax-document'; + +function Document() { + return ( + + + + + Rax App Demo +