From 1cd6561497b53ec36d7e8966654467d3ddcb4d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=A7=E6=AF=85?= Date: Mon, 20 Dec 2021 16:50:32 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E5=BC=80=E6=BA=90=E5=87=BA?= =?UTF-8?q?=E7=A0=81=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/code-generator/.editorconfig | 13 + packages/code-generator/.eslintignore | 16 + packages/code-generator/.eslintrc.js | 8 + packages/code-generator/.gitignore | 110 ++ packages/code-generator/.prettierrc.js | 7 + packages/code-generator/CONTRIBUTING.md | 39 + packages/code-generator/README.md | 21 + packages/code-generator/abc.json | 13 + .../bin/lowcode-code-generator.js | 26 + packages/code-generator/commitlint.config.js | 3 + packages/code-generator/example-schema.json | 276 +++ packages/code-generator/jest.config.js | 9 + packages/code-generator/package.json | 128 ++ .../scripts/build-template-static-files.js | 125 ++ .../code-generator/scripts/fixDefVersion.js | 80 + .../scripts/move-files-to-build-dest.js | 24 + .../src/analyzer/componentAnalyzer.ts | 35 + packages/code-generator/src/cli/index.ts | 1 + packages/code-generator/src/cli/run.ts | 129 ++ packages/code-generator/src/config/env.ts | 3 + packages/code-generator/src/const/file.ts | 3 + .../code-generator/src/const/generator.ts | 129 ++ packages/code-generator/src/const/index.ts | 12 + .../src/generator/ChunkBuilder.ts | 123 ++ .../src/generator/CodeBuilder.ts | 103 + .../src/generator/ModuleBuilder.ts | 109 ++ .../src/generator/ProjectBuilder.ts | 294 +++ packages/code-generator/src/index.ts | 122 ++ .../code-generator/src/parser/SchemaParser.ts | 355 ++++ .../src/plugins/common/esmodule.ts | 435 +++++ .../src/plugins/common/requireUtils.ts | 25 + .../src/plugins/component/rax/commonDeps.ts | 35 + .../src/plugins/component/rax/const.ts | 18 + .../plugins/component/rax/containerClass.ts | 170 ++ .../component/rax/containerInitState.ts | 66 + .../component/rax/containerInjectContext.ts | 134 ++ .../rax/containerInjectDataSourceEngine.ts | 188 ++ .../component/rax/containerInjectUtils.ts | 69 + .../component/rax/containerLifeCycle.ts | 144 ++ .../plugins/component/rax/containerMethods.ts | 84 + .../src/plugins/component/rax/jsx.ts | 399 ++++ .../src/plugins/component/react/const.ts | 9 + .../plugins/component/react/containerClass.ts | 133 ++ .../component/react/containerInitState.ts | 63 + .../react/containerInjectDataSourceEngine.ts | 179 ++ .../component/react/containerInjectI18n.ts | 58 + .../component/react/containerInjectUtils.ts | 93 + .../component/react/containerLifeCycle.ts | 108 ++ .../component/react/containerMethod.ts | 50 + .../src/plugins/component/react/jsx.ts | 95 + .../component/react/reactCommonDeps.ts | 30 + .../src/plugins/component/style/css.ts | 52 + .../src/plugins/project/constants.ts | 59 + .../plugins/project/framework/icejs/index.ts | 17 + .../project/framework/icejs/plugins/entry.ts | 56 + .../framework/icejs/plugins/entryHtml.ts | 46 + .../framework/icejs/plugins/globalStyle.ts | 56 + .../framework/icejs/plugins/packageJSON.ts | 101 + .../project/framework/icejs/plugins/router.ts | 84 + .../icejs/template/files/README.md.ts | 73 + .../icejs/template/files/abc.json.ts | 17 + .../icejs/template/files/build.json.ts | 33 + .../icejs/template/files/editorconfig.ts | 25 + .../icejs/template/files/eslintignore.ts | 28 + .../icejs/template/files/eslintrc.js.ts | 16 + .../icejs/template/files/gitignore.ts | 36 + .../icejs/template/files/jsconfig.json.ts | 24 + .../icejs/template/files/prettierignore.ts | 22 + .../icejs/template/files/prettierrc.js.ts | 16 + .../components/Footer/index.jsx.ts | 25 + .../components/Footer/index.style.ts | 26 + .../BasicLayout/components/Logo/index.jsx.ts | 27 + .../components/Logo/index.style.ts | 31 + .../components/PageNav/index.jsx.ts | 81 + .../src/layouts/BasicLayout/index.jsx.ts | 92 + .../src/layouts/BasicLayout/menuConfig.js.ts | 22 + .../icejs/template/files/stylelintignore.ts | 20 + .../icejs/template/files/stylelintrc.js.ts | 16 + .../icejs/template/files/tsconfig.json.ts | 46 + .../project/framework/icejs/template/index.ts | 52 + .../framework/icejs/template/static-files.ts | 50 + .../plugins/project/framework/rax/index.ts | 19 + .../framework/rax/plugins/appConfig.ts | 50 + .../framework/rax/plugins/buildConfig.ts | 51 + .../project/framework/rax/plugins/entry.ts | 61 + .../framework/rax/plugins/entryDocument.ts | 63 + .../framework/rax/plugins/globalStyle.ts | 64 + .../framework/rax/plugins/packageJSON.ts | 131 ++ .../rax/template/files/.eslintignore.ts | 15 + .../rax/template/files/.eslintrc.js.ts | 16 + .../rax/template/files/.gitignore.ts | 16 + .../rax/template/files/.prettierignore.ts | 15 + .../rax/template/files/.prettierrc.js.ts | 16 + .../rax/template/files/.stylelintignore.ts | 15 + .../rax/template/files/.stylelintrc.js.ts | 16 + .../framework/rax/template/files/README.md.ts | 16 + .../rax/template/files/jsconfig.json.ts | 16 + .../rax/template/files/tsconfig.json.ts | 16 + .../project/framework/rax/template/index.ts | 60 + .../framework/rax/template/static-files.ts | 29 + .../rax/types/RaxFrameworkOptions.ts | 82 + .../src/plugins/project/i18n.ts | 91 + .../src/plugins/project/utils.ts | 155 ++ .../code-generator/src/postprocessor/index.ts | 3 + .../src/postprocessor/prettier/index.ts | 42 + .../src/publisher/disk/index.ts | 72 + .../src/publisher/disk/utils.ts | 78 + .../code-generator/src/publisher/zip/index.ts | 66 + .../code-generator/src/publisher/zip/utils.ts | 64 + .../code-generator/src/solutions/icejs.ts | 99 + .../code-generator/src/solutions/rax-app.ts | 82 + packages/code-generator/src/types/analyze.ts | 7 + packages/code-generator/src/types/core.ts | 192 ++ packages/code-generator/src/types/deps.ts | 38 + packages/code-generator/src/types/error.ts | 17 + packages/code-generator/src/types/index.ts | 7 + .../code-generator/src/types/intermediate.ts | 68 + packages/code-generator/src/types/jsx.ts | 29 + .../code-generator/src/types/publisher.ts | 17 + .../code-generator/src/utils/OrderedSet.ts | 33 + packages/code-generator/src/utils/Scope.ts | 30 + .../code-generator/src/utils/ScopeBindings.ts | 56 + .../code-generator/src/utils/aopHelper.ts | 27 + packages/code-generator/src/utils/common.ts | 41 + .../code-generator/src/utils/compositeType.ts | 222 +++ packages/code-generator/src/utils/debug.ts | 3 + .../src/utils/encodeJsxAttrString.ts | 18 + packages/code-generator/src/utils/errors.ts | 26 + .../src/utils/expressionParser.ts | 382 ++++ .../code-generator/src/utils/jsExpression.ts | 134 ++ packages/code-generator/src/utils/jsSlot.ts | 65 + .../code-generator/src/utils/jsxHelpers.ts | 11 + .../code-generator/src/utils/nodeToJSX.ts | 391 ++++ .../code-generator/src/utils/resultHelper.ts | 35 + packages/code-generator/src/utils/schema.ts | 140 ++ .../src/utils/templateHelper.ts | 30 + packages/code-generator/src/utils/validate.ts | 10 + packages/code-generator/src/utils/version.ts | 29 + .../static-files/rax/.eslintignore.template | 8 + .../static-files/rax/.eslintrc.js.template | 15 + .../static-files/rax/.gitignore.template | 18 + .../static-files/rax/.prettierignore.template | 8 + .../static-files/rax/.prettierrc.js.template | 3 + .../rax/.stylelintignore.template | 8 + .../static-files/rax/.stylelintrc.js.template | 3 + .../static-files/rax/README.md.template | 15 + .../static-files/rax/jsconfig.json.template | 10 + .../static-files/rax/tsconfig.json.template | 33 + packages/code-generator/test-cases/.gitignore | 1 + .../expected/demo-project/.eslintignore | 8 + .../demo01/expected/demo-project/.eslintrc.js | 15 + .../demo01/expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../demo01/expected/demo-project/README.md | 15 + .../demo01/expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../demo01/expected/demo-project/package.json | 33 + .../demo01/expected/demo-project/src/app.js | 9 + .../demo01/expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../demo01/expected/demo-project/src/i18n.js | 31 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 151 ++ .../demo01/expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../test-cases/rax-app/demo01/schema.json5 | 55 + .../expected/demo-project/.eslintignore | 8 + .../demo02/expected/demo-project/.eslintrc.js | 15 + .../demo02/expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../demo02/expected/demo-project/README.md | 15 + .../demo02/expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../demo02/expected/demo-project/package.json | 37 + .../demo02/expected/demo-project/src/app.js | 9 + .../demo02/expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 9 + .../demo02/expected/demo-project/src/i18n.js | 31 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 358 ++++ .../demo02/expected/demo-project/src/utils.js | 70 + .../expected/demo-project/tsconfig.json | 33 + .../test-cases/rax-app/demo02/schema.json5 | 375 ++++ .../expected/demo-project/.eslintignore | 8 + .../demo03/expected/demo-project/.eslintrc.js | 15 + .../demo03/expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../demo03/expected/demo-project/README.md | 15 + .../demo03/expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../demo03/expected/demo-project/package.json | 34 + .../demo03/expected/demo-project/src/app.js | 9 + .../demo03/expected/demo-project/src/app.json | 19 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 9 + .../demo03/expected/demo-project/src/i18n.js | 31 + .../demo-project/src/pages/Detail/index.css | 0 .../demo-project/src/pages/Detail/index.jsx | 160 ++ .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 160 ++ .../demo-project/src/pages/List/index.css | 0 .../demo-project/src/pages/List/index.jsx | 163 ++ .../demo03/expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../test-cases/rax-app/demo03/schema.json5 | 176 ++ .../test-cases/rax-app/demo04/README.md | 1 + .../expected/demo-project/.eslintignore | 8 + .../demo04/expected/demo-project/.eslintrc.js | 15 + .../demo04/expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../demo04/expected/demo-project/README.md | 15 + .../demo04/expected/demo-project/build.json | 8 + .../expected/demo-project/jsconfig.json | 10 + .../demo04/expected/demo-project/package.json | 34 + .../demo04/expected/demo-project/src/app.js | 9 + .../demo04/expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 9 + .../demo04/expected/demo-project/src/i18n.js | 31 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 155 ++ .../demo04/expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../test-cases/rax-app/demo04/schema.json5 | 85 + .../expected/demo-project/.eslintignore | 8 + .../demo05/expected/demo-project/.eslintrc.js | 15 + .../demo05/expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../demo05/expected/demo-project/README.md | 15 + .../demo05/expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../demo05/expected/demo-project/package.json | 33 + .../demo05/expected/demo-project/src/app.js | 9 + .../demo05/expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../demo05/expected/demo-project/src/i18n.js | 38 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 157 ++ .../demo05/expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../test-cases/rax-app/demo05/schema.json5 | 73 + .../expected/demo-project/.eslintignore | 8 + .../expected/demo-project/.eslintrc.js | 15 + .../expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../expected/demo-project/README.md | 15 + .../expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../expected/demo-project/package.json | 34 + .../expected/demo-project/src/app.js | 9 + .../expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../expected/demo-project/src/i18n.js | 38 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 163 ++ .../expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../rax-app/demo06-jsslot/schema.json5 | 84 + .../expected/demo-project/.eslintignore | 8 + .../expected/demo-project/.eslintrc.js | 15 + .../expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../expected/demo-project/README.md | 15 + .../expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../expected/demo-project/package.json | 33 + .../expected/demo-project/src/app.js | 9 + .../expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../expected/demo-project/src/i18n.js | 38 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 157 ++ .../expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../demo07-newline-in-props/schema.json5 | 78 + .../expected/demo-project/.eslintignore | 8 + .../expected/demo-project/.eslintrc.js | 15 + .../expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../expected/demo-project/README.md | 15 + .../expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../expected/demo-project/package.json | 34 + .../expected/demo-project/src/app.js | 9 + .../expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../expected/demo-project/src/i18n.js | 38 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 163 ++ .../expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../schema.json5 | 90 + .../expected/demo-project/.eslintignore | 8 + .../expected/demo-project/.eslintrc.js | 15 + .../expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../expected/demo-project/README.md | 15 + .../expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../expected/demo-project/package.json | 34 + .../expected/demo-project/src/app.js | 9 + .../expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../expected/demo-project/src/i18n.js | 38 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 166 ++ .../expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../schema.json5 | 94 + .../expected/demo-project/.eslintignore | 8 + .../expected/demo-project/.eslintrc.js | 15 + .../expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../expected/demo-project/README.md | 15 + .../expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../expected/demo-project/package.json | 34 + .../expected/demo-project/src/app.js | 9 + .../expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../expected/demo-project/src/i18n.js | 38 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 168 ++ .../expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../schema.json5 | 89 + .../expected/demo-project/.eslintignore | 8 + .../expected/demo-project/.eslintrc.js | 15 + .../expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../expected/demo-project/README.md | 15 + .../expected/demo-project/build.json | 8 + .../expected/demo-project/jsconfig.json | 10 + .../expected/demo-project/package.json | 36 + .../expected/demo-project/src/app.js | 9 + .../expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../expected/demo-project/src/i18n.js | 31 + .../demo-project/src/pages/Aaaa/index.css | 0 .../demo-project/src/pages/Aaaa/index.jsx | 180 ++ .../expected/demo-project/src/utils.js | 61 + .../expected/demo-project/tsconfig.json | 33 + .../demo11-utils-name-alias/schema.json5 | 208 ++ .../expected/demo-project/.eslintignore | 8 + .../expected/demo-project/.eslintrc.js | 15 + .../expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../expected/demo-project/README.md | 15 + .../expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../expected/demo-project/package.json | 33 + .../expected/demo-project/src/app.js | 9 + .../expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../expected/demo-project/src/i18n.js | 38 + .../demo-project/src/pages/Home/index.css | 0 .../demo-project/src/pages/Home/index.jsx | 171 ++ .../expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../rax-app/demo12-refs/schema.json5 | 74 + .../expected/demo-project/.eslintignore | 8 + .../expected/demo-project/.eslintrc.js | 15 + .../expected/demo-project/.gitignore | 18 + .../expected/demo-project/.prettierignore | 8 + .../expected/demo-project/.prettierrc.js | 3 + .../expected/demo-project/.stylelintignore | 8 + .../expected/demo-project/.stylelintrc.js | 3 + .../expected/demo-project/README.md | 15 + .../expected/demo-project/build.json | 5 + .../expected/demo-project/jsconfig.json | 10 + .../expected/demo-project/package.json | 32 + .../expected/demo-project/src/app.js | 9 + .../expected/demo-project/src/app.json | 11 + .../expected/demo-project/src/constants.js | 3 + .../demo-project/src/document/index.jsx | 25 + .../expected/demo-project/src/global.css | 3 + .../expected/demo-project/src/i18n.js | 31 + .../demo-project/src/pages/Example/index.css | 0 .../demo-project/src/pages/Example/index.jsx | 182 ++ .../expected/demo-project/src/utils.js | 45 + .../expected/demo-project/tsconfig.json | 33 + .../demo13-datasource-prop/schema.json5 | 65 + .../demo1/expected/demo-project/.editorconfig | 14 + .../demo1/expected/demo-project/.eslintignore | 17 + .../demo1/expected/demo-project/.eslintrc.js | 5 + .../demo1/expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../demo1/expected/demo-project/README.md | 62 + .../demo1/expected/demo-project/abc.json | 6 + .../demo1/expected/demo-project/build.json | 22 + .../demo1/expected/demo-project/jsconfig.json | 13 + .../demo1/expected/demo-project/package.json | 43 + .../expected/demo-project/public/index.html | 12 + .../demo1/expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 13 + .../demo1/expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 172 ++ .../demo1/expected/demo-project/src/routes.js | 18 + .../demo1/expected/demo-project/src/utils.js | 47 + .../demo1/expected/demo-project/tsconfig.json | 35 + .../test-cases/react-app/demo1/schema.json5 | 276 +++ .../expected/demo-project/.editorconfig | 14 + .../expected/demo-project/.eslintignore | 17 + .../expected/demo-project/.eslintrc.js | 5 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../expected/demo-project/README.md | 62 + .../expected/demo-project/abc.json | 6 + .../expected/demo-project/build.json | 22 + .../expected/demo-project/jsconfig.json | 13 + .../expected/demo-project/package.json | 47 + .../expected/demo-project/public/index.html | 12 + .../expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Aaaa/index.css | 0 .../demo-project/src/pages/Aaaa/index.jsx | 89 + .../expected/demo-project/src/routes.js | 18 + .../expected/demo-project/src/utils.js | 61 + .../expected/demo-project/tsconfig.json | 35 + .../demo2-utils-name-alias/schema.json5 | 195 ++ .../demo2/expected/demo-project/.editorconfig | 14 + .../demo2/expected/demo-project/.eslintignore | 17 + .../demo2/expected/demo-project/.eslintrc.js | 5 + .../demo2/expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../demo2/expected/demo-project/README.md | 62 + .../demo2/expected/demo-project/abc.json | 6 + .../demo2/expected/demo-project/build.json | 22 + .../demo2/expected/demo-project/jsconfig.json | 13 + .../demo2/expected/demo-project/package.json | 43 + .../expected/demo-project/public/index.html | 12 + .../demo2/expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 13 + .../demo2/expected/demo-project/src/i18n.js | 42 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 94 + .../demo2/expected/demo-project/src/routes.js | 18 + .../demo2/expected/demo-project/src/utils.js | 47 + .../demo2/expected/demo-project/tsconfig.json | 35 + .../test-cases/react-app/demo2/schema.json5 | 256 +++ .../demo3/expected/demo-project/.editorconfig | 14 + .../demo3/expected/demo-project/.eslintignore | 17 + .../demo3/expected/demo-project/.eslintrc.js | 5 + .../demo3/expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../demo3/expected/demo-project/README.md | 62 + .../demo3/expected/demo-project/abc.json | 6 + .../demo3/expected/demo-project/build.json | 22 + .../demo3/expected/demo-project/jsconfig.json | 13 + .../demo3/expected/demo-project/package.json | 43 + .../expected/demo-project/public/index.html | 12 + .../demo3/expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 13 + .../demo3/expected/demo-project/src/i18n.js | 42 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 64 + .../demo3/expected/demo-project/src/routes.js | 18 + .../demo3/expected/demo-project/src/utils.js | 47 + .../demo3/expected/demo-project/tsconfig.json | 35 + .../test-cases/react-app/demo3/schema.json5 | 159 ++ .../demo4/expected/demo-project/.editorconfig | 14 + .../demo4/expected/demo-project/.eslintignore | 17 + .../demo4/expected/demo-project/.eslintrc.js | 5 + .../demo4/expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../demo4/expected/demo-project/README.md | 62 + .../demo4/expected/demo-project/abc.json | 6 + .../demo4/expected/demo-project/build.json | 22 + .../demo4/expected/demo-project/jsconfig.json | 13 + .../demo4/expected/demo-project/package.json | 44 + .../expected/demo-project/public/index.html | 12 + .../demo4/expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 6 + .../demo4/expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 267 +++ .../demo4/expected/demo-project/src/routes.js | 18 + .../demo4/expected/demo-project/src/utils.js | 47 + .../demo4/expected/demo-project/tsconfig.json | 35 + .../test-cases/react-app/demo4/schema.json5 | 353 ++++ .../demo5/expected/demo-project/.editorconfig | 14 + .../demo5/expected/demo-project/.eslintignore | 17 + .../demo5/expected/demo-project/.eslintrc.js | 5 + .../demo5/expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../demo5/expected/demo-project/README.md | 62 + .../demo5/expected/demo-project/abc.json | 6 + .../demo5/expected/demo-project/build.json | 22 + .../demo5/expected/demo-project/jsconfig.json | 13 + .../demo5/expected/demo-project/package.json | 46 + .../expected/demo-project/public/index.html | 12 + .../demo5/expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 6 + .../demo5/expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 460 +++++ .../demo5/expected/demo-project/src/routes.js | 18 + .../demo5/expected/demo-project/src/utils.js | 47 + .../demo5/expected/demo-project/tsconfig.json | 35 + .../test-cases/react-app/demo5/schema.json5 | 679 +++++++ .../expected/demo-project/.editorconfig | 14 + .../expected/demo-project/.eslintignore | 17 + .../expected/demo-project/.eslintrc.js | 5 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../expected/demo-project/README.md | 62 + .../expected/demo-project/abc.json | 6 + .../expected/demo-project/build.json | 22 + .../expected/demo-project/jsconfig.json | 13 + .../expected/demo-project/package.json | 43 + .../expected/demo-project/public/index.html | 12 + .../expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 13 + .../expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 172 ++ .../expected/demo-project/src/routes.js | 18 + .../expected/demo-project/src/utils.js | 47 + .../expected/demo-project/tsconfig.json | 35 + .../demo6-literal-condition/schema.json5 | 273 +++ .../expected/demo-project/.editorconfig | 14 + .../expected/demo-project/.eslintignore | 17 + .../expected/demo-project/.eslintrc.js | 5 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../expected/demo-project/README.md | 62 + .../expected/demo-project/abc.json | 6 + .../expected/demo-project/build.json | 22 + .../expected/demo-project/jsconfig.json | 13 + .../expected/demo-project/package.json | 45 + .../expected/demo-project/public/index.html | 12 + .../expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 1291 +++++++++++++ .../expected/demo-project/src/routes.js | 18 + .../expected/demo-project/src/utils.js | 47 + .../expected/demo-project/tsconfig.json | 35 + .../demo7-literal-condition2/schema.json5 | 1703 +++++++++++++++++ .../expected/demo-project/.editorconfig | 14 + .../expected/demo-project/.eslintignore | 17 + .../expected/demo-project/.eslintrc.js | 5 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../expected/demo-project/README.md | 62 + .../expected/demo-project/abc.json | 6 + .../expected/demo-project/build.json | 22 + .../expected/demo-project/jsconfig.json | 13 + .../expected/demo-project/package.json | 43 + .../expected/demo-project/public/index.html | 12 + .../expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Example/index.css | 0 .../demo-project/src/pages/Example/index.jsx | 87 + .../expected/demo-project/src/routes.js | 18 + .../expected/demo-project/src/utils.js | 47 + .../expected/demo-project/tsconfig.json | 35 + .../demo8-datasource-prop/schema.json5 | 65 + .../expected/demo-project/.editorconfig | 14 + .../expected/demo-project/.eslintignore | 17 + .../expected/demo-project/.eslintrc.js | 5 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../expected/demo-project/README.md | 62 + .../expected/demo-project/abc.json | 6 + .../expected/demo-project/build.json | 22 + .../expected/demo-project/jsconfig.json | 13 + .../expected/demo-project/package.json | 43 + .../expected/demo-project/public/index.html | 12 + .../expected/demo-project/src/app.js | 11 + .../src/components/Index/index.css | 0 .../src/components/Index/index.jsx | 96 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../expected/demo-project/src/routes.js | 11 + .../expected/demo-project/src/utils.js | 47 + .../expected/demo-project/tsconfig.json | 35 + .../demo9-datasource-engine/schema.json5 | 59 + .../expected/demo-project/.editorconfig | 14 + .../expected/demo-project/.eslintignore | 17 + .../expected/demo-project/.eslintrc.js | 5 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../expected/demo-project/README.md | 62 + .../expected/demo-project/abc.json | 6 + .../expected/demo-project/build.json | 22 + .../expected/demo-project/jsconfig.json | 13 + .../expected/demo-project/package.json | 46 + .../expected/demo-project/public/index.html | 12 + .../expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 959 ++++++++++ .../expected/demo-project/src/routes.js | 18 + .../expected/demo-project/src/utils.js | 47 + .../expected/demo-project/tsconfig.json | 35 + .../react-app/demo_10-jsslot/schema.json5 | 1206 ++++++++++++ .../expected/demo-project/.editorconfig | 14 + .../expected/demo-project/.eslintignore | 17 + .../expected/demo-project/.eslintrc.js | 5 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../expected/demo-project/README.md | 62 + .../expected/demo-project/abc.json | 6 + .../expected/demo-project/build.json | 22 + .../expected/demo-project/jsconfig.json | 13 + .../expected/demo-project/package.json | 46 + .../expected/demo-project/public/index.html | 12 + .../expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 1222 ++++++++++++ .../expected/demo-project/src/routes.js | 18 + .../expected/demo-project/src/utils.js | 47 + .../expected/demo-project/tsconfig.json | 35 + .../react-app/demo_11-jsslot-2/schema.json5 | 1457 ++++++++++++++ .../demo1/expected/demo-project/.editorconfig | 14 + .../demo1/expected/demo-project/.eslintignore | 17 + .../demo1/expected/demo-project/.eslintrc.js | 5 + .../demo1/expected/demo-project/.gitignore | 25 + .../expected/demo-project/.prettierignore | 11 + .../expected/demo-project/.prettierrc.js | 5 + .../expected/demo-project/.stylelintignore | 9 + .../expected/demo-project/.stylelintrc.js | 5 + .../demo1/expected/demo-project/README.md | 62 + .../demo1/expected/demo-project/abc.json | 6 + .../demo1/expected/demo-project/build.json | 22 + .../demo1/expected/demo-project/jsconfig.json | 13 + .../demo1/expected/demo-project/package.json | 37 + .../expected/demo-project/public/index.html | 12 + .../demo1/expected/demo-project/src/app.js | 11 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/global.scss | 13 + .../demo1/expected/demo-project/src/i18n.js | 33 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 70 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 79 + .../demo1/expected/demo-project/src/routes.js | 18 + .../demo1/expected/demo-project/src/utils.js | 47 + .../demo1/expected/demo-project/tsconfig.json | 35 + .../react-module/demo1/schema.json5 | 296 +++ .../code-generator/tests/bugfix/.gitignore | 1 + .../tests/bugfix/page-element1.schema.json | 844 ++++++++ .../tests/bugfix/page-element1.test.ts | 79 + .../tests/bugfix/page-element2.schema.json | 844 ++++++++ .../tests/bugfix/page-element2.test.ts | 79 + packages/code-generator/tests/cli.test.ts | 35 + .../tests/helpers/solutionHelper.ts | 106 + .../__snapshots__/requireUtils.test.ts.snap | 18 + .../tests/plugins/common/requireUtils.test.ts | 17 + .../p0-condition-at-root.test.ts.snap | 207 ++ .../plugins/jsx/p0-condition-at-root.test.ts | 86 + .../__snapshots__/prettier.test.ts.snap | 39 + .../tests/postprocessor/prettier.test.ts | 39 + .../code-generator/tests/public/README.md | 1 + .../__snapshots__/p0-basic.test.ts.snap | 178 ++ .../SchemaParser/data/schema-with-slot.json | 1457 ++++++++++++++ .../public/SchemaParser/p0-basic.test.ts | 13 + .../tests/public/publisher/disk/disk.test.ts | 48 + .../tests/public/publisher/zip/zip.test.ts | 44 + .../tests/public/solutions/rax-app.test.ts | 64 + .../tests/public/solutions/react-app.test.ts | 63 + .../code-generator/tests/types/errors.test.ts | 41 + .../tests/utils/compositeType.test.ts | 18 + .../code-generator/tests/utils/errors.test.ts | 27 + ...parseExpressionConvertThis2Context.test.ts | 95 + .../parseExpressionGetGlobalVariables.test.ts | 134 ++ .../utils/schema/data/schema-with-slot.json | 1457 ++++++++++++++ .../tests/utils/schema/handleSubNodes.test.ts | 92 + .../tests/utils/validate.test.ts | 20 + .../tests/utils/version.test.ts | 33 + packages/code-generator/tsconfig.json | 37 + 874 files changed, 44434 insertions(+) create mode 100644 packages/code-generator/.editorconfig create mode 100644 packages/code-generator/.eslintignore create mode 100644 packages/code-generator/.eslintrc.js create mode 100644 packages/code-generator/.gitignore create mode 100644 packages/code-generator/.prettierrc.js create mode 100644 packages/code-generator/CONTRIBUTING.md create mode 100644 packages/code-generator/README.md create mode 100644 packages/code-generator/abc.json create mode 100755 packages/code-generator/bin/lowcode-code-generator.js create mode 100644 packages/code-generator/commitlint.config.js create mode 100644 packages/code-generator/example-schema.json create mode 100644 packages/code-generator/jest.config.js create mode 100644 packages/code-generator/package.json create mode 100644 packages/code-generator/scripts/build-template-static-files.js create mode 100644 packages/code-generator/scripts/fixDefVersion.js create mode 100644 packages/code-generator/scripts/move-files-to-build-dest.js create mode 100644 packages/code-generator/src/analyzer/componentAnalyzer.ts create mode 100644 packages/code-generator/src/cli/index.ts create mode 100644 packages/code-generator/src/cli/run.ts create mode 100644 packages/code-generator/src/config/env.ts create mode 100644 packages/code-generator/src/const/file.ts create mode 100644 packages/code-generator/src/const/generator.ts create mode 100644 packages/code-generator/src/const/index.ts create mode 100644 packages/code-generator/src/generator/ChunkBuilder.ts create mode 100644 packages/code-generator/src/generator/CodeBuilder.ts create mode 100644 packages/code-generator/src/generator/ModuleBuilder.ts create mode 100644 packages/code-generator/src/generator/ProjectBuilder.ts create mode 100644 packages/code-generator/src/index.ts create mode 100644 packages/code-generator/src/parser/SchemaParser.ts create mode 100644 packages/code-generator/src/plugins/common/esmodule.ts create mode 100644 packages/code-generator/src/plugins/common/requireUtils.ts create mode 100644 packages/code-generator/src/plugins/component/rax/commonDeps.ts create mode 100644 packages/code-generator/src/plugins/component/rax/const.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerClass.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerInitState.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerInjectContext.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerInjectUtils.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerMethods.ts create mode 100644 packages/code-generator/src/plugins/component/rax/jsx.ts create mode 100644 packages/code-generator/src/plugins/component/react/const.ts create mode 100644 packages/code-generator/src/plugins/component/react/containerClass.ts create mode 100644 packages/code-generator/src/plugins/component/react/containerInitState.ts create mode 100644 packages/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts create mode 100644 packages/code-generator/src/plugins/component/react/containerInjectI18n.ts create mode 100644 packages/code-generator/src/plugins/component/react/containerInjectUtils.ts create mode 100644 packages/code-generator/src/plugins/component/react/containerLifeCycle.ts create mode 100644 packages/code-generator/src/plugins/component/react/containerMethod.ts create mode 100644 packages/code-generator/src/plugins/component/react/jsx.ts create mode 100644 packages/code-generator/src/plugins/component/react/reactCommonDeps.ts create mode 100644 packages/code-generator/src/plugins/component/style/css.ts create mode 100644 packages/code-generator/src/plugins/project/constants.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/index.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/menuConfig.js.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/stylelintignore.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/stylelintrc.js.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/files/tsconfig.json.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/index.ts create mode 100644 packages/code-generator/src/plugins/project/framework/icejs/template/static-files.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/index.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/plugins/appConfig.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/plugins/buildConfig.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/plugins/entry.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/plugins/entryDocument.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/plugins/globalStyle.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/plugins/packageJSON.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/.eslintignore.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/.eslintrc.js.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/.gitignore.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/.prettierignore.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/.prettierrc.js.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/.stylelintignore.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/.stylelintrc.js.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/README.md.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/jsconfig.json.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/files/tsconfig.json.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/index.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/template/static-files.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/types/RaxFrameworkOptions.ts create mode 100644 packages/code-generator/src/plugins/project/i18n.ts create mode 100644 packages/code-generator/src/plugins/project/utils.ts create mode 100644 packages/code-generator/src/postprocessor/index.ts create mode 100644 packages/code-generator/src/postprocessor/prettier/index.ts create mode 100644 packages/code-generator/src/publisher/disk/index.ts create mode 100644 packages/code-generator/src/publisher/disk/utils.ts create mode 100644 packages/code-generator/src/publisher/zip/index.ts create mode 100644 packages/code-generator/src/publisher/zip/utils.ts create mode 100644 packages/code-generator/src/solutions/icejs.ts create mode 100644 packages/code-generator/src/solutions/rax-app.ts create mode 100644 packages/code-generator/src/types/analyze.ts create mode 100644 packages/code-generator/src/types/core.ts create mode 100644 packages/code-generator/src/types/deps.ts create mode 100644 packages/code-generator/src/types/error.ts create mode 100644 packages/code-generator/src/types/index.ts create mode 100644 packages/code-generator/src/types/intermediate.ts create mode 100644 packages/code-generator/src/types/jsx.ts create mode 100644 packages/code-generator/src/types/publisher.ts create mode 100644 packages/code-generator/src/utils/OrderedSet.ts create mode 100644 packages/code-generator/src/utils/Scope.ts create mode 100644 packages/code-generator/src/utils/ScopeBindings.ts create mode 100644 packages/code-generator/src/utils/aopHelper.ts create mode 100644 packages/code-generator/src/utils/common.ts create mode 100644 packages/code-generator/src/utils/compositeType.ts create mode 100644 packages/code-generator/src/utils/debug.ts create mode 100644 packages/code-generator/src/utils/encodeJsxAttrString.ts create mode 100644 packages/code-generator/src/utils/errors.ts create mode 100644 packages/code-generator/src/utils/expressionParser.ts create mode 100644 packages/code-generator/src/utils/jsExpression.ts create mode 100644 packages/code-generator/src/utils/jsSlot.ts create mode 100644 packages/code-generator/src/utils/jsxHelpers.ts create mode 100644 packages/code-generator/src/utils/nodeToJSX.ts create mode 100644 packages/code-generator/src/utils/resultHelper.ts create mode 100644 packages/code-generator/src/utils/schema.ts create mode 100644 packages/code-generator/src/utils/templateHelper.ts create mode 100644 packages/code-generator/src/utils/validate.ts create mode 100644 packages/code-generator/src/utils/version.ts create mode 100644 packages/code-generator/static-files/rax/.eslintignore.template create mode 100644 packages/code-generator/static-files/rax/.eslintrc.js.template create mode 100644 packages/code-generator/static-files/rax/.gitignore.template create mode 100644 packages/code-generator/static-files/rax/.prettierignore.template create mode 100644 packages/code-generator/static-files/rax/.prettierrc.js.template create mode 100644 packages/code-generator/static-files/rax/.stylelintignore.template create mode 100644 packages/code-generator/static-files/rax/.stylelintrc.js.template create mode 100644 packages/code-generator/static-files/rax/README.md.template create mode 100644 packages/code-generator/static-files/rax/jsconfig.json.template create mode 100644 packages/code-generator/static-files/rax/tsconfig.json.template create mode 100644 packages/code-generator/test-cases/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo01/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo01/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo02/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo02/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/pages/Detail/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/pages/Detail/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/pages/List/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/pages/List/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo03/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo03/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo04/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo04/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo04/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo05/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo05/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo06-jsslot/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo07-newline-in-props/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo08-jsslot-with-multiple-children/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo09-jsslot-with-conditional-children/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo10-jsslot-with-loop-children/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo11-utils-name-alias/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/pages/Home/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/pages/Home/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo12-refs/schema.json5 create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/app.json create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/document/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/global.css create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/pages/Example/index.css create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/pages/Example/index.jsx create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/rax-app/demo13-datasource-prop/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo1/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo1/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo2-utils-name-alias/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo2/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo2/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo3/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo3/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo4/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo4/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo5/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo5/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo6-literal-condition/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo7-literal-condition2/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo8-datasource-prop/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/components/Index/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/components/Index/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo9-datasource-engine/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo_10-jsslot/schema.json5 create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-app/demo_11-jsslot-2/schema.json5 create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/.editorconfig create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/.eslintignore create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/.eslintrc.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/.gitignore create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/.prettierignore create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/.prettierrc.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/.stylelintignore create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/.stylelintrc.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/README.md create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/abc.json create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/build.json create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/jsconfig.json create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/package.json create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/public/index.html create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/app.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/constants.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/global.scss create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/i18n.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/pages/Test/index.css create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/pages/Test/index.jsx create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/routes.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/src/utils.js create mode 100644 packages/code-generator/test-cases/react-module/demo1/expected/demo-project/tsconfig.json create mode 100644 packages/code-generator/test-cases/react-module/demo1/schema.json5 create mode 100644 packages/code-generator/tests/bugfix/.gitignore create mode 100644 packages/code-generator/tests/bugfix/page-element1.schema.json create mode 100644 packages/code-generator/tests/bugfix/page-element1.test.ts create mode 100644 packages/code-generator/tests/bugfix/page-element2.schema.json create mode 100644 packages/code-generator/tests/bugfix/page-element2.test.ts create mode 100644 packages/code-generator/tests/cli.test.ts create mode 100644 packages/code-generator/tests/helpers/solutionHelper.ts create mode 100644 packages/code-generator/tests/plugins/common/__snapshots__/requireUtils.test.ts.snap create mode 100644 packages/code-generator/tests/plugins/common/requireUtils.test.ts create mode 100644 packages/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap create mode 100644 packages/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts create mode 100644 packages/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap create mode 100644 packages/code-generator/tests/postprocessor/prettier.test.ts create mode 100644 packages/code-generator/tests/public/README.md create mode 100644 packages/code-generator/tests/public/SchemaParser/__snapshots__/p0-basic.test.ts.snap create mode 100644 packages/code-generator/tests/public/SchemaParser/data/schema-with-slot.json create mode 100644 packages/code-generator/tests/public/SchemaParser/p0-basic.test.ts create mode 100644 packages/code-generator/tests/public/publisher/disk/disk.test.ts create mode 100644 packages/code-generator/tests/public/publisher/zip/zip.test.ts create mode 100644 packages/code-generator/tests/public/solutions/rax-app.test.ts create mode 100644 packages/code-generator/tests/public/solutions/react-app.test.ts create mode 100644 packages/code-generator/tests/types/errors.test.ts create mode 100644 packages/code-generator/tests/utils/compositeType.test.ts create mode 100644 packages/code-generator/tests/utils/errors.test.ts create mode 100644 packages/code-generator/tests/utils/expressionParser/parseExpressionConvertThis2Context.test.ts create mode 100644 packages/code-generator/tests/utils/expressionParser/parseExpressionGetGlobalVariables.test.ts create mode 100644 packages/code-generator/tests/utils/schema/data/schema-with-slot.json create mode 100644 packages/code-generator/tests/utils/schema/handleSubNodes.test.ts create mode 100644 packages/code-generator/tests/utils/validate.test.ts create mode 100644 packages/code-generator/tests/utils/version.test.ts create mode 100644 packages/code-generator/tsconfig.json diff --git a/packages/code-generator/.editorconfig b/packages/code-generator/.editorconfig new file mode 100644 index 000000000..319299684 --- /dev/null +++ b/packages/code-generator/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +quote_type = single + +[*.md] +trim_trailing_whitespace = false diff --git a/packages/code-generator/.eslintignore b/packages/code-generator/.eslintignore new file mode 100644 index 000000000..b6fe41870 --- /dev/null +++ b/packages/code-generator/.eslintignore @@ -0,0 +1,16 @@ +# 忽略目录 +node_modules/ +build/ +dist/ +test-cases/ +test/ +tests/ +output/ +es/ +lib/ +coverage/ + +# 忽略文件 +**/*.min.js +**/*-min.js +**/*.bundle.js diff --git a/packages/code-generator/.eslintrc.js b/packages/code-generator/.eslintrc.js new file mode 100644 index 000000000..8def4f39d --- /dev/null +++ b/packages/code-generator/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + extends: 'eslint-config-ali/typescript/react', + rules: { + 'max-len': ['error', { code: 200 }], + 'function-paren-newline': 'off', + '@typescript-eslint/indent': 'off', + }, +}; diff --git a/packages/code-generator/.gitignore b/packages/code-generator/.gitignore new file mode 100644 index 000000000..9a1713b09 --- /dev/null +++ b/packages/code-generator/.gitignore @@ -0,0 +1,110 @@ +# project custom +build +es +dist +output +package-lock.json +yarn.lock +deploy-space/packages +deploy-space/.env +/demo/ +/demo-output*/ +/generated/ + +# IDE +.vscode +.idea + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release +lib + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# mac config files +.DS_Store + +# codealike +codealike.json +.node + +# def publish +.package diff --git a/packages/code-generator/.prettierrc.js b/packages/code-generator/.prettierrc.js new file mode 100644 index 000000000..24c5859e6 --- /dev/null +++ b/packages/code-generator/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + printWidth: 100, + tabWidth: 2, + semi: true, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/packages/code-generator/CONTRIBUTING.md b/packages/code-generator/CONTRIBUTING.md new file mode 100644 index 000000000..efab0a574 --- /dev/null +++ b/packages/code-generator/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# 如何共建 + +1. 拉取最新代码,切换到 develop 分支,基于 develop 分支切出一个 feature 或 hotfix 分支 +2. 安装依赖(`yarn`),然后先跑一遍 `yarn test` 看看是否所有用例都能通过 +3. 在 tests 目录下编写您的需求/问题的测试用例 +4. 修改 src 下的一些代码,然后运行 `yarn test` 或 `yarn start` 启动 jest 进行调测 +5. 确保所有的测试用例都能通过时,提 MR 给 @牧毅 -- MR 将在 1 个工作日内给您回复意见。 + +当然,欢迎提前私聊沟通 @牧毅,或加入 低代码渲染/出码服务金牌用户群 讨论沟通。 + +# FAQ + +## 如何查看单测覆盖率? + +执行 `yarn test:cov` 命令,这样会自动生成单测覆盖率的报告到 `coverage` 目录下。 + +## 如何只执行一个测试用例? + +```sh +yarn test -t 'demo2-utils-name-alias' +``` + +## 更新特定测试用例的 expected: + +```sh +yarn test:update-snapshots -t 'demo2-utils-name-alias' +``` + +## 如何只执行某个测试用例文件? + +执行 `npx jest 测试用例的文件路径` 即可,如: + +```sh +npx jest tests/plugins/common/requireUtils.test.ts +``` + +## 如何调试某个测试用例? + +建议需要打断点的地方通过 VSCode 打上断点,然后打开 VSCode 的 JavaScript Debug Terminal,在其中执行 `npx jest tests/path/to/your/test/file.ts` 或 `npx jest -t your-test-case-title` 来执行你的测试用例 -- 这样执行到打了断点的语句时会自动断住,以便调试。 diff --git a/packages/code-generator/README.md b/packages/code-generator/README.md new file mode 100644 index 000000000..003f2359c --- /dev/null +++ b/packages/code-generator/README.md @@ -0,0 +1,21 @@ +# 出码模块 + +**重要!!! 本模块是 Node 端运行的!本模块是 Node 端运行的!本模块是 Node 端运行的!暂不支持 Web 端直接跑。** + +如果有业务诉求需要在 Web 端运行,可以联系 @牧毅,会在架构组讨论优先度。 + +## 使用方法 + +需要快速体验效果的,可以: + +- 使用命令行工具快速体验:`tnpx @ali/lowcode-code-generator -i example-schema.json -o generated -s icejs` (其中 example-schema.json 可以从[这里下载](https://unpkg.antfin-inc.com/@ali/lowcode-code-generator-cli@1.1.0/example-schema.json)) +- 或访问 Git 仓库 [ali-lowcode/code-generator-demo](https://code.aone.alibaba-inc.com/ali-lowcode/code-generator-demo) 获取 demo 工程 + +更多更灵活地接入定制请参阅: + +- [接入 & 定制出码](https://yuque.antfin.com/docs/share/5aab0684-3492-40bd-8bf2-53ae6ac1033d?#) +- [出码原理](https://yuque.antfin.com/docs/share/1a2f0415-a8ac-4159-b2e9-4cfebb5eab28?#) + +## 参与共建 + +欢迎参与共建,如何共建请参阅:[./CONTRIBUTING.md](https://code.aone.alibaba-inc.com/ali-lowcode/code-generator/blob/develop/CONTRIBUTING.md) diff --git a/packages/code-generator/abc.json b/packages/code-generator/abc.json new file mode 100644 index 000000000..99e68e6b9 --- /dev/null +++ b/packages/code-generator/abc.json @@ -0,0 +1,13 @@ +{ + "assets": { + "type": "command", + "command": { + "cmd": [ + "tnpm install", + "node scripts/fixDefVersion ./package.json", + "tnpm run build", + "node scripts/move-files-to-build-dest" + ] + } + } +} diff --git a/packages/code-generator/bin/lowcode-code-generator.js b/packages/code-generator/bin/lowcode-code-generator.js new file mode 100755 index 000000000..c502d69f4 --- /dev/null +++ b/packages/code-generator/bin/lowcode-code-generator.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node +/* eslint-disable no-var */ +/* eslint-disable @typescript-eslint/no-require-imports */ + +var program = require('commander'); + +program + .description('Generate code from ali lowcode schema') + .requiredOption('-s, --solution ', 'specify the solution to use (icejs/rax/recore)') + .option('-i, --input ', 'specify the input schema file') + .option('-o, --output ', 'specify the output directory', 'generated') + .option('-c, --cwd ', 'specify the working directory', '.') + .option('-q, --quiet', 'be quiet, do not output anything unless get error', false) + .arguments('ali lowcode schema JSON file') + .parse(process.argv); + +var options = program.opts(); +if (options.cwd) { + process.chdir(options.cwd); +} + +require('../lib/cli') + .run(program.args, options) + .then((retCode) => { + process.exit(retCode); + }); diff --git a/packages/code-generator/commitlint.config.js b/packages/code-generator/commitlint.config.js new file mode 100644 index 000000000..52f3b754b --- /dev/null +++ b/packages/code-generator/commitlint.config.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['ali'], +}; diff --git a/packages/code-generator/example-schema.json b/packages/code-generator/example-schema.json new file mode 100644 index 000000000..bdcfd7399 --- /dev/null +++ b/packages/code-generator/example-schema.json @@ -0,0 +1,276 @@ +{ + "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() { console.log('componentDidMount'); }" + } + }, + "dataSource": { + "list": [ + { + "id": "urlParams", + "type": "urlParams" + }, + + { + "id": "user", + "type": "fetch", + "options": { + "method": "GET", + "uri": "https://shs.alibaba-inc.com/mock/1458/demo/user", + "isSync": true + }, + "dataHandler": { + "type": "JSExpression", + "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}" + } + }, + + { + "id": "orders", + "type": "fetch", + "options": { + "method": "GET", + "uri": "https://shs.alibaba-inc.com/mock/1458/demo/orders", + "isSync": true + }, + "dataHandler": { + "type": "JSExpression", + "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}" + } + } + ], + "dataHandler": { + "type": "JSExpression", + "value": "function (dataMap) {\n console.info(\"All datasources loaded:\", dataMap);\n}" + } + }, + "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", + "condition": { + "type": "JSExpression", + "value": "this.index >= 1" + }, + "loop": ["a", "b", "c"], + "props": { + "type": "primary", + "style": { + "margin": "0 5px 0 5px" + } + }, + "children": [ + { + "type": "JSExpression", + "value": "this.item" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "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": "Test" + } +} diff --git a/packages/code-generator/jest.config.js b/packages/code-generator/jest.config.js new file mode 100644 index 000000000..0b213cd36 --- /dev/null +++ b/packages/code-generator/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + transformIgnorePatterns: ['/node_modules/(?!core-js)/'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], + collectCoverage: false, + collectCoverageFrom: ['src/**/*.{ts,tsx}', '!**/node_modules/**', '!**/vendor/**'], + testMatch: ['/tests/**/*.test.ts'], +}; diff --git a/packages/code-generator/package.json b/packages/code-generator/package.json new file mode 100644 index 000000000..10d2e3579 --- /dev/null +++ b/packages/code-generator/package.json @@ -0,0 +1,128 @@ +{ + "name": "@ali/lowcode-code-generator", + "version": "1.3.0", + "description": "出码引擎 for LowCode Engine", + "license": "MIT", + "main": "lib/index.js", + "module": "es/index.js", + "typings": "es/index.d.ts", + "files": [ + "bin", + "lib", + "es", + "demo", + "dist", + "CHANGELOG.md", + "README.md", + "example-schema.json" + ], + "bin": { + "lowcode-code-generator": "bin/lowcode-code-generator.js" + }, + "scripts": { + "start": "jest --watchAll", + "build": "npm run build:bs", + "build:bs": "rimraf lib es dist && npm run build:cjs && npm run build:esm", + "build:cjs": "tsc --module commonjs --outDir lib", + "build:esm": "tsc --module es6 --outDir es", + "clean": "rimraf es lib dist test-cases/*/*/actual", + "lint": "eslint --ext .jsx,.js,.ts,.tsx src/", + "lintfix": "eslint --ext .jsx,.js,.ts,.tsx --fix src/", + "template": "node ./scripts/build-template-static-files.js", + "test": "jest", + "test:cov": "jest --coverage", + "test:update-snapshots": "cross-env UPDATE_EXPECTED=true jest -u", + "release:beta": "standard-version -t @ali/lowcode-code-generator\\@ --prerelease beta && git push --follow-tags && tnpm publish --tag beta", + "release": "standard-version -t @ali/lowcode-code-generator\\@ && git push --follow-tags && tnpm publish", + "prepublishOnly": "npm run build", + "demo": "node bin/lowcode-code-generator.js -i example-schema.json -o demo -s icejs" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged", + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" + } + }, + "lint-staged": { + "**/*.{js,jsx,ts,tsx}": "eslint" + }, + "dependencies": { + "@ali/lowcode-types": "^1.0.50", + "@babel/generator": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/runtime": "^7.12.5", + "@babel/traverse": "^7.12.12", + "@babel/types": "^7.12.12", + "@types/debug": "^4.1.7", + "@types/fs-extra": "^9.0.12", + "@types/glob": "^7.2.0", + "@types/lodash": "^4.14.162", + "@types/qs": "^6.9.6", + "@types/semver": "^7.3.4", + "chalk": "^4.1.0", + "change-case": "^3.1.0", + "commander": "^6.1.0", + "debug": "^4.3.2", + "fs-extra": "9.x", + "glob": "^7.2.0", + "html-entities": "^2.3.2", + "json5": "^2.2.0", + "jsonc": "^2.0.0", + "jszip": "^3.5.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "mock-fs": "^5.1.2", + "moment": "^2.29.1", + "path-browserify": "^1.0.1", + "prettier": "^2.5.1", + "qs": "^6.10.1", + "semver": "^7.3.4", + "short-uuid": "^3.1.1", + "tslib": "^2.3.1" + }, + "browser": { + "path": "path-browserify", + "lodash": "lodash-es", + "prettier": "prettier/standalone" + }, + "devDependencies": { + "@iceworks/spec": "^1.4.2", + "@types/babel__traverse": "^7.11.0", + "@types/jest": "^27.0.2", + "@types/lodash": "^4.14.162", + "@types/node": "^14.14.20", + "@types/prettier": "^2.4.2", + "@typescript-eslint/eslint-plugin": "^4.12.0", + "@typescript-eslint/parser": "^4.12.0", + "build-plugin-component": "^0.2.22", + "cross-env": "^7.0.3", + "esbuild": "^0.14.5", + "esbuild-plugin-ignore": "^1.1.0", + "esbuild-visualizer": "^0.3.1", + "eslint": "^7.17.0", + "eslint-config-ali": "^11.4.1", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-react": "^7.22.0", + "eslint-plugin-react-hooks": "^4.2.0", + "jest": "^27.3.1", + "rimraf": "^3.0.2", + "standard-version": "^9.1.1", + "ts-jest": "^27.0.7", + "ts-loader": "^6.2.2", + "ts-node": "^8.10.2", + "tsconfig-paths": "^3.9.0", + "typescript": "4.x", + "yargs-parser": "^20.2.9" + }, + "engines": { + "node": ">=10.0.0", + "install-node": "14.x" + }, + "publishConfig": { + "registry": "http://registry.npm.alibaba-inc.com" + }, + "tnpm": { + "mode": "yarn", + "lockfile": "enable" + } +} diff --git a/packages/code-generator/scripts/build-template-static-files.js b/packages/code-generator/scripts/build-template-static-files.js new file mode 100644 index 000000000..daa48369e --- /dev/null +++ b/packages/code-generator/scripts/build-template-static-files.js @@ -0,0 +1,125 @@ +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/quotes */ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/* eslint-disable @typescript-eslint/no-require-imports */ +// @ts-check +// 这个文件是用来构建模板中的静态文件的 +const fs = require('fs'); +const glob = require('glob'); +const path = require('path'); +const JSON5 = require('json5'); +const { spawnSync } = require('child_process'); + +const PROJECT_ROOT = path.join(__dirname, '..'); + +const TEMPLATES = [ + { + sourceDir: path.join(PROJECT_ROOT, 'static-files/rax'), + outputDir: path.join(PROJECT_ROOT, 'src/plugins/project/framework/rax/template'), + }, +]; + +try { + TEMPLATES.forEach(buildTemplateStaticFiles); + console.log('All done.'); +} catch (e) { + console.error(e); + process.exit(1); +} + +function buildTemplateStaticFiles({ sourceDir, outputDir }) { + console.log('processing %s template...', path.dirname(sourceDir)); + + // 扫描所有的目录 + const sourceFiles = glob.sync('**/*', { + nodir: true, + dot: true, + cwd: sourceDir, + }); + + console.log('got %d files: %o', sourceFiles.length, sourceFiles); + + const staticFiles = { + imports: [], + runs: [], + }; + + // 生成对应的文件 + sourceFiles.forEach((sourceFileName, index) => { + console.log('processing %s', sourceFileName); + const sourceFileContent = fs.readFileSync(path.join(sourceDir, sourceFileName), 'utf-8'); + const sourceFileRealName = sourceFileName.replace(/\.template$/, ''); + const outputFileName = `${sourceFileRealName}.ts`; + const outputFileFullPath = path.join(outputDir, 'files', outputFileName); + + const sourceFileExtName = path.extname(sourceFileRealName); + const sourceFileBaseName = path.basename(sourceFileRealName, sourceFileExtName); + + // 确保目录存在 + fs.mkdirSync(path.dirname(outputFileFullPath), { recursive: true }); + + // 写入文件 + fs.writeFileSync( + outputFileFullPath, + [ + `/* eslint-disable max-len */`, + `/* Note: this file is generated by "npm run template", please dont modify this file directly */`, + `/* -- instead, you should modify "${path.relative( + PROJECT_ROOT, + path.join(sourceDir, sourceFileName), + )}" and run "npm run template" */`, + `import { ResultFile } from '@ali/lowcode-types';`, + '', + `export default function getFile(): [string[], ResultFile] {`, + ` return ${JSON5.stringify([ + // 文件目录: + path.dirname(sourceFileRealName).split(path.sep).filter(Boolean), + // 文件名和内容: + { + name: sourceFileBaseName, + ext: sourceFileExtName.replace(/^\./, ''), + content: sourceFileContent, + }, + ])};`, + `}`, + '', + ].join('\n'), + { + encoding: 'utf-8', + }, + ); + + staticFiles.imports.push(`import file${index} from './files/${sourceFileRealName}';`); + + staticFiles.runs.push(` runFileGenerator(root, file${index})`); + }); + + console.log('generating static-files.ts...'); + fs.writeFileSync( + path.join(outputDir, 'static-files.ts'), + [ + `/* Note: this file is generated by "npm run template", please dont modify this file directly */`, + `import { ResultDir } from '@ali/lowcode-types'; + + import { createResultDir } from '../../../../../utils/resultHelper'; + import { runFileGenerator } from '../../../../../utils/templateHelper';`, + ...staticFiles.imports, + '', + `export function generateStaticFiles(root = createResultDir('.')): ResultDir {`, + ...staticFiles.runs, + ` return root;`, + `}`, + '', + ].join('\n'), + { encoding: 'utf-8' }, + ); + + // prettier 一把 + console.log('run prettier...'); + spawnSync('npx', ['prettier', '--write', `${outputDir}`], { + stdio: 'inherit', + shell: true, + }); + + console.log('done %s', path.basename(sourceDir)); +} diff --git a/packages/code-generator/scripts/fixDefVersion.js b/packages/code-generator/scripts/fixDefVersion.js new file mode 100644 index 000000000..b9b6d8319 --- /dev/null +++ b/packages/code-generator/scripts/fixDefVersion.js @@ -0,0 +1,80 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/no-require-imports */ +// @ts-check - check the types to avoid silly mistakes +// This is a script to fix the version in package.json during DEF publishing. +// Test this file: +// +// $ BUILD_GIT_BRANCH=release/1.1.3 BUILD_ARGV_STR=--def_publish_env=daily node scripts/fixDefVersion ./package.json +// --> should fix the package.json version to 1.1.3-beta.xxxx +// +// $ BUILD_GIT_BRANCH=release/1.1.3 BUILD_ARGV_STR=--def_publish_env=prod node scripts/fixDefVersion ./package.json +// --> should fix the package.json version to 1.1.3 + +const fs = require('fs'); +const moment = require('moment'); +const program = require('commander'); +const parseArgs = require('yargs-parser'); + +program + .description('Fix version for def publishing TNPM packages') + .option('--no-beta', 'no beta version', false) + .arguments('package.json file path (only one is needed)') + .parse(process.argv); + +try { + const packageJsonFilePath = program.args[0]; + if (!packageJsonFilePath) { + program.help(); + process.exit(2); + } + + const destVersion = fixVersion({ + packageJsonFilePath, + env: process.env, + beta: program.opts().beta, + }); + + console.log(`Fixed version to: ${destVersion}`); +} catch (err) { + console.error('Got error: ', err); + process.exit(1); +} + +function fixVersion({ packageJsonFilePath, env = process.env, beta = true }) { + if (!env.BUILD_GIT_BRANCH) { + throw new Error('env.BUILD_GIT_BRANCH is required'); + } + + if (!env.BUILD_ARGV_STR) { + throw new Error('env.BUILD_ARGV_STR is required'); + } + + const gitBranchVersion = parseBuildBranchVersion(env.BUILD_GIT_BRANCH); + const buildArgs = parseArgs(env.BUILD_ARGV_STR); + const buildEnv = buildArgs.def_publish_env; // daily | prod + + const destVersion = + buildEnv === 'prod' || !beta + ? gitBranchVersion + : `${gitBranchVersion}-beta.${moment().format('MMDDHHmm').replace(/^0+/, '')}`; + + const packageJson = JSON.parse(fs.readFileSync(packageJsonFilePath, 'utf-8')); + + packageJson.version = destVersion; + + if (env.BUILD_GIT_COMMITID) { + packageJson.gitHead = env.BUILD_GIT_COMMITID; + } + + fs.writeFileSync(packageJsonFilePath, `${JSON.stringify(packageJson, null, 2)}\n`, { + encoding: 'utf8', + }); + + return destVersion; +} + +function parseBuildBranchVersion(branchName) { + const m = `${branchName}`.match(/\d+\.\d+\.\d+/); + return (m && m[0]) || ''; +} diff --git a/packages/code-generator/scripts/move-files-to-build-dest.js b/packages/code-generator/scripts/move-files-to-build-dest.js new file mode 100644 index 000000000..736df9968 --- /dev/null +++ b/packages/code-generator/scripts/move-files-to-build-dest.js @@ -0,0 +1,24 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +const fs = require('fs'); +const { spawnSync } = require('child_process'); + +const BUILD_DEST = process.env.BUILD_DEST || '.package'; + +fs.mkdirSync(BUILD_DEST, { recursive: true }); + +const distFiles = [...require('../package.json').files, 'package.json']; + +distFiles.forEach((file) => { + console.log('mv %s', file); + if (file === BUILD_DEST) { + fs.mkdirSync(`${BUILD_DEST}/${file}`, { recursive: true }); + spawnSync('mv', [`${file}/*`, `${BUILD_DEST}/${file}/`], { shell: true, stdio: 'inherit' }); + } +}); + +distFiles.forEach((file) => { + console.log('mv %s', file); + if (file !== BUILD_DEST) { + spawnSync('mv', [file, `${BUILD_DEST}/${file}`], { shell: true, stdio: 'inherit' }); + } +}); diff --git a/packages/code-generator/src/analyzer/componentAnalyzer.ts b/packages/code-generator/src/analyzer/componentAnalyzer.ts new file mode 100644 index 000000000..5153df948 --- /dev/null +++ b/packages/code-generator/src/analyzer/componentAnalyzer.ts @@ -0,0 +1,35 @@ +import type { NodeSchema, CompositeObject } from '@ali/lowcode-types'; +import type { TComponentAnalyzer } from '../types'; + +import { handleSubNodes } from '../utils/schema'; + +export const componentAnalyzer: TComponentAnalyzer = (container) => { + let hasRefAttr = false; + const nodeValidator = (n: NodeSchema) => { + if (n.props) { + const props = n.props as CompositeObject; + if (props.ref) { + hasRefAttr = true; + } + } + }; + + nodeValidator(container); + + if (!hasRefAttr && container.children) { + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + handleSubNodes( + container.children, + { + node: nodeValidator, + }, + { + rerun: true, + }, + ); + } + + return { + isUsingRef: hasRefAttr, + }; +}; diff --git a/packages/code-generator/src/cli/index.ts b/packages/code-generator/src/cli/index.ts new file mode 100644 index 000000000..2e6f96763 --- /dev/null +++ b/packages/code-generator/src/cli/index.ts @@ -0,0 +1 @@ +export * from './run'; diff --git a/packages/code-generator/src/cli/run.ts b/packages/code-generator/src/cli/run.ts new file mode 100644 index 000000000..6d8bb1531 --- /dev/null +++ b/packages/code-generator/src/cli/run.ts @@ -0,0 +1,129 @@ +/* eslint-disable no-console */ +import chalk from 'chalk'; +import * as fs from 'fs-extra'; +import JSON5 from 'json5'; +import { jsonc } from 'jsonc'; +import { spawnSync } from 'child_process'; +import * as path from 'path'; + +import { getErrorMessage } from '../utils/errors'; +import CodeGenerator from '..'; +import type { IProjectBuilder } from '..'; +import type { ProjectSchema } from '@ali/lowcode-types'; + +/** + * 执行出码 CLI 命令 + * @param args 入参数组 + * @param options 选项 + * @returns {Promise} 错误码 + */ +export async function run( + args: string[], + options: { + solution: string; + input?: string; + output?: string; + quiet?: boolean; + }, +): Promise { + try { + const schemaFile = options.input || args[0]; + if (!schemaFile) { + throw new Error( + 'a schema file must be specified by `--input ` or by the first positional argument', + ); + } + + if ((options.input && args.length > 0) || args.length > 1) { + throw new Error( + 'only one schema file can be specified, either by `--input ` or by the first positional argument', + ); + } + + // 读取 Schema + const schema = await loadSchemaFile(schemaFile); + + // 创建一个项目构建器 + const createProjectBuilder = await getProjectBuilderFactory(options.solution, { + quiet: options.quiet, + }); + const builder = createProjectBuilder(); + + // 生成代码 + const generatedSourceCodes = await builder.generateProject(schema); + + // 输出到磁盘 + const publisher = CodeGenerator.publishers.disk(); + + await publisher.publish({ + project: generatedSourceCodes, + outputPath: options.output || 'generated', + projectSlug: 'example', + createProjectFolder: false, + }); + return 0; + } catch (e) { + console.log(chalk.red(getErrorMessage(e) || `Unexpected error: ${e}`)); + return 1; + } +} + +async function getProjectBuilderFactory( + solution: string, + { quiet }: { quiet?: boolean }, +): Promise<() => IProjectBuilder> { + if (solution in CodeGenerator.solutions) { + return CodeGenerator.solutions[solution as 'icejs' | 'rax']; + } + + const solutionPackageName = isLocalSolution(solution) + ? solution + : `${solution.startsWith('@') ? solution : `@ali/lowcode-solution-${solution}`}`; + + if (!isLocalSolution(solution)) { + if (!quiet) { + console.log(`"${solution}" is not internal, installing it as ${solutionPackageName}...`); + } + + spawnSync('tnpm', ['i', solutionPackageName], { + stdio: quiet ? 'ignore' : 'inherit', + }); + } + + // eslint-disable-next-line @typescript-eslint/no-require-imports + const solutionExports = require(!isLocalSolution(solution) + ? solutionPackageName + : `${path.isAbsolute(solution) ? solution : path.join(process.cwd(), solution)}`); + + const projectBuilderFactory = + solutionExports.createProjectBuilder || + solutionExports.createAppBuilder || + solutionExports.default; + + if (typeof projectBuilderFactory !== 'function') { + throw new Error( + `"${solutionPackageName}" should export project builder factory via named export 'createProjectBuilder' or via default export`, + ); + } + + return projectBuilderFactory; +} + +function isLocalSolution(solution: string) { + return solution.startsWith('.') || solution.startsWith('/') || solution.startsWith('~'); +} + +async function loadSchemaFile(schemaFile: string): Promise { + if (!schemaFile) { + throw new Error('invalid schema file name'); + } + + const schemaFileContent = await fs.readFile(schemaFile, 'utf8'); + + if (/\.json5/.test(schemaFile)) { + return JSON5.parse(schemaFileContent); + } + + // 默认用 JSONC 的格式解析(兼容 JSON) + return jsonc.parse(schemaFileContent); +} diff --git a/packages/code-generator/src/config/env.ts b/packages/code-generator/src/config/env.ts new file mode 100644 index 000000000..30d564c06 --- /dev/null +++ b/packages/code-generator/src/config/env.ts @@ -0,0 +1,3 @@ +import * as path from 'path'; + +export const CODE_GENERATOR_ROOT = path.join(__dirname, '../..'); diff --git a/packages/code-generator/src/const/file.ts b/packages/code-generator/src/const/file.ts new file mode 100644 index 000000000..d29ea43a3 --- /dev/null +++ b/packages/code-generator/src/const/file.ts @@ -0,0 +1,3 @@ +import { FileType } from '../types/core'; + +export const FILE_TYPE_FAMILY = [[FileType.TSX, FileType.TS, FileType.JSX, FileType.JS]]; diff --git a/packages/code-generator/src/const/generator.ts b/packages/code-generator/src/const/generator.ts new file mode 100644 index 000000000..119745838 --- /dev/null +++ b/packages/code-generator/src/const/generator.ts @@ -0,0 +1,129 @@ +export const COMMON_CHUNK_NAME = { + ExternalDepsImport: 'CommonExternalDependencyImport', + InternalDepsImport: 'CommonInternalDependencyImport', + ImportAliasDefine: 'CommonImportAliasDefine', + FileVarDefine: 'CommonFileScopeVarDefine', + FileUtilDefine: 'CommonFileScopeMethodDefine', + FileMainContent: 'CommonFileMainContent', + FileExport: 'CommonFileExport', + 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', + InsPrivateMethod: 'CommonClassDefineInsPrivateMethod', + End: 'CommonClassDefineEnd', +}; + +export const DEFAULT_LINK_AFTER = { + [COMMON_CHUNK_NAME.ExternalDepsImport]: [], + [COMMON_CHUNK_NAME.InternalDepsImport]: [COMMON_CHUNK_NAME.ExternalDepsImport], + [COMMON_CHUNK_NAME.ImportAliasDefine]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport, + ], + [COMMON_CHUNK_NAME.FileVarDefine]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + ], + [COMMON_CHUNK_NAME.FileUtilDefine]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + ], + [CLASS_DEFINE_CHUNK_NAME.Start]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + 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.InsPrivateMethod]: [ + 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, + ], + [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.InsPrivateMethod, + CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + ], + [COMMON_CHUNK_NAME.FileMainContent]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + 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.ImportAliasDefine, + 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/const/index.ts b/packages/code-generator/src/const/index.ts new file mode 100644 index 000000000..103d912db --- /dev/null +++ b/packages/code-generator/src/const/index.ts @@ -0,0 +1,12 @@ +export const NATIVE_ELE_PKG = 'native'; + +export const CONTAINER_TYPE = { + COMPONENT: 'Component', + BLOCK: 'Block', + PAGE: 'Page', +}; + +export const SUPPORT_SCHEMA_VERSION_LIST = ['0.0.1', '1.0.0']; + +export * from './file'; +export * from './generator'; diff --git a/packages/code-generator/src/generator/ChunkBuilder.ts b/packages/code-generator/src/generator/ChunkBuilder.ts new file mode 100644 index 000000000..6799d5940 --- /dev/null +++ b/packages/code-generator/src/generator/ChunkBuilder.ts @@ -0,0 +1,123 @@ +import { BuilderComponentPlugin, IChunkBuilder, ICodeChunk, ICodeStruct, FileType } from '../types'; + +import { COMMON_SUB_MODULE_NAME } from '../const/generator'; +import { FILE_TYPE_FAMILY } from '../const/file'; + +interface ChunkGroupInfo { + chunk: ICodeChunk; + familyIdx?: number; +} + +function whichFamily(type: FileType): [number, FileType[]] | undefined { + const idx = FILE_TYPE_FAMILY.findIndex((family) => family.indexOf(type) >= 0); + if (idx < 0) { + return undefined; + } + return [idx, FILE_TYPE_FAMILY[idx]]; +} + +export const groupChunks = (chunks: ICodeChunk[]): ICodeChunk[][] => { + const tmp: Record> = {}; + const col = chunks.reduce((chunksSet: Record, chunk) => { + const fileKey = chunk.subModule || COMMON_SUB_MODULE_NAME; + if (!chunksSet[fileKey]) { + // eslint-disable-next-line no-param-reassign + chunksSet[fileKey] = []; + } + const res = whichFamily(chunk.fileType as FileType); + const info: ChunkGroupInfo = { + chunk, + }; + if (res) { + const [familyIdx, family] = res; + const rank = family.indexOf(chunk.fileType as FileType); + if (tmp[fileKey]) { + if (tmp[fileKey][familyIdx] !== undefined) { + if (tmp[fileKey][familyIdx] > rank) { + tmp[fileKey][familyIdx] = rank; + } + } else { + tmp[fileKey][familyIdx] = rank; + } + } else { + tmp[fileKey] = {}; + tmp[fileKey][familyIdx] = rank; + } + info.familyIdx = familyIdx; + } + + chunksSet[fileKey].push(info); + return chunksSet; + }, {}); + + const result: ICodeChunk[][] = []; + Object.keys(col).forEach((key) => { + const byType: Record = {}; + col[key].forEach((info) => { + let t: string = info.chunk.fileType; + if (info.familyIdx !== undefined) { + t = FILE_TYPE_FAMILY[info.familyIdx][tmp[key][info.familyIdx]]; + // eslint-disable-next-line no-param-reassign + info.chunk.fileType = t; + } + if (!byType[t]) { + byType[t] = []; + } + byType[t].push(info.chunk); + }); + result.push(...Object.keys(byType).map((t) => byType[t])); + }); + + return result; +}; + +/** + * 代码片段构建器 + * + * @export + * @class ChunkBuilder + * @template T + */ +export class ChunkBuilder implements IChunkBuilder { + private plugins: BuilderComponentPlugin[]; + + constructor(plugins: BuilderComponentPlugin[] = []) { + this.plugins = plugins; + } + + async run( + ir: unknown, + initialStructure: ICodeStruct = { + ir, + chunks: [], + depNames: [], + contextData: {}, + }, + ) { + const structure = initialStructure; + + const finalStructure: ICodeStruct = await this.plugins.reduce( + async (previousPluginOperation: Promise, plugin) => { + const modifiedStructure = await previousPluginOperation; + return plugin(modifiedStructure); + }, + Promise.resolve(structure), + ); + + const chunks = groupChunks(finalStructure.chunks); + + return { + chunks, + }; + } + + getPlugins() { + return this.plugins; + } + + addPlugin(plugin: BuilderComponentPlugin) { + this.plugins.push(plugin); + } +} + +export default ChunkBuilder; diff --git a/packages/code-generator/src/generator/CodeBuilder.ts b/packages/code-generator/src/generator/CodeBuilder.ts new file mode 100644 index 000000000..e633babbf --- /dev/null +++ b/packages/code-generator/src/generator/CodeBuilder.ts @@ -0,0 +1,103 @@ +import { + ChunkContent, + ChunkType, + CodeGeneratorError, + CodeGeneratorFunction, + ICodeBuilder, + ICodeChunk, +} from '../types'; + +export class CodeBuilder implements ICodeBuilder { + private chunkDefinitions: ICodeChunk[] = []; + + private generators: { [key: string]: CodeGeneratorFunction } = { + [ChunkType.STRING]: (str: string) => str, // no-op for string chunks + [ChunkType.JSON]: (json: Record) => JSON.stringify(json), // stringify json to string + }; + + constructor(chunkDefinitions: ICodeChunk[] = []) { + this.chunkDefinitions = chunkDefinitions; + } + + /** + * Links all chunks together based on their requirements. Returns an array + * of ordered chunk names which need to be compiled and glued together. + */ + link(chunkDefinitions: ICodeChunk[] = []): string { + const chunks = chunkDefinitions || this.chunkDefinitions; + if (chunks.length <= 0) { + return ''; + } + + const unprocessedChunks = chunks.map((chunk) => { + return { + name: chunk.name, + type: chunk.type, + content: chunk.content, + linkAfter: this.cleanupInvalidChunks(chunk.linkAfter, chunks), + }; + }); + + const resultingString: string[] = []; + + while (unprocessedChunks.length > 0) { + let indexToRemove = 0; + for (let index = 0; index < unprocessedChunks.length; index++) { + if (unprocessedChunks[index].linkAfter.length <= 0) { + indexToRemove = index; + break; + } + } + + if (unprocessedChunks[indexToRemove].linkAfter.length > 0) { + throw new CodeGeneratorError( + 'Operation aborted. Reason: cyclic dependency between chunks.', + ); + } + + const { type, content, name } = unprocessedChunks[indexToRemove]; + const compiledContent = this.generateByType(type, content); + if (compiledContent) { + resultingString.push(`${compiledContent}\n`); + } + + unprocessedChunks.splice(indexToRemove, 1); + if (!unprocessedChunks.some((ch) => ch.name === name)) { + unprocessedChunks.forEach( + // remove the processed chunk from all the linkAfter arrays from the remaining chunks + (ch) => { + // eslint-disable-next-line no-param-reassign + ch.linkAfter = ch.linkAfter.filter((after) => after !== name); + }, + ); + } + } + + return resultingString.join('\n'); + } + + generateByType(type: string, content: unknown): string { + if (!content) { + return ''; + } + if (Array.isArray(content)) { + return content.map((contentItem) => this.generateByType(type, contentItem)).join('\n'); + } + + if (!this.generators[type]) { + throw new Error( + `Attempted to generate unknown type ${type}. Please register a generator for this type in builder/index.ts`, + ); + } + + return this.generators[type](content); + } + + // remove invalid chunks (which did not end up being created) from the linkAfter fields + // one use-case is when you want to remove the import plugin + private cleanupInvalidChunks(linkAfter: string[], chunks: ICodeChunk[]) { + return linkAfter.filter((chunkName) => chunks.some((chunk) => chunk.name === chunkName)); + } +} + +export default CodeBuilder; diff --git a/packages/code-generator/src/generator/ModuleBuilder.ts b/packages/code-generator/src/generator/ModuleBuilder.ts new file mode 100644 index 000000000..dce0e8739 --- /dev/null +++ b/packages/code-generator/src/generator/ModuleBuilder.ts @@ -0,0 +1,109 @@ +import { ProjectSchema, ResultFile, ResultDir } from '@ali/lowcode-types'; + +import { + BuilderComponentPlugin, + CodeGeneratorError, + ICodeChunk, + ICompiledModule, + IModuleBuilder, + IParseResult, + 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 { createResultFile, createResultDir, addFile } from '../utils/resultHelper'; + +export function createModuleBuilder( + options: { + plugins: BuilderComponentPlugin[]; + postProcessors: PostProcessor[]; + mainFileName?: string; + } = { + plugins: [], + postProcessors: [], + }, +): IModuleBuilder { + const chunkGenerator = new ChunkBuilder(options.plugins); + const linker = new CodeBuilder(); + + const generateModule = async (input: unknown): Promise => { + const moduleMainName = options.mainFileName || COMMON_SUB_MODULE_NAME; + if (chunkGenerator.getPlugins().length <= 0) { + throw new CodeGeneratorError( + 'No plugins found. Component generation cannot work without any plugins!', + ); + } + + let files: ResultFile[] = []; + + const { chunks } = await chunkGenerator.run(input); + chunks.forEach((fileChunkList) => { + const content = linker.link(fileChunkList); + const file = createResultFile( + fileChunkList[0].subModule || moduleMainName, + fileChunkList[0].fileType, + content, + ); + files.push(file); + }); + + if (options.postProcessors.length > 0) { + files = files.map((file) => { + let { content } = file; + const type = file.ext; + options.postProcessors.forEach((processer) => { + content = processer(content, type); + }); + + return createResultFile(file.name, type, content); + }); + } + + return { + files, + }; + }; + + const generateModuleCode = async (schema: ProjectSchema | 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 = createResultDir(containerInfo.moduleName); + files.forEach((file) => addFile(dir, file)); + + return dir; + }; + + const linkCodeChunks = (chunks: Record, fileName: string) => { + const files: ResultFile[] = []; + + Object.keys(chunks).forEach((fileKey) => { + const fileChunkList = chunks[fileKey]; + const content = linker.link(fileChunkList); + const file = createResultFile( + fileChunkList[0].subModule || fileName, + fileChunkList[0].fileType, + content, + ); + files.push(file); + }); + + return files; + }; + + 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 new file mode 100644 index 000000000..b9f389582 --- /dev/null +++ b/packages/code-generator/src/generator/ProjectBuilder.ts @@ -0,0 +1,294 @@ +import { ResultDir, ResultFile, ProjectSchema } from '@ali/lowcode-types'; + +import { + IModuleBuilder, + IParseResult, + IProjectBuilder, + IProjectPlugins, + IProjectTemplate, + ISchemaParser, + PostProcessor, +} from '../types'; + +import { SchemaParser } from '../parser/SchemaParser'; +import { createResultDir, addDirectory, addFile } from '../utils/resultHelper'; + +import { createModuleBuilder } from '../generator/ModuleBuilder'; +import { ProjectPreProcessor, ProjectPostProcessor } from '../types/core'; +import { CodeGeneratorError } from '../types/error'; + +interface IModuleInfo { + moduleName?: string; + path: string[]; + files: ResultFile[]; +} + +export interface ProjectBuilderInitOptions { + /** 项目模板 */ + template: IProjectTemplate; + /** 项目插件 */ + plugins: IProjectPlugins; + /** 模块后置处理器 */ + postProcessors: PostProcessor[]; + /** Schema 解析器 */ + schemaParser?: ISchemaParser; + /** 项目级别的前置处理器 */ + projectPreProcessors?: ProjectPreProcessor[]; + /** 项目级别的后置处理器 */ + projectPostProcessors?: ProjectPostProcessor[]; +} + +export class ProjectBuilder implements IProjectBuilder { + /** 项目模板 */ + private template: IProjectTemplate; + + /** 项目插件 */ + private plugins: IProjectPlugins; + + /** 模块后置处理器 */ + private postProcessors: PostProcessor[]; + + /** Schema 解析器 */ + private schemaParser: ISchemaParser; + + /** 项目级别的前置处理器 */ + private projectPreProcessors: ProjectPreProcessor[]; + + /** 项目级别的后置处理器 */ + private projectPostProcessors: ProjectPostProcessor[]; + + constructor({ + template, + plugins, + postProcessors, + schemaParser = new SchemaParser(), + projectPreProcessors = [], + projectPostProcessors = [], + }: ProjectBuilderInitOptions) { + this.template = template; + this.plugins = plugins; + this.postProcessors = postProcessors; + this.schemaParser = schemaParser; + this.projectPreProcessors = projectPreProcessors; + this.projectPostProcessors = projectPostProcessors; + } + + async generateProject(originalSchema: ProjectSchema | string): Promise { + // Init + const { schemaParser } = this; + const builders = this.createModuleBuilders(); + + const projectRoot = await this.template.generateTemplate(); + + let schema: ProjectSchema = + typeof originalSchema === 'string' ? JSON.parse(originalSchema) : originalSchema; + + // Validate + if (!schemaParser.validate(schema)) { + throw new CodeGeneratorError('Schema is invalid'); + } + + // Parse / Format + + // Preprocess + for (const preProcessor of this.projectPreProcessors) { + // eslint-disable-next-line no-await-in-loop + schema = await preProcessor(schema); + } + + // Collect Deps + // Parse JSExpression + const parseResult: IParseResult = schemaParser.parse(schema); + let buildResult: IModuleInfo[] = []; + + // Generator Code module + // components + // pages + const containerBuildResult: IModuleInfo[] = await Promise.all( + parseResult.containers.map(async (containerInfo) => { + let builder: IModuleBuilder; + let path: string[]; + if (containerInfo.containerType === 'Page') { + builder = builders.pages; + path = this.template.slots.pages.path; + } else { + builder = builders.components; + path = this.template.slots.components.path; + } + + const { files } = await builder.generateModule(containerInfo); + + return { + moduleName: containerInfo.moduleName, + path, + files, + }; + }), + ); + buildResult = buildResult.concat(containerBuildResult); + + // router + if (parseResult.globalRouter && builders.router) { + const { files } = await builders.router.generateModule(parseResult.globalRouter); + + buildResult.push({ + path: this.template.slots.router.path, + files, + }); + } + + // entry + if (parseResult.project && builders.entry) { + const { files } = await builders.entry.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.entry.path, + files, + }); + } + + // appConfig + if (builders.appConfig) { + const { files } = await builders.appConfig.generateModule(parseResult); + + buildResult.push({ + path: this.template.slots.appConfig.path, + files, + }); + } + + // buildConfig + if (builders.buildConfig) { + const { files } = await builders.buildConfig.generateModule(parseResult); + + buildResult.push({ + path: this.template.slots.buildConfig.path, + files, + }); + } + + // constants? + 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, + files, + }); + } + + // utils? + 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, + files, + }); + } + + // i18n? + if (builders.i18n && this.template.slots.i18n) { + const { files } = await builders.i18n.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.i18n.path, + files, + }); + } + + // globalStyle + if (parseResult.project && builders.globalStyle) { + const { files } = await builders.globalStyle.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.globalStyle.path, + files, + }); + } + + // htmlEntry + if (parseResult.project && builders.htmlEntry) { + const { files } = await builders.htmlEntry.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.htmlEntry.path, + files, + }); + } + + // packageJSON + if (parseResult.project && builders.packageJSON) { + const { files } = await builders.packageJSON.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.packageJSON.path, + files, + }); + } + + // TODO: 更多 slots 的处理??是不是可以考虑把 template 中所有的 slots 都处理下? + + // Post Process + + // Combine Modules + buildResult.forEach((moduleInfo) => { + let targetDir = getDirFromRoot(projectRoot, moduleInfo.path); + if (moduleInfo.moduleName) { + const dir = createResultDir(moduleInfo.moduleName); + addDirectory(targetDir, dir); + targetDir = dir; + } + moduleInfo.files.forEach((file) => addFile(targetDir, file)); + }); + + // post-processors + let finalResult = projectRoot; + for (const projectPostProcessor of this.projectPostProcessors) { + // eslint-disable-next-line no-await-in-loop + finalResult = await projectPostProcessor(finalResult, schema, originalSchema); + } + + return finalResult; + } + + private createModuleBuilders(): Record { + const builders: Record = {}; + + 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, + }); + } + }); + + return builders; + } +} + +export function createProjectBuilder(initOptions: ProjectBuilderInitOptions): IProjectBuilder { + return new ProjectBuilder(initOptions); +} + +function getDirFromRoot(root: ResultDir, path: string[]): ResultDir { + let current: ResultDir = root; + path.forEach((p) => { + const exist = current.dirs.find((d) => d.name === p); + if (exist) { + current = exist; + } else { + const newDir = createResultDir(p); + addDirectory(current, newDir); + current = newDir; + } + }); + + return current; +} diff --git a/packages/code-generator/src/index.ts b/packages/code-generator/src/index.ts new file mode 100644 index 000000000..d928c4ffc --- /dev/null +++ b/packages/code-generator/src/index.ts @@ -0,0 +1,122 @@ +/** + * 低代码引擎的出码模块,负责将编排产出的 Schema 转换成实际可执行的代码。 + * 注意:为了保持 API 的稳定性, 这里所有导出的 API 均要显式命名方式导出 + * (即用 export { xxx } from 'xx' 的方式,不要直接 export * from 'xxx') + * 而且所有导出的 API 务必在 tests/public 中编写单元测试 + */ +import { createProjectBuilder } from './generator/ProjectBuilder'; +import { createModuleBuilder } from './generator/ModuleBuilder'; +import { createDiskPublisher } from './publisher/disk'; +import { createZipPublisher } from './publisher/zip'; +import createIceJsProjectBuilder, { plugins as reactPlugins } from './solutions/icejs'; +import createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app'; + +// 引入说明 +import { REACT_CHUNK_NAME } from './plugins/component/react/const'; +import { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from './const/generator'; + +// 引入通用插件组 +import esmodule from './plugins/common/esmodule'; +import requireUtils from './plugins/common/requireUtils'; + +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 prettier from './postprocessor/prettier'; + +// 引入常用工具 +import * as utilsCommon from './utils/common'; +import * as utilsCompositeType from './utils/compositeType'; +import * as utilsJsExpression from './utils/jsExpression'; +import * as utilsJsSlot from './utils/jsSlot'; +import * as utilsNodeToJSX from './utils/nodeToJSX'; +import * as utilsResultHelper from './utils/resultHelper'; +import * as utilsTemplateHelper from './utils/templateHelper'; +import * as utilsValidate from './utils/validate'; +import * as utilsSchema from './utils/schema'; + +import * as CONSTANTS from './const'; + +// 引入内置解决方案模块 +import icejs from './plugins/project/framework/icejs'; +import rax from './plugins/project/framework/rax'; + +export default { + createProjectBuilder, + createModuleBuilder, + solutions: { + icejs: createIceJsProjectBuilder, + rax: createRaxAppProjectBuilder, + }, + solutionParts: { + icejs, + rax, + }, + publishers: { + disk: createDiskPublisher, + zip: createZipPublisher, + }, + plugins: { + common: { + /** + * 处理 ES Module + * @deprecated please use esModule + */ + esmodule, + esModule: esmodule, + requireUtils, + }, + react: { + ...reactPlugins, + }, + rax: { + ...raxPlugins, + }, + style: { + css, + }, + project: { + constants, + i18n, + utils, + }, + }, + postprocessor: { + prettier, + }, + utils: { + common: utilsCommon, + compositeType: utilsCompositeType, + jsExpression: utilsJsExpression, + jsSlot: utilsJsSlot, + nodeToJSX: utilsNodeToJSX, + resultHelper: utilsResultHelper, + templateHelper: utilsTemplateHelper, + validate: utilsValidate, + schema: utilsSchema, + }, + chunkNames: { + COMMON_CHUNK_NAME, + CLASS_DEFINE_CHUNK_NAME, + REACT_CHUNK_NAME, + }, + defaultLinkAfter: { + COMMON_DEFAULT_LINK_AFTER: DEFAULT_LINK_AFTER, + }, + constants: CONSTANTS, +}; + +// 一些类型定义 +export * from './types'; + +// 一些常量定义 +export * from './const'; + +// 一些工具函数 +export * from './analyzer/componentAnalyzer'; +export * from './parser/SchemaParser'; +export * from './generator/ChunkBuilder'; +export * from './generator/CodeBuilder'; +export * from './generator/ModuleBuilder'; +export * from './generator/ProjectBuilder'; diff --git a/packages/code-generator/src/parser/SchemaParser.ts b/packages/code-generator/src/parser/SchemaParser.ts new file mode 100644 index 000000000..e1e1a2a99 --- /dev/null +++ b/packages/code-generator/src/parser/SchemaParser.ts @@ -0,0 +1,355 @@ +/** + * 解析器是对输入的固定格式数据做拆解,使其符合引擎后续步骤预期,完成统一处理逻辑的步骤。 + * 本解析器面向的是标准 schema 协议。 + */ +import changeCase from 'change-case'; +import { + UtilItem, + NodeDataType, + NodeSchema, + ContainerSchema, + ProjectSchema, + PropsMap, + NodeData, + NpmInfo, +} from '@ali/lowcode-types'; +import { + IPageMeta, + CodeGeneratorError, + CompatibilityError, + DependencyType, + IContainerInfo, + IDependency, + IExternalDependency, + IInternalDependency, + InternalDependencyType, + IParseResult, + ISchemaParser, + INpmPackage, + IRouterInfo, +} from '../types'; + +import { SUPPORT_SCHEMA_VERSION_LIST } from '../const'; + +import { getErrorMessage } from '../utils/errors'; +import { handleSubNodes } from '../utils/schema'; +import { uniqueArray } from '../utils/common'; +import { componentAnalyzer } from '../analyzer/componentAnalyzer'; +import { ensureValidClassName } from '../utils/validate'; + +const defaultContainer: IContainerInfo = { + containerType: 'Component', + componentName: 'Component', + moduleName: 'Index', + fileName: 'Index', + css: '', + props: {}, +}; + +function getRootComponentName(typeName: string, maps: Record): string { + if (maps[typeName]) { + const rec = maps[typeName]; + if (rec.destructuring) { + return rec.componentName || typeName; + } + + const peerName = Object.keys(maps).find((depName: string) => { + const depInfo = maps[depName]; + return ( + depName !== typeName && + !depInfo.destructuring && + depInfo.package === rec.package && + depInfo.version === rec.version && + depInfo.main === rec.main && + depInfo.exportName === rec.exportName && + depInfo.subName === rec.subName + ); + }); + + return peerName || typeName; + } + return typeName; +} + +function processChildren(schema: NodeSchema): void { + if (schema.props) { + if (Array.isArray(schema.props)) { + // FIXME: is array type props description + } else { + const nodeProps = schema.props as PropsMap; + if (nodeProps.children) { + if (!schema.children) { + // eslint-disable-next-line no-param-reassign + schema.children = nodeProps.children as NodeDataType; + } else { + let _children: NodeData[] = []; + + if (Array.isArray(schema.children)) { + _children = _children.concat(schema.children); + } else { + _children.push(schema.children); + } + + if (Array.isArray(nodeProps.children)) { + _children = _children.concat(nodeProps.children as NodeData[]); + } else { + _children.push(nodeProps.children as NodeData); + } + + // eslint-disable-next-line no-param-reassign + schema.children = _children; + } + delete nodeProps.children; + } + } + } +} + +export class SchemaParser implements ISchemaParser { + validate(schema: ProjectSchema): boolean { + if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) { + throw new CompatibilityError(`Not support schema with version [${schema.version}]`); + } + + return true; + } + + parse(schemaSrc: ProjectSchema | string): IParseResult { + // TODO: collect utils depends in JSExpression + const compDeps: Record = {}; + const internalDeps: Record = {}; + let utilsDeps: IExternalDependency[] = []; + + const schema = this.decodeSchema(schemaSrc); + + // 解析三方组件依赖 + schema.componentsMap.forEach((info) => { + if (info.componentName) { + compDeps[info.componentName] = { + ...info, + dependencyType: DependencyType.External, + componentName: info.componentName, + exportName: info.exportName ?? info.componentName, + version: info.version || '*', + destructuring: info.destructuring ?? false, + }; + } + }); + + let containers: IContainerInfo[]; + // Test if this is a lowcode component without container + if (schema.componentsTree.length > 0) { + const firstRoot: ContainerSchema = schema.componentsTree[0] as ContainerSchema; + + if (!('fileName' in firstRoot) || !firstRoot.fileName) { + // 整个 schema 描述一个容器,且无根节点定义 + const container: IContainerInfo = { + ...firstRoot, + ...defaultContainer, + props: firstRoot.props || defaultContainer.props, + css: firstRoot.css || defaultContainer.css, + moduleName: (firstRoot as IContainerInfo).moduleName || defaultContainer.moduleName, + children: schema.componentsTree as NodeSchema[], + }; + containers = [container]; + } else { + // 普通带 1 到多个容器的 schema + containers = schema.componentsTree.map((n) => { + const subRoot = n as ContainerSchema; + const container: IContainerInfo = { + ...subRoot, + componentName: getRootComponentName(subRoot.componentName, compDeps), + containerType: subRoot.componentName, + moduleName: ensureValidClassName(changeCase.pascalCase(subRoot.fileName)), + }; + return container; + }); + } + } else { + throw new CodeGeneratorError("Can't find anything to generate."); + } + + // 分析引用能力的依赖 + containers = containers.map((con) => ({ + ...con, + analyzeResult: componentAnalyzer(con as ContainerSchema), + })); + + // 建立所有容器的内部依赖索引 + containers.forEach((container) => { + let type; + switch (container.containerType) { + case 'Page': + type = InternalDependencyType.PAGE; + break; + case 'Block': + type = InternalDependencyType.BLOCK; + break; + default: + type = InternalDependencyType.COMPONENT; + break; + } + + const dep: IInternalDependency = { + type, + moduleName: container.moduleName, + destructuring: false, + exportName: container.moduleName, + dependencyType: DependencyType.Internal, + }; + + internalDeps[dep.moduleName] = dep; + }); + + const containersDeps = ([] as IDependency[]).concat(...containers.map((c) => c.deps || [])); + // TODO: 不应该在出码部分解决? + // 处理 children 写在了 props 里的情况 + containers.forEach((container) => { + if (container.children) { + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + handleSubNodes( + container.children, + { + node: (i: NodeSchema) => processChildren(i), + }, + { + rerun: true, + }, + ); + } + }); + + // 分析容器内部组件依赖 + containers.forEach((container) => { + const depNames = this.getComponentNames(container); + // eslint-disable-next-line no-param-reassign + container.deps = uniqueArray(depNames, (i: string) => i) + .map((depName) => internalDeps[depName] || compDeps[depName]) + .filter(Boolean); + // container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]); + }); + + // 分析路由配置 + const routes: IRouterInfo['routes'] = containers + .filter((container) => container.containerType === 'Page') + .map((page) => { + const { meta } = page; + if (meta) { + return { + path: (meta as IPageMeta).router || `/${page.fileName}`, // 如果无法找到页面路由信息,则用 fileName 做兜底 + fileName: page.fileName, + componentName: page.moduleName, + }; + } + + return { + path: '', + fileName: page.fileName, + componentName: page.moduleName, + }; + }); + + const routerDeps = routes + .map((r) => internalDeps[r.componentName] || compDeps[r.componentName]) + .filter((dep) => !!dep); + + // 分析 Utils 依赖 + let utils: UtilItem[]; + if (schema.utils) { + utils = schema.utils; + utilsDeps = schema.utils + .filter( + (u): u is { name: string; type: 'npm' | 'tnpm'; content: NpmInfo } => + u.type !== 'function', + ) + .map( + (u): IExternalDependency => ({ + ...u.content, + componentName: u.name, + version: u.content.version || '*', + destructuring: u.content.destructuring ?? false, + exportName: u.content.exportName ?? u.name, + }), + ); + } else { + utils = []; + } + + // 分析项目 npm 依赖 + let npms: INpmPackage[] = []; + containers.forEach((con) => { + const p = (con.deps || []) + .map((dep) => { + return dep.dependencyType === DependencyType.External ? dep : null; + }) + .filter((dep) => dep !== null); + const npmInfos: INpmPackage[] = p.filter(Boolean).map((i) => ({ + package: (i as IExternalDependency).package, + version: (i as IExternalDependency).version, + })); + npms.push(...npmInfos); + }); + + npms.push( + ...utilsDeps.map((utilsDep) => ({ + package: utilsDep.package, + version: utilsDep.version, + })), + ); + + npms = uniqueArray(npms, (i) => i.package).filter(Boolean); + + return { + containers, + globalUtils: { + utils, + deps: utilsDeps, + }, + globalI18n: schema.i18n, + globalRouter: { + routes, + deps: routerDeps, + }, + project: { + css: schema.css, + constants: schema.constants, + config: schema.config || {}, + meta: schema.meta || {}, + i18n: schema.i18n, + containersDeps, + utilsDeps, + packages: npms || [], + }, + }; + } + + getComponentNames(children: NodeDataType): string[] { + return handleSubNodes( + children, + { + node: (i: NodeSchema) => i.componentName, + }, + { + rerun: true, + }, + ); + } + + decodeSchema(schemaSrc: string | ProjectSchema): ProjectSchema { + let schema: ProjectSchema; + if (typeof schemaSrc === 'string') { + try { + schema = JSON.parse(schemaSrc); + } catch (error) { + throw new CodeGeneratorError( + `Parse schema failed: ${getErrorMessage(error) || 'unknown reason'}`, + ); + } + } else { + schema = schemaSrc; + } + return schema; + } +} + +export default SchemaParser; diff --git a/packages/code-generator/src/plugins/common/esmodule.ts b/packages/code-generator/src/plugins/common/esmodule.ts new file mode 100644 index 000000000..02d9128ff --- /dev/null +++ b/packages/code-generator/src/plugins/common/esmodule.ts @@ -0,0 +1,435 @@ +import { COMMON_CHUNK_NAME } from '../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + CodeGeneratorError, + DependencyType, + FileType, + ICodeChunk, + ICodeStruct, + IDependency, + IExternalDependency, + IInternalDependency, + IWithDependency, +} from '../../types'; + +import { isValidIdentifier } from '../../utils/validate'; + +// TODO: main 这个信息到底怎么用,是不是外部包不需要使用? +const DEP_MAIN_BLOCKLIST = ['lib', 'lib/index', 'es', 'es/index', 'main']; +const DEFAULT_EXPORT_NAME = '__default__'; + +function groupDepsByPack(deps: IDependency[]): Record { + const depMap: Record = {}; + + const addDep = (pkg: string, dep: IDependency) => { + if (!depMap[pkg]) { + depMap[pkg] = []; + } + depMap[pkg].push(dep); + }; + + deps.forEach((dep) => { + if (dep.dependencyType === DependencyType.Internal) { + addDep(`${(dep as IInternalDependency).moduleName}${dep.main ? `/${dep.main}` : ''}`, dep); + } else { + let depMain = ''; + // TODO: 部分类型的 main 暂时认为没用 + if (dep.main && DEP_MAIN_BLOCKLIST.indexOf(dep.main) < 0) { + depMain = dep.main; + } + if (depMain.substring(0, 1) === '/') { + depMain = depMain.substring(1); + } + addDep(`${(dep as IExternalDependency).package}${depMain ? `/${depMain}` : ''}`, dep); + } + }); + + return depMap; +} + +interface IDependencyItem { + exportName: string; + aliasName?: string; + isDefault?: boolean; + subName?: string; + nodeIdentifier?: string; // 与使用处的映射关系,理论上是不可变更的,如需变更需要提供额外信息 + source: IDependency; +} + +interface IExportItem { + exportName: string; + aliasNames: string[]; + isDefault?: boolean; + needOriginExport: boolean; +} + +function getDependencyIdentifier(info: IDependencyItem): string { + return info.aliasName || info.exportName; +} + +function buildPackageImport( + pkg: string, + deps: IDependency[], + targetFileType: string, + useAliasName: boolean, +): ICodeChunk[] { + const chunks: ICodeChunk[] = []; + + const exportItems: Record = {}; + const defaultExportNames: string[] = []; + + const depsInfo: IDependencyItem[] = deps.map((dep) => { + const info: IDependencyItem = { + exportName: dep.exportName, + isDefault: !dep.destructuring, + subName: dep.subName || undefined, + nodeIdentifier: dep.componentName || undefined, + source: dep, + }; + + // 下面 5 个逻辑是清理不必要的冗余信息,做到数据结构归一化 + if (info.isDefault) { + if (defaultExportNames.indexOf(info.exportName) < 0) { + defaultExportNames.push(info.exportName); + } + } + + if (!info.subName) { + if (info.nodeIdentifier === info.exportName) { + info.nodeIdentifier = undefined; + } + + if (info.isDefault) { + info.aliasName = info.nodeIdentifier || info.exportName; + info.exportName = DEFAULT_EXPORT_NAME; + } + + if (info.nodeIdentifier) { + info.aliasName = info.nodeIdentifier; + info.nodeIdentifier = undefined; + } + } else { + if (info.isDefault) { + info.aliasName = info.exportName; + info.exportName = DEFAULT_EXPORT_NAME; + } + + if (info.nodeIdentifier === `${info.exportName}.${info.subName}`) { + info.nodeIdentifier = undefined; + } + } + + return info; + }); + + // 建立 export 项目的列表 + depsInfo.forEach((info) => { + if (!exportItems[info.exportName]) { + exportItems[info.exportName] = { + exportName: info.exportName, + isDefault: info.isDefault, + aliasNames: [], + needOriginExport: false, + }; + } + + if (!info.nodeIdentifier && !info.aliasName) { + exportItems[info.exportName].needOriginExport = true; + } + }); + + // 建立别名字典 + depsInfo.forEach((info) => { + if (info.aliasName) { + const { aliasNames } = exportItems[info.exportName]; + if (aliasNames.indexOf(info.aliasName) < 0) { + aliasNames.push(info.aliasName); + } + } + }); + + // fix: 父组件ImportAliasDefine, 与子组件import的父组件冲突情况 + depsInfo.forEach((info) => { + if (info.nodeIdentifier) { + const exportItem = exportItems[info.exportName]; + if (!exportItem.needOriginExport && exportItem.aliasNames.length > 0) { + // eslint-disable-next-line no-param-reassign + info.aliasName = exportItem.aliasNames[0]; + } + } + }); + + // 发现 nodeIdentifier 与 exportName 或者 aliasName 冲突的场景 + const nodeIdentifiers = depsInfo.map((info) => info.nodeIdentifier).filter(Boolean); + const conflictInfos = Object.keys(exportItems) + .map((exportName) => { + const exportItem = exportItems[exportName]; + const usedNames = [ + ...exportItem.aliasNames, + ...(exportItem.needOriginExport || exportItem.aliasNames.length <= 0 ? [exportName] : []), + ]; + const conflictNames = usedNames.filter((n) => nodeIdentifiers.indexOf(n) >= 0); + if (conflictNames.length > 0) { + return [ + ...(conflictNames.indexOf(exportName) >= 0 ? [[exportName, true, exportItem]] : []), + ...conflictNames.filter((n) => n !== exportName).map((n) => [n, false, exportItem]), + ]; + } + return []; + }) + .flat(); + + const conflictExports = conflictInfos.filter((c) => c[1]).map((c) => c[0] as string); + const conflictAlias = conflictInfos.filter((c) => !c[1]).map((c) => c[0] as string); + + const solutions: Record = {}; + + depsInfo.forEach((info) => { + if (info.aliasName && conflictAlias.indexOf(info.aliasName) >= 0) { + // find solution + let solution = solutions[info.aliasName]; + if (!solution) { + solution = `${info.aliasName}Alias`; + const conflictItem = (conflictInfos.find((c) => c[0] === info.aliasName) || + [])[2] as IExportItem; + conflictItem.aliasNames = conflictItem.aliasNames.filter((a) => a !== info.aliasName); + conflictItem.aliasNames.push(solution); + solutions[info.aliasName] = solution; + } + // eslint-disable-next-line no-param-reassign + info.aliasName = solution; + } + + if (conflictExports.indexOf(info.exportName) >= 0) { + // find solution + let solution = solutions[info.exportName]; + if (!solution) { + solution = `${info.exportName}Export`; + const conflictItem = (conflictInfos.find((c) => c[0] === info.exportName) || + [])[2] as IExportItem; + conflictItem.aliasNames.push(solution); + conflictItem.needOriginExport = false; + solutions[info.exportName] = solution; + } + // eslint-disable-next-line no-param-reassign + info.aliasName = solution; + } + }); + + // 判断是否所有依赖都有合法的 Identifier + depsInfo.forEach((info) => { + const name = info.aliasName || info.exportName; + if (!isValidIdentifier(name)) { + throw new CodeGeneratorError(`Invalid Identifier [${name}]`); + } + if (info.nodeIdentifier && !isValidIdentifier(info.nodeIdentifier)) { + throw new CodeGeneratorError(`Invalid Identifier [${info.nodeIdentifier}]`); + } + }); + + const aliasDefineStatements: Record = {}; + if (useAliasName) { + Object.keys(exportItems).forEach((exportName) => { + const aliasList = exportItems[exportName]?.aliasNames || []; + if (aliasList.length > 0) { + const srcName = exportItems[exportName].needOriginExport ? exportName : aliasList[0]; + const aliasNameList = exportItems[exportName].needOriginExport + ? aliasList + : aliasList.slice(1); + aliasNameList.forEach((a) => { + if (!aliasDefineStatements[a]) { + aliasDefineStatements[a] = `const ${a} = ${srcName};`; + } + }); + } + }); + } + + function getDefaultExportName(info: IDependencyItem): string { + if (info.isDefault) { + return defaultExportNames[0]; + } + return info.exportName; + } + + depsInfo.forEach((info) => { + // 如果是子组件,则导出父组件,并且根据自组件命名规则,判断是否需要定义标识符 + if (info.nodeIdentifier) { + // 前提,存在 nodeIdentifier 一定是有 subName 的,不然前面会优化掉 + const ownerName = getDependencyIdentifier(info); + + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ImportAliasDefine, + content: useAliasName ? `const ${info.nodeIdentifier} = ${ownerName}.${info.subName};` : '', + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport], + ext: { + originalName: `${getDefaultExportName(info)}.${info.subName}`, + aliasName: info.nodeIdentifier, + dependency: info.source, + }, + }); + } else if (info.aliasName) { + let contentStatement = ''; + if (aliasDefineStatements[info.aliasName]) { + contentStatement = aliasDefineStatements[info.aliasName]; + delete aliasDefineStatements[info.aliasName]; + } + + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ImportAliasDefine, + content: contentStatement, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport], + ext: { + originalName: getDefaultExportName(info), + aliasName: info.aliasName, + dependency: info.source, + }, + }); + } + }); + + // 可能会剩余一些存在二次转换的定义 + Object.keys(aliasDefineStatements).forEach((a) => { + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ImportAliasDefine, + content: aliasDefineStatements[a], + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport], + }); + }); + + const exportItemList = Object.keys(exportItems).map((k) => exportItems[k]); + const defaultExport = exportItemList.filter((item) => item.isDefault); + const otherExports = exportItemList.filter((item) => !item.isDefault); + + const statementL = ['import']; + if (defaultExport.length > 0) { + if (useAliasName) { + statementL.push(defaultExportNames[0]); + } else { + statementL.push(defaultExport[0].aliasNames[0]); + } + if (otherExports.length > 0) { + statementL.push(', '); + } + } + if (otherExports.length > 0) { + const items = otherExports.map((item) => { + return !useAliasName || item.needOriginExport || item.aliasNames.length <= 0 + ? item.exportName + : `${item.exportName} as ${item.aliasNames[0]}`; + }); + statementL.push(`{ ${items.join(', ')} }`); + } + statementL.push('from'); + + const getInternalDependencyModuleId = () => `@/${(deps[0] as IInternalDependency).type}/${pkg}`; + + if (deps[0].dependencyType === DependencyType.Internal) { + // TODO: Internal Deps path use project slot setting + statementL.push(`'${getInternalDependencyModuleId()}';`); + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: statementL.join(' '), + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + } else { + statementL.push(`'${pkg}';`); + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: statementL.join(' '), + linkAfter: [], + }); + } + + // 处理下一些额外的 default 方式的导入 + if (defaultExportNames.length > 1) { + if (deps[0].dependencyType === DependencyType.Internal) { + defaultExportNames.slice(1).forEach((exportName) => { + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: `import ${exportName} from '${getInternalDependencyModuleId()}';`, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + }); + } else { + defaultExportNames.slice(1).forEach((exportName) => { + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: `import ${exportName} from '${pkg}';`, + linkAfter: [], + }); + + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ImportAliasDefine, + content: '', + linkAfter: [], + ext: { + aliasName: exportName, + originalName: exportName, + dependency: { + package: pkg, + componentName: exportName, + }, + }, + }); + }); + } + } + + return chunks; +} + +export interface PluginConfig { + fileType?: string; // 导出的文件类型 + useAliasName?: boolean; // 是否使用 componentName 重命名组件 identifier +} + +const pluginFactory: BuilderComponentPluginFactory = (config?: PluginConfig) => { + const cfg = { + fileType: FileType.JS, + useAliasName: true, + ...(config || {}), + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IWithDependency; + + if (ir && ir.deps && ir.deps.length > 0) { + const packs = groupDepsByPack(ir.deps); + + Object.keys(packs).forEach((pkg) => { + const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType, cfg.useAliasName); + next.chunks.push(...chunks); + }); + } + + return next; + }; + + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/common/requireUtils.ts b/packages/code-generator/src/plugins/common/requireUtils.ts new file mode 100644 index 000000000..4dacf68e5 --- /dev/null +++ b/packages/code-generator/src/plugins/common/requireUtils.ts @@ -0,0 +1,25 @@ +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 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; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/commonDeps.ts b/packages/code-generator/src/plugins/component/rax/commonDeps.ts new file mode 100644 index 000000000..99285aad8 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/commonDeps.ts @@ -0,0 +1,35 @@ +import { COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../types'; + +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: ` + // 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 + // 例外:rax 框架的导出名和各种组件名除外。 + import { createElement, Component } from 'rax'; + import { getSearchParams as __$$getSearchParams } from 'rax-app'; + `, + linkAfter: [], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/const.ts b/packages/code-generator/src/plugins/component/rax/const.ts new file mode 100644 index 000000000..a0a07b550 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/const.ts @@ -0,0 +1,18 @@ +export const RAX_CHUNK_NAME = { + ClassDidMountBegin: 'RaxComponentClassDidMountBegin', + ClassDidMountContent: 'RaxComponentClassDidMountContent', + ClassDidMountEnd: 'RaxComponentClassDidMountEnd', + ClassWillUnmountBegin: 'RaxComponentClassWillUnmountBegin', + ClassWillUnmountContent: 'RaxComponentClassWillUnmountContent', + ClassWillUnmountEnd: 'RaxComponentClassWillUnmountEnd', + ClassRenderBegin: 'RaxComponentClassRenderBegin', + ClassRenderPre: 'RaxComponentClassRenderPre', + ClassRenderJSX: 'RaxComponentClassRenderJSX', + ClassRenderEnd: 'RaxComponentClassRenderEnd', + MethodsBegin: 'RaxComponentMethodsBegin', + MethodsContent: 'RaxComponentMethodsContent', + MethodsEnd: 'RaxComponentMethodsEnd', + LifeCyclesBegin: 'RaxComponentLifeCyclesBegin', + LifeCyclesContent: 'RaxComponentLifeCyclesContent', + LifeCyclesEnd: 'RaxComponentLifeCyclesEnd', +}; diff --git a/packages/code-generator/src/plugins/component/rax/containerClass.ts b/packages/code-generator/src/plugins/component/rax/containerClass.ts new file mode 100644 index 000000000..6b90f4fff --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerClass.ts @@ -0,0 +1,170 @@ +import changeCase from 'change-case'; +import { + COMMON_CHUNK_NAME, + CLASS_DEFINE_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; +import { RAX_CHUNK_NAME } from './const'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { ensureValidClassName } from '../../../utils/validate'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + // 将模块名转换成 PascalCase 的格式,并添加特定后缀,防止命名冲突 + const componentClassName = ensureValidClassName( + `${changeCase.pascalCase(ir.moduleName)}$$Page`, + ); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.Start, + content: `class ${componentClassName} extends Component {`, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + 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, + CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + RAX_CHUNK_NAME.ClassRenderEnd, + RAX_CHUNK_NAME.MethodsEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorStart, + content: 'constructor(props, context) { super(props); ', + linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + content: '} /* end of constructor */', + linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassDidMountBegin, + content: 'componentDidMount() {', + linkAfter: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.InsVar, + CLASS_DEFINE_CHUNK_NAME.InsMethod, + CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassDidMountEnd, + content: '} /* end of componentDidMount */', + linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin, RAX_CHUNK_NAME.ClassDidMountContent], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassWillUnmountBegin, + content: 'componentWillUnmount() {', + linkAfter: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.InsVar, + CLASS_DEFINE_CHUNK_NAME.InsMethod, + RAX_CHUNK_NAME.ClassDidMountEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassWillUnmountEnd, + content: '} /* end of componentWillUnmount */', + linkAfter: [RAX_CHUNK_NAME.ClassWillUnmountBegin, RAX_CHUNK_NAME.ClassWillUnmountContent], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassRenderBegin, + content: 'render() {', + linkAfter: [RAX_CHUNK_NAME.ClassDidMountEnd, RAX_CHUNK_NAME.ClassWillUnmountEnd], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassRenderEnd, + content: '} /* end of render */', + linkAfter: [ + RAX_CHUNK_NAME.ClassRenderBegin, + RAX_CHUNK_NAME.ClassRenderPre, + RAX_CHUNK_NAME.ClassRenderJSX, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + content: ` + _i18nText(t) { + const locale = this._context.getLocale(); + return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US; + } + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.FileExport, + content: `export default ${componentClassName};`, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + CLASS_DEFINE_CHUNK_NAME.End, + ], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/containerInitState.ts b/packages/code-generator/src/plugins/component/rax/containerInitState.ts new file mode 100644 index 000000000..788a22a39 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerInitState.ts @@ -0,0 +1,66 @@ +import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import Scope from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; + implementType: 'inConstructor' | 'insMember' | 'hooks'; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + implementType: 'insMember', + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const scope = Scope.createRootScope(); + + const state = ir.state || {}; + const fields = Object.keys(state).map((stateName) => { + // TODO: 这里用什么 handlers? + const value = generateCompositeType(state[stateName], scope); + return `${JSON.stringify(stateName)}: ${value}`; + }); + + 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]], + }); + } + // TODO: hooks state?? + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/containerInjectContext.ts b/packages/code-generator/src/plugins/component/rax/containerInjectContext.ts new file mode 100644 index 000000000..149339ec3 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerInjectContext.ts @@ -0,0 +1,134 @@ +/* eslint-disable @typescript-eslint/indent */ +import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { RAX_CHUNK_NAME } from './const'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const useRef = !!ir.analyzeResult?.isUsingRef; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: "import __$$constants from '../../constants';", + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + // TODO: i18n 是可选的,如果没有 i18n 这个文件怎么办?该怎么判断? + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: "import * as __$$i18n from '../../i18n';", + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: ` + _context = this._createContext(); + `, + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + // TODO: 按照目前的实现方案,代码的插拔能力太弱了,需要有一些变化。 + // Step 1: 增加前置的分析器 + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + content: ` + _createContext() { + const self = this; + const context = { + get state() { + return self.state; + }, + setState(newState, callback) { + self.setState(newState, callback); + }, + get dataSourceMap() { + return self._dataSourceEngine.dataSourceMap || {}; + }, + async reloadDataSource() { + await self._dataSourceEngine.reloadDataSource(); + }, + get utils() { + return self._utils; + }, + get page() { + return context; + }, + get component() { + return context; + }, + get props() { + return self.props; + }, + get constants() { + return __$$constants; + }, + i18n: __$$i18n.i18n, + i18nFormat: __$$i18n.i18nFormat, + getLocale: __$$i18n.getLocale, + setLocale(locale) { + __$$i18n.setLocale(locale); + self.forceUpdate(); + },${ + useRef + ? ` + $(refName) { + return self._refsManager.get(refName); + }, + $$(refName) { + return self._refsManager.getAll(refName); + }, + get _refsManager() { + if (!self._refsManager) { + self._refsManager = new RefsManager(); + } + return self._refsManager; + }, + ` + : '' + } + ...this._methods, + }; + + return context; + } + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts b/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts new file mode 100644 index 000000000..8c880246b --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts @@ -0,0 +1,188 @@ +/* eslint-disable @typescript-eslint/indent */ + +import { + CompositeValue, + JSExpression, + InterpretDataSourceConfig, + isJSExpression, + isJSFunction, +} from '@ali/lowcode-types'; +import changeCase from 'change-case'; + +import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator'; +import Scope from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IScope, +} from '../../../types'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser'; +import { isContainerSchema } from '../../../utils/schema'; +import { RaxFrameworkOptions } from '../../project/framework/rax/types/RaxFrameworkOptions'; +import { RAX_CHUNK_NAME } from './const'; + +export interface PluginConfig extends RaxFrameworkOptions { + fileType?: string; + dataSourceHandlersPackageMap?: Record; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + dataSourceHandlersPackageMap: + config?.dataSourceHandlersPackageMap || config?.datasourceConfig?.handlersPackages, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const scope = Scope.createRootScope(); + const dataSourceConfig = isContainerSchema(pre.ir) ? pre.ir.dataSource : null; + const dataSourceItems: InterpretDataSourceConfig[] = + (dataSourceConfig && dataSourceConfig.list) || []; + const dataSourceEngineOptions = { runtimeConfig: true }; + if (dataSourceItems.length > 0) { + const requestHandlersMap: Record = {}; + + dataSourceItems.forEach((ds) => { + const dsType = ds.type || 'fetch'; + if (!(dsType in requestHandlersMap) && dsType !== 'custom') { + const handlerFactoryName = `__$$create${changeCase.pascal(dsType)}RequestHandler`; + + requestHandlersMap[dsType] = { + type: 'JSExpression', + value: `${handlerFactoryName}(${ + dsType === 'urlParams' ? '__$$getSearchParams()' : '' + })`, + }; + + const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`; + const handlerPkgName = + cfg.dataSourceHandlersPackageMap?.[dsType] || + `@ali/lowcode-datasource-${changeCase.kebab(dsType)}-handler`; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: ` + import { ${handlerFactoryExportName} as ${handlerFactoryName} } from '${handlerPkgName}'; + `, + linkAfter: [], + }); + } + }); + + Object.assign(dataSourceEngineOptions, { requestHandlersMap }); + } + + const datasourceEnginePackageName = + cfg.datasourceConfig?.enginePackage || '@ali/lowcode-datasource-engine'; + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: ` + import { create as __$$createDataSourceEngine } from '${datasourceEnginePackageName}/runtime'; + `, + linkAfter: [], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType!, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: ` + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine( + this._dataSourceConfig, + this._context, + ${generateCompositeType(dataSourceEngineOptions, scope)} + );`, + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType!, + name: RAX_CHUNK_NAME.ClassDidMountContent, + content: ` + this._dataSourceEngine.reloadDataSource(); + `, + linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType!, + name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + content: ` +_defineDataSourceConfig() { + const __$$context = this._context; + return (${generateCompositeType( + { + ...dataSourceConfig, + list: [ + ...dataSourceItems.map((item) => ({ + // 数据源引擎默认的 errorHandler 是空的,而且并不会触发组件重新渲染…… + // 这会导致页面状态不能正常展示,故这里处理下: + errorHandler: { + type: 'JSFunction', + value: `function (err){ + setTimeout(() => { + this.setState({ __refresh: Date.now() + Math.random() }); + }, 0); + throw err; + }`, + }, + ...item, + isInit: + typeof item.isInit === 'boolean' || typeof item.isInit === 'undefined' + ? item.isInit ?? true + : wrapAsFunction(item.isInit, scope), + options: wrapAsFunction(item.options, scope), + })), + ], + }, + scope, + { + handlers: { + function: (jsFunc) => parseExpressionConvertThis2Context(jsFunc.value, '__$$context'), + expression: (jsExpr) => parseExpressionConvertThis2Context(jsExpr.value, '__$$context'), + }, + }, + )}); +} + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; + +function wrapAsFunction(value: CompositeValue, scope: IScope): CompositeValue { + if (isJSExpression(value) || isJSFunction(value)) { + return { + type: 'JSExpression', + value: `function(){ return ((${value.value}))}`, + }; + } + + return { + type: 'JSExpression', + value: `function(){return((${generateCompositeType(value, scope)}))}`, + }; +} diff --git a/packages/code-generator/src/plugins/component/rax/containerInjectUtils.ts b/packages/code-generator/src/plugins/component/rax/containerInjectUtils.ts new file mode 100644 index 000000000..32d3f4bb0 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerInjectUtils.ts @@ -0,0 +1,69 @@ +import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { RAX_CHUNK_NAME } from './const'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const useRef = !!ir.analyzeResult?.isUsingRef; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + // TODO: 下面这个路径有没有更好的方式来获取?而非写死 + content: ` + import __$$projectUtils${useRef ? ', { RefsManager }' : ''} from '../../utils'; + `, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: '_utils = this._defineUtils();', + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + + content: ` + _defineUtils() { + return { + ...__$$projectUtils, + }; + }`, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts b/packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts new file mode 100644 index 000000000..b84b96bb2 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts @@ -0,0 +1,144 @@ +import _ from 'lodash'; +import { isJSExpression, isJSFunction } from '@ali/lowcode-types'; + +import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator'; +import { RAX_CHUNK_NAME } from './const'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + FileType, + ChunkType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { debug } from '../../../utils/debug'; + +export interface PluginConfig { + fileType: string; + exportNameMapping: Record; + normalizeNameMapping: Record; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + exportNameMapping: {}, + normalizeNameMapping: { + didMount: 'componentDidMount', + willUnmount: 'componentWillUnmount', + }, + ...config, + }; + + const exportNameMapping = new Map(Object.entries(cfg.exportNameMapping)); + const normalizeNameMapping = new Map(Object.entries(cfg.normalizeNameMapping)); + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + // Rax 先只支持 didMount 和 willUnmount 吧 + + const ir = next.ir as IContainerInfo; + const { lifeCycles } = ir; + + if (lifeCycles && !_.isEmpty(lifeCycles)) { + Object.entries(lifeCycles).forEach(([lifeCycleName, lifeCycleMethodExpr]) => { + // 过滤掉非法数据(有些场景下会误传入空字符串或 null) + if ( + !isJSFunction(lifeCycles[lifeCycleName]) && + !isJSExpression(lifeCycles[lifeCycleName]) + ) { + return; + } + + const normalizeName = normalizeNameMapping.get(lifeCycleName) || lifeCycleName; + const exportName = exportNameMapping.get(lifeCycleName) || lifeCycleName; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.LifeCyclesContent, + content: `${exportName}: (${lifeCycleMethodExpr.value}),`, + linkAfter: [RAX_CHUNK_NAME.LifeCyclesBegin], + }); + + if (normalizeName === 'constructor') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: `this._lifeCycles.${exportName}();`, + linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart], + }); + } else if (normalizeName === 'componentDidMount') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassDidMountContent, + content: `this._lifeCycles.${exportName}();`, + linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin], + }); + } else if (normalizeName === 'componentWillUnmount') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassWillUnmountContent, + content: `this._lifeCycles.${exportName}();`, + linkAfter: [RAX_CHUNK_NAME.ClassWillUnmountBegin], + }); + } else { + debug(`[CodeGen]: unknown life cycle: ${lifeCycleName}`); + } + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: '_lifeCycles = this._defineLifeCycles();', + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.LifeCyclesBegin, + content: ` + _defineLifeCycles() { + const __$$lifeCycles = ({ + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd, CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.LifeCyclesEnd, + content: ` + }); + + // 为所有的方法绑定上下文 + Object.entries(__$$lifeCycles).forEach(([lifeCycleName, lifeCycleMethod]) => { + if (typeof lifeCycleMethod === 'function') { + __$$lifeCycles[lifeCycleName] = (...args) => { + return lifeCycleMethod.apply(this._context, args); + } + } + }); + + return __$$lifeCycles; + } + `, + linkAfter: [RAX_CHUNK_NAME.LifeCyclesBegin, RAX_CHUNK_NAME.LifeCyclesContent], + }); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/containerMethods.ts b/packages/code-generator/src/plugins/component/rax/containerMethods.ts new file mode 100644 index 000000000..6e23dc090 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerMethods.ts @@ -0,0 +1,84 @@ +import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +import { RAX_CHUNK_NAME } from './const'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: ` + _methods = this._defineMethods(); + `, + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.MethodsBegin, + content: ` + _defineMethods() { + return ({ + `, + linkAfter: [ + RAX_CHUNK_NAME.ClassRenderEnd, + CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + RAX_CHUNK_NAME.LifeCyclesEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.MethodsEnd, + content: ` + }); + } + `, + linkAfter: [RAX_CHUNK_NAME.MethodsBegin, RAX_CHUNK_NAME.MethodsContent], + }); + + if (ir.methods && Object.keys(ir.methods).length > 0) { + Object.entries(ir.methods).forEach(([methodName, methodDefine]) => { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.MethodsContent, + content: `${methodName}: (${methodDefine.value}),`, + linkAfter: [RAX_CHUNK_NAME.MethodsBegin], + }); + }); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/jsx.ts b/packages/code-generator/src/plugins/component/rax/jsx.ts new file mode 100644 index 000000000..61b9a8e45 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/jsx.ts @@ -0,0 +1,399 @@ +import { + NodeSchema, + JSExpression, + NpmInfo, + CompositeValue, + isJSExpression, +} from '@ali/lowcode-types'; + +import _ from 'lodash'; +import changeCase from 'change-case'; +import { Expression } from '@babel/types'; +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + CodePiece, + FileType, + ICodeChunk, + ICodeStruct, + IContainerInfo, + PIECE_TYPE, + HandlerSet, + IScope, + NodeGeneratorConfig, + NodePlugin, + AttrPlugin, +} from '../../../types'; + +import { RAX_CHUNK_NAME } from './const'; +import { COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { generateExpression } from '../../../utils/jsExpression'; +import { + createNodeGenerator, + generateConditionReactCtrl, + generateReactExprInJS, +} from '../../../utils/nodeToJSX'; +import { generateCompositeType } from '../../../utils/compositeType'; +import Scope from '../../../utils/Scope'; +import { + parseExpression, + parseExpressionConvertThis2Context, + parseExpressionGetGlobalVariables, +} from '../../../utils/expressionParser'; + +export interface PluginConfig { + fileType: string; + + /** 是否要忽略小程序 */ + ignoreMiniApp?: boolean; +} + +// TODO: componentName 若并非大写字符打头,甚至并非是一个有效的 JS 标识符怎么办?? +// FIXME: 我想了下,这块应该放到解析阶段就去做掉,对所有 componentName 做 identifier validate,然后对不合法的做统一替换。 +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const rootScope = Scope.createRootScope(); + + // Rax 构建到小程序的时候,不能给组件起起别名,得直接引用,故这里将所有的别名替换掉 + // 先收集下所有的 alias 的映射 + const componentsNameAliasMap = new Map(); + next.chunks.forEach((chunk) => { + if (isImportAliasDefineChunk(chunk)) { + componentsNameAliasMap.set(chunk.ext.aliasName, chunk.ext.originalName); + } + }); + + // 注意:这里其实隐含了一个假设:schema 中的 componentName 应该是一个有效的 JS 标识符,而且是大写字母打头的 + // FIXME: 为了快速修复临时加的逻辑,需要用 pre-process 的方式替代处理。 + const mapComponentNameToAliasOrKeepIt = (componentName: string) => + componentsNameAliasMap.get(componentName) || componentName; + + // 然后过滤掉所有的别名 chunks + next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk)); + + // 如果直接按目前的 React 的方式之间出码 JSX 的话,会有 3 个问题: + // 1. 小程序出码的时候,循环变量没法拿到 + // 2. 小程序出码的时候,很容易出现 Uncaught TypeError: Cannot read property 'avatar' of undefined 这样的异常(如下图的 50 行) -- 因为若直接出码,Rax 构建到小程序的时候会立即计算所有在视图中用到的变量 + // 3. 通过 this.xxx 能拿到的东西太多了,而且自定义的 methods 可能会无意间破坏 Rax 框架或小程序框架在页面 this 上的东东 + const customHandlers: HandlerSet = { + expression(input: JSExpression, scope: IScope) { + return transformJsExpr(generateExpression(input, scope), scope); + }, + function(input, scope: IScope) { + return transformThis2Context(input.value || 'null', scope); + }, + }; + + // 创建代码生成器 + const commonNodeGenerator = createNodeGenerator({ + handlers: customHandlers, + tagMapping: mapComponentNameToAliasOrKeepIt, + nodePlugins: [generateReactExprInJS, generateConditionReactCtrl, generateRaxLoopCtrl], + attrPlugins: [generateNodeAttrForRax.bind({ cfg })], + }); + + // 生成 JSX 代码 + const jsxContent = commonNodeGenerator(ir, rootScope); + + if (!cfg.ignoreMiniApp) { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: "import { isMiniApp as __$$isMiniApp } from 'universal-env';", + linkAfter: [], + }); + } + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassRenderPre, + // TODO: setState, dataSourceMap, reloadDataSource, utils, i18n, i18nFormat, getLocale, setLocale 这些在 Rax 的编译模式下不能在视图中直接访问,需要转化成 this.xxx + content: ` + const __$$context = this._context; + const { state, setState, dataSourceMap, reloadDataSource, utils, constants, i18n, i18nFormat, getLocale, setLocale } = __$$context; + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassRenderJSX, + content: `return ${jsxContent};`, + linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin, RAX_CHUNK_NAME.ClassRenderPre], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.CustomContent, + content: ` + + function __$$eval(expr) { + try { + return expr(); + } catch (err) { + try { + if (window.handleEvalError) { + window.handleEvalError('Failed to evaluate: ', expr, err); + } + } catch (e) {} + } + } + + function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; + } + + function __$$createChildContext(oldContext, ext) { + return Object.assign({}, oldContext, ext); + } + + `, + linkAfter: [COMMON_CHUNK_NAME.FileExport], + }); + + return next; + }; + + return plugin; +}; + +export default pluginFactory; + +function transformJsExpr(expr: string, scope: IScope) { + if (!expr) { + return 'undefined'; + } + + if (isLiteralAtomicExpr(expr)) { + return expr; + } + + const exprAst = parseExpression(expr); + + // 对于下面这些比较安全的字面值,可以直接返回对应的表达式,而非包一层 + if (isSimpleStraightLiteral(exprAst)) { + return expr; + } + + switch (exprAst.type) { + // 对于直接写个函数的,则不用再包下,因为这样不会抛出异常的 + case 'ArrowFunctionExpression': + case 'FunctionExpression': + return transformThis2Context(exprAst, scope); + + default: + break; + } + + // 其他的都需要包一层 + return `__$$eval(() => (${transformThis2Context(exprAst, scope)}))`; +} + +/** 判断是非是一些简单直接的字面值 */ +function isSimpleStraightLiteral(expr: Expression): boolean { + switch (expr.type) { + case 'BigIntLiteral': + case 'BooleanLiteral': + case 'DecimalLiteral': + case 'NullLiteral': + case 'NumericLiteral': + case 'RegExpLiteral': + case 'StringLiteral': + return true; + default: + return false; + } +} + +function isImportAliasDefineChunk(chunk: ICodeChunk): chunk is ICodeChunk & { + ext: { + aliasName: string; + originalName: string; + dependency: NpmInfo; + }; +} { + return ( + chunk.name === COMMON_CHUNK_NAME.ImportAliasDefine && + !!chunk.ext && + typeof chunk.ext.aliasName === 'string' && + typeof chunk.ext.originalName === 'string' && + !!(chunk.ext.dependency as NpmInfo | null)?.componentName + ); +} + +/** + * 判断是否是原子类型的表达式 + */ +function isLiteralAtomicExpr(expr: string): boolean { + return ( + expr === 'null' || + expr === 'undefined' || + expr === 'true' || + expr === 'false' || + /^-?\d+(\.\d+)?$/.test(expr) + ); +} + +/** + * 将所有的 this.xxx 替换为 __$$context.xxx + * @param expr + */ +function transformThis2Context(expr: string | Expression, scope: IScope): string { + // 下面这种字符串替换的方式虽然简单直接,但是对于复杂场景会误匹配,故后期改成了解析 AST 然后修改 AST 最后再重新生成代码的方式 + // return expr + // .replace(/\bthis\.item\./g, () => 'item.') + // .replace(/\bthis\.index\./g, () => 'index.') + // .replace(/\bthis\./g, () => '__$$context.'); + + return parseExpressionConvertThis2Context( + expr, + '__$$context', + scope.bindings?.getAllBindings() || [], + ); +} + +function generateRaxLoopCtrl( + nodeItem: NodeSchema, + scope: IScope, + config?: NodeGeneratorConfig, + next?: NodePlugin, +): CodePiece[] { + if (nodeItem.loop) { + const loopItemName = nodeItem.loopArgs?.[0] || 'item'; + const loopIndexName = nodeItem.loopArgs?.[1] || 'index'; + const subScope = scope.createSubScope([loopItemName, loopIndexName]); + const pieces: CodePiece[] = next ? next(nodeItem, subScope, config) : []; + + const loopDataExpr = `__$$evalArray(() => (${transformThis2Context( + generateCompositeType(nodeItem.loop, scope, { handlers: config?.handlers }), + scope, + )}))`; + + pieces.unshift({ + value: `${loopDataExpr}.map((${loopItemName}, ${loopIndexName}) => ((__$$context) => (`, + type: PIECE_TYPE.BEFORE, + }); + + pieces.push({ + value: `))(__$$createChildContext(__$$context, { ${loopItemName}, ${loopIndexName} })))`, + type: PIECE_TYPE.AFTER, + }); + + return pieces; + } + + return next ? next(nodeItem, scope, config) : []; +} + +function generateNodeAttrForRax( + this: { cfg: PluginConfig }, + attrData: { attrName: string; attrValue: CompositeValue }, + scope: IScope, + config?: NodeGeneratorConfig, + next?: AttrPlugin, +): CodePiece[] { + if (!this.cfg.ignoreMiniApp && /^on/.test(attrData.attrName)) { + // else: onXxx 的都是事件处理函数需要特殊处理下 + return generateEventHandlerAttrForRax(attrData.attrName, attrData.attrValue, scope, config); + } + + if (attrData.attrName === 'ref') { + return [ + { + name: attrData.attrName, + value: `__$$context._refsManager.linkRef('${attrData.attrValue}')`, + type: PIECE_TYPE.ATTR, + }, + ]; + } + + return next ? next(attrData, scope, config) : []; +} + +function generateEventHandlerAttrForRax( + attrName: string, + attrValue: CompositeValue, + scope: IScope, + config?: NodeGeneratorConfig, +): CodePiece[] { + // -- 事件处理函数中 JSExpression 转成 JSFunction 来处理,避免当 JSExpression 处理的时候多包一层 eval 而导致 Rax 转码成小程序的时候出问题 + const valueExpr = generateCompositeType( + isJSExpression(attrValue) ? { type: 'JSFunction', value: attrValue.value } : attrValue, + scope, + { + handlers: config?.handlers, + }, + ); + + // 查询当前作用域下的变量 + const currentScopeVariables = scope.bindings?.getAllBindings() || []; + if (currentScopeVariables.length <= 0) { + return [ + { + type: PIECE_TYPE.ATTR, + name: attrName, + value: valueExpr, + }, + ]; + } + + // 提取出所有的未定义的全局变量 + const undeclaredVariablesInValueExpr = parseExpressionGetGlobalVariables(valueExpr); + const referencedLocalVariables = _.intersection( + undeclaredVariablesInValueExpr, + currentScopeVariables, + ); + if (referencedLocalVariables.length <= 0) { + return [ + { + type: PIECE_TYPE.ATTR, + name: attrName, + value: valueExpr, + }, + ]; + } + + const wrappedAttrValueExpr = [ + '(...__$$args) => {', + ' if (__$$isMiniApp) {', + ' const __$$event = __$$args[0];', + ...referencedLocalVariables.map( + (localVar) => `const ${localVar} = __$$event.target.dataset.${localVar};`, + ), + ` return (${valueExpr}).apply(this, __$$args);`, + ' } else {', + ` return (${valueExpr}).apply(this, __$$args);`, + ' }', + '}', + ].join('\n'); + + return [ + ...referencedLocalVariables.map((localVar) => ({ + type: PIECE_TYPE.ATTR, + name: `data-${changeCase.snake(localVar)}`, + value: localVar, + })), + { + type: PIECE_TYPE.ATTR, + name: attrName, + value: wrappedAttrValueExpr, + }, + ]; +} diff --git a/packages/code-generator/src/plugins/component/react/const.ts b/packages/code-generator/src/plugins/component/react/const.ts new file mode 100644 index 000000000..629466827 --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/const.ts @@ -0,0 +1,9 @@ +export const REACT_CHUNK_NAME = { + ClassRenderStart: 'ReactComponentClassRenderStart', + ClassRenderPre: 'ReactComponentClassRenderPre', + ClassRenderEnd: 'ReactComponentClassRenderEnd', + ClassRenderJSX: 'ReactComponentClassRenderJSX', + 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 new file mode 100644 index 000000000..0758c893e --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/containerClass.ts @@ -0,0 +1,133 @@ +import changeCase from 'change-case'; +import { + COMMON_CHUNK_NAME, + CLASS_DEFINE_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; +import { REACT_CHUNK_NAME } from './const'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { ensureValidClassName } from '../../../utils/validate'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + // 将模块名转换成 PascalCase 的格式,并添加特定后缀,防止命名冲突 + const componentClassName = ensureValidClassName( + `${changeCase.pascalCase(ir.moduleName)}$$Page`, + ); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.Start, + content: `class ${componentClassName} extends React.Component {`, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + 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: [ + ...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End], + REACT_CHUNK_NAME.ClassRenderEnd, + REACT_CHUNK_NAME.ClassDidMountEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorStart, + content: 'constructor(props, context) { super(props); ', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + content: '}', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: REACT_CHUNK_NAME.ClassDidMountStart, + content: 'componentDidMount() {', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: REACT_CHUNK_NAME.ClassDidMountEnd, + content: '}', + linkAfter: [REACT_CHUNK_NAME.ClassDidMountContent, REACT_CHUNK_NAME.ClassDidMountStart], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: REACT_CHUNK_NAME.ClassRenderStart, + content: 'render() {', + linkAfter: [ + ...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End], + REACT_CHUNK_NAME.ClassDidMountEnd, + ], + }); + + 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 ${componentClassName};`, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + CLASS_DEFINE_CHUNK_NAME.End, + ], + }); + + return next; + }; + return 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 new file mode 100644 index 000000000..19fd830ed --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/containerInitState.ts @@ -0,0 +1,63 @@ +import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import Scope from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; + implementType: 'inConstructor' | 'insMember' | 'hooks'; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + implementType: 'inConstructor', + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const scope = Scope.createRootScope(); + + const state = ir.state || {}; + const fields = Object.keys(state).map((stateName) => { + const value = generateCompositeType(state[stateName], scope); + return `${stateName}: ${value},`; + }); + + 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 pluginFactory; diff --git a/packages/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts b/packages/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts new file mode 100644 index 000000000..5ed02db41 --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts @@ -0,0 +1,179 @@ +/* eslint-disable @typescript-eslint/indent */ + +import { + CompositeValue, + JSExpression, + InterpretDataSourceConfig, + isJSExpression, + isJSFunction, +} from '@ali/lowcode-types'; +import changeCase from 'change-case'; + +import { + CLASS_DEFINE_CHUNK_NAME, + COMMON_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; +import Scope from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IScope, +} from '../../../types'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser'; +import { isContainerSchema } from '../../../utils/schema'; +import { REACT_CHUNK_NAME } from './const'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const scope = Scope.createRootScope(); + const dataSourceConfig = isContainerSchema(pre.ir) ? pre.ir.dataSource : null; + const dataSourceItems: InterpretDataSourceConfig[] = + (dataSourceConfig && dataSourceConfig.list) || []; + const dataSourceEngineOptions = { runtimeConfig: true }; + if (dataSourceItems.length > 0) { + const requestHandlersMap: Record = {}; + + dataSourceItems.forEach((ds) => { + const dsType = ds.type || 'fetch'; + if (!(dsType in requestHandlersMap) && dsType !== 'custom') { + const handlerFactoryName = `__$$create${changeCase.pascal(dsType)}RequestHandler`; + + requestHandlersMap[dsType] = { + type: 'JSExpression', + value: + handlerFactoryName + (dsType === 'urlParams' ? '(window.location.search)' : '()'), + }; + + const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`; + const handlerPkgName = `@ali/lowcode-datasource-${changeCase.kebab(dsType)}-handler`; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: ` + import { ${handlerFactoryExportName} as ${handlerFactoryName} } from '${handlerPkgName}'; + `, + linkAfter: [], + }); + } + }); + + Object.assign(dataSourceEngineOptions, { requestHandlersMap }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: ` + import { create as __$$createDataSourceEngine } from '@ali/lowcode-datasource-engine/runtime'; + `, + linkAfter: [], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: ` + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine( + this._dataSourceConfig, + this, + ${generateCompositeType(dataSourceEngineOptions, scope)} + ); + + get dataSourceMap() { + return this._dataSourceEngine.dataSourceMap || {}; + } + + reloadDataSource = async () => { + await this._dataSourceEngine.reloadDataSource(); + } + + `, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]], + }); + + next.chunks.unshift({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: REACT_CHUNK_NAME.ClassDidMountContent, + content: ` + this._dataSourceEngine.reloadDataSource(); + `, + linkAfter: [REACT_CHUNK_NAME.ClassDidMountStart], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: ` + _defineDataSourceConfig() { + const _this = this; + return (${generateCompositeType( + { + ...dataSourceConfig, + list: [ + ...dataSourceItems.map((item) => ({ + ...item, + isInit: wrapAsFunction(item.isInit, scope), + options: wrapAsFunction(item.options, scope), + })), + ], + }, + scope, + { + handlers: { + function: (jsFunc) => parseExpressionConvertThis2Context(jsFunc.value, '_this'), + expression: (jsExpr) => parseExpressionConvertThis2Context(jsExpr.value, '_this'), + }, + }, + )}); + } + `, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; + +function wrapAsFunction(value: CompositeValue, scope: IScope): CompositeValue { + if (isJSExpression(value) || isJSFunction(value)) { + return { + type: 'JSExpression', + value: `function(){ return ((${value.value}))}`, + }; + } + + return { + type: 'JSExpression', + value: `function(){return((${generateCompositeType(value, scope)}))}`, + }; +} diff --git a/packages/code-generator/src/plugins/component/react/containerInjectI18n.ts b/packages/code-generator/src/plugins/component/react/containerInjectI18n.ts new file mode 100644 index 000000000..6a6c39e05 --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/containerInjectI18n.ts @@ -0,0 +1,58 @@ +import { + CLASS_DEFINE_CHUNK_NAME, + COMMON_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + // TODO: 下面这个路径有没有更好的方式来获取?而非写死 + content: ` + import { i18n as _$$i18n } from '../../i18n'; + `, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: ` + i18n = (i18nKey) => { + return _$$i18n(i18nKey); + } + `, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }); + + return next; + }; + return 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 new file mode 100644 index 000000000..09da40220 --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts @@ -0,0 +1,93 @@ +import { + CLASS_DEFINE_CHUNK_NAME, + COMMON_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + next.contextData.useRefApi = true; + const useRef = !!ir.analyzeResult?.isUsingRef; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + // TODO: 下面这个路径有没有更好的方式来获取?而非写死 + content: ` + import utils${useRef ? ', { RefsManager }' : ''} from '../../utils'; + `, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + 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], + }); + + if (useRef) { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: 'this._refsManager = new RefsManager();', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: ` + $ = (refName) => { + return this._refsManager.get(refName); + } + `, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: ` + $$ = (refName) => { + return this._refsManager.getAll(refName); + } + `, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }); + } + + return next; + }; + return 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 new file mode 100644 index 000000000..2f2a2eb3e --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts @@ -0,0 +1,108 @@ +import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; +import { REACT_CHUNK_NAME } from './const'; + +import { generateFunction } from '../../../utils/jsExpression'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeChunk, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { isJSFunction, isJSExpression } from '@ali/lowcode-types'; + +export interface PluginConfig { + fileType: string; + exportNameMapping: Record; + normalizeNameMapping: Record; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + exportNameMapping: {}, + normalizeNameMapping: {}, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + if (ir.lifeCycles) { + const { lifeCycles } = ir; + const chunks = Object.keys(lifeCycles).map((lifeCycleName) => { + // 过滤掉非法数据(有些场景下会误传入空字符串或 null) + if ( + !isJSFunction(lifeCycles[lifeCycleName]) && + !isJSExpression(lifeCycles[lifeCycleName]) + ) { + return null; + } + + let normalizeName; + // constructor会取到对象的构造函数 + if (lifeCycleName === 'constructor') { + normalizeName = lifeCycleName; + } else { + 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: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }), + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]], + }; + } + + if (normalizeName === 'componentDidMount') { + return { + type: ChunkType.STRING, + fileType: cfg.fileType, + name: REACT_CHUNK_NAME.ClassDidMountContent, + content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }), + linkAfter: [REACT_CHUNK_NAME.ClassDidMountStart], + }; + } + + if (normalizeName === 'render') { + return { + type: ChunkType.STRING, + fileType: cfg.fileType, + name: REACT_CHUNK_NAME.ClassRenderPre, + content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }), + linkAfter: [REACT_CHUNK_NAME.ClassRenderStart], + }; + } + + return { + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: generateFunction(lifeCycles[lifeCycleName], { + name: exportName, + isMember: true, + }), + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }; + }); + + next.chunks.push(...chunks.filter((x): x is ICodeChunk => x !== null)); + } + + return next; + }; + return 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 new file mode 100644 index 000000000..b44b9a74b --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/containerMethod.ts @@ -0,0 +1,50 @@ +import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; + +import { generateFunction } from '../../../utils/jsExpression'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeChunk, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + if (ir.methods) { + const { methods } = ir; + const chunks = Object.keys(methods).map((methodName) => ({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: generateFunction(methods[methodName], { name: methodName, isMember: true }), + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + })); + + next.chunks.push(...chunks); + } + + return next; + }; + return 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 new file mode 100644 index 000000000..201b77260 --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/jsx.ts @@ -0,0 +1,95 @@ +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, + IScope, + NodeGeneratorConfig, + PIECE_TYPE, +} from '../../../types'; + +import { REACT_CHUNK_NAME } from './const'; +import { COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { createReactNodeGenerator } from '../../../utils/nodeToJSX'; +import Scope from '../../../utils/Scope'; + +export interface PluginConfig { + fileType?: string; + nodeTypeMapping?: Record; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg = { + fileType: FileType.JSX, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + nodeTypeMapping: {} as Record, + ...config, + }; + + const { nodeTypeMapping } = cfg; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const generatorPlugins: NodeGeneratorConfig = { + tagMapping: (v) => nodeTypeMapping[v] || v, + }; + + if (next.contextData.useRefApi) { + generatorPlugins.attrPlugins = [ + (attrData, scope, pluginCfg, nextFunc) => { + if (attrData.attrName === 'ref') { + return [ + { + name: attrData.attrName, + value: `this._refsManager.linkRef('${attrData.attrValue}')`, + type: PIECE_TYPE.ATTR, + }, + ]; + } + + return nextFunc ? nextFunc(attrData, scope, pluginCfg) : []; + }, + ]; + } + + const generator = createReactNodeGenerator(generatorPlugins); + + const ir = next.ir as IContainerInfo; + const scope: IScope = Scope.createRootScope(); + const jsxContent = generator(ir, scope); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: REACT_CHUNK_NAME.ClassRenderJSX, + content: ` + const __$$context = this; + return ${jsxContent}; + `, + linkAfter: [REACT_CHUNK_NAME.ClassRenderStart, REACT_CHUNK_NAME.ClassRenderPre], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.CustomContent, + content: ` + function __$$createChildContext(oldContext, ext) { + return Object.assign({}, oldContext, ext); + } + + `, + linkAfter: [COMMON_CHUNK_NAME.FileExport], + }); + return next; + }; + return 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 new file mode 100644 index 000000000..2e71f8d90 --- /dev/null +++ b/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts @@ -0,0 +1,30 @@ +import { COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../types'; + +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; + }; + 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 new file mode 100644 index 000000000..4ef94fdd7 --- /dev/null +++ b/packages/code-generator/src/plugins/component/style/css.ts @@ -0,0 +1,52 @@ +import { COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; + moduleFileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.CSS, + moduleFileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.StyleCssContent, + content: ir.css, + linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport], + }); + + 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 pluginFactory; diff --git a/packages/code-generator/src/plugins/project/constants.ts b/packages/code-generator/src/plugins/project/constants.ts new file mode 100644 index 000000000..08870e507 --- /dev/null +++ b/packages/code-generator/src/plugins/project/constants.ts @@ -0,0 +1,59 @@ +import { COMMON_CHUNK_NAME } from '../../const/generator'; +import { generateCompositeType } from '../../utils/compositeType'; +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../types'; +import Scope from '../../utils/Scope'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IProjectInfo; + const scope = Scope.createRootScope(); + const constantStr = generateCompositeType(ir.constants || {}, scope); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.FileVarDefine, + content: ` + const __$$constants = (${constantStr}); + `, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.FileExport, + content: ` + export default __$$constants; + `, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + COMMON_CHUNK_NAME.FileMainContent, + ], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/project/framework/icejs/index.ts b/packages/code-generator/src/plugins/project/framework/icejs/index.ts new file mode 100644 index 000000000..e9c8f255f --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/index.ts @@ -0,0 +1,17 @@ +import template from './template'; +import entry from './plugins/entry'; +import entryHtml from './plugins/entryHtml'; +import globalStyle from './plugins/globalStyle'; +import packageJSON from './plugins/packageJSON'; +import router from './plugins/router'; + +export default { + template, + plugins: { + entry, + entryHtml, + globalStyle, + packageJSON, + router, + }, +}; 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 new file mode 100644 index 000000000..b5dc2d8f8 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts @@ -0,0 +1,56 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../../../types'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + 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: 'app', + }, + router: { + type: 'hash', + }, + }; + createApp(appConfig); + `, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + ], + }); + + return next; + }; + return 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 new file mode 100644 index 000000000..e5837a8dd --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts @@ -0,0 +1,46 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../../../../types'; + +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 || 'Ice App'} + + +
+ + + `, + linkAfter: [], + }); + + return next; + }; + return 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 new file mode 100644 index 000000000..3daaeecdc --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts @@ -0,0 +1,56 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../../../../types'; + +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; + }; + return 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 new file mode 100644 index 000000000..9ca0b6a43 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts @@ -0,0 +1,101 @@ +import { PackageJSON } from '@ali/lowcode-types'; + +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../../../../types'; + +interface IIceJsPackageJSON extends PackageJSON { + ideMode: { + name: string; + }; + iceworks: { + type: string; + adapter: string; + }; + originTemplate: string; +} + +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', + '@ali/lowcode-datasource-engine': '*', + // TODO: 如何动态获取下面这些依赖? + '@ali/lowcode-datasource-url-params-handler': '*', + '@ali/lowcode-datasource-fetch-handler': '*', + '@ali/lowcode-datasource-mtop-handler': '*', + '@ali/lowcode-datasource-mopen-handler': '*', + 'intl-messageformat': '^9.3.6', + }, + 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', + }; + + ir.packages.forEach((packageInfo) => { + packageJson.dependencies[packageInfo.package] = packageInfo.version; + }); + + next.chunks.push({ + type: ChunkType.JSON, + fileType: FileType.JSON, + name: COMMON_CHUNK_NAME.FileMainContent, + content: packageJson, + linkAfter: [], + }); + + return next; + }; + return 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 new file mode 100644 index 000000000..0e2e8c1f7 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts @@ -0,0 +1,84 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IRouterInfo, +} from '../../../../../types'; + +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.ImportAliasDefine, + 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.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileMainContent, + ], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts new file mode 100644 index 000000000..1fb96bec0 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts @@ -0,0 +1,73 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'README', + 'md', + ` +## Scaffold Lite + +> 轻量级模板,使用 JavaScript,仅包含基础的 Layout。 + +## 使用 + +\`\`\`bash +# 安装依赖 +$ npm install + +# 启动服务 +$ npm start # visit http://localhost:3333 +\`\`\` + +[More docs](https://ice.work/docs/guide/about). + +## 目录 + +\`\`\`md +├── build/ # 构建产物 +├── mock/ # 本地模拟数据 +│ ├── index.[j,t]s +├── public/ +│ ├── index.html # 应用入口 HTML +│ └── favicon.png # Favicon +├── src/ # 源码路径 +│ ├── components/ # 自定义业务组件 +│ │ └── Guide/ +│ │ ├── index.[j,t]sx +│ │ ├── index.module.scss +│ ├── layouts/ # 布局组件 +│ │ └── BasicLayout/ +│ │ ├── index.[j,t]sx +│ │ └── index.module.scss +│ ├── pages/ # 页面 +│ │ └── Home/ # home 页面,约定路由转成小写 +│ │ ├── components/ # 页面级自定义业务组件 +│ │ ├── models.[j,t]sx # 页面级数据状态 +│ │ ├── index.[j,t]sx # 页面入口 +│ │ └── index.module.scss # 页面样式文件 +│ ├── configs/ # [可选] 配置文件 +│ │ └── menu.[j,t]s # [可选] 菜单配置 +│ ├── models/ # [可选] 应用级数据状态 +│ │ └── user.[j,t]s +│ ├── utils/ # [可选] 工具库 +│ ├── global.scss # 全局样式 +│ ├── routes.[j,t]s # 路由配置 +│ └── app.[j,t]s[x] # 应用入口脚本 +├── build.json # 工程配置 +├── README.md +├── package.json +├── .editorconfig +├── .eslintignore +├── .eslintrc.[j,t]s +├── .gitignore +├── .stylelintignore +├── .stylelintrc.[j,t]s +├── .gitignore +└── [j,t]sconfig.json +\`\`\` + `, + ); + + return [[], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts new file mode 100644 index 000000000..0f9e8a532 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts @@ -0,0 +1,17 @@ +import { ResultFile } from '@ali/lowcode-types'; + +export default function getFile(): [string[], ResultFile] { + return [ + [], + { + name: 'abc', + ext: 'json', + content: ` +{ + "type": "ice-app", + "builder": "@ali/builder-ice-app" +} + `, + }, + ]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts new file mode 100644 index 000000000..533aea2ad --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts @@ -0,0 +1,33 @@ +import { ResultFile } from '@ali/lowcode-types'; + +export default function getFile(): [string[], ResultFile] { + return [ + [], + { + name: 'build', + ext: 'json', + content: ` +{ + "entry": "src/app.js", + "plugins": [ + [ + "build-plugin-fusion", + { + "themePackage": "@alifd/theme-design-pro" + } + ], + [ + "build-plugin-moment-locales", + { + "locales": [ + "zh-cn" + ] + } + ], + "@ali/build-plugin-ice-def" + ] +} + `, + }, + ]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts new file mode 100644 index 000000000..bf80464dd --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts @@ -0,0 +1,25 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + '.editorconfig', + '', + ` +# 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 + `, + ); + + return [[], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts new file mode 100644 index 000000000..a26db9de1 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts @@ -0,0 +1,28 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + '.eslintignore', + '', + ` +# 忽略目录 +build/ +tests/ +demo/ +.ice/ + +# node 覆盖率文件 +coverage/ + +# 忽略文件 +**/*-min.js +**/*.min.js + +package-lock.json +yarn.lock + `, + ); + + return [[], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts new file mode 100644 index 000000000..733c3e174 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts @@ -0,0 +1,16 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + '.eslintrc', + 'js', + ` +const { eslint } = require('@ice/spec'); + +module.exports = eslint; + `, + ); + + return [[], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts new file mode 100644 index 000000000..408a93205 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts @@ -0,0 +1,36 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + '.gitignore', + '', + ` +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + `, + ); + + return [[], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts new file mode 100644 index 000000000..cde81c77f --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts @@ -0,0 +1,24 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'jsconfig', + 'json', + ` +{ + "compilerOptions": { + "baseUrl": ".", + "jsx": "react", + "paths": { + "@/*": ["./src/*"], + "ice": [".ice/index.ts"], + "ice/*": [".ice/pages/*"] + } + } +} + `, + ); + + return [[], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts new file mode 100644 index 000000000..6206dca28 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts @@ -0,0 +1,22 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + '.prettierignore', + '', + ` +build/ +tests/ +demo/ +.ice/ +coverage/ +**/*-min.js +**/*.min.js +package-lock.json +yarn.lock + `, + ); + + return [[], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts new file mode 100644 index 000000000..1793891ed --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts @@ -0,0 +1,16 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + '.prettierrc', + 'js', + ` +const { prettier } = require('@ice/spec'); + +module.exports = prettier; + `, + ); + + return [[], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts new file mode 100644 index 000000000..131728077 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts @@ -0,0 +1,25 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'jsx', + ` +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( +

+ Alibaba Fusion +
+ © 2019-现在 Alibaba Fusion & ICE +

+ ); +} + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts new file mode 100644 index 000000000..5093a4cf9 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts @@ -0,0 +1,26 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'module.scss', + ` +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts new file mode 100644 index 000000000..efb8377ed --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts @@ -0,0 +1,27 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'jsx', + ` +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( +
+ + {image && logo} + {text} + +
+ ); +} + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts new file mode 100644 index 000000000..ebbf1e453 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts @@ -0,0 +1,31 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'module.scss', + ` +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts new file mode 100644 index 000000000..302d16d71 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts @@ -0,0 +1,81 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'jsx', + ` +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, withRouter } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + + {childrenItems} + + ); + return subNav; + } + + return null; + } + + const navItem = ( + + {item.name} + + ); + return navItem; +} + +const Navigation = (props, context) => { + const { location } = props; + const { pathname } = location; + const { isCollapse } = context; + return ( + + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +const PageNav = withRouter(Navigation); +export default PageNav; + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'PageNav'], file]; +} diff --git a/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts new file mode 100644 index 000000000..8a97f76d8 --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts @@ -0,0 +1,92 @@ +import { ResultFile } from '@ali/lowcode-types'; +import { createResultFile } from '../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'jsx', + ` +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + + + + + + + + + + + + {children} + +