diff --git a/.gitignore b/.gitignore index 6a19ae3e0c..cb875f7f7a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,8 @@ packages/*/dist/ packages/*/output/ packages/demo/ package-lock.json -yarn.lock pnpm-lock.yaml +yarn.lock deploy-space/packages deploy-space/.env @@ -16,6 +16,7 @@ deploy-space/.env # IDE .vscode .idea +.npmrc # Logs logs @@ -109,4 +110,4 @@ typings/ codealike.json .node -.must.config.js \ No newline at end of file +.must.config.js diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index a089167a78..0000000000 --- a/babel.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: [ - ['@babel/plugin-proposal-decorators', { legacy: true }], - [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }], - ], -}; \ No newline at end of file diff --git a/deploy-space/lerna.json b/deploy-space/lerna.json index 31d37d2d38..6e93aa0baf 100644 --- a/deploy-space/lerna.json +++ b/deploy-space/lerna.json @@ -1,6 +1,6 @@ { "version": "independent", - "npmClient": "yarn", + "npmClient": "pnpm", "registry": "http://registry.npm.alibaba-inc.com", "useWorkspaces": true, "packages": [ diff --git a/docs/docs/api/setters.md b/docs/docs/api/setters.md index 9b3c9d705d..4e1eac744f 100644 --- a/docs/docs/api/setters.md +++ b/docs/docs/api/setters.md @@ -73,7 +73,7 @@ registerSetter( ```typescript import { setters, skeleton } from '@felce/lowcode-engine'; -import { setterMap, pluginMap } from '@alilc/lowcode-engine-ext'; +import { setterMap, pluginMap } from '@felce/lowcode-engine-ext'; import { IPublicModelPluginContext } from '@felce/lowcode-types'; const SetterRegistry = (ctx: IPublicModelPluginContext) => { diff --git a/docs/docs/faq/faq017.md b/docs/docs/faq/faq017.md index f2c7afa273..33f9576bf7 100644 --- a/docs/docs/faq/faq017.md +++ b/docs/docs/faq/faq017.md @@ -3,9 +3,7 @@ title: vue 画布支持说明 sidebar_position: 17 tags: [FAQ] --- + #### 低代码引擎官方是否支持 Vue 画布 -短期没有支持的计划 -#### 社区研发的 Vue 画布 -##### 肯耐珂萨团队实现的 Vue 画布 -github:[https://github.com/KNXCloud/lowcode-engine-vue](https://github.com/KNXCloud/lowcode-engine-vue) +fork修改自 github:[https://github.com/KNXCloud/lowcode-engine-vue](https://github.com/KNXCloud/lowcode-engine-vue) diff --git a/docs/docs/faq/faq024.md b/docs/docs/faq/faq024.md index 4dfc4acbfa..83df9973b0 100644 --- a/docs/docs/faq/faq024.md +++ b/docs/docs/faq/faq024.md @@ -1,6 +1,6 @@ --- title: workspace 模式常见问题 -sidebar_position: 23 +sidebar_position: 24 tags: [FAQ] --- diff --git a/docs/docs/faq/faq025.md b/docs/docs/faq/faq025.md new file mode 100644 index 0000000000..0ac305d257 --- /dev/null +++ b/docs/docs/faq/faq025.md @@ -0,0 +1,28 @@ +--- +title: 为什么使用lerna-lite替换lerna +sidebar_position: 25 +tags: [FAQ] +--- + +#### lerna 有什么问题? + +lerna publish 命令,不支持 publishConfig 配置。 + +参见: + +- [publishConfig does not overrides after "lerna publish"](https://github.com/lerna/lerna/issues/3402) +- [The publishConfig of lerna is different from pnpm , it is not support "main" , "module" and "types"](https://github.com/lerna/lerna/issues/3568) + +其中答主提到 lerna-lite 早已支持,lerna却迟迟没有跟进,判定没有后续支持的可能。 + +#### lerna-lite + +lerna-lite 是一个 lerna 的 fork,支持 publishConfig 配置。 + +使用时必须全局安装 @lerna-lite/cli。 + +#### 用到了哪些模块 + +本工程采用 vite + pnpm + lerna-lite 的组合管理,由 pnpm 管理 workspace 及依赖,由 vite 管理打包启动,lerna-lite 管理发布。 + +所以,主要使用到 lerna-lite 的 version、publish 命令。 diff --git a/docs/docs/faq/index.md b/docs/docs/faq/index.md index ef8d7b3b15..296cfac38a 100644 --- a/docs/docs/faq/index.md +++ b/docs/docs/faq/index.md @@ -7,20 +7,24 @@ tags: [FAQ] 不定期将社区常见问题及答案维护到此处 ## Demo 使用 + - [渲染唯一标识(key)](/site/docs/faq/faq002) - [点击事件如何添加参数](/site/docs/faq/faq003) - [如何通过 API 手动调用数据源请求](/site/docs/faq/faq006) ## 设计器定制 + - [如何通过 this.utils 使用第三方工具扩展](/site/docs/faq/faq005) - [设置面板中的高级 tab 如何配置](/site/docs/faq/faq007) - [插件面板如何调整位置](/site/docs/faq/faq010) - [workspace 模式常见问题](/site/docs/faq/faq024) ## 源码和依赖 + - [某某 npm 包对应的源码在哪里?](/site/docs/faq/faq008) ## 错误和报错 + - [物料出现 Component Not Found 相关报错](/site/docs/faq/faq009) - [VERSION_PLACEHOLDER is not defined](/site/docs/faq/faq014) - [Cannot read property 'Icon' of Undefined](/site/docs/faq/faq016) @@ -29,6 +33,7 @@ tags: [FAQ] - [Slot组件渲染报错问题](/site/docs/faq/faq023) ## 物料相关问题 + - [如何获取物料当前处于编辑态还是渲染态](/site/docs/faq/faq011) - [Procode 物料如何调用数据源方法](/site/docs/faq/faq012) - [已有组件如何快速接入引擎](/site/docs/faq/faq015) @@ -37,11 +42,15 @@ tags: [FAQ] - [节点无法拖拽到 Page 下](/site/docs/faq/faq022) ## 其他说明 + - [vue 画布支持说明](/site/docs/faq/faq017) - [是否可以生成 Vue 页面代码?](/site/docs/faq/faq018) +- [为什么使用lerna-lite替换lerna](/site/docs/faq/faq025) ## 参与贡献 + - [提交 PR 时,明明签署过 CLA,仍被提示需要签署](/site/docs/faq/faq021) ## 相关依赖文档 + - [build-scripts 的使用文档](/site/docs/faq/faq001) diff --git a/docs/docs/guide/create/useEditor.md b/docs/docs/guide/create/useEditor.md index 151e6cd5af..91b6c6538a 100644 --- a/docs/docs/guide/create/useEditor.md +++ b/docs/docs/guide/create/useEditor.md @@ -13,9 +13,11 @@ sidebar_position: 0 1. 确保本地安装了 Node.js 和 npm,如果没有,[您可以通过 nvm 进行快捷的安装](https://github.com/nvm-sh/nvm) 2. 确保为 npm [设置了可以访问的 npm 源,保证安装过程无网络问题](https://npmmirror.com/) 3. 安装官方命令行工具 + ```bash npm install -g @alilc/create-element@latest ``` + 4. 通过命令行工具创建 ```bash @@ -31,17 +33,23 @@ sidebar_position: 0 > 注 @alilc/create-element 版本需 >= 1.0.4,若看不到`编辑器`选项,请重新执行步骤 3 5. 进入创建后的目录 + ```bash cd editor-project-name ``` + 6. 安装依赖 + ```bash npm install ``` + 7. 安装依赖成功后,启动项目 (注意观察上一步的输出,如有 error 等失败信息,请先进行排查) + ```bash npm start ``` + 执行后如果看到这个界面,说明项目启动成功。您可以继续看后续章节了。本章节后续内容均为高级配置方式。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN013qJVoV1OAcFNKFrIQ_!!6000000001665-2-tps-3060-1634.png) @@ -60,7 +68,7 @@ sidebar_position: 0 @@ -72,7 +80,7 @@ sidebar_position: 0 @@ -91,18 +99,18 @@ sidebar_position: 0 ``` -> 注:如果 unpkg 的服务比较缓慢,您可以使用官方 CDN 来获得确定版本的低代码引擎,如对于引擎的 1.0.18 版本,可用以下官方 CDN 替代 +> 注:如果 unpkg 的服务比较缓慢,您可以使用官方 cnpm CDN 来获得确定版本的低代码引擎,如对于引擎的 1.4.0 版本,可用以下cnpm CDN 替代 > -> - [https://uipaas-assets.com/prod/npm/@felce/lowcode-engine/1.0.18/dist/js/engine-core.js](https://uipaas-assets.com/prod/npm/@felce/lowcode-engine/1.0.18/dist/js/engine-core.js) +> - [https://registry.npmmirror.com/@felce/lowcode-engine/1.4.0/files/dist/js/engine-core.js](https://registry.npmmirror.com/@felce/lowcode-engine/1.4.0/files/dist/js/engine-core.js) ### 配置打包 @@ -116,7 +124,7 @@ sidebar_position: 0 "prop-types": "var window.PropTypes", "@alifd/next": "var window.Next", "@felce/lowcode-engine": "var window.AliLowCodeEngine", - "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt", + "@felce/lowcode-engine-ext": "var window.AliLowCodeEngineExt", "moment": "var window.moment", "lodash": "var window._" } diff --git a/docs/docs/guide/design/renderer.md b/docs/docs/guide/design/renderer.md index 022dccd4bb..74bcc6b624 100644 --- a/docs/docs/guide/design/renderer.md +++ b/docs/docs/guide/design/renderer.md @@ -12,7 +12,7 @@ sidebar_position: 4 ## npm 包与仓库信息 - React 框架渲染 npm 包:@felce/lowcode-react-renderer -- 仓库:[https://github.com/fe-lce/lowcode-engine](https://github.com/fe-lce/lowcode-engine) 下的 +- 仓库:[https://github.com/fe-lce/lowcode-engine-react](https://github.com/fe-lce/lowcode-engine-react) 下的 - packages/renderer-core - packages/react-renderer - packages/react-simulator-renderer diff --git a/docs/docs/guide/design/setter.md b/docs/docs/guide/design/setter.md index 62b795d9b7..5bd6c33ad4 100644 --- a/docs/docs/guide/design/setter.md +++ b/docs/docs/guide/design/setter.md @@ -18,7 +18,7 @@ sidebar_position: 6 ## npm 包与仓库信息 -- npm 包:@alilc/lowcode-engine-ext +- npm 包:@felce/lowcode-engine-ext - 仓库:[https://github.com/fe-lce/lowcode-engine-ext](https://github.com/fe-lce/lowcode-engine-ext) ## 设置器模块原理 diff --git a/docs/docs/participate/index.md b/docs/docs/participate/index.md index 1a602a73bf..c833dc5463 100644 --- a/docs/docs/participate/index.md +++ b/docs/docs/participate/index.md @@ -34,20 +34,28 @@ npm install && npm run setup { "proxy": [ [ - "https://uipaas-assets.com/prod/npm/@felce/lowcode-engine/(.*)/dist/js/engine-core.js", + "https://registry.npmmirror.com/@felce/lowcode-engine/(.*)/dist/js/engine-core.js", "http://localhost:5555/js/AliLowCodeEngine.js" ], [ - "https://uipaas-assets.com/prod/npm/@felce/lowcode-engine/(.*)/dist/css/engine-core.css", + "https://registry.npmmirror.com/@felce/lowcode-engine/(.*)/dist/css/engine-core.css", "http://localhost:5555/css/AliLowCodeEngine.css" ], [ - "https?://uipaas-assets.com/prod/npm/@felce/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", + "https://registry.npmmirror.com/@felce/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", "http://localhost:5555/js/ReactSimulatorRenderer.js" ], [ - "https?://uipaas-assets.com/prod/npm/@felce/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", + "https://registry.npmmirror.com/@felce/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", "http://localhost:5555/css/ReactSimulatorRenderer.css" + ], + [ + "https://registry.npmmirror.com/@felce/lowcode-engine/(.*)/dist/js/vue-simulator-renderer.js", + "http://localhost:5555/js/VueSimulatorRenderer.js" + ], + [ + "https://registry.npmmirror.com/@felce/lowcode-engine/(.*)/dist/css/vue-simulator-renderer.css", + "http://localhost:5555/css/VueSimulatorRenderer.css" ] ] } diff --git a/docs/docs/specs/material-spec.md b/docs/docs/specs/material-spec.md index c766c68347..484f1b534e 100644 --- a/docs/docs/specs/material-spec.md +++ b/docs/docs/specs/material-spec.md @@ -145,11 +145,11 @@ npm install @alifd/ice-layout -S "@alifd/next": "1.x" // 【可选】可以是一个 util 类型的组件,如果依赖 next,请务必写语义化版本号,不要写*这种 }, "devDependencies": { - "react": "^16.5.0", - "react-dom": "^16.5.0" + "react": "^18.3.1", + "react-dom": "^18.3.1" }, "peerDependencies": { - "react": "^16.5.0" + "react": "^18" }, "componentConfig": { // 【私有字段】组件配置信息 "name": "button", // 组件英文名 diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 3ce8ba033c..e633eb9adf 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -9,19 +9,19 @@ const navbar = require('./config/navbar'); const config = { title: 'Low-Code Engine', tagline: 'Low-Code Engine is awesome!', - url: 'https://lowcode-engine.cn', - baseUrl: '/site/', + url: 'https://felce.cn', + baseUrl: '/', onBrokenLinks: 'throw', onBrokenMarkdownLinks: 'warn', favicon: 'https://img.alicdn.com/imgextra/i2/O1CN01TNJDDg20pKniPOkN4_!!6000000006898-2-tps-66-78.png', - organizationName: 'alibaba', // Usually your GitHub org/user name. + organizationName: 'fe-lce', // Usually your GitHub org/user name. projectName: 'lowcode-engine', // Usually your repo name. i18n: { - defaultLocale: 'zh-Hans', - locales: ['zh-Hans'], + defaultLocale: 'zh', + locales: ['zh'], }, plugins: [ @@ -61,7 +61,7 @@ const config = { navbar, footer: { // style: 'dark', - copyright: `Copyright © ${new Date().getFullYear()} 阿里巴巴集团, Inc. Built with Docusaurus.`, + copyright: `Copyright © ${new Date().getFullYear()} felce, Inc. Built with Docusaurus.`, }, // 主题切换 prism: { @@ -79,6 +79,7 @@ const config = { themes: [ [ require.resolve('@easyops-cn/docusaurus-search-local'), + /** @type {import("@easyops-cn/docusaurus-search-local").PluginOptions} */ { hashed: true, // For Docs using Chinese, The `language` is recommended to set to: diff --git a/docs/package.json b/docs/package.json index 4d3aa2c616..f0db55e634 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@felce/lowcode-engine-docs", - "version": "1.2.31", + "version": "1.4.1", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ @@ -20,21 +20,21 @@ "syncOss": "node ./scripts/sync-oss.js" }, "dependencies": { - "@docusaurus/core": "^2.2.0", - "@docusaurus/preset-classic": "^2.2.0", - "@easyops-cn/docusaurus-search-local": "^0.32.0", - "@mdx-js/react": "^1.6.22", - "axios": "^1.1.3", - "clsx": "^1.2.1", - "fs-extra": "^10.1.0", - "prism-react-renderer": "^1.3.5", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "@docusaurus/core": "3.6.2", + "@docusaurus/preset-classic": "3.6.2", + "@easyops-cn/docusaurus-search-local": "^0.45.0", + "@mdx-js/react": "3.1.0", + "axios": "^1.7.7", + "clsx": "2.1.1", + "fs-extra": "11.2.0", + "prism-react-renderer": "2.4.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" }, "devDependencies": { - "@docusaurus/module-type-aliases": "^2.2.0", - "@tsconfig/docusaurus": "^1.0.5", - "typescript": "^4.7.4" + "@docusaurus/module-type-aliases": "3.6.2", + "@tsconfig/docusaurus": "2.0.3", + "typescript": "^5.6.3" }, "browserslist": { "production": [ diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index cdf826a64a..5f76de52ba 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -8,7 +8,7 @@ export default function ToIndex(): JSX.Element { /** * 跳转到首页 */ - window.location.href = '/index'; + window.location.href = '/docs/guide/quickStart/intro'; return <>; }} diff --git a/lerna.json b/lerna.json index d0d5e9aea2..150cc26be0 100644 --- a/lerna.json +++ b/lerna.json @@ -1,16 +1,14 @@ { - "lerna": "4.0.0", - "version": "1.4.0", - "npmClient": "yarn", + "$schema": "node_modules/@lerna-list/cli/schemas/lerna-schema.json", + "version": "1.5.1", + "npmClient": "pnpm", "useWorkspaces": true, "packages": [ "packages/*" ], "command": { - "bootstrap": { - "npmClientArgs": [ - "--no-package-lock" - ] + "run": { + "npmClient": "pnpm" }, "version": { "allowBranch": [ @@ -22,7 +20,7 @@ ] }, "publish": { - "npmClient": "npm", + "npmClient": "pnpm", "verifyRegistry": false, "verifyAccess": false, "ignoreChanges": [ diff --git a/modules/code-generator/.gitignore b/modules/code-generator/.gitignore deleted file mode 100644 index bf10c9f823..0000000000 --- a/modules/code-generator/.gitignore +++ /dev/null @@ -1,122 +0,0 @@ -# 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 - -# types -/types - -# backup files -*.bak - -# tests -tests/fixtures/**/actual - - - diff --git a/modules/code-generator/.prettierrc.js b/modules/code-generator/.prettierrc.js deleted file mode 100644 index 24c5859e6e..0000000000 --- a/modules/code-generator/.prettierrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - printWidth: 100, - tabWidth: 2, - semi: true, - singleQuote: true, - trailingComma: 'all', -}; diff --git a/modules/code-generator/.versionrc b/modules/code-generator/.versionrc deleted file mode 100644 index a41c11e264..0000000000 --- a/modules/code-generator/.versionrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "releaseCommitMessageFormat": "chore(release): code-generator - {{currentTag}}" -} \ No newline at end of file diff --git a/modules/code-generator/CHANGELOG.md b/modules/code-generator/CHANGELOG.md deleted file mode 100644 index 8a6c546cd8..0000000000 --- a/modules/code-generator/CHANGELOG.md +++ /dev/null @@ -1,266 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - -### [1.0.7-beta.2](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.3...@felce/lowcode-code-generator@1.0.7-beta.2) (2022-11-24) - -### Bug Fixes - -- 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 \_\_$evalArray 的问题 ([3b9b177](https://github.com/fe-lce/lowcode-engine/commit/3b9b177b052169cd0c1078cf8b488f04cb374dac)) -- 🐛 解决出码缺乏对于 i18n 数据的 params 的处理的问题 ([2cf788c](https://github.com/fe-lce/lowcode-engine/commit/2cf788c1716ae63fef20004348c59a5a65c6b3d2)), closes [#288](https://github.com/fe-lce/lowcode-engine/issues/288) -- 🐛 解决小程序环境没有 window, 而 rax 出码中却默认在 \_\_$eval 中用到 window 的问题 ([ce531ae](https://github.com/fe-lce/lowcode-engine/commit/ce531aeb457711fac92d828b431cfc3d643b3682)) -- add support for jsx expression ([453e069](https://github.com/fe-lce/lowcode-engine/commit/453e0699ece06d98e59227e23248baf1de4082aa)) -- 修复生成的 icejs 项目不支持 constants 的问题, fixes [#1259](https://github.com/fe-lce/lowcode-engine/issues/1259) ([a079fbc](https://github.com/fe-lce/lowcode-engine/commit/a079fbc256f8275e8a69eb6d8abb6f6b08179578)) -- 修正 react 框架出码中在严格模式对 methods 和 context 的处理 ([b1a6100](https://github.com/fe-lce/lowcode-engine/commit/b1a61006bba4292790899c7c49c9c611a9384472)) - -### [1.0.7-beta.1](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.7-beta.0...@felce/lowcode-code-generator@1.0.7-beta.1) (2022-10-26) - -### Bug Fixes - -- fix empty string lost when generate variable ([2cf74cd](https://github.com/fe-lce/lowcode-engine/commit/2cf74cd04b4f48a3501d37329d39784f6964366a)) - -### [1.0.7-beta.0](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.6-beta.0...@felce/lowcode-code-generator@1.0.7-beta.0) (2022-10-25) - -### [1.0.6-beta.0](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.3...@felce/lowcode-code-generator@1.0.6-beta.0) (2022-10-25) - -### Features - -- 🎸 设计态支持数据源引擎配置 ([04631f8](https://github.com/fe-lce/lowcode-engine/commit/04631f813782dbf6d175f51c40ccc75ca4c099d2)) -- 大纲树支持节点过滤 ([f30db20](https://github.com/fe-lce/lowcode-engine/commit/f30db20606f5f2fdac0017305b1dda7ab2258c4b)) -- 为 renderer 追加 displayName,以支持后续的反射功能 ([6399cce](https://github.com/fe-lce/lowcode-engine/commit/6399cce05ae494dac6facf4366949b0b97576079)) -- 资产包支持一个package从另一个package异步导出 ([#1150](https://github.com/fe-lce/lowcode-engine/issues/1150)) ([6b78157](https://github.com/fe-lce/lowcode-engine/commit/6b78157b211d6eabf60297b9ce980a3e10cc8272)) -- add availableActions for ComponentMeta ([de1f60b](https://github.com/fe-lce/lowcode-engine/commit/de1f60bbee157267e2c2212df1077cc49ce506f4)) -- add code coverage action ([ed3ddcf](https://github.com/fe-lce/lowcode-engine/commit/ed3ddcf5c942a8e78e1f247e41d4159da97e75a8)) -- add componentMeta getter for setingPropEntry ([2f8b954](https://github.com/fe-lce/lowcode-engine/commit/2f8b9545de0210260001a832b52f608238ac4191)) -- add expanded to shell SettingPropEntry ([534e294](https://github.com/fe-lce/lowcode-engine/commit/534e29429d445d97c71d95d4c4e492868527bb6b)) -- add flag createIfNode for ShellNode#getProp ([152a24d](https://github.com/fe-lce/lowcode-engine/commit/152a24d65528d0a3b7990c9aa87e6d8d09aa9b2a)) -- add getComponentsMap() for DocumentModel ([f956645](https://github.com/fe-lce/lowcode-engine/commit/f9566454ef83eb4c48b68d63a766c3d0ff927c73)) -- add getExtraPropValue setExtraPropValue to shell SettingPropEntry ([70e7c1c](https://github.com/fe-lce/lowcode-engine/commit/70e7c1c2e8998e80d58447759efdf651105724a9)) -- add id setter for DocumentModel ([941ae05](https://github.com/fe-lce/lowcode-engine/commit/941ae0592586334694c48197aaa6692d49cefbce)) -- add importSchema event for documentModel ([4b8ec09](https://github.com/fe-lce/lowcode-engine/commit/4b8ec09e86e3950a9d4066c28e681a59273b4c93)) -- add isGroup & items to shell SettingPropEntry ([7b76ff3](https://github.com/fe-lce/lowcode-engine/commit/7b76ff357e4e638454c31a9b1324fb68966ec522)) -- add mergeChldren API for shell node ([a47d4ee](https://github.com/fe-lce/lowcode-engine/commit/a47d4eea28cf4479e3b3a2bd1d194a6433666825)) -- add onMountNode event for DocumentModel ([dcc247c](https://github.com/fe-lce/lowcode-engine/commit/dcc247c7d54f6af2ed36d46bfd79c7eacf7bd604)) -- add renderer for simulatorHost ([1cfc8d6](https://github.com/fe-lce/lowcode-engine/commit/1cfc8d668b8897ef3a53c11520312cc6d18338f9)) -- add script for synchronizing packages to intranet registry ([b4f463e](https://github.com/fe-lce/lowcode-engine/commit/b4f463e7d45f7b476de04bd4d98ad9f74d53cf13)) -- add scrollToNode for simulator host ([#1075](https://github.com/fe-lce/lowcode-engine/issues/1075)) ([0bcd9ff](https://github.com/fe-lce/lowcode-engine/commit/0bcd9ff78227aeddaf2fdc22d10fbd662fed91d3)) -- add setVisible for Node ([ba90327](https://github.com/fe-lce/lowcode-engine/commit/ba90327eac0f5f82f6349bb9a7684bf51259e9c9)) -- add showArea & hideArea method for skeleton ([8f6b53e](https://github.com/fe-lce/lowcode-engine/commit/8f6b53e67d89ee7af754132f0994a759522b3821)) -- add slotNode for shell prop ([d9a44c5](https://github.com/fe-lce/lowcode-engine/commit/d9a44c5de7861e9180567b4afb787e381cefac61)) -- add some features ([18d1a4f](https://github.com/fe-lce/lowcode-engine/commit/18d1a4fe1d952bcd4715e693def09fee94da49a5)) -- add some necessary methods and attributes ([4fd7f27](https://github.com/fe-lce/lowcode-engine/commit/4fd7f27f8eb33b66324ede279b412940fc1f7032)) -- add some params for onDragstart & onDrag & onDragend ([d1c9838](https://github.com/fe-lce/lowcode-engine/commit/d1c9838343ba1bdd4c02c1cfbf1f920dd8c87e7d)) -- add top attrbute for Shell SettingPropEntry ([51aca3d](https://github.com/fe-lce/lowcode-engine/commit/51aca3d330b6483c05b71867f1b362a9f5db6cfe)) -- added lowcode engine standard specs ([f25feba](https://github.com/fe-lce/lowcode-engine/commit/f25feba63f181efa83f1a8dff530e1c39ab1b34c)) -- added lowcode engine standard specs ([57df803](https://github.com/fe-lce/lowcode-engine/commit/57df803179ca9cec4e8ab1dac1be577175732e65)) -- added thisRequiredInJSE API to control whether JSExpression expression access context must use this ([#702](https://github.com/fe-lce/lowcode-engine/issues/702)) ([da7f77e](https://github.com/fe-lce/lowcode-engine/commit/da7f77ee91b3bf441a4a57614872df32d6a1d041)) -- assetLoader loda scripts with async=false ([f6ad4a1](https://github.com/fe-lce/lowcode-engine/commit/f6ad4a157df8c0ff7db327f4770f454998693d9a)) -- change loop sertter config, set defaultValue prop to JsonSetter ([aa6b9c8](https://github.com/fe-lce/lowcode-engine/commit/aa6b9c8f7a5353771af9f46216310f044e57c533)) -- cp dist files of simulator-renderer to that of engine ([03c5397](https://github.com/fe-lce/lowcode-engine/commit/03c53971df6de8c35620fd77743ac4f57a82d323)) -- export nodeChildrenSymbol && remove some unnecessary editor.set ([e83adce](https://github.com/fe-lce/lowcode-engine/commit/e83adcee815eea73b6b1ed4f43f4d684c11818ca)) -- fix render-core leaf hoc component condition config should get from leaf exportSchema fn ([85704c3](https://github.com/fe-lce/lowcode-engine/commit/85704c36946191a1b88db789cfac59e9d027a371)) -- low-code components support lifecycle and function execution ([176583f](https://github.com/fe-lce/lowcode-engine/commit/176583f48af573d30c0d2c36faa3d901b0541c06)) -- **material-parser:** check module before install it; fix default value issue in ts parser ([fc452f7](https://github.com/fe-lce/lowcode-engine/commit/fc452f7166f02acfba6076c1a9425e6f5880b5f6)) -- modify the output method of rendering module parsing errors ([8255b79](https://github.com/fe-lce/lowcode-engine/commit/8255b7945836ee5d25fae73913faa6d0af7b3ff3)) -- pass e to customizeIgnoreSelectors ([900b239](https://github.com/fe-lce/lowcode-engine/commit/900b2394323e85f0dce5df83dfc773f96da23e24)) -- refine nesting drawer ([4c032d0](https://github.com/fe-lce/lowcode-engine/commit/4c032d0d0ead9731c038bd62dccc4a7d96435183)) -- refine nesting drawer ([94a211e](https://github.com/fe-lce/lowcode-engine/commit/94a211e2795f74721cfd2ae3ff38a1d3607e9cd0)) -- refine pop drawer ([abf8fae](https://github.com/fe-lce/lowcode-engine/commit/abf8fae3ef4d62b5688362e1b98f1b508a207029)) -- requestHandlersMap should be optional ([ee7160e](https://github.com/fe-lce/lowcode-engine/commit/ee7160ea3c625d421c07730ef51711b8f14392a0)) -- return unbind function for onChangeDetecting & onChangeSelection ([30267cb](https://github.com/fe-lce/lowcode-engine/commit/30267cb173fca2cd80a61450b9f2fe2bceac0f06)) -- support for hiding settings tabs when there is only one item ([#669](https://github.com/fe-lce/lowcode-engine/issues/669)) ([cbd95a1](https://github.com/fe-lce/lowcode-engine/commit/cbd95a1778415406670f37507ce957af6b3ecd4a)) -- support for NotFoundComponent design state is optional ([#1013](https://github.com/fe-lce/lowcode-engine/issues/1013)) ([d3c891e](https://github.com/fe-lce/lowcode-engine/commit/d3c891e2a46d138e31c81a7f9b804a8240154df5)) -- support opening document with id ([3f7c0cd](https://github.com/fe-lce/lowcode-engine/commit/3f7c0cd5191b7924f2630c58e6439f4d4a936ac9)) -- support SPA mode ([1f9150e](https://github.com/fe-lce/lowcode-engine/commit/1f9150e4b260d522bd7cb31497069b700a1e8576)) -- sync utils/constants ([#506](https://github.com/fe-lce/lowcode-engine/issues/506)) ([2871b5b](https://github.com/fe-lce/lowcode-engine/commit/2871b5ba4c3dbf1ed76bf4d6359fb457190a9b22)) -- the tips when dragging a component from the component panel same with the moving component ([dbe0764](https://github.com/fe-lce/lowcode-engine/commit/dbe0764ff4901450f03ca56b62167fbc87d2524a)) - -### Bug Fixes - -- 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 \_\_$evalArray 的问题 ([3b9b177](https://github.com/fe-lce/lowcode-engine/commit/3b9b177b052169cd0c1078cf8b488f04cb374dac)) -- 🐛 解决出码缺乏对于 i18n 数据的 params 的处理的问题 ([2cf788c](https://github.com/fe-lce/lowcode-engine/commit/2cf788c1716ae63fef20004348c59a5a65c6b3d2)), closes [#288](https://github.com/fe-lce/lowcode-engine/issues/288) -- 🐛 解决小程序环境没有 window, 而 rax 出码中却默认在 \_\_$eval 中用到 window 的问题 ([ce531ae](https://github.com/fe-lce/lowcode-engine/commit/ce531aeb457711fac92d828b431cfc3d643b3682)) -- 🐛 修复数据源引擎请求处理器映射严格模式下被过滤的问题 ([75626d8](https://github.com/fe-lce/lowcode-engine/commit/75626d877db017b8862b1d5e64d75f3af7ff667a)) -- 🐛 修正 i18n 里面的一个参数命名问题 ([20c6fca](https://github.com/fe-lce/lowcode-engine/commit/20c6fca03e99b11fa5c257cbbda0d4d23f410090)) -- 新元素无法在大纲树拖拽 ([3d41fd5](https://github.com/fe-lce/lowcode-engine/commit/3d41fd5d0783048a7cfb54c6f80d058856153d25)) -- 修复React17选中组件bug ([750d282](https://github.com/fe-lce/lowcode-engine/commit/750d282c03a880204fefdef01e180510465b82f8)) -- 修正 react 框架出码中在严格模式对 methods 和 context 的处理 ([b1a6100](https://github.com/fe-lce/lowcode-engine/commit/b1a61006bba4292790899c7c49c9c611a9384472)) -- 左侧抽屉固定模式层级不足 ([c657cee](https://github.com/fe-lce/lowcode-engine/commit/c657cee0694e3126dee89588a2aa17c4e118f786)) -- add lowcode-designer, lowcode-utils dependencies ([d250242](https://github.com/fe-lce/lowcode-engine/commit/d2502427ca988881747a35bd8da49f024939b833)) -- add support for jsx expression ([1043ef8](https://github.com/fe-lce/lowcode-engine/commit/1043ef82b1e9ceefc3b74fd21eb28e9a740bd1db)) -- addon-combine affect metadata unexpectedly ([fc5fbc6](https://github.com/fe-lce/lowcode-engine/commit/fc5fbc63a04a32bc887754f32e74c76149d74b05)) -- adjust synchronize-order of packages ([81a7304](https://github.com/fe-lce/lowcode-engine/commit/81a73049bd848524e1156761ded08ddf325863ba)) -- change typescript type export to export type ([50e4a03](https://github.com/fe-lce/lowcode-engine/commit/50e4a03b7d810131ce413cc057b43d4a726f1ebe)) -- change typescript type export to export type ([573504b](https://github.com/fe-lce/lowcode-engine/commit/573504b0e3537ca60d234ce2b2f3feedb323405e)) -- declare parameter appHelper for valid engine options ([058a842](https://github.com/fe-lce/lowcode-engine/commit/058a84226af8ca19d8c7d63599d80d0cdf70281c)) -- defaultValue should be evaluated inspite of condition result is falsy, fixes [#1045](https://github.com/fe-lce/lowcode-engine/issues/1045) ([fcfce3c](https://github.com/fe-lce/lowcode-engine/commit/fcfce3cbeb5a53600c40aea07ffef19c9c9591c4)) -- delete the defaultValue configuration outside the loop ([acf7449](https://github.com/fe-lce/lowcode-engine/commit/acf7449ca231d45e8ed7e1d9416817ea11b1266f)) -- delete unused typescript types ([63f5d2c](https://github.com/fe-lce/lowcode-engine/commit/63f5d2ca3e0bda92898fd0df28c9500707812082)) -- delete unused typescript types ([2432aed](https://github.com/fe-lce/lowcode-engine/commit/2432aed83d55407d2f8b5f94910ada7ea78bb59e)) -- designer/loadIncrementalAssets await Sequential ([#841](https://github.com/fe-lce/lowcode-engine/issues/841)) ([8232424](https://github.com/fe-lce/lowcode-engine/commit/823242469743d235923b3b946ec7d2db70887ead)) -- error thrown when triggering undo after save schema on SchemaPane ([9be46e7](https://github.com/fe-lce/lowcode-engine/commit/9be46e7b34e3a40cbc489dbae4bfd0915c2090e3)) -- fallback focusNode to root if empty ([a9a118f](https://github.com/fe-lce/lowcode-engine/commit/a9a118fe6e79080245c6eea42ed26772b7c784ca)) -- **filter:** unique key prop warning ([3fe6e41](https://github.com/fe-lce/lowcode-engine/commit/3fe6e41536cd3a9b9c7eaca5b353de4bd1f91b11)) -- **filter:** unique key prop warning ([06e6920](https://github.com/fe-lce/lowcode-engine/commit/06e6920602bdf21b6e1ffe5cfa3dfe4856e7c57e)) -- fix css resources with parameters not loading correctly ([f859752](https://github.com/fe-lce/lowcode-engine/commit/f85975211814147d40ae5330a76cb21cb6c66916)) -- fix css resources with parameters not loading correctly ([9a5a04a](https://github.com/fe-lce/lowcode-engine/commit/9a5a04ac9560fb6a51bf4e0ed8ea446381d39c35)) -- fix dataSource needs to be compatible due to empty schema ([98bc477](https://github.com/fe-lce/lowcode-engine/commit/98bc477d80dbf7993f89befdb42762d78a55fb1b)) -- fix displayName spell mistake ([2b2bcbd](https://github.com/fe-lce/lowcode-engine/commit/2b2bcbdaebde6a3ce974072f586386ef7ef3497c)) -- fix internal project.getSchema default stage is error ([0d40db2](https://github.com/fe-lce/lowcode-engine/commit/0d40db2581f4fe5a9e22f763f21aec641e366c34)) -- fix lint issues for renderer-core/renderer/base ([d85437d](https://github.com/fe-lce/lowcode-engine/commit/d85437d4af1043371e27dfde98cecf914b93a126)) -- fix lint issues for renderer-core/renderer/base ([4b59190](https://github.com/fe-lce/lowcode-engine/commit/4b59190c7f9d518bc7efac44b7eeee73f1b5d177)) -- fix low-code component rendering problems: 1. thisRequiredInJSE does not take effect 2. jsx components cannot obtain source components ([5dd4625](https://github.com/fe-lce/lowcode-engine/commit/5dd462544fbbbccfa97165f2bcfeed8629fab2a3)) -- fix material-spec demo ([438cccd](https://github.com/fe-lce/lowcode-engine/commit/438cccd58e4341638070c1d8b2d4e78e4e20e3fb)) -- fix misused doc urls ([16a8857](https://github.com/fe-lce/lowcode-engine/commit/16a88578634b9da2f04698df5ca5a5e69151bb97)) -- fix monitor utils incorrect assignment method ([bf280c6](https://github.com/fe-lce/lowcode-engine/commit/bf280c6fa1e46d084fc8f20323164816fad4076f)) -- fix outline-pane invisible occasionally when dragging tree node ([031c7f2](https://github.com/fe-lce/lowcode-engine/commit/031c7f25f10a6cfebfc7929c9226f4e4167a359f)) -- fix outline-tree initialization failed ([a2d5c6f](https://github.com/fe-lce/lowcode-engine/commit/a2d5c6fd90ca0226bbbfea01a4b28c8b8d307a78)) -- fix render module state expression initialization exception ([5bd68ee](https://github.com/fe-lce/lowcode-engine/commit/5bd68ee6b448fa58b022870b3f8175d8b77febde)) -- fix render module state expression initialization exception ([9c545cc](https://github.com/fe-lce/lowcode-engine/commit/9c545cca6004f65e2f206ea001cefa3fa3cfa807)) -- fix setter hooks error ([8a3a0b8](https://github.com/fe-lce/lowcode-engine/commit/8a3a0b824162e25a930711c6fef511b4b369e897)) -- fix test case failures of designer ([4b0521a](https://github.com/fe-lce/lowcode-engine/commit/4b0521a47494f78e120f75021e0a076fb00ce53e)) -- Fix the conversion failure of some props expressions under Slot props of low-code components ([7db5461](https://github.com/fe-lce/lowcode-engine/commit/7db5461706c739fac673b2466bc2fda7661242e4)) -- fix the leaf hoc component fails to monitor Node changes, and modify the logic for get node ([6ee6b07](https://github.com/fe-lce/lowcode-engine/commit/6ee6b07a10ba4aac583def52d8ff1fa78d111d0b)) -- fix the leaf hoc component fails to monitor Node changes, and modify the logic for get node ([f400172](https://github.com/fe-lce/lowcode-engine/commit/f4001728259047b09db75d76a8c3ef1e1bcb4e0a)) -- fix the problem that material.getComponentMetasMap returns the wrong result ([e02933c](https://github.com/fe-lce/lowcode-engine/commit/e02933c18bc15519b2eba8ad946282502a509611)) -- Fix the rendering error caused by incorrect key value when configuring the loop ([1026763](https://github.com/fe-lce/lowcode-engine/commit/1026763dc5a77d4395a1e86e5a0084ab4fb4230c)) -- fix the unit test failure problem caused by thisRequiredInJSE modification ([c2c59b7](https://github.com/fe-lce/lowcode-engine/commit/c2c59b7ff72ba06156bbcdb952262739d6188209)) -- fix unnecessary props calculation ([f1fed75](https://github.com/fe-lce/lowcode-engine/commit/f1fed75f39be8289ede1ec558b04428a69e25b5f)) -- fixed an issue where materials would be rendered multiple times ([9d187cc](https://github.com/fe-lce/lowcode-engine/commit/9d187ccb7de55857e861d3fc881c610506872d03)) -- fixed an issue where materials would be rendered multiple times ([64cc328](https://github.com/fe-lce/lowcode-engine/commit/64cc3283c15342151a8f93c46a276681f3575153)) -- fixed focusNodeSelector configuration not taking effect ([9beae9c](https://github.com/fe-lce/lowcode-engine/commit/9beae9c3269901bf03a29033121c7d480571bce5)) -- fixed the issue that thisRequiredInJSE did not take effect in some scenarios ([7e5a919](https://github.com/fe-lce/lowcode-engine/commit/7e5a919f9352397f11741fd911495996469c0256)) -- in ES require changed to import ([b4d7d6d](https://github.com/fe-lce/lowcode-engine/commit/b4d7d6d8c290a335a2c1f60731d4417b23444941)) -- in ES require changed to import ([7c8cd36](https://github.com/fe-lce/lowcode-engine/commit/7c8cd36a10a7caa61de31a15abd93ab8a97fbe08)) -- leaf should be type of ShellNode other than InnerNode ([5bb8cf5](https://github.com/fe-lce/lowcode-engine/commit/5bb8cf5d12d38d70b69fa28deb2f8aa0afa9b9b9)) -- lowcode component exec lifecycle has error ([f99a47e](https://github.com/fe-lce/lowcode-engine/commit/f99a47e502080134454795f5e361cfa4fba3f03b)) -- lowcode component leaf dont have export prop, exec leaf.export make error ([9d51dcd](https://github.com/fe-lce/lowcode-engine/commit/9d51dcdae38850be0206861f2cae74ca68805c25)) -- missing engine options config info ([a79875c](https://github.com/fe-lce/lowcode-engine/commit/a79875cf8698d3912b50526d97f6ac72e9a21fc9)) -- missing engine options config info ([9ccded0](https://github.com/fe-lce/lowcode-engine/commit/9ccded006ef44cd538abaa140250e519243bf090)) -- npm run clean error in windows ([a176e9d](https://github.com/fe-lce/lowcode-engine/commit/a176e9d245981fb5718c8d144f477202b3796be6)) -- project event listeners will not be invoked sometimes ([a0c772f](https://github.com/fe-lce/lowcode-engine/commit/a0c772fb903cf5eb9e0b811b64bbe3846d4ba8ac)) -- project.exportSchema api lack stage param & setAssets should be a async fn ([0ea76a7](https://github.com/fe-lce/lowcode-engine/commit/0ea76a746fac8ea8e7b999d42434c468c85d6372)) -- project.exportSchema should export componentsMap of all documents ([969a130](https://github.com/fe-lce/lowcode-engine/commit/969a130b373fb028f8051e96cb9d79f1de0a2a1c)) -- removed incorrectly calling childWhitelist hook logic during drag and drop ([#1141](https://github.com/fe-lce/lowcode-engine/issues/1141)) ([6576346](https://github.com/fe-lce/lowcode-engine/commit/6576346b9185bedb090be9c84129e077cf5389b3)) -- renderer not rendering correct components when loading components with loadAsyncLibrary api ([9b3b4f9](https://github.com/fe-lce/lowcode-engine/commit/9b3b4f9b0e35ef3ea2f0117f0cdb2254e15d5389)) -- should pass index param when creating a Prop instance under a list type Prop instance, fix [#780](https://github.com/fe-lce/lowcode-engine/issues/780) ([a8de3f2](https://github.com/fe-lce/lowcode-engine/commit/a8de3f299c7b26fa939d2b2ea1428143e2b5fb01)) -- simulator eclipses setting area [#773](https://github.com/fe-lce/lowcode-engine/issues/773) ([b4b30a3](https://github.com/fe-lce/lowcode-engine/commit/b4b30a359932f5c0e8fde1b28f54a883c87901d8)) -- spec typo ([#1064](https://github.com/fe-lce/lowcode-engine/issues/1064)) ([ecb9dca](https://github.com/fe-lce/lowcode-engine/commit/ecb9dca2b9386ef6fadfd009d161a9203b9b9558)) -- try catch calculation of dynamic setter ([f61e2a2](https://github.com/fe-lce/lowcode-engine/commit/f61e2a2b8a3d8d6754474cd392bc259917c7eb10)) -- type=legao dont make request ([98ececa](https://github.com/fe-lce/lowcode-engine/commit/98ececa9c11f93e5f849b201b5b5e7ff453733d7)) -- **types:** rrror declaration of the children prop ([951d1cb](https://github.com/fe-lce/lowcode-engine/commit/951d1cb103fa46c0e7926d6138657c7d10cc4f88)) -- use the original object if it is not a shell object ([5ea53f7](https://github.com/fe-lce/lowcode-engine/commit/5ea53f706b6571946bcfa56b8655b55717381771)) -- use the outer documentation url of unique key, fixes [#868](https://github.com/fe-lce/lowcode-engine/issues/868) ([d770007](https://github.com/fe-lce/lowcode-engine/commit/d770007ff8c39e6cf527e07a7d6468dbb88c776d)) -- use the outer documentation url of unique key, fixes [#868](https://github.com/fe-lce/lowcode-engine/issues/868) ([912ee22](https://github.com/fe-lce/lowcode-engine/commit/912ee22180a424f63298c319c62fb481513af904)) -- use uppercase resize trigger names based on material spec ([7fda0ef](https://github.com/fe-lce/lowcode-engine/commit/7fda0efe131e0e2e3141849cf3f87307e7ce1b36)) -- when designMode is not design, the hidden attribute does not take effect ([3dd0b6d](https://github.com/fe-lce/lowcode-engine/commit/3dd0b6d0a86267e3029c176ff49aff793ce3e186)) - -### [1.0.4](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.4-beta.0...@felce/lowcode-code-generator@1.0.4) (2022-04-12) - -### Bug Fixes - -- 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 \_\_$evalArray 的问题 ([eb4cc69](https://github.com/fe-lce/lowcode-engine/commit/eb4cc693f5dbcae54546c569eb8fa331d074e062)) - -### [1.0.4-beta.1](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.4-beta.0...@felce/lowcode-code-generator@1.0.4-beta.1) (2022-04-11) - -### Bug Fixes - -- 🐛 解决 react 中 jsx 出码的时候对于循环数据漏包 \_\_$evalArray 的问题 ([987f4ce](https://github.com/fe-lce/lowcode-engine/commit/987f4cea54ef8a75d0b63a0268b5a20b2938b8a7)) - -### [1.0.4-beta.0](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.3...@felce/lowcode-code-generator@1.0.4-beta.0) (2022-04-10) - -### Features - -- **material-parser:** check module before install it; fix default value issue in ts parser ([fc452f7](https://github.com/fe-lce/lowcode-engine/commit/fc452f7166f02acfba6076c1a9425e6f5880b5f6)) - -### Bug Fixes - -- 🐛 修正 i18n 里面的一个参数命名问题 ([1e9e388](https://github.com/fe-lce/lowcode-engine/commit/1e9e388ce9104d76c4f6d9bc513c57e5059d7982)) -- 🐛 解决出码缺乏对于 i18n 数据的 params 的处理的问题 ([1eb9add](https://github.com/fe-lce/lowcode-engine/commit/1eb9addd8df2323f9aabac87af32ac2efcd6bf22)), closes [#288](https://github.com/fe-lce/lowcode-engine/issues/288) -- 🐛 解决小程序环境没有 window, 而 rax 出码中却默认在 \_\_$eval 中用到 window 的问题 ([67dabb0](https://github.com/fe-lce/lowcode-engine/commit/67dabb04beb32b6e94eb1276222e53b416e47c9d)) -- Fix the conversion failure of some props expressions under Slot props of low-code components ([7db5461](https://github.com/fe-lce/lowcode-engine/commit/7db5461706c739fac673b2466bc2fda7661242e4)) -- fix unnecessary props calculation ([f1fed75](https://github.com/fe-lce/lowcode-engine/commit/f1fed75f39be8289ede1ec558b04428a69e25b5f)) -- 修正 react 框架出码中在严格模式对 methods 和 context 的处理 ([79db4ac](https://github.com/fe-lce/lowcode-engine/commit/79db4ac97f34f24b7f7460fb3fc67521967f8cc5)) - -### [1.0.3](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.2...@felce/lowcode-code-generator@1.0.3) (2022-03-29) - -### Features - -- add getConvertedExtraKey / getOriginalExtraKey to utils ([8e7bb9d](https://github.com/fe-lce/lowcode-engine/commit/8e7bb9d4b86454dd77c6928eb769cd764cad8630)) - -### Bug Fixes - -- 🐛 出码: 解决 componentName 和 exportName 不一致时生成的 import 语句的问题 ([eefc091](https://github.com/fe-lce/lowcode-engine/commit/eefc091ee7e86d6214d20d486212cb5aff237946)) -- component cannot be redisplayed by configuration after rendering is closed ([c54f369](https://github.com/fe-lce/lowcode-engine/commit/c54f369e1860d818479dda9d6429f851c0b08fa6)) -- fix loop configuration auto fill empty array issue ([d087092](https://github.com/fe-lce/lowcode-engine/commit/d087092fd712eff0556adacda692d3ff6f2f9f22)) -- make important true by default ([c63b6e1](https://github.com/fe-lce/lowcode-engine/commit/c63b6e1bfadc3fc87ed41840952e02ffbff24fab)) -- make insertAfter & insertBefore work ([70fd372](https://github.com/fe-lce/lowcode-engine/commit/70fd3720d098d6e227acb9281ee22feee66b9c0b)) -- npm源 ([437adcc](https://github.com/fe-lce/lowcode-engine/commit/437adccf5f2dbb400de6e2bef10cfc4b65286f2b)) -- prop should return undefined when all items are undefined ([5bb9ec7](https://github.com/fe-lce/lowcode-engine/commit/5bb9ec7a1dfaabfdb5369226b54d5f63a7999e59)) -- should not create new prop while querying fileName ([19c207d](https://github.com/fe-lce/lowcode-engine/commit/19c207d29de045f473ba73baaf34e7294d40261a)) -- variable binding lost after modify the mock value ([ef95b56](https://github.com/fe-lce/lowcode-engine/commit/ef95b5683273d8302bde1582de8afe3d87a808d8)) -- Workbench should receive the original skeleton other than shell skeleton ([d5c3ca1](https://github.com/fe-lce/lowcode-engine/commit/d5c3ca1068ce2c2140980bd059d0da333574dc34)) - -### [1.0.2](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.2-beta.1...@felce/lowcode-code-generator@1.0.2) (2022-03-08) - -### [1.0.2-beta.1](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.2-beta.0...@felce/lowcode-code-generator@1.0.2-beta.1) (2022-03-08) - -### Bug Fixes - -- 🐛 补充 icejs 模板中缺失的依赖包 ([a94553e](https://github.com/fe-lce/lowcode-engine/commit/a94553e503d439b67478df6a34950d9e3d15a063)) - -### [1.0.2-beta.0](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.0...@felce/lowcode-code-generator@1.0.2-beta.0) (2022-03-08) - -### Features - -- 在 skeleton 增加几个方法和事件 ([a7d436a](https://github.com/fe-lce/lowcode-engine/commit/a7d436a0525a0ce0c7229710077111f283b452f4)) -- modify npm private control & version ([ee55d02](https://github.com/fe-lce/lowcode-engine/commit/ee55d024a7f964ccf35a0efabec817364cea8041)) -- modify yuque link in README ([d522034](https://github.com/fe-lce/lowcode-engine/commit/d522034879d20a7b5ed12f8fe02a30662a2ea7c6)) -- remove CHANGELOG.md ([b996414](https://github.com/fe-lce/lowcode-engine/commit/b996414c436b5d2439c8368eb4e001cdbcd02892)) -- remove module field in material-parser package.json ([6141c27](https://github.com/fe-lce/lowcode-engine/commit/6141c273c9c32eea22b5374679fe625e6ea15394)) -- rename build:umd ([23c7959](https://github.com/fe-lce/lowcode-engine/commit/23c795931e1d5cf43e9c21cd902441c69c1ecc63)) -- replace tnpm with npm ([36caf0f](https://github.com/fe-lce/lowcode-engine/commit/36caf0f18980c16f7ebb82ac845ad6b33e033567)) -- support UMD packageing for react-renderer ([982d0d6](https://github.com/fe-lce/lowcode-engine/commit/982d0d676b3dfbfc10a2190c0040126d6925ed37)) - -### Bug Fixes - -- 🐛 去掉 npm 上没有的依赖 ([#68](https://github.com/fe-lce/lowcode-engine/issues/68)) ([e7ce779](https://github.com/fe-lce/lowcode-engine/commit/e7ce77987eb05871dd1675d2a88367c5569bfbff)) -- 兼容 setters 为空的情况 ([56b459a](https://github.com/fe-lce/lowcode-engine/commit/56b459a017a8350a911ef20f0166d1e62b6390e4)) -- 解决 package.json 中误添加了没有用到的数据源类型的 handler 的包的问题 ([#56](https://github.com/fe-lce/lowcode-engine/issues/56)) ([76341c8](https://github.com/fe-lce/lowcode-engine/commit/76341c8456b227192bb65537dc3d16033db0b3a1)) -- 解决出码的一些问题 ([#87](https://github.com/fe-lce/lowcode-engine/issues/87)) ([4a01c97](https://github.com/fe-lce/lowcode-engine/commit/4a01c97ea6bf23eb677888ba1aba54e5c9f4f630)) -- 修复 setup 的逻辑 ([1cfb15a](https://github.com/fe-lce/lowcode-engine/commit/1cfb15aebea9796af23b2135f2aa4409d81283d7)) -- 修正一些对内的地址 ([07cc1f2](https://github.com/fe-lce/lowcode-engine/commit/07cc1f2954530c64a1a3d260e8d532c9e19892e8)) -- 增加必要的方法 ([1b38a81](https://github.com/fe-lce/lowcode-engine/commit/1b38a812653656aa02100a3b1b2a581188d1b3ef)) -- fix tsconfig of material-parser ([46725cb](https://github.com/fe-lce/lowcode-engine/commit/46725cb9f3166912c8f5b42f1e0b1177158c1ee3)) -- lint&fix auto generated types.ts ([7dde970](https://github.com/fe-lce/lowcode-engine/commit/7dde9701c7960b29523abddf32421cdbac47016d)) -- The outline tree does not display the loop flag when the loop is an empty array ([191e284](https://github.com/fe-lce/lowcode-engine/commit/191e284f2fa190c2b3aecb4df31849b2bdc99d38)) - -### [1.0.1](https://github.com/fe-lce/lowcode-engine/compare/@felce/lowcode-code-generator@1.0.0...@felce/lowcode-code-generator@1.0.1) (2022-03-08) - -### Features - -- 在 skeleton 增加几个方法和事件 ([a7d436a](https://github.com/fe-lce/lowcode-engine/commit/a7d436a0525a0ce0c7229710077111f283b452f4)) -- modify npm private control & version ([ee55d02](https://github.com/fe-lce/lowcode-engine/commit/ee55d024a7f964ccf35a0efabec817364cea8041)) -- modify yuque link in README ([d522034](https://github.com/fe-lce/lowcode-engine/commit/d522034879d20a7b5ed12f8fe02a30662a2ea7c6)) -- remove CHANGELOG.md ([b996414](https://github.com/fe-lce/lowcode-engine/commit/b996414c436b5d2439c8368eb4e001cdbcd02892)) -- remove module field in material-parser package.json ([6141c27](https://github.com/fe-lce/lowcode-engine/commit/6141c273c9c32eea22b5374679fe625e6ea15394)) -- rename build:umd ([23c7959](https://github.com/fe-lce/lowcode-engine/commit/23c795931e1d5cf43e9c21cd902441c69c1ecc63)) -- replace tnpm with npm ([36caf0f](https://github.com/fe-lce/lowcode-engine/commit/36caf0f18980c16f7ebb82ac845ad6b33e033567)) -- support UMD packageing for react-renderer ([982d0d6](https://github.com/fe-lce/lowcode-engine/commit/982d0d676b3dfbfc10a2190c0040126d6925ed37)) - -### Bug Fixes - -- 🐛 修正一些示例地址 ([8d21283](https://github.com/fe-lce/lowcode-engine/commit/8d212832e77a1ec763db668683917705774acd0d)) -- 兼容 setters 为空的情况 ([56b459a](https://github.com/fe-lce/lowcode-engine/commit/56b459a017a8350a911ef20f0166d1e62b6390e4)) -- 修复 setup 的逻辑 ([1cfb15a](https://github.com/fe-lce/lowcode-engine/commit/1cfb15aebea9796af23b2135f2aa4409d81283d7)) -- 修正一些对内的地址 ([07cc1f2](https://github.com/fe-lce/lowcode-engine/commit/07cc1f2954530c64a1a3d260e8d532c9e19892e8)) -- 增加必要的方法 ([1b38a81](https://github.com/fe-lce/lowcode-engine/commit/1b38a812653656aa02100a3b1b2a581188d1b3ef)) -- fix tsconfig of material-parser ([46725cb](https://github.com/fe-lce/lowcode-engine/commit/46725cb9f3166912c8f5b42f1e0b1177158c1ee3)) -- lint&fix auto generated types.ts ([7dde970](https://github.com/fe-lce/lowcode-engine/commit/7dde9701c7960b29523abddf32421cdbac47016d)) -- The outline tree does not display the loop flag when the loop is an empty array ([191e284](https://github.com/fe-lce/lowcode-engine/commit/191e284f2fa190c2b3aecb4df31849b2bdc99d38)) - -## 1.0.0 (2022-02-17) - -### Features - -- first commit - genesis ([4f4ac51](https://github.com/fe-lce/lowcode-engine/commit/4f4ac5115d18357a7399632860808f6cffc33fad)) diff --git a/modules/code-generator/CONTRIBUTING.md b/modules/code-generator/CONTRIBUTING.md deleted file mode 100644 index 5950d40025..0000000000 --- a/modules/code-generator/CONTRIBUTING.md +++ /dev/null @@ -1,40 +0,0 @@ -# 如何共建 - -1. 拉取最新代码,切换到 develop 分支,基于 develop 分支切出一个 feature 或 hotfix 分支 -2. 到 `lowcode-engine` 项目根目录下,执行 `lerna bootstrap && lerna run build --scope "@felce/lowcode-types"` 来安装依赖并构建 -3. 到 `lowcode-engine/modules/code-generator`下,安装依赖(`npm i`),然后先跑一遍 `npm test` 看看是否所有用例都能通过 (如果网络条件不太好,建议使用 [cnpm - 淘宝提供的中国 NPM 镜像](https://npmmirror.com/)) -4. 在 tests 目录下编写您的需求/问题的测试用例 -5. 修改 src 下的一些代码,然后运行 `npm test` 或 `npm start` 启动 jest 进行调测 -6. 确保所有的测试用例都能通过时,提 MR 给 @牧毅 -- MR 将在 1 个工作日内给您回复意见。 - -当然,欢迎提前私聊沟通 @牧毅,或加入 低代码渲染/出码服务金牌用户群 讨论沟通。 - -# FAQ - -## 如何查看单测覆盖率? - -执行 `npm test:cov` 命令,这样会自动生成单测覆盖率的报告到 `coverage` 目录下。 - -## 如何只执行一个测试用例? - -```sh -npm test -t 'demo2-utils-name-alias' -``` - -## 更新特定测试用例的 expected: - -```sh -npm 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/modules/code-generator/README.md b/modules/code-generator/README.md deleted file mode 100644 index cf61fba9ce..0000000000 --- a/modules/code-generator/README.md +++ /dev/null @@ -1,123 +0,0 @@ -# 出码 - -所谓出码,即将低代码编排出的 schema 进行解析并转换成最终可执行的代码的过程。本模块提供有 Icejs 和 Rax 两套框架的出码方案,并提供了强大而灵活的扩展机制。 - -## 使用方法 - -### 1) 通过命令行快速体验 - -欢迎使用命令行工具快速体验:`npx @felce/lowcode-code-generator -i example-schema.json -o generated -s icejs` - ---其中 example-schema.json 可以从[这里下载](https://unpkg.com/@felce/lowcode-code-generator@beta/example-schema.json) - -### 2) 通过设计器插件快速体验 - -1. 安装依赖: `npm install --save @alilc/lowcode-plugin-code-generator` -2. 注册插件: - -```ts -import { plugins } from '@felce/lowcode-engine'; -import CodeGenPlugin from '@alilc/lowcode-plugin-code-generator'; - -// 在你的初始化函数中: -await plugins.register(CodeGenPlugin); - -// 如果您不希望自动加上出码按钮,则可以这样注册 -await plugins.register(CodeGenPlugin, { disableCodeGenActionBtn: true }); -``` - -然后运行你的低代码编辑器项目即可 -- 在设计器的右上角会出现一个“出码”按钮,点击即可在浏览器中出码并预览。 - -### 3)服务端出码接入 - -此代码生成器一开始就是为服务端出码设计的,你可以直接这样来在 node.js 环境中使用: - -1. 安装依赖: `npm install --save @felce/lowcode-code-generator` -2. 引入代码生成器: - -```js -import CodeGenerator from '@felce/lowcode-code-generator'; -``` - -3. 创建项目构建器: - -```js -const projectBuilder = CodeGenerator.solutions.icejs(); -``` - -4. 生成代码 - -```js -const project = await projectBuilder.generateProject( - schema, // 编排搭建出来的 schema -); -``` - -5. 将生成的代码写入到磁盘中(也可以生成一个 zip 包) - -```js -// 写入磁盘 -await CodeGenerator.publishers.disk().publish({ - project, // 上一步生成的 project - outputPath: '/path/to/your/output/dir', // 输出目录 - projectSlug: 'your-project-slug', // 项目标识 -}); - -// 写入到 zip 包 -await CodeGenerator.publishers.zip().publish({ - project, // 上一步生成的 project - outputPath: '/path/to/your/output/dir', // 输出目录 - projectSlug: 'your-project-slug', // 项目标识 -- 对应生成 your-project-slug.zip 文件 -}); -``` - -注:一般来说在服务端出码可以跟 github/gitlab, CI 和 CD 流程等一起串起来使用,通常用于优化性能。 - -### 4)浏览器中出码接入 - -随着现在电脑性能和浏览器技术的发展,出码其实已经不必非得在服务端做了,借助于 Web Worker 特性,可以在浏览器中进行出码: - -1. 安装依赖: `npm install --save @felce/lowcode-code-generator` -2. 引入代码生成器: - -```js -import * as CodeGenerator from '@felce/lowcode-code-generator/standalone-loader'; -``` - -3. 【可选】提前初始化代码生成器: - -```js -// 提前初始化下,这样后面用的时候更快(这个 init 内部会提前准备好创建 worker 的一些资源) -await CodeGenerator.init(); -``` - -4. 出码 - -```js -const project = await CodeGenerator.generateCode({ - solution: 'icejs', // 出码方案 (目前内置有 icejs 和 rax ) - schema, // 编排搭建出来的 schema -}); - -console.log(project); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果) -``` - -注:一般来说在浏览器中出码适合做即时预览功能。 - -5. 下载 zip 包 - -```js -// 写入到 zip 包 -await CodeGenerator.publishers.zip().publish({ - project, // 上一步生成的 project - projectSlug: 'your-project-slug', // 项目标识 -- 对应下载 your-project-slug.zip 文件 -}); -``` - -### 5)自定义出码 - -前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 欢迎参考 ./src/plugins/xxx 来编写您自己的出码插件,然后参考 ./src/solutions/xxx 将各种插件组合成一套适合您的业务场景的出码方案。 - -## 参与共建 - -欢迎参与共建,如何共建请参阅:[./CONTRIBUTING.md](https://github.com/fe-lce/lowcode-engine/blob/main/modules/code-generator/CONTRIBUTING.md) diff --git a/modules/code-generator/babel.config.js b/modules/code-generator/babel.config.js deleted file mode 100644 index c5986f2bc0..0000000000 --- a/modules/code-generator/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/modules/code-generator/bin/lowcode-code-generator.js b/modules/code-generator/bin/lowcode-code-generator.js deleted file mode 100755 index 79c36c49a0..0000000000 --- a/modules/code-generator/bin/lowcode-code-generator.js +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env node -/* eslint-disable no-var */ -/* eslint-disable prefer-arrow-callback */ -/* eslint-disable @typescript-eslint/no-require-imports */ - -var program = require('commander'); - -program - .command('generate', { isDefault: true }) - .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) - .option('-v, --verbose', 'be verbose, output more information', false) - .option('--solution-options ', 'specify the solution options', '{}') - .arguments('[input-schema] ali lowcode schema JSON file') - .action(function doGenerate(inputSchema, command) { - var options = command.opts(); - if (options.cwd) { - process.chdir(options.cwd); - } - - require('../dist/cli') - .run(inputSchema ? [inputSchema] : [], options) - .then((retCode) => { - process.exit(retCode); - }); - }); - -program - .command('init-solution') - .option('-c, --cwd ', 'specify the working directory', '.') - .option('-q, --quiet', 'be quiet, do not output anything unless get error', false) - .option('-v, --verbose', 'be verbose, output more information', false) - .arguments('') - .action(function initSolution(solutionName, command) { - var options = command.opts(); - if (options.cwd) { - process.chdir(options.cwd); - } - - require('../dist/cli') - .initSolution([solutionName], options) - .then((retCode) => { - process.exit(retCode); - }); - }); - -program.parse(process.argv); - diff --git a/modules/code-generator/example-schema.json b/modules/code-generator/example-schema.json deleted file mode 100644 index 5e31b1bea9..0000000000 --- a/modules/code-generator/example-schema.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "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": "outerView", - "autoLoading": true - }, - "fileName": "test", - "state": { - "text": "outer" - }, - "lifeCycles": { - "componentDidMount": { - "type": "JSFunction", - "value": "function componentDidMount() { console.log('componentDidMount'); }" - } - }, - "dataSource": { - "list": [ - { - "id": "urlParams", - "type": "urlParams" - }, - - { - "id": "user", - "type": "fetch", - "options": { - "method": "GET", - "uri": "https://shs.xxx.com/mock/1458/demo/user", - "isSync": true - }, - "dataHandler": { - "type": "JSFunction", - "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.xxx.com/mock/1458/demo/orders", - "isSync": true - }, - "dataHandler": { - "type": "JSFunction", - "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}" - } - } - ], - "dataHandler": { - "type": "JSFunction", - "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.xxx.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/modules/code-generator/example-schema.json5 b/modules/code-generator/example-schema.json5 deleted file mode 100644 index 4ab02999ec..0000000000 --- a/modules/code-generator/example-schema.json5 +++ /dev/null @@ -1,276 +0,0 @@ -{ - 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: 'outerView', - autoLoading: true, - }, - fileName: 'test', - state: { - text: 'outer', - }, - lifeCycles: { - componentDidMount: { - type: 'JSFunction', - value: "function componentDidMount() { console.log('componentDidMount'); }", - }, - }, - dataSource: { - list: [ - { - id: 'urlParams', - type: 'urlParams', - }, - - { - id: 'user', - type: 'fetch', - options: { - method: 'GET', - uri: 'https://shs.xxx.com/mock/1458/demo/user', - isSync: true, - }, - dataHandler: { - type: 'JSFunction', - 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.xxx.com/mock/1458/demo/orders', - isSync: true, - }, - dataHandler: { - type: 'JSFunction', - value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}', - }, - }, - ], - dataHandler: { - type: 'JSFunction', - 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.xxx.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/modules/code-generator/jest.config.js b/modules/code-generator/jest.config.js deleted file mode 100644 index 0f908143da..0000000000 --- a/modules/code-generator/jest.config.js +++ /dev/null @@ -1,10 +0,0 @@ -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'], - setupFiles: ['./jest.setup.js'], -}; diff --git a/modules/code-generator/jest.setup.js b/modules/code-generator/jest.setup.js deleted file mode 100644 index 67da56145a..0000000000 --- a/modules/code-generator/jest.setup.js +++ /dev/null @@ -1,12 +0,0 @@ -// 对于 standalone 模式的专门 polyfills -if (process.env.TEST_TARGET === 'standalone') { - // 模拟浏览器环境 - global.window = global; - global.self = global; - - // 将所有测试用例里面的 './src' 都替换为 './dist/standalone' - jest.mock('./src', () => require('./dist/standalone')); -} - -// 如果在调试模式下,则不限制超时时间 -jest.setTimeout(typeof v8debug === 'object' ? Infinity : 30 * 1000); diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json deleted file mode 100644 index 48f7c423aa..0000000000 --- a/modules/code-generator/package.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "name": "@felce/lowcode-code-generator", - "version": "1.1.7", - "description": "出码引擎 for LowCode Engine", - "license": "MIT", - "main": "lib/index.js", - "module": "es/index.js", - "typings": "types/index.d.ts", - "files": [ - "bin", - "lib", - "es", - "demo", - "dist", - "types", - "standalone", - "standalone-worker", - "standalone-loader", - "loader", - "CHANGELOG.md", - "README.md", - "CONTRIBUTING.md", - "example-schema.json", - "example-schema.json5" - ], - "bin": { - "lowcode-code-generator": "bin/lowcode-code-generator.js" - }, - "scripts": { - "start": "jest --watchAll", - "build": "npm run clean && node scripts/build", - "build:standalone": "node scripts/build-standalone", - "clean": "rimraf es lib dist types generated demo coverage output test-cases/*/*/actual", - "lint": "eslint --ext .jsx,.js,.ts,.tsx src/", - "lintfix": "eslint --ext .jsx,.js,.ts,.tsx --fix src/", - "check:types": "tsc --noEmit", - "template": "node ./scripts/build-template-static-files.js", - "test": "npm run test:normal && npm run test:standalone", - "test:normal": "jest", - "test:standalone": "node scripts/test-standalone", - "test:cov": "jest --coverage", - "test:update-snapshots": "cross-env UPDATE_EXPECTED=true jest -u", - "analyze:standalone": "ANALYZE=true node scripts/build-standalone", - "release:beta": "standard-version -t @felce/lowcode-code-generator\\@ -r patch --prerelease beta && git push --follow-tags && npm publish --tag beta", - "release:patch": "standard-version -t @felce/lowcode-code-generator\\@ -r patch && git push --follow-tags && npm publish", - "release:minor": "standard-version -t @felce/lowcode-code-generator\\@ -r minor && git push --follow-tags && npm publish", - "prepublishOnly": "npm run build", - "demo": "node bin/lowcode-code-generator.js -i example-schema.json -o demo -s icejs" - }, - "standard-version": { - "skip": { - "changelog": true - } - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged", - "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" - } - }, - "lint-staged": { - "**/*.{js,jsx,ts,tsx}": "eslint" - }, - "dependencies": { - "@felce/lowcode-types": "^1.0.0", - "@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/node-fetch": "2.x", - "@types/qs": "^6.9.6", - "@types/semver": "^7.3.4", - "buffer": "^6.0.3", - "chalk": "^4.1.0", - "change-case": "^3.1.0", - "commander": "^6.1.0", - "debug": "^4.3.2", - "file-saver": "^2.0.5", - "fp-ts": "^2.11.9", - "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", - "nanomatch": "^1.2.13", - "node-fetch": "2.x", - "path-browserify": "^1.0.1", - "prettier": "^2.5.1", - "qs": "^6.10.1", - "semver": "^7.3.4", - "short-uuid": "^3.1.1", - "babel-jest": "^26.5.2", - "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/file-saver": "^2.0.7", - "@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", - "concurrently": "^6.5.1", - "cross-env": "^7.0.3", - "esbuild": "^0.14.5", - "esbuild-plugin-alias": "^0.2.1", - "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": "^26.5.2", - "jest-util": "^27.4.2", - "rimraf": "^3.0.2", - "standard-version": "^9.1.1", - "ts-jest": "^26.5.2", - "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" - }, - "publishConfig": { - "access": "public", - "registry": "https://registry.npmjs.org/" - }, - "repository": { - "type": "http", - "url": "https://github.com/fe-lce/lowcode-engine/tree/main/modules/code-generator" - }, - "bugs": "https://github.com/fe-lce/lowcode-engine/issues", - "homepage": "https://github.com/fe-lce/lowcode-engine/#readme" -} diff --git a/modules/code-generator/scripts/build-cli.js b/modules/code-generator/scripts/build-cli.js deleted file mode 100644 index 40fcb731a6..0000000000 --- a/modules/code-generator/scripts/build-cli.js +++ /dev/null @@ -1,56 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-require-imports */ -const esbuild = require('esbuild'); -const ignorePlugin = require('esbuild-plugin-ignore'); - -// 执行脚本 -(async () => { - try { - console.log('building...'); - const result = await esbuild.build({ - entryPoints: ['src/cli/index.ts'], - outfile: 'dist/cli.js', - bundle: true, - platform: 'node', - target: ['node10'], - format: 'cjs', - sourcemap: true, - sourcesContent: true, - plugins: [ - ignorePlugin([ - // @felce/lowcode-types 中误依赖了 react,这里忽略下 - { - resourceRegExp: /^react$/, - contextRegExp: /./, - }, - { - resourceRegExp: /setter-config/, - contextRegExp: /lowcode-types/, - }, - ]), - ], - define: {}, - treeShaking: true, - minify: false, - minifyWhitespace: false, - minifyIdentifiers: false, - minifySyntax: false, - legalComments: 'external', - external: Object.keys(require('../package.json').dependencies), - }); - if (result.errors.length > 0) { - throw result.errors; - } - - if (result.warnings.length > 0) { - result.warnings.forEach((warnings) => { - console.warn(warnings); - }); - } - - console.log('done'); - } catch (e) { - console.error(e); - process.exit(1); - } -})(); diff --git a/modules/code-generator/scripts/build-standalone-loader.js b/modules/code-generator/scripts/build-standalone-loader.js deleted file mode 100644 index bee318dddb..0000000000 --- a/modules/code-generator/scripts/build-standalone-loader.js +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-require-imports */ -const esbuild = require('esbuild'); - -const packageVersion = require('../package.json').version; -console.log('build standalone-loader: packageVersion=%s', packageVersion); - -const enableAnalyze = process.env.ANALYZE === 'true'; -const buildConfig = { - entryPoints: ['src/standalone-loader.ts'], - outfile: 'dist/standalone-loader.js', - metafile: enableAnalyze, - bundle: true, - target: ['chrome69'], - format: 'cjs', - sourcemap: true, - sourcesContent: true, - external: Object.keys(require('../package.json').dependencies), - define: { - process: JSON.stringify({ - env: { - NODE_ENV: 'production', - STANDALONE: 'true', - }, - }), - __PACKAGE_VERSION__: JSON.stringify(packageVersion), - }, - minify: false, - minifyWhitespace: false, - minifyIdentifiers: false, - minifySyntax: false, - legalComments: 'external', - treeShaking: true, -}; - -// 执行脚本 -(async () => { - try { - console.log('building cjs...'); - const result = await esbuild.build({ - ...buildConfig, - }); - if (result.errors.length > 0) { - throw result.errors; - } - - if (result.warnings.length > 0) { - result.warnings.forEach((warnings) => { - console.warn(warnings); - }); - } - - const result2 = await esbuild.build({ - ...buildConfig, - outfile: buildConfig.outfile.replace(/\.js$/, '.esm.js'), - format: 'esm', - }); - if (result2.errors.length > 0) { - throw result2.errors; - } - - if (result2.warnings.length > 0) { - result2.warnings.forEach((warnings) => { - console.warn(warnings); - }); - } - - console.log('done'); - } catch (e) { - console.error(e); - process.exit(1); - } -})(); diff --git a/modules/code-generator/scripts/build-standalone-worker.js b/modules/code-generator/scripts/build-standalone-worker.js deleted file mode 100644 index 3134566b24..0000000000 --- a/modules/code-generator/scripts/build-standalone-worker.js +++ /dev/null @@ -1,107 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-require-imports */ -const esbuild = require('esbuild'); -const { spawnSync } = require('child_process'); -const ignorePlugin = require('esbuild-plugin-ignore'); -const fs = require('fs'); -const path = require('path'); - -const enableAnalyze = process.env.ANALYZE === 'true'; -const buildConfig = { - entryPoints: ['src/standalone-worker.ts'], - outfile: 'dist/standalone-worker.js', - metafile: enableAnalyze, - bundle: true, - target: ['chrome69'], - format: 'iife', - sourcemap: true, - sourcesContent: true, - plugins: [ - ignorePlugin([ - { - resourceRegExp: /^fs$/, - contextRegExp: /./, - }, - // @felce/lowcode-types 中误依赖了 react,这里忽略下 - { - resourceRegExp: /^react$/, - contextRegExp: /./, - }, - { - resourceRegExp: /setter-config/, - contextRegExp: /lowcode-types|..[\\/]types/, - }, - ]), - ], - define: { - process: JSON.stringify({ - env: { - NODE_ENV: 'production', - STANDALONE: 'true', - }, - }), - }, - treeShaking: true, -}; - -// 执行脚本 -(async () => { - try { - console.log('building...'); - const result = await esbuild.build({ - ...buildConfig, - minify: false, - minifyWhitespace: false, - minifyIdentifiers: false, - minifySyntax: false, - legalComments: 'external', - }); - if (result.errors.length > 0) { - throw result.errors; - } - - if (result.warnings.length > 0) { - result.warnings.forEach((warnings) => { - console.warn(warnings); - }); - } - - if (enableAnalyze) { - const metaFile = buildConfig.outfile.replace(/\.js/, '.meta.json'); - const statsFile = buildConfig.outfile.replace(/\.js/, '.stats.html'); - fs.writeFileSync(metaFile, JSON.stringify(result.metafile || {}), { encoding: 'utf-8' }); - spawnSync('npx', ['esbuild-visualizer', '--metadata', metaFile, '--filename', statsFile], { - shell: true, - stdio: 'inherit', - }); - spawnSync('open', [statsFile], { - shell: true, - stdio: 'inherit', - }); - return; - } - - const outFileContent = fs.readFileSync(buildConfig.outfile, 'utf-8'); - - console.log('minifying...'); - const minifiedOutFile = buildConfig.outfile.replace(/\.js$/, '.min.js'); - const minifiedResult = esbuild.transformSync(outFileContent, { - minify: true, - sourcemap: true, - sourcesContent: true, - sourcefile: path.basename(buildConfig.outfile), - }); - - fs.writeFileSync(minifiedOutFile, minifiedResult.code, { encoding: 'utf-8' }); - fs.writeFileSync(`${minifiedOutFile}.map`, minifiedResult.map, { encoding: 'utf-8' }); - - minifiedResult.warnings.forEach((warnings) => { - console.log(warnings); - }); - - console.log('done'); - } catch (e) { - console.error(e); - process.exit(1); - } -})(); diff --git a/modules/code-generator/scripts/build-standalone.js b/modules/code-generator/scripts/build-standalone.js deleted file mode 100644 index 804a7754db..0000000000 --- a/modules/code-generator/scripts/build-standalone.js +++ /dev/null @@ -1,135 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-require-imports */ -const esbuild = require('esbuild'); -const { spawnSync } = require('child_process'); -const ignorePlugin = require('esbuild-plugin-ignore'); -const fs = require('fs'); -const path = require('path'); - -const UMD_GLOBAL_NAME = 'AliLowCodeCodeGenerator'; - -const enableAnalyze = process.env.ANALYZE === 'true'; -const buildConfig = { - entryPoints: ['src/standalone.ts'], - outfile: 'dist/standalone.js', - metafile: enableAnalyze, - bundle: true, - target: ['chrome69'], - format: 'cjs', - sourcemap: true, - sourcesContent: true, - plugins: [ - ignorePlugin([ - { - resourceRegExp: /^fs$/, - contextRegExp: /./, - }, - // @felce/lowcode-types 中误依赖了 react,这里忽略下 - { - resourceRegExp: /^react$/, - contextRegExp: /./, - }, - { - resourceRegExp: /setter-config/, - contextRegExp: /lowcode-types|..[\\/]types/, - }, - ]), - ], - define: { - process: JSON.stringify({ - env: { - NODE_ENV: 'production', - STANDALONE: 'true', - }, - }), - }, - treeShaking: true, -}; - -// 执行脚本 -(async () => { - try { - console.log('building...'); - const result = await esbuild.build({ - ...buildConfig, - minify: false, - minifyWhitespace: false, - minifyIdentifiers: false, - minifySyntax: false, - legalComments: 'external', - }); - if (result.errors.length > 0) { - throw result.errors; - } - - if (result.warnings.length > 0) { - result.warnings.forEach((warnings) => { - console.warn(warnings); - }); - } - - if (enableAnalyze) { - const metaFile = buildConfig.outfile.replace(/\.js/, '.meta.json'); - const statsFile = buildConfig.outfile.replace(/\.js/, '.stats.html'); - fs.writeFileSync(metaFile, JSON.stringify(result.metafile || {}), { encoding: 'utf-8' }); - spawnSync('npx', ['esbuild-visualizer', '--metadata', metaFile, '--filename', statsFile], { - shell: true, - stdio: 'inherit', - }); - spawnSync('open', [statsFile], { - shell: true, - stdio: 'inherit', - }); - return; - } - - const outFileContent = transformCjsToUmdFile(buildConfig.outfile); - - console.log('minifying...'); - const minifiedOutFile = buildConfig.outfile.replace(/\.js$/, '.min.js'); - const minifiedResult = esbuild.transformSync(outFileContent, { - minify: true, - sourcemap: true, - sourcesContent: true, - sourcefile: path.basename(buildConfig.outfile), - }); - - fs.writeFileSync(minifiedOutFile, minifiedResult.code, { encoding: 'utf-8' }); - fs.writeFileSync(`${minifiedOutFile}.map`, minifiedResult.map, { encoding: 'utf-8' }); - - minifiedResult.warnings.forEach((warnings) => { - console.log(warnings); - }); - - console.log('done'); - } catch (e) { - console.error(e); - process.exit(1); - } -})(); - -// esbuild 没有直接提供 UMD 格式,所以这里我们自行包装转换下 -function transformCjsToUmdFile(file) { - const globalName = UMD_GLOBAL_NAME; - const fileContent = fs.readFileSync(file, { encoding: 'utf-8' }); - const transformedFileContent = `(function (global, factory) { - if (typeof exports === 'object' && typeof module !== 'undefined'){ - factory(module, exports); - } else if (typeof define === 'function' && define.amd) { - define(['module', 'exports'], factory); - } else { - global = global || self; - var m = { exports: {} }; - factory(m, m.exports); - global.${globalName} = m.exports; - } -}(this, function (module, exports) { - 'use strict'; - ${fileContent}; - return module.exports; -})); -`; - - fs.writeFileSync(file, transformedFileContent, { encoding: 'utf-8' }); - return transformedFileContent; -} diff --git a/modules/code-generator/scripts/build-template-static-files.js b/modules/code-generator/scripts/build-template-static-files.js deleted file mode 100644 index c802498a06..0000000000 --- a/modules/code-generator/scripts/build-template-static-files.js +++ /dev/null @@ -1,125 +0,0 @@ -/* 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 '@felce/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 '@felce/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/modules/code-generator/scripts/build-types b/modules/code-generator/scripts/build-types deleted file mode 100755 index 61414063c6..0000000000 --- a/modules/code-generator/scripts/build-types +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -echo building types... -tsc --outDir types --declaration --emitDeclarationOnly && \ - echo built types... && \ - rm -rf types/packages && \ - mv types/modules/code-generator/src/* types/ && \ - rm -rf types/modules - - diff --git a/modules/code-generator/scripts/build.js b/modules/code-generator/scripts/build.js deleted file mode 100644 index 841eacab55..0000000000 --- a/modules/code-generator/scripts/build.js +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-require-imports */ -const _ = require('lodash'); -const esbuild = require('esbuild'); -const concurrently = require('concurrently'); -const argv = require('yargs-parser')(process.argv.slice(2)); -const packageJson = require('../package.json'); - -if (!argv.format) { - buildAll(); -} else { - buildFormat(argv.format, argv.out || 'dist'); -} - -function buildAll() { - concurrently( - [ - { name: 'build:types', command: 'sh scripts/build-types' }, - { name: 'build:cjs', command: 'node scripts/build --format=cjs --out=lib' }, - { name: 'build:esm', command: 'node scripts/build --format=esm --out=es' }, - { name: 'build:standalone', command: 'node scripts/build-standalone' }, - { name: 'build:standalone-worker', command: 'node scripts/build-standalone-worker' }, - { name: 'build:standalone-loader', command: 'node scripts/build-standalone-loader' }, - { name: 'build:cli', command: 'node scripts/build-cli' }, - ], - { - prefix: 'name', - killOthers: ['failure'], - restartTries: 0, - }, - ).then( - () => { - console.log('all done.'); - }, - () => { - process.exit(1); - }, - ); -} - -function buildFormat(format, outDir) { - try { - console.log('building %s...', format); - const startTime = Date.now(); - const result = esbuild.buildSync({ - entryPoints: ['src/index.ts'], - outfile: `${outDir}/index.js`, - bundle: true, - platform: 'node', - target: ['node10'], - format, - sourcemap: true, - sourcesContent: true, - define: {}, - treeShaking: true, - external: _.keys(packageJson.dependencies), - minify: false, - legalComments: 'external', - }); - if (result.errors.length > 0) { - throw result.errors; - } - - if (result.warnings.length > 0) { - result.warnings.forEach((warnings) => { - console.warn(warnings); - }); - } - - console.log('built %s in %ds', format, ((Date.now() - startTime) / 1000).toFixed(2)); - } catch (e) { - console.error(e); - process.exit(1); - } -} diff --git a/modules/code-generator/scripts/move-files-to-build-dest.js b/modules/code-generator/scripts/move-files-to-build-dest.js deleted file mode 100644 index 736df9968f..0000000000 --- a/modules/code-generator/scripts/move-files-to-build-dest.js +++ /dev/null @@ -1,24 +0,0 @@ -/* 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/modules/code-generator/scripts/run-demo-project b/modules/code-generator/scripts/run-demo-project deleted file mode 100755 index 1ad7dce234..0000000000 --- a/modules/code-generator/scripts/run-demo-project +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env node - -// @ts-check -const program = require('commander'); -const { spawnSync } = require('child_process'); -const glob = require('glob'); -const fs = require('fs'); -const path = require('path'); -const _ = require('lodash'); - -program - .option('--npm ', 'specify the npm command location or alias') - .arguments('') - .action((project, options) => { - try { - if (!fs.existsSync(project)) { - throw new Error(`Project ${project} does not exist`); - } - - const getProjectActualPath = [ - () => path.resolve(process.cwd(), project), - () => - path.resolve( - process.cwd(), - path.join( - project, - path.dirname(glob.sync('*/package.json', { cwd: project })[0] || ''), - ), - ), - ] - .map((x) => _.memoize(x)) - .find((x) => fs.existsSync(path.join(x(), 'package.json'))); - - if (!getProjectActualPath) { - throw new Error(`Project ${project} is not a valid project(no package.json)`); - } - - const projectActualPath = getProjectActualPath(); - if (path.resolve(process.cwd(), project) !== projectActualPath) { - console.log('Changing directory to', path.relative(process.cwd(), projectActualPath)); - } - - process.chdir(projectActualPath); - - const npm = options.npm || 'npm'; - const cmd = `${npm} install && ${npm} start`; - console.log('# %s', cmd); - spawnSync(cmd, { stdio: 'inherit', shell: true }); - } catch (err) { - console.log(err); - process.exit(1); - } - }); - -program.parse(process.argv); diff --git a/modules/code-generator/scripts/test-standalone.js b/modules/code-generator/scripts/test-standalone.js deleted file mode 100644 index 55d876d573..0000000000 --- a/modules/code-generator/scripts/test-standalone.js +++ /dev/null @@ -1,17 +0,0 @@ -// 测试 standalone 模式的基本功能 -// 注1:指定文件测试就直接在后面加文件: node scripts/test-standalone.js tests/public/rax-app.test.ts -// 注2:指定测试用例就直接在后面加`-t xxx`: node scripts/test-standalone.js tests/public/rax-app.test.ts -t demo01 -const { spawnSync } = require('child_process'); - -// 一定要先构建 -spawnSync('npm', ['run', 'build:standalone'], { shell: true, stdio: 'inherit' }); - -// 然后只执行特定的一些测试用例 -spawnSync('npx', ['jest', ...process.argv.slice(2)], { - env: { - ...process.env, - TEST_TARGET: 'standalone', - }, - shell: true, - stdio: 'inherit', -}); diff --git a/modules/code-generator/src/analyzer/componentAnalyzer.ts b/modules/code-generator/src/analyzer/componentAnalyzer.ts deleted file mode 100644 index 8a504aeec7..0000000000 --- a/modules/code-generator/src/analyzer/componentAnalyzer.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { IPublicTypeNodeSchema, IPublicTypeCompositeObject } from '@felce/lowcode-types'; -import type { TComponentAnalyzer } from '../types'; - -import { handleSubNodes } from '../utils/schema'; - -export const componentAnalyzer: TComponentAnalyzer = (container) => { - let hasRefAttr = false; - const nodeValidator = (n: IPublicTypeNodeSchema) => { - if (n.props) { - const props = n.props as IPublicTypeCompositeObject; - 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/modules/code-generator/src/cli/index.ts b/modules/code-generator/src/cli/index.ts deleted file mode 100644 index fcbbc8a349..0000000000 --- a/modules/code-generator/src/cli/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './run'; -export * from './init-solution'; diff --git a/modules/code-generator/src/cli/init-solution.ts b/modules/code-generator/src/cli/init-solution.ts deleted file mode 100644 index 63ee66ea87..0000000000 --- a/modules/code-generator/src/cli/init-solution.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable no-console */ -import * as fs from 'fs-extra'; -import * as path from 'path'; -import chalk from 'chalk'; -import * as changeCase from 'change-case'; -import { getErrorMessage } from '../utils/errors'; -import { getLowcodeSolutionTemplateFiles } from './solutions/example-solution'; - - -export async function initSolution(args: string[], options: { - quiet?: boolean; - verbose?: boolean; -}) { - try { - const cwd = process.cwd(); - let solutionName = args[0] || 'hello'; - let solutionPath = path.resolve(cwd, solutionName); - if (solutionName === '.') { - solutionName = path.basename(cwd); - solutionPath = cwd; - } - - const modifyFileContent = (content: string) => - content - .replace(/hello-world/g, changeCase.paramCase(solutionName)) - .replace(/HelloWorld/g, changeCase.pascalCase(solutionName)) - .replace(/Hello World/g, changeCase.titleCase(solutionName)); - - await ensureDirExists(solutionPath); - - const templateFiles = getLowcodeSolutionTemplateFiles(); - for (const templateFile of templateFiles) { - if (options.verbose) { - console.log('%s', chalk.gray(`creating file ${templateFile.file}`)); - } - - const templateFilePath = path.join(solutionPath, templateFile.file); - await ensureDirExists(path.dirname(templateFilePath)); - await fs.writeFile(templateFilePath, modifyFileContent(templateFile.content), { encoding: 'utf-8' }); - } - - if (!options.quiet) { - console.log('%s', chalk.green(`solution ${solutionName} created successfully`)); - } - - return 0; - } catch (e) { - console.log(chalk.red(getErrorMessage(e) || `Unexpected error: ${e}`)); - if (typeof e === 'object' && (e as { stack: string } | null)?.stack && options.verbose) { - console.log(chalk.gray((e as { stack: string }).stack)); - } - return 1; - } -} - -async function ensureDirExists(dirPath: string) { - try { - await fs.mkdir(dirPath, { recursive: true }); - } catch (e) { - if ((e as { code: string }).code === 'EEXIST') { - return;// ignore existing error - } - throw e; - } -} \ No newline at end of file diff --git a/modules/code-generator/src/cli/run.ts b/modules/code-generator/src/cli/run.ts deleted file mode 100644 index 304f5ea9aa..0000000000 --- a/modules/code-generator/src/cli/run.ts +++ /dev/null @@ -1,146 +0,0 @@ -/* 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 { IPublicTypeProjectSchema } from '@felce/lowcode-types'; - -/** - * 执行出码 CLI 命令 - * @param args 入参数组 - * @param options 选项 - * @returns {Promise} 错误码 - */ -export async function run( - args: string[], - options: { - solution: string; - input?: string; - output?: string; - quiet?: boolean; - verbose?: boolean; - solutionOptions?: string; - }, -): 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', - ); - } - - let solutionOptions = {}; - - if (options.solutionOptions) { - try { - solutionOptions = JSON.parse(options.solutionOptions); - } catch (err: any) { - throw new Error(`solution options parse error, error message is "${err.message}"`); - } - } - - // 读取 Schema - const schema = await loadSchemaFile(schemaFile); - - // 创建一个项目构建器 - const createProjectBuilder = await getProjectBuilderFactory(options.solution, { - quiet: options.quiet, - }); - const builder = createProjectBuilder(solutionOptions); - - // 生成代码 - 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}`)); - if (typeof e === 'object' && (e as { stack: string } | null)?.stack && options.verbose) { - console.log(chalk.gray((e as { stack: string }).stack)); - } - return 1; - } -} - -async function getProjectBuilderFactory( - solution: string, - { quiet }: { quiet?: boolean }, -): Promise<(options: { [prop: string]: any }) => IProjectBuilder> { - if (solution in CodeGenerator.solutions) { - return CodeGenerator.solutions[solution as 'icejs' | 'rax']; - } - - const solutionPackageName = isLocalSolution(solution) - ? solution - : `${solution.startsWith('@') ? solution : `@alilc/lowcode-solution-${solution}`}`; - - if (!isLocalSolution(solution)) { - if (!quiet) { - console.log(`"${solution}" is not internal, installing it as ${solutionPackageName}...`); - } - - spawnSync('npm', ['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/modules/code-generator/src/cli/solutions/example-solution.ts b/modules/code-generator/src/cli/solutions/example-solution.ts deleted file mode 100644 index 6c779292fe..0000000000 --- a/modules/code-generator/src/cli/solutions/example-solution.ts +++ /dev/null @@ -1,795 +0,0 @@ -export function getLowcodeSolutionTemplateFiles() { - return [ - { - file: '.editorconfig', - content: `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 -`, - }, - { - file: '.eslintignore', - content: `# 忽略目录 -node_modules/ -build/ -dist/ -test-cases/ -test/ -tests/ -output/ -es/ -lib/ -coverage/ - -# 忽略文件 -**/*.min.js -**/*-min.js -**/*.bundle.js -`, - }, - { - file: '.eslintrc.js', - content: `module.exports = { - extends: 'eslint-config-ali/typescript/react', - rules: { - 'max-len': ['error', { code: 200 }], - 'comma-dangle': 0, - }, -}; -`, - }, - { - file: '.gitignore', - content: `# project custom -build -es -lib -dist -output -package-lock.json -deploy-space/packages -deploy-space/.env -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 -`, - }, - { - file: '.prettierignore', - content: '/test-cases/', - }, - { - file: '.prettierrc', - content: `{ - "tabWidth": 2, - "singleQuote": true, - "trailingComma": "es5" -} -`, - }, - { - file: 'CHANGELOG.md', - content: '', - }, - { - file: 'CONTRIBUTING.md', - content: `# 欢迎共建 - -# 注意 - -- 注意解决 eslint 问题 -- 注意代码格式化 -- 建议安装 prettier 插件 -- 发布前注意要跑通 demo 和所有的单测 - -## 本地调试运行 Demo - -\`\`\`sh -> npm run demo -\`\`\` - -## 本地跑单测 - -\`\`\`sh -> npm test -\`\`\` -`, - }, - { - file: 'README.md', - content: `# 低代码出码自定义方案之 Hello World - -## 直接执行 - -\`\`\`sh -> npx ali-lowcode-solution-hello-world demo-schema.json -\`\`\` - -## 本地调试运行 Demo - -\`\`\`sh -> npm run demo -\`\`\` -`, - }, - { - file: 'demo-schema.json', - content: `{ - "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": "JSFunction", - "value": "function componentDidMount() {\\n console.log('componentDidMount');\\n}" - } - }, - "methodsModule": { - "type": "JSModule", - "source": "export function helloWorld() {\\n console.log('Hello world!');\\n}\\n" - }, - "dataSource": { - "list": [ - { - "id": "urlParams", - "type": "urlParams" - }, - - { - "id": "user", - "type": "fetch", - "options": { - "method": "GET", - "uri": "https://shs.xxx.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.xxx.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.xxx.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": "月飞" - } -} -`, - }, - { - file: 'jest.config.js', - content: `module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - testPathIgnorePatterns: ['/node_modules/', '/test-cases/', '/static-files/', '/lib/'], -}; -`, - }, - { - file: 'package.json', - content: `{ - "name": "ali-lowcode-solution-hello-world", - "version": "1.0.0", - "description": "AlLowCode Code Generate Solution - Hello World", - "files": [ - "src", - "lib", - "tests", - "jest.config.js", - ".editorconfig", - ".eslintignore", - ".eslintrc.js", - ".gitignore", - ".prettierignore", - ".prettierrc", - "CHANGELOG.md", - "CONTRIBUTING.md", - "demo-schema.json", - "package.json", - "README.md", - "tsconfig.json" - ], - "main": "lib/index.js", - "scripts": { - "start": "jest --watch", - "build": "npm run clean && concurrently 'npm run build:ts' 'npm run lint'", - "build:ts": "tsc", - "check:type": "tsc -p . --noEmit", - "clean": "rm -rf build dist lib generated", - "dev": "build-scripts start", - "lint": "eslint --ext .tsx,.ts,.js,.jsx src", - "lintfix": "eslint --fix --color --ext .tsx,.ts,.js,.jsx src", - "lint-staged": "lint-staged", - "prepublishOnly": "npm run build", - "postpublish": "git push origin master --tags", - "test": "jest", - "test:watch": "jest --watch", - "test:update-snapshots": "cross-env UPDATE_EXPECTED=true npx jest", - "demo": "npm run build && npx @felce/lowcode-code-generator --solution . --output generated demo-schema.json" - }, - "repository": { - "type": "git", - "url": "git@github.com:your-name/ali-lowcode-solution-hello-world.git" - }, - "author": "", - "license": "ISC", - "publishConfig": { - "registry": "https://registry.npm.xxx.com" - }, - "dependencies": { - "@felce/lowcode-code-generator": "^1.0.0", - "@felce/lowcode-types": "^1.0.0", - "tslib": "^2.3.0" - }, - "devDependencies": { - "@types/async": "^3.2.3", - "@types/jest": "^26.0.17", - "@typescript-eslint/eslint-plugin": "^4.28.4", - "@typescript-eslint/parser": "^4.28.4", - "async": "^3.2.0", - "babel-runtime": "^6.26.0", - "concurrently": "^5.2.0", - "cross-env": "^7.0.0", - "debug": "^4.1.1", - "eslint": "^7.31.0", - "eslint-config-ali": "^12.1.0", - "eslint-plugin-import": "^2.23.4", - "eslint-plugin-react": "^7.24.0", - "eslint-plugin-react-hooks": "^4.2.0", - "glob": "^7.2.0", - "husky": "4.2.5", - "jest": "^26.6.3", - "json5": "^2.2.0", - "lint-staged": "10.1.x", - "lodash": "^4.17.21", - "md5": "^2.2.1", - "prettier": "^2.3.2", - "ts-jest": "^26.4.4", - "ts-node": "^9.0.0", - "typescript": "4.x" - } -} -`, - }, - { - file: 'tsconfig.json', - content: `{ - "compilerOptions": { - "esModuleInterop": true, - "declaration": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "importHelpers": true, - "incremental": false, - "jsx": "react", - "moduleResolution": "node", - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "stripInternal": true, - "outDir": "./lib", - "declarationDir": "./lib", - "rootDirs": ["./src"], - "target": "es6", - "module": "commonjs", - "lib": ["esnext"], - "types": ["jest", "node"], - "noUnusedLocals": false, - "noUnusedParameters": false - }, - "include": ["src/**/*", "typings/**/*"] -} -`, - }, - { - file: 'src/index.ts', - content: `import CodeGen from '@felce/lowcode-code-generator'; - -import examplePlugin from './plugins/example'; - -export default function createHelloWorldProjectBuilder() { - return CodeGen.createProjectBuilder({ - template: CodeGen.solutionParts.icejs.template, - plugins: { - components: [ - CodeGen.plugins.icejs.reactCommonDeps(), - CodeGen.plugins.common.esModule({ fileType: 'jsx' }), - CodeGen.plugins.common.styleImport(), - CodeGen.plugins.icejs.containerClass(), - CodeGen.plugins.icejs.containerInjectContext(), - CodeGen.plugins.icejs.containerInjectUtils(), - CodeGen.plugins.icejs.containerInjectDataSourceEngine(), - CodeGen.plugins.icejs.containerInjectI18n(), - CodeGen.plugins.icejs.containerInjectConstants(), - CodeGen.plugins.icejs.containerInitState(), - CodeGen.plugins.icejs.containerLifeCycle(), - CodeGen.plugins.icejs.containerMethod(), - examplePlugin(), - CodeGen.plugins.icejs.jsx({ - nodeTypeMapping: { - Div: 'div', - Component: 'div', - Page: 'div', - Block: 'div', - }, - }), - CodeGen.plugins.style.css(), - ], - pages: [ - CodeGen.plugins.icejs.reactCommonDeps(), - CodeGen.plugins.common.esModule({ fileType: 'jsx' }), - CodeGen.plugins.common.styleImport(), - CodeGen.plugins.icejs.containerClass(), - CodeGen.plugins.icejs.containerInjectContext(), - CodeGen.plugins.icejs.containerInjectUtils(), - CodeGen.plugins.icejs.containerInjectDataSourceEngine(), - CodeGen.plugins.icejs.containerInjectI18n(), - CodeGen.plugins.icejs.containerInjectConstants(), - CodeGen.plugins.icejs.containerInitState(), - CodeGen.plugins.icejs.containerLifeCycle(), - CodeGen.plugins.icejs.containerMethod(), - examplePlugin(), - CodeGen.plugins.icejs.jsx({ - nodeTypeMapping: { - Div: 'div', - Component: 'div', - Page: 'div', - Block: 'div', - }, - }), - CodeGen.plugins.style.css(), - ], - router: [ - CodeGen.plugins.common.esModule(), - CodeGen.solutionParts.icejs.plugins.router(), - ], - entry: [CodeGen.solutionParts.icejs.plugins.entry()], - constants: [CodeGen.plugins.project.constants()], - utils: [ - CodeGen.plugins.common.esModule(), - CodeGen.plugins.project.utils('react'), - ], - i18n: [CodeGen.plugins.project.i18n()], - globalStyle: [CodeGen.solutionParts.icejs.plugins.globalStyle()], - htmlEntry: [CodeGen.solutionParts.icejs.plugins.entryHtml()], - packageJSON: [CodeGen.solutionParts.icejs.plugins.packageJSON()], - }, - postProcessors: [CodeGen.postprocessor.prettier()], - }); -} -`, - }, - { - file: 'src/plugins/example.ts', - content: `import { - ICodeStruct, - BuilderComponentPlugin, - BuilderComponentPluginFactory, - FileType, - ChunkType, - IContainerInfo, - COMMON_CHUNK_NAME, - CLASS_DEFINE_CHUNK_NAME, - DEFAULT_LINK_AFTER, -} from '@felce/lowcode-code-generator'; - -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 & { - methodsModule?: { - type?: 'JSModule'; - source?: string; - }; - }; - - if (ir.methodsModule?.type !== 'JSModule' || !ir.methodsModule?.source) { - return next; - } - - // 创建 methods.jsx - next.chunks.push({ - type: ChunkType.STRING, - subModule: 'methods', - fileType: cfg.fileType, - name: COMMON_CHUNK_NAME.CustomContent, - content: ir.methodsModule.source, - linkAfter: [], - }); - - // 引入对应的模块 - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: COMMON_CHUNK_NAME.InternalDepsImport, - content: "import __$$methodsModule from './methods';", - linkAfter: [...DEFAULT_LINK_AFTER[COMMON_CHUNK_NAME.InternalDepsImport]], - }); - - // 将导出的东东都放到 class 上实例方法部分 - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, - content: 'Object.assign(this, __$$methodsModule);', - linkAfter: [ - ...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent], - ], - }); - - return next; - }; - - return plugin; -}; - -export default pluginFactory; -`, - }, - { - file: 'tests/basic.test.ts', - content: `test('basic functions should be ok', () => { - // 这里放一些单元测试 - expect(0).toBe(0); -}); -`, - }, - ]; -} diff --git a/modules/code-generator/src/config/env.ts b/modules/code-generator/src/config/env.ts deleted file mode 100644 index 30d564c06e..0000000000 --- a/modules/code-generator/src/config/env.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as path from 'path'; - -export const CODE_GENERATOR_ROOT = path.join(__dirname, '../..'); diff --git a/modules/code-generator/src/const/file.ts b/modules/code-generator/src/const/file.ts deleted file mode 100644 index d29ea43a33..0000000000 --- a/modules/code-generator/src/const/file.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { FileType } from '../types/core'; - -export const FILE_TYPE_FAMILY = [[FileType.TSX, FileType.TS, FileType.JSX, FileType.JS]]; diff --git a/modules/code-generator/src/const/generator.ts b/modules/code-generator/src/const/generator.ts deleted file mode 100644 index 1197458381..0000000000 --- a/modules/code-generator/src/const/generator.ts +++ /dev/null @@ -1,129 +0,0 @@ -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/modules/code-generator/src/const/index.ts b/modules/code-generator/src/const/index.ts deleted file mode 100644 index 24449ca429..0000000000 --- a/modules/code-generator/src/const/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -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']; - -// built-in slot names which have been handled in ProjectBuilder -export const BUILTIN_SLOT_NAMES = [ - 'pages', - 'components', - 'router', - 'entry', - 'appConfig', - 'buildConfig', - 'constants', - 'utils', - 'i18n', - 'globalStyle', - 'htmlEntry', - 'packageJSON', - 'demo', -]; - -export const isBuiltinSlotName = function (name: string) { - return BUILTIN_SLOT_NAMES.includes(name); -}; - -export * from './file'; -export * from './generator'; diff --git a/modules/code-generator/src/core/jsx/handlers/transformJsExpression.ts b/modules/code-generator/src/core/jsx/handlers/transformJsExpression.ts deleted file mode 100644 index 3bdb8fb5c1..0000000000 --- a/modules/code-generator/src/core/jsx/handlers/transformJsExpression.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { IScope } from '../../../types'; -import { parseExpression } from '../../../utils/expressionParser'; -import { isLiteralAtomicExpr } from '../util/isLiteralAtomicExpr'; -import { isSimpleStraightLiteral } from '../util/isSimpleStraightLiteral'; -import { transformThis2Context } from './transformThis2Context'; - -export function transformJsExpr( - expr: string, - scope: IScope, - { dontWrapEval = false, dontTransformThis2ContextAtRootScope = false } = {}, -) { - if (!expr) { - return 'undefined'; - } - - if (isLiteralAtomicExpr(expr)) { - return expr; - } - - const exprAst = parseExpression(expr); - - // 对于下面这些比较安全的字面值,可以直接返回对应的表达式,而非包一层 - if (isSimpleStraightLiteral(exprAst)) { - return expr; - } - - if (dontWrapEval) { - return transformThis2Context(exprAst, scope, { - ignoreRootScope: dontTransformThis2ContextAtRootScope, - }); - } - - switch (exprAst.type) { - // 对于直接写个函数的,则不用再包下,因为这样不会抛出异常的 - case 'ArrowFunctionExpression': - case 'FunctionExpression': - return transformThis2Context(exprAst, scope, { - ignoreRootScope: dontTransformThis2ContextAtRootScope, - }); - - default: - break; - } - - // 其他的都需要包一层 - return `__$$eval(() => (${transformThis2Context(exprAst, scope, { - ignoreRootScope: dontTransformThis2ContextAtRootScope, - })}))`; -} diff --git a/modules/code-generator/src/core/jsx/handlers/transformThis2Context.ts b/modules/code-generator/src/core/jsx/handlers/transformThis2Context.ts deleted file mode 100644 index fbb1c17cbc..0000000000 --- a/modules/code-generator/src/core/jsx/handlers/transformThis2Context.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Expression } from '@babel/types'; -import generate from '@babel/generator'; -import { IScope } from '../../../types'; -import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser'; - -/** - * 将所有的 this.xxx 替换为 __$$context.xxx - * @param expr - */ -export function transformThis2Context( - expr: string | Expression, - scope: IScope, - { ignoreRootScope = false } = {}, -): string { - if (ignoreRootScope && scope.parent == null) { - return typeof expr === 'string' ? expr : generate(expr).code; - } - - // 下面这种字符串替换的方式虽然简单直接,但是对于复杂场景会误匹配,故后期改成了解析 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() || [], - ); -} diff --git a/modules/code-generator/src/core/jsx/util/isLiteralAtomicExpr.ts b/modules/code-generator/src/core/jsx/util/isLiteralAtomicExpr.ts deleted file mode 100644 index fe0c95a9d1..0000000000 --- a/modules/code-generator/src/core/jsx/util/isLiteralAtomicExpr.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * 判断是否是原子类型的表达式 - */ -export function isLiteralAtomicExpr(expr: string): boolean { - return ( - expr === 'null' || - expr === 'undefined' || - expr === 'true' || - expr === 'false' || - /^-?\d+(\.\d+)?$/.test(expr) - ); -} diff --git a/modules/code-generator/src/core/jsx/util/isSimpleStraightLiteral.ts b/modules/code-generator/src/core/jsx/util/isSimpleStraightLiteral.ts deleted file mode 100644 index 0b071527bd..0000000000 --- a/modules/code-generator/src/core/jsx/util/isSimpleStraightLiteral.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Expression } from '@babel/types'; - -/** 判断是非是一些简单直接的字面值 */ -export 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; - } -} diff --git a/modules/code-generator/src/generator/ChunkBuilder.ts b/modules/code-generator/src/generator/ChunkBuilder.ts deleted file mode 100644 index 6799d5940d..0000000000 --- a/modules/code-generator/src/generator/ChunkBuilder.ts +++ /dev/null @@ -1,123 +0,0 @@ -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/modules/code-generator/src/generator/CodeBuilder.ts b/modules/code-generator/src/generator/CodeBuilder.ts deleted file mode 100644 index e633babbf5..0000000000 --- a/modules/code-generator/src/generator/CodeBuilder.ts +++ /dev/null @@ -1,103 +0,0 @@ -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/modules/code-generator/src/generator/ModuleBuilder.ts b/modules/code-generator/src/generator/ModuleBuilder.ts deleted file mode 100644 index d0fc943758..0000000000 --- a/modules/code-generator/src/generator/ModuleBuilder.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { IPublicTypeProjectSchema, ResultFile, ResultDir } from '@felce/lowcode-types'; - -import { - BuilderComponentPlugin, - CodeGeneratorError, - ICodeChunk, - ICompiledModule, - IContextData, - 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; - contextData?: IContextData; - } = { - 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, { - ir: input, - chunks: [], - depNames: [], - contextData: options.contextData || {}, - }); - - 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, ext: type, name } = file; - options.postProcessors.forEach((processer) => { - content = processer(content, type, name); - }); - - return createResultFile(file.name, type, content); - }); - } - - return { - files, - }; - }; - - const generateModuleCode = async ( - schema: IPublicTypeProjectSchema | 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/modules/code-generator/src/generator/ProjectBuilder.ts b/modules/code-generator/src/generator/ProjectBuilder.ts deleted file mode 100644 index 4e6d57e151..0000000000 --- a/modules/code-generator/src/generator/ProjectBuilder.ts +++ /dev/null @@ -1,372 +0,0 @@ -import { ResultDir, ResultFile, IPublicTypeProjectSchema } from '@felce/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 './ModuleBuilder'; -import { ProjectPreProcessor, ProjectPostProcessor, IContextData } from '../types/core'; -import { CodeGeneratorError } from '../types/error'; -import { isBuiltinSlotName } from '../const'; - -interface IModuleInfo { - moduleName?: string; - path: string[]; - files: ResultFile[]; -} - -export interface ProjectBuilderInitOptions { - /** 项目模板 */ - template: IProjectTemplate; - - /** 项目插件 */ - plugins: IProjectPlugins; - - /** 模块后置处理器 */ - postProcessors: PostProcessor[]; - - /** Schema 解析器 */ - schemaParser?: ISchemaParser; - - /** 项目级别的前置处理器 */ - projectPreProcessors?: ProjectPreProcessor[]; - - /** 项目级别的后置处理器 */ - projectPostProcessors?: ProjectPostProcessor[]; - - /** 是否处于严格模式 */ - inStrictMode?: boolean; - - /** 一些额外的上下文数据 */ - extraContextData?: Record; - - /** - * Hook which is used to customize original options, we can reorder/add/remove plugins/processors - * of the existing solution. - */ - customizeBuilderOptions?(originalOptions: ProjectBuilderInitOptions): ProjectBuilderInitOptions; -} - -export class ProjectBuilder implements IProjectBuilder { - /** 项目模板 */ - private template: IProjectTemplate; - - /** 项目插件 */ - private plugins: IProjectPlugins; - - /** 模块后置处理器 */ - private postProcessors: PostProcessor[]; - - /** Schema 解析器 */ - private schemaParser: ISchemaParser; - - /** 项目级别的前置处理器 */ - private projectPreProcessors: ProjectPreProcessor[]; - - /** 项目级别的后置处理器 */ - private projectPostProcessors: ProjectPostProcessor[]; - - /** 是否处于严格模式 */ - readonly inStrictMode: boolean; - - /** 一些额外的上下文数据 */ - readonly extraContextData: IContextData; - - constructor(builderOptions: ProjectBuilderInitOptions) { - let customBuilderOptions = builderOptions; - if (typeof builderOptions.customizeBuilderOptions === 'function') { - customBuilderOptions = builderOptions.customizeBuilderOptions(builderOptions); - } - const { - template, - plugins, - postProcessors, - schemaParser = new SchemaParser(), - projectPreProcessors = [], - projectPostProcessors = [], - inStrictMode = false, - extraContextData = {}, - } = customBuilderOptions; - this.template = template; - this.plugins = plugins; - this.postProcessors = postProcessors; - this.schemaParser = schemaParser; - this.projectPreProcessors = projectPreProcessors; - this.projectPostProcessors = projectPostProcessors; - this.inStrictMode = inStrictMode; - this.extraContextData = extraContextData; - } - - async generateProject(originalSchema: IPublicTypeProjectSchema | string): Promise { - // Init - const { schemaParser } = this; - - let schema: IPublicTypeProjectSchema = - typeof originalSchema === 'string' ? JSON.parse(originalSchema) : originalSchema; - - // Parse / Format - // Preprocess - for (const preProcessor of this.projectPreProcessors) { - // eslint-disable-next-line no-await-in-loop - schema = await preProcessor(schema); - } - - // Validate - if (!schemaParser.validate(schema)) { - throw new CodeGeneratorError('Schema is invalid'); - } - - // Collect Deps - // Parse JSExpression - const parseResult: IParseResult = schemaParser.parse(schema); - - const projectRoot = await this.template.generateTemplate(parseResult); - - let buildResult: IModuleInfo[] = []; - - const builders = this.createModuleBuilders({ - extraContextData: { - projectRemark: parseResult?.project?.projectRemark, - template: this.template, - }, - }); - // 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, - }); - } - - // demo - if (parseResult.project && builders.demo) { - const { files } = await builders.demo.generateModule(parseResult.project); - buildResult.push({ - path: this.template.slots.demo.path, - files, - }); - } - - // handle extra slots - await this.generateExtraSlots(builders, parseResult, buildResult); - - // Post Process - const isSingleComponent = parseResult?.project?.projectRemark?.isSingleComponent; - // Combine Modules - buildResult.forEach((moduleInfo) => { - let targetDir = getDirFromRoot(projectRoot, moduleInfo.path); - // if project only contain single component, skip creation of directory. - if (moduleInfo.moduleName && !isSingleComponent) { - 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, { - template: this.template, - parseResult, - }); - } - - return finalResult; - } - - private createModuleBuilders( - extraContextData: Record = {}, - ): 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, - contextData: { - // template: this.template, - inStrictMode: this.inStrictMode, - tolerateEvalErrors: true, - evalErrorsHandler: '', - ...this.extraContextData, - ...extraContextData, - }, - ...options, - }); - } - }); - - return builders; - } - - private async generateExtraSlots( - builders: Record, - parseResult: IParseResult, - buildResult: IModuleInfo[], - ) { - for (const slotName in this.template.slots) { - if (!isBuiltinSlotName(slotName)) { - const { files } = await builders[slotName].generateModule(parseResult); - buildResult.push({ - path: this.template.slots[slotName].path, - files, - }); - } - } - } -} - -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/modules/code-generator/src/index.ts b/modules/code-generator/src/index.ts deleted file mode 100644 index da9b12d877..0000000000 --- a/modules/code-generator/src/index.ts +++ /dev/null @@ -1,121 +0,0 @@ -/** - * 低代码引擎的出码模块,负责将编排产出的 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 icejsPlugins } from './solutions/icejs'; -import createIceJs3ProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3'; -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 styleImport from './plugins/common/styleImport'; - -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 globalUtils from './utils'; - -import * as CONSTANTS from './const'; - -// 引入内置解决方案模块 -import icejs from './plugins/project/framework/icejs'; -import icejs3 from './plugins/project/framework/icejs3'; -import rax from './plugins/project/framework/rax'; - -export default { - createProjectBuilder, - createModuleBuilder, - solutions: { - icejs: createIceJsProjectBuilder, - icejs3: createIceJs3ProjectBuilder, - rax: createRaxAppProjectBuilder, - }, - solutionParts: { - icejs, - icejs3, - rax, - }, - publishers: { - disk: createDiskPublisher, - zip: createZipPublisher, - }, - plugins: { - common: { - - /** - * 处理 ES Module - * @deprecated please use esModule - */ - esmodule, - esModule: esmodule, - requireUtils, - styleImport, - }, - style: { - css, - }, - project: { - constants, - i18n, - utils, - }, - icejs: { - ...icejsPlugins, - }, - icejs3: { - ...icejs3Plugins, - }, - rax: { - ...raxPlugins, - }, - - /** - * @deprecated please use icejs - */ - react: { - ...icejsPlugins, - }, - }, - postprocessor: { - prettier, - }, - utils: globalUtils, - 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/modules/code-generator/src/parser/SchemaParser.ts b/modules/code-generator/src/parser/SchemaParser.ts deleted file mode 100644 index 83dfc9838b..0000000000 --- a/modules/code-generator/src/parser/SchemaParser.ts +++ /dev/null @@ -1,394 +0,0 @@ -/** - * 解析器是对输入的固定格式数据做拆解,使其符合引擎后续步骤预期,完成统一处理逻辑的步骤。 - * 本解析器面向的是标准 schema 协议。 - */ -import changeCase from 'change-case'; -import { - IPublicTypeUtilItem, - IPublicTypeNodeDataType, - IPublicTypeNodeSchema, - IPublicTypeContainerSchema, - IPublicTypeProjectSchema, - IPublicTypePropsMap, - IPublicTypeNodeData, - IPublicTypeNpmInfo, -} from '@felce/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, isValidContainerType, ContainerType } from '../utils/schema'; -import { uniqueArray } from '../utils/common'; -import { componentAnalyzer } from '../analyzer/componentAnalyzer'; -import { ensureValidClassName } from '../utils/validate'; -import type { ProjectRemark } from '../types/intermediate'; - -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: IPublicTypeNodeSchema): void { - if (schema.props) { - if (Array.isArray(schema.props)) { - // FIXME: is array type props description - } else { - const nodeProps = schema.props as IPublicTypePropsMap; - if (nodeProps.children) { - if (!schema.children) { - // eslint-disable-next-line no-param-reassign - schema.children = nodeProps.children as IPublicTypeNodeDataType; - } else { - let _children: IPublicTypeNodeData[] = []; - - 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 IPublicTypeNodeData[]); - } else { - _children.push(nodeProps.children as IPublicTypeNodeData); - } - - // eslint-disable-next-line no-param-reassign - schema.children = _children; - } - delete nodeProps.children; - } - } - } -} - -function getInternalDep(internalDeps: Record, depName: string) { - const dep = internalDeps[depName]; - return dep && dep.type !== InternalDependencyType.PAGE ? dep : null; -} - -export class SchemaParser implements ISchemaParser { - validate(schema: IPublicTypeProjectSchema): boolean { - if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) { - throw new CompatibilityError(`Not support schema with version [${schema.version}]`); - } - - return true; - } - - parse(schemaSrc: IPublicTypeProjectSchema | 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: any) => { - 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: IPublicTypeContainerSchema = schema - .componentsTree[0] as IPublicTypeContainerSchema; - - if (!firstRoot.fileName && !isValidContainerType(firstRoot)) { - // 整个 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 IPublicTypeNodeSchema[], - }; - containers = [container]; - } else { - // 普通带 1 到多个容器的 schema - containers = schema.componentsTree.map((n) => { - const subRoot = n as IPublicTypeContainerSchema; - const container: IContainerInfo = { - ...subRoot, - componentName: getRootComponentName(subRoot.componentName, compDeps), - containerType: subRoot.componentName, - moduleName: ensureValidClassName( - subRoot.componentName === ContainerType.Component - ? subRoot.fileName - : 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 IPublicTypeContainerSchema), - })); - - // 建立所有容器的内部依赖索引 - 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: IPublicTypeNodeSchema) => 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) => getInternalDep(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: IPublicTypeUtilItem[]; - if (schema.utils) { - utils = schema.utils; - utilsDeps = schema.utils - .filter( - (u): u is { name: string; type: 'npm' | 'tnpm'; content: IPublicTypeNpmInfo } => - 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 || [], - dataSourcesTypes: this.collectDataSourcesTypes(schema), - projectRemark: this.getProjectRemark(containers), - }, - }; - } - - getProjectRemark(containers: IContainerInfo[]): ProjectRemark { - return { - isSingleComponent: containers.length === 1 && containers[0].containerType === 'Component', - }; - } - - getComponentNames(children: IPublicTypeNodeDataType): string[] { - return handleSubNodes( - children, - { - node: (i: IPublicTypeNodeSchema) => i.componentName, - }, - { - rerun: true, - }, - ); - } - - decodeSchema(schemaSrc: string | IPublicTypeProjectSchema): IPublicTypeProjectSchema { - let schema: IPublicTypeProjectSchema; - 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; - } - - private collectDataSourcesTypes(schema: IPublicTypeProjectSchema): string[] { - const dataSourcesTypes = new Set(); - - // 数据源的默认类型为 fetch - const defaultDataSourceType = 'fetch'; - - // 收集应用级别的数据源 - schema.dataSource?.list?.forEach((ds) => { - dataSourcesTypes.add(ds.type || defaultDataSourceType); - }); - - // 收集容器级别的数据源(页面/组件/区块) - schema.componentsTree.forEach((rootNode) => { - rootNode.dataSource?.list?.forEach((ds) => { - dataSourcesTypes.add(ds.type || defaultDataSourceType); - }); - }); - - return Array.from(dataSourcesTypes.values()); - } -} - -export default SchemaParser; diff --git a/modules/code-generator/src/plugins/common/esmodule.ts b/modules/code-generator/src/plugins/common/esmodule.ts deleted file mode 100644 index 53f3f9418b..0000000000 --- a/modules/code-generator/src/plugins/common/esmodule.ts +++ /dev/null @@ -1,479 +0,0 @@ -import { flatMap, camelCase, get } from 'lodash'; -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 getExportNameOfDep(dep: IDependency): string { - if (dep.destructuring) { - return ( - dep.exportName || - dep.componentName || - throwNewError('destructuring dependency must have exportName or componentName') - ); - } - - if (!dep.subName) { - return ( - dep.componentName || - dep.exportName || - throwNewError('dependency item must have componentName or exportName') - ); - } - - return ( - dep.exportName || - `__$${camelCase( - get(dep, 'moduleName') || - get(dep, 'package') || - throwNewError('dep.moduleName or dep.package is undefined'), - )}_default` - ); -} - -function throwNewError(msg: string): never { - throw new Error(msg); -} - -function buildPackageImport( - pkg: string, - deps: IDependency[], - targetFileType: string, - useAliasName: boolean, -): ICodeChunk[] { - // 如果压根没有包,则不生成对应的 import 语句(生成了没有任何意义) - if (!pkg || pkg === 'undefined' || pkg === 'null') { - // TODO: 要不要加个 warning? - return []; - } - - const chunks: ICodeChunk[] = []; - - const exportItems: Record = {}; - const defaultExportNames: string[] = []; - - const depsInfo: IDependencyItem[] = deps.map((dep) => { - const info: IDependencyItem = { - exportName: getExportNameOfDep(dep), - 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 = flatMap(Object.keys(exportItems), (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 []; - }); - - 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) { - // default 方式的导入会生成单独de import 语句,无需生成赋值语句 - if (info.isDefault && defaultExportNames.find((n) => n === info.aliasName)) { - delete aliasDefineStatements[info.aliasName]; - return; - } - - 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 - filter?: (deps: IDependency[]) => IDependency[]; // 支持过滤能力 -} - -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 deps = cfg.filter ? cfg.filter(ir.deps) : ir.deps; - const packs = groupDepsByPack(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/modules/code-generator/src/plugins/common/requireUtils.ts b/modules/code-generator/src/plugins/common/requireUtils.ts deleted file mode 100644 index 4dacf68e5a..0000000000 --- a/modules/code-generator/src/plugins/common/requireUtils.ts +++ /dev/null @@ -1,25 +0,0 @@ -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/modules/code-generator/src/plugins/common/styleImport.ts b/modules/code-generator/src/plugins/common/styleImport.ts deleted file mode 100644 index 23e1293025..0000000000 --- a/modules/code-generator/src/plugins/common/styleImport.ts +++ /dev/null @@ -1,64 +0,0 @@ -import changeCase from 'change-case'; -import { - FileType, - BuilderComponentPluginFactory, - BuilderComponentPlugin, - ICodeStruct, - IWithDependency, - ChunkType, -} from '../../types'; - -import { COMMON_CHUNK_NAME } from '../../const/generator'; - -const pluginFactory: BuilderComponentPluginFactory = () => { - const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { - const next: ICodeStruct = { - ...pre, - }; - - const ir = next.ir as IWithDependency; - const { chunks } = next; - - if (ir && ir.deps && ir.deps.length > 0) { - let lowcodeMaterialsStyleAdded = false; - let fusionUIStyleAdded = false; - let nextStyleAddedMap: Record = {}; - ir.deps.forEach((dep: any) => { - if (dep.package === '@alifd/next' && !nextStyleAddedMap[dep.exportName]) { - chunks.push({ - type: ChunkType.STRING, - fileType: FileType.JSX, - name: COMMON_CHUNK_NAME.InternalDepsImport, - content: `import '@alifd/next/lib/${changeCase.paramCase(dep.exportName)}/style';`, - linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], - }); - nextStyleAddedMap[dep.exportName] = true; - } else if (dep.package === '@alilc/lowcode-materials' && !lowcodeMaterialsStyleAdded) { - chunks.push({ - type: ChunkType.STRING, - fileType: FileType.JSX, - name: COMMON_CHUNK_NAME.InternalDepsImport, - content: 'import \'@alilc/lowcode-materials/lib/style\';', - linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], - }); - lowcodeMaterialsStyleAdded = true; - } else if (dep.package === '@alifd/fusion-ui' && !fusionUIStyleAdded) { - chunks.push({ - type: ChunkType.STRING, - fileType: FileType.JSX, - name: COMMON_CHUNK_NAME.InternalDepsImport, - content: 'import \'@alifd/fusion-ui/lib/style\';', - linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], - }); - fusionUIStyleAdded = true; - } - }); - } - - return next; - }; - - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/commonDeps.ts b/modules/code-generator/src/plugins/component/rax/commonDeps.ts deleted file mode 100644 index 99285aad84..0000000000 --- a/modules/code-generator/src/plugins/component/rax/commonDeps.ts +++ /dev/null @@ -1,35 +0,0 @@ -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/modules/code-generator/src/plugins/component/rax/const.ts b/modules/code-generator/src/plugins/component/rax/const.ts deleted file mode 100644 index a0a07b550c..0000000000 --- a/modules/code-generator/src/plugins/component/rax/const.ts +++ /dev/null @@ -1,18 +0,0 @@ -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/modules/code-generator/src/plugins/component/rax/containerClass.ts b/modules/code-generator/src/plugins/component/rax/containerClass.ts deleted file mode 100644 index 5e923635b4..0000000000 --- a/modules/code-generator/src/plugins/component/rax/containerClass.ts +++ /dev/null @@ -1,157 +0,0 @@ -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: 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/modules/code-generator/src/plugins/component/rax/containerInitState.ts b/modules/code-generator/src/plugins/component/rax/containerInitState.ts deleted file mode 100644 index bf37881a2a..0000000000 --- a/modules/code-generator/src/plugins/component/rax/containerInitState.ts +++ /dev/null @@ -1,66 +0,0 @@ -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/modules/code-generator/src/plugins/component/rax/containerInjectContext.ts b/modules/code-generator/src/plugins/component/rax/containerInjectContext.ts deleted file mode 100644 index fed943aabc..0000000000 --- a/modules/code-generator/src/plugins/component/rax/containerInjectContext.ts +++ /dev/null @@ -1,145 +0,0 @@ -/* 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'; -import { DEFAULT_LINK_AFTER } 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.ConstructorContent, - content: ` - __$$i18n._inject2(this); - `, - linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]], - }); - - 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/modules/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts b/modules/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts deleted file mode 100644 index 930a279e24..0000000000 --- a/modules/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-disable @typescript-eslint/indent */ - -import { - IPublicTypeCompositeValue, - IPublicTypeJSExpression, - InterpretDataSourceConfig, - isJSExpression, - isJSFunction, -} from '@felce/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; - - /** - * 数据源的 handlers 的映射配置 - * @deprecated 请使用 datasourceConfig.handlersPackages 来配置 - */ - 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] || - `@alilc/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 || '@alilc/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: IPublicTypeCompositeValue, - scope: IScope, -): IPublicTypeCompositeValue { - 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/modules/code-generator/src/plugins/component/rax/containerInjectUtils.ts b/modules/code-generator/src/plugins/component/rax/containerInjectUtils.ts deleted file mode 100644 index 32d3f4bb02..0000000000 --- a/modules/code-generator/src/plugins/component/rax/containerInjectUtils.ts +++ /dev/null @@ -1,69 +0,0 @@ -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/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts b/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts deleted file mode 100644 index 5db72248a8..0000000000 --- a/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts +++ /dev/null @@ -1,146 +0,0 @@ -import _ from 'lodash'; -import { isJSExpression, isJSFunction } from '@felce/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'; -import { isJSExpressionFn } from '../../../utils/common'; - -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]) && - !isJSExpressionFn(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/modules/code-generator/src/plugins/component/rax/containerMethods.ts b/modules/code-generator/src/plugins/component/rax/containerMethods.ts deleted file mode 100644 index 6e23dc090f..0000000000 --- a/modules/code-generator/src/plugins/component/rax/containerMethods.ts +++ /dev/null @@ -1,84 +0,0 @@ -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/modules/code-generator/src/plugins/component/rax/jsx.ts b/modules/code-generator/src/plugins/component/rax/jsx.ts deleted file mode 100644 index 9b10669e6b..0000000000 --- a/modules/code-generator/src/plugins/component/rax/jsx.ts +++ /dev/null @@ -1,327 +0,0 @@ -import { - IPublicTypeNodeSchema, - IPublicTypeJSExpression, - IPublicTypeNpmInfo, - IPublicTypeCompositeValue, - isJSExpression, -} from '@felce/lowcode-types'; - -import _ from 'lodash'; -import changeCase from 'change-case'; -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 { parseExpressionGetGlobalVariables } from '../../../utils/expressionParser'; -import { transformThis2Context } from '../../../core/jsx/handlers/transformThis2Context'; -import { transformJsExpr } from '../../../core/jsx/handlers/transformJsExpression'; - -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(); - const { tolerateEvalErrors = true, evalErrorsHandler = '' } = next.contextData; - - // 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: IPublicTypeJSExpression, scope: IScope) { - return transformJsExpr(generateExpression(input, scope), scope, { - dontWrapEval: !tolerateEvalErrors, - }); - }, - 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: [ - tolerateEvalErrors && - ` - function __$$eval(expr) { - try { - return expr(); - } catch (error) { - ${evalErrorsHandler} - } - } - - function __$$evalArray(expr) { - const res = __$$eval(expr); - return Array.isArray(res) ? res : []; - } - `, - ` - function __$$createChildContext(oldContext, ext) { - return Object.assign({}, oldContext, ext); - } - `, - ] - .filter(Boolean) - .join('\n'), - linkAfter: [COMMON_CHUNK_NAME.FileExport], - }); - - return next; - - function generateRaxLoopCtrl( - nodeItem: IPublicTypeNodeSchema, - 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 = tolerateEvalErrors - ? `__$$evalArray(() => (${transformThis2Context( - generateCompositeType(nodeItem.loop, scope, { handlers: config?.handlers }), - scope, - )}))` - : `(${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) : []; - } - }; - - return plugin; -}; - -export default pluginFactory; - -function isImportAliasDefineChunk(chunk: ICodeChunk): chunk is ICodeChunk & { - ext: { - aliasName: string; - originalName: string; - dependency: IPublicTypeNpmInfo; - }; -} { - return ( - chunk.name === COMMON_CHUNK_NAME.ImportAliasDefine && - !!chunk.ext && - typeof chunk.ext.aliasName === 'string' && - typeof chunk.ext.originalName === 'string' && - !!(chunk.ext.dependency as IPublicTypeNpmInfo | null)?.componentName - ); -} - -function generateNodeAttrForRax( - this: { cfg: PluginConfig }, - attrData: { attrName: string; attrValue: IPublicTypeCompositeValue }, - 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: IPublicTypeCompositeValue, - 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/modules/code-generator/src/plugins/component/react/const.ts b/modules/code-generator/src/plugins/component/react/const.ts deleted file mode 100644 index 6294668276..0000000000 --- a/modules/code-generator/src/plugins/component/react/const.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const REACT_CHUNK_NAME = { - ClassRenderStart: 'ReactComponentClassRenderStart', - ClassRenderPre: 'ReactComponentClassRenderPre', - ClassRenderEnd: 'ReactComponentClassRenderEnd', - ClassRenderJSX: 'ReactComponentClassRenderJSX', - ClassDidMountStart: 'ReactComponentClassDidMountStart', - ClassDidMountEnd: 'ReactComponentClassDidMountEnd', - ClassDidMountContent: 'ReactComponentClassDidMountContent', -}; diff --git a/modules/code-generator/src/plugins/component/react/containerClass.ts b/modules/code-generator/src/plugins/component/react/containerClass.ts deleted file mode 100644 index eab6cbebee..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerClass.ts +++ /dev/null @@ -1,145 +0,0 @@ -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)}$$${ir.containerType}`, - ); - - 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, - ], - }); - - if (ir.containerType === 'Component') { - next.chunks.push({ - type: ChunkType.STRING, - fileType: FileType.JSX, - name: CLASS_DEFINE_CHUNK_NAME.InsVar, - content: `static displayName = '${ir.moduleName}';`, - linkAfter: [ - CLASS_DEFINE_CHUNK_NAME.Start, - ], - }); - } - - 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/modules/code-generator/src/plugins/component/react/containerInitState.ts b/modules/code-generator/src/plugins/component/react/containerInitState.ts deleted file mode 100644 index d1dd0d1ddf..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerInitState.ts +++ /dev/null @@ -1,63 +0,0 @@ -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: string } = { - 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/modules/code-generator/src/plugins/component/react/containerInjectConstants.ts b/modules/code-generator/src/plugins/component/react/containerInjectConstants.ts deleted file mode 100644 index 92cd4a3920..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerInjectConstants.ts +++ /dev/null @@ -1,55 +0,0 @@ -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, - content: "import __$$constants from '../../constants';", - linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], - }); - - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: CLASS_DEFINE_CHUNK_NAME.InsVar, - content: ` - get constants() { - return __$$constants || {}; - } - `, - linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]], - }); - - return next; - }; - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerInjectContext.ts b/modules/code-generator/src/plugins/component/react/containerInjectContext.ts deleted file mode 100644 index 434a5cf1c7..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerInjectContext.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator'; - -import { Scope } from '../../../utils/Scope'; - -import { - BuilderComponentPlugin, - BuilderComponentPluginFactory, - ChunkType, - FileType, - ICodeStruct, - IContainerInfo, -} from '../../../types'; -import { DEFAULT_LINK_AFTER } 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 scope = Scope.createRootScope(); - - const { inStrictMode } = next.contextData; - if (!inStrictMode) { - // 非严格模式下,上下文就是自己 - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: CLASS_DEFINE_CHUNK_NAME.InsVar, - content: ` - _context = this; - `, - linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], - }); - } else { - // 严格模式下的上下文只保留协议中规定的那些 - 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], - }); - - 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 self.constants; }, - get $() { return self.$ }, - get $$() { return self.$$ }, - ...this._methods, - }; - - return context; - } - `, - linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod], - }); - } - - return next; - }; - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts b/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts deleted file mode 100644 index ac7aa72ae2..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts +++ /dev/null @@ -1,206 +0,0 @@ -/* eslint-disable @typescript-eslint/indent */ - -import { - IPublicTypeCompositeValue, - IPublicTypeJSExpression, - InterpretDataSourceConfig, - isJSExpression, - isJSFunction, -} from '@felce/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 { isValidContainerType } from '../../../utils/schema'; -import { REACT_CHUNK_NAME } from './const'; -import { isJSExpressionFn } from '../../../utils/common'; - -export interface PluginConfig { - fileType?: string; - - /** - * 数据源配置 - */ - datasourceConfig?: { - /** 数据源引擎的版本 */ - engineVersion?: string; - - /** 数据源引擎的包名 */ - enginePackage?: string; - - /** 数据源 handlers 的版本 */ - handlersVersion?: { - [key: string]: string; - }; - - /** 数据源 handlers 的包名 */ - handlersPackages?: { - [key: string]: string; - }; - }; -} - -const pluginFactory: BuilderComponentPluginFactory = (config?) => { - const cfg = { - ...config, - fileType: config?.fileType || FileType.JSX, - }; - - const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { - const next: ICodeStruct = { - ...pre, - }; - - const scope = Scope.createRootScope(); - const dataSourceConfig = isValidContainerType(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 = - cfg.datasourceConfig?.handlersPackages?.[dsType] || - `@alilc/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 '@alilc/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: IPublicTypeCompositeValue, - scope: IScope, -): IPublicTypeCompositeValue { - if (isJSExpression(value) || isJSFunction(value) || isJSExpressionFn(value)) { - return { - type: 'JSExpression', - value: `function(){ return ((${value.value}))}.bind(this)`, - }; - } - - return { - type: 'JSExpression', - value: `function(){return((${generateCompositeType(value, scope)}))}.bind(this)`, - }; -} diff --git a/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts b/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts deleted file mode 100644 index aff42af15f..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { - CLASS_DEFINE_CHUNK_NAME, - COMMON_CHUNK_NAME, - DEFAULT_LINK_AFTER, -} from '../../../const/generator'; - -import { - BuilderComponentPlugin, - BuilderComponentPluginFactory, - ChunkType, - FileType, - ICodeStruct, -} from '../../../types'; -import { getSlotRelativePath } from '../../../utils/pathHelper'; - -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, - content: ` - import * as __$$i18n from '${getSlotRelativePath({ contextData: next.contextData, from: 'components', to: 'i18n' })}'; - `, - linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], - }); - - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, - content: ` - __$$i18n._inject2(this); - `, - linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]], - }); - - return next; - }; - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts b/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts deleted file mode 100644 index d9eb14f769..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { - CLASS_DEFINE_CHUNK_NAME, - COMMON_CHUNK_NAME, - DEFAULT_LINK_AFTER, -} from '../../../const/generator'; - -import { - BuilderComponentPlugin, - BuilderComponentPluginFactory, - ChunkType, - FileType, - ICodeStruct, - IContainerInfo, -} from '../../../types'; -import { getSlotRelativePath } from '../../../utils/pathHelper'; - -export interface PluginConfig { - fileType?: string; - - /** prefer using class property to define utils */ - preferClassProperty?: boolean; -} - -const pluginFactory: BuilderComponentPluginFactory = (config?) => { - const cfg: PluginConfig & { fileType: string } = { - 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, - content: ` - import utils${useRef ? ', { RefsManager }' : ''} from '${getSlotRelativePath({ contextData: next.contextData, from: 'components', to: 'utils' })}'; - `, - linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], - }); - - if (cfg.preferClassProperty) { - // mode: class property - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: CLASS_DEFINE_CHUNK_NAME.InsVar, - content: 'utils = utils;', - linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]], - }); - } else { - // mode: assign in constructor - 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]], - }); - } else { - // useRef 为 false 的时候是指没有组件在 props 中配置 ref 属性,但这个时候其实也可能有代码访问 this.$/$$ 所以还是加上个空的代码 - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: CLASS_DEFINE_CHUNK_NAME.InsMethod, - content: ' $ = () => null; ', - 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: ' $$ = () => []; ', - linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], - }); - } - - return next; - }; - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts b/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts deleted file mode 100644 index ec4c46e8bd..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts +++ /dev/null @@ -1,117 +0,0 @@ -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 '@felce/lowcode-types'; -import { isJSExpressionFn } from '../../../utils/common'; - -export interface PluginConfig { - fileType?: string; - exportNameMapping?: Record; - normalizeNameMapping?: Record; - exclude?: string[]; -} - -const pluginFactory: BuilderComponentPluginFactory = (config?) => { - const cfg = { - 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]) && - !isJSExpressionFn(lifeCycles[lifeCycleName]) && - !isJSExpression(lifeCycles[lifeCycleName]) - ) { - return null; - } - - let normalizeName; - // constructor会取到对象的构造函数 - if (lifeCycleName === 'constructor') { - normalizeName = lifeCycleName; - } else { - normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName; - } - - if (cfg?.exclude?.includes(normalizeName)) { - return null; - } - - 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]], - }; - }) - .filter((i) => !!i); - - next.chunks.push(...chunks.filter((x): x is ICodeChunk => x !== null)); - } - - return next; - }; - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerMethod.ts b/modules/code-generator/src/plugins/component/react/containerMethod.ts deleted file mode 100644 index fc4a387057..0000000000 --- a/modules/code-generator/src/plugins/component/react/containerMethod.ts +++ /dev/null @@ -1,70 +0,0 @@ -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'; -import { isValidIdentifier } from '../../../utils/validate'; - -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 { inStrictMode } = next.contextData; - - if (!ir.methods) { - return next; - } - - // 将这些 methods 都定义到 class 上 - 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); - - // 严格模式下需要将这些方法都挂到上下文中 - if (inStrictMode) { - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, - content: Object.keys(ir.methods) - .map((methodName) => - isValidIdentifier(methodName) ? `.${methodName}` : `[${JSON.stringify(methodName)}]`, - ) - .map((method) => `this._context${method} = this${method};`) - .join('\n'), - linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]], - }); - } - - return next; - }; - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/jsx.ts b/modules/code-generator/src/plugins/component/react/jsx.ts deleted file mode 100644 index f8a46c4825..0000000000 --- a/modules/code-generator/src/plugins/component/react/jsx.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { - BuilderComponentPlugin, - BuilderComponentPluginFactory, - ChunkType, - FileType, - HandlerSet, - 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'; -import { IPublicTypeJSExpression } from '@felce/lowcode-types'; -import { generateExpression } from '../../../utils/jsExpression'; -import { transformJsExpr } from '../../../core/jsx/handlers/transformJsExpression'; -import { transformThis2Context } from '../../../core/jsx/handlers/transformThis2Context'; -import { generateCompositeType } from '../../../utils/compositeType'; - -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 { tolerateEvalErrors = true, evalErrorsHandler = '' } = next.contextData; - - // 这里会将内部的一些子上下文的访问(this.xxx)转换为 __$$context.xxx 的形式 - // 与 Rax 所不同的是,这里不会将最顶层的 this 转换掉 - const customHandlers: HandlerSet = { - expression(input: IPublicTypeJSExpression, scope: IScope, config) { - return transformJsExpr(generateExpression(input, scope), scope, { - dontWrapEval: !(config?.tolerateEvalErrors ?? tolerateEvalErrors), - dontTransformThis2ContextAtRootScope: true, - }); - }, - function(input, scope: IScope) { - return transformThis2Context( - generateCompositeType( - { - type: 'JSFunction', - value: input.value || 'function () {}', - }, - Scope.createRootScope(), - ), - scope, - { ignoreRootScope: true }, - ); - }, - }; - - const generatorPlugins: NodeGeneratorConfig = { - handlers: customHandlers, - tagMapping: (v) => nodeTypeMapping[v] || v, - tolerateEvalErrors, - }; - - 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._context || this; - const { state } = __$$context; - 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: [ - tolerateEvalErrors && - ` - function __$$eval(expr) { - try { - return expr(); - } catch (error) { - ${evalErrorsHandler} - } - } - - function __$$evalArray(expr) { - const res = __$$eval(expr); - return Array.isArray(res) ? res : []; - } - `, - ` - function __$$createChildContext(oldContext, ext) { - const childContext = { - ...oldContext, - ...ext, - }; - childContext.__proto__ = oldContext; - return childContext; - } - `, - ] - .filter(Boolean) - .join('\n'), - linkAfter: [COMMON_CHUNK_NAME.FileExport], - }); - return next; - }; - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/reactCommonDeps.ts b/modules/code-generator/src/plugins/component/react/reactCommonDeps.ts deleted file mode 100644 index f42aaf61bd..0000000000 --- a/modules/code-generator/src/plugins/component/react/reactCommonDeps.ts +++ /dev/null @@ -1,33 +0,0 @@ -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: ` -// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 -// 例外:react 框架的导出名和各种组件名除外。 -import React from \'react\';`, - linkAfter: [], - }); - - return next; - }; - return plugin; -}; - -export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/style/css.ts b/modules/code-generator/src/plugins/component/style/css.ts deleted file mode 100644 index 4ef94fdd7c..0000000000 --- a/modules/code-generator/src/plugins/component/style/css.ts +++ /dev/null @@ -1,52 +0,0 @@ -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/modules/code-generator/src/plugins/project/constants.ts b/modules/code-generator/src/plugins/project/constants.ts deleted file mode 100644 index 18b286c934..0000000000 --- a/modules/code-generator/src/plugins/project/constants.ts +++ /dev/null @@ -1,59 +0,0 @@ -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/modules/code-generator/src/plugins/project/framework/icejs/index.ts b/modules/code-generator/src/plugins/project/framework/icejs/index.ts deleted file mode 100644 index e9c8f255fa..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -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/modules/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts deleted file mode 100644 index b5dc2d8f8a..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts +++ /dev/null @@ -1,56 +0,0 @@ -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/modules/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts deleted file mode 100644 index e5837a8dde..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts +++ /dev/null @@ -1,46 +0,0 @@ -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/modules/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts deleted file mode 100644 index 3daaeecdc0..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts +++ /dev/null @@ -1,56 +0,0 @@ -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/modules/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts deleted file mode 100644 index cc8003c1e7..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { PackageJSON } from '@felce/lowcode-types'; - -import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; - -import { - BuilderComponentPlugin, - BuilderComponentPluginFactory, - ChunkType, - FileType, - ICodeStruct, - IProjectInfo, -} from '../../../../../types'; -import { buildDataSourceDependencies } from '../../../../../utils/dataSource'; - -interface IIceJsPackageJSON extends PackageJSON { - ideMode: { - name: string; - }; - iceworks: { - type: string; - adapter: string; - }; - originTemplate: string; -} - -export type IceJsPackageJsonPluginConfig = { - /** - * 数据源配置 - */ - datasourceConfig?: { - /** 数据源引擎的版本 */ - engineVersion?: string; - /** 数据源引擎的包名 */ - enginePackage?: string; - /** 数据源 handlers 的版本 */ - handlersVersion?: { - [key: string]: string; - }; - /** 数据源 handlers 的包名 */ - handlersPackages?: { - [key: string]: string; - }; - }; - /** 包名 */ - packageName?: string; - /** 版本 */ - packageVersion?: string; -}; - -const pluginFactory: BuilderComponentPluginFactory = (cfg) => { - const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { - const next: ICodeStruct = { - ...pre, - }; - - const ir = next.ir as IProjectInfo; - - const packageJson: IIceJsPackageJSON = { - name: cfg?.packageName || 'icejs-demo-app', - version: cfg?.packageVersion || '0.1.5', - description: '轻量级模板,使用 JavaScript,仅包含基础的 Layout。', - dependencies: { - moment: '^2.24.0', - react: '^16.4.1', - 'react-dom': '^16.4.1', - 'react-router': '^5.2.1', - '@alifd/theme-design-pro': '^0.x', - 'intl-messageformat': '^9.3.6', - '@ice/store': '^1.4.3', - '@loadable/component': '^5.15.2', - - // 数据源相关的依赖: - ...buildDataSourceDependencies(ir, cfg?.datasourceConfig), - }, - 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', - }, - 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.xxx.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/modules/code-generator/src/plugins/project/framework/icejs/plugins/router.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/router.ts deleted file mode 100644 index 0e2e8c1f79..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/plugins/router.ts +++ /dev/null @@ -1,84 +0,0 @@ -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/modules/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts deleted file mode 100644 index 1a0af6c022..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts deleted file mode 100644 index 64c69e8c88..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts deleted file mode 100644 index 38baba44ad..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ResultFile } from '@felce/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" - ] - } - ] - ] -} - `, - }, - ]; -} diff --git a/modules/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts deleted file mode 100644 index 047a28d4c6..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts deleted file mode 100644 index 6f217227b3..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts deleted file mode 100644 index 2d2838991f..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts deleted file mode 100644 index 5f93665286..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts deleted file mode 100644 index a859c38376..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts deleted file mode 100644 index 18e55fd6ed..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts deleted file mode 100644 index ae48aaaf17..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts deleted file mode 100644 index ae5b302ba1..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts deleted file mode 100644 index 7204e9903c..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts deleted file mode 100644 index bce1af8443..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts deleted file mode 100644 index 50fa8d001c..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts deleted file mode 100644 index 02b8791bd1..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { ResultFile } from '@felce/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/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts deleted file mode 100644 index c544e96101..0000000000 --- a/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { ResultFile } from '@felce/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} - -