diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..319299684a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +quote_type = single + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..ad6cd2ec2e --- /dev/null +++ b/.eslintignore @@ -0,0 +1,18 @@ +# 忽略目录 +node_modules +test-cases +test +output +build +dist +demo +es +lib +tests +.* +~* + +# 忽略文件 +**/*.min.js +**/*-min.js +**/*.bundle.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..d43a7b389d --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,38 @@ +module.exports = { + extends: 'eslint-config-ali/typescript/react', + rules: { + 'react/no-multi-comp': 0, + 'no-unused-expressions': 0, + 'implicit-arrow-linebreak': 1, + 'no-nested-ternary': 1, + 'no-mixed-operators': 1, + '@typescript-eslint/ban-types': 1, + 'no-shadow': 1, + 'no-prototype-builtins': 1, + 'no-useless-constructor': 1, + 'no-empty-function': 1, + '@typescript-eslint/member-ordering': 0, + 'lines-between-class-members': 0, + 'no-await-in-loop': 0, + 'no-plusplus': 0, + '@typescript-eslint/no-parameter-properties': 0, + '@typescript-eslint/no-unused-vars': 1, + 'no-multi-assign': 1, + 'no-dupe-class-members': 1, + 'react/no-deprecated': 1, + 'no-useless-escape': 1, + 'brace-style': 1, + '@typescript-eslint/no-inferrable-types': 0, + 'no-proto': 0, + 'prefer-const': 0, + 'eol-last': 0, + 'react/no-find-dom-node': 0, + 'no-case-declarations': 0, + '@typescript-eslint/indent': 0, + 'import/no-cycle': 0, + '@typescript-eslint/no-shadow': 0, + "@typescript-eslint/method-signature-style": 0, + "@typescript-eslint/consistent-type-assertions": 0, + "@typescript-eslint/no-useless-constructor": 0, + } +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..2f87724cb9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,108 @@ +# project custom +build +dist +packages/*/lib/ +packages/*/es/ +packages/*/dist/ +packages/*/output/ +packages/demo/ +package-lock.json +yarn.lock +deploy-space/packages +deploy-space/.env + + +# 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 diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000000..24c5859e6e --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + printWidth: 100, + tabWidth: 2, + semi: true, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000000..bec25cf294 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,9 @@ +# 忽略目录 +node_modules/ +build/ +dist/ + +# 忽略文件 +**/*.min.css +**/*-min.css +**/*.bundle.css diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 0000000000..2ba42f6d56 --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: 'stylelint-config-ali', + rules: { + "selector-max-id": 2 + } +}; diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..78b6a56f94 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2634 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.0.55](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.54...v1.0.55) (2021-06-17) + + +### Bug Fixes + +* 兼容 icon 为 esmodule 功能 ([8319b13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8319b13051405f7a62328320c88545f22de28901)) +* **vision:** 兼容原 vision proto transducers 功能 ([2ba28f9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2ba28f928a095166c434639670b20c4988cf57fe)) +* deploy node version 14.17.0 ([a187d0d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a187d0d2bf5b6aedf787aa38374f3c7e46f71085)) +* 以节点id作为key,修复拖拽、增删时组件频繁卸载的问题 ([341f938](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/341f938f7fbf557b5b57965b711e369d75ec5e09)) +* 修复 valueChange 不会因为子属性变化而通知父属性事件监听, 考虑到后续推荐直接使用 setValue, 也实现了 valueChange 事件 ([1297e3c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1297e3c0e5f13a50bdd6e79ce5da37a8272e1ff7)) +* 修复设置区 stage 回到首页的功能 ([cec923b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cec923b8ff477eb5a419b09f30b0abdf1f211877)) + + +### Features + +* 支持设置是否允许画布鼠标事件的冒泡 ([4e5c7f5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4e5c7f57c1837c40cb4e8ec6b14af22c4b9ad4e4)) + + + + + +## [1.0.54](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.53...v1.0.54) (2021-06-08) + + +### Bug Fixes + +* fieldId 有值时跳过 initial, 因为在目前 vc 的 fieldId 实现是每次返回不同的值 ([0360572](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/03605724769b72ab28aa6c4ae7311c10257dd8f0)) + + + + + +## [1.0.53](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.52...v1.0.53) (2021-06-07) + + +### Bug Fixes + +* 修复 slot 类型在 history 操作时被清空的 bug ([1de2621](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1de26215b23a64abe085d52ecae9a769a2dc56b8)) + + + + + +## [1.0.52](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.51...v1.0.52) (2021-06-07) + + +### Bug Fixes + +* undefined 不能跳过 slot 的初始化 ([34cd56e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/34cd56e2c3910f0d0a3f0354313af106db4590d6)) +* 修复格式化JSExpression时将数据传丢的问题 ([a6ebc3a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a6ebc3aa75e998788a19472af496df67b24f0f3c)) +* 修改 build.cloud.json ([c28970b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c28970b6dbc9fbc542f5785613c7d3a61adcd468)) +* 处理 slot 被关闭的情况 ([662c9d6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/662c9d67bda861d369e49f6725cc12d05f3169a0)) + + + + + +## [1.0.51](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.49...v1.0.51) (2021-06-03) + + +### Bug Fixes + +* build-plugin-component 要求必须有 index 文件 ([f54f5b5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f54f5b5775fa816a00376fb7d2285dadeaa70ab5)) +* fieldId 重置需要限定在同一个 doc, 解决多 doc 时 fieldId 重复导致重置的问题 ([7d2bb4f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7d2bb4fa791a2bb1f83a4f9b2951a7947efe001e)) +* 修复 initial / initialValue 在复制组件时不会被重新调用的 bug ([68ddca9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/68ddca93f5ead30110a4f6a98dfe724c9fe7d983)) +* 修改 params 临时存储位置 ([87a1c74](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/87a1c7442013e1d67c1152e71cf7aded33814e38)) +* 兼容没有 prototype 的情况 ([e442436](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e4424364403aa53e5eef4c2ede284285de93cc6a)) +* 参照 vision 的实现, ignore 只影响 save 阶段, 不影响画布渲染 ([9411c9d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9411c9d9a02e919babf3c50c5cbf3d0bbb4fea64)) +* 在压缩态没有类名, 换个方式实现 ([f874823](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f874823502acc50cee050bb150dec11906644fad)) +* 改成从 @ali/lowcode-engine 引入 ([866b957](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/866b957f37c792192d792cd7a295d91139a37e94)) +* 跳过 JSExpression 并带有 events 的初始化流程 ([37809e7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/37809e71e8309c8c686f14bcc050013c5c705c09)) +* 跳过 JSSlot 类型的快捷设值 ([ab45c0f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ab45c0f2558e4d548b485567430c29f42b236f7e)) +* 还是将 dropLocation 设为非响应式变量, 基于性能考量 ([2acc70a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2acc70a4226ce81ae5f7321e6c1c0e768103694d)) + + +### Features + +* project 支持 onSimulatorReady 的事件 ([79d0c33](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/79d0c33109535c6241ff94500e971f76e3ad8f0e)) +* 导出 utils 命名空间 ([e3738cc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e3738ccecad2296309b4c06ab4db767214918f41)) +* 支持 disableAutoRender 配置项 ([719928a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/719928a02c8d4fb295a5412a94447c59e52b7b7d)) +* 支持 visionSettings.enableFilterReducerInRenderStage 配置项 ([277a185](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/277a18564a71abd4d7fc55b16cb9cc84a41eed35)) +* 支持自定义 bem-tools ([1e00783](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1e00783af81db6c84e893a8d6c95e1082e1c041c)) +* 支持节点拖拽时被放入容器的视觉反馈, 通过 enableReactiveContainer 配置项 ([6a308ba](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6a308ba81d2ba11b05309cc65b7e7efeca1bda96)) +* 新增vision engineconfig,支持禁用某些reducer ([94d8080](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/94d8080fe9863ad97c0c0c70ff4b1e1c9c7bcdb8)) +* **editor-skeleton&editor-core:** 添加了点击setter-pane后抛出editor事件 ([2c697c9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2c697c99130990d90ab29471789c96b22cc7c5fa)) + + + + + +## [1.0.49](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48...v1.0.49) (2021-05-20) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.48](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.4...v1.0.48) (2021-05-17) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.48-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.3...v1.0.48-beta.4) (2021-05-14) + + +### Features + +* 增加画布右键事件的参数 ([bd0070c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd0070c3dea9df91c77fafe9159f8f5e215eaa56)) + + + + + +## [1.0.48-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.2...v1.0.48-beta.3) (2021-05-13) + + +### Bug Fixes + +* fix array-setter bugs ([12d60b2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/12d60b28907813aaa9e656c5c8f8e979fd1805db)) + + +### Features + +* prototype.setPackageName增加第二个入参 ([8f2ffed](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8f2ffed45150392bed076d5d459f7eb3bfbe7ca3)) +* 支持在 host 里刷新渲染器 ([ccbbf74](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ccbbf743ad596b0ce1c569569e6e663868e575c4)) + + + + + +## [1.0.48-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.1...v1.0.48-beta.2) (2021-05-12) + + +### Bug Fixes + +* 锁定 @builder/babel-preset-ice@1.0.1 ([c639edf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c639edf758452305a006e99404ae2db35b0171f4)) + + +### Features + +* 完善 schema 中的 componentsMap 和 utils 信息 ([f335223](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f3352231a0ce0d31c9bf63fa0872a2e11de276a3)) + + + + + +## [1.0.48-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.48-beta.0...v1.0.48-beta.1) (2021-05-12) + + +### Bug Fixes + +* 使用 utils 中声明的 name 字段当 key ([b5f93a2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b5f93a2b6e132d4a606750a33a28f60aeabf3de4)) + + + + + +## [1.0.48-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.47...v1.0.48-beta.0) (2021-05-11) + + +### Bug Fixes + +* 兼容 useVariableChange ([ae522e7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ae522e7bcc31c9e09c83aec8d294267a429402a6)) + + +### Features + +* 支持引擎 init 时传入参数, 逐渐取代 editor 参数的功能 ([a9c4b97](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a9c4b97135be13ce78feead34a9cc45571767004)) +* 支持设计器里的 utils 注入机制 (vu-xxx & 简单类型的 umd) ([b23231e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b23231e8d013a603bc73917a1ae7c8ff1caf83c2)) +* 物料描述中的钩子函数等支持 JSFunction 形式 ([9bcb1b7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9bcb1b7dd53fef2d0227cd7c400e3dcbb7472cb5)) + + + + + +## [1.0.47](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.47-beta.1...v1.0.47) (2021-04-28) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.47-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.47-beta.0...v1.0.47-beta.1) (2021-04-28) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.47-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.46...v1.0.47-beta.0) (2021-04-28) + + +### Bug Fixes + +* 修复第一次切换页面就提示有数据修改未保存的行为 ([ca4222a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ca4222a98ede60f43c717b3dd303c6c2985f3191)) +* 提前 simulator mount 的时间点, 修复极低概率出现的 style 丢失现象 ([b65460f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b65460f029257a68245134176e8d2d445832da9a)) + + + + + +## [1.0.46](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.46-beta.0...v1.0.46) (2021-04-27) + + +### Bug Fixes + +* 允许不加载 engine-ext 的场景 ([e732f6c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e732f6cdc027d7250b02aa21224300a56fc04ad8)) + + + + + +## [1.0.46-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.45...v1.0.46-beta.0) (2021-04-25) + + +### Bug Fixes + +* fix rax page-render missing context ([d7de766](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d7de766c1f0c8c19a3b9d3096ef6f9c019b91d51)) +* 优化获取 simulator 的逻辑, 解决偶现 style 没被注入的问题 ([f84ec7e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f84ec7e72ef6a0fc2f9a62faf0067e49948d9786)) + + + + + +## [1.0.45](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.45-beta.1...v1.0.45) (2021-04-23) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.45-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.45-beta.0...v1.0.45-beta.1) (2021-04-22) + + +### Bug Fixes + +* 支持children属性,对齐react-simulator ([8d05f30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8d05f3017784af58e90a989c3de955d6f010f8d0)) + + +### Features + +* assset.json package 对象支持 exportName, 用来适配 umd 导出的 name ([6a1af9d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6a1af9d72964d0b1656b6e7e807dd29d4ea9cbf2)) +* 支持全局css ([e371092](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e3710929529a5faa274795223417511b0319a43f)) +* 支持获取组件引用的提案 ([f0d2d56](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f0d2d569108629b3ad1054f4e92e91a0b84f6104)) + + + + + +## [1.0.45-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.44...v1.0.45-beta.0) (2021-04-21) + + +### Bug Fixes + +* rax模拟器去掉滚动条(小程序IDE和一般小程序真正显示都是没有的),也解决滚动条占用页面总宽度的问题 ([e9bea62](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e9bea627ef2f4b4237a289e873e0e08b2e97d973)) +* 使用 cdn combo 服务时, 最后一行的 //# sourceMappingURL=engine-core.js.map 导致后面内容都被注释 ([8da27d9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8da27d973f7ac4b8c4fb42b1617a248a8c712219)) +* 修复无法 remove currentDocument ([4157aa0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4157aa0443f718ac5bc95ebcae0de50971856af5)) +* 修复设备切换时设备尺寸超过页面bug;iphonex/6默认尺寸 ([b7c1876](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b7c187623d385a460402343d1db10fea45d95e8b)) + + + + + +## [1.0.44](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.44-beta.2...v1.0.44) (2021-04-14) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.44-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.44-beta.1...v1.0.44-beta.2) (2021-04-14) + + +### Bug Fixes + +* 解决 radio 组件无法删除, 且影响其他组件也无法删除的问题 ([f2ce27c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f2ce27c811667d7bd41cbdb41cfbc9d7c7330f8f)) + + + + + +## [1.0.44-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.44-beta.0...v1.0.44-beta.1) (2021-04-14) + + +### Bug Fixes + +* 调整 components 触发视图刷新的机制, designer _componentMetasMap 引用更新才触发 renderer components 更新 ([a9cead0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a9cead0339e253752c7bbd33c069286335a4a671)) + + + + + +## [1.0.44-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.43...v1.0.44-beta.0) (2021-04-13) + + +### Bug Fixes + +* componentsMap 中加入低代码组件信息 ([b7c1183](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b7c11834602d8e4ea84d2dea035a3abf97b33d5c)) + + + + + +## [1.0.43](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.43-beta.0...v1.0.43) (2021-04-13) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.43-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.42...v1.0.43-beta.0) (2021-04-13) + + +### Bug Fixes + +* 修复在没有选中任何画布节点时, 添加模态框异常的 bug ([34e8105](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/34e8105c104e7fe98d9446d96d44206c069d8d4b)) +* 移除 renderer 内 components 的响应式逻辑 ([c02f0ec](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c02f0ec8374406e2d916fcc2a23c7f88b52ab80d)) + + + + + +## [1.0.42](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.42-beta.1...v1.0.42) (2021-04-06) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.42-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.42-beta.0...v1.0.42-beta.1) (2021-04-06) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.42-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.41...v1.0.42-beta.0) (2021-04-06) + + +### Bug Fixes + +* 升级和降级 schema 的操作都跳过数组, 因为 dataSource 和 ListSetter 都依赖了乐高的 schema 结构 ([1c430a2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1c430a2e66343a8e433075fe7b472d8a06b02d98)) + + + + + +## [1.0.41](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.41-beta.1...v1.0.41) (2021-04-06) + + +### Bug Fixes + +* bypass dataSource ([3cb331d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3cb331dcbeee62959ef0b1614c6c3cb2bd3c1a3e)) + + + + + +## [1.0.41-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.41-beta.1...v1.0.41-beta.2) (2021-04-06) + + +### Bug Fixes + +* bypass dataSource ([f6fd095](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f6fd095db2ff01454257a1322ad695d89c139f1a)) + + + + + +## [1.0.41-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.41-beta.0...v1.0.41-beta.1) (2021-04-06) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.41-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.40...v1.0.41-beta.0) (2021-04-02) + + +### Bug Fixes + +* 修复转换 schema 双向不对等的 bug ([5f85174](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5f851740b30c306bdb686afa422df8630ba00b8a)) + + +### Features + +* add deviceStyle props ([1a09282](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1a09282bfae8bbbd3a2af32a68cd28276b03129f)) + + + + + +## [1.0.40](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.40-beta.1...v1.0.40) (2021-03-31) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.40-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.40-beta.0...v1.0.40-beta.1) (2021-03-31) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.40-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.5...v1.0.40-beta.0) (2021-03-31) + + +### Bug Fixes + +* 对齐 getConfig 的实现 ([7b551fb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7b551fb5b8392640f55cd79f41ee06a2afdac202)) + + + + + +## [1.0.39-beta.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.4...v1.0.39-beta.5) (2021-03-31) + + +### Features + +* 增加 getConfig / getItems / selected 等兼容 vision 的 API ([9a3352b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9a3352b05411b23a831bcbea056642413c19c36e)) + + + + + +## [1.0.39-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.3...v1.0.39-beta.4) (2021-03-30) + + +### Bug Fixes + +* 修复无法获取 libraryMap ([393d9ce](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/393d9cebf82026f1501fc653377e949c2b703584)) + + + + + +## [1.0.39-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.2...v1.0.39-beta.3) (2021-03-22) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.39-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.39-beta.1...v1.0.39-beta.2) (2021-03-22) + + +### Bug Fixes + +* renderer-core 在非设计渲染态时, 不应处理 hidden 属性 ([7857096](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7857096c0f56308195cc9e27de4f549eee72a10e)) +* 以字符串注册 editor 实例 ([b9c5b3a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9c5b3a0fdbc11ee287befae1eb3864ed761831b)) +* 修复array-setter 初始化重复多次执行onChange ([e8f83fc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e8f83fc4b39d8591eb662e53f95619743b6da5eb)) +* 修复arraysetter 初始化重复执行onChange问题 ([0486dbb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0486dbb320f63c6ebf9448c97c20cc37feb1d9dd)) + + +### Features + +* 异步加载asset ([a5ca12a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5ca12ab691f611dd706ac295ee3cc4965701ca3)) + + + + + +## [1.0.39-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.3...v1.0.39-beta.1) (2021-03-12) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.39-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.3...v1.0.39-beta.0) (2021-03-12) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.38-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.1...v1.0.38-beta.3) (2021-03-11) + + +### Bug Fixes + +* 修复 overridePropsConfigure 失效的 bug ([7168a90](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7168a903ce8b4d5346b751dc812828199ae1b3b6)) + + +### Features + +* 低代码组件支持实时修改属性 ([e7b4e2c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e7b4e2cc9cf80bcc073c142d7b06a8e2be5895a5)) + + + + + +## [1.0.38-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.1...v1.0.38-beta.2) (2021-03-11) + + +### Bug Fixes + +* 修复 overridePropsConfigure 失效的 bug ([7168a90](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7168a903ce8b4d5346b751dc812828199ae1b3b6)) + + +### Features + +* 低代码组件支持实时修改属性 ([e7b4e2c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e7b4e2cc9cf80bcc073c142d7b06a8e2be5895a5)) + + + + + +## [1.0.38-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.38-beta.0...v1.0.38-beta.1) (2021-03-09) + + +### Bug Fixes + +* 修复 vc 组件里 icon svg 写 class 时样式异常 ([c6b4b2c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c6b4b2cfd03dbb56f0283cc78a800f48f15b28fc)) + + + + + +## [1.0.38-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37...v1.0.38-beta.0) (2021-03-08) + + +### Bug Fixes + +* 修复 Dialog 错误地添加到非 Page 节点下 ([28d7960](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/28d7960c52f8ada1501f2a3d903973ca2a3d7729)) + + + + + +## [1.0.37](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.6...v1.0.37) (2021-03-05) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + + + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.37](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.6...v1.0.37) (2021-03-05) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.37-beta.6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.3...v1.0.37-beta.6) (2021-03-03) + + +### Bug Fixes + +* rax渲染添加容器占位显示 ([a60c580](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a60c580e7709b4b83fdfdcc365bc7ca54e4a57bc)) +* 在切换 setter 时清空 hotvalue ([5f3c4e9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5f3c4e91d36ffd3289bd336586de48b0492340d6)) + + +### Features + +* add deviceMapper to adaptor different components lib ([b807597](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b807597be96cd4c5ccce6870495be3c1eff5c8b9)) +* add pane drag, use config "enableDrag:true" ([2cb24a4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2cb24a41c06d72435974f349e27da8f8d5474676)) +* add prototypeWrapper&preprocessor ([a2dd868](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a2dd868f906df2a7b050686f34df784a8f65ec07)) + + + + + +## [1.0.37-beta.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.4...v1.0.37-beta.5) (2021-02-24) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.37-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.3...v1.0.37-beta.4) (2021-02-24) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + +## [1.0.37-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.2...v1.0.37-beta.3) (2021-02-24) + +**Note:** Version bump only for package ali-lowcode-engine + + + + + + +## [1.0.37-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.37-beta.1...v1.0.37-beta.2) (2021-02-23) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.37-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.36...v1.0.37-beta.1) (2021-02-23) + + +### Bug Fixes + +* lifecycle reducer 跳过非 vc 的组件 ([b295da1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b295da1)) +* 修复 canDropIn / canDropTo 转成 nestingRule 异常 ([6406417](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6406417)) +* 修复点击大纲树节点时, 画布也滚动到相应位置 ([badc6ef](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/badc6ef)) + + +### Features + +* 隔离运行插件 ([298c810](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/298c810)) + + + + + +## [1.0.36](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.36-beta.0...v1.0.36) (2021-02-04) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.36-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.35...v1.0.36-beta.0) (2021-02-04) + + +### Bug Fixes + +* 修复handleI18n未定义的问题 ([7f14946](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7f14946)) + + + + + +## [1.0.35](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.35-beta.1...v1.0.35) (2021-02-03) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.35-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.35-beta.0...v1.0.35-beta.1) (2021-02-03) + + +### Bug Fixes + +* 修复 deploy.sh 拷贝文件路径不对 ([9eb31c4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9eb31c4)) + + +### Features + +* 支持 Node#wrapWith API ([265a84f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/265a84f)) + + + + + +## [1.0.35-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.33...v1.0.35-beta.0) (2021-02-01) + + +### Bug Fixes + +* 优化 vc-live-editing 注入逻辑(后续可能要开个配置项让用户选择版本) ([386d120](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/386d120)) + + +### Features + +* add i18n support for react simulator & render ([6946512](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6946512)) +* 分离 engine.js 为 engine-core.js + engine-ext.js ([361a68b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/361a68b)) +* 重构renderer ([c9e0b21](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c9e0b21)) +* 重构renderer ([4546dc0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4546dc0)) +* 重构renderer ([630d320](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/630d320)) + + + + + +## [1.0.33](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.33-beta.1...v1.0.33) (2021-01-29) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.33-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.33-beta.0...v1.0.33-beta.1) (2021-01-28) + + +### Bug Fixes + +* deep-parser 也只能应用在 vc 组件上 ([faac829](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/faac829)) +* 修复arraysetter其他setter设值失败的问题 ([085eb66](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/085eb66)) + + + + + +## [1.0.33-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.32...v1.0.33-beta.0) (2021-01-28) + + +### Bug Fixes + +* 修复从其他页面粘贴过来的 modal 位置不对 ([158b6a6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/158b6a6)) +* 修复设置迭代参数异常的 bug ([c26da97](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c26da97)) +* 修复设计器嵌入到 iframe 时产生跨域异常 ([46dce7a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/46dce7a)) + + + + + +## [1.0.32](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.32-beta.2...v1.0.32) (2021-01-26) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.32-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.32-beta.0...v1.0.32-beta.2) (2021-01-26) + + +### Bug Fixes + +* 同步 vision-polyfill 中对 resize 方向的控制逻辑 ([2aa5968](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2aa5968)) + + + + + +## [1.0.32-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.31...v1.0.32-beta.0) (2021-01-25) + + +### Bug Fixes + +* 修复鼠标从 left-float 面板滑出后, 面板关闭的问题 ([835ad4b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/835ad4b)) +* 考虑兼容原来只处理4向的场景 ([e3fc9b4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e3fc9b4)) + + +### Features + +* meta 增加 hideSelectTools ([e7287d4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e7287d4)) +* metadata 增加 canHovering 配置 ([88e128e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/88e128e)) +* 增加 plugin 的 autoInit 注册方式 ([4f9be73](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4f9be73)) +* 增加 setup:skip-build 脚本 ([1b142cd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1b142cd)) +* 增强 bem resize (ws, wn, es, en) ([ac05124](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ac05124)) +* 支持canSelecting & moMoveHook添加node参数 ([baf2d30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/baf2d30)) + + + + + +## [1.0.31](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.31-beta.1...v1.0.31) (2021-01-15) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.31-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30...v1.0.31-beta.1) (2021-01-15) + + +### Bug Fixes + +* 修复 vc-live-editing 功能 ([8c019a3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8c019a3)) +* 延迟加载内置 setter ([99cbdd5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/99cbdd5)) + + +### Features + +* setters 下增加 getSettersMap 方法 ([7e020a1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7e020a1)) + + + + + +## [1.0.31-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30...v1.0.31-beta.0) (2021-01-15) + + +### Bug Fixes + +* 修复 vc-live-editing 功能 ([8c019a3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8c019a3)) + + +### Features + +* setters 下增加 getSettersMap 方法 ([7e020a1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7e020a1)) + + + + + +## [1.0.30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.17...v1.0.30) (2021-01-14) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.30-beta.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.16...v1.0.30-beta.17) (2021-01-14) + + +### Bug Fixes + +* 变量绑定时未触发事件, http://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/issues/100851 ([cc72fe8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cc72fe8)) +* 调整 editor-setters 的加载时机 ([8e66793](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8e66793)) + + + + + +## [1.0.30-beta.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.14...v1.0.30-beta.16) (2021-01-14) + + +### Features + +* 将 typings 在顶层导出 ([d2aed7d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2aed7d)) + + + + + +## [1.0.30-beta.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.14...v1.0.30-beta.15) (2021-01-13) + + +### Features + +* 将 typings 在顶层导出 ([9d9b6f4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9d9b6f4)) + + + + + +## [1.0.30-beta.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.13...v1.0.30-beta.14) (2021-01-13) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.30-beta.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.12...v1.0.30-beta.13) (2021-01-13) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.30-beta.12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.11...v1.0.30-beta.12) (2021-01-13) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.30-beta.11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.10...v1.0.30-beta.11) (2021-01-12) + + +### Bug Fixes + +* 注册 builtinSetters / live-editing, 增加 init ([373556a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/373556a)) + + + + + +## [1.0.30-beta.10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.9...v1.0.30-beta.10) (2021-01-12) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.30-beta.9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.8...v1.0.30-beta.9) (2021-01-11) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.30-beta.8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.7...v1.0.30-beta.8) (2021-01-11) + + +### Features + +* 增加全局 API 模块和 vision-polyfill 模块 ([826ef2c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/826ef2c)) + + + + + +## [1.0.30-beta.7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.30-beta.6...v1.0.30-beta.7) (2021-01-11) + + +### Features + +* 支持 Panel / Widget / PanelDock 等类型的面板 disable / enable 方法, 以及相应的事件触发 ([06d2f43](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/06d2f43)) + + + + + +## [1.0.30-beta.6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.29...v1.0.30-beta.6) (2021-01-09) + + +### Bug Fixes + +* regist builtinSetters ([87f5f01](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/87f5f01)) +* 修复 preset-vision 版本号自动生成 ([1cfbe45](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1cfbe45)) + + +### Features + +* 支持 PanelDock 的 disable / enable 方法, 可用于初始化前后的开闭操作 ([60b12a4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/60b12a4)) + + + + + +## [1.0.29](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.28-beta.2...v1.0.29) (2021-01-05) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.28-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.28-beta.1...v1.0.28-beta.2) (2021-01-04) + + +### Bug Fixes + +* 初次 bootstrap 构建 types / utils ([1e59de5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1e59de5)) + + + + + +## [1.0.28-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27...v1.0.28-beta.1) (2021-01-04) + + +### Bug Fixes + +* 补全 componentsMap 的信息 ([eebd4a2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eebd4a2)) +* 适配vs-style,vs-select ([a69c1e4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a69c1e4)) + + +### Features + +* 🎸 utils 的定义中增加对于 function 类型的支持 ([29b1daf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/29b1daf)) +* 支持新版的 plugin 机制 ([1e8fc63](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1e8fc63)) + + + + + +## [1.0.28-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27...v1.0.28-beta.0) (2021-01-04) + + +### Bug Fixes + +* 补全 componentsMap 的信息 ([eebd4a2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eebd4a2)) +* 适配vs-style,vs-select ([a69c1e4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a69c1e4)) + + +### Features + +* 🎸 utils 的定义中增加对于 function 类型的支持 ([29b1daf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/29b1daf)) +* 支持新版的 plugin 机制 ([1e8fc63](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1e8fc63)) + + + + + +## [1.0.27](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.2...v1.0.27) (2020-12-24) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.27-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.1...v1.0.27-beta.2) (2020-12-23) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.27-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.0...v1.0.27-beta.1) (2020-12-23) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.27-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26...v1.0.27-beta.0) (2020-12-23) + + +### Features + +* 支持小程序低代码组件 ([b0aeed3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b0aeed3)) + + + + + +## [1.0.26](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26-beta.1...v1.0.26) (2020-12-22) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.26-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26-beta.0...v1.0.26-beta.1) (2020-12-22) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.26-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.25-beta.1...v1.0.26-beta.0) (2020-12-22) + + +### Bug Fixes + +* rax perf ([3abe2ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3abe2ab)) +* requestHandlersMap 没有加到 appContext 里 ([a8d43c3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a8d43c3)) +* simulator-renderer 补充丢失代码 ([67dd7e2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/67dd7e2)) +* 传递正确的 removeIndex 给到 subtreeModified 钩子 ([822b2fd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/822b2fd)) +* 修复 overridePropsConfigure 参数为数组时的逻辑 ([4e58e09](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4e58e09)) +* 修复组件不会插入到选中节点之内或者之后的逻辑 ([93b005b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/93b005b)) + + +### Features + +* 支持 build sourceMap, 方便用户调试 ([6bf75cd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6bf75cd)) +* 支持用户修改 builtinComponentActions ([bc183d1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bc183d1)) + + + + + +## [1.0.25-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.4...v1.0.25-beta.1) (2020-12-15) + + +### Bug Fixes + +* 修复 prop 无法删除最后一个 item ([e18a386](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e18a386)) +* 修复大纲树和组件面板来回点击异常 ([8b9a6ec](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b9a6ec)) + + + + + +## [1.0.24-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.3...v1.0.24-beta.4) (2020-12-14) + + +### Bug Fixes + +* 修复 prop.remove 在只有一个属性时无法删除的 bug ([037ecfd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/037ecfd)) + + + + + +## [1.0.24-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.2...v1.0.24-beta.3) (2020-12-11) + + +### Bug Fixes + +* registSetters in preset general ([ebe5d04](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ebe5d04)) +* svg-icon 默认改为 large ([21d92ff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/21d92ff)) +* 粘贴时判断 canDropIn ([07dab6d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/07dab6d)) + + +### Features + +* remove preset-general from cdn ([e126f24](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e126f24)) + + + + + +## [1.0.24-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.1...v1.0.24-beta.2) (2020-12-10) + + +### Bug Fixes + +* 删除无用代码, 解决 ts 编译报错 ([1f241ea](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1f241ea)) + + + + + +## [1.0.24-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.0...v1.0.24-beta.1) (2020-12-09) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.24-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23...v1.0.24-beta.0) (2020-12-09) + + +### Bug Fixes + +* fix wrong configure when isExtends is false 5123d071 ([d2de572](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2de572)) +* 修复设置区不刷新的 bug ([6b65364](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6b65364)) + + +### Features + +* array/object setter support getValue & setValue ([3175745](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3175745)) + + + + + +## [1.0.23](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.2...v1.0.23) (2020-12-08) + + +### Features + +* 加上 plugin-outline-pane ([83c0772](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/83c0772)) + + + + + +## [1.0.23-beta.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.4...v1.0.23-beta.5) (2020-12-08) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.23-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.3...v1.0.23-beta.4) (2020-12-08) + + +### Features + +* 加回 demo ([0a65224](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0a65224)) + + + + + +## [1.0.23-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.2...v1.0.23-beta.3) (2020-12-08) + + +### Features + +* 加上 plugin-outline-pane ([83c0772](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/83c0772)) + + + + + +## [1.0.23-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.1...v1.0.23-beta.2) (2020-12-08) + + +### Bug Fixes + +* editor-core 统一版本 ([edd4129](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/edd4129)) +* 补充 [@ali](https://gitlab.alibaba-inc.com/ali)/lowcode-editor-setters 依赖 ([c25c014](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c25c014)) + + +### Features + +* 增加 plugin-designer ([8bff207](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8bff207)) + + + + + +## [1.0.23-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-29...v1.0.23-beta.1) (2020-12-07) + + +### Bug Fixes + +* 🐛 fix typo of dataHandler ([acd1f06](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/acd1f06)) +* 🐛 Rax 出码到小程序, 事件处理函数绑定 JSExpression 时也不应该包裹一个 eval, 小程序会报错 ([9f129aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9f129aa)) +* 🐛 Result use types package ([dd97a0c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dd97a0c)) +* 🐛 schema 中没有 state 的定义, 出码后的 Rax/React 组件应有个默认的空的 state ([7e37f8d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7e37f8d)) +* 🐛 use lowcode types ([b11425b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b11425b)) +* 🐛 小程序里面不支持可选链 "?.", 先直接访问 dataSourceEngine 吧 ([36c486b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/36c486b)) +* 🐛 根据低代码规范,数据源的配置中isInit和 type 都是有默认值的,所以应该是可选的 ([4baf0b4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4baf0b4)) +* 🐛 经验证发现小程序里面还是得包上 eval 否则 Rax 框架会误把 context 发送到渲染进程而出错 ([c7a10c0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c7a10c0)) +* 🐛 若全量引入 lodash 则在小程序下会跑不通,所以改成引入 lodash/clone ([a1a3b68](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a1a3b68)) +* 🐛 解决 Rax 出码到小程序的时候 require(xxx) 语句不能被编译的问题 ([332a473](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/332a473)) +* 🐛 解决出码的 disk publisher 不能正确地创建子目录的问题 ([fb5ba93](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fb5ba93)) +* 🐛 解决多行文本在出码的时候生成的字符串是无效代码的问题 ([fa68857](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fa68857)) +* 🐛 解决条件渲染场景下若条件值为 0 会误渲染出 0 的问题 ([71aa2f6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/71aa2f6)) +* add package json typings ([6378595](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6378595)) +* babel build bug & add some comment ([1511e2c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1511e2c)) +* build error ([d06d944](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d06d944)) +* checkId 需要传递 ([bdff2b1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bdff2b1)) +* children 在 schema 和 props 中并存的情况处理 ([7b639eb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7b639eb)) +* datasource engine adpater ([52d0d88](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/52d0d88)) +* datasource package.json files 新增lib文件 ([a8a1749](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a8a1749)) +* datasource版本错误问题 ([a247878](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a247878)) +* enhance api design ([95d67c1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/95d67c1)) +* eslint ([98f3a17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/98f3a17)) +* eslint ([c346137](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c346137)) +* fix bug ([113e409](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/113e409)) +* fix function bug ([ab151df](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ab151df)) +* fix test result ([7f6fbe8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7f6fbe8)) +* fix typescript related bugs, including the following: ([d4c45d2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d4c45d2)) +* ignore eslintrc in test-case ([c0ef4bc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c0ef4bc)) +* JSExpression 增加 compiled ([9f51e39](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9f51e39)) +* jsonp handler rename ([cf3a61a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cf3a61a)) +* js编辑器移除尾逗号 ([7cd5c5c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7cd5c5c)) +* loadAsyncLibrary之后buildComponents ([aaec683](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/aaec683)) +* lock vesions of monaco ([b13f87b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b13f87b)) +* lowcode types update ([79e51a9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/79e51a9)) +* lowcode types update ([af5ef18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af5ef18)) +* merge problems & deps bugs ([7a36eab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7a36eab)) +* miniAppBuildType config(temp) ([584b4c2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/584b4c2)) +* miss scope ([97242c3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/97242c3)) +* monaco cdn url update ([7b2fe13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7b2fe13)) +* object property name fix logic ([dd69113](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dd69113)) +* package json ([8170523](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8170523)) +* polyfill Promise.allSettled ([9ca4b3f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9ca4b3f)) +* pure string export in jsx ([1a9e953](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1a9e953)) +* remove wrong propType match ([73e69fa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/73e69fa)) +* schema 变更处理 ([a0e5a26](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a0e5a26)) +* start shell add datasource build ([0537495](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0537495)) +* this 丢失问题 ([3423dc5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3423dc5)) +* tsconfig 修复 ([64a477c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/64a477c)) +* typo of onResizeEnd and remove ([8df5f05](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8df5f05)) +* update ([2f28a1d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2f28a1d)) +* update ([79be069](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/79be069)) +* update demo-server deps ([23ded02](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/23ded02)) +* will fetch 按照协议修改 ([b9bf800](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9bf800)) +* 代码结构调整 ([af4bc83](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af4bc83)) +* **editor-skeleton:** fix dynamic setter support in mixed-setter ([1726354](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1726354)) +* 修复 asset 中 componentList 为空时报错的 bug ([49517a6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/49517a6)) +* 修复 slot 以及子节点不销毁 ([8ef62c8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8ef62c8)) +* 修复BoolSetter的defaultValue不生效的问题 ([a701d5e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a701d5e)) +* 修复setter设置defaultValue不生效的问题 ([0cf47da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0cf47da)) +* 修复数据源的接入问题 ([98ae1ed](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/98ae1ed)) +* 修复组件面板 i18n 警告 ([37a409d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/37a409d)) +* 修复编辑器转化bug,增加窗口最大最小化功能 ([05666af](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/05666af)) +* 修改 asyncLibraryMap 拼写错误 ([8b2f045](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b2f045)) +* 修改style-setter报错,loadAsyncLib 判断 ([7fe793a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7fe793a)) +* 兼容服务大厅已有的的 api 字段 ([8f5d0ce](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8f5d0ce)) +* 函数签名及方法名拼写问题 ([e05790b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e05790b)) +* 删除测试代码 ([f08a067](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f08a067)) +* 去除 handler 依赖 ([806ca62](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/806ca62)) +* 合并数据源引擎修复代码 ([53f3554](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/53f3554)) +* 将monaco基础包全部移除,采用cdn形式注入 ([510f1c0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/510f1c0)) +* 支持 checkId 开关功能, 在 setSchema 时关闭, 避免 id 被不断重置 ([44bdda1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/44bdda1)) +* 设计和预览两种场景下 requestHandlersMap 的接入 ([f9e5397](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f9e5397)) +* 设计和预览两种场景下 requestHandlersMap 的接入 ([707de45](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/707de45)) +* 重构jsonsetter,移除iceluna ([cd7ee0d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cd7ee0d)) + + +### Features + +* **material-parser:** fix react-color version in tc & publish v1.0.23 ([975a5cd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/975a5cd)) +* 🎸 add rax code generator solution and test case ([20c0953](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/20c0953)) +* 🎸 custom 类型的数据源请求不需要 handler ([fa939c4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fa939c4)) +* 🎸 globalStyle 支持定制样式文件的后缀名 ([e78dae0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e78dae0)) +* 🎸 Rax 出码中增加对 urlParams 这种特殊数据源的处理 ([c743afd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c743afd)) +* 🎸 Rax 出码中添加数据源的 dataHandler 并与数据源引擎的对齐参数 ([42b9db3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/42b9db3)) +* 🎸 Rax 出码器支持路由功能 ([8ecc002](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8ecc002)) +* 🎸 Rax 出码支持 constants 常量定义 ([fcf6c32](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fcf6c32)) +* 🎸 Rax 出码适配数据源引擎的默认 requestHandlers ([5f529ae](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5f529ae)) +* 🎸 urlParams 类型的数据源不需要 options, 所以 options 改成可选为好 ([8114c6f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8114c6f)) +* 🎸 与国凯的数据源保持一致,将 urlParams 所需的 search 参数直接传入 ([19fabc1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/19fabc1)) +* 🎸 与国凯的数据源引擎联调,对齐包名和导出方式 ([fea0946](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fea0946)) +* 🎸 为 Rax 出码增加对 i18n 的支持 ([8d198bd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8d198bd)) +* 🎸 优化 Rax 出码时对绑定的表达式的包裹逻辑, 对于一些简单的安全的表达式不做包裹 ([facfa2a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/facfa2a)) +* 🎸 优化 ResultDir 的报错信息, 更方便定位问题 ([965ef4a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/965ef4a)) +* 🎸 优化完善 Rax 出码相关的模板和插件 ([c3d909a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c3d909a)) +* 🎸 出码模块的 DiskPublisher 改成支持传入自定义 FS ([46c896e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/46c896e)) +* 🎸 出码模块的 schema 相关的类型统一都改成引用 [@ali](https://gitlab.alibaba-inc.com/ali)/lowcode-types 中的,与设计器一致 ([27a9800](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/27a9800)) +* 🎸 完善 Rax 出码, 补充更复杂的带有数据源绑定/条件/循环以及 Utils 的测试用例并 pass ([adcfacb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/adcfacb)) +* 🎸 完善 Rax 出码, 跑通第一个测试用例👏👏👏 ([9f62110](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9f62110)) +* 🎸 完善 Rax 出码的时候的全局样式处理 ([058b087](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/058b087)) +* 🎸 完善 utils 面板, 默认不用传入类型则表示支持NPM, TNPM 和 function 类型 ([3e9a445](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3e9a445)) +* 🎸 容器的模块名统一都用 PascalCase, 并为页面添加特定后缀防止与组件名冲突 ([42f7bdb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/42f7bdb)) +* 🎸 导出 Rax 的 solutions 的定义 ([27f0e13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/27f0e13)) +* 🎸 按 826 对齐结论调整出码和数据源引擎 ([b9a562e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9a562e)) +* 🎸 按照中后台搭建协议规范文档补充 JSFunction 的定义和数据源定义中一些字段 ([8b1d0c7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b1d0c7)) +* 🎸 搞定 Rax 出码的时候的 package.json 中的 dependencies ([eba172c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eba172c)) +* 🎸 支持对 JSON 文件进行 prettier 格式化 ([b7c4854](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b7c4854)) +* 🎸 数据源的requestHandlers选项改成requestHandlersMap, 命名更清晰 ([42e41bb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/42e41bb)) +* 🎸 数据源的类型默认是 fetch ([ec8a191](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ec8a191)) +* 🎸 新增 less 文件类型的定义, 以备后续某些 solution 出码用 less 文件作为样式文件 ([cac29d8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cac29d8)) +* 🎸 根据低代码协议文档, 完善UtilsMap的定义 ([7fe4bc0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7fe4bc0)) +* 🎸 根据低代码协议文档, 将 BlockSchema 也改成继承自 ContainerSchema ([7901c8e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7901c8e)) +* 🎸 添加 didMount 和 willUnmount 两个基本的生命周期 ([e33a95e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e33a95e)) +* 🎸 添加一个判断 ContainerSchema 的 util 方便后续用 ([c3fdfe5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c3fdfe5)) +* 🎸 添加数据源引擎 ([624e2f8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/624e2f8)) +* 🎸 补充一个默认的数据源的构建后的样子 ([78f34ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/78f34ab)) +* 🎸 补充对数据源的一些处理 ([4572b53](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4572b53)) +* 🎸 补充规范中定义的 JSFunction 类型 ([9e32525](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9e32525)) +* 🎸 解决通过 Rax 出码到小程序的时候循环里面没法用循环变量的问题 ([779ea7c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/779ea7c)) +* 🎸 还原出码模块的 solutions 的导出 ([c2a7d63](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c2a7d63)) +* 🎸 通过 config.miniAppBuildType 来支持 Rax 的 runtime 模式 ([35fcdd9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/35fcdd9)) +* add datasource engine & handlers ([d115ce0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d115ce0)) +* add jsonp datahandler ([dcdcf28](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dcdcf28)) +* createApp时拿取onReady的入参 ([92d29c6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/92d29c6)) +* renderer 层透传 requestHandlersMap ([e12e031](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e12e031)) +* renderer 接入数据源引擎 ([a155920](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a155920)) +* split datasource types ([fd80698](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fd80698)) +* style 迁移 ([6ce97da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6ce97da)) +* support params & returns of func propType ([0e46e49](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0e46e49)) +* update datasource engine ([bf7b7d1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bf7b7d1)) +* update datasource engine ([cf3c7db](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cf3c7db)) +* use fixed version of react-docgen ([2993287](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2993287)) +* use parseJsDoc to parse propType docblock ([0b80be6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0b80be6)) +* 完成 utils 面板的基本功能 ([425c24d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/425c24d)) +* 支持 FunctionComponent 选中 ([d2d44e6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2d44e6)) +* 数据源面板 ([47f55ca](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/47f55ca)) +* 数据源面板 ([56eaff5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56eaff5)) +* 新增class-name setter ([a9f1131](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a9f1131)) +* 新增插件的静态函数onInit,每次插件安装的时候会执行 ([fb943c5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fb943c5)) +* 新增支持异步类型library ([2a491ae](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2a491ae)) +* 添加 utils 面板 ([29ad679](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/29ad679)) +* 调整 datasource-handlers ([2b9bcb5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2b9bcb5)) +* **version:** 发布版本1.0.9 ([eb00490](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eb00490)) +* 组件面板支持业务组件独立展示 ([e9d8d3d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e9d8d3d)) + + + + + +## [1.0.23-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-29...v1.0.23-beta.0) (2020-12-07) + + +### Bug Fixes + +* 🐛 fix typo of dataHandler ([acd1f06](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/acd1f06)) +* 🐛 Rax 出码到小程序, 事件处理函数绑定 JSExpression 时也不应该包裹一个 eval, 小程序会报错 ([9f129aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9f129aa)) +* 🐛 Result use types package ([dd97a0c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dd97a0c)) +* 🐛 schema 中没有 state 的定义, 出码后的 Rax/React 组件应有个默认的空的 state ([7e37f8d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7e37f8d)) +* 🐛 use lowcode types ([b11425b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b11425b)) +* 🐛 小程序里面不支持可选链 "?.", 先直接访问 dataSourceEngine 吧 ([36c486b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/36c486b)) +* 🐛 根据低代码规范,数据源的配置中isInit和 type 都是有默认值的,所以应该是可选的 ([4baf0b4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4baf0b4)) +* 🐛 经验证发现小程序里面还是得包上 eval 否则 Rax 框架会误把 context 发送到渲染进程而出错 ([c7a10c0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c7a10c0)) +* 🐛 若全量引入 lodash 则在小程序下会跑不通,所以改成引入 lodash/clone ([a1a3b68](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a1a3b68)) +* 🐛 解决 Rax 出码到小程序的时候 require(xxx) 语句不能被编译的问题 ([332a473](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/332a473)) +* 🐛 解决出码的 disk publisher 不能正确地创建子目录的问题 ([fb5ba93](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fb5ba93)) +* 🐛 解决多行文本在出码的时候生成的字符串是无效代码的问题 ([fa68857](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fa68857)) +* 🐛 解决条件渲染场景下若条件值为 0 会误渲染出 0 的问题 ([71aa2f6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/71aa2f6)) +* add package json typings ([6378595](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6378595)) +* babel build bug & add some comment ([1511e2c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1511e2c)) +* build error ([d06d944](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d06d944)) +* checkId 需要传递 ([bdff2b1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bdff2b1)) +* children 在 schema 和 props 中并存的情况处理 ([7b639eb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7b639eb)) +* datasource engine adpater ([52d0d88](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/52d0d88)) +* datasource package.json files 新增lib文件 ([a8a1749](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a8a1749)) +* datasource版本错误问题 ([a247878](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a247878)) +* enhance api design ([95d67c1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/95d67c1)) +* eslint ([98f3a17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/98f3a17)) +* eslint ([c346137](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c346137)) +* fix bug ([113e409](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/113e409)) +* fix function bug ([ab151df](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ab151df)) +* fix test result ([7f6fbe8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7f6fbe8)) +* fix typescript related bugs, including the following: ([d4c45d2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d4c45d2)) +* ignore eslintrc in test-case ([c0ef4bc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c0ef4bc)) +* JSExpression 增加 compiled ([9f51e39](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9f51e39)) +* jsonp handler rename ([cf3a61a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cf3a61a)) +* js编辑器移除尾逗号 ([7cd5c5c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7cd5c5c)) +* loadAsyncLibrary之后buildComponents ([aaec683](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/aaec683)) +* lock vesions of monaco ([b13f87b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b13f87b)) +* lowcode types update ([79e51a9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/79e51a9)) +* lowcode types update ([af5ef18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af5ef18)) +* merge problems & deps bugs ([7a36eab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7a36eab)) +* miniAppBuildType config(temp) ([584b4c2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/584b4c2)) +* miss scope ([97242c3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/97242c3)) +* monaco cdn url update ([7b2fe13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7b2fe13)) +* object property name fix logic ([dd69113](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dd69113)) +* package json ([8170523](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8170523)) +* polyfill Promise.allSettled ([9ca4b3f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9ca4b3f)) +* pure string export in jsx ([1a9e953](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1a9e953)) +* remove wrong propType match ([73e69fa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/73e69fa)) +* schema 变更处理 ([a0e5a26](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a0e5a26)) +* start shell add datasource build ([0537495](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0537495)) +* this 丢失问题 ([3423dc5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3423dc5)) +* tsconfig 修复 ([64a477c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/64a477c)) +* typo of onResizeEnd and remove ([8df5f05](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8df5f05)) +* update ([2f28a1d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2f28a1d)) +* update ([79be069](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/79be069)) +* update demo-server deps ([23ded02](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/23ded02)) +* will fetch 按照协议修改 ([b9bf800](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9bf800)) +* 代码结构调整 ([af4bc83](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af4bc83)) +* **editor-skeleton:** fix dynamic setter support in mixed-setter ([1726354](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1726354)) +* 修复 asset 中 componentList 为空时报错的 bug ([49517a6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/49517a6)) +* 修复 slot 以及子节点不销毁 ([8ef62c8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8ef62c8)) +* 修复BoolSetter的defaultValue不生效的问题 ([a701d5e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a701d5e)) +* 修复setter设置defaultValue不生效的问题 ([0cf47da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0cf47da)) +* 修复数据源的接入问题 ([98ae1ed](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/98ae1ed)) +* 修复组件面板 i18n 警告 ([37a409d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/37a409d)) +* 修复编辑器转化bug,增加窗口最大最小化功能 ([05666af](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/05666af)) +* 修改 asyncLibraryMap 拼写错误 ([8b2f045](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b2f045)) +* 修改style-setter报错,loadAsyncLib 判断 ([7fe793a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7fe793a)) +* 兼容服务大厅已有的的 api 字段 ([8f5d0ce](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8f5d0ce)) +* 函数签名及方法名拼写问题 ([e05790b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e05790b)) +* 删除测试代码 ([f08a067](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f08a067)) +* 去除 handler 依赖 ([806ca62](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/806ca62)) +* 合并数据源引擎修复代码 ([53f3554](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/53f3554)) +* 将monaco基础包全部移除,采用cdn形式注入 ([510f1c0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/510f1c0)) +* 支持 checkId 开关功能, 在 setSchema 时关闭, 避免 id 被不断重置 ([44bdda1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/44bdda1)) +* 设计和预览两种场景下 requestHandlersMap 的接入 ([f9e5397](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f9e5397)) +* 设计和预览两种场景下 requestHandlersMap 的接入 ([707de45](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/707de45)) +* 重构jsonsetter,移除iceluna ([cd7ee0d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cd7ee0d)) + + +### Features + +* **material-parser:** fix react-color version in tc & publish v1.0.23 ([975a5cd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/975a5cd)) +* 🎸 add rax code generator solution and test case ([20c0953](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/20c0953)) +* 🎸 custom 类型的数据源请求不需要 handler ([fa939c4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fa939c4)) +* 🎸 globalStyle 支持定制样式文件的后缀名 ([e78dae0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e78dae0)) +* 🎸 Rax 出码中增加对 urlParams 这种特殊数据源的处理 ([c743afd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c743afd)) +* 🎸 Rax 出码中添加数据源的 dataHandler 并与数据源引擎的对齐参数 ([42b9db3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/42b9db3)) +* 🎸 Rax 出码器支持路由功能 ([8ecc002](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8ecc002)) +* 🎸 Rax 出码支持 constants 常量定义 ([fcf6c32](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fcf6c32)) +* 🎸 Rax 出码适配数据源引擎的默认 requestHandlers ([5f529ae](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5f529ae)) +* 🎸 urlParams 类型的数据源不需要 options, 所以 options 改成可选为好 ([8114c6f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8114c6f)) +* 🎸 与国凯的数据源保持一致,将 urlParams 所需的 search 参数直接传入 ([19fabc1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/19fabc1)) +* 🎸 与国凯的数据源引擎联调,对齐包名和导出方式 ([fea0946](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fea0946)) +* 🎸 为 Rax 出码增加对 i18n 的支持 ([8d198bd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8d198bd)) +* 🎸 优化 Rax 出码时对绑定的表达式的包裹逻辑, 对于一些简单的安全的表达式不做包裹 ([facfa2a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/facfa2a)) +* 🎸 优化 ResultDir 的报错信息, 更方便定位问题 ([965ef4a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/965ef4a)) +* 🎸 优化完善 Rax 出码相关的模板和插件 ([c3d909a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c3d909a)) +* 🎸 出码模块的 DiskPublisher 改成支持传入自定义 FS ([46c896e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/46c896e)) +* 🎸 出码模块的 schema 相关的类型统一都改成引用 [@ali](https://gitlab.alibaba-inc.com/ali)/lowcode-types 中的,与设计器一致 ([27a9800](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/27a9800)) +* 🎸 完善 Rax 出码, 补充更复杂的带有数据源绑定/条件/循环以及 Utils 的测试用例并 pass ([adcfacb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/adcfacb)) +* 🎸 完善 Rax 出码, 跑通第一个测试用例👏👏👏 ([9f62110](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9f62110)) +* 🎸 完善 Rax 出码的时候的全局样式处理 ([058b087](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/058b087)) +* 🎸 完善 utils 面板, 默认不用传入类型则表示支持NPM, TNPM 和 function 类型 ([3e9a445](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3e9a445)) +* 🎸 容器的模块名统一都用 PascalCase, 并为页面添加特定后缀防止与组件名冲突 ([42f7bdb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/42f7bdb)) +* 🎸 导出 Rax 的 solutions 的定义 ([27f0e13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/27f0e13)) +* 🎸 按 826 对齐结论调整出码和数据源引擎 ([b9a562e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9a562e)) +* 🎸 按照中后台搭建协议规范文档补充 JSFunction 的定义和数据源定义中一些字段 ([8b1d0c7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b1d0c7)) +* 🎸 搞定 Rax 出码的时候的 package.json 中的 dependencies ([eba172c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eba172c)) +* 🎸 支持对 JSON 文件进行 prettier 格式化 ([b7c4854](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b7c4854)) +* 🎸 数据源的requestHandlers选项改成requestHandlersMap, 命名更清晰 ([42e41bb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/42e41bb)) +* 🎸 数据源的类型默认是 fetch ([ec8a191](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ec8a191)) +* 🎸 新增 less 文件类型的定义, 以备后续某些 solution 出码用 less 文件作为样式文件 ([cac29d8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cac29d8)) +* 🎸 根据低代码协议文档, 完善UtilsMap的定义 ([7fe4bc0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7fe4bc0)) +* 🎸 根据低代码协议文档, 将 BlockSchema 也改成继承自 ContainerSchema ([7901c8e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7901c8e)) +* 🎸 添加 didMount 和 willUnmount 两个基本的生命周期 ([e33a95e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e33a95e)) +* 🎸 添加一个判断 ContainerSchema 的 util 方便后续用 ([c3fdfe5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c3fdfe5)) +* 🎸 添加数据源引擎 ([624e2f8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/624e2f8)) +* 🎸 补充一个默认的数据源的构建后的样子 ([78f34ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/78f34ab)) +* 🎸 补充对数据源的一些处理 ([4572b53](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4572b53)) +* 🎸 补充规范中定义的 JSFunction 类型 ([9e32525](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9e32525)) +* 🎸 解决通过 Rax 出码到小程序的时候循环里面没法用循环变量的问题 ([779ea7c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/779ea7c)) +* 🎸 还原出码模块的 solutions 的导出 ([c2a7d63](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c2a7d63)) +* 🎸 通过 config.miniAppBuildType 来支持 Rax 的 runtime 模式 ([35fcdd9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/35fcdd9)) +* add datasource engine & handlers ([d115ce0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d115ce0)) +* add jsonp datahandler ([dcdcf28](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dcdcf28)) +* createApp时拿取onReady的入参 ([92d29c6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/92d29c6)) +* renderer 层透传 requestHandlersMap ([e12e031](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e12e031)) +* renderer 接入数据源引擎 ([a155920](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a155920)) +* split datasource types ([fd80698](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fd80698)) +* style 迁移 ([6ce97da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6ce97da)) +* support params & returns of func propType ([0e46e49](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0e46e49)) +* update datasource engine ([bf7b7d1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bf7b7d1)) +* update datasource engine ([cf3c7db](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cf3c7db)) +* use fixed version of react-docgen ([2993287](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2993287)) +* use parseJsDoc to parse propType docblock ([0b80be6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0b80be6)) +* 完成 utils 面板的基本功能 ([425c24d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/425c24d)) +* 支持 FunctionComponent 选中 ([d2d44e6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2d44e6)) +* 数据源面板 ([47f55ca](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/47f55ca)) +* 数据源面板 ([56eaff5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56eaff5)) +* 新增class-name setter ([a9f1131](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a9f1131)) +* 新增插件的静态函数onInit,每次插件安装的时候会执行 ([fb943c5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fb943c5)) +* 新增支持异步类型library ([2a491ae](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2a491ae)) +* 添加 utils 面板 ([29ad679](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/29ad679)) +* 调整 datasource-handlers ([2b9bcb5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2b9bcb5)) +* **version:** 发布版本1.0.9 ([eb00490](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eb00490)) +* 组件面板支持业务组件独立展示 ([e9d8d3d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e9d8d3d)) + + + + + +## [0.13.1-29](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-28...v0.13.1-29) (2020-12-03) + + +### Bug Fixes + +* 修复 setDevice 的时机,从 currentDocument -> simualtor ([0f14884](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0f14884)) + + + + + +## [0.13.1-28](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-27...v0.13.1-28) (2020-12-03) + + +### Bug Fixes + +* documentModel 里的 addon 相关函数跟原 vision 实现对齐 ([b0ea548](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b0ea548)) +* 原地编辑功能异常, 编辑时需要禁掉快捷键 ([3c000de](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3c000de)) + + + + + +## [0.13.1-27](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-26...v0.13.1-27) (2020-12-02) + + +### Bug Fixes + +* 修复 registerAddon 函数 ([309920a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/309920a)) + + + + + +## [0.13.1-26](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-25...v0.13.1-26) (2020-12-02) + + +### Bug Fixes + +* rax 组件无法拖拽的问题 ([3a4d47a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3a4d47a)) + + + + + +## [0.13.1-25](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-24...v0.13.1-25) (2020-12-01) + + + + +**Note:** Version bump only for package undefined + + +## [0.13.1-24](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-23...v0.13.1-24) (2020-11-26) + + +### Bug Fixes + +* 优化选中页面根节点时, 直接点击组件面板插入位置 ([c1ca2c6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c1ca2c6)) + + + + + +## [0.13.1-23](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-22...v0.13.1-23) (2020-11-25) + + + + +**Note:** Version bump only for package undefined + + +## [0.13.1-22](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-19...v0.13.1-22) (2020-11-25) + + +### Features + +* 支持无组件配置的设置面板形态 ([46c5bf9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/46c5bf9)) + + + + + +## [0.13.1-19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-18...v0.13.1-19) (2020-11-24) + + + + +**Note:** Version bump only for package undefined + + +## [0.13.1-18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-15...v0.13.1-18) (2020-11-20) + + +### Bug Fixes + +* 修复 setDevice 里获取 currentDocument 的逻辑 ([275b7aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/275b7aa)) + + + + + +## [0.13.1-15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-11...v0.13.1-15) (2020-11-18) + + +### Bug Fixes + +* build 版本号修改 ([fd71970](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fd71970)) +* 修复 project.unload 无法正常删除 document 的 bug ([5e6e91b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5e6e91b)) +* 去掉 AppHelper ([da9bb7f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/da9bb7f)) +* 解决 device 变化后不刷新视图的 bug ([11e8e02](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/11e8e02)) + + +### Features + +* 支持绝对布局容器中不显示 dragHost ([6eb9436](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6eb9436)) +* 暴露 registerMetadataTransducer 接口 ([cd12677](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cd12677)) + + + + +## [0.12.1-19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-18...v0.12.1-19) (2020-10-17) + + +### Features + +* 低成本方案支持绝对布局容器 ([a6067e8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a6067e8)) + + + + +## [0.12.1-18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-17...v0.12.1-18) (2020-10-17) + + +### Bug Fixes + +* 样式调整 ([2228ab9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2228ab9)) + + + + +## [0.12.1-17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-16...v0.12.1-17) (2020-10-14) + + +### Bug Fixes + +* build.json ([3594455](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3594455)) +* build.json ([48ee29d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/48ee29d)) +* build.json ([f993586](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f993586)) + + + + +## [0.12.1-16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-15...v0.12.1-16) (2020-10-12) + + + + +## [0.12.1-15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-1...v0.12.1-15) (2020-10-12) + + +### Bug Fixes + +* stage-box 样式优化 ([de4074a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/de4074a)) +* 样式兼容 ([0f2dea4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0f2dea4)) +* 样式微调 ([9816859](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9816859)) + + +### Features + +* getSuitableInsertion 支持 node 参数,checkNestingDown 将 target 转换为 Node ([5425864](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5425864)) +* 使用 release/1.0.0 的 editor-setters ([80d74d6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/80d74d6)) + + + + +## [0.12.1-14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-13...v0.12.1-14) (2020-10-10) + + +### Bug Fixes + +* lc-container-placeholder 样式修改 ([d939285](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d939285)) +* pane 宽度统一设置为 300 ([ff576b9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ff576b9)) + + + + +## [0.12.1-13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-12...v0.12.1-13) (2020-09-28) + + +### Bug Fixes + +* remove engine-tabpane css className ([d2fe75d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2fe75d)) + + + + +## [0.12.1-12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-11...v0.12.1-12) (2020-09-28) + + +### Bug Fixes + +* update package.json ([dfb2b47](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dfb2b47)) + + + + +## [0.12.1-11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-10...v0.12.1-11) (2020-09-27) + + + + +## [0.12.1-10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-9...v0.12.1-10) (2020-09-27) + + + + +## [0.12.1-9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-8...v0.12.1-9) (2020-09-27) + + + + +## [0.12.1-8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-7...v0.12.1-8) (2020-09-27) + + + + +## [0.12.1-7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-2...v0.12.1-7) (2020-09-27) + + +### Bug Fixes + +* build 配置文件修改 ([91cfb56](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/91cfb56)) +* designer.componentsMap ([d8d32a2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d8d32a2)) +* preset-vision 引入默认 setter,支持物料中心组件 ([0513318](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0513318)) +* 使用 componentMeta.isModal 代替 protoType.isModal() ([b787dc4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b787dc4)) +* 使用引擎标准的 lc-container-placeholder,支持 children 属性 ([b262665](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b262665)) + + +### Features + +* skeleton 增加全局 catch ([58b8200](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/58b8200)) + + + + + +## [0.13.1-12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-11...v0.13.1-12) (2020-11-18) + + +### Bug Fixes + +* build 版本号修改 ([fd71970](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fd71970)) +* 修复 project.unload 无法正常删除 document 的 bug ([5e6e91b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5e6e91b)) +* 去掉 AppHelper ([da9bb7f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/da9bb7f)) +* 解决 device 变化后不刷新视图的 bug ([11e8e02](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/11e8e02)) + + +### Features + +* 支持绝对布局容器中不显示 dragHost ([6eb9436](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6eb9436)) +* 暴露 registerMetadataTransducer 接口 ([cd12677](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cd12677)) + + + + +## [0.12.1-19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-18...v0.12.1-19) (2020-10-17) + + +### Features + +* 低成本方案支持绝对布局容器 ([a6067e8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a6067e8)) + + + + +## [0.12.1-18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-17...v0.12.1-18) (2020-10-17) + + +### Bug Fixes + +* 样式调整 ([2228ab9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2228ab9)) + + + + +## [0.12.1-17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-16...v0.12.1-17) (2020-10-14) + + +### Bug Fixes + +* build.json ([3594455](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3594455)) +* build.json ([48ee29d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/48ee29d)) +* build.json ([f993586](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f993586)) + + + + +## [0.12.1-16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-15...v0.12.1-16) (2020-10-12) + + + + +## [0.12.1-15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-1...v0.12.1-15) (2020-10-12) + + +### Bug Fixes + +* stage-box 样式优化 ([de4074a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/de4074a)) +* 样式兼容 ([0f2dea4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0f2dea4)) +* 样式微调 ([9816859](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9816859)) + + +### Features + +* getSuitableInsertion 支持 node 参数,checkNestingDown 将 target 转换为 Node ([5425864](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5425864)) +* 使用 release/1.0.0 的 editor-setters ([80d74d6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/80d74d6)) + + + + +## [0.12.1-14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-13...v0.12.1-14) (2020-10-10) + + +### Bug Fixes + +* lc-container-placeholder 样式修改 ([d939285](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d939285)) +* pane 宽度统一设置为 300 ([ff576b9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ff576b9)) + + + + +## [0.12.1-13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-12...v0.12.1-13) (2020-09-28) + + +### Bug Fixes + +* remove engine-tabpane css className ([d2fe75d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2fe75d)) + + + + +## [0.12.1-12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-11...v0.12.1-12) (2020-09-28) + + +### Bug Fixes + +* update package.json ([dfb2b47](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dfb2b47)) + + + + +## [0.12.1-11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-10...v0.12.1-11) (2020-09-27) + + + + +## [0.12.1-10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-9...v0.12.1-10) (2020-09-27) + + + + +## [0.12.1-9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-8...v0.12.1-9) (2020-09-27) + + + + +## [0.12.1-8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-7...v0.12.1-8) (2020-09-27) + + + + +## [0.12.1-7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-2...v0.12.1-7) (2020-09-27) + + +### Bug Fixes + +* build 配置文件修改 ([91cfb56](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/91cfb56)) +* designer.componentsMap ([d8d32a2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d8d32a2)) +* preset-vision 引入默认 setter,支持物料中心组件 ([0513318](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0513318)) +* 使用 componentMeta.isModal 代替 protoType.isModal() ([b787dc4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b787dc4)) +* 使用引擎标准的 lc-container-placeholder,支持 children 属性 ([b262665](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b262665)) + + +### Features + +* skeleton 增加全局 catch ([58b8200](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/58b8200)) + + + + + +## [0.13.1-11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-10...v0.13.1-11) (2020-11-02) + + +### Bug Fixes + +* 解决 slot 在关闭时没有正常回收节点 ([642a404](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/642a404)) + + + + + +## [0.13.1-10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-9...v0.13.1-10) (2020-10-26) + + + + +**Note:** Version bump only for package undefined + + +## [0.13.1-9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-7...v0.13.1-9) (2020-10-26) + + +### Bug Fixes + +* 处理 slot 开启/关闭操作中, 无法正常创建 slot 的bug ([3e86d09](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3e86d09)) + + + + + +## [0.13.1-8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-7...v0.13.1-8) (2020-10-26) + + + + +**Note:** Version bump only for package undefined + + +## [0.13.1-7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-6...v0.13.1-7) (2020-10-23) + + +### Features + +* 兼容 didDropOut 接口 ([2655c4a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2655c4a)) + + + + + +## [0.13.1-6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-5...v0.13.1-6) (2020-10-22) + + +### Bug Fixes + +* 修复修改 componentsMap 后无法刷新视图的 bug ([a1e7f21](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a1e7f21)) + + + + + +## [0.13.1-5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-4...v0.13.1-5) (2020-10-20) + + + + +**Note:** Version bump only for package undefined + + +## [0.13.1-4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-3...v0.13.1-4) (2020-10-20) + + + + +**Note:** Version bump only for package undefined + + +## [0.13.1-3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-2...v0.13.1-3) (2020-10-19) + + +### Bug Fixes + +* 修复 JSSlot 被转成 i18n 结构 ([f2c3292](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f2c3292)) + + + + + +## [0.13.1-2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-1...v0.13.1-2) (2020-10-19) + + +### Bug Fixes + +* convertI18nObject ([66d43f2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/66d43f2)) +* **editor-skeleton:** fix dynamic setter support in mixed-setter ([fca10ac](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fca10ac)) + + + + + +## [0.13.1-1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-3...v0.13.1-1) (2020-10-12) + + + + +**Note:** Version bump only for package undefined + + +## [0.12.1-3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-2...v0.12.1-3) (2020-10-12) + + +### Bug Fixes + +* 去掉 flags ([75fc3c6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/75fc3c6)) +* 处理 JSExpreesion 的 i18n 场景 ([9b87407](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9b87407)) + + + + + +## [0.12.1-2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.12.1-1...v0.12.1-2) (2020-09-23) + + +### Bug Fixes + +* i18n 绑定变量后消失 ([0aafafe](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0aafafe)) + + + + + +## [0.12.1-1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.9-9...v0.12.1-1) (2020-09-22) + + +### Bug Fixes + +* path with / ([2470363](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2470363)) + + + + + +## [1.0.9-9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.9-8...v1.0.9-9) (2020-09-22) + + +### Features + +* 支持 node.children.onInsert ([f120df5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f120df5)) + + + + + +## [1.0.9-8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.9-7...v1.0.9-8) (2020-09-22) + + +### Bug Fixes + +* JSSlot 格式也需要转换成 JSBlock ([e591aba](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e591aba)) +* revert 一段错误修改的代码 & 优化代码 ([614dbf2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/614dbf2)) +* save 的时候删除空的 props ([69cda3e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/69cda3e)) +* vision兼容标准api ([394db8d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/394db8d)) +* 修复修改 勾选框、富文本编辑器、下拉选择 等组件标题报错 ([8ba26ee](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8ba26ee)) +* 删除一个 console log ([79b7042](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/79b7042)) +* 去除乐高vision兼容影响 ([9e47561](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9e47561)) + + + + + +## [1.0.9-7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.9-5...v1.0.9-7) (2020-09-18) + + +### Bug Fixes + +* 1. 小程序导航配置 pagePath -> path 2.OneAPIConfig -> oneAPIConfig ([2714285](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2714285)) +* 修改 renderer 需等待 document 才开始渲染 ([e7cc9bc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e7cc9bc)) + + + + + +## [1.0.9-5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.9-2...v1.0.9-5) (2020-09-17) + + +### Bug Fixes + +* 低代码组件丢失代码找回 ([aac8126](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/aac8126)) +* 1.修复 rax 路由问题 2.切换 designMode 重新 setupSelection 3.settingpane add state shouldIgnoreRoot ([890ec76](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/890ec76)) +* should set field ([20c3b27](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/20c3b27)) +* should set field - demo-server ([6cfa0aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6cfa0aa)) +* source-editor bug & exp-setter bug ([5cd88d4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5cd88d4)) + + +### Features + +* 补充一些 vision API ([933cef1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/933cef1)) + + + + + +## [1.0.9-2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.9-1...v1.0.9-2) (2020-09-14) + + + + +**Note:** Version bump only for package undefined + + +## [1.0.9-1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.9-0...v1.0.9-1) (2020-09-14) + + + + +**Note:** Version bump only for package undefined + + +## 1.0.9-0 (2020-09-14) + + +### Bug Fixes + +* fieldId 重复问题 ([e761b1a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e761b1a)) +* (location) => ({location}) ([0e75b8e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0e75b8e)) +* [material-parser]fix bug of main field & remove useless debugger ([8fde0ec](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8fde0ec)) +* 🐛 add history pane for vision demo ([3ce7079](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3ce7079)) +* 🐛 add hotkey up/down/left/right ([9c8afe8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9c8afe8)) +* 🐛 add pollyfill for vision page.getHistory ([0b905d0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0b905d0)) +* 🐛 add tip on setter title ([c93c1d0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c93c1d0)) +* 🐛 after event name & TabItem parent limitation ([76fb0b3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/76fb0b3)) +* 🐛 bugs about deps ([1eabd50](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1eabd50)) +* 🐛 Card component's settings ([f44e7ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f44e7ab)) +* 🐛 Cascader init status ([e4a28c4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e4a28c4)) +* 🐛 children in props ([fe0ace8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fe0ace8)) +* 🐛 codeout btn fix ([afda7d4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/afda7d4)) +* 🐛 Collapse render error ([6fed968](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6fed968)) +* 🐛 empty ([927c8f2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/927c8f2)) +* 🐛 error when quick search ([801d954](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/801d954)) +* 🐛 eslint ([e3ca0bd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e3ca0bd)) +* 🐛 eslint ([14803dd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/14803dd)) +* 🐛 fix bug of transforming type ([ebbe58d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ebbe58d)) +* 🐛 fix bug of unevaluated default values ([22b667c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/22b667c)) +* 🐛 fix bug of validate schema ([3f97523](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3f97523)) +* 🐛 fix Menu & MenuButton assets cfg ([3d40aa2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3d40aa2)) +* 🐛 fix remaining bugs of unevaluated default values ([7947134](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7947134)) +* 🐛 get deps info from slot ([6c3ae36](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6c3ae36)) +* 🐛 getPrototype is undefined ([95b3409](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/95b3409)) +* 🐛 group chunks by filetype family ([db144a9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/db144a9)) +* 🐛 history pane zindex ([48f3be1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/48f3be1)) +* 🐛 i18n面板不生效 ([27cd916](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/27cd916)) +* 🐛 loop bug ([8f53910](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8f53910)) +* 🐛 mainArea 画布切换,MainArea 重新初始化导致 iframe 初始化报错 ([5054d06](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5054d06)) +* 🐛 Menu Items ([5ecacef](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5ecacef)) +* 🐛 repair children before deps analyze ([737d06e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/737d06e)) +* 🐛 save and generator last page ([3e4254c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3e4254c)) +* 🐛 style setter not working ([c88ea6b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c88ea6b)) +* 🐛 support JSFunction type ([9061e4b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9061e4b)) +* 🐛 Tab & TabItem assets config ([0cc08fb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0cc08fb)) +* 🐛 Tag assets ([b460dcf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b460dcf)) +* 🐛 Tag components setting ([de941da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/de941da)) +* 🐛 Timeline asset config ([436dadd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/436dadd)) +* 🐛 title缺少icon字段,临时转接一下 ([2f9bb25](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2f9bb25)) +* 🐛 update shell ([15fb964](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/15fb964)) +* 🐛 update start scripts ([6330f21](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6330f21)) +* 🐛 use intl ([a22e66a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a22e66a)) +* 🐛 use JsonSetter as dataSource Setter ([553f924](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/553f924)) +* 🐛 修复主设置面板下 stagebox 的样式问题 ([d5a98c0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d5a98c0)) +* 🐛 修复区块面板命名冲突的问题 ([de50ebf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/de50ebf)) +* 🐛 修复富文本高级内容弹层样式问题 ([edb480d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/edb480d)) +* 🐛 修复编辑面板 ([a0bad77](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a0bad77)) +* 🐛 增加 getAddonData api ([68b7e29](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/68b7e29)) +* 🐛 增加传入组件children的默认值[], 对之前的非健壮组件做兼容 ([af0f2df](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af0f2df)) +* 🐛 增加剪切快捷键 ([a73a82e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a73a82e)) +* 🐛 快捷键支持 ([73374dd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/73374dd)) +* 🐛 更改复杂类型生成工具的接口形式,减少调用复杂度 ([ce616b5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ce616b5)) +* 🐛 添加 loop 和 condition 的判断 ([b521ebe](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b521ebe)) +* 🐛 清理无用代码 ([015b58a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/015b58a)) +* 🐛 用 isI18nData 判断 meta title ([732bccf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/732bccf)) +* 🐛 移动快捷键 ([7c8a27c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7c8a27c)) +* 🐛 绑定动作无法打开代码面板 ([160d6f7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/160d6f7)) +* 🐛 解决点击组件时无法聚焦到点中的组件上的问题 ([852d882](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/852d882)) +* 🐛 逻辑简化 ([710f3ba](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/710f3ba)) +* 😈 table 无法选中问题 ([34825f8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/34825f8)) +* 😊修复arraysetter删除不更新问题 ([9d8a730](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9d8a730)) +* 1. 修复dialog拖入不显示问题 2. dialog 只能在根节点下 3. 引入 modalNodeManager ([65977e7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/65977e7)) +* add component ([995785d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/995785d)) +* add extraEnv ([9058ac8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9058ac8)) +* add FaultComponent style ([77b0b2c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/77b0b2c)) +* add pages.toData method ([95d3cb3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/95d3cb3)) +* add unique key ([e48307d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e48307d)) +* border action style ([6b91535](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6b91535)) +* call consumer ([70a1472](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/70a1472)) +* cancel dragging on invalid position ([f961096](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f961096)) +* canDropIn 为 boolean 时失效 ([7508fb6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7508fb6)) +* cloneElement bug ([d5c5614](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d5c5614)) +* compatiable bug ([45574db](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/45574db)) +* compatiable old VE api ([45af1c5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/45af1c5)) +* compatiableReducer 递归 ([e905928](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e905928)) +* condition增加异常保护 ([8324368](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8324368)) +* CR 问题修复 ([f054cbf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f054cbf)) +* createComponent 支持所有 schema ([7f946f5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7f946f5)) +* currentPage.id 返回 formUuid ([775725d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/775725d)) +* demo ([9142805](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9142805)) +* demo data ([b4a27fc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b4a27fc)) +* demo 中引入locode-editor-general ([1f03857](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1f03857)) +* depend ([c90996d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c90996d)) +* div 不显示问题 ([1b6533c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1b6533c)) +* documentModel toData 方法 ([1ea0d73](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1ea0d73)) +* dropdown and menu schema ([ae1d125](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ae1d125)) +* editor ([ccd9162](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ccd9162)) +* enhance compile config ([2899149](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2899149)) +* export data ([41f7724](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/41f7724)) +* factory api ([237b866](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/237b866)) +* fieldId 重复 ([5d64312](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5d64312)) +* fieldId 重置bug ([31215da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/31215da)) +* findDOMNodes ([7abf606](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7abf606)) +* findDOMNodes error ([6f5342d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6f5342d)) +* fix bug of build errors ([770a1b6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/770a1b6)) +* fix bug of missing ajv ([a37d655](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a37d655)) +* fix bug of missing types in material-parser ([9ce0a73](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9ce0a73)) +* fix function-setter bug ([8fd77df](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8fd77df)) +* fix function-setter bug ([dced647](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dced647)) +* fix mixsetter style ([0ecce83](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0ecce83)) +* fix NextTable callback function ([ce77375](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ce77375)) +* fix source edit bug ([047247c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/047247c)) +* force schema ([6d0a8ff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6d0a8ff)) +* formUuid 可能不在 url 中 ([8657ab8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8657ab8)) +* get pakcage.json ([8b99a51](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8b99a51)) +* getDocId ([34341d6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/34341d6)) +* getSuitablePlace ([03e7c57](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/03e7c57)) +* handling the undefined variable ([0efe8b4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0efe8b4)) +* history API ([e411687](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e411687)) +* history.listen({location}) => history.listen(location) ([25a6390](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/25a6390)) +* i18n parser & setting ([dbdd9e4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dbdd9e4)) +* intl ([8a061ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8a061ab)) +* layout tabbar number ([3975571](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3975571)) +* lc-borders-actions ([56d9f5f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56d9f5f)) +* left-fixed-pane 设置宽度不生效 ([a5f0d5e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5f0d5e)) +* live editing outline colore ([791771c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/791771c)) +* merge ([ac55847](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ac55847)) +* miniapp compwrapper ref ([5ae08f5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5ae08f5)) +* miniapp demo ([7c42473](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7c42473)) +* modal node locate ([9a72dd7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9a72dd7)) +* modify docId ([dc95033](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dc95033)) +* modify layout props ([9baba75](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9baba75)) +* nextId append the id of document ([80a5c93](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/80a5c93)) +* nextId() 逻辑调整 ([488a5d8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/488a5d8)) +* NodeChildren伪装为Array保证向前兼容 ([7950bf5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7950bf5)) +* onDocumentChange ([eb60d1f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eb60d1f)) +* onReRender ([29ea5f7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/29ea5f7)) +* panel visible time ([18ac1fa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/18ac1fa)) +* parse custom methods function ([87d8b86](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/87d8b86)) +* patch prototype ([f20bfaa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f20bfaa)) +* path resolve problem ([b12c0f8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b12c0f8)) +* plugin-desiger 支持从 editor 获取 device 参数 ([43bc29b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/43bc29b)) +* plugin-designer ([2dfbcd4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2dfbcd4)) +* post process file error ([389eaf7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/389eaf7)) +* prop type=UNSET 时返回 undefined ([f437f30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f437f30)) +* props.getNode 防死循环 ([444e25c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/444e25c)) +* quickSearch error ([a8009ef](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a8009ef)) +* rax finddom 方法重写 ([1d90928](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1d90928)) +* raxFindDOMNodes ([90430f3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/90430f3)) +* react simulator rendererContainer props ([6e1eac0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6e1eac0)) +* remove 1.txt ([796d09d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/796d09d)) +* remove abstract identifer ([2e45266](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2e45266)) +* remove console ([6c703d8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6c703d8)) +* remove console ([6889123](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6889123)) +* remove debugger ([a835dc6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a835dc6)) +* remove vision dependency from plugin-undo-redo ([08b93f9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/08b93f9)) +* rename MixinSetter to MixedSetter ([0e9a740](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0e9a740)) +* render children ([487f257](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/487f257)) +* render error样式 ([d601d5e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d601d5e)) +* rendererContainer ([486713a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/486713a)) +* revert ([dad21e2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dad21e2)) +* rm demo in lib ([55630d6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/55630d6)) +* router change ([920e584](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/920e584)) +* router rerender ([d886abc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d886abc)) +* same name chunk case ([d6855e2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d6855e2)) +* schema should be componentsTree ([69a2a89](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/69a2a89)) +* set i18n setter value when change mixed setter ([72d81c2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/72d81c2)) +* setter 报错不影响页面渲染 ([c0a6022](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c0a6022)) +* setting pane tab active ([06d7b50](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/06d7b50)) +* setting 面板样式调整 ([922b361](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/922b361)) +* settingField items is empty when type is not 'group' ([582c41a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/582c41a)) +* settingfield添加props修复地区组件切换类型报错 ([88348f7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/88348f7)) +* settings pane ([27db010](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/27db010)) +* skeleton.topArea.hide() 不生效的问题 ([6d2b955](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6d2b955)) +* slot 兼容问题 + loop key bug fix ([bc64017](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bc64017)) +* style ([4694331](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4694331)) +* support dropObject is data ([809fda7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/809fda7)) +* supports ([371b84c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/371b84c)) +* tip direction ([f51d496](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f51d496)) +* topbar search icon ([0447801](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0447801)) +* Trunk add getSetter ([b6d64c3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b6d64c3)) +* Trunk.getSetter return ReactElement ([34bf71d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/34bf71d)) +* try get settingfield ([56f242f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56f242f)) +* ts type ([1732e7d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1732e7d)) +* typeName 为 any 时转换出的 MixedSetter 缺少 props 的问题 ([4b9084f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4b9084f)) +* uniqueid ([8db52f0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8db52f0)) +* update package.json ([f1ec59c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f1ec59c)) +* updateProps before init ([760e6a6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/760e6a6)) +* upgradePropsReducer ([e68977f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e68977f)) +* use webpack for package ([b350a88](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b350a88)) +* using the same eslint config ([5532c94](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5532c94)) +* variable init bug ([6d55bd3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6d55bd3)) +* vc-filter bug fix ([31ea5d5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/31ea5d5)) +* VC-Filter组件的适配问题 ([1f581b8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1f581b8)) +* vision API 兼容 DockPane.getDocks() ([f72fb66](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f72fb66)) +* vision prop 初始化时有依赖已初始化的 prop,需要实时添加 ([1feb46f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1feb46f)) +* vision 大包 window 指向问题 ([aa1b526](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/aa1b526)) +* VisualEngine 仍使用 ifframe 中 window 对象 ([9d19731](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9d19731)) +* window.parent ([7e1b8ff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7e1b8ff)) +* 不对外暴露 Node ([05957ce](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/05957ce)) +* 不应该限定 parent 才做解绑操作 ([2e616e3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2e616e3)) +* 临时解决 lowCodeComponent 性能问题 ([25b4ba2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/25b4ba2)) +* 优化simulator样式 ([25ba893](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/25ba893)) +* 优化树子节点删除逻辑 ([47e814f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/47e814f)) +* 优化画布中点击事件屏蔽,增加富文本组件的部分屏蔽 ([ec08c6c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ec08c6c)) +* 优化画布中点击事件屏蔽,增加富文本组件的部分屏蔽 ([a5b6557](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5b6557)) +* 低代码组件 props 显示 object 问题 ([116498e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/116498e)) +* 低代码组件修改之后渲染为空 ([ef71632](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ef71632)) +* 使用深拷贝赋值并修改 dataSource.list 避免影响 legao 现有逻辑 ([82c5d2e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/82c5d2e)) +* 保存区块按钮渲染异常 ([33a7227](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/33a7227)) +* 修复 condition 代码导出错误 ([57b30cf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/57b30cf)) +* 修复 initial 重复、type = 'composite' 时 items 为空 ([bf79e63](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bf79e63)) +* 修复 preset-vision 版本 lifeCycles 丢失以及 slot 初始化问题 ([7cf6d24](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7cf6d24)) +* 修复 slot 获取初始值异常的 bug ([63b19f1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/63b19f1)) +* 修复 toolbar 弹出位置异常 ([b40b9a4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b40b9a4)) +* 修复bool类型对应的setter ([2df6230](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2df6230)) +* 修复js面板引用计数问题 ([fcc1a6f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fcc1a6f)) +* 修复低代码组件内部部分区域无法选中 ([f0adaa5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f0adaa5)) +* 修复低代码组件设计器、区块设计器根节点为 Page 的问题,修复 topArea 样式 ([e85b542](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e85b542)) +* 修复删除时,当前组件信息丢失问题 ([3bd1248](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3bd1248)) +* 修复判断动态 setter 的逻辑 ([d195d7f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d195d7f)) +* 修复取不到值的情况 ([5e7e488](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5e7e488)) +* 修复在切换页面时,没有销毁相应节点导致的一系列bug ([59fac25](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/59fac25)) +* 修复导入的组件拖入画布报错 ([caf9915](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/caf9915)) +* 修复无法拖动的问题 ([2b2de74](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2b2de74)) +* 修复组件面板详情加载不了的 bug ([cca3309](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cca3309)) +* 修复获取 currentPage 的逻辑 ([d8221db](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d8221db)) +* 修改dataSource items -> list ([46eadd1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/46eadd1)) +* 修改js面板的保存schema问题 ([0ee8892](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0ee8892)) +* 修改插件面板配置 ([f9ceda5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f9ceda5)) +* 修改移动端设备宽度 ([cd7b1e6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cd7b1e6)) +* 兼容 listSetter 内部变量,修复回退 fieldId 重置问题 ([c95e618](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c95e618)) +* 兼容 rpx ([5050af7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5050af7)) +* 兼容 variable 历史数据格式 ([d666317](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d666317)) +* 兼容modal模式 ([1092ee9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1092ee9)) +* 兼容vision体系代码面板中引用计数功能 ([8ade6d8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8ade6d8)) +* 兼容事件绑定 ([f4c07af](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f4c07af)) +* 兼容原来 prototype 的 componentName/view ([d542a40](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d542a40)) +* 兼容小程序面板的特殊情况 ([3c686ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3c686ab)) +* 初始就create 所有documentInstance, 否则路由跳转有问题 ([fdd6978](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fdd6978)) +* 动作面板名字 ([f734a61](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f734a61)) +* 区块模板切换之后数据不显示 ([292c1c3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/292c1c3)) +* 区块模板根节点支持 Div ([c3b796e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c3b796e)) +* 区块组件无法删除 ([d936d2b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d936d2b)) +* 卡片内容不可用拖动 ([6a85c43](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6a85c43)) +* 去掉根据 componentName 判断 isModal 的逻辑 ([28f0213](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/28f0213)) +* 可以降级到历史的 JSBlock 格式 ([af1746b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af1746b)) +* 右侧配置面板样式修复 ([05f62da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/05f62da)) +* 右侧配置面板面包屑点击无效 ([353fb10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/353fb10)) +* 合并后bugfix ([c3e6b4b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c3e6b4b)) +* 在 renderer 层面做 function component 包装,避免影响 rax 等其他场景 ([1f920dd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1f920dd)) +* 在Transducer中添加对MixedSetter的支持 ([7317f2f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7317f2f)) +* 在设计器里,所有组件都需要展示,不管 condition 为何值 ([0e7e038](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0e7e038)) +* 增加 getNode 兼容接口 ([5b6792f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5b6792f)) +* 增加try catch ([6f5d11c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6f5d11c)) +* 增加兼容 API ([2960446](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2960446)) +* 处理 function component 无法选中的问题,本质上是没有 ref ([fa94aab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fa94aab)) +* 处理 schema id 重复的问题 ([d2316be](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2316be)) +* 处理选区的 toolkit 位置不对的 bug ([bfc63db](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bfc63db)) +* 复制之后 fieldId 重复 ([36621ea](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/36621ea)) +* 多选时设置项异常 ([8cc9d73](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8cc9d73)) +* 大纲树节点显示隐藏埋点 ([e91ab1f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e91ab1f)) +* 实现 removeDocument ([c07b447](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c07b447)) +* 导入的组件默认怎么变量绑定 ([fc398c2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fc398c2)) +* 导入的组件默认怎么变量绑定 ([194d8d8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/194d8d8)) +* 快捷键增加判断 ([0f64829](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0f64829)) +* 快捷键增加判断 ([e18a231](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e18a231)) +* 拖拽时要解除与原来节点的关系 ([7a6bf2c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7a6bf2c)) +* 支持 AC 组件 ([c287bad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c287bad)) +* 支持事件 VE_EVENTS.VE_PAGE_PAGE_READY ([935ffad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/935ffad)) +* 支持低代码组件样式 ([6e64be1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6e64be1)) +* 支持自定义 Block 容器 ([1c0b508](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1c0b508)) +* 支持页面回滚 ([5d7dc2f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5d7dc2f)) +* 新增自定义模式 demo & 导出自定义需要的信息 ([07e2759](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/07e2759)) +* 暂时使用 live 模式作为条件判断是否限制选中 Page 组件 ([0bab030](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0bab030)) +* 更改生成 id 的规则, 否则命中 recore 解析 id 的一个限制 ([5adff44](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5adff44)) +* 根据目标元素的canDropIn函数判断是否能放入其他元素 ([21d4f64](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/21d4f64)) +* 框架样式调整 ([58790c5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/58790c5)) +* 没有 modal node 时不显示模态视图 ([555824c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/555824c)) +* 清理代码依赖及版本 ([0b15d30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0b15d30)) +* 灵犀vc组件中调用config, 补充进去 ([7171aa2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7171aa2)) +* 用户在动态修改 prototype 时也需要重新计算 meta ([66c21c0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/66c21c0)) +* 画布BorderAction埋点数据 ([d813b50](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d813b50)) +* 禁止组件拉到 Page 的直接子节点, 以及替换 tab 组件 ([d93a291](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d93a291)) +* 移除 isInSimulator 函数 ([6370889](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6370889)) +* 简化 onPageReady 实现逻辑 ([a36e5f2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a36e5f2)) +* 组件缺失占位 ([aff2f34](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/aff2f34)) +* 补充documnet-model中addonData 相关方法 ([cbc70ea](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cbc70ea)) +* 补全 packageName, 否则在组件面板会被隐藏 ([88e5008](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/88e5008)) +* 解决 set('schema') 后 componentsTree 越来越多的 bug ([a171d3e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a171d3e)) +* **settings-pane:** overflow problem ([d2d8556](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d2d8556)) +* 解决点击数据源,自动隐藏的问题 ([7dcd61c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7dcd61c)) +* 调整 upgrade 和 init 的流程 ([09fc1a0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/09fc1a0)) +* 调整visionNode修改未知 ([da59235](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/da59235)) +* 调整保存成功弹出框位置 ([5198dae](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5198dae)) +* 适配Nav组件 ([7e9829f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7e9829f)) +* 部分低代码组件渲染报错 ([093015c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/093015c)) +* **designer:** fix insertion style ([82c10d2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/82c10d2)) +* **designer/node.ts:** fix hasLoop logic ([99a7288](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/99a7288)) +* 钉住行为调整 ([91a390e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/91a390e)) +* 页面加载之后就被标记位 isModified ([2840d27](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2840d27)) +* **editor-skeleton:** add canSetFixed prop to panel config ([1b57d5c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1b57d5c)) +* **rax-render:** hidden无效 ([08a3e36](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/08a3e36)) +* **react-renderer:** fix hasLoop logic ([577e0eb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/577e0eb)) + + +### Code Refactoring + +* 💡 refactor with react-docgen ([64c9daa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/64c9daa)) + + +### Features + +* 🎸 add component descriptions in assets ([ceb15f9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ceb15f9)) +* 🎸 add demo-server ([df35c6a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/df35c6a)) +* 🎸 add missing dependencies to editor ([54477aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/54477aa)) +* 🎸 add node type mapping config for jsx plugin ([19a51b8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/19a51b8)) +* 🎸 Box config edit ([49b49ee](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/49b49ee)) +* 🎸 Button update ([7969273](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7969273)) +* 🎸 code generator fix slot support ([e51b9cb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e51b9cb)) +* 🎸 Collapse component update ([c682cc5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c682cc5)) +* 🎸 Collapse.panel has drop in Collapse ([d4d41e4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d4d41e4)) +* 🎸 modify repo config & template config ([049e6cb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/049e6cb)) +* 🎸 pagination update ([f13b3ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f13b3ab)) +* 🎸 ployfill for vision ([41a0647](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/41a0647)) +* 🎸 polyfill exchange ([286e7d8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/286e7d8)) +* 🎸 polyfill exchange ([7070557](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7070557)) +* 🎸 polyfill style ([c48846d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c48846d)) +* 🎸 polyfill style ([a6381d7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a6381d7)) +* 🎸 prototype getTitle 支持 i18n ([18807ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/18807ab)) +* 🎸 saveload btn for demo ([f91da66](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f91da66)) +* 🎸 support parsing fusion source code ([5895cf1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5895cf1)) +* 🎸 support parsing sub components ([70f3e32](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/70f3e32)) +* 🎸 update sh ([3e23362](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3e23362)) +* 🎸 update upload component ([10abef5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/10abef5)) +* 🎸 upload update ([f81932b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f81932b)) +* 🎸 为了能更好地在设计态模拟, 将 device 透传到组件树根组件上 ([2a253fb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2a253fb)) +* 🎸 为了能更好地在设计态模拟, 将 device 透传到组件树根组件上 ([7ab7def](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7ab7def)) +* 🎸 为容器的占位元素增加一个特定的 class 方便在设计器里定制样式 ([5077141](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5077141)) +* 🎸 增加icon相关的判断函数 ([89064f5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/89064f5)) +* 🎸 增加icon获取api ([f1a0823](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f1a0823)) +* 🎸 增加一个hover事件效果 ([da5dd1a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/da5dd1a)) +* 🎸 增加节点选择组件调用入口 ([e945d79](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e945d79)) +* 🎸 容器占位原生的样式从内联改成写在 CSS 文件里,方便被覆盖样式 ([a616e18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a616e18)) +* 🎸 支持设置模拟器的 viewport 的宽高和缩放级别 ([3a54241](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3a54241)) +* 🎸 旧的组件无法继续沿用,增加了一个节点选择组件 ([f042041](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f042041)) +* $ method ([cf50292](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cf50292)) +* add ? to component designer/src/designer/setting/utils.js ([0025e3c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0025e3c)) +* add alias for get index ([e853a4f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e853a4f)) +* add color-setter ([a149921](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a149921)) +* add eslint ignore ([28ad3e9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/28ad3e9)) +* add expression-setter AutoComplete tips ([9c62a49](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9c62a49)) +* add favicon for preview ([9c1b2d6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9c1b2d6)) +* add filter reducer ([17c6ed3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/17c6ed3)) +* add function setter ([114b6b0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/114b6b0)) +* add init and ready lifecycles ([fd100c9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fd100c9)) +* add label for i18n setter in slots ([b298c18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b298c18)) +* add Monitor ([f915d19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f915d19)) +* add prettier post processor ([49ac9a3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/49ac9a3)) +* add recore project template ([267953b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/267953b)) +* add resize box ([14a55ae](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/14a55ae)) +* add root field to material parser options ([c6724e9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c6724e9)) +* add setters ([15317b0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/15317b0)) +* add setters ([af62a3e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af62a3e)) +* add style setter ([efb3e5e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/efb3e5e)) +* add style-setters ([99b1d84](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/99b1d84)) +* add template create tool ([e906683](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e906683)) +* add URL link for setter titles ([4678408](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4678408)) +* add xima ([ff1e17a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ff1e17a)) +* add zip publisher ([31156ed](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/31156ed)) +* bord resizing ([361f4f6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/361f4f6)) +* border resizing ([c7fc28c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c7fc28c)) +* cache lazyElement ([8f3b4e6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8f3b4e6)) +* change reducer stage ([c2e83c7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c2e83c7)) +* code generator main process ([021d6e0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/021d6e0)) +* complet dynamically render ([edf14c1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/edf14c1)) +* complet preview ([56c16ff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56c16ff)) +* complet Trunk ([fcd0af8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fcd0af8)) +* complete component protocol json schema & validate method ([3df360d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3df360d)) +* complete live-editing expr & i18n ([3ac08ba](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3ac08ba)) +* current DocuemntInstance add refresh method ([b18a0d2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b18a0d2)) +* demo schema & complex children type ([a5ee6bd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5ee6bd)) +* demo 构造 componentsMap ([f445ffe](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f445ffe)) +* double outline & ZH_EN support ([b379bd7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b379bd7)) +* duplicate ([ec932aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ec932aa)) +* Exchange ([ef5a72e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ef5a72e)) +* export Monitor ([51025f0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/51025f0)) +* export navigator ([ef99ec2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ef99ec2)) +* export publisher ([4a53faa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4a53faa)) +* extend deviceClassName ([0e96074](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0e96074)) +* fix gaps ([32af3d3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/32af3d3)) +* for box resizing ([77e325f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/77e325f)) +* for box resizing ([cb2854d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cb2854d)) +* get layout config from legao-design ([b9103a2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9103a2)) +* get SettingField instead of SettingPropEntry for compatibility ([2787a12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2787a12)) +* history log ([fbb3577](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fbb3577)) +* immigrate aimake materialin ([44ac85f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/44ac85f)) +* import react-docgen to parse propTypes ([6e66168](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6e66168)) +* init ([b0de4f3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b0de4f3)) +* init rax-render ([7167767](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7167767)) +* iphonex 样式 ([e3637b0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e3637b0)) +* iphonex 样式 ([08d7875](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/08d7875)) +* JSexpression props ([26f4fb1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/26f4fb1)) +* left pane style ([c149f64](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c149f64)) +* left pane title style; setting pane style ([66e8c25](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/66e8c25)) +* lint command ([fae976c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fae976c)) +* live mode lifeCycles ([66f0c79](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/66f0c79)) +* live 模式取消 mock 兼容 ([ab66fd4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ab66fd4)) +* load assets for preview ([5376469](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5376469)) +* merge live mode ([92c3039](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/92c3039)) +* mixin-setter get all setter ([a5eb62d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5eb62d)) +* mixin-setter get all setter ([eaa84d2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eaa84d2)) +* panel增加自动埋点 ([afc7758](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/afc7758)) +* plugin preview ([18f149e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/18f149e)) +* prepare publish for code-generator ([93ff5c2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/93ff5c2)) +* preview ([abeb2ba](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/abeb2ba)) +* project builder fix & publish demo to disk ([26983b3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/26983b3)) +* rax render ([6ce0093](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6ce0093)) +* rax render ([95bf331](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/95bf331)) +* rax render ([038d74e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/038d74e)) +* rax-render 兼容 ([877d3fc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/877d3fc)) +* rax-render 拦截逻辑 & request 调用 webtable(mock) ([42108f6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/42108f6)) +* ReactProvider ([0e50a20](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0e50a20)) +* recore solution ([3bfe758](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3bfe758)) +* register-defaults 改为可选项 ([2195797](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2195797)) +* remove -p tslint.json for test ([6d013e1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6d013e1)) +* remove useless codes & modify generator ([dcd1b33](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dcd1b33)) +* rewrite demo & export plugins and utils ([6cf7c3d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6cf7c3d)) +* run vision polyfill ([33750b7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/33750b7)) +* save display JSON result ([5afd388](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5afd388)) +* select add setters ([c84e3a7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c84e3a7)) +* setting-pane 新增removeProp 函数 ([b97c807](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b97c807)) +* show value state ([bd49e50](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd49e50)) +* style setter 国际化 ([4619ee3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4619ee3)) +* support components ([d72c0d1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d72c0d1)) +* support float pane fixed ([40d8260](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/40d8260)) +* support global inline editing ([4f7179b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4f7179b)) +* support localizing ([e1faa84](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e1faa84)) +* support multiple exported components ([db1b6de](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/db1b6de)) +* support plaintext liveediting ([ea62f12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ea62f12)) +* support prop.autorun ([c0a5235](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c0a5235)) +* support subtreeModified ([7eeb51c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7eeb51c)) +* support typescript & dynamic parsing in material parser ([6168ef5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6168ef5)) +* tree 组件修改 ([7efa52f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7efa52f)) +* use new ComponentPane ([56ae5ad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56ae5ad)) +* ve事件埋点 ([700e5b0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/700e5b0)) +* window._table ([e6cce31](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e6cce31)) +* 主设置面板里深层次界面通过 stagebox 进行过渡 ([783e945](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/783e945)) +* 修复状态切换失效 ([2e3f60d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2e3f60d)) +* 修改rax-render ([14ad77c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/14ad77c)) +* 在 editor-preset-vision 中对 legao schema 进行向前兼容 ([7867917](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7867917)) +* 增加 defaultFixed,面板可默认固定 ([eb51b5e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/eb51b5e)) +* 增加 node replaceWith 方法 ([d44f95b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d44f95b)) +* 增加color-setter,json-setter ([93e76ce](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/93e76ce)) +* 增加loading扩展点 ([3a1e900](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3a1e900)) +* 增加miniapp外壳 ([bccce8c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bccce8c)) +* 增加出码按钮 ([6f7b066](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6f7b066)) +* 大纲树埋点 ([fa24821](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fa24821)) +* 大纲树展开折叠埋点 ([d9828f2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d9828f2)) +* 大纲树支持模态视图 ([3785e1c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3785e1c)) +* 容器组件支持传入 placeholder 和对应样式 ([0c4de43](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0c4de43)) +* 导出的schema增加componentsMap ([dbc958c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/dbc958c)) +* 引擎层埋点 ([69de533](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/69de533)) +* 抽离AppHelper ([1f6d131](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1f6d131)) +* 接入乐高组件面板 ([e40b1f3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e40b1f3)) +* 支持 entry 模式 ([fe1f6f1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fe1f6f1)) +* 支持body和背景样式 ([661d98d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/661d98d)) +* 支持低代码组件设计态实时改变 ([c5a817b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c5a817b)) +* 支持多 pages 的 schema 结构 ([d9b5adb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d9b5adb)) +* 支持编译渲染 ([0a42151](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0a42151)) +* 支持配置layouts属性 ([8464235](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8464235)) +* 新增functionSetter ([9359ac6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9359ac6)) +* 新增simulatorurl,可以设置cdn使用simulator ([1f45b05](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1f45b05)) +* 新增事件入参功能 ([0614fa7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0614fa7)) +* **designer:** add blank page logic ([aeeb9ba](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/aeeb9ba)) +* **designer:** add builtin hotkeys ([2ec5883](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2ec5883)) +* **rax-provider:** init ([cb0f382](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cb0f382)) +* **vision-polyfill:** add context ([f724487](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f724487)) +* **vision-polyfill:** add context as portal ([bd12730](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd12730)) +* **vision-polyfill:** support polyfill of vision package ([204fdfe](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/204fdfe)) +* 新增分隔符物料配置 ([af39c17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/af39c17)) +* 新增用于小程序跳过 variable 检测设置 hotvalue 的方法 ([ef799eb](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ef799eb)) +* 编辑器 hooks 能力实现 ([f3ac23b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f3ac23b)) +* 自动埋点 ([fecf34d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fecf34d)) +* 适配 webtable ([91f1702](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/91f1702)) +* 适配TreeNode节点 ([8c36928](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8c36928)) +* 适配乐高 OneApi 数据源,将 options.params 从 Array 改为 Object ([aa135c0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/aa135c0)) +* 透出loading ([e96934a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e96934a)) +* 透出错误边界捕捉不到的错误 ([f224abf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f224abf)) + + +### Reverts + +* 去掉多余注释 ([2495afa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2495afa)) + + +### BREAKING CHANGES + +* 🧨 use react-docgen to replace parser diff --git a/CONTRIBUTOR.md b/CONTRIBUTOR.md new file mode 100644 index 0000000000..bcadf23431 --- /dev/null +++ b/CONTRIBUTOR.md @@ -0,0 +1,23 @@ +十分感谢参与贡献过低代码引擎的小伙伴们,下面名单按字母排序: +- [albertxiao1994](https://github.com/albertxiao1994) +- [alex-mm](https://github.com/alex-mm) +- [alvarto](https://github.com/alvarto) +- [chenmingjia](https://github.com/chenmingjia) +- [Clarence-pan](https://github.com/Clarence-pan) +- [hujiulong](https://github.com/hujiulong) +- [hzd822](https://github.com/hzd822) +- [JackLian](https://github.com/JackLian) +- [jayjliang](https://github.com/jayjliang) +- [Jeffery-Young](https://github.com/Jeffery-Young) +- [jinggk](https://github.com/jinggk) +- [junlonghuo](https://github.com/junlonghuo) +- [leoyuan](https://github.com/leoyuan) +- [liujuping](https://github.com/liujuping) +- [lqy978599280](https://github.com/lqy978599280) +- [mark-ck](https://github.com/mark-ck) +- [mochen666](https://github.com/mochen666) +- [tsy77](https://github.com/tsy77) +- [Ychangqing](https://github.com/Ychangqing) +- [youluna](https://github.com/youluna) + +如果您贡献过低代码引擎,但是没有看到您的名字,为我们的疏忽感到抱歉。欢迎您通过 PR 补充上自己的名字。 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000..9b990cccb8 --- /dev/null +++ b/README.md @@ -0,0 +1,136 @@ +

+ + + +

+ +

LowCodeEngine

+ +
+ +一套面向扩展设计的企业级低代码技术体系 + +[![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url] + +[![Discussions][discussions-image]][discussions-url] [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url] + +[npm-image]: https://img.shields.io/npm/v/@alilc/lowcode-engine.svg?style=flat-square +[npm-url]: http://npmjs.org/package/@alilc/lowcode-engine + +[download-image]: https://img.shields.io/npm/dm/@alilc/lowcode-engine.svg?style=flat-square +[download-url]: https://npmjs.org/package/@alilc/lowcode-engine +[help-wanted-image]: https://flat.badgen.net/github/label-issues/alibaba/lowcode-engine/help%20wanted/open +[help-wanted-url]: https://github.com/alibaba/lowcode-engine/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22 +[discussions-image]: https://img.shields.io/badge/discussions-on%20github-blue?style=flat-square +[discussions-url]: https://github.com/alibaba/lowcode-engine/discussions + +[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square +[issues-helper-url]: https://github.com/actions-cool/issues-helper + +
+ +[![](https://img.alicdn.com/imgextra/i4/O1CN01GhzQuE1rnenyCCQTF_!!6000000005676-0-tps-2878-1588.jpg)](http://lowcode-engine.cn) + +## ✨ 特性 + +- 🌈 提炼自企业级低代码平台的面向扩展开发的内核引擎,奉行最小内核,最强生态的设计理念 +- 📦 开箱即用的高质量生态元素,包括 物料体系、设置器、插件 等 +- ⚙️ 完善的工具链,支持 物料体系、设置器、插件 等生态元素的全链路研发周期 +- 🔌 强大的扩展能力,已支撑近 100 个各种垂直类低代码平台 +- 🛡 使用 TypeScript 开发,提供完整的类型定义文件 + +## 🎯 兼容环境 + +- 现代浏览器(Chrome >= 80, Edge >= 80, last 2 safari versions, last 2 firefox versions) + +## 📚 引擎协议 + +引擎完整实现了《阿里巴巴中后台前端基础搭建协议规范》和《阿里巴巴中后台前端物料协议规范》,协议栈是低代码领域的物料能否流通的关键部分。 + +![image](https://user-images.githubusercontent.com/1195765/150266126-fef3e3a9-d6a4-4f8e-8592-745f1a344162.png) + +## 🌰 使用示例 + +```bash +npm install @alilc/lowcode-engine --save-dev +``` + +> **TIPS:仅支持 cdn 方式引入,npm 包用于提供 typings 等代码提示能力** + +```ts +import { init, skeleton } from '@alilc/lowcode-engine'; + +skeleton.add({ + area: 'topArea', + type: 'Widget', + name: 'logo', + content: YourFantaticLogo, + contentProps: { + logo: + 'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png', + href: '/', + }, + props: { + align: 'left', + width: 100, + }, +}); + +init(document.getElementById('lce')); +``` + +### 工程化配置: +```json +{ + "externals": { + "@alilc/lowcode-engine": "var window.AliLowCodeEngine", + "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt" + } +} +``` + +### cdn 可选方式: +#### 方式 1:unpkg +```html +https://unpkg.com/@alilc/lowcode-engine@1.0.0/dist/js/engine-core.js + +https://unpkg.com/@alilc/lowcode-react-simulator-renderer@1.0.0/dist/js/react-simulator-renderer.js +``` + +#### 方式 2:jsdelivr +```html +https://cdn.jsdelivr.net/npm/@alilc/lowcode-engine@1.0.0/dist/js/engine-core.js + +https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.0/dist/js/react-simulator-renderer.js +``` + +#### 方式 3:使用自有 cdn +将源码中 packages/engine/dist 和 packages/(react|rax)-simulator-renderer/dist 下的文件传至你的 cdn 提供商 + +## 🔗 链接 + +- [官网首页 WIP](http://lowcode-engine.cn/) +- [官方物料 WIP](http://lowcode-engine.cn/) +- [官方设置器(setter)WIP](http://lowcode-engine.cn/) +- [官方插件(plugin)WIP](http://lowcode-engine.cn/) +- [用户文档 WIP](http://lowcode-engine.cn/) +- [贡献指南 WIP](http://lowcode-engine.cn/) +- [更新日志](CHANGELOG..md) + +## 💻 本地调试 + +```bash +$ git clone git@github.com:alibaba/lowcode-engine.git +$ cd lowcode-engine +$ npm install +$ npm run setup +$ npm start +``` + +lowcode-engine 启动后,提供了几个 umd 文件,可以结合 [lowcode-demo](https://github.com/alibaba/lowcode-demo) 项目做调试,文件代理规则参考这里。 + +## 🤝 参与共建 + +请先阅读 [贡献指南 WIP](http://lowcode-engine.cn/docs/react/contributing-cn). + +> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393),更好的问题更容易获得帮助。 \ No newline at end of file diff --git a/abc.json b/abc.json new file mode 100644 index 0000000000..0d707e80a9 --- /dev/null +++ b/abc.json @@ -0,0 +1,11 @@ +{ + "name": "lowcode-engine", + "assets": { + "type": "command", + "command": { + "cmd": [ + "./scripts/deploy.sh $BUILD_DEST" + ] + } + } +} diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000000..52f3b754b8 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['ali'], +}; diff --git a/deploy-space/lerna.json b/deploy-space/lerna.json new file mode 100644 index 0000000000..31d37d2d38 --- /dev/null +++ b/deploy-space/lerna.json @@ -0,0 +1,9 @@ +{ + "version": "independent", + "npmClient": "yarn", + "registry": "http://registry.npm.alibaba-inc.com", + "useWorkspaces": true, + "packages": [ + "packages/*" + ] +} diff --git a/deploy-space/package.json b/deploy-space/package.json new file mode 100644 index 0000000000..37698f1dc2 --- /dev/null +++ b/deploy-space/package.json @@ -0,0 +1,16 @@ +{ + "private": true, + "workspaces": { + "packages": [ + "packages/*" + ], + "nohoist": [ + "**/css-modules-typescript-loader", + "**/@alife/theme-lowcode-*" + ] + }, + "dependencies": { + "tslib": "^1.11.1", + "typescript": "^3.8.3" + } +} diff --git a/deploy-space/static/index.html b/deploy-space/static/index.html new file mode 100644 index 0000000000..3b4cbddc29 --- /dev/null +++ b/deploy-space/static/index.html @@ -0,0 +1,79 @@ + + + + + + + LowCodeEngine Editor DEMO + + + + + + + + + + + + + + + + + +
+ + + + + + + + diff --git a/deploy-space/static/preview.html b/deploy-space/static/preview.html new file mode 100644 index 0000000000..1e79181e93 --- /dev/null +++ b/deploy-space/static/preview.html @@ -0,0 +1,83 @@ + + + + + + + LowCodeEngine Editor DEMO + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + diff --git a/deploy-space/tsconfig.json b/deploy-space/tsconfig.json new file mode 100644 index 0000000000..005c63fad7 --- /dev/null +++ b/deploy-space/tsconfig.json @@ -0,0 +1,40 @@ +{ + "compilerOptions": { + "declaration": false, + "lib": ["es2015", "dom"], + // Target latest version of ECMAScript. + "target": "esnext", + // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. + "module": "esnext", + // Search under node_modules for non-relative imports. + "moduleResolution": "node", + // Process & infer types from .js files. + "allowJs": true, + // Report errors in .js files. + "checkJs": false, + // Don't emit; allow Babel to transform files. + // "noEmit": true, + // Enable strictest settings like strictNullChecks & noImplicitAny. + "strict": false, + // Allow default imports from modules with no default export. This does not affect code emit, just typechecking. + "allowSyntheticDefaultImports": true, + // Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. + "esModuleInterop": true, + // Specify JSX code generation: 'preserve', 'react-native', or 'react'. + "jsx": "preserve", + // Import emit helpers (e.g. __extends, __rest, etc..) from tslib + "importHelpers": true, + // Enables experimental support for ES7 decorators. + "experimentalDecorators": true, + // Generates corresponding .map file. + "sourceMap": false, + // Disallow inconsistently-cased references to the same file. + "forceConsistentCasingInFileNames": true, + // Allow json import + "resolveJsonModule": true, + // skip type checking of declaration files + "skipLibCheck": true, + "outDir": "lib" + }, + "exclude": ["**/test", "**/lib", "**/es", "node_modules"] +} diff --git a/docs/code-specification.md b/docs/code-specification.md new file mode 100644 index 0000000000..0a7c9f5556 --- /dev/null +++ b/docs/code-specification.md @@ -0,0 +1,37 @@ +编码规约 +--- + +### 命名 + + - 使用 `PascalCase` 为类型命名 + - 使用 `I` 做为接口名前缀 + - 使用 `PascalCase` 为枚举值命名 + - 使用 `camelCase` 为函数命名 + - 使用 `camelCase` 为属性或本地变量命名 + - 不要为私有属性名添加 `_` 前缀 + - 尽可能使用完整的单词拼写命名 + - 文件夹/文件命名统一使用小写 `get-custom-data.ts` + +### 组件 + + - 一个文件对应一个组件或类 + +### 类型 + + - 不要随意导出类型/函数,除非你要在不同的组件中共享它 + - 不要在全局命名空间内定义类型/值 + - 共享的类型应该在 `types.ts` 里定义 + - 在一个文件里,类型定义应该出现在顶部 + - interface 和 type 很类似,原则上能用 interface 实现,就用 interface , 如果不能才用 type + +### 注释 + + - 为函数,接口,枚举类型和类使用 JSDoc 风格的注释 + +### 字符串 + + - 使用单引号 `''` + +### 单元测试 + + - 单元测试文件根据文件目录结构来放置 diff --git a/index.ts b/index.ts new file mode 100644 index 0000000000..362b5d8b66 --- /dev/null +++ b/index.ts @@ -0,0 +1,7 @@ +import renderer from './packages/react-simulator-renderer/src/renderer'; + +if (typeof window !== 'undefined') { + (window as any).SimulatorRenderer = renderer; +} + +export default renderer; diff --git a/lerna.json b/lerna.json new file mode 100644 index 0000000000..0ea13fe27f --- /dev/null +++ b/lerna.json @@ -0,0 +1,36 @@ +{ + "lerna": "4.0.0", + "version": "1.0.0", + "npmClient": "yarn", + "useWorkspaces": true, + "packages": [ + "packages/*" + ], + "command": { + "bootstrap": { + "npmClientArgs": [ + "--no-package-lock" + ] + }, + "version": { + "allowBranch": [ + "master", + "main", + "release/*", + "daily/*", + "refactor/*" + ] + }, + "publish": { + "npmClient": "npm", + "verifyRegistry": false, + "verifyAccess": false, + "ignoreChanges": [ + "**/*.md", + "**/test/**" + ], + "message": "chore(release): publish %v", + "conventionalCommits": true + } + } +} diff --git a/modules/code-generator/.gitignore b/modules/code-generator/.gitignore new file mode 100644 index 0000000000..b233ed9b31 --- /dev/null +++ b/modules/code-generator/.gitignore @@ -0,0 +1,113 @@ +# 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 diff --git a/modules/code-generator/.prettierrc.js b/modules/code-generator/.prettierrc.js new file mode 100644 index 0000000000..24c5859e6e --- /dev/null +++ b/modules/code-generator/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + printWidth: 100, + tabWidth: 2, + semi: true, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/modules/code-generator/CHANGELOG.md b/modules/code-generator/CHANGELOG.md new file mode 100644 index 0000000000..67b89d6763 --- /dev/null +++ b/modules/code-generator/CHANGELOG.md @@ -0,0 +1,105 @@ +# 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.0-beta.20](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/compare/@alilc/lowcode-code-generator@1.0.0-beta.19...@alilc/lowcode-code-generator@1.0.0-beta.20) (2022-02-14) + + +### Bug Fixes + +* 🐛 解决 standalone 入口的类型定义找不到的问题 ([ea735b0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/ea735b0422f26f4fdde4989478b308c22bae8f07)) + +## [1.0.0-beta.19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/compare/@alilc/lowcode-code-generator@1.0.0-beta.18...@alilc/lowcode-code-generator@1.0.0-beta.19) (2022-02-14) + + +### Bug Fixes + +* 🐛 补充自定义出码方案中缺失的示例插件文件 ([b583421](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/b5834214482ba73dc33753aed9e1166bca4b7374)) +* 🐛 解决 init-solution 命令生成的 demo-schema.json 格式非法的问题 ([b090732](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/b090732cb750aa60dfe9c7e34dd6709bfd537642)) + +## [1.0.0-beta.18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/compare/@alilc/lowcode-code-generator@1.0.0-beta.16...@alilc/lowcode-code-generator@1.0.0-beta.18) (2022-02-14) + + +### Features + +* 插件版本号校验 ([b22ae6a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/b22ae6a75065e0c4dfa290c7b8c4ec4c7e661b53)) +* 插件版本号校验,调整判断条件 ([2cf2182](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/2cf218245812825aa729657a9b1ac4b574d75cb5)) +* 增加 setKey / rerender 几个 API, shell node 单例化 ([e7999fa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/e7999faf78ec22395f218aab22e7accc18ad9b53)) +* add contributor list ([9368ea4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/9368ea46bd4b1eaae0848d51780d8a0896384875)) + + +### Bug Fixes + +* 🐛 解决通过命令行初始化自定义出码方案的时候报错的问题 ([ca6daff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/ca6daff89498056b0248e3996edfee75379881ac)) +* 🐛 解决通过命令行方式使用出码模块的时候报错的问题 ([da3f301](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/da3f3011d3ea34f59f0f3d6bd230fcfa436be103)) +* 处理遗留下来的 todo ([67c20a9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/67c20a993d44d6b2353eec6aab94636c1b2328b6)) +* 单测问题修复 ([b940fc2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/b940fc215737936267d2a3a202c7269695293060)) +* 调整 slot 默认关闭逻辑 ([0c0cd84](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/0c0cd8452cef94afc3afe025b9ce54a18274f5a4)) +* cr问题修复 ([a27f5aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/a27f5aaf73dd884051714a98d85644a9a0b6d69b)) + +## [1.0.0-beta.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/compare/@alilc/lowcode-code-generator@1.0.0-beta.16...@alilc/lowcode-code-generator@1.0.0-beta.17) (2022-02-14) + + +### Features + +* 插件版本号校验 ([b22ae6a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/b22ae6a75065e0c4dfa290c7b8c4ec4c7e661b53)) +* 插件版本号校验,调整判断条件 ([2cf2182](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/2cf218245812825aa729657a9b1ac4b574d75cb5)) +* 增加 setKey / rerender 几个 API, shell node 单例化 ([e7999fa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/e7999faf78ec22395f218aab22e7accc18ad9b53)) +* add contributor list ([9368ea4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/9368ea46bd4b1eaae0848d51780d8a0896384875)) + + +### Bug Fixes + +* 🐛 解决通过命令行初始化自定义出码方案的时候报错的问题 ([ca6daff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/ca6daff89498056b0248e3996edfee75379881ac)) +* 🐛 解决通过命令行方式使用出码模块的时候报错的问题 ([da3f301](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/da3f3011d3ea34f59f0f3d6bd230fcfa436be103)) +* 处理遗留下来的 todo ([67c20a9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/67c20a993d44d6b2353eec6aab94636c1b2328b6)) +* 单测问题修复 ([b940fc2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/b940fc215737936267d2a3a202c7269695293060)) +* 调整 slot 默认关闭逻辑 ([0c0cd84](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/0c0cd8452cef94afc3afe025b9ce54a18274f5a4)) +* cr问题修复 ([a27f5aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/a27f5aaf73dd884051714a98d85644a9a0b6d69b)) + +## [1.0.0-beta.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/compare/@alilc/lowcode-code-generator@1.0.0-beta.15...@alilc/lowcode-code-generator@1.0.0-beta.16) (2022-02-07) + + +### Features + +* 🎸 升级 @alilc/lowcode-types ([71f9c6c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/71f9c6c88f55f3e176e5bd40ddf4593a24ad3aea)) +* 补充 node#isEmpty ([e8229b8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/e8229b89dbdf1b93d529f2534ec9bf1fd25c2566)) +* 调整插件依赖配置位置 ([655b597](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/655b5976ac2a310bb679a06f418a154ccefd9d56)) +* 增加 setting-prop-entry#getDefaultValue ([3e43cd3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/3e43cd3af9c213b2b7694b6204b509850e786749)) +* 增设计模式作为是否使用循环判断的条件 & NotFoundComponent 组件新增 __componentName 属性 ([06f86de](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/06f86deef7bb88249c54731df9f2deb374443d21)) +* add preference declaration control to plugin ([2256156](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/22561563451dc565a2aea930d0679fe528520513)) + + +### Bug Fixes + +* 🐛 解决出码模块在 node 环境中使用时 zip publisher 不能正确识别为 node 环境的问题 ([ffa9908](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/ffa9908365fbe6fa5230c6f890cebf4fb44a7188)) +* 🐛 解决通过 npm 安装并测试的时候一堆报错问题 ([7245617](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/7245617da2bae55e67e4dff5eeda6c14981fdd4b)) +* 🐛 修正 icejs 模板中的 abc.json 的 builder ([e63cf7a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/e63cf7affb0bf7f072d965bda3c8dd90cf015e2d)) +* 根据新的插件 pluginName 修改代码 ([1faed05](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/1faed05dab26674b84ab0f065263b9ad9aeade46)) +* 兼容 arraysetter 场景 ([f462f3d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/f462f3de172d3d05db38234db982c58f5e6321ee)) +* 修复 getResizingHandlers 回调参数没有转换的问题 ([2e6c51d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/2e6c51d9cb0835791889656b3b9709a9a6cd630d)) + +## [1.0.0-beta.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/compare/@alilc/lowcode-code-generator@1.0.0-beta.14...@alilc/lowcode-code-generator@1.0.0-beta.15) (2022-01-19) + + +### Bug Fixes + +* 🐛 修正 standalone-worker 的默认地址 ([f477372](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/f477372f8c2432d6300b39b82e73cdfe4cf25f8d)) + +## 1.0.0-beta.14 (2022-01-19) + + +### Features + +* 补充 dragon 以及部分代码优化 ([595478a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/595478a7cb2d1288450920404bd79bf0b7fa4424)) +* 补充 setting-prop-entry#getPropValue 值 ([224acbf](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/224acbff2c8a949d4cda01f2371d6a7ba0b8df4d)) +* 补充几个 API 以及调整为 umd 导出 AliLowCodeEngine ([b56debc](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/b56debc9b7cb78a5a049291d9079292a32e85d20)) +* 出码模块支持 standalone 模式 ([f1fb35a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/f1fb35a1c39ebff3d1ddb28262ac556dbd249df3)) +* 第一版 readme ([db42cb5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/db42cb529a27f58a42cda4f9c33107f4d24abc23)) +* setting-prop-entry 增加一个 API ([6c1fdc3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/6c1fdc35828cdf0133846454c0a33708dc606d9a)) + + +### Bug Fixes + +* 修正命令行的位置 ([eb046c0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/eb046c0fd5983105e2d93fbc1c53b6b08935f66f)) +* less-variables ([15cccd6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine-2.x/commit/15cccd6892e375c7d83719aed416e3a320bcd931)) diff --git a/modules/code-generator/CONTRIBUTING.md b/modules/code-generator/CONTRIBUTING.md new file mode 100644 index 0000000000..c6af74bf71 --- /dev/null +++ b/modules/code-generator/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# 如何共建 + +1. 拉取最新代码,切换到 develop 分支,基于 develop 分支切出一个 feature 或 hotfix 分支 +2. 安装依赖(`npm`),然后先跑一遍 `npm test` 看看是否所有用例都能通过 (如果网络条件不太好,建议使用 [cnpm - 淘宝提供的中国 NPM 镜像](https://npmmirror.com/)) +3. 在 tests 目录下编写您的需求/问题的测试用例 +4. 修改 src 下的一些代码,然后运行 `npm test` 或 `npm start` 启动 jest 进行调测 +5. 确保所有的测试用例都能通过时,提 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 new file mode 100644 index 0000000000..be661559a3 --- /dev/null +++ b/modules/code-generator/README.md @@ -0,0 +1,113 @@ +# 出码 + +所谓出码,即将低代码编排出的 schema 进行解析并转换成最终可执行的代码的过程。本模块提供有 Icejs 和 Rax 两套框架的出码方案,并提供了强大而灵活的扩展机制。 + +## 使用方法 + +### 1) 通过命令行快速体验 + +欢迎使用命令行工具快速体验:`npx @alilc/lowcode-code-generator -i example-schema.json -o generated -s icejs` + +--其中 example-schema.json 可以从[这里下载](https://unpkg.com/@alilc/lowcode-code-generator@beta/example-schema.json) + +### 2) 通过设计器插件快速体验 + +1. 安装依赖: `npm install --save @alilc/lowcode-plugin-code-generator` +2. 注册插件: + +```ts +import { plugins } from '@alilc/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 @alilc/lowcode-code-generator` +2. 引入代码生成器: + +```js +import CodeGenerator from '@alilc/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 @alilc/lowcode-code-generator` +2. 引入代码生成器: + +```js +import * as CodeGenerator from '@alilc/lowcode-code-generator/standalone-loader'; +``` + +3. 【可选】提前初始化代码生成器: + +```js +// 提前初始化下,这样后面用的时候更快(这个 init 内部会提前准备好创建 worker 的一些资源) +await CodeGenerator.init(); +``` + +4. 出码 + +```js +const result = await CodeGenerator.generateCode({ + solution: 'icejs', // 出码方案 (目前内置有 icejs 和 rax ) + schema, // 编排搭建出来的 schema +}); + +console.log(result); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果) +``` + +注:一般来说在浏览器中出码适合做即时预览功能。 + +### 5)自定义出码 + +前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 欢迎参考 ./src/plugins/xxx 来编写您自己的出码插件,然后参考 ./src/solutions/xxx 将各种插件组合成一套适合您的业务场景的出码方案。 + +## 参与共建 + +欢迎参与共建,如何共建请参阅:[./CONTRIBUTING.md](https://code.aone.alibaba-inc.com/ali-lowcode/code-generator/blob/develop/CONTRIBUTING.md) diff --git a/modules/code-generator/bin/lowcode-code-generator.js b/modules/code-generator/bin/lowcode-code-generator.js new file mode 100755 index 0000000000..6259a5a6fc --- /dev/null +++ b/modules/code-generator/bin/lowcode-code-generator.js @@ -0,0 +1,51 @@ +#!/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) + .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 new file mode 100644 index 0000000000..bdcfd73990 --- /dev/null +++ b/modules/code-generator/example-schema.json @@ -0,0 +1,276 @@ +{ + "version": "1.0.0", + "componentsMap": [ + { + "componentName": "Button", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Button" + }, + { + "componentName": "Button.Group", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Button", + "subName": "Group" + }, + { + "componentName": "Input", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Input" + }, + { + "componentName": "Form", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Form" + }, + { + "componentName": "Form.Item", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Form", + "subName": "Item" + }, + { + "componentName": "NumberPicker", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "NumberPicker" + }, + { + "componentName": "Select", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Select" + } + ], + "componentsTree": [ + { + "componentName": "Page", + "id": "node$1", + "meta": { + "title": "测试", + "router": "/" + }, + "props": { + "ref": "outterView", + "autoLoading": true + }, + "fileName": "test", + "state": { + "text": "outter" + }, + "lifeCycles": { + "componentDidMount": { + "type": "JSExpression", + "value": "function() { console.log('componentDidMount'); }" + } + }, + "dataSource": { + "list": [ + { + "id": "urlParams", + "type": "urlParams" + }, + + { + "id": "user", + "type": "fetch", + "options": { + "method": "GET", + "uri": "https://shs.alibaba-inc.com/mock/1458/demo/user", + "isSync": true + }, + "dataHandler": { + "type": "JSExpression", + "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}" + } + }, + + { + "id": "orders", + "type": "fetch", + "options": { + "method": "GET", + "uri": "https://shs.alibaba-inc.com/mock/1458/demo/orders", + "isSync": true + }, + "dataHandler": { + "type": "JSExpression", + "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}" + } + } + ], + "dataHandler": { + "type": "JSExpression", + "value": "function (dataMap) {\n console.info(\"All datasources loaded:\", dataMap);\n}" + } + }, + "children": [ + { + "componentName": "Form", + "id": "node$2", + "props": { + "labelCol": { + "type": "JSExpression", + "value": "this.state.colNum" + }, + "style": {}, + "ref": "testForm" + }, + "children": [ + { + "componentName": "Form.Item", + "id": "node$3", + "props": { + "label": "姓名:", + "name": "name", + "initValue": "李雷" + }, + "children": [ + { + "componentName": "Input", + "id": "node$4", + "props": { + "placeholder": "请输入", + "size": "medium", + "style": { + "width": 320 + } + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node$5", + "props": { + "label": "年龄:", + "name": "age", + "initValue": "22" + }, + "children": [ + { + "componentName": "NumberPicker", + "id": "node$6", + "props": { + "size": "medium", + "type": "normal" + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node$7", + "props": { + "label": "职业:", + "name": "profession" + }, + "children": [ + { + "componentName": "Select", + "id": "node$8", + "props": { + "dataSource": [ + { + "label": "教师", + "value": "t" + }, + { + "label": "医生", + "value": "d" + }, + { + "label": "歌手", + "value": "s" + } + ] + } + } + ] + }, + { + "componentName": "Div", + "id": "node$9", + "props": { + "style": { + "textAlign": "center" + } + }, + "children": [ + { + "componentName": "Button.Group", + "id": "node$a", + "props": {}, + "children": [ + { + "componentName": "Button", + "id": "node$b", + "condition": { + "type": "JSExpression", + "value": "this.index >= 1" + }, + "loop": ["a", "b", "c"], + "props": { + "type": "primary", + "style": { + "margin": "0 5px 0 5px" + } + }, + "children": [ + { + "type": "JSExpression", + "value": "this.item" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "constants": { + "ENV": "prod", + "DOMAIN": "xxx.alibaba-inc.com" + }, + "css": "body {font-size: 12px;} .table { width: 100px;}", + "config": { + "sdkVersion": "1.0.3", + "historyMode": "hash", + "targetRootID": "J_Container", + "layout": { + "componentName": "BasicLayout", + "props": { + "logo": "...", + "name": "测试网站" + } + }, + "theme": { + "package": "@alife/theme-fusion", + "version": "^0.1.0", + "primary": "#ff9966" + } + }, + "meta": { + "name": "demo应用", + "git_group": "appGroup", + "project_name": "app_demo", + "description": "这是一个测试应用", + "spma": "spa23d", + "creator": "Test" + } +} diff --git a/modules/code-generator/example-schema.json5 b/modules/code-generator/example-schema.json5 new file mode 100644 index 0000000000..1c9e6641c5 --- /dev/null +++ b/modules/code-generator/example-schema.json5 @@ -0,0 +1,276 @@ +{ + version: '1.0.0', + componentsMap: [ + { + componentName: 'Button', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Button', + }, + { + componentName: 'Button.Group', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Button', + subName: 'Group', + }, + { + componentName: 'Input', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Input', + }, + { + componentName: 'Form', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Form', + }, + { + componentName: 'Form.Item', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Form', + subName: 'Item', + }, + { + componentName: 'NumberPicker', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'NumberPicker', + }, + { + componentName: 'Select', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Select', + }, + ], + componentsTree: [ + { + componentName: 'Page', + id: 'node$1', + meta: { + title: '测试', + router: '/', + }, + props: { + ref: 'outterView', + autoLoading: true, + }, + fileName: 'test', + state: { + text: 'outter', + }, + lifeCycles: { + componentDidMount: { + type: 'JSExpression', + value: "function() { console.log('componentDidMount'); }", + }, + }, + dataSource: { + list: [ + { + id: 'urlParams', + type: 'urlParams', + }, + + { + id: 'user', + type: 'fetch', + options: { + method: 'GET', + uri: 'https://shs.alibaba-inc.com/mock/1458/demo/user', + isSync: true, + }, + dataHandler: { + type: 'JSExpression', + value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}', + }, + }, + + { + id: 'orders', + type: 'fetch', + options: { + method: 'GET', + uri: 'https://shs.alibaba-inc.com/mock/1458/demo/orders', + isSync: true, + }, + dataHandler: { + type: 'JSExpression', + value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}', + }, + }, + ], + dataHandler: { + type: 'JSExpression', + value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}', + }, + }, + children: [ + { + componentName: 'Form', + id: 'node$2', + props: { + labelCol: { + type: 'JSExpression', + value: 'this.state.colNum', + }, + style: {}, + ref: 'testForm', + }, + children: [ + { + componentName: 'Form.Item', + id: 'node$3', + props: { + label: '姓名:', + name: 'name', + initValue: '李雷', + }, + children: [ + { + componentName: 'Input', + id: 'node$4', + props: { + placeholder: '请输入', + size: 'medium', + style: { + width: 320, + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node$5', + props: { + label: '年龄:', + name: 'age', + initValue: '22', + }, + children: [ + { + componentName: 'NumberPicker', + id: 'node$6', + props: { + size: 'medium', + type: 'normal', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node$7', + props: { + label: '职业:', + name: 'profession', + }, + children: [ + { + componentName: 'Select', + id: 'node$8', + props: { + dataSource: [ + { + label: '教师', + value: 't', + }, + { + label: '医生', + value: 'd', + }, + { + label: '歌手', + value: 's', + }, + ], + }, + }, + ], + }, + { + componentName: 'Div', + id: 'node$9', + props: { + style: { + textAlign: 'center', + }, + }, + children: [ + { + componentName: 'Button.Group', + id: 'node$a', + props: {}, + children: [ + { + componentName: 'Button', + id: 'node$b', + condition: { + type: 'JSExpression', + value: 'this.index >= 1', + }, + loop: ['a', 'b', 'c'], + props: { + type: 'primary', + style: { + margin: '0 5px 0 5px', + }, + }, + children: [ + { + type: 'JSExpression', + value: 'this.item', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + constants: { + ENV: 'prod', + DOMAIN: 'xxx.alibaba-inc.com', + }, + css: 'body {font-size: 12px;} .table { width: 100px;}', + config: { + sdkVersion: '1.0.3', + historyMode: 'hash', + targetRootID: 'J_Container', + layout: { + componentName: 'BasicLayout', + props: { + logo: '...', + name: '测试网站', + }, + }, + theme: { + package: '@alife/theme-fusion', + version: '^0.1.0', + primary: '#ff9966', + }, + }, + meta: { + name: 'demo应用', + git_group: 'appGroup', + project_name: 'app_demo', + description: '这是一个测试应用', + spma: 'spa23d', + creator: 'Test', + }, +} diff --git a/modules/code-generator/jest.config.js b/modules/code-generator/jest.config.js new file mode 100644 index 0000000000..0b213cd367 --- /dev/null +++ b/modules/code-generator/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + transformIgnorePatterns: ['/node_modules/(?!core-js)/'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], + collectCoverage: false, + collectCoverageFrom: ['src/**/*.{ts,tsx}', '!**/node_modules/**', '!**/vendor/**'], + testMatch: ['/tests/**/*.test.ts'], +}; diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json new file mode 100644 index 0000000000..e4d040c153 --- /dev/null +++ b/modules/code-generator/package.json @@ -0,0 +1,138 @@ +{ + "name": "@alilc/lowcode-code-generator", + "version": "1.0.0-beta.20", + "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 @alilc/lowcode-code-generator\\@ --prerelease beta && git push --follow-tags && npm publish --tag beta", + "release": "standard-version -t @alilc/lowcode-code-generator\\@ && 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" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged", + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" + } + }, + "lint-staged": { + "**/*.{js,jsx,ts,tsx}": "eslint" + }, + "dependencies": { + "@alilc/lowcode-types": "^1.0.0-beta.19", + "@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", + "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", + "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", + "tslib": "^2.3.1" + }, + "browser": { + "path": "path-browserify", + "lodash": "lodash-es", + "prettier": "prettier/standalone" + }, + "devDependencies": { + "@iceworks/spec": "^1.4.2", + "@types/babel__traverse": "^7.11.0", + "@types/jest": "^27.0.2", + "@types/lodash": "^4.14.162", + "@types/node": "^14.14.20", + "@types/prettier": "^2.4.2", + "@typescript-eslint/eslint-plugin": "^4.12.0", + "@typescript-eslint/parser": "^4.12.0", + "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": "^27.4.7", + "jest-util": "^27.4.2", + "rimraf": "^3.0.2", + "standard-version": "^9.1.1", + "ts-jest": "^27.1.3", + "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/" + } +} diff --git a/modules/code-generator/scripts/build-cli.js b/modules/code-generator/scripts/build-cli.js new file mode 100644 index 0000000000..394f87f6e9 --- /dev/null +++ b/modules/code-generator/scripts/build-cli.js @@ -0,0 +1,56 @@ +/* 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([ + // @alilc/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 new file mode 100644 index 0000000000..bee318dddb --- /dev/null +++ b/modules/code-generator/scripts/build-standalone-loader.js @@ -0,0 +1,73 @@ +/* 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 new file mode 100644 index 0000000000..c5f87395bc --- /dev/null +++ b/modules/code-generator/scripts/build-standalone-worker.js @@ -0,0 +1,107 @@ +/* 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: /./, + }, + // @alilc/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 new file mode 100644 index 0000000000..3b101f5ac0 --- /dev/null +++ b/modules/code-generator/scripts/build-standalone.js @@ -0,0 +1,135 @@ +/* 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: /./, + }, + // @alilc/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 new file mode 100644 index 0000000000..4daad4360d --- /dev/null +++ b/modules/code-generator/scripts/build-template-static-files.js @@ -0,0 +1,125 @@ +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/quotes */ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/* eslint-disable @typescript-eslint/no-require-imports */ +// @ts-check +// 这个文件是用来构建模板中的静态文件的 +const fs = require('fs'); +const glob = require('glob'); +const path = require('path'); +const JSON5 = require('json5'); +const { spawnSync } = require('child_process'); + +const PROJECT_ROOT = path.join(__dirname, '..'); + +const TEMPLATES = [ + { + sourceDir: path.join(PROJECT_ROOT, 'static-files/rax'), + outputDir: path.join(PROJECT_ROOT, 'src/plugins/project/framework/rax/template'), + }, +]; + +try { + TEMPLATES.forEach(buildTemplateStaticFiles); + console.log('All done.'); +} catch (e) { + console.error(e); + process.exit(1); +} + +function buildTemplateStaticFiles({ sourceDir, outputDir }) { + console.log('processing %s template...', path.dirname(sourceDir)); + + // 扫描所有的目录 + const sourceFiles = glob.sync('**/*', { + nodir: true, + dot: true, + cwd: sourceDir, + }); + + console.log('got %d files: %o', sourceFiles.length, sourceFiles); + + const staticFiles = { + imports: [], + runs: [], + }; + + // 生成对应的文件 + sourceFiles.forEach((sourceFileName, index) => { + console.log('processing %s', sourceFileName); + const sourceFileContent = fs.readFileSync(path.join(sourceDir, sourceFileName), 'utf-8'); + const sourceFileRealName = sourceFileName.replace(/\.template$/, ''); + const outputFileName = `${sourceFileRealName}.ts`; + const outputFileFullPath = path.join(outputDir, 'files', outputFileName); + + const sourceFileExtName = path.extname(sourceFileRealName); + const sourceFileBaseName = path.basename(sourceFileRealName, sourceFileExtName); + + // 确保目录存在 + fs.mkdirSync(path.dirname(outputFileFullPath), { recursive: true }); + + // 写入文件 + fs.writeFileSync( + outputFileFullPath, + [ + `/* eslint-disable max-len */`, + `/* Note: this file is generated by "npm run template", please dont modify this file directly */`, + `/* -- instead, you should modify "${path.relative( + PROJECT_ROOT, + path.join(sourceDir, sourceFileName), + )}" and run "npm run template" */`, + `import { ResultFile } from '@alilc/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 '@alilc/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 new file mode 100755 index 0000000000..61414063c6 --- /dev/null +++ b/modules/code-generator/scripts/build-types @@ -0,0 +1,10 @@ +#!/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 new file mode 100644 index 0000000000..841eacab55 --- /dev/null +++ b/modules/code-generator/scripts/build.js @@ -0,0 +1,75 @@ +/* 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 new file mode 100644 index 0000000000..736df9968f --- /dev/null +++ b/modules/code-generator/scripts/move-files-to-build-dest.js @@ -0,0 +1,24 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +const fs = require('fs'); +const { spawnSync } = require('child_process'); + +const BUILD_DEST = process.env.BUILD_DEST || '.package'; + +fs.mkdirSync(BUILD_DEST, { recursive: true }); + +const distFiles = [...require('../package.json').files, 'package.json']; + +distFiles.forEach((file) => { + console.log('mv %s', file); + if (file === BUILD_DEST) { + fs.mkdirSync(`${BUILD_DEST}/${file}`, { recursive: true }); + spawnSync('mv', [`${file}/*`, `${BUILD_DEST}/${file}/`], { shell: true, stdio: 'inherit' }); + } +}); + +distFiles.forEach((file) => { + console.log('mv %s', file); + if (file !== BUILD_DEST) { + spawnSync('mv', [file, `${BUILD_DEST}/${file}`], { shell: true, stdio: 'inherit' }); + } +}); diff --git a/modules/code-generator/scripts/test-standalone.js b/modules/code-generator/scripts/test-standalone.js new file mode 100644 index 0000000000..55d876d573 --- /dev/null +++ b/modules/code-generator/scripts/test-standalone.js @@ -0,0 +1,17 @@ +// 测试 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 new file mode 100644 index 0000000000..952295a15f --- /dev/null +++ b/modules/code-generator/src/analyzer/componentAnalyzer.ts @@ -0,0 +1,35 @@ +import type { NodeSchema, CompositeObject } from '@alilc/lowcode-types'; +import type { TComponentAnalyzer } from '../types'; + +import { handleSubNodes } from '../utils/schema'; + +export const componentAnalyzer: TComponentAnalyzer = (container) => { + let hasRefAttr = false; + const nodeValidator = (n: NodeSchema) => { + if (n.props) { + const props = n.props as CompositeObject; + if (props.ref) { + hasRefAttr = true; + } + } + }; + + nodeValidator(container); + + if (!hasRefAttr && container.children) { + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + handleSubNodes( + container.children, + { + node: nodeValidator, + }, + { + rerun: true, + }, + ); + } + + return { + isUsingRef: hasRefAttr, + }; +}; diff --git a/modules/code-generator/src/cli/index.ts b/modules/code-generator/src/cli/index.ts new file mode 100644 index 0000000000..bbada81cfd --- /dev/null +++ b/modules/code-generator/src/cli/index.ts @@ -0,0 +1,2 @@ +export * from './run'; +export * from './init-solution'; \ No newline at end of file diff --git a/modules/code-generator/src/cli/init-solution.ts b/modules/code-generator/src/cli/init-solution.ts new file mode 100644 index 0000000000..63ee66ea87 --- /dev/null +++ b/modules/code-generator/src/cli/init-solution.ts @@ -0,0 +1,65 @@ +/* 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 new file mode 100644 index 0000000000..0100abba73 --- /dev/null +++ b/modules/code-generator/src/cli/run.ts @@ -0,0 +1,133 @@ +/* eslint-disable no-console */ +import chalk from 'chalk'; +import * as fs from 'fs-extra'; +import JSON5 from 'json5'; +import { jsonc } from 'jsonc'; +import { spawnSync } from 'child_process'; +import * as path from 'path'; + +import { getErrorMessage } from '../utils/errors'; +import CodeGenerator from '..'; +import type { IProjectBuilder } from '..'; +import type { ProjectSchema } from '@alilc/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; + }, +): Promise { + try { + const schemaFile = options.input || args[0]; + if (!schemaFile) { + throw new Error( + 'a schema file must be specified by `--input ` or by the first positional argument', + ); + } + + if ((options.input && args.length > 0) || args.length > 1) { + throw new Error( + 'only one schema file can be specified, either by `--input ` or by the first positional argument', + ); + } + + // 读取 Schema + const schema = await loadSchemaFile(schemaFile); + + // 创建一个项目构建器 + const createProjectBuilder = await getProjectBuilderFactory(options.solution, { + quiet: options.quiet, + }); + const builder = createProjectBuilder(); + + // 生成代码 + const generatedSourceCodes = await builder.generateProject(schema); + + // 输出到磁盘 + const publisher = CodeGenerator.publishers.disk(); + + await publisher.publish({ + project: generatedSourceCodes, + outputPath: options.output || 'generated', + projectSlug: 'example', + createProjectFolder: false, + }); + return 0; + } catch (e) { + console.log(chalk.red(getErrorMessage(e) || `Unexpected error: ${e}`)); + 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<() => 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('tnpm', ['i', solutionPackageName], { + stdio: quiet ? 'ignore' : 'inherit', + }); + } + + // eslint-disable-next-line @typescript-eslint/no-require-imports + const solutionExports = require(!isLocalSolution(solution) + ? solutionPackageName + : `${path.isAbsolute(solution) ? solution : path.join(process.cwd(), solution)}`); + + const projectBuilderFactory = + solutionExports.createProjectBuilder || + solutionExports.createAppBuilder || + solutionExports.default; + + if (typeof projectBuilderFactory !== 'function') { + throw new Error( + `"${solutionPackageName}" should export project builder factory via named export 'createProjectBuilder' or via default export`, + ); + } + + return projectBuilderFactory; +} + +function isLocalSolution(solution: string) { + return solution.startsWith('.') || solution.startsWith('/') || solution.startsWith('~'); +} + +async function loadSchemaFile(schemaFile: string): Promise { + if (!schemaFile) { + throw new Error('invalid schema file name'); + } + + const schemaFileContent = await fs.readFile(schemaFile, 'utf8'); + + if (/\.json5/.test(schemaFile)) { + return JSON5.parse(schemaFileContent); + } + + // 默认用 JSONC 的格式解析(兼容 JSON) + return jsonc.parse(schemaFileContent); +} diff --git a/modules/code-generator/src/cli/solutions/example-solution.ts b/modules/code-generator/src/cli/solutions/example-solution.ts new file mode 100644 index 0000000000..40fc265dd2 --- /dev/null +++ b/modules/code-generator/src/cli/solutions/example-solution.ts @@ -0,0 +1,789 @@ +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": "JSExpression", + "value": "function() { console.log('componentDidMount'); }" + } + }, + "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.alibaba-inc.com/mock/1458/demo/user", + "isSync": true + }, + "dataHandler": { + "type": "JSExpression", + "value": "function (response) {\\nif (!response.data.success){\\n throw new Error(response.data.message);\\n }\\n return response.data.data;\\n}" + } + }, + + { + "id": "orders", + "type": "fetch", + "options": { + "method": "GET", + "uri": "https://shs.alibaba-inc.com/mock/1458/demo/orders", + "isSync": true + }, + "dataHandler": { + "type": "JSExpression", + "value": "function (response) {\\nif (!response.data.success){\\n throw new Error(response.data.message);\\n }\\n return response.data.data.result;\\n}" + } + } + ], + "dataHandler": { + "type": "JSExpression", + "value": "function (dataMap) {\\n console.info(\\"All datasources loaded:\\", dataMap);\\n}" + } + }, + "children": [ + { + "componentName": "Form", + "id": "node$2", + "props": { + "labelCol": { + "type": "JSExpression", + "value": "this.state.colNum" + }, + "style": {}, + "ref": "testForm" + }, + "children": [ + { + "componentName": "Form.Item", + "id": "node$3", + "props": { + "label": "姓名:", + "name": "name", + "initValue": "李雷" + }, + "children": [ + { + "componentName": "Input", + "id": "node$4", + "props": { + "placeholder": "请输入", + "size": "medium", + "style": { + "width": 320 + } + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node$5", + "props": { + "label": "年龄:", + "name": "age", + "initValue": "22" + }, + "children": [ + { + "componentName": "NumberPicker", + "id": "node$6", + "props": { + "size": "medium", + "type": "normal" + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node$7", + "props": { + "label": "职业:", + "name": "profession" + }, + "children": [ + { + "componentName": "Select", + "id": "node$8", + "props": { + "dataSource": [ + { + "label": "教师", + "value": "t" + }, + { + "label": "医生", + "value": "d" + }, + { + "label": "歌手", + "value": "s" + } + ] + } + } + ] + }, + { + "componentName": "Div", + "id": "node$9", + "props": { + "style": { + "textAlign": "center" + } + }, + "children": [ + { + "componentName": "Button.Group", + "id": "node$a", + "props": {}, + "children": [ + { + "componentName": "Button", + "id": "node$b", + "condition": { + "type": "JSExpression", + "value": "this.index >= 1" + }, + "loop": ["a", "b", "c"], + "props": { + "type": "primary", + "style": { + "margin": "0 5px 0 5px" + } + }, + "children": [ + { + "type": "JSExpression", + "value": "this.item" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "constants": { + "ENV": "prod", + "DOMAIN": "xxx.alibaba-inc.com" + }, + "css": "body {font-size: 12px;} .table { width: 100px;}", + "config": { + "sdkVersion": "1.0.3", + "historyMode": "hash", + "targetRootID": "J_Container", + "layout": { + "componentName": "BasicLayout", + "props": { + "logo": "...", + "name": "测试网站" + } + }, + "theme": { + "package": "@alife/theme-fusion", + "version": "^0.1.0", + "primary": "#ff9966" + } + }, + "meta": { + "name": "demo应用", + "git_group": "appGroup", + "project_name": "app_demo", + "description": "这是一个测试应用", + "spma": "spa23d", + "creator": "月飞" + } +} +`, + }, + { + 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 @alilc/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.alibaba-inc.com" + }, + "dependencies": { + "@alilc/lowcode-code-generator": "^1.0.0-beta.16", + "@alilc/lowcode-types": "^1.0.0-beta.21", + "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 '@alilc/lowcode-code-generator'; + +import examplePlugin from './plugins/example'; + +export default function createHelloWorldProjectBuilder() { + return CodeGen.createProjectBuilder({ + template: CodeGen.solutionParts.icejs.template, + plugins: { + components: [ + CodeGen.plugins.react.reactCommonDeps(), + CodeGen.plugins.common.esmodule({ fileType: 'jsx' }), + CodeGen.plugins.react.containerClass(), + CodeGen.plugins.react.containerInjectUtils(), + CodeGen.plugins.react.containerInjectDataSourceEngine(), + CodeGen.plugins.react.containerInjectI18n(), + CodeGen.plugins.react.containerInitState(), + CodeGen.plugins.react.containerLifeCycle(), + CodeGen.plugins.react.containerMethod(), + examplePlugin(), + CodeGen.plugins.react.jsx({ + nodeTypeMapping: { + Div: 'div', + Component: 'div', + Page: 'div', + Block: 'div', + }, + }), + CodeGen.plugins.style.css(), + ], + pages: [ + CodeGen.plugins.react.reactCommonDeps(), + CodeGen.plugins.common.esmodule({ fileType: 'jsx' }), + CodeGen.plugins.react.containerClass(), + CodeGen.plugins.react.containerInjectUtils(), + CodeGen.plugins.react.containerInjectDataSourceEngine(), + CodeGen.plugins.react.containerInjectI18n(), + CodeGen.plugins.react.containerInitState(), + CodeGen.plugins.react.containerLifeCycle(), + CodeGen.plugins.react.containerMethod(), + examplePlugin(), + CodeGen.plugins.react.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 '@alilc/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 new file mode 100644 index 0000000000..30d564c06e --- /dev/null +++ b/modules/code-generator/src/config/env.ts @@ -0,0 +1,3 @@ +import * as path from 'path'; + +export const CODE_GENERATOR_ROOT = path.join(__dirname, '../..'); diff --git a/modules/code-generator/src/const/file.ts b/modules/code-generator/src/const/file.ts new file mode 100644 index 0000000000..d29ea43a33 --- /dev/null +++ b/modules/code-generator/src/const/file.ts @@ -0,0 +1,3 @@ +import { FileType } from '../types/core'; + +export const FILE_TYPE_FAMILY = [[FileType.TSX, FileType.TS, FileType.JSX, FileType.JS]]; diff --git a/modules/code-generator/src/const/generator.ts b/modules/code-generator/src/const/generator.ts new file mode 100644 index 0000000000..1197458381 --- /dev/null +++ b/modules/code-generator/src/const/generator.ts @@ -0,0 +1,129 @@ +export const COMMON_CHUNK_NAME = { + ExternalDepsImport: 'CommonExternalDependencyImport', + InternalDepsImport: 'CommonInternalDependencyImport', + ImportAliasDefine: 'CommonImportAliasDefine', + FileVarDefine: 'CommonFileScopeVarDefine', + FileUtilDefine: 'CommonFileScopeMethodDefine', + FileMainContent: 'CommonFileMainContent', + FileExport: 'CommonFileExport', + StyleDepsImport: 'CommonStyleDepsImport', + StyleCssContent: 'CommonStyleCssContent', + HtmlContent: 'CommonHtmlContent', + CustomContent: 'CommonCustomContent', +}; + +export const CLASS_DEFINE_CHUNK_NAME = { + Start: 'CommonClassDefineStart', + ConstructorStart: 'CommonClassDefineConstructorStart', + ConstructorContent: 'CommonClassDefineConstructorContent', + ConstructorEnd: 'CommonClassDefineConstructorEnd', + StaticVar: 'CommonClassDefineStaticVar', + StaticMethod: 'CommonClassDefineStaticMethod', + InsVar: 'CommonClassDefineInsVar', + InsVarMethod: 'CommonClassDefineInsVarMethod', + InsMethod: 'CommonClassDefineInsMethod', + InsPrivateMethod: 'CommonClassDefineInsPrivateMethod', + End: 'CommonClassDefineEnd', +}; + +export const DEFAULT_LINK_AFTER = { + [COMMON_CHUNK_NAME.ExternalDepsImport]: [], + [COMMON_CHUNK_NAME.InternalDepsImport]: [COMMON_CHUNK_NAME.ExternalDepsImport], + [COMMON_CHUNK_NAME.ImportAliasDefine]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport, + ], + [COMMON_CHUNK_NAME.FileVarDefine]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + ], + [COMMON_CHUNK_NAME.FileUtilDefine]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + ], + [CLASS_DEFINE_CHUNK_NAME.Start]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + ], + [CLASS_DEFINE_CHUNK_NAME.ConstructorStart]: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.StaticVar, + CLASS_DEFINE_CHUNK_NAME.StaticMethod, + CLASS_DEFINE_CHUNK_NAME.InsVar, + CLASS_DEFINE_CHUNK_NAME.InsVarMethod, + ], + [CLASS_DEFINE_CHUNK_NAME.ConstructorContent]: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart], + [CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]: [ + CLASS_DEFINE_CHUNK_NAME.ConstructorStart, + CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + ], + [CLASS_DEFINE_CHUNK_NAME.StaticVar]: [CLASS_DEFINE_CHUNK_NAME.Start], + [CLASS_DEFINE_CHUNK_NAME.StaticMethod]: [ + CLASS_DEFINE_CHUNK_NAME.Start, CLASS_DEFINE_CHUNK_NAME.StaticVar, + ], + [CLASS_DEFINE_CHUNK_NAME.InsVar]: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.StaticVar, + CLASS_DEFINE_CHUNK_NAME.StaticMethod, + ], + [CLASS_DEFINE_CHUNK_NAME.InsVarMethod]: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.StaticVar, + CLASS_DEFINE_CHUNK_NAME.StaticMethod, + CLASS_DEFINE_CHUNK_NAME.InsVar, + ], + [CLASS_DEFINE_CHUNK_NAME.InsMethod]: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.StaticVar, + CLASS_DEFINE_CHUNK_NAME.StaticMethod, + CLASS_DEFINE_CHUNK_NAME.InsVar, + CLASS_DEFINE_CHUNK_NAME.InsVarMethod, + CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + ], + [CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod]: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.StaticVar, + CLASS_DEFINE_CHUNK_NAME.StaticMethod, + CLASS_DEFINE_CHUNK_NAME.InsVar, + CLASS_DEFINE_CHUNK_NAME.InsVarMethod, + CLASS_DEFINE_CHUNK_NAME.InsMethod, + CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + ], + [CLASS_DEFINE_CHUNK_NAME.End]: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.StaticVar, + CLASS_DEFINE_CHUNK_NAME.StaticMethod, + CLASS_DEFINE_CHUNK_NAME.InsVar, + CLASS_DEFINE_CHUNK_NAME.InsVarMethod, + CLASS_DEFINE_CHUNK_NAME.InsMethod, + CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + ], + [COMMON_CHUNK_NAME.FileMainContent]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + CLASS_DEFINE_CHUNK_NAME.End, + ], + [COMMON_CHUNK_NAME.FileExport]: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + CLASS_DEFINE_CHUNK_NAME.End, + COMMON_CHUNK_NAME.FileMainContent, + ], + [COMMON_CHUNK_NAME.StyleDepsImport]: [], + [COMMON_CHUNK_NAME.StyleCssContent]: [COMMON_CHUNK_NAME.StyleDepsImport], + [COMMON_CHUNK_NAME.HtmlContent]: [], +}; + +export const COMMON_SUB_MODULE_NAME = 'index'; diff --git a/modules/code-generator/src/const/index.ts b/modules/code-generator/src/const/index.ts new file mode 100644 index 0000000000..103d912db6 --- /dev/null +++ b/modules/code-generator/src/const/index.ts @@ -0,0 +1,12 @@ +export const NATIVE_ELE_PKG = 'native'; + +export const CONTAINER_TYPE = { + COMPONENT: 'Component', + BLOCK: 'Block', + PAGE: 'Page', +}; + +export const SUPPORT_SCHEMA_VERSION_LIST = ['0.0.1', '1.0.0']; + +export * from './file'; +export * from './generator'; diff --git a/modules/code-generator/src/core/jsx/handlers/transformJsExpression.ts b/modules/code-generator/src/core/jsx/handlers/transformJsExpression.ts new file mode 100644 index 0000000000..3bdb8fb5c1 --- /dev/null +++ b/modules/code-generator/src/core/jsx/handlers/transformJsExpression.ts @@ -0,0 +1,49 @@ +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 new file mode 100644 index 0000000000..fbb1c17cbc --- /dev/null +++ b/modules/code-generator/src/core/jsx/handlers/transformThis2Context.ts @@ -0,0 +1,29 @@ +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 new file mode 100644 index 0000000000..fe0c95a9d1 --- /dev/null +++ b/modules/code-generator/src/core/jsx/util/isLiteralAtomicExpr.ts @@ -0,0 +1,12 @@ +/** + * 判断是否是原子类型的表达式 + */ +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 new file mode 100644 index 0000000000..0b071527bd --- /dev/null +++ b/modules/code-generator/src/core/jsx/util/isSimpleStraightLiteral.ts @@ -0,0 +1,17 @@ +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 new file mode 100644 index 0000000000..6799d5940d --- /dev/null +++ b/modules/code-generator/src/generator/ChunkBuilder.ts @@ -0,0 +1,123 @@ +import { BuilderComponentPlugin, IChunkBuilder, ICodeChunk, ICodeStruct, FileType } from '../types'; + +import { COMMON_SUB_MODULE_NAME } from '../const/generator'; +import { FILE_TYPE_FAMILY } from '../const/file'; + +interface ChunkGroupInfo { + chunk: ICodeChunk; + familyIdx?: number; +} + +function whichFamily(type: FileType): [number, FileType[]] | undefined { + const idx = FILE_TYPE_FAMILY.findIndex((family) => family.indexOf(type) >= 0); + if (idx < 0) { + return undefined; + } + return [idx, FILE_TYPE_FAMILY[idx]]; +} + +export const groupChunks = (chunks: ICodeChunk[]): ICodeChunk[][] => { + const tmp: Record> = {}; + const col = chunks.reduce((chunksSet: Record, chunk) => { + const fileKey = chunk.subModule || COMMON_SUB_MODULE_NAME; + if (!chunksSet[fileKey]) { + // eslint-disable-next-line no-param-reassign + chunksSet[fileKey] = []; + } + const res = whichFamily(chunk.fileType as FileType); + const info: ChunkGroupInfo = { + chunk, + }; + if (res) { + const [familyIdx, family] = res; + const rank = family.indexOf(chunk.fileType as FileType); + if (tmp[fileKey]) { + if (tmp[fileKey][familyIdx] !== undefined) { + if (tmp[fileKey][familyIdx] > rank) { + tmp[fileKey][familyIdx] = rank; + } + } else { + tmp[fileKey][familyIdx] = rank; + } + } else { + tmp[fileKey] = {}; + tmp[fileKey][familyIdx] = rank; + } + info.familyIdx = familyIdx; + } + + chunksSet[fileKey].push(info); + return chunksSet; + }, {}); + + const result: ICodeChunk[][] = []; + Object.keys(col).forEach((key) => { + const byType: Record = {}; + col[key].forEach((info) => { + let t: string = info.chunk.fileType; + if (info.familyIdx !== undefined) { + t = FILE_TYPE_FAMILY[info.familyIdx][tmp[key][info.familyIdx]]; + // eslint-disable-next-line no-param-reassign + info.chunk.fileType = t; + } + if (!byType[t]) { + byType[t] = []; + } + byType[t].push(info.chunk); + }); + result.push(...Object.keys(byType).map((t) => byType[t])); + }); + + return result; +}; + +/** + * 代码片段构建器 + * + * @export + * @class ChunkBuilder + * @template T + */ +export class ChunkBuilder implements IChunkBuilder { + private plugins: BuilderComponentPlugin[]; + + constructor(plugins: BuilderComponentPlugin[] = []) { + this.plugins = plugins; + } + + async run( + ir: unknown, + initialStructure: ICodeStruct = { + ir, + chunks: [], + depNames: [], + contextData: {}, + }, + ) { + const structure = initialStructure; + + const finalStructure: ICodeStruct = await this.plugins.reduce( + async (previousPluginOperation: Promise, plugin) => { + const modifiedStructure = await previousPluginOperation; + return plugin(modifiedStructure); + }, + Promise.resolve(structure), + ); + + const chunks = groupChunks(finalStructure.chunks); + + return { + chunks, + }; + } + + getPlugins() { + return this.plugins; + } + + addPlugin(plugin: BuilderComponentPlugin) { + this.plugins.push(plugin); + } +} + +export default ChunkBuilder; diff --git a/modules/code-generator/src/generator/CodeBuilder.ts b/modules/code-generator/src/generator/CodeBuilder.ts new file mode 100644 index 0000000000..e633babbf5 --- /dev/null +++ b/modules/code-generator/src/generator/CodeBuilder.ts @@ -0,0 +1,103 @@ +import { + ChunkContent, + ChunkType, + CodeGeneratorError, + CodeGeneratorFunction, + ICodeBuilder, + ICodeChunk, +} from '../types'; + +export class CodeBuilder implements ICodeBuilder { + private chunkDefinitions: ICodeChunk[] = []; + + private generators: { [key: string]: CodeGeneratorFunction } = { + [ChunkType.STRING]: (str: string) => str, // no-op for string chunks + [ChunkType.JSON]: (json: Record) => JSON.stringify(json), // stringify json to string + }; + + constructor(chunkDefinitions: ICodeChunk[] = []) { + this.chunkDefinitions = chunkDefinitions; + } + + /** + * Links all chunks together based on their requirements. Returns an array + * of ordered chunk names which need to be compiled and glued together. + */ + link(chunkDefinitions: ICodeChunk[] = []): string { + const chunks = chunkDefinitions || this.chunkDefinitions; + if (chunks.length <= 0) { + return ''; + } + + const unprocessedChunks = chunks.map((chunk) => { + return { + name: chunk.name, + type: chunk.type, + content: chunk.content, + linkAfter: this.cleanupInvalidChunks(chunk.linkAfter, chunks), + }; + }); + + const resultingString: string[] = []; + + while (unprocessedChunks.length > 0) { + let indexToRemove = 0; + for (let index = 0; index < unprocessedChunks.length; index++) { + if (unprocessedChunks[index].linkAfter.length <= 0) { + indexToRemove = index; + break; + } + } + + if (unprocessedChunks[indexToRemove].linkAfter.length > 0) { + throw new CodeGeneratorError( + 'Operation aborted. Reason: cyclic dependency between chunks.', + ); + } + + const { type, content, name } = unprocessedChunks[indexToRemove]; + const compiledContent = this.generateByType(type, content); + if (compiledContent) { + resultingString.push(`${compiledContent}\n`); + } + + unprocessedChunks.splice(indexToRemove, 1); + if (!unprocessedChunks.some((ch) => ch.name === name)) { + unprocessedChunks.forEach( + // remove the processed chunk from all the linkAfter arrays from the remaining chunks + (ch) => { + // eslint-disable-next-line no-param-reassign + ch.linkAfter = ch.linkAfter.filter((after) => after !== name); + }, + ); + } + } + + return resultingString.join('\n'); + } + + generateByType(type: string, content: unknown): string { + if (!content) { + return ''; + } + if (Array.isArray(content)) { + return content.map((contentItem) => this.generateByType(type, contentItem)).join('\n'); + } + + if (!this.generators[type]) { + throw new Error( + `Attempted to generate unknown type ${type}. Please register a generator for this type in builder/index.ts`, + ); + } + + return this.generators[type](content); + } + + // remove invalid chunks (which did not end up being created) from the linkAfter fields + // one use-case is when you want to remove the import plugin + private cleanupInvalidChunks(linkAfter: string[], chunks: ICodeChunk[]) { + return linkAfter.filter((chunkName) => chunks.some((chunk) => chunk.name === chunkName)); + } +} + +export default CodeBuilder; diff --git a/modules/code-generator/src/generator/ModuleBuilder.ts b/modules/code-generator/src/generator/ModuleBuilder.ts new file mode 100644 index 0000000000..447e593b87 --- /dev/null +++ b/modules/code-generator/src/generator/ModuleBuilder.ts @@ -0,0 +1,109 @@ +import { ProjectSchema, ResultFile, ResultDir } from '@alilc/lowcode-types'; + +import { + BuilderComponentPlugin, + CodeGeneratorError, + ICodeChunk, + ICompiledModule, + IModuleBuilder, + IParseResult, + ISchemaParser, + PostProcessor, +} from '../types'; + +import { COMMON_SUB_MODULE_NAME } from '../const/generator'; + +import { SchemaParser } from '../parser/SchemaParser'; +import { ChunkBuilder } from './ChunkBuilder'; +import { CodeBuilder } from './CodeBuilder'; +import { createResultFile, createResultDir, addFile } from '../utils/resultHelper'; + +export function createModuleBuilder( + options: { + plugins: BuilderComponentPlugin[]; + postProcessors: PostProcessor[]; + mainFileName?: string; + } = { + plugins: [], + postProcessors: [], + }, +): IModuleBuilder { + const chunkGenerator = new ChunkBuilder(options.plugins); + const linker = new CodeBuilder(); + + const generateModule = async (input: unknown): Promise => { + const moduleMainName = options.mainFileName || COMMON_SUB_MODULE_NAME; + if (chunkGenerator.getPlugins().length <= 0) { + throw new CodeGeneratorError( + 'No plugins found. Component generation cannot work without any plugins!', + ); + } + + let files: ResultFile[] = []; + + const { chunks } = await chunkGenerator.run(input); + chunks.forEach((fileChunkList) => { + const content = linker.link(fileChunkList); + const file = createResultFile( + fileChunkList[0].subModule || moduleMainName, + fileChunkList[0].fileType, + content, + ); + files.push(file); + }); + + if (options.postProcessors.length > 0) { + files = files.map((file) => { + let { content } = file; + const type = file.ext; + options.postProcessors.forEach((processer) => { + content = processer(content, type); + }); + + return createResultFile(file.name, type, content); + }); + } + + return { + files, + }; + }; + + const generateModuleCode = async (schema: ProjectSchema | string): Promise => { + // Init + const schemaParser: ISchemaParser = new SchemaParser(); + const parseResult: IParseResult = schemaParser.parse(schema); + + const containerInfo = parseResult.containers[0]; + const { files } = await generateModule(containerInfo); + + const dir = createResultDir(containerInfo.moduleName); + files.forEach((file) => addFile(dir, file)); + + return dir; + }; + + const linkCodeChunks = (chunks: Record, fileName: string) => { + const files: ResultFile[] = []; + + Object.keys(chunks).forEach((fileKey) => { + const fileChunkList = chunks[fileKey]; + const content = linker.link(fileChunkList); + const file = createResultFile( + fileChunkList[0].subModule || fileName, + fileChunkList[0].fileType, + content, + ); + files.push(file); + }); + + return files; + }; + + return { + generateModule, + generateModuleCode, + linkCodeChunks, + addPlugin: chunkGenerator.addPlugin.bind(chunkGenerator), + }; +} diff --git a/modules/code-generator/src/generator/ProjectBuilder.ts b/modules/code-generator/src/generator/ProjectBuilder.ts new file mode 100644 index 0000000000..68cc8a30c8 --- /dev/null +++ b/modules/code-generator/src/generator/ProjectBuilder.ts @@ -0,0 +1,294 @@ +import { ResultDir, ResultFile, ProjectSchema } from '@alilc/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 } from '../types/core'; +import { CodeGeneratorError } from '../types/error'; + +interface IModuleInfo { + moduleName?: string; + path: string[]; + files: ResultFile[]; +} + +export interface ProjectBuilderInitOptions { + /** 项目模板 */ + template: IProjectTemplate; + /** 项目插件 */ + plugins: IProjectPlugins; + /** 模块后置处理器 */ + postProcessors: PostProcessor[]; + /** Schema 解析器 */ + schemaParser?: ISchemaParser; + /** 项目级别的前置处理器 */ + projectPreProcessors?: ProjectPreProcessor[]; + /** 项目级别的后置处理器 */ + projectPostProcessors?: ProjectPostProcessor[]; +} + +export class ProjectBuilder implements IProjectBuilder { + /** 项目模板 */ + private template: IProjectTemplate; + + /** 项目插件 */ + private plugins: IProjectPlugins; + + /** 模块后置处理器 */ + private postProcessors: PostProcessor[]; + + /** Schema 解析器 */ + private schemaParser: ISchemaParser; + + /** 项目级别的前置处理器 */ + private projectPreProcessors: ProjectPreProcessor[]; + + /** 项目级别的后置处理器 */ + private projectPostProcessors: ProjectPostProcessor[]; + + constructor({ + template, + plugins, + postProcessors, + schemaParser = new SchemaParser(), + projectPreProcessors = [], + projectPostProcessors = [], + }: ProjectBuilderInitOptions) { + this.template = template; + this.plugins = plugins; + this.postProcessors = postProcessors; + this.schemaParser = schemaParser; + this.projectPreProcessors = projectPreProcessors; + this.projectPostProcessors = projectPostProcessors; + } + + async generateProject(originalSchema: ProjectSchema | string): Promise { + // Init + const { schemaParser } = this; + const builders = this.createModuleBuilders(); + + const projectRoot = await this.template.generateTemplate(); + + let schema: ProjectSchema = + typeof originalSchema === 'string' ? JSON.parse(originalSchema) : originalSchema; + + // Validate + if (!schemaParser.validate(schema)) { + throw new CodeGeneratorError('Schema is invalid'); + } + + // Parse / Format + + // Preprocess + for (const preProcessor of this.projectPreProcessors) { + // eslint-disable-next-line no-await-in-loop + schema = await preProcessor(schema); + } + + // Collect Deps + // Parse JSExpression + const parseResult: IParseResult = schemaParser.parse(schema); + let buildResult: IModuleInfo[] = []; + + // Generator Code module + // components + // pages + const containerBuildResult: IModuleInfo[] = await Promise.all( + parseResult.containers.map(async (containerInfo) => { + let builder: IModuleBuilder; + let path: string[]; + if (containerInfo.containerType === 'Page') { + builder = builders.pages; + path = this.template.slots.pages.path; + } else { + builder = builders.components; + path = this.template.slots.components.path; + } + + const { files } = await builder.generateModule(containerInfo); + + return { + moduleName: containerInfo.moduleName, + path, + files, + }; + }), + ); + buildResult = buildResult.concat(containerBuildResult); + + // router + if (parseResult.globalRouter && builders.router) { + const { files } = await builders.router.generateModule(parseResult.globalRouter); + + buildResult.push({ + path: this.template.slots.router.path, + files, + }); + } + + // entry + if (parseResult.project && builders.entry) { + const { files } = await builders.entry.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.entry.path, + files, + }); + } + + // appConfig + if (builders.appConfig) { + const { files } = await builders.appConfig.generateModule(parseResult); + + buildResult.push({ + path: this.template.slots.appConfig.path, + files, + }); + } + + // buildConfig + if (builders.buildConfig) { + const { files } = await builders.buildConfig.generateModule(parseResult); + + buildResult.push({ + path: this.template.slots.buildConfig.path, + files, + }); + } + + // constants? + if (parseResult.project && builders.constants && this.template.slots.constants) { + const { files } = await builders.constants.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.constants.path, + files, + }); + } + + // utils? + if (parseResult.globalUtils && builders.utils && this.template.slots.utils) { + const { files } = await builders.utils.generateModule(parseResult.globalUtils); + + buildResult.push({ + path: this.template.slots.utils.path, + files, + }); + } + + // i18n? + if (builders.i18n && this.template.slots.i18n) { + const { files } = await builders.i18n.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.i18n.path, + files, + }); + } + + // globalStyle + if (parseResult.project && builders.globalStyle) { + const { files } = await builders.globalStyle.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.globalStyle.path, + files, + }); + } + + // htmlEntry + if (parseResult.project && builders.htmlEntry) { + const { files } = await builders.htmlEntry.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.htmlEntry.path, + files, + }); + } + + // packageJSON + if (parseResult.project && builders.packageJSON) { + const { files } = await builders.packageJSON.generateModule(parseResult.project); + + buildResult.push({ + path: this.template.slots.packageJSON.path, + files, + }); + } + + // TODO: 更多 slots 的处理??是不是可以考虑把 template 中所有的 slots 都处理下? + + // Post Process + + // Combine Modules + buildResult.forEach((moduleInfo) => { + let targetDir = getDirFromRoot(projectRoot, moduleInfo.path); + if (moduleInfo.moduleName) { + const dir = createResultDir(moduleInfo.moduleName); + addDirectory(targetDir, dir); + targetDir = dir; + } + moduleInfo.files.forEach((file) => addFile(targetDir, file)); + }); + + // post-processors + let finalResult = projectRoot; + for (const projectPostProcessor of this.projectPostProcessors) { + // eslint-disable-next-line no-await-in-loop + finalResult = await projectPostProcessor(finalResult, schema, originalSchema); + } + + return finalResult; + } + + private createModuleBuilders(): Record { + const builders: Record = {}; + + Object.keys(this.plugins).forEach((pluginName) => { + if (this.plugins[pluginName].length > 0) { + const options: { mainFileName?: string } = {}; + if (this.template.slots[pluginName] && this.template.slots[pluginName].fileName) { + options.mainFileName = this.template.slots[pluginName].fileName; + } + builders[pluginName] = createModuleBuilder({ + plugins: this.plugins[pluginName], + postProcessors: this.postProcessors, + ...options, + }); + } + }); + + return builders; + } +} + +export function createProjectBuilder(initOptions: ProjectBuilderInitOptions): IProjectBuilder { + return new ProjectBuilder(initOptions); +} + +function getDirFromRoot(root: ResultDir, path: string[]): ResultDir { + let current: ResultDir = root; + path.forEach((p) => { + const exist = current.dirs.find((d) => d.name === p); + if (exist) { + current = exist; + } else { + const newDir = createResultDir(p); + addDirectory(current, newDir); + current = newDir; + } + }); + + return current; +} diff --git a/modules/code-generator/src/index.ts b/modules/code-generator/src/index.ts new file mode 100644 index 0000000000..d928c4ffc7 --- /dev/null +++ b/modules/code-generator/src/index.ts @@ -0,0 +1,122 @@ +/** + * 低代码引擎的出码模块,负责将编排产出的 Schema 转换成实际可执行的代码。 + * 注意:为了保持 API 的稳定性, 这里所有导出的 API 均要显式命名方式导出 + * (即用 export { xxx } from 'xx' 的方式,不要直接 export * from 'xxx') + * 而且所有导出的 API 务必在 tests/public 中编写单元测试 + */ +import { createProjectBuilder } from './generator/ProjectBuilder'; +import { createModuleBuilder } from './generator/ModuleBuilder'; +import { createDiskPublisher } from './publisher/disk'; +import { createZipPublisher } from './publisher/zip'; +import createIceJsProjectBuilder, { plugins as reactPlugins } from './solutions/icejs'; +import createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app'; + +// 引入说明 +import { REACT_CHUNK_NAME } from './plugins/component/react/const'; +import { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from './const/generator'; + +// 引入通用插件组 +import esmodule from './plugins/common/esmodule'; +import requireUtils from './plugins/common/requireUtils'; + +import css from './plugins/component/style/css'; +import constants from './plugins/project/constants'; +import i18n from './plugins/project/i18n'; +import utils from './plugins/project/utils'; +import prettier from './postprocessor/prettier'; + +// 引入常用工具 +import * as utilsCommon from './utils/common'; +import * as utilsCompositeType from './utils/compositeType'; +import * as utilsJsExpression from './utils/jsExpression'; +import * as utilsJsSlot from './utils/jsSlot'; +import * as utilsNodeToJSX from './utils/nodeToJSX'; +import * as utilsResultHelper from './utils/resultHelper'; +import * as utilsTemplateHelper from './utils/templateHelper'; +import * as utilsValidate from './utils/validate'; +import * as utilsSchema from './utils/schema'; + +import * as CONSTANTS from './const'; + +// 引入内置解决方案模块 +import icejs from './plugins/project/framework/icejs'; +import rax from './plugins/project/framework/rax'; + +export default { + createProjectBuilder, + createModuleBuilder, + solutions: { + icejs: createIceJsProjectBuilder, + rax: createRaxAppProjectBuilder, + }, + solutionParts: { + icejs, + rax, + }, + publishers: { + disk: createDiskPublisher, + zip: createZipPublisher, + }, + plugins: { + common: { + /** + * 处理 ES Module + * @deprecated please use esModule + */ + esmodule, + esModule: esmodule, + requireUtils, + }, + react: { + ...reactPlugins, + }, + rax: { + ...raxPlugins, + }, + style: { + css, + }, + project: { + constants, + i18n, + utils, + }, + }, + postprocessor: { + prettier, + }, + utils: { + common: utilsCommon, + compositeType: utilsCompositeType, + jsExpression: utilsJsExpression, + jsSlot: utilsJsSlot, + nodeToJSX: utilsNodeToJSX, + resultHelper: utilsResultHelper, + templateHelper: utilsTemplateHelper, + validate: utilsValidate, + schema: utilsSchema, + }, + chunkNames: { + COMMON_CHUNK_NAME, + CLASS_DEFINE_CHUNK_NAME, + REACT_CHUNK_NAME, + }, + defaultLinkAfter: { + COMMON_DEFAULT_LINK_AFTER: DEFAULT_LINK_AFTER, + }, + constants: CONSTANTS, +}; + +// 一些类型定义 +export * from './types'; + +// 一些常量定义 +export * from './const'; + +// 一些工具函数 +export * from './analyzer/componentAnalyzer'; +export * from './parser/SchemaParser'; +export * from './generator/ChunkBuilder'; +export * from './generator/CodeBuilder'; +export * from './generator/ModuleBuilder'; +export * from './generator/ProjectBuilder'; diff --git a/modules/code-generator/src/parser/SchemaParser.ts b/modules/code-generator/src/parser/SchemaParser.ts new file mode 100644 index 0000000000..a8510e9b5f --- /dev/null +++ b/modules/code-generator/src/parser/SchemaParser.ts @@ -0,0 +1,355 @@ +/** + * 解析器是对输入的固定格式数据做拆解,使其符合引擎后续步骤预期,完成统一处理逻辑的步骤。 + * 本解析器面向的是标准 schema 协议。 + */ +import changeCase from 'change-case'; +import { + UtilItem, + NodeDataType, + NodeSchema, + ContainerSchema, + ProjectSchema, + PropsMap, + NodeData, + NpmInfo, +} from '@alilc/lowcode-types'; +import { + IPageMeta, + CodeGeneratorError, + CompatibilityError, + DependencyType, + IContainerInfo, + IDependency, + IExternalDependency, + IInternalDependency, + InternalDependencyType, + IParseResult, + ISchemaParser, + INpmPackage, + IRouterInfo, +} from '../types'; + +import { SUPPORT_SCHEMA_VERSION_LIST } from '../const'; + +import { getErrorMessage } from '../utils/errors'; +import { handleSubNodes } from '../utils/schema'; +import { uniqueArray } from '../utils/common'; +import { componentAnalyzer } from '../analyzer/componentAnalyzer'; +import { ensureValidClassName } from '../utils/validate'; + +const defaultContainer: IContainerInfo = { + containerType: 'Component', + componentName: 'Component', + moduleName: 'Index', + fileName: 'Index', + css: '', + props: {}, +}; + +function getRootComponentName(typeName: string, maps: Record): string { + if (maps[typeName]) { + const rec = maps[typeName]; + if (rec.destructuring) { + return rec.componentName || typeName; + } + + const peerName = Object.keys(maps).find((depName: string) => { + const depInfo = maps[depName]; + return ( + depName !== typeName && + !depInfo.destructuring && + depInfo.package === rec.package && + depInfo.version === rec.version && + depInfo.main === rec.main && + depInfo.exportName === rec.exportName && + depInfo.subName === rec.subName + ); + }); + + return peerName || typeName; + } + return typeName; +} + +function processChildren(schema: NodeSchema): void { + if (schema.props) { + if (Array.isArray(schema.props)) { + // FIXME: is array type props description + } else { + const nodeProps = schema.props as PropsMap; + if (nodeProps.children) { + if (!schema.children) { + // eslint-disable-next-line no-param-reassign + schema.children = nodeProps.children as NodeDataType; + } else { + let _children: NodeData[] = []; + + if (Array.isArray(schema.children)) { + _children = _children.concat(schema.children); + } else { + _children.push(schema.children); + } + + if (Array.isArray(nodeProps.children)) { + _children = _children.concat(nodeProps.children as NodeData[]); + } else { + _children.push(nodeProps.children as NodeData); + } + + // eslint-disable-next-line no-param-reassign + schema.children = _children; + } + delete nodeProps.children; + } + } + } +} + +export class SchemaParser implements ISchemaParser { + validate(schema: ProjectSchema): boolean { + if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) { + throw new CompatibilityError(`Not support schema with version [${schema.version}]`); + } + + return true; + } + + parse(schemaSrc: ProjectSchema | string): IParseResult { + // TODO: collect utils depends in JSExpression + const compDeps: Record = {}; + const internalDeps: Record = {}; + let utilsDeps: IExternalDependency[] = []; + + const schema = this.decodeSchema(schemaSrc); + + // 解析三方组件依赖 + schema.componentsMap.forEach((info) => { + if (info.componentName) { + compDeps[info.componentName] = { + ...info, + dependencyType: DependencyType.External, + componentName: info.componentName, + exportName: info.exportName ?? info.componentName, + version: info.version || '*', + destructuring: info.destructuring ?? false, + }; + } + }); + + let containers: IContainerInfo[]; + // Test if this is a lowcode component without container + if (schema.componentsTree.length > 0) { + const firstRoot: ContainerSchema = schema.componentsTree[0] as ContainerSchema; + + if (!('fileName' in firstRoot) || !firstRoot.fileName) { + // 整个 schema 描述一个容器,且无根节点定义 + const container: IContainerInfo = { + ...firstRoot, + ...defaultContainer, + props: firstRoot.props || defaultContainer.props, + css: firstRoot.css || defaultContainer.css, + moduleName: (firstRoot as IContainerInfo).moduleName || defaultContainer.moduleName, + children: schema.componentsTree as NodeSchema[], + }; + containers = [container]; + } else { + // 普通带 1 到多个容器的 schema + containers = schema.componentsTree.map((n) => { + const subRoot = n as ContainerSchema; + const container: IContainerInfo = { + ...subRoot, + componentName: getRootComponentName(subRoot.componentName, compDeps), + containerType: subRoot.componentName, + moduleName: ensureValidClassName(changeCase.pascalCase(subRoot.fileName)), + }; + return container; + }); + } + } else { + throw new CodeGeneratorError("Can't find anything to generate."); + } + + // 分析引用能力的依赖 + containers = containers.map((con) => ({ + ...con, + analyzeResult: componentAnalyzer(con as ContainerSchema), + })); + + // 建立所有容器的内部依赖索引 + containers.forEach((container) => { + let type; + switch (container.containerType) { + case 'Page': + type = InternalDependencyType.PAGE; + break; + case 'Block': + type = InternalDependencyType.BLOCK; + break; + default: + type = InternalDependencyType.COMPONENT; + break; + } + + const dep: IInternalDependency = { + type, + moduleName: container.moduleName, + destructuring: false, + exportName: container.moduleName, + dependencyType: DependencyType.Internal, + }; + + internalDeps[dep.moduleName] = dep; + }); + + const containersDeps = ([] as IDependency[]).concat(...containers.map((c) => c.deps || [])); + // TODO: 不应该在出码部分解决? + // 处理 children 写在了 props 里的情况 + containers.forEach((container) => { + if (container.children) { + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + handleSubNodes( + container.children, + { + node: (i: NodeSchema) => processChildren(i), + }, + { + rerun: true, + }, + ); + } + }); + + // 分析容器内部组件依赖 + containers.forEach((container) => { + const depNames = this.getComponentNames(container); + // eslint-disable-next-line no-param-reassign + container.deps = uniqueArray(depNames, (i: string) => i) + .map((depName) => internalDeps[depName] || compDeps[depName]) + .filter(Boolean); + // container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]); + }); + + // 分析路由配置 + const routes: IRouterInfo['routes'] = containers + .filter((container) => container.containerType === 'Page') + .map((page) => { + const { meta } = page; + if (meta) { + return { + path: (meta as IPageMeta).router || `/${page.fileName}`, // 如果无法找到页面路由信息,则用 fileName 做兜底 + fileName: page.fileName, + componentName: page.moduleName, + }; + } + + return { + path: '', + fileName: page.fileName, + componentName: page.moduleName, + }; + }); + + const routerDeps = routes + .map((r) => internalDeps[r.componentName] || compDeps[r.componentName]) + .filter((dep) => !!dep); + + // 分析 Utils 依赖 + let utils: UtilItem[]; + if (schema.utils) { + utils = schema.utils; + utilsDeps = schema.utils + .filter( + (u): u is { name: string; type: 'npm' | 'tnpm'; content: NpmInfo } => + u.type !== 'function', + ) + .map( + (u): IExternalDependency => ({ + ...u.content, + componentName: u.name, + version: u.content.version || '*', + destructuring: u.content.destructuring ?? false, + exportName: u.content.exportName ?? u.name, + }), + ); + } else { + utils = []; + } + + // 分析项目 npm 依赖 + let npms: INpmPackage[] = []; + containers.forEach((con) => { + const p = (con.deps || []) + .map((dep) => { + return dep.dependencyType === DependencyType.External ? dep : null; + }) + .filter((dep) => dep !== null); + const npmInfos: INpmPackage[] = p.filter(Boolean).map((i) => ({ + package: (i as IExternalDependency).package, + version: (i as IExternalDependency).version, + })); + npms.push(...npmInfos); + }); + + npms.push( + ...utilsDeps.map((utilsDep) => ({ + package: utilsDep.package, + version: utilsDep.version, + })), + ); + + npms = uniqueArray(npms, (i) => i.package).filter(Boolean); + + return { + containers, + globalUtils: { + utils, + deps: utilsDeps, + }, + globalI18n: schema.i18n, + globalRouter: { + routes, + deps: routerDeps, + }, + project: { + css: schema.css, + constants: schema.constants, + config: schema.config || {}, + meta: schema.meta || {}, + i18n: schema.i18n, + containersDeps, + utilsDeps, + packages: npms || [], + }, + }; + } + + getComponentNames(children: NodeDataType): string[] { + return handleSubNodes( + children, + { + node: (i: NodeSchema) => i.componentName, + }, + { + rerun: true, + }, + ); + } + + decodeSchema(schemaSrc: string | ProjectSchema): ProjectSchema { + let schema: ProjectSchema; + if (typeof schemaSrc === 'string') { + try { + schema = JSON.parse(schemaSrc); + } catch (error) { + throw new CodeGeneratorError( + `Parse schema failed: ${getErrorMessage(error) || 'unknown reason'}`, + ); + } + } else { + schema = schemaSrc; + } + return schema; + } +} + +export default SchemaParser; diff --git a/modules/code-generator/src/plugins/common/esmodule.ts b/modules/code-generator/src/plugins/common/esmodule.ts new file mode 100644 index 0000000000..3401d5eacc --- /dev/null +++ b/modules/code-generator/src/plugins/common/esmodule.ts @@ -0,0 +1,443 @@ +import { flatMap } 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 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: dep.exportName, + isDefault: !dep.destructuring, + subName: dep.subName || undefined, + nodeIdentifier: dep.componentName || undefined, + source: dep, + }; + + // 下面 5 个逻辑是清理不必要的冗余信息,做到数据结构归一化 + if (info.isDefault) { + if (defaultExportNames.indexOf(info.exportName) < 0) { + defaultExportNames.push(info.exportName); + } + } + + if (!info.subName) { + if (info.nodeIdentifier === info.exportName) { + info.nodeIdentifier = undefined; + } + + if (info.isDefault) { + info.aliasName = info.nodeIdentifier || info.exportName; + info.exportName = DEFAULT_EXPORT_NAME; + } + + if (info.nodeIdentifier) { + info.aliasName = info.nodeIdentifier; + info.nodeIdentifier = undefined; + } + } else { + if (info.isDefault) { + info.aliasName = info.exportName; + info.exportName = DEFAULT_EXPORT_NAME; + } + + if (info.nodeIdentifier === `${info.exportName}.${info.subName}`) { + info.nodeIdentifier = undefined; + } + } + + return info; + }); + + // 建立 export 项目的列表 + depsInfo.forEach((info) => { + if (!exportItems[info.exportName]) { + exportItems[info.exportName] = { + exportName: info.exportName, + isDefault: info.isDefault, + aliasNames: [], + needOriginExport: false, + }; + } + + if (!info.nodeIdentifier && !info.aliasName) { + exportItems[info.exportName].needOriginExport = true; + } + }); + + // 建立别名字典 + depsInfo.forEach((info) => { + if (info.aliasName) { + const { aliasNames } = exportItems[info.exportName]; + if (aliasNames.indexOf(info.aliasName) < 0) { + aliasNames.push(info.aliasName); + } + } + }); + + // fix: 父组件ImportAliasDefine, 与子组件import的父组件冲突情况 + depsInfo.forEach((info) => { + if (info.nodeIdentifier) { + const exportItem = exportItems[info.exportName]; + if (!exportItem.needOriginExport && exportItem.aliasNames.length > 0) { + // eslint-disable-next-line no-param-reassign + info.aliasName = exportItem.aliasNames[0]; + } + } + }); + + // 发现 nodeIdentifier 与 exportName 或者 aliasName 冲突的场景 + const nodeIdentifiers = depsInfo.map((info) => info.nodeIdentifier).filter(Boolean); + const conflictInfos = 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) { + let contentStatement = ''; + if (aliasDefineStatements[info.aliasName]) { + contentStatement = aliasDefineStatements[info.aliasName]; + delete aliasDefineStatements[info.aliasName]; + } + + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ImportAliasDefine, + content: contentStatement, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport], + ext: { + originalName: getDefaultExportName(info), + aliasName: info.aliasName, + dependency: info.source, + }, + }); + } + }); + + // 可能会剩余一些存在二次转换的定义 + Object.keys(aliasDefineStatements).forEach((a) => { + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ImportAliasDefine, + content: aliasDefineStatements[a], + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport, COMMON_CHUNK_NAME.InternalDepsImport], + }); + }); + + const exportItemList = Object.keys(exportItems).map((k) => exportItems[k]); + const defaultExport = exportItemList.filter((item) => item.isDefault); + const otherExports = exportItemList.filter((item) => !item.isDefault); + + const statementL = ['import']; + if (defaultExport.length > 0) { + if (useAliasName) { + statementL.push(defaultExportNames[0]); + } else { + statementL.push(defaultExport[0].aliasNames[0]); + } + if (otherExports.length > 0) { + statementL.push(', '); + } + } + if (otherExports.length > 0) { + const items = otherExports.map((item) => { + return !useAliasName || item.needOriginExport || item.aliasNames.length <= 0 + ? item.exportName + : `${item.exportName} as ${item.aliasNames[0]}`; + }); + statementL.push(`{ ${items.join(', ')} }`); + } + statementL.push('from'); + + const getInternalDependencyModuleId = () => `@/${(deps[0] as IInternalDependency).type}/${pkg}`; + + if (deps[0].dependencyType === DependencyType.Internal) { + // TODO: Internal Deps path use project slot setting + statementL.push(`'${getInternalDependencyModuleId()}';`); + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: statementL.join(' '), + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + } else { + statementL.push(`'${pkg}';`); + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: statementL.join(' '), + linkAfter: [], + }); + } + + // 处理下一些额外的 default 方式的导入 + if (defaultExportNames.length > 1) { + if (deps[0].dependencyType === DependencyType.Internal) { + defaultExportNames.slice(1).forEach((exportName) => { + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: `import ${exportName} from '${getInternalDependencyModuleId()}';`, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + }); + } else { + defaultExportNames.slice(1).forEach((exportName) => { + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: `import ${exportName} from '${pkg}';`, + linkAfter: [], + }); + + chunks.push({ + type: ChunkType.STRING, + fileType: targetFileType, + name: COMMON_CHUNK_NAME.ImportAliasDefine, + content: '', + linkAfter: [], + ext: { + aliasName: exportName, + originalName: exportName, + dependency: { + package: pkg, + componentName: exportName, + }, + }, + }); + }); + } + } + + return chunks; +} + +export interface PluginConfig { + fileType?: string; // 导出的文件类型 + useAliasName?: boolean; // 是否使用 componentName 重命名组件 identifier +} + +const pluginFactory: BuilderComponentPluginFactory = (config?: PluginConfig) => { + const cfg = { + fileType: FileType.JS, + useAliasName: true, + ...(config || {}), + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IWithDependency; + + if (ir && ir.deps && ir.deps.length > 0) { + const packs = groupDepsByPack(ir.deps); + + Object.keys(packs).forEach((pkg) => { + const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType, cfg.useAliasName); + next.chunks.push(...chunks); + }); + } + + return next; + }; + + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/common/requireUtils.ts b/modules/code-generator/src/plugins/common/requireUtils.ts new file mode 100644 index 0000000000..4dacf68e5a --- /dev/null +++ b/modules/code-generator/src/plugins/common/requireUtils.ts @@ -0,0 +1,25 @@ +import { COMMON_CHUNK_NAME } from '../../const/generator'; + +import { BuilderComponentPlugin, BuilderComponentPluginFactory, ChunkType, FileType, ICodeStruct } from '../../types'; + +// TODO: How to merge this logic to common deps +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: 'import * from \'react\';', + linkAfter: [], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/commonDeps.ts b/modules/code-generator/src/plugins/component/rax/commonDeps.ts new file mode 100644 index 0000000000..99285aad84 --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/commonDeps.ts @@ -0,0 +1,35 @@ +import { COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../types'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: ` + // 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 + // 例外:rax 框架的导出名和各种组件名除外。 + import { createElement, Component } from 'rax'; + import { getSearchParams as __$$getSearchParams } from 'rax-app'; + `, + linkAfter: [], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/const.ts b/modules/code-generator/src/plugins/component/rax/const.ts new file mode 100644 index 0000000000..a0a07b550c --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/const.ts @@ -0,0 +1,18 @@ +export const RAX_CHUNK_NAME = { + ClassDidMountBegin: 'RaxComponentClassDidMountBegin', + ClassDidMountContent: 'RaxComponentClassDidMountContent', + ClassDidMountEnd: 'RaxComponentClassDidMountEnd', + ClassWillUnmountBegin: 'RaxComponentClassWillUnmountBegin', + ClassWillUnmountContent: 'RaxComponentClassWillUnmountContent', + ClassWillUnmountEnd: 'RaxComponentClassWillUnmountEnd', + ClassRenderBegin: 'RaxComponentClassRenderBegin', + ClassRenderPre: 'RaxComponentClassRenderPre', + ClassRenderJSX: 'RaxComponentClassRenderJSX', + ClassRenderEnd: 'RaxComponentClassRenderEnd', + MethodsBegin: 'RaxComponentMethodsBegin', + MethodsContent: 'RaxComponentMethodsContent', + MethodsEnd: 'RaxComponentMethodsEnd', + LifeCyclesBegin: 'RaxComponentLifeCyclesBegin', + LifeCyclesContent: 'RaxComponentLifeCyclesContent', + LifeCyclesEnd: 'RaxComponentLifeCyclesEnd', +}; diff --git a/modules/code-generator/src/plugins/component/rax/containerClass.ts b/modules/code-generator/src/plugins/component/rax/containerClass.ts new file mode 100644 index 0000000000..6b90f4fffd --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/containerClass.ts @@ -0,0 +1,170 @@ +import changeCase from 'change-case'; +import { + COMMON_CHUNK_NAME, + CLASS_DEFINE_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; +import { RAX_CHUNK_NAME } from './const'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { ensureValidClassName } from '../../../utils/validate'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + // 将模块名转换成 PascalCase 的格式,并添加特定后缀,防止命名冲突 + const componentClassName = ensureValidClassName( + `${changeCase.pascalCase(ir.moduleName)}$$Page`, + ); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.Start, + content: `class ${componentClassName} extends Component {`, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.End, + content: '}', + linkAfter: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + RAX_CHUNK_NAME.ClassRenderEnd, + RAX_CHUNK_NAME.MethodsEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorStart, + content: 'constructor(props, context) { super(props); ', + linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + content: '} /* end of constructor */', + linkAfter: DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassDidMountBegin, + content: 'componentDidMount() {', + linkAfter: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.InsVar, + CLASS_DEFINE_CHUNK_NAME.InsMethod, + CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassDidMountEnd, + content: '} /* end of componentDidMount */', + linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin, RAX_CHUNK_NAME.ClassDidMountContent], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassWillUnmountBegin, + content: 'componentWillUnmount() {', + linkAfter: [ + CLASS_DEFINE_CHUNK_NAME.Start, + CLASS_DEFINE_CHUNK_NAME.InsVar, + CLASS_DEFINE_CHUNK_NAME.InsMethod, + RAX_CHUNK_NAME.ClassDidMountEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassWillUnmountEnd, + content: '} /* end of componentWillUnmount */', + linkAfter: [RAX_CHUNK_NAME.ClassWillUnmountBegin, RAX_CHUNK_NAME.ClassWillUnmountContent], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassRenderBegin, + content: 'render() {', + linkAfter: [RAX_CHUNK_NAME.ClassDidMountEnd, RAX_CHUNK_NAME.ClassWillUnmountEnd], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: RAX_CHUNK_NAME.ClassRenderEnd, + content: '} /* end of render */', + linkAfter: [ + RAX_CHUNK_NAME.ClassRenderBegin, + RAX_CHUNK_NAME.ClassRenderPre, + RAX_CHUNK_NAME.ClassRenderJSX, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + content: ` + _i18nText(t) { + const locale = this._context.getLocale(); + return t[locale] ?? t[String(locale).replace('-', '_')] ?? t[t.use || 'zh_CN'] ?? t.en_US; + } + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.FileExport, + content: `export default ${componentClassName};`, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + CLASS_DEFINE_CHUNK_NAME.End, + ], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/containerInitState.ts b/modules/code-generator/src/plugins/component/rax/containerInitState.ts new file mode 100644 index 0000000000..bf37881a2a --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/containerInitState.ts @@ -0,0 +1,66 @@ +import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import { Scope } from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; + implementType: 'inConstructor' | 'insMember' | 'hooks'; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + implementType: 'insMember', + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const scope = Scope.createRootScope(); + + const state = ir.state || {}; + const fields = Object.keys(state).map((stateName) => { + // TODO: 这里用什么 handlers? + const value = generateCompositeType(state[stateName], scope); + return `${JSON.stringify(stateName)}: ${value}`; + }); + + if (cfg.implementType === 'inConstructor') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: `this.state = { ${fields.join(',')} };`, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]], + }); + } else if (cfg.implementType === 'insMember') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: `state = { ${fields.join(',')} };`, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]], + }); + } + // TODO: hooks state?? + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/containerInjectContext.ts b/modules/code-generator/src/plugins/component/rax/containerInjectContext.ts new file mode 100644 index 0000000000..149339ec34 --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/containerInjectContext.ts @@ -0,0 +1,134 @@ +/* eslint-disable @typescript-eslint/indent */ +import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { RAX_CHUNK_NAME } from './const'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const useRef = !!ir.analyzeResult?.isUsingRef; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: "import __$$constants from '../../constants';", + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + // TODO: i18n 是可选的,如果没有 i18n 这个文件怎么办?该怎么判断? + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: "import * as __$$i18n from '../../i18n';", + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: ` + _context = this._createContext(); + `, + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + // TODO: 按照目前的实现方案,代码的插拔能力太弱了,需要有一些变化。 + // Step 1: 增加前置的分析器 + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + content: ` + _createContext() { + const self = this; + const context = { + get state() { + return self.state; + }, + setState(newState, callback) { + self.setState(newState, callback); + }, + get dataSourceMap() { + return self._dataSourceEngine.dataSourceMap || {}; + }, + async reloadDataSource() { + await self._dataSourceEngine.reloadDataSource(); + }, + get utils() { + return self._utils; + }, + get page() { + return context; + }, + get component() { + return context; + }, + get props() { + return self.props; + }, + get constants() { + return __$$constants; + }, + i18n: __$$i18n.i18n, + i18nFormat: __$$i18n.i18nFormat, + getLocale: __$$i18n.getLocale, + setLocale(locale) { + __$$i18n.setLocale(locale); + self.forceUpdate(); + },${ + useRef + ? ` + $(refName) { + return self._refsManager.get(refName); + }, + $$(refName) { + return self._refsManager.getAll(refName); + }, + get _refsManager() { + if (!self._refsManager) { + self._refsManager = new RefsManager(); + } + return self._refsManager; + }, + ` + : '' + } + ...this._methods, + }; + + return context; + } + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts b/modules/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts new file mode 100644 index 0000000000..47d654b903 --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts @@ -0,0 +1,188 @@ +/* eslint-disable @typescript-eslint/indent */ + +import { + CompositeValue, + JSExpression, + InterpretDataSourceConfig, + isJSExpression, + isJSFunction, +} from '@alilc/lowcode-types'; +import changeCase from 'change-case'; + +import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator'; +import { Scope } from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IScope, +} from '../../../types'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser'; +import { isContainerSchema } from '../../../utils/schema'; +import { RaxFrameworkOptions } from '../../project/framework/rax/types/RaxFrameworkOptions'; +import { RAX_CHUNK_NAME } from './const'; + +export interface PluginConfig extends RaxFrameworkOptions { + fileType?: string; + dataSourceHandlersPackageMap?: Record; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + dataSourceHandlersPackageMap: + config?.dataSourceHandlersPackageMap || config?.datasourceConfig?.handlersPackages, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const scope = Scope.createRootScope(); + const dataSourceConfig = isContainerSchema(pre.ir) ? pre.ir.dataSource : null; + const dataSourceItems: InterpretDataSourceConfig[] = + (dataSourceConfig && dataSourceConfig.list) || []; + const dataSourceEngineOptions = { runtimeConfig: true }; + if (dataSourceItems.length > 0) { + const requestHandlersMap: Record = {}; + + dataSourceItems.forEach((ds) => { + const dsType = ds.type || 'fetch'; + if (!(dsType in requestHandlersMap) && dsType !== 'custom') { + const handlerFactoryName = `__$$create${changeCase.pascal(dsType)}RequestHandler`; + + requestHandlersMap[dsType] = { + type: 'JSExpression', + value: `${handlerFactoryName}(${ + dsType === 'urlParams' ? '__$$getSearchParams()' : '' + })`, + }; + + const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`; + const handlerPkgName = + cfg.dataSourceHandlersPackageMap?.[dsType] || + `@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: CompositeValue, scope: IScope): CompositeValue { + if (isJSExpression(value) || isJSFunction(value)) { + return { + type: 'JSExpression', + value: `function(){ return ((${value.value}))}`, + }; + } + + return { + type: 'JSExpression', + value: `function(){return((${generateCompositeType(value, scope)}))}`, + }; +} diff --git a/modules/code-generator/src/plugins/component/rax/containerInjectUtils.ts b/modules/code-generator/src/plugins/component/rax/containerInjectUtils.ts new file mode 100644 index 0000000000..32d3f4bb02 --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/containerInjectUtils.ts @@ -0,0 +1,69 @@ +import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { RAX_CHUNK_NAME } from './const'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const useRef = !!ir.analyzeResult?.isUsingRef; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + // TODO: 下面这个路径有没有更好的方式来获取?而非写死 + content: ` + import __$$projectUtils${useRef ? ', { RefsManager }' : ''} from '../../utils'; + `, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: '_utils = this._defineUtils();', + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + + content: ` + _defineUtils() { + return { + ...__$$projectUtils, + }; + }`, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts b/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts new file mode 100644 index 0000000000..f928c3995e --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts @@ -0,0 +1,144 @@ +import _ from 'lodash'; +import { isJSExpression, isJSFunction } from '@alilc/lowcode-types'; + +import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator'; +import { RAX_CHUNK_NAME } from './const'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + FileType, + ChunkType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { debug } from '../../../utils/debug'; + +export interface PluginConfig { + fileType: string; + exportNameMapping: Record; + normalizeNameMapping: Record; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + exportNameMapping: {}, + normalizeNameMapping: { + didMount: 'componentDidMount', + willUnmount: 'componentWillUnmount', + }, + ...config, + }; + + const exportNameMapping = new Map(Object.entries(cfg.exportNameMapping)); + const normalizeNameMapping = new Map(Object.entries(cfg.normalizeNameMapping)); + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + // Rax 先只支持 didMount 和 willUnmount 吧 + + const ir = next.ir as IContainerInfo; + const { lifeCycles } = ir; + + if (lifeCycles && !_.isEmpty(lifeCycles)) { + Object.entries(lifeCycles).forEach(([lifeCycleName, lifeCycleMethodExpr]) => { + // 过滤掉非法数据(有些场景下会误传入空字符串或 null) + if ( + !isJSFunction(lifeCycles[lifeCycleName]) && + !isJSExpression(lifeCycles[lifeCycleName]) + ) { + return; + } + + const normalizeName = normalizeNameMapping.get(lifeCycleName) || lifeCycleName; + const exportName = exportNameMapping.get(lifeCycleName) || lifeCycleName; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.LifeCyclesContent, + content: `${exportName}: (${lifeCycleMethodExpr.value}),`, + linkAfter: [RAX_CHUNK_NAME.LifeCyclesBegin], + }); + + if (normalizeName === 'constructor') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: `this._lifeCycles.${exportName}();`, + linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart], + }); + } else if (normalizeName === 'componentDidMount') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassDidMountContent, + content: `this._lifeCycles.${exportName}();`, + linkAfter: [RAX_CHUNK_NAME.ClassDidMountBegin], + }); + } else if (normalizeName === 'componentWillUnmount') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassWillUnmountContent, + content: `this._lifeCycles.${exportName}();`, + linkAfter: [RAX_CHUNK_NAME.ClassWillUnmountBegin], + }); + } else { + debug(`[CodeGen]: unknown life cycle: ${lifeCycleName}`); + } + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: '_lifeCycles = this._defineLifeCycles();', + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.LifeCyclesBegin, + content: ` + _defineLifeCycles() { + const __$$lifeCycles = ({ + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd, CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.LifeCyclesEnd, + content: ` + }); + + // 为所有的方法绑定上下文 + Object.entries(__$$lifeCycles).forEach(([lifeCycleName, lifeCycleMethod]) => { + if (typeof lifeCycleMethod === 'function') { + __$$lifeCycles[lifeCycleName] = (...args) => { + return lifeCycleMethod.apply(this._context, args); + } + } + }); + + return __$$lifeCycles; + } + `, + linkAfter: [RAX_CHUNK_NAME.LifeCyclesBegin, RAX_CHUNK_NAME.LifeCyclesContent], + }); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/containerMethods.ts b/modules/code-generator/src/plugins/component/rax/containerMethods.ts new file mode 100644 index 0000000000..6e23dc090f --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/containerMethods.ts @@ -0,0 +1,84 @@ +import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +import { RAX_CHUNK_NAME } from './const'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: ` + _methods = this._defineMethods(); + `, + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.MethodsBegin, + content: ` + _defineMethods() { + return ({ + `, + linkAfter: [ + RAX_CHUNK_NAME.ClassRenderEnd, + CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod, + RAX_CHUNK_NAME.LifeCyclesEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.MethodsEnd, + content: ` + }); + } + `, + linkAfter: [RAX_CHUNK_NAME.MethodsBegin, RAX_CHUNK_NAME.MethodsContent], + }); + + if (ir.methods && Object.keys(ir.methods).length > 0) { + Object.entries(ir.methods).forEach(([methodName, methodDefine]) => { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.MethodsContent, + content: `${methodName}: (${methodDefine.value}),`, + linkAfter: [RAX_CHUNK_NAME.MethodsBegin], + }); + }); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/rax/jsx.ts b/modules/code-generator/src/plugins/component/rax/jsx.ts new file mode 100644 index 0000000000..32faded5c8 --- /dev/null +++ b/modules/code-generator/src/plugins/component/rax/jsx.ts @@ -0,0 +1,319 @@ +import { + NodeSchema, + JSExpression, + NpmInfo, + CompositeValue, + isJSExpression, +} from '@alilc/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(); + + // Rax 构建到小程序的时候,不能给组件起起别名,得直接引用,故这里将所有的别名替换掉 + // 先收集下所有的 alias 的映射 + const componentsNameAliasMap = new Map(); + next.chunks.forEach((chunk) => { + if (isImportAliasDefineChunk(chunk)) { + componentsNameAliasMap.set(chunk.ext.aliasName, chunk.ext.originalName); + } + }); + + // 注意:这里其实隐含了一个假设:schema 中的 componentName 应该是一个有效的 JS 标识符,而且是大写字母打头的 + // FIXME: 为了快速修复临时加的逻辑,需要用 pre-process 的方式替代处理。 + const mapComponentNameToAliasOrKeepIt = (componentName: string) => + componentsNameAliasMap.get(componentName) || componentName; + + // 然后过滤掉所有的别名 chunks + next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk)); + + // 如果直接按目前的 React 的方式之间出码 JSX 的话,会有 3 个问题: + // 1. 小程序出码的时候,循环变量没法拿到 + // 2. 小程序出码的时候,很容易出现 Uncaught TypeError: Cannot read property 'avatar' of undefined 这样的异常(如下图的 50 行) -- 因为若直接出码,Rax 构建到小程序的时候会立即计算所有在视图中用到的变量 + // 3. 通过 this.xxx 能拿到的东西太多了,而且自定义的 methods 可能会无意间破坏 Rax 框架或小程序框架在页面 this 上的东东 + const customHandlers: HandlerSet = { + expression(input: JSExpression, scope: IScope) { + return transformJsExpr(generateExpression(input, scope), scope); + }, + function(input, scope: IScope) { + return transformThis2Context(input.value || 'null', scope); + }, + }; + + // 创建代码生成器 + const commonNodeGenerator = createNodeGenerator({ + handlers: customHandlers, + tagMapping: mapComponentNameToAliasOrKeepIt, + nodePlugins: [generateReactExprInJS, generateConditionReactCtrl, generateRaxLoopCtrl], + attrPlugins: [generateNodeAttrForRax.bind({ cfg })], + }); + + // 生成 JSX 代码 + const jsxContent = commonNodeGenerator(ir, rootScope); + + if (!cfg.ignoreMiniApp) { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: "import { isMiniApp as __$$isMiniApp } from 'universal-env';", + linkAfter: [], + }); + } + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassRenderPre, + // TODO: setState, dataSourceMap, reloadDataSource, utils, i18n, i18nFormat, getLocale, setLocale 这些在 Rax 的编译模式下不能在视图中直接访问,需要转化成 this.xxx + content: ` + const __$$context = this._context; + const { state, setState, dataSourceMap, reloadDataSource, utils, constants, i18n, i18nFormat, getLocale, setLocale } = __$$context; + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassRenderJSX, + content: `return ${jsxContent};`, + linkAfter: [RAX_CHUNK_NAME.ClassRenderBegin, RAX_CHUNK_NAME.ClassRenderPre], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.CustomContent, + content: ` + + function __$$eval(expr) { + try { + return expr(); + } catch (err) { + try { + if (window.handleEvalError) { + window.handleEvalError('Failed to evaluate: ', expr, err); + } + } catch (e) {} + } + } + + function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; + } + + function __$$createChildContext(oldContext, ext) { + return Object.assign({}, oldContext, ext); + } + + `, + linkAfter: [COMMON_CHUNK_NAME.FileExport], + }); + + return next; + }; + + return plugin; +}; + +export default pluginFactory; + +function isImportAliasDefineChunk(chunk: ICodeChunk): chunk is ICodeChunk & { + ext: { + aliasName: string; + originalName: string; + dependency: NpmInfo; + }; +} { + return ( + chunk.name === COMMON_CHUNK_NAME.ImportAliasDefine && + !!chunk.ext && + typeof chunk.ext.aliasName === 'string' && + typeof chunk.ext.originalName === 'string' && + !!(chunk.ext.dependency as NpmInfo | null)?.componentName + ); +} + +function generateRaxLoopCtrl( + nodeItem: NodeSchema, + scope: IScope, + config?: NodeGeneratorConfig, + next?: NodePlugin, +): CodePiece[] { + if (nodeItem.loop) { + const loopItemName = nodeItem.loopArgs?.[0] || 'item'; + const loopIndexName = nodeItem.loopArgs?.[1] || 'index'; + const subScope = scope.createSubScope([loopItemName, loopIndexName]); + const pieces: CodePiece[] = next ? next(nodeItem, subScope, config) : []; + + const loopDataExpr = `__$$evalArray(() => (${transformThis2Context( + generateCompositeType(nodeItem.loop, scope, { handlers: config?.handlers }), + scope, + )}))`; + + pieces.unshift({ + value: `${loopDataExpr}.map((${loopItemName}, ${loopIndexName}) => ((__$$context) => (`, + type: PIECE_TYPE.BEFORE, + }); + + pieces.push({ + value: `))(__$$createChildContext(__$$context, { ${loopItemName}, ${loopIndexName} })))`, + type: PIECE_TYPE.AFTER, + }); + + return pieces; + } + + return next ? next(nodeItem, scope, config) : []; +} + +function generateNodeAttrForRax( + this: { cfg: PluginConfig }, + attrData: { attrName: string; attrValue: CompositeValue }, + scope: IScope, + config?: NodeGeneratorConfig, + next?: AttrPlugin, +): CodePiece[] { + if (!this.cfg.ignoreMiniApp && /^on/.test(attrData.attrName)) { + // else: onXxx 的都是事件处理函数需要特殊处理下 + return generateEventHandlerAttrForRax(attrData.attrName, attrData.attrValue, scope, config); + } + + if (attrData.attrName === 'ref') { + return [ + { + name: attrData.attrName, + value: `__$$context._refsManager.linkRef('${attrData.attrValue}')`, + type: PIECE_TYPE.ATTR, + }, + ]; + } + + return next ? next(attrData, scope, config) : []; +} + +function generateEventHandlerAttrForRax( + attrName: string, + attrValue: CompositeValue, + scope: IScope, + config?: NodeGeneratorConfig, +): CodePiece[] { + // -- 事件处理函数中 JSExpression 转成 JSFunction 来处理,避免当 JSExpression 处理的时候多包一层 eval 而导致 Rax 转码成小程序的时候出问题 + const valueExpr = generateCompositeType( + isJSExpression(attrValue) ? { type: 'JSFunction', value: attrValue.value } : attrValue, + scope, + { + handlers: config?.handlers, + }, + ); + + // 查询当前作用域下的变量 + const currentScopeVariables = scope.bindings?.getAllBindings() || []; + if (currentScopeVariables.length <= 0) { + return [ + { + type: PIECE_TYPE.ATTR, + name: attrName, + value: valueExpr, + }, + ]; + } + + // 提取出所有的未定义的全局变量 + const undeclaredVariablesInValueExpr = parseExpressionGetGlobalVariables(valueExpr); + const referencedLocalVariables = _.intersection( + undeclaredVariablesInValueExpr, + currentScopeVariables, + ); + if (referencedLocalVariables.length <= 0) { + return [ + { + type: PIECE_TYPE.ATTR, + name: attrName, + value: valueExpr, + }, + ]; + } + + const wrappedAttrValueExpr = [ + '(...__$$args) => {', + ' if (__$$isMiniApp) {', + ' const __$$event = __$$args[0];', + ...referencedLocalVariables.map( + (localVar) => `const ${localVar} = __$$event.target.dataset.${localVar};`, + ), + ` return (${valueExpr}).apply(this, __$$args);`, + ' } else {', + ` return (${valueExpr}).apply(this, __$$args);`, + ' }', + '}', + ].join('\n'); + + return [ + ...referencedLocalVariables.map((localVar) => ({ + type: PIECE_TYPE.ATTR, + name: `data-${changeCase.snake(localVar)}`, + value: localVar, + })), + { + type: PIECE_TYPE.ATTR, + name: attrName, + value: wrappedAttrValueExpr, + }, + ]; +} diff --git a/modules/code-generator/src/plugins/component/react/const.ts b/modules/code-generator/src/plugins/component/react/const.ts new file mode 100644 index 0000000000..6294668276 --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/const.ts @@ -0,0 +1,9 @@ +export const REACT_CHUNK_NAME = { + ClassRenderStart: 'ReactComponentClassRenderStart', + ClassRenderPre: 'ReactComponentClassRenderPre', + ClassRenderEnd: 'ReactComponentClassRenderEnd', + ClassRenderJSX: 'ReactComponentClassRenderJSX', + ClassDidMountStart: 'ReactComponentClassDidMountStart', + ClassDidMountEnd: 'ReactComponentClassDidMountEnd', + ClassDidMountContent: 'ReactComponentClassDidMountContent', +}; diff --git a/modules/code-generator/src/plugins/component/react/containerClass.ts b/modules/code-generator/src/plugins/component/react/containerClass.ts new file mode 100644 index 0000000000..0758c893e2 --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/containerClass.ts @@ -0,0 +1,133 @@ +import changeCase from 'change-case'; +import { + COMMON_CHUNK_NAME, + CLASS_DEFINE_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; +import { REACT_CHUNK_NAME } from './const'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { ensureValidClassName } from '../../../utils/validate'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + // 将模块名转换成 PascalCase 的格式,并添加特定后缀,防止命名冲突 + const componentClassName = ensureValidClassName( + `${changeCase.pascalCase(ir.moduleName)}$$Page`, + ); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.Start, + content: `class ${componentClassName} extends React.Component {`, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.End, + content: '}', + linkAfter: [ + ...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End], + REACT_CHUNK_NAME.ClassRenderEnd, + REACT_CHUNK_NAME.ClassDidMountEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorStart, + content: 'constructor(props, context) { super(props); ', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorEnd, + content: '}', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorEnd]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: REACT_CHUNK_NAME.ClassDidMountStart, + content: 'componentDidMount() {', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: REACT_CHUNK_NAME.ClassDidMountEnd, + content: '}', + linkAfter: [REACT_CHUNK_NAME.ClassDidMountContent, REACT_CHUNK_NAME.ClassDidMountStart], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: REACT_CHUNK_NAME.ClassRenderStart, + content: 'render() {', + linkAfter: [ + ...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End], + REACT_CHUNK_NAME.ClassDidMountEnd, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: REACT_CHUNK_NAME.ClassRenderEnd, + content: '}', + linkAfter: [ + REACT_CHUNK_NAME.ClassRenderStart, + REACT_CHUNK_NAME.ClassRenderPre, + REACT_CHUNK_NAME.ClassRenderJSX, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.FileExport, + content: `export default ${componentClassName};`, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + CLASS_DEFINE_CHUNK_NAME.End, + ], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerInitState.ts b/modules/code-generator/src/plugins/component/react/containerInitState.ts new file mode 100644 index 0000000000..5f246e1156 --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/containerInitState.ts @@ -0,0 +1,63 @@ +import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import { Scope } from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; + implementType: 'inConstructor' | 'insMember' | 'hooks'; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + implementType: 'inConstructor', + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + const scope = Scope.createRootScope(); + + const state = ir.state || {}; + const fields = Object.keys(state).map((stateName) => { + const value = generateCompositeType(state[stateName], scope); + return `${stateName}: ${value},`; + }); + + if (cfg.implementType === 'inConstructor') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: `this.state = { ${fields.join('')} };`, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]], + }); + } else if (cfg.implementType === 'insMember') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: `state = { ${fields.join('')} };`, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]], + }); + } + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts b/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts new file mode 100644 index 0000000000..860b9e7552 --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts @@ -0,0 +1,179 @@ +/* eslint-disable @typescript-eslint/indent */ + +import { + CompositeValue, + JSExpression, + InterpretDataSourceConfig, + isJSExpression, + isJSFunction, +} from '@alilc/lowcode-types'; +import changeCase from 'change-case'; + +import { + CLASS_DEFINE_CHUNK_NAME, + COMMON_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; +import { Scope } from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IScope, +} from '../../../types'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser'; +import { isContainerSchema } from '../../../utils/schema'; +import { REACT_CHUNK_NAME } from './const'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const scope = Scope.createRootScope(); + const dataSourceConfig = isContainerSchema(pre.ir) ? pre.ir.dataSource : null; + const dataSourceItems: InterpretDataSourceConfig[] = + (dataSourceConfig && dataSourceConfig.list) || []; + const dataSourceEngineOptions = { runtimeConfig: true }; + if (dataSourceItems.length > 0) { + const requestHandlersMap: Record = {}; + + dataSourceItems.forEach((ds) => { + const dsType = ds.type || 'fetch'; + if (!(dsType in requestHandlersMap) && dsType !== 'custom') { + const handlerFactoryName = `__$$create${changeCase.pascal(dsType)}RequestHandler`; + + requestHandlersMap[dsType] = { + type: 'JSExpression', + value: + handlerFactoryName + (dsType === 'urlParams' ? '(window.location.search)' : '()'), + }; + + const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`; + const handlerPkgName = `@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: CompositeValue, scope: IScope): CompositeValue { + if (isJSExpression(value) || isJSFunction(value)) { + return { + type: 'JSExpression', + value: `function(){ return ((${value.value}))}`, + }; + } + + return { + type: 'JSExpression', + value: `function(){return((${generateCompositeType(value, scope)}))}`, + }; +} diff --git a/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts b/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts new file mode 100644 index 0000000000..6a6c39e055 --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts @@ -0,0 +1,58 @@ +import { + CLASS_DEFINE_CHUNK_NAME, + COMMON_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + // TODO: 下面这个路径有没有更好的方式来获取?而非写死 + content: ` + import { i18n as _$$i18n } from '../../i18n'; + `, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: ` + i18n = (i18nKey) => { + return _$$i18n(i18nKey); + } + `, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts b/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts new file mode 100644 index 0000000000..09da40220f --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts @@ -0,0 +1,93 @@ +import { + CLASS_DEFINE_CHUNK_NAME, + COMMON_CHUNK_NAME, + DEFAULT_LINK_AFTER, +} from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + next.contextData.useRefApi = true; + const useRef = !!ir.analyzeResult?.isUsingRef; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + // TODO: 下面这个路径有没有更好的方式来获取?而非写死 + content: ` + import utils${useRef ? ', { RefsManager }' : ''} from '../../utils'; + `, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: 'this.utils = utils;', + linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart], + }); + + if (useRef) { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: 'this._refsManager = new RefsManager();', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorContent]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: ` + $ = (refName) => { + return this._refsManager.get(refName); + } + `, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: ` + $$ = (refName) => { + return this._refsManager.getAll(refName); + } + `, + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts b/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts new file mode 100644 index 0000000000..8caa9b105a --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts @@ -0,0 +1,108 @@ +import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; +import { REACT_CHUNK_NAME } from './const'; + +import { generateFunction } from '../../../utils/jsExpression'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeChunk, + ICodeStruct, + IContainerInfo, +} from '../../../types'; +import { isJSFunction, isJSExpression } from '@alilc/lowcode-types'; + +export interface PluginConfig { + fileType: string; + exportNameMapping: Record; + normalizeNameMapping: Record; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + exportNameMapping: {}, + normalizeNameMapping: {}, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + if (ir.lifeCycles) { + const { lifeCycles } = ir; + const chunks = Object.keys(lifeCycles).map((lifeCycleName) => { + // 过滤掉非法数据(有些场景下会误传入空字符串或 null) + if ( + !isJSFunction(lifeCycles[lifeCycleName]) && + !isJSExpression(lifeCycles[lifeCycleName]) + ) { + return null; + } + + let normalizeName; + // constructor会取到对象的构造函数 + if (lifeCycleName === 'constructor') { + normalizeName = lifeCycleName; + } else { + normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName; + } + + const exportName = cfg.exportNameMapping[lifeCycleName] || lifeCycleName; + if (normalizeName === 'constructor') { + return { + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }), + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.ConstructorStart]], + }; + } + + if (normalizeName === 'componentDidMount') { + return { + type: ChunkType.STRING, + fileType: cfg.fileType, + name: REACT_CHUNK_NAME.ClassDidMountContent, + content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }), + linkAfter: [REACT_CHUNK_NAME.ClassDidMountStart], + }; + } + + if (normalizeName === 'render') { + return { + type: ChunkType.STRING, + fileType: cfg.fileType, + name: REACT_CHUNK_NAME.ClassRenderPre, + content: generateFunction(lifeCycles[lifeCycleName], { isBlock: true }), + linkAfter: [REACT_CHUNK_NAME.ClassRenderStart], + }; + } + + return { + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: generateFunction(lifeCycles[lifeCycleName], { + name: exportName, + isMember: true, + }), + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + }; + }); + + next.chunks.push(...chunks.filter((x): x is ICodeChunk => x !== null)); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/containerMethod.ts b/modules/code-generator/src/plugins/component/react/containerMethod.ts new file mode 100644 index 0000000000..b44b9a74bb --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/containerMethod.ts @@ -0,0 +1,50 @@ +import { CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from '../../../const/generator'; + +import { generateFunction } from '../../../utils/jsExpression'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeChunk, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + if (ir.methods) { + const { methods } = ir; + const chunks = Object.keys(methods).map((methodName) => ({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsMethod, + content: generateFunction(methods[methodName], { name: methodName, isMember: true }), + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], + })); + + next.chunks.push(...chunks); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/react/jsx.ts b/modules/code-generator/src/plugins/component/react/jsx.ts new file mode 100644 index 0000000000..67c18e1779 --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/jsx.ts @@ -0,0 +1,131 @@ +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 { JSExpression } from '@alilc/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, + }; + + // 这里会将内部的一些子上下文的访问(this.xxx)转换为 __$$context.xxx 的形式 + // 与 Rax 所不同的是,这里不会将最顶层的 this 转换掉 + const customHandlers: HandlerSet = { + expression(input: JSExpression, scope: IScope) { + return transformJsExpr(generateExpression(input, scope), scope, { + dontWrapEval: true, + dontTransformThis2ContextAtRootScope: true, + }); + }, + function(input, scope: IScope) { + return transformThis2Context( + generateCompositeType( + { + type: 'JSFunction', + value: input.value || 'null', + }, + Scope.createRootScope(), + ), + scope, + { ignoreRootScope: true }, + ); + }, + }; + + const generatorPlugins: NodeGeneratorConfig = { + handlers: customHandlers, + tagMapping: (v) => nodeTypeMapping[v] || v, + }; + + if (next.contextData.useRefApi) { + generatorPlugins.attrPlugins = [ + (attrData, scope, pluginCfg, nextFunc) => { + if (attrData.attrName === 'ref') { + return [ + { + name: attrData.attrName, + value: `this._refsManager.linkRef('${attrData.attrValue}')`, + type: PIECE_TYPE.ATTR, + }, + ]; + } + + return nextFunc ? nextFunc(attrData, scope, pluginCfg) : []; + }, + ]; + } + + const generator = createReactNodeGenerator(generatorPlugins); + + const ir = next.ir as IContainerInfo; + const scope: IScope = Scope.createRootScope(); + const jsxContent = generator(ir, scope); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: REACT_CHUNK_NAME.ClassRenderJSX, + content: ` + const __$$context = this; + const { state } = this; + return ${jsxContent}; + `, + linkAfter: [REACT_CHUNK_NAME.ClassRenderStart, REACT_CHUNK_NAME.ClassRenderPre], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.CustomContent, + content: ` + function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; + } + `, + 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 new file mode 100644 index 0000000000..2e71f8d90b --- /dev/null +++ b/modules/code-generator/src/plugins/component/react/reactCommonDeps.ts @@ -0,0 +1,30 @@ +import { COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../types'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: 'import React from \'react\';', + linkAfter: [], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/component/style/css.ts b/modules/code-generator/src/plugins/component/style/css.ts new file mode 100644 index 0000000000..4ef94fdd7c --- /dev/null +++ b/modules/code-generator/src/plugins/component/style/css.ts @@ -0,0 +1,52 @@ +import { COMMON_CHUNK_NAME } from '../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +export interface PluginConfig { + fileType: string; + moduleFileType: string; +} + +const pluginFactory: BuilderComponentPluginFactory = (config?) => { + const cfg: PluginConfig = { + fileType: FileType.CSS, + moduleFileType: FileType.JSX, + ...config, + }; + + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IContainerInfo; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: COMMON_CHUNK_NAME.StyleCssContent, + content: ir.css, + linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.moduleFileType, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: `import './index.${cfg.fileType}';`, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/constants.ts b/modules/code-generator/src/plugins/project/constants.ts new file mode 100644 index 0000000000..18b286c934 --- /dev/null +++ b/modules/code-generator/src/plugins/project/constants.ts @@ -0,0 +1,59 @@ +import { COMMON_CHUNK_NAME } from '../../const/generator'; +import { generateCompositeType } from '../../utils/compositeType'; +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../types'; +import { Scope } from '../../utils/Scope'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IProjectInfo; + const scope = Scope.createRootScope(); + const constantStr = generateCompositeType(ir.constants || {}, scope); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.FileVarDefine, + content: ` + const __$$constants = (${constantStr}); + `, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.FileExport, + content: ` + export default __$$constants; + `, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + COMMON_CHUNK_NAME.FileMainContent, + ], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs/index.ts b/modules/code-generator/src/plugins/project/framework/icejs/index.ts new file mode 100644 index 0000000000..e9c8f255fa --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/index.ts @@ -0,0 +1,17 @@ +import template from './template'; +import entry from './plugins/entry'; +import entryHtml from './plugins/entryHtml'; +import globalStyle from './plugins/globalStyle'; +import packageJSON from './plugins/packageJSON'; +import router from './plugins/router'; + +export default { + template, + plugins: { + entry, + entryHtml, + globalStyle, + packageJSON, + router, + }, +}; diff --git a/modules/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts new file mode 100644 index 0000000000..b5dc2d8f8a --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/plugins/entry.ts @@ -0,0 +1,56 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../../../types'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: ` + import { createApp } from 'ice'; + `, + linkAfter: [], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.FileMainContent, + content: ` + const appConfig = { + app: { + rootId: 'app', + }, + router: { + type: 'hash', + }, + }; + createApp(appConfig); + `, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + ], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts new file mode 100644 index 0000000000..e5837a8dde --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/plugins/entryHtml.ts @@ -0,0 +1,46 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../../../../types'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IProjectInfo; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.HTML, + name: COMMON_CHUNK_NAME.HtmlContent, + content: ` + + + + + + + ${ir?.meta?.name || 'Ice App'} + + +
+ + + `, + linkAfter: [], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts new file mode 100644 index 0000000000..3daaeecdc0 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/plugins/globalStyle.ts @@ -0,0 +1,56 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../../../../types'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IProjectInfo; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.SCSS, + name: COMMON_CHUNK_NAME.StyleDepsImport, + content: ` + // 引入默认全局样式 + @import '@alifd/next/reset.scss'; + `, + linkAfter: [], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.SCSS, + name: COMMON_CHUNK_NAME.StyleCssContent, + content: ` + body { + -webkit-font-smoothing: antialiased; + } + `, + linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.SCSS, + name: COMMON_CHUNK_NAME.StyleCssContent, + content: ir.css || '', + linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts new file mode 100644 index 0000000000..8c9bd95d70 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts @@ -0,0 +1,101 @@ +import { PackageJSON } from '@alilc/lowcode-types'; + +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../../../../types'; + +interface IIceJsPackageJSON extends PackageJSON { + ideMode: { + name: string; + }; + iceworks: { + type: string; + adapter: string; + }; + originTemplate: string; +} + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IProjectInfo; + + const packageJson: IIceJsPackageJSON = { + name: '@alifd/scaffold-lite-js', + version: '0.1.5', + description: '轻量级模板,使用 JavaScript,仅包含基础的 Layout。', + dependencies: { + moment: '^2.24.0', + react: '^16.4.1', + 'react-dom': '^16.4.1', + '@alifd/theme-design-pro': '^0.x', + '@alilc/lowcode-datasource-engine': '*', + // TODO: 如何动态获取下面这些依赖? + '@alilc/lowcode-datasource-url-params-handler': '*', + '@alilc/lowcode-datasource-fetch-handler': '*', + '@alilc/lowcode-datasource-mtop-handler': '*', + '@alilc/lowcode-datasource-mopen-handler': '*', + 'intl-messageformat': '^9.3.6', + }, + devDependencies: { + '@ice/spec': '^1.0.0', + 'build-plugin-fusion': '^0.1.0', + 'build-plugin-moment-locales': '^0.1.0', + eslint: '^6.0.1', + 'ice.js': '^1.0.0', + stylelint: '^13.2.0', + '@ali/build-plugin-ice-def': '^0.1.0', + }, + scripts: { + start: 'icejs start', + build: 'icejs build', + lint: 'npm run eslint && npm run stylelint', + eslint: 'eslint --cache --ext .js,.jsx ./', + stylelint: 'stylelint ./**/*.scss', + }, + ideMode: { + name: 'ice-react', + }, + iceworks: { + type: 'react', + adapter: 'adapter-react-v3', + }, + engines: { + node: '>=8.0.0', + }, + repository: { + type: 'git', + url: 'http://gitlab.alibaba-inc.com/msd/leak-scan/tree/master', + }, + private: true, + originTemplate: '@alifd/scaffold-lite-js', + }; + + ir.packages.forEach((packageInfo) => { + packageJson.dependencies[packageInfo.package] = packageInfo.version; + }); + + next.chunks.push({ + type: ChunkType.JSON, + fileType: FileType.JSON, + name: COMMON_CHUNK_NAME.FileMainContent, + content: packageJson, + linkAfter: [], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs/plugins/router.ts b/modules/code-generator/src/plugins/project/framework/icejs/plugins/router.ts new file mode 100644 index 0000000000..0e2e8c1f79 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/plugins/router.ts @@ -0,0 +1,84 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IRouterInfo, +} from '../../../../../types'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IRouterInfo; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: ` + import BasicLayout from '@/layouts/BasicLayout'; + `, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.FileVarDefine, + content: ` + const routerConfig = [ + { + path: '/', + component: BasicLayout, + children: [ + ${ir.routes + .map( + (route) => ` + { + path: '${route.path}', + component: ${route.componentName}, + } + `, + ) + .join(',')} + ], + }, + ]; + `, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileUtilDefine, + ], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JS, + name: COMMON_CHUNK_NAME.FileExport, + content: ` + export default routerConfig; + `, + linkAfter: [ + COMMON_CHUNK_NAME.ExternalDepsImport, + COMMON_CHUNK_NAME.InternalDepsImport, + COMMON_CHUNK_NAME.FileUtilDefine, + COMMON_CHUNK_NAME.ImportAliasDefine, + COMMON_CHUNK_NAME.FileVarDefine, + COMMON_CHUNK_NAME.FileMainContent, + ], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/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 new file mode 100644 index 0000000000..a908e10730 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/README.md.ts @@ -0,0 +1,73 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..c3bc1bb8cd --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/abc.json.ts @@ -0,0 +1,17 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..b7e0365321 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/build.json.ts @@ -0,0 +1,33 @@ +import { ResultFile } from '@alilc/lowcode-types'; + +export default function getFile(): [string[], ResultFile] { + return [ + [], + { + name: 'build', + ext: 'json', + content: ` +{ + "entry": "src/app.js", + "plugins": [ + [ + "build-plugin-fusion", + { + "themePackage": "@alifd/theme-design-pro" + } + ], + [ + "build-plugin-moment-locales", + { + "locales": [ + "zh-cn" + ] + } + ], + "@ali/build-plugin-ice-def" + ] +} + `, + }, + ]; +} diff --git a/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 new file mode 100644 index 0000000000..876b1b02b2 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/editorconfig.ts @@ -0,0 +1,25 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..9a106bb16d --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintignore.ts @@ -0,0 +1,28 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..7731c9ee47 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/eslintrc.js.ts @@ -0,0 +1,16 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..5c6eb3f13b --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/gitignore.ts @@ -0,0 +1,36 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..5132f3f303 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/jsconfig.json.ts @@ -0,0 +1,24 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..9e858153bf --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierignore.ts @@ -0,0 +1,22 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..80c3d71ba3 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/prettierrc.js.ts @@ -0,0 +1,16 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..9647a76439 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts @@ -0,0 +1,25 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..941be0d263 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts @@ -0,0 +1,26 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..9c078c92c2 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts @@ -0,0 +1,27 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..5ac92b550f --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts @@ -0,0 +1,31 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..ef517bccb7 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts @@ -0,0 +1,81 @@ +import { ResultFile } from '@alilc/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 new file mode 100644 index 0000000000..9c7318dab0 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs/template/files/src/layouts/BasicLayout/index.jsx.ts @@ -0,0 +1,92 @@ +import { ResultFile } from '@alilc/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} + +