From 5d259055fbe199661fdf21d830b671a04e4d13e1 Mon Sep 17 00:00:00 2001 From: "wuji.xwt" Date: Tue, 15 Sep 2020 19:06:35 +0800 Subject: [PATCH 1/2] refactor: code style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3681622 * chore: remove unnecessary code * refactor: react-render using TypeScript * chore: build-script * refactor: editor-skeleton * refactor: designer * refactor: material-parser * refactor: editor-setters * refactor: js to ts for rax-provider Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3678180 * refactor: rax-provider * feat: add build command * chore: compilerOptions for rax-provider * refactor: JS to TS for Rax Renderer Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3678935 * refactor: rax-renderer * Merge remote-tracking branch 'origin/refactor/js-to-ts' into refactor/js2ts-rax-renderer * Merge remote-tracking branch 'origin/refactor/js-to-ts' into refactor/js2ts-rax-renderer * refactor: ts-nocheck * chore: ts compile error * fix: ts rootDir * fix: compile error * chore: using same tsconfig for rax component * refactor: ts compile rax-renderer && rax-provider * Merge remote-tracking branch 'origin/release/1.0.0' into refactor/js-to-ts # Conflicts: # packages/rax-render/src/utils/appHelper.js # packages/rax-render/src/utils/appHelper.ts # packages/utils/src/appHelper.ts * refactor: no JS file * refactor: remove lint * feat: add xima * feat: add eslint ignore * style: fix by lint * feat: lint command * fix: using the same eslint config * style: eslint settings * Merge remote-tracking branch 'origin/release/1.0.0' into refactor/code-style # Conflicts: # packages/plugin-event-bind-dialog/src/index.tsx # packages/plugin-source-editor/src/index.tsx # packages/runtime/src/core/container.ts # packages/runtime/src/core/provider.ts * Merge remote-tracking branch 'origin/release/1.0.0' into refactor/code-style # Conflicts: # packages/designer/src/document/document-model.ts # packages/designer/src/document/node/node-children.ts # packages/designer/src/document/node/props/prop.ts # packages/plugin-source-editor/src/index.tsx * fix: 修改dataSource items -> list * Merge remote-tracking branch 'origin/relase/1.0.0' into refactor/code-style # Conflicts: # packages/react-renderer/package.json * refactor: component-panel plugin-component-pane 代码规范化 Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3703771 * feat: support bizcomps * refactor: component-panel * style: eslint * Merge branch 'refactor/code-style' into fix/ducheng-source-style * style: code style * Merge branch 'fix/ducheng-source-style' into 'refactor/code-style' Code review title: Fix/ducheng source style Code review Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3705972 * style: for demo * style: for demo-server * style: for plugin-event-bind-dialog * style: for plugin-sample-preview * style: for plugin-undo-redo * style: plugin-variable-bind-dialog * style: types * style: for utils * Merge remote-tracking branch 'origin/release/1.0.0' into refactor/code-style # Conflicts: # packages/editor-setters/src/expression-setter/locale/snippets.ts # packages/editor-setters/src/json-setter/locale/snippets.ts # packages/editor-setters/src/locale/snippets.ts # packages/plugin-components-pane/package.json # packages/rax-render/src/hoc/compWrapper.tsx # packages/rax-render/src/utils/index.ts # packages/react-renderer/src/context/appContext.ts * style: editor-preset-general editor-preset-general 代码规范化 Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3707974 * style: editor-preset-general * fix: should set field * fix: should set field - demo-server * refactor(style): fix code style for designer refactor(style): fix code style for editor-core refactor(style): fix code style for editor-skeleton refactor(style): fix code style for react-simulator-renderer refactor(style): fix code style for rax-simulator-renderer * Merge branch 'refactor/lihao-code-style' into 'refactor/code-style' Code review title: refactor(style): fix code style for designer Code review description: refactor(style): fix code style for editor-core refactor(style): fix code style for editor-skeleton refactor(style): fix code style for react-simulator-renderer refactor(style): fix code style for rax-simulator-renderer Code review Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3709472 * style: react/no-multi-comp set to 0 for designer * style: ignore editor-prset-vision * style: fix for plugin-outline-pane * style: fix for rax-provider * style: react-provider * style: runtime * style: rax-render * Merge remote-tracking branch 'origin/release/1.0.0' into refactor/code-style # Conflicts: # packages/editor-setters/src/expression-setter/index.tsx # packages/plugin-source-editor/src/index.tsx # packages/plugin-source-editor/src/transform.ts * refactor: material parser code style 1. 修复eslint问题 2. instanceOf => any 3. 修复node类型解析失败问题 Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3716330 * refactor: material parser code style * refactor: code-generator code style 1. rax 出码合并 2. code style 修复 注:合并的代码中带了 datasource 的 Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3717159 * Merge branch 'feat/rax-code-generator' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into feat/rax-code-generator # Conflicts: # packages/code-generator/src/generator/ProjectBuilder.ts # packages/code-generator/src/parser/SchemaParser.ts # packages/code-generator/src/plugins/component/rax/jsx.ts # packages/code-generator/src/plugins/project/constants.ts # packages/code-generator/src/plugins/project/framework/rax/plugins/packageJSON.ts # packages/code-generator/src/plugins/project/i18n.ts # packages/code-generator/src/publisher/disk/index.ts # packages/code-generator/src/publisher/disk/utils.ts # packages/code-generator/src/types/core.ts # packages/code-generator/src/types/schema.ts # packages/code-generator/src/utils/compositeType.ts # packages/code-generator/src/utils/nodeToJSX.ts * refactor: code-generator * Merge remote-tracking branch 'origin/refactor/code-style' into refactor/code-style-code-generator # Conflicts: # .vscode/launch.json * Revert "refactor: code-generator code style " This reverts commit ebc78e8788f83e8fda0e146758af43b878125c10. * chore: eslintrc && eslintignore * style: for plugin-source-editor * style: fix by eslint --fix * style: scripts/ * style: datasource-engine * feat: pre-commit * Merge branch 'refactor/code-style' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into refactor/code-style # Conflicts: # .eslintignore # packages/code-generator/src/parser/SchemaParser.ts # packages/code-generator/src/plugins/component/rax/containerInitState.ts # packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts # packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts # packages/code-generator/src/plugins/project/framework/rax/plugins/buildConfig.ts # packages/code-generator/src/utils/OrderedSet.ts # packages/code-generator/src/utils/ScopeBindings.ts # packages/code-generator/src/utils/expressionParser.ts # packages/code-generator/src/utils/schema.ts # packages/datasource-engine/src/core/DataSourceEngine.ts # packages/datasource-engine/src/core/RuntimeDataSource.ts # packages/datasource-engine/src/types/IRuntimeContext.ts # packages/datasource-engine/src/types/index.ts * refactor: code style code-generator 对 code style 分支上次合并的 code-generator 修改做了 revert 重新在 code style 分支基础上对代码样式做了修复 rax 合并分支会另行 fix 后向 release 分支提 MR Link: https://code.aone.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/codereview/3719702 * refactor: code style fix * style: for code-generator * Merge remote-tracking branch 'origin/release/1.0.0' into refactor/code-style # Conflicts: # packages/editor-skeleton/src/transducers/addon-combine.ts # packages/plugin-components-pane/package.json # packages/plugin-components-pane/src/components/base/index.tsx # packages/plugin-components-pane/src/components/component-list/index.tsx # packages/plugin-components-pane/src/i18n/index.ts # packages/plugin-components-pane/src/i18n/strings/index.ts # packages/plugin-components-pane/src/index.tsx # packages/plugin-event-bind-dialog/src/index.tsx # packages/plugin-source-editor/src/index.tsx # packages/plugin-source-editor/src/transform.ts * style: auto fix --- .editorconfig | 2 +- .eslintignore | 18 +- .eslintrc | 3 - .eslintrc.js | 3 + .prettierignore | 4 - .prettierrc | 8 - .prettierrc.js | 7 + .stylelintignore | 9 + .stylelintrc.js | 3 + .vscode/launch.json | 2 +- README.md | 11 +- commitlint.config.js | 3 + package.json | 38 +- packages/code-generator/demo/demo.js | 4 +- .../src/@types/ali__my-prettier/index.d.ts | 2 +- .../code-generator/src/const/generator.ts | 2 +- packages/code-generator/src/const/index.ts | 2 +- .../src/generator/CodeBuilder.ts | 11 +- .../src/generator/ModuleBuilder.ts | 2 +- .../src/generator/ProjectBuilder.ts | 2 + .../code-generator/src/model/ResultDir.ts | 2 + .../code-generator/src/model/ResultFile.ts | 4 +- .../code-generator/src/parser/SchemaParser.ts | 9 +- .../src/plugins/common/esmodule.ts | 4 +- .../src/plugins/common/requireUtils.ts | 2 +- .../component/rax/containerInitState.ts | 68 + .../rax/containerInjectDataSourceEngine.ts | 157 + .../component/rax/containerLifeCycle.ts | 120 + .../plugins/component/react/containerClass.ts | 2 +- .../component/react/containerDataSource.ts | 2 +- .../component/react/containerInitState.ts | 2 +- .../component/react/containerInjectUtils.ts | 4 +- .../component/react/containerLifeCycle.ts | 2 +- .../component/react/containerMethod.ts | 2 +- .../src/plugins/component/react/jsx.ts | 2 +- .../component/react/reactCommonDeps.ts | 3 +- .../src/plugins/component/recore/pageFrame.ts | 4 +- .../src/plugins/component/recore/pageStyle.ts | 2 +- .../plugins/component/recore/pageVmHeader.ts | 2 +- .../src/plugins/component/style/css.ts | 2 +- .../framework/icejs/plugins/packageJSON.ts | 4 +- .../project/framework/icejs/plugins/router.ts | 8 +- .../framework/rax/plugins/buildConfig.ts | 52 + .../recore/template/files/abc.json.ts | 1 - .../recore/template/files/build.json.ts | 1 - .../recore/template/files/package.json.ts | 1 - .../template/files/public/index.html.ts | 1 - .../template/files/src/config/app.ts.ts | 3 +- .../files/src/config/components.ts.ts | 3 +- .../template/files/src/config/utils.ts.ts | 3 +- .../recore/template/files/src/index.ts.ts | 1 - .../recore/template/files/tsconfig.json.ts | 1 - .../src/postprocessor/prettier/index.ts | 4 +- .../src/publisher/disk/index.ts | 4 +- .../src/publisher/disk/utils.ts | 2 +- .../code-generator/src/publisher/zip/index.ts | 10 +- .../code-generator/src/publisher/zip/utils.ts | 10 +- packages/code-generator/src/types/error.ts | 9 - .../code-generator/src/types/intermediate.ts | 1 - packages/code-generator/src/types/schema.ts | 2 +- .../code-generator/src/utils/OrderedSet.ts | 34 + .../code-generator/src/utils/ScopeBindings.ts | 56 + packages/code-generator/src/utils/common.ts | 4 +- .../src/utils/expressionParser.ts | 243 + .../code-generator/src/utils/nodeToJSX.ts | 6 +- packages/code-generator/src/utils/schema.ts | 87 + .../code-generator/tools/createTemplate.js | 36 +- packages/datasource-engine/.eslintrc.js | 6 + .../src/core/DataSourceEngine.ts | 124 + .../src/core/RuntimeDataSource.ts | 94 + .../src/types/IRuntimeContext.ts | 24 + packages/datasource-engine/src/types/index.ts | 1 + packages/demo-server/.eslintrc.js | 24 - packages/demo-server/.prettierrc | 4 - packages/demo-server/package.json | 8 - .../demo-server/src/api/api.controller.ts | 6 +- packages/demo-server/src/app.controller.ts | 6 +- packages/demo-server/src/publisher/index.ts | 38 +- packages/demo-server/src/publisher/utils.ts | 50 +- packages/demo/src/app/plugins/provider.ts | 4 +- packages/demo/src/editor/components.ts | 2 +- packages/demo/src/editor/config.ts | 3 - packages/demo/src/editor/index.tsx | 2 +- packages/demo/src/editor/plugins/codeout.tsx | 2 +- packages/demo/src/editor/plugins/saveload.tsx | 5 +- packages/demo/src/vision/module.d.ts | 4 +- packages/designer/.eslintrc.js | 16 + .../bem-tools/border-detecting.tsx | 10 +- .../bem-tools/border-resizing.tsx | 9 +- .../bem-tools/border-selecting.tsx | 7 +- .../bem-tools/drag-resize-engine.ts | 47 +- .../src/builtin-simulator/bem-tools/index.tsx | 2 +- .../builtin-simulator/bem-tools/insertion.tsx | 7 +- .../src/builtin-simulator/create-simulator.ts | 6 +- .../src/builtin-simulator/host-view.tsx | 9 +- .../designer/src/builtin-simulator/host.ts | 75 +- .../live-editing/live-editing.ts | 34 +- .../builtin-simulator/node-selector/index.tsx | 5 +- .../builtin-simulator/resource-consumer.ts | 6 +- .../builtin-simulator/utils/parse-metadata.ts | 4 +- .../src/builtin-simulator/utils/path.ts | 2 +- .../src/builtin-simulator/utils/throttle.ts | 1 + .../src/builtin-simulator/viewport.ts | 15 +- packages/designer/src/component-meta.ts | 42 +- .../designer/src/designer/active-tracker.ts | 2 +- .../designer/src/designer/builtin-hotkey.ts | 9 +- packages/designer/src/designer/clipboard.ts | 7 +- .../designer/src/designer/designer-view.tsx | 6 +- packages/designer/src/designer/designer.ts | 17 +- packages/designer/src/designer/detecting.ts | 4 + .../src/designer/drag-ghost/index.tsx | 6 +- packages/designer/src/designer/dragon.ts | 8 +- packages/designer/src/designer/index.ts | 1 + packages/designer/src/designer/location.ts | 4 + .../designer/src/designer/offset-observer.ts | 40 +- packages/designer/src/designer/scroller.ts | 21 +- .../src/designer/setting/setting-field.ts | 12 +- .../designer/setting/setting-prop-entry.ts | 22 +- .../src/designer/setting/setting-top-entry.ts | 23 +- .../designer/src/document/document-model.ts | 63 +- .../designer/src/document/document-view.tsx | 3 +- packages/designer/src/document/history.ts | 8 +- .../src/document/node/exclusive-group.ts | 7 + .../src/document/node/modal-nodes-manager.ts | 9 +- .../src/document/node/node-children.ts | 17 +- packages/designer/src/document/node/node.ts | 52 +- .../src/document/node/props/prop-stash.ts | 3 + .../designer/src/document/node/props/prop.ts | 23 +- .../designer/src/document/node/props/props.ts | 69 +- .../document/node/props/value-to-source.ts | 84 +- packages/designer/src/document/selection.ts | 6 +- packages/designer/src/icons/clone.tsx | 4 +- packages/designer/src/icons/component.tsx | 2 +- packages/designer/src/icons/container.tsx | 2 +- packages/designer/src/icons/hidden.tsx | 2 +- packages/designer/src/icons/page.tsx | 2 +- packages/designer/src/project/project.ts | 46 +- packages/designer/src/utils/tree.ts | 2 +- packages/editor-core/.eslintrc.js | 14 + packages/editor-core/build.plugin.js | 3 +- packages/editor-core/src/di/ioc-context.ts | 1 + packages/editor-core/src/di/setter.ts | 2 +- packages/editor-core/src/editor.ts | 21 +- packages/editor-core/src/hotkey.ts | 15 +- .../editor-core/src/intl/ali-global-locale.ts | 5 +- packages/editor-core/src/intl/index.ts | 12 +- packages/editor-core/src/utils/app-preset.ts | 2 +- .../editor-core/src/utils/focus-tracker.ts | 24 +- packages/editor-core/src/utils/obx.ts | 3 +- packages/editor-core/src/utils/request.ts | 3 +- .../src/widgets/tip/tip-container.tsx | 2 +- .../src/widgets/tip/tip-handler.ts | 5 +- .../editor-core/src/widgets/tip/tip-item.tsx | 9 +- .../editor-core/src/widgets/title/index.tsx | 5 +- .../editor-preset-general/build.plugin.js | 2 +- packages/editor-preset-general/src/index.ts | 16 +- .../editor-preset-general/src/live-editing.ts | 12 +- packages/editor-preset-vision/.eslintrc.js | 20 + packages/editor-preset-vision/build.plugin.js | 2 +- .../editor-preset-vision/src/base/base.ts | 3 + .../src/base/schemaManager.ts | 2 + .../src/base/visualDesigner.ts | 6 + .../src/base/visualManager.ts | 1 + .../editor-preset-vision/src/bundle/bundle.ts | 8 + .../src/bundle/prototype.ts | 15 +- .../editor-preset-vision/src/bundle/trunk.ts | 5 +- .../src/bundle/upgrade-metadata.ts | 29 +- .../src/components/index.tsx | 3 + packages/editor-preset-vision/src/context.ts | 6 + .../editor-preset-vision/src/drag-engine.ts | 2 +- packages/editor-preset-vision/src/editor.ts | 14 +- packages/editor-preset-vision/src/env.ts | 1 + packages/editor-preset-vision/src/exchange.ts | 4 +- .../editor-preset-vision/src/fields/field.tsx | 17 +- .../src/fields/fields.tsx | 25 +- .../src/fields/inlinetip.tsx | 2 +- .../src/fields/settingField.tsx | 38 +- .../src/fields/variableSetter.tsx | 7 +- .../src/fields/variableSwitcher.tsx | 10 +- packages/editor-preset-vision/src/flags.ts | 5 +- .../src/i18n-util/index.js | 4 +- packages/editor-preset-vision/src/index.ts | 8 +- packages/editor-preset-vision/src/panes.ts | 12 +- packages/editor-preset-vision/src/prop.ts | 30 +- .../src/rootNodeVisitor.ts | 4 + .../src/vc-live-editing.ts | 8 +- packages/editor-preset-vision/src/viewport.ts | 15 +- .../editor-setters/src/color-setter/index.tsx | 15 +- .../src/events-setter/index.tsx | 123 +- .../src/expression-setter/index.tsx | 57 +- .../src/expression-setter/locale/snippets.ts | 66 +- .../src/expression-setter/locale/utils.ts | 6 +- .../src/expression-setter/locale/zh-CN.ts | 2 +- .../src/function-setter/index.tsx | 153 +- .../editor-setters/src/icon-setter/index.tsx | 12 +- packages/editor-setters/src/index.tsx | 15 +- .../editor-setters/src/json-setter/index.tsx | 150 +- .../src/json-setter/locale/snippets.ts | 66 +- .../src/json-setter/locale/utils.ts | 6 +- .../src/json-setter/locale/zh-CN.ts | 2 +- .../editor-setters/src/locale/snippets.ts | 66 +- packages/editor-setters/src/locale/utils.ts | 6 +- packages/editor-setters/src/locale/zh-CN.ts | 2 +- .../editor-setters/src/mixed-setter/index.tsx | 24 +- .../src/mixed-setter/locale/utils.ts | 6 +- .../src/mixed-setter/locale/zh-CN.ts | 2 +- .../editor-setters/src/style-setter/index.tsx | 10 +- packages/editor-skeleton/.eslintrc.js | 16 + packages/editor-skeleton/src/area.ts | 10 +- .../src/components/array-setter/index.tsx | 30 +- .../src/components/array-setter/sortable.tsx | 5 +- .../src/components/field/fields.tsx | 18 +- .../src/components/mixed-setter/index.tsx | 14 +- .../src/components/object-setter/index.tsx | 11 +- .../src/components/popup/index.tsx | 6 +- .../src/components/settings/index.ts | 1 + .../src/components/settings/main.ts | 2 + .../src/components/settings/settings-pane.tsx | 18 +- .../src/components/settings/utils.ts | 2 +- .../src/components/slot-setter/index.tsx | 3 +- .../src/components/stage-box/stage-box.tsx | 4 +- .../src/components/stage-box/stage-chain.ts | 1 + .../src/components/stage-box/stage.tsx | 2 + .../src/components/widget-views/index.tsx | 18 + packages/editor-skeleton/src/icons/clear.tsx | 2 +- .../editor-skeleton/src/icons/convert.tsx | 2 +- packages/editor-skeleton/src/icons/fix.tsx | 4 +- packages/editor-skeleton/src/icons/float.tsx | 6 +- .../editor-skeleton/src/icons/variable.tsx | 2 +- .../src/layouts/bottom-area.tsx | 4 +- .../editor-skeleton/src/layouts/left-area.tsx | 7 +- .../src/layouts/left-fixed-pane.tsx | 1 + .../src/layouts/left-float-pane.tsx | 12 +- .../editor-skeleton/src/layouts/main-area.tsx | 1 + .../src/layouts/right-area.tsx | 4 +- .../editor-skeleton/src/layouts/top-area.tsx | 9 +- .../editor-skeleton/src/layouts/workbench.tsx | 1 + .../editor-skeleton/src/register-defaults.ts | 4 +- packages/editor-skeleton/src/skeleton.ts | 14 +- .../src/transducers/addon-combine.ts | 9 +- .../src/transducers/parse-props.ts | 5 +- packages/editor-skeleton/src/types.ts | 22 +- packages/editor-skeleton/src/widget/dock.ts | 10 +- .../editor-skeleton/src/widget/panel-dock.ts | 15 +- packages/editor-skeleton/src/widget/panel.ts | 16 +- packages/editor-skeleton/src/widget/stage.ts | 8 +- packages/editor-skeleton/src/widget/utils.ts | 2 +- .../src/widget/widget-container.ts | 5 + packages/editor-skeleton/src/widget/widget.ts | 11 +- packages/material-parser/README.md | 2 + packages/material-parser/demo/component.jsx | 7 +- packages/material-parser/package.json | 1 + packages/material-parser/src/core/index.ts | 2 +- .../material-parser/src/core/schema/types.ts | 70 +- packages/material-parser/src/generate.ts | 3 +- packages/material-parser/src/index.ts | 9 +- packages/material-parser/src/localize.ts | 11 +- packages/material-parser/src/parse/index.ts | 11 +- .../js/handlers/componentMethodsHandler.ts | 9 +- .../parse/js/handlers/defaultPropsHandler.ts | 56 +- .../src/parse/js/handlers/flowTypeHandler.ts | 8 +- .../src/parse/js/handlers/propTypeHandler.ts | 2 +- .../material-parser/src/parse/js/index.ts | 7 +- .../parse/js/resolver/findAssignedMethods.ts | 11 +- .../src/parse/js/resolver/index.ts | 31 +- .../resolver/isReactComponentStaticMember.ts | 1 + .../src/parse/js/resolver/isStaticMethod.ts | 1 + .../js/resolver/resolveExportDeclaration.ts | 4 +- .../src/parse/js/resolver/resolveHOC.ts | 10 +- .../src/parse/js/resolver/resolveImport.ts | 3 +- .../js/resolver/resolveTranspiledClass.ts | 8 +- .../src/parse/js/utils/cache.ts | 2 +- .../src/parse/js/utils/flowUtilityTypes.ts | 1 + .../js/utils/getFlowTypeFromReactComponent.ts | 3 +- .../src/parse/js/utils/getName.ts | 5 +- .../src/parse/js/utils/makeProxy.ts | 9 +- .../js/utils/resolveGenericTypeAnnotation.ts | 1 + .../src/parse/runtime/index.ts | 41 +- .../material-parser/src/parse/transform.ts | 78 +- .../material-parser/src/parse/ts/index.ts | 105 +- packages/material-parser/src/scan.ts | 5 +- packages/material-parser/src/types/Basic.ts | 4 + .../material-parser/src/types/ChannelType.ts | 4 +- .../material-parser/src/types/EcologyType.ts | 4 +- .../src/types/ExtensionName.ts | 9 - .../material-parser/src/types/IAccesser.ts | 4 +- .../material-parser/src/types/ICompiler.ts | 15 - .../src/types/IExtensionConfigManifest.ts | 4 +- .../src/types/IMaterialScanModel.ts | 4 +- .../src/types/IMaterializeOptions.ts | 7 +- packages/material-parser/src/types/Meta.ts | 2 +- packages/material-parser/src/types/index.ts | 29 +- packages/material-parser/src/utils.ts | 53 +- .../material-parser/src/validate/index.ts | 3 +- packages/material-parser/test/antd.ts | 2 +- .../fixtures/__snapshots__/test/antd.ts.md | 13353 +--------------- .../fixtures/__snapshots__/test/antd.ts.snap | Bin 346778 -> 289489 bytes .../fixtures/__snapshots__/test/fusion.ts.md | 1396 +- .../__snapshots__/test/fusion.ts.snap | Bin 84944 -> 80795 bytes .../fixtures/__snapshots__/test/index.ts.md | 95 +- .../fixtures/__snapshots__/test/index.ts.snap | Bin 3851 -> 3433 bytes .../fixtures/__snapshots__/test/online.ts.md | 213 +- .../__snapshots__/test/online.ts.snap | Bin 4071 -> 3060 bytes .../components/__tests__/util/domHook.ts | 2 +- .../__tests__/unreachableException.test.js | 2 +- .../antd-component/components/_util/raf.ts | 4 +- .../antd-component/components/_util/ref.ts | 2 +- .../components/_util/styleChecker.tsx | 2 +- .../_util/throttleByAnimationFrame.tsx | 2 +- .../antd-component/components/_util/type.ts | 2 +- .../antd-component/components/_util/wave.tsx | 4 +- .../components/alert/ErrorBoundary.tsx | 14 +- .../components/anchor/Anchor.tsx | 2 +- .../components/auto-complete/index.tsx | 44 +- .../avatar/__tests__/Avatar.test.js | 2 +- .../components/avatar/index.tsx | 14 +- .../components/badge/ScrollNumber.tsx | 16 +- .../antd-component/components/badge/index.tsx | 10 +- .../components/breadcrumb/Breadcrumb.tsx | 8 +- .../breadcrumb/__tests__/Breadcrumb.test.js | 2 +- .../components/button/__tests__/type.test.tsx | 2 +- .../components/button/button.tsx | 6 +- .../components/calendar/Header.tsx | 4 +- .../components/calendar/generateCalendar.tsx | 4 +- .../components/carousel/index.tsx | 8 +- .../components/cascader/index.tsx | 28 +- .../components/checkbox/Group.tsx | 8 +- .../components/collapse/Collapse.tsx | 4 +- .../components/comment/index.tsx | 2 +- .../config-provider/__tests__/locale.test.js | 32 +- .../date-picker/generatePicker/index.tsx | 18 +- .../components/descriptions/Row.tsx | 4 +- .../drawer/__tests__/Drawer.test.js | 2 +- .../components/dropdown/dropdown.tsx | 14 +- .../components/form/FormItem.tsx | 22 +- .../components/form/FormList.tsx | 2 +- .../components/form/__tests__/index.test.js | 7 +- .../components/form/context.tsx | 2 +- .../antd-component/components/form/util.ts | 35 +- .../antd-component/components/grid/col.tsx | 12 +- .../antd-component/components/grid/row.tsx | 12 +- .../antd-component/components/input/Input.tsx | 52 +- .../components/input/ResizableTextArea.tsx | 10 +- .../components/input/Search.tsx | 20 +- .../components/input/__tests__/index.test.js | 4 +- .../input/__tests__/textarea.test.js | 4 +- .../components/layout/Sider.tsx | 18 +- .../antd-component/components/list/Item.tsx | 16 +- .../components/list/__tests__/Item.test.js | 2 +- .../antd-component/components/list/index.tsx | 2 +- .../components/locale/tr_TR.tsx | 4 +- .../components/mentions/index.tsx | 2 +- .../components/menu/MenuItem.tsx | 4 +- .../antd-component/components/menu/index.tsx | 14 +- .../components/message/index.tsx | 3 +- .../modal/__tests__/confirm.test.js | 2 +- .../notification/hooks/useNotification.tsx | 9 +- .../components/notification/index.tsx | 17 +- .../components/page-header/index.tsx | 6 +- .../components/pagination/Pagination.tsx | 2 +- .../popover/__tests__/index.test.js | 2 +- .../antd-component/components/rate/index.tsx | 2 +- .../components/result/__tests__/index.test.js | 2 +- .../components/result/index.tsx | 9 +- .../components/select/index.tsx | 2 +- .../components/skeleton/Avatar.tsx | 2 +- .../components/skeleton/Paragraph.tsx | 4 +- .../components/skeleton/Skeleton.tsx | 3 +- .../skeleton/__tests__/index.test.js | 11 +- .../components/slider/index.tsx | 32 +- .../antd-component/components/space/index.tsx | 4 +- .../components/statistic/Countdown.tsx | 7 +- .../components/statistic/Number.tsx | 2 +- .../statistic/__tests__/index.test.js | 4 +- .../components/statistic/utils.tsx | 2 +- .../components/table/ColumnGroup.tsx | 4 +- .../antd-component/components/table/Table.tsx | 22 +- .../table/__tests__/Table.filter.test.js | 1 - .../table/__tests__/Table.sorter.test.js | 28 +- .../components/table/__tests__/type.test.tsx | 2 +- .../table/hooks/useFilter/FilterDropdown.tsx | 2 +- .../table/hooks/useFilter/index.tsx | 57 +- .../components/table/hooks/usePagination.ts | 2 +- .../components/table/hooks/useSelection.tsx | 4 +- .../components/table/hooks/useSorter.tsx | 67 +- .../components/table/interface.tsx | 28 +- .../antd-component/components/tabs/index.tsx | 2 +- .../components/time-picker/index.tsx | 2 +- .../timeline/__tests__/index.test.js | 17 +- .../components/tooltip/index.tsx | 3 +- .../components/tooltip/placements.tsx | 14 +- .../transfer/__tests__/index.test.js | 17 +- .../components/transfer/index.tsx | 14 +- .../components/transfer/list.tsx | 6 +- .../components/tree-select/index.tsx | 7 +- .../antd-component/components/tree/Tree.tsx | 5 +- .../components/typography/Paragraph.tsx | 2 +- .../components/typography/util.tsx | 12 +- .../components/upload/Upload.tsx | 2 +- .../components/upload/UploadList.tsx | 52 +- .../upload/__tests__/upload.test.js | 33 +- .../components/upload/interface.tsx | 4 +- .../components/upload/utils.tsx | 2 +- .../fusion-next-component/src/affix/index.jsx | 438 +- .../fusion-next-component/src/affix/util.js | 32 +- .../src/animate/animate.jsx | 242 +- .../src/animate/child.jsx | 462 +- .../src/animate/expand.jsx | 224 +- .../src/avatar/index.jsx | 214 +- .../fusion-next-component/src/badge/index.jsx | 152 +- .../fusion-next-component/src/badge/sup.jsx | 363 +- .../src/balloon/alignMap.js | 384 +- .../src/balloon/balloon.jsx | 586 +- .../src/balloon/index.jsx | 62 +- .../src/balloon/inner.jsx | 166 +- .../src/balloon/tooltip.jsx | 289 +- .../fusion-next-component/src/balloon/util.js | 34 +- .../fusion-next-component/src/box/index.jsx | 376 +- .../src/breadcrumb/index.jsx | 386 +- .../src/breadcrumb/item.jsx | 102 +- .../src/button/index.jsx | 52 +- .../src/button/view/button.jsx | 316 +- .../src/button/view/group.jsx | 84 +- .../src/calendar/calendar.jsx | 538 +- .../src/calendar/head/card-header.jsx | 190 +- .../src/calendar/head/menu.jsx | 107 +- .../src/calendar/head/month-panel-header.jsx | 84 +- .../src/calendar/head/year-panel-header.jsx | 92 +- .../src/calendar/index.jsx | 112 +- .../src/calendar/range-calendar.jsx | 670 +- .../src/calendar/table/date-table-head.jsx | 38 +- .../src/calendar/table/date-table.jsx | 222 +- .../src/calendar/table/month-table.jsx | 154 +- .../src/calendar/table/year-table.jsx | 170 +- .../src/calendar/utils/index.js | 144 +- .../src/card/actions.jsx | 48 +- .../src/card/bullet-header.jsx | 84 +- .../fusion-next-component/src/card/card.jsx | 166 +- .../src/card/collapse-content.jsx | 224 +- .../src/card/content.jsx | 54 +- .../src/card/divider.jsx | 58 +- .../fusion-next-component/src/card/header.jsx | 98 +- .../fusion-next-component/src/card/index.jsx | 36 +- .../fusion-next-component/src/card/media.jsx | 92 +- .../src/cascader-select/cascader-select.jsx | 1433 +- .../src/cascader-select/index.jsx | 64 +- .../src/cascader/cascader.jsx | 1482 +- .../src/cascader/index.jsx | 38 +- .../src/cascader/item.jsx | 296 +- .../src/cascader/menu.jsx | 178 +- .../src/cascader/utils.js | 251 +- .../src/checkbox/checkbox-group.jsx | 422 +- .../src/checkbox/checkbox.jsx | 503 +- .../src/collapse/collapse.jsx | 405 +- .../src/collapse/panel.jsx | 179 +- .../src/config-provider/cache.js | 58 +- .../src/config-provider/config.jsx | 375 +- .../src/config-provider/consumer.jsx | 42 +- .../src/config-provider/error-boundary.jsx | 76 +- .../src/config-provider/get-context-props.jsx | 136 +- .../src/config-provider/index.jsx | 328 +- .../src/date-picker/date-picker.jsx | 1194 +- .../src/date-picker/index.jsx | 78 +- .../src/date-picker/module/panel-footer.jsx | 156 +- .../src/date-picker/month-picker.jsx | 748 +- .../src/date-picker/range-picker.jsx | 1882 ++- .../src/date-picker/util/index.js | 232 +- .../src/date-picker/week-picker.jsx | 686 +- .../src/date-picker/year-picker.jsx | 730 +- .../src/demo-helper/index.jsx | 1276 +- .../src/dialog/dialog.jsx | 604 +- .../src/dialog/index.jsx | 98 +- .../src/dialog/inner.jsx | 366 +- .../fusion-next-component/src/dialog/show.jsx | 357 +- .../src/divider/index.jsx | 92 +- .../src/drawer/drawer.jsx | 426 +- .../src/drawer/inner.jsx | 238 +- .../src/dropdown/dropdown.jsx | 229 +- .../src/dropdown/index.jsx | 30 +- .../fusion-next-component/src/field/index.js | 58 +- .../fusion-next-component/src/field/utils.js | 70 +- .../src/form/enhance.jsx | 148 +- .../fusion-next-component/src/form/error.jsx | 158 +- .../fusion-next-component/src/form/form.jsx | 356 +- .../fusion-next-component/src/form/index.jsx | 36 +- .../fusion-next-component/src/form/item.jsx | 720 +- .../fusion-next-component/src/form/reset.jsx | 90 +- .../fusion-next-component/src/form/submit.jsx | 94 +- .../fusion-next-component/src/grid/col.jsx | 290 +- .../fusion-next-component/src/grid/index.jsx | 40 +- .../fusion-next-component/src/grid/row.jsx | 248 +- .../src/icon/icon-font.jsx | 100 +- .../fusion-next-component/src/icon/index.jsx | 164 +- .../fusion-next-component/src/input/base.jsx | 410 +- .../fusion-next-component/src/input/group.jsx | 130 +- .../fusion-next-component/src/input/index.jsx | 6 +- .../fusion-next-component/src/input/input.jsx | 676 +- .../src/input/password.jsx | 69 +- .../src/input/textarea.jsx | 478 +- .../fusion-next-component/src/list/item.jsx | 102 +- .../fusion-next-component/src/list/list.jsx | 112 +- .../src/loading/index.jsx | 290 +- .../fusion-next-component/src/locale/en-us.js | 258 +- .../fusion-next-component/src/locale/ja-jp.js | 258 +- .../fusion-next-component/src/locale/zh-cn.js | 258 +- .../fusion-next-component/src/locale/zh-tw.js | 258 +- .../src/menu-button/index.jsx | 368 +- .../fusion-next-component/src/menu/index.jsx | 44 +- .../src/menu/view/checkable-item.jsx | 250 +- .../src/menu/view/checkbox-item.jsx | 68 +- .../src/menu/view/create.jsx | 288 +- .../src/menu/view/divider.jsx | 28 +- .../src/menu/view/group.jsx | 106 +- .../src/menu/view/item.jsx | 382 +- .../src/menu/view/menu.jsx | 1715 +- .../src/menu/view/popup-item.jsx | 504 +- .../src/menu/view/radio-item.jsx | 54 +- .../src/menu/view/selectable-item.jsx | 270 +- .../src/menu/view/sub-menu.jsx | 498 +- .../src/menu/view/util.js | 10 +- .../src/message/index.jsx | 2 +- .../src/message/message.jsx | 298 +- .../src/message/toast.jsx | 358 +- .../src/mixin-ui-state/index.jsx | 81 +- .../fusion-next-component/src/nav/group.jsx | 64 +- .../fusion-next-component/src/nav/item.jsx | 68 +- .../fusion-next-component/src/nav/nav.jsx | 418 +- .../src/nav/popup-item.jsx | 90 +- .../fusion-next-component/src/nav/sub-nav.jsx | 102 +- .../src/notification/config.js | 12 +- .../src/notification/index.jsx | 462 +- .../src/number-picker/index.jsx | 12 +- .../src/number-picker/number-picker.jsx | 966 +- .../src/overlay/gateway.jsx | 100 +- .../src/overlay/index.jsx | 4 +- .../src/overlay/manager.js | 28 +- .../src/overlay/overlay.jsx | 1305 +- .../src/overlay/popup.jsx | 630 +- .../src/overlay/position.jsx | 240 +- .../src/overlay/utils/find-node.js | 40 +- .../src/overlay/utils/position.js | 839 +- .../src/pagination/pagination.jsx | 1135 +- .../src/progress/index.jsx | 44 +- .../src/progress/view/progress-circle.jsx | 256 +- .../src/progress/view/progress-line.jsx | 148 +- .../src/progress/view/progress.jsx | 86 +- .../src/radio/radio-group.jsx | 468 +- .../fusion-next-component/src/radio/radio.jsx | 477 +- .../fusion-next-component/src/range/index.jsx | 26 +- .../fusion-next-component/src/range/utils.jsx | 52 +- .../src/range/view/fixedSlider.jsx | 336 +- .../src/range/view/mark.jsx | 120 +- .../src/range/view/range.jsx | 1387 +- .../src/range/view/scale.jsx | 106 +- .../src/range/view/selected.jsx | 232 +- .../src/range/view/slider.jsx | 78 +- .../src/range/view/track.jsx | 12 +- .../src/rating/index.jsx | 20 +- .../src/rating/rating.jsx | 898 +- .../src/responsive-grid/cell.jsx | 39 +- .../src/responsive-grid/create-style.js | 518 +- .../src/responsive-grid/util.js | 40 +- .../src/search/Search.jsx | 527 +- .../src/search/index.jsx | 34 +- .../src/select/auto-complete.jsx | 618 +- .../fusion-next-component/src/select/base.jsx | 1098 +- .../src/select/data-store.js | 148 +- .../src/select/option-group.jsx | 18 +- .../src/select/option.jsx | 22 +- .../src/select/select.jsx | 1784 +-- .../fusion-next-component/src/select/util.js | 350 +- .../fusion-next-component/src/shell/base.jsx | 154 +- .../fusion-next-component/src/shell/index.jsx | 60 +- .../fusion-next-component/src/shell/shell.jsx | 1100 +- .../fusion-next-component/src/shell/util.js | 56 +- .../src/slider/index.jsx | 128 +- .../src/slider/slick/arrow.jsx | 240 +- .../src/slider/slick/dots.jsx | 164 +- .../src/slider/slick/inner-slider.jsx | 711 +- .../src/slider/slick/mixins/event-handlers.js | 569 +- .../src/slider/slick/mixins/helpers.js | 831 +- .../src/slider/slick/mixins/trackHelper.js | 318 +- .../src/slider/slick/track.jsx | 350 +- .../src/slider/slider.jsx | 382 +- .../src/split-button/index.jsx | 454 +- .../fusion-next-component/src/step/index.jsx | 28 +- .../src/step/view/step-item.jsx | 755 +- .../src/step/view/step.jsx | 410 +- .../src/switch/index.jsx | 322 +- .../fusion-next-component/src/tab/index.jsx | 74 +- .../fusion-next-component/src/tab/tab.jsx | 484 +- .../src/tab/tabs/content.jsx | 82 +- .../src/tab/tabs/nav.jsx | 1194 +- .../src/tab/tabs/tab-item.jsx | 96 +- .../src/tab/tabs/utils.js | 54 +- .../fusion-next-component/src/table/base.jsx | 1170 +- .../src/table/base/body.jsx | 345 +- .../src/table/base/cell.jsx | 240 +- .../src/table/base/filter.jsx | 388 +- .../src/table/base/header.jsx | 347 +- .../src/table/base/resize.jsx | 123 +- .../src/table/base/row.jsx | 412 +- .../src/table/base/sort.jsx | 162 +- .../src/table/base/wrapper.jsx | 28 +- .../src/table/column-group.jsx | 54 +- .../src/table/column.jsx | 122 +- .../src/table/expanded.jsx | 413 +- .../src/table/expanded/row.jsx | 246 +- .../fusion-next-component/src/table/fixed.jsx | 317 +- .../src/table/fixed/body.jsx | 106 +- .../src/table/fixed/header.jsx | 64 +- .../src/table/fixed/wrapper.jsx | 31 +- .../fusion-next-component/src/table/index.jsx | 128 +- .../src/table/list-footer.jsx | 32 +- .../src/table/list-header.jsx | 50 +- .../fusion-next-component/src/table/list.jsx | 183 +- .../src/table/list/body.jsx | 2 +- .../src/table/list/row.jsx | 287 +- .../fusion-next-component/src/table/lock.jsx | 1350 +- .../src/table/lock/body.jsx | 56 +- .../src/table/lock/header.jsx | 26 +- .../src/table/lock/row.jsx | 64 +- .../src/table/selection.jsx | 562 +- .../src/table/selection/row.jsx | 38 +- .../src/table/sticky.jsx | 113 +- .../src/table/sticky/header.jsx | 65 +- .../fusion-next-component/src/table/tree.jsx | 342 +- .../src/table/tree/cell.jsx | 179 +- .../src/table/tree/row.jsx | 60 +- .../fusion-next-component/src/table/util.js | 69 +- .../src/table/virtual.jsx | 569 +- .../src/table/virtual/body.jsx | 156 +- .../src/tag/closeable.jsx | 106 +- .../fusion-next-component/src/tag/index.jsx | 84 +- .../src/tag/selectable.jsx | 136 +- .../src/tag/tag-group.jsx | 38 +- .../fusion-next-component/src/tag/tag.jsx | 476 +- .../src/time-picker/index.jsx | 36 +- .../src/time-picker/module/time-menu.jsx | 232 +- .../src/time-picker/panel.jsx | 280 +- .../src/time-picker/time-picker.jsx | 718 +- .../src/time-picker/utils/index.js | 34 +- .../src/timeline/locale/index.js | 4 +- .../src/timeline/view/timeline-item.jsx | 324 +- .../src/timeline/view/timeline.jsx | 226 +- .../src/transfer/view/transfer-item.jsx | 292 +- .../src/transfer/view/transfer-panel.jsx | 598 +- .../src/transfer/view/transfer.jsx | 974 +- .../src/tree-select/index.jsx | 26 +- .../src/tree-select/tree-select.jsx | 1392 +- .../fusion-next-component/src/tree/index.jsx | 2 +- .../src/tree/view/tree-node-input.jsx | 34 +- .../src/tree/view/tree-node.jsx | 1008 +- .../src/tree/view/tree.jsx | 1738 +- .../src/tree/view/util.js | 251 +- .../src/typography/paragraph.jsx | 32 +- .../src/typography/text.jsx | 148 +- .../src/typography/title.jsx | 40 +- .../src/typography/typography.jsx | 20 +- .../fusion-next-component/src/upload/base.jsx | 43 +- .../fusion-next-component/src/upload/card.jsx | 249 +- .../src/upload/dragger.jsx | 186 +- .../src/upload/index.jsx | 164 +- .../fusion-next-component/src/upload/list.jsx | 900 +- .../src/upload/runtime/html5-uploader.jsx | 221 +- .../src/upload/runtime/iframe-uploader.jsx | 467 +- .../src/upload/runtime/index.jsx | 46 +- .../src/upload/runtime/request.jsx | 160 +- .../src/upload/runtime/selecter.jsx | 246 +- .../src/upload/runtime/uploader.js | 270 +- .../src/upload/transform.js | 40 +- .../src/upload/upload.jsx | 862 +- .../fusion-next-component/src/upload/util.js | 58 +- .../fusion-next-component/src/util/dom.js | 362 +- .../fusion-next-component/src/util/env.js | 38 +- .../fusion-next-component/src/util/events.js | 42 +- .../fusion-next-component/src/util/focus.js | 120 +- .../fusion-next-component/src/util/func.js | 62 +- .../fusion-next-component/src/util/guid.js | 6 +- .../fusion-next-component/src/util/htmlId.js | 22 +- .../fusion-next-component/src/util/keycode.js | 56 +- .../fusion-next-component/src/util/log.js | 22 +- .../fusion-next-component/src/util/object.js | 259 +- .../fusion-next-component/src/util/string.js | 50 +- .../fusion-next-component/src/util/support.js | 82 +- .../src/virtual-list/virtual-list.jsx | 716 +- .../src/basic/AIMakeBlank/container.js | 7 +- .../src/basic/AIMakeIcon/container.js | 7 +- .../src/basic/AIMakeImage/container.js | 7 +- .../src/basic/AIMakeLink/container.js | 7 +- .../src/basic/AIMakePlaceholder/container.js | 7 +- .../src/basic/AIMakeText/container.js | 7 +- .../src/basic/Root/container.js | 7 +- .../src/container.js | 7 +- .../test/fixtures/ts-component/src/index.tsx | 1 - packages/material-parser/test/fusion.ts | 2 +- packages/material-parser/test/index.ts | 1 - packages/material-parser/test/online.ts | 10 +- .../material-parser/test/validate/index.ts | 5 +- .../src/components/base/index.tsx | 7 +- .../src/components/component-list/index.tsx | 8 + packages/plugin-components-pane/src/index.tsx | 6 +- packages/plugin-designer/.eslintrc.js | 14 + .../plugin-event-bind-dialog/src/index.tsx | 75 +- packages/plugin-outline-pane/.eslintrc.js | 7 + .../src/helper/dwell-timer.ts | 11 +- .../src/helper/indent-track.ts | 6 +- .../src/icons/arrow-right.tsx | 2 +- .../plugin-outline-pane/src/icons/outline.tsx | 2 - .../src/icons/radio-active.tsx | 4 +- .../plugin-outline-pane/src/icons/radio.tsx | 4 +- packages/plugin-outline-pane/src/main.ts | 64 +- .../plugin-outline-pane/src/tree-master.ts | 12 +- packages/plugin-outline-pane/src/tree-node.ts | 24 +- packages/plugin-outline-pane/src/tree.ts | 5 +- .../src/views/root-tree-node.tsx | 10 +- .../src/views/tree-branches.tsx | 24 +- .../src/views/tree-node.tsx | 10 +- .../src/views/tree-title.tsx | 65 +- .../plugin-outline-pane/src/views/tree.tsx | 19 +- packages/plugin-sample-preview/src/index.tsx | 6 +- packages/plugin-source-editor/src/index.tsx | 147 +- packages/plugin-source-editor/src/module.d.ts | 2 +- .../plugin-source-editor/src/transform.ts | 144 +- packages/plugin-undo-redo/src/index.tsx | 4 +- .../plugin-variable-bind-dialog/src/index.tsx | 48 +- packages/plugin-zh-en/src/index.tsx | 12 +- packages/rax-provider/src/provider.ts | 45 +- packages/rax-render/.eslintrc.js | 9 + .../rax-render/demo/miniapp/pages/index.js | 2 +- .../demo/wechat-miniprogram/pages/index.js | 2 +- packages/rax-render/package.json | 1 + .../rax-render/src/comp/visualDom/index.tsx | 4 +- packages/rax-render/src/engine/base.tsx | 59 +- packages/rax-render/src/engine/compEngine.tsx | 6 +- packages/rax-render/src/engine/pageEngine.tsx | 7 +- packages/rax-render/src/engine/tempEngine.tsx | 2 +- packages/rax-render/src/hoc/compFactory.tsx | 8 +- packages/rax-render/src/hoc/compWrapper.tsx | 6 +- packages/rax-render/src/utils/dataHelper.ts | 41 +- packages/rax-render/src/utils/index.ts | 17 +- packages/rax-render/src/utils/request.ts | 24 +- packages/rax-simulator-renderer/.eslintrc.js | 14 + .../src/builtin-components/leaf.tsx | 3 +- .../src/builtin-components/renderUtils.ts | 6 +- .../src/builtin-components/slot.tsx | 21 +- .../src/renderer-view.tsx | 13 +- .../rax-simulator-renderer/src/renderer.ts | 30 +- .../src/utils/find-dom-nodes.ts | 1 + .../src/utils/loader.ts | 1 + .../rax-simulator-renderer/src/utils/style.ts | 2 + .../src/components/LazyComponent/index.tsx | 4 +- packages/react-provider/src/provider.tsx | 33 +- packages/react-renderer/.eslintrc.js | 8 + .../demo/config/components/A.jsx | 3 + .../demo/config/components/Div.jsx | 3 + .../demo/config/components/Image.jsx | 4 + .../demo/config/components/Text.jsx | 4 + .../react-renderer/demo/config/constants.js | 2 +- packages/react-renderer/demo/config/utils.js | 4 +- .../react-renderer/demo/schemas/dataSource.js | 68 +- packages/react-renderer/demo/schemas/i18n.js | 36 +- packages/react-renderer/package.json | 2 +- .../src/components/VisualDom.tsx | 4 + .../react-renderer/src/context/appContext.ts | 4 +- packages/react-renderer/src/engine/index.tsx | 76 +- packages/react-renderer/src/index.tsx | 57 +- .../react-renderer/src/renderer/addon.tsx | 10 +- packages/react-renderer/src/renderer/base.tsx | 63 +- .../react-renderer/src/renderer/block.tsx | 10 +- .../react-renderer/src/renderer/component.tsx | 10 +- packages/react-renderer/src/renderer/page.tsx | 6 +- packages/react-renderer/src/renderer/temp.tsx | 9 +- .../react-renderer/src/utils/dataHelper.ts | 20 +- packages/react-renderer/src/utils/index.ts | 80 +- packages/react-renderer/src/utils/request.ts | 3 +- .../react-simulator-renderer/.eslintrc.js | 15 + .../builtin-components/builtin-components.ts | 1 + .../src/builtin-components/leaf.tsx | 3 +- .../src/builtin-components/slot.tsx | 1 + .../src/renderer-view.tsx | 18 +- .../react-simulator-renderer/src/renderer.ts | 53 +- packages/runtime/src/core/container.ts | 4 + packages/runtime/src/core/provider.ts | 21 +- packages/runtime/src/core/runApp.ts | 18 +- packages/types/src/editor.ts | 24 +- packages/types/src/metadata.ts | 14 +- packages/types/src/schema.ts | 4 +- packages/types/src/setter-config.ts | 4 +- packages/types/src/title.ts | 2 +- packages/types/src/utils.ts | 14 +- packages/types/src/value-type.ts | 2 - packages/utils/src/asset.ts | 15 +- packages/utils/src/build-components.ts | 6 +- packages/utils/src/clone-deep.ts | 1 + packages/utils/src/create-content.ts | 2 +- packages/utils/src/create-icon.tsx | 6 +- packages/utils/src/cursor.ts | 3 + packages/utils/src/env.ts | 2 +- packages/utils/src/get-prototype-of.ts | 1 + packages/utils/src/is-object.ts | 2 +- packages/utils/src/is-react.ts | 5 +- packages/utils/src/set-prototype-of.ts | 1 + packages/utils/src/svg-icon.tsx | 3 +- scripts/addowner.js | 15 +- templates/src/index.js | 4 +- xima.config.js | 3 + 807 files changed, 48051 insertions(+), 59248 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.js delete mode 100644 .prettierignore delete mode 100644 .prettierrc create mode 100644 .prettierrc.js create mode 100644 .stylelintignore create mode 100644 .stylelintrc.js create mode 100644 commitlint.config.js create mode 100644 packages/code-generator/src/plugins/component/rax/containerInitState.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts create mode 100644 packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts create mode 100644 packages/code-generator/src/plugins/project/framework/rax/plugins/buildConfig.ts create mode 100644 packages/code-generator/src/utils/OrderedSet.ts create mode 100644 packages/code-generator/src/utils/ScopeBindings.ts create mode 100644 packages/code-generator/src/utils/expressionParser.ts create mode 100644 packages/code-generator/src/utils/schema.ts create mode 100644 packages/datasource-engine/.eslintrc.js create mode 100644 packages/datasource-engine/src/core/DataSourceEngine.ts create mode 100644 packages/datasource-engine/src/core/RuntimeDataSource.ts create mode 100644 packages/datasource-engine/src/types/IRuntimeContext.ts create mode 100644 packages/datasource-engine/src/types/index.ts delete mode 100644 packages/demo-server/.eslintrc.js delete mode 100644 packages/demo-server/.prettierrc create mode 100644 packages/designer/.eslintrc.js create mode 100644 packages/editor-core/.eslintrc.js create mode 100644 packages/editor-preset-vision/.eslintrc.js create mode 100644 packages/editor-skeleton/.eslintrc.js create mode 100644 packages/material-parser/src/types/Basic.ts delete mode 100644 packages/material-parser/src/types/ExtensionName.ts delete mode 100644 packages/material-parser/src/types/ICompiler.ts create mode 100644 packages/plugin-designer/.eslintrc.js create mode 100644 packages/plugin-outline-pane/.eslintrc.js create mode 100644 packages/rax-render/.eslintrc.js create mode 100644 packages/rax-simulator-renderer/.eslintrc.js create mode 100644 packages/react-renderer/.eslintrc.js create mode 100644 packages/react-simulator-renderer/.eslintrc.js create mode 100644 xima.config.js diff --git a/.editorconfig b/.editorconfig index ee55bb502..319299684 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,9 +1,9 @@ -# http://editorconfig.org root = true [*] indent_style = space indent_size = 2 +end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true diff --git a/.eslintignore b/.eslintignore index bf7fdf065..129fb3332 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,7 +1,17 @@ -.idea/ -.vscode/ -build/ +# 忽略目录 +node_modules +test-cases +test +output +build +dist +demo +es +lib .* ~* -node_modules +# 忽略文件 +**/*.min.js +**/*-min.js +**/*.bundle.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 847ef2c13..000000000 --- a/.eslintrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./node_modules/@ali/lowcode-config/.eslintrc" -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..dab7837f3 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: 'eslint-config-ali/typescript/react', +}; diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 28af681fc..000000000 --- a/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -**/test/**/*.ts -**/test/**/*.js -**/template/**/*.template -**/template/**/*.tpl diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index ba026f068..000000000 --- a/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "trailingComma": "all", - "tabWidth": 2, - "semi": true, - "singleQuote": true, - "printWidth": 120, - "arrowParens": "always" -} diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 000000000..24c5859e6 --- /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 000000000..bec25cf29 --- /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 000000000..74a5a54e3 --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: 'stylelint-config-ali', +}; diff --git a/.vscode/launch.json b/.vscode/launch.json index f242fc1f3..98523af22 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "node", "request": "launch", "runtimeExecutable": "${workspaceFolder}/packages/material-parser/node_modules/.bin/ava", - "runtimeArgs": ["debug", "--break", "${file}"] + "runtimeArgs": ["debug", "--break", "${workspaceFolder}/packages/material-parser/test/antd.ts"] } ] } diff --git a/README.md b/README.md index 34ff152c5..6cfc5a252 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,20 @@ ## Ali Lowcode Engine(阿里低代码引擎) -[Lerna](https://github.com/lerna/lerna) + [TS](https://www.typescriptlang.org/) - ## 开发 -#### 创建新包: +#### 创建新包 - `./scripts/create.sh ` -#### 跑起来: +#### 运行示例 - `npm run setup` - `npm start` -#### 开发提交: +#### 开发提交 - `git add ` -- `npm run commit` # 在根目录 +- `git commit -a "feat: xxx"` ## 发布 @@ -24,7 +22,6 @@ ## 注意 -- Commit 动作尽量使用 `npm run commit`,其内部调用了 `git cz`,方便按语义化版本自动递增,以及自动生成 `CHANGELOG.md` - `packages` 工程里一些开发时公共依赖(比如:`typescript`、`ava` 等)会放到工程顶层 - 工程里的 `.md`、`test/` 等文件修改不会产生新的发布 - 当工程里存在多个 ts 文件的目录时,最终产生的文件会按文件夹形式放到 `lib` 下 diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 000000000..52f3b754b --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['ali'], +}; diff --git a/package.json b/package.json index ac1ca5168..a8f50276a 100644 --- a/package.json +++ b/package.json @@ -12,40 +12,34 @@ "scripts": { "build": "./scripts/build.sh", "clean": "rm -rf ./packages/*/lib ./packages/*/es ./packages/*/dist ./packages/*/build", - "commit": "git-cz", + "lint": "eslint --ext .ts,.tsx,.js,.jsx ./ --quiet", + "lint:fix": "eslint --ext .ts,.tsx,.js,.jsx ./ --quiet --fix", "pub": "lerna publish --force-publish --cd-version prepatch", "setup": "./scripts/setup.sh", "start": "./scripts/start.sh", "start:server": "./scripts/start-server.sh", "test": "lerna run test --stream", - "test:snapshot": "lerna run test:snapshot" + "test:snapshot": "lerna run test:snapshot", + "xima:fix": "xima fix", + "xima:scan": "xima scan" }, - "lint-staged": { - "*.{tsx,ts}": [ - "eslint --quiet", - "git add" - ] - }, - "config": { - "commitizen": { - "path": "node_modules/cz-conventional-changelog" + "husky": { + "hooks": { + "commit-msg": "xima exec commitlint -E HUSKY_GIT_PARAMS", + "pre-commit": "xima exec lint-staged" } }, + "lint-staged": { + "**/*.{js,jsx,ts,tsx}": "xima exec eslint", + "**/*.{css,scss,less}": "xima exec stylelint" + }, "devDependencies": { - "@ali/lowcode-config": "^2.0.5", "ava": "^1.0.1", - "babel-eslint": "^10.0.3", - "commitizen": "^3.0.5", - "cz-conventional-changelog": "^2.1.0", - "eslint": "^6.5.1", - "git-cz": "^4.3.1", - "husky": "^4.2.3", "lerna": "^2.11.0", - "lint-staged": "^8.1.0", - "prettier": "^1.15.3", "ts-node": "^7.0.1", "tslib": "^1.9.3", - "typescript": "^3.2.2" + "typescript": "^3.2.2", + "xima": "^0.2.15" }, "engines": { "node": ">=10.0.0" @@ -54,4 +48,4 @@ "mode": "yarn", "lockfile": "enable" } -} +} \ No newline at end of file diff --git a/packages/code-generator/demo/demo.js b/packages/code-generator/demo/demo.js index a3ca9ca46..1c760446d 100644 --- a/packages/code-generator/demo/demo.js +++ b/packages/code-generator/demo/demo.js @@ -59,7 +59,7 @@ function main() { builder.generateProject(schemaJson).then((result) => { displayResultInConsole(result); - writeResultToDisk(result, 'output/lowcodeDemo').then((response) => console.log('Write to disk: ', JSON.stringify(response)),); + writeResultToDisk(result, 'output/lowcodeDemo').then((response) => console.log('Write to disk: ', JSON.stringify(response))); return result; }); } @@ -160,7 +160,7 @@ function exportProject() { builder.generateProject(schemaJson).then((result) => { displayResultInConsole(result); - writeResultToDisk(result, 'output/lowcodeDemo').then((response) => console.log('Write to disk: ', JSON.stringify(response)),); + writeResultToDisk(result, 'output/lowcodeDemo').then((response) => console.log('Write to disk: ', JSON.stringify(response))); return result; }); } diff --git a/packages/code-generator/src/@types/ali__my-prettier/index.d.ts b/packages/code-generator/src/@types/ali__my-prettier/index.d.ts index d21a2b18a..1751a79ff 100644 --- a/packages/code-generator/src/@types/ali__my-prettier/index.d.ts +++ b/packages/code-generator/src/@types/ali__my-prettier/index.d.ts @@ -1,4 +1,4 @@ -/// +// / declare module '@ali/my-prettier' { function format(text: string, type: string): string; diff --git a/packages/code-generator/src/const/generator.ts b/packages/code-generator/src/const/generator.ts index 9028b9226..3d3950420 100644 --- a/packages/code-generator/src/const/generator.ts +++ b/packages/code-generator/src/const/generator.ts @@ -109,6 +109,6 @@ export const DEFAULT_LINK_AFTER = { [COMMON_CHUNK_NAME.StyleDepsImport]: [], [COMMON_CHUNK_NAME.StyleCssContent]: [COMMON_CHUNK_NAME.StyleDepsImport], [COMMON_CHUNK_NAME.HtmlContent]: [], -} +}; export const COMMON_SUB_MODULE_NAME = 'index'; diff --git a/packages/code-generator/src/const/index.ts b/packages/code-generator/src/const/index.ts index d637ad03c..790fa23e0 100644 --- a/packages/code-generator/src/const/index.ts +++ b/packages/code-generator/src/const/index.ts @@ -1,4 +1,4 @@ -export const NATIVE_ELE_PKG: string = 'native'; +export const NATIVE_ELE_PKG = 'native'; export const CONTAINER_TYPE = { COMPONENT: 'Component', diff --git a/packages/code-generator/src/generator/CodeBuilder.ts b/packages/code-generator/src/generator/CodeBuilder.ts index ad7f33622..96fbb5710 100644 --- a/packages/code-generator/src/generator/CodeBuilder.ts +++ b/packages/code-generator/src/generator/CodeBuilder.ts @@ -12,7 +12,7 @@ export default class Builder implements ICodeBuilder { private generators: { [key: string]: CodeGeneratorFunction } = { [ChunkType.STRING]: (str: string) => str, // no-op for string chunks - [ChunkType.JSON]: (json: object) => JSON.stringify(json), // stringify json to string + [ChunkType.JSON]: (json: Record) => JSON.stringify(json), // stringify json to string }; constructor(chunkDefinitions: ICodeChunk[] = []) { @@ -58,14 +58,15 @@ export default class Builder implements ICodeBuilder { const { type, content, name } = unprocessedChunks[indexToRemove]; const compiledContent = this.generateByType(type, content); if (compiledContent) { - resultingString.push(compiledContent + '\n'); + 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 => (ch.linkAfter = ch.linkAfter.filter(after => after !== name)), + // eslint-disable-next-line no-param-reassign + ch => { ch.linkAfter = ch.linkAfter.filter(after => after !== name); }, ); } } @@ -95,8 +96,6 @@ export default class Builder implements ICodeBuilder { // 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), - ); + return linkAfter.filter(chunkName => chunks.some(chunk => chunk.name === chunkName)); } } diff --git a/packages/code-generator/src/generator/ModuleBuilder.ts b/packages/code-generator/src/generator/ModuleBuilder.ts index 063434cb4..f70abc669 100644 --- a/packages/code-generator/src/generator/ModuleBuilder.ts +++ b/packages/code-generator/src/generator/ModuleBuilder.ts @@ -51,7 +51,7 @@ export function createModuleBuilder( if (options.postProcessors.length > 0) { files = files.map((file) => { - let content = file.content; + let { content } = file; const type = file.ext; options.postProcessors.forEach((processer) => { content = processer(content, type); diff --git a/packages/code-generator/src/generator/ProjectBuilder.ts b/packages/code-generator/src/generator/ProjectBuilder.ts index 34211d0e5..a10ad67e8 100644 --- a/packages/code-generator/src/generator/ProjectBuilder.ts +++ b/packages/code-generator/src/generator/ProjectBuilder.ts @@ -40,7 +40,9 @@ function getDirFromRoot(root: IResultDir, path: string[]): IResultDir { export class ProjectBuilder implements IProjectBuilder { private template: IProjectTemplate; + private plugins: IProjectPlugins; + private postProcessors: PostProcessor[]; constructor({ diff --git a/packages/code-generator/src/model/ResultDir.ts b/packages/code-generator/src/model/ResultDir.ts index 3888859c1..c456a9459 100644 --- a/packages/code-generator/src/model/ResultDir.ts +++ b/packages/code-generator/src/model/ResultDir.ts @@ -2,7 +2,9 @@ import { CodeGeneratorError, IResultDir, IResultFile } from '../types'; export default class ResultDir implements IResultDir { public name: string; + public dirs: IResultDir[]; + public files: IResultFile[]; constructor(name: string) { diff --git a/packages/code-generator/src/model/ResultFile.ts b/packages/code-generator/src/model/ResultFile.ts index 08b3032b8..b8064bfab 100644 --- a/packages/code-generator/src/model/ResultFile.ts +++ b/packages/code-generator/src/model/ResultFile.ts @@ -2,10 +2,12 @@ import { IResultFile } from '../types'; export default class ResultFile implements IResultFile { public name: string; + public ext: string; + public content: string; - constructor(name: string, ext: string = 'jsx', content: string = '') { + constructor(name: string, ext = 'jsx', content = '') { this.name = name; this.ext = ext; this.content = content; diff --git a/packages/code-generator/src/parser/SchemaParser.ts b/packages/code-generator/src/parser/SchemaParser.ts index ddb9e4c1c..1c3ef0eb0 100644 --- a/packages/code-generator/src/parser/SchemaParser.ts +++ b/packages/code-generator/src/parser/SchemaParser.ts @@ -20,7 +20,6 @@ import { IExternalDependency, IInternalDependency, InternalDependencyType, - IPageMeta, IParseResult, IProjectSchema, ISchemaParser, @@ -95,7 +94,7 @@ class SchemaParser implements ISchemaParser { }); } } else { - throw new CodeGeneratorError(`Can't find anything to generate.`); + throw new CodeGeneratorError('Can\'t find anything to generate.'); } // 建立所有容器的内部依赖索引 @@ -160,7 +159,7 @@ class SchemaParser implements ISchemaParser { const routes = containers .filter((container) => container.containerType === 'Page') .map((page) => { - const meta = page.meta as IPageMeta; + const { meta } = page; if (meta) { return { path: meta.router, @@ -190,7 +189,9 @@ class SchemaParser implements ISchemaParser { let npms: INpmPackage[] = []; containers.forEach((con) => { const p = (con.deps || []) - .map((dep) => (dep.dependencyType === DependencyType.External ? dep : null)) + .map((dep) => { + return dep.dependencyType === DependencyType.External ? dep : null; + }) .filter((dep) => dep !== null); npms.push(...((p as unknown) as INpmPackage[])); }); diff --git a/packages/code-generator/src/plugins/common/esmodule.ts b/packages/code-generator/src/plugins/common/esmodule.ts index 2fbff2fed..e270988de 100644 --- a/packages/code-generator/src/plugins/common/esmodule.ts +++ b/packages/code-generator/src/plugins/common/esmodule.ts @@ -88,7 +88,9 @@ function buildPackageImport(pkg: string, deps: IDependency[], targetFileType: st } }); - const items = Object.keys(imports).map((src) => (src === imports[src] ? src : `${src} as ${imports[src]}`)); + const items = Object.keys(imports).map((src) => { + return src === imports[src] ? src : `${src} as ${imports[src]}`; + }); const statementL = ['import']; if (defaultImport) { diff --git a/packages/code-generator/src/plugins/common/requireUtils.ts b/packages/code-generator/src/plugins/common/requireUtils.ts index 9da850a4c..6d2fcfe92 100644 --- a/packages/code-generator/src/plugins/common/requireUtils.ts +++ b/packages/code-generator/src/plugins/common/requireUtils.ts @@ -19,7 +19,7 @@ const pluginFactory: BuilderComponentPluginFactory = () => { type: ChunkType.STRING, fileType: FileType.JSX, name: COMMON_CHUNK_NAME.InternalDepsImport, - content: `import * from 'react';`, + content: 'import * from \'react\';', linkAfter: [], }); diff --git a/packages/code-generator/src/plugins/component/rax/containerInitState.ts b/packages/code-generator/src/plugins/component/rax/containerInitState.ts new file mode 100644 index 000000000..0d635963c --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerInitState.ts @@ -0,0 +1,68 @@ +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'; + +type 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(); + + if (ir.state) { + const { state } = ir; + const fields = Object.keys(state).map((stateName) => { + // TODO: 这里用什么 handlers? + 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]], + }); + } + // TODO: hooks state?? + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts b/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts new file mode 100644 index 000000000..6115730b0 --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts @@ -0,0 +1,157 @@ +/* eslint-disable @typescript-eslint/indent */ + +import { CompositeValue, JSExpression, DataSourceConfig, isJSExpression, isJSFunction } from '@ali/lowcode-types'; +import changeCase from 'change-case'; + +import { CLASS_DEFINE_CHUNK_NAME, COMMON_CHUNK_NAME } from '../../../const/generator'; +import Scope from '../../../utils/Scope'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IScope, +} from '../../../types'; + +import { generateCompositeType } from '../../../utils/compositeType'; +import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser'; +import { isContainerSchema } from '../../../utils/schema'; +import { RAX_CHUNK_NAME } from './const'; + +type 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: DataSourceConfig[] = (dataSourceConfig && dataSourceConfig.list) || []; + const dataSourceEngineOptions = { runtimeConfig: true }; + if (dataSourceItems.length > 0) { + const requestHandlersMap = {} as 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' ? '(this.props.location.search)' : '()'), + }; + + const handlerFactoryExportName = `create${changeCase.pascal(dsType)}Handler`; + const handlerPkgName = `@ali/lowcode-datasource-${changeCase.kebab(dsType)}-handler`; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: ` + import { ${handlerFactoryExportName} as ${handlerFactoryName} } from '${handlerPkgName}'; + `, + linkAfter: [], + }); + } + }); + + Object.assign(dataSourceEngineOptions, { requestHandlersMap }); + } + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.ExternalDepsImport, + content: ` + import { create as __$$createDataSourceEngine } from '@ali/lowcode-datasource-engine/runtime'; + `, + linkAfter: [], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: ` + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine( + this._dataSourceConfig, + this._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) => ({ + ...item, + isInit: wrapAsFunction(item.isInit, scope), + options: wrapAsFunction(item.options, scope), + })), + ], + }, + scope, + { + handlers: { + function: (jsFunc) => parseExpressionConvertThis2Context(jsFunc.value, '__$$context'), + expression: (jsExpr) => parseExpressionConvertThis2Context(jsExpr.value, '__$$context'), + }, + }, + )}); +} + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; + +function wrapAsFunction(value: CompositeValue, scope: IScope): CompositeValue { + if (isJSExpression(value) || isJSFunction(value)) { + return { + type: 'JSExpression', + value: `function(){ return ((${value.value}))}`, + }; + } + + return { + type: 'JSExpression', + value: `function(){return((${generateCompositeType(value, scope)}))}`, + }; +} diff --git a/packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts b/packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts new file mode 100644 index 000000000..28cfac83d --- /dev/null +++ b/packages/code-generator/src/plugins/component/rax/containerLifeCycle.ts @@ -0,0 +1,120 @@ +import _ from 'lodash'; + +import { CLASS_DEFINE_CHUNK_NAME } from '../../../const/generator'; +import { RAX_CHUNK_NAME } from './const'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + FileType, + ChunkType, + ICodeStruct, + IContainerInfo, +} from '../../../types'; + +type 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, + }; + + // Rax 先只支持 didMount 和 willUnmount 吧 + + const ir = next.ir as IContainerInfo; + const { lifeCycles } = ir; + + if (lifeCycles && !_.isEmpty(lifeCycles)) { + Object.entries(lifeCycles).forEach(([lifeCycleName, lifeCycleMethodExpr]) => { + const normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName; + const exportName = cfg.exportNameMapping[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 === 'didMount') { + 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 === 'willUnmount') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.ClassWillUnmountContent, + content: `this._lifeCycles.${exportName}();`, + linkAfter: [RAX_CHUNK_NAME.ClassWillUnmountBegin], + }); + } else { + // TODO: print warnings? Unknown life cycle + } + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: '_lifeCycles = this._defineLifeCycles();', + linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.LifeCyclesBegin, + content: ` + _defineLifeCycles() { + const __$$lifeCycles = ({ + `, + linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd, CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: RAX_CHUNK_NAME.LifeCyclesEnd, + content: ` + }); + + // 为所有的方法绑定上下文 + Object.entries(__$$lifeCycles).forEach(([lifeCycleName, lifeCycleMethod]) => { + if (typeof lifeCycleMethod === 'function') { + __$$lifeCycles[lifeCycleName] = (...args) => { + return lifeCycleMethod.apply(this._context, args); + } + } + }); + + return __$$lifeCycles; + } + `, + linkAfter: [RAX_CHUNK_NAME.LifeCyclesBegin, RAX_CHUNK_NAME.LifeCyclesContent], + }); + } + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/component/react/containerClass.ts b/packages/code-generator/src/plugins/component/react/containerClass.ts index 7ca5e685f..b84e7aa6e 100644 --- a/packages/code-generator/src/plugins/component/react/containerClass.ts +++ b/packages/code-generator/src/plugins/component/react/containerClass.ts @@ -35,7 +35,7 @@ const pluginFactory: BuilderComponentPluginFactory = () => { type: ChunkType.STRING, fileType: FileType.JSX, name: CLASS_DEFINE_CHUNK_NAME.End, - content: `}`, + content: '}', linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start, REACT_CHUNK_NAME.ClassRenderEnd], }); diff --git a/packages/code-generator/src/plugins/component/react/containerDataSource.ts b/packages/code-generator/src/plugins/component/react/containerDataSource.ts index b60cb9539..8907dea36 100644 --- a/packages/code-generator/src/plugins/component/react/containerDataSource.ts +++ b/packages/code-generator/src/plugins/component/react/containerDataSource.ts @@ -29,7 +29,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => const ir = next.ir as IContainerInfo; if (ir.state) { - const state = ir.state; + const { state } = ir; const fields = Object.keys(state).map((stateName) => { const value = generateCompositeType(state[stateName]); return `${stateName}: ${value},`; diff --git a/packages/code-generator/src/plugins/component/react/containerInitState.ts b/packages/code-generator/src/plugins/component/react/containerInitState.ts index 9550244f1..3ab10463c 100644 --- a/packages/code-generator/src/plugins/component/react/containerInitState.ts +++ b/packages/code-generator/src/plugins/component/react/containerInitState.ts @@ -31,7 +31,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => const ir = next.ir as IContainerInfo; if (ir.state) { - const state = ir.state; + const { state } = ir; const fields = Object.keys(state).map((stateName) => { const value = generateCompositeType(state[stateName]); return `${stateName}: ${value},`; diff --git a/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts b/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts index 8cded167b..bf065b77d 100644 --- a/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts +++ b/packages/code-generator/src/plugins/component/react/containerInjectUtils.ts @@ -10,7 +10,7 @@ import { type PluginConfig = { fileType: string; -} +}; const pluginFactory: BuilderComponentPluginFactory = (config?) => { const cfg: PluginConfig = { @@ -27,7 +27,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => type: ChunkType.STRING, fileType: cfg.fileType, name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, - content: `this.utils = utils;`, + content: 'this.utils = utils;', linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart], }); diff --git a/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts b/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts index 000355b7d..585cd6d7e 100644 --- a/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts +++ b/packages/code-generator/src/plugins/component/react/containerLifeCycle.ts @@ -35,7 +35,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => const ir = next.ir as IContainerInfo; if (ir.lifeCycles) { - const lifeCycles = ir.lifeCycles; + const { lifeCycles } = ir; const chunks = Object.keys(lifeCycles).map((lifeCycleName) => { const normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName; const exportName = cfg.exportNameMapping[lifeCycleName] || lifeCycleName; diff --git a/packages/code-generator/src/plugins/component/react/containerMethod.ts b/packages/code-generator/src/plugins/component/react/containerMethod.ts index 148f2cffd..ecc89d828 100644 --- a/packages/code-generator/src/plugins/component/react/containerMethod.ts +++ b/packages/code-generator/src/plugins/component/react/containerMethod.ts @@ -30,7 +30,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => const ir = next.ir as IContainerInfo; if (ir.methods) { - const methods = ir.methods; + const { methods } = ir; const chunks = Object.keys(methods).map((methodName) => ({ type: ChunkType.STRING, fileType: cfg.fileType, diff --git a/packages/code-generator/src/plugins/component/react/jsx.ts b/packages/code-generator/src/plugins/component/react/jsx.ts index 3f2c7b0e2..78ee3f790 100644 --- a/packages/code-generator/src/plugins/component/react/jsx.ts +++ b/packages/code-generator/src/plugins/component/react/jsx.ts @@ -14,7 +14,7 @@ import { createReactNodeGenerator } from '../../../utils/nodeToJSX'; type PluginConfig = { fileType?: string; nodeTypeMapping?: Record; -} +}; const pluginFactory: BuilderComponentPluginFactory = (config?) => { const cfg = { diff --git a/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts b/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts index 2e75a5b7e..2e71f8d90 100644 --- a/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts +++ b/packages/code-generator/src/plugins/component/react/reactCommonDeps.ts @@ -6,7 +6,6 @@ import { ChunkType, FileType, ICodeStruct, - IContainerInfo, } from '../../../types'; const pluginFactory: BuilderComponentPluginFactory = () => { @@ -19,7 +18,7 @@ const pluginFactory: BuilderComponentPluginFactory = () => { type: ChunkType.STRING, fileType: FileType.JSX, name: COMMON_CHUNK_NAME.ExternalDepsImport, - content: `import React from 'react';`, + content: 'import React from \'react\';', linkAfter: [], }); diff --git a/packages/code-generator/src/plugins/component/recore/pageFrame.ts b/packages/code-generator/src/plugins/component/recore/pageFrame.ts index e302a64bc..80aa08287 100644 --- a/packages/code-generator/src/plugins/component/recore/pageFrame.ts +++ b/packages/code-generator/src/plugins/component/recore/pageFrame.ts @@ -21,7 +21,7 @@ const pluginFactory: BuilderComponentPluginFactory = () => { type: ChunkType.STRING, fileType: FileType.TS, name: COMMON_CHUNK_NAME.ExternalDepsImport, - content: `import { BaseController } from '@ali/recore-renderer';`, + content: 'import { BaseController } from \'@ali/recore-renderer\';', linkAfter: [], }); @@ -37,7 +37,7 @@ const pluginFactory: BuilderComponentPluginFactory = () => { type: ChunkType.STRING, fileType: FileType.TS, name: CLASS_DEFINE_CHUNK_NAME.End, - content: `}`, + content: '}', linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.End]], }); diff --git a/packages/code-generator/src/plugins/component/recore/pageStyle.ts b/packages/code-generator/src/plugins/component/recore/pageStyle.ts index fc8ca41b5..7f243487a 100644 --- a/packages/code-generator/src/plugins/component/recore/pageStyle.ts +++ b/packages/code-generator/src/plugins/component/recore/pageStyle.ts @@ -22,7 +22,7 @@ const pluginFactory: BuilderComponentPluginFactory = () => { type: ChunkType.STRING, fileType: FileType.TS, name: CLASS_DEFINE_CHUNK_NAME.StaticVar, - content: `static cssText = '${ir.css.replace(/\'/g, '\\\'')}';`, + content: `static cssText = '${ir.css.replace(/'/g, '\\\'')}';`, linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.StaticVar]], }); } diff --git a/packages/code-generator/src/plugins/component/recore/pageVmHeader.ts b/packages/code-generator/src/plugins/component/recore/pageVmHeader.ts index 6ef8ac44f..71ee2335c 100644 --- a/packages/code-generator/src/plugins/component/recore/pageVmHeader.ts +++ b/packages/code-generator/src/plugins/component/recore/pageVmHeader.ts @@ -17,7 +17,7 @@ const pluginFactory: BuilderComponentPluginFactory = () => { type: ChunkType.STRING, fileType: 'vx', name: COMMON_CHUNK_NAME.CustomContent, - content: `
`, + content: '
', linkAfter: [], }); diff --git a/packages/code-generator/src/plugins/component/style/css.ts b/packages/code-generator/src/plugins/component/style/css.ts index a2e8b46f0..167d9be41 100644 --- a/packages/code-generator/src/plugins/component/style/css.ts +++ b/packages/code-generator/src/plugins/component/style/css.ts @@ -12,7 +12,7 @@ import { type PluginConfig = { fileType: string; moduleFileType: string; -} +}; const pluginFactory: BuilderComponentPluginFactory = (config?) => { const cfg: PluginConfig = { diff --git a/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts b/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts index f238b6af0..8d4a864c5 100644 --- a/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts +++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/packageJSON.ts @@ -73,7 +73,9 @@ const pluginFactory: BuilderComponentPluginFactory = () => { originTemplate: '@alifd/scaffold-lite-js', }; - ir.packages.forEach((packageInfo) => (packageJson.dependencies[packageInfo.package] = packageInfo.version)); + ir.packages.forEach((packageInfo) => { + packageJson.dependencies[packageInfo.package] = packageInfo.version; + }); next.chunks.push({ type: ChunkType.JSON, diff --git a/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts b/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts index b4f2d718f..bb2d7c47f 100644 --- a/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts +++ b/packages/code-generator/src/plugins/project/framework/icejs/plugins/router.ts @@ -38,15 +38,15 @@ const pluginFactory: BuilderComponentPluginFactory = () => { component: BasicLayout, children: [ ${ir.routes - .map( - route => ` + .map( + route => ` { path: '${route.path}', component: ${route.componentName}, } `, - ) - .join(',')} + ) + .join(',')} ], }, ]; diff --git a/packages/code-generator/src/plugins/project/framework/rax/plugins/buildConfig.ts b/packages/code-generator/src/plugins/project/framework/rax/plugins/buildConfig.ts new file mode 100644 index 000000000..2afb2e97d --- /dev/null +++ b/packages/code-generator/src/plugins/project/framework/rax/plugins/buildConfig.ts @@ -0,0 +1,52 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IParseResult, +} from '../../../../../types'; + +const pluginFactory: BuilderComponentPluginFactory = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IParseResult; + const miniAppBuildType = ir.project?.config.miniAppBuildType; + + const buildCfg = { + inlineStyle: false, + plugins: [ + [ + 'build-plugin-rax-app', + { + targets: ['web', 'miniapp'], + miniapp: miniAppBuildType + ? { + buildType: miniAppBuildType, + } + : undefined, + }, + ], + '@ali/build-plugin-rax-app-def', + ], + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSON, + name: COMMON_CHUNK_NAME.CustomContent, + content: `${JSON.stringify(buildCfg, null, 2) }\n`, + linkAfter: [], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/abc.json.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/abc.json.ts index b7523b5f9..d83eeccfb 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/abc.json.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/abc.json.ts @@ -25,4 +25,3 @@ export default function getFile(): [string[], IResultFile] { return [[], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/build.json.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/build.json.ts index 08c1ab78a..16590134d 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/build.json.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/build.json.ts @@ -29,4 +29,3 @@ export default function getFile(): [string[], IResultFile] { return [[], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/package.json.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/package.json.ts index d8da2daaa..2e82c8266 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/package.json.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/package.json.ts @@ -63,4 +63,3 @@ export default function getFile(): [string[], IResultFile] { return [[], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/public/index.html.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/public/index.html.ts index af229a7e0..c0d09de31 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/public/index.html.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/public/index.html.ts @@ -48,4 +48,3 @@ export default function getFile(): [string[], IResultFile] { return [['public'], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/app.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/app.ts.ts index 784662e28..b4d86e5e6 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/app.ts.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/app.ts.ts @@ -72,6 +72,5 @@ export default { `, ); - return [['src','config'], file]; + return [['src', 'config'], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/components.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/components.ts.ts index c894e92aa..b08b4593b 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/components.ts.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/components.ts.ts @@ -38,6 +38,5 @@ export default componentsMap; `, ); - return [['src','config'], file]; + return [['src', 'config'], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/utils.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/utils.ts.ts index 84237ae1d..241186e48 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/utils.ts.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/config/utils.ts.ts @@ -24,6 +24,5 @@ export default { `, ); - return [['src','config'], file]; + return [['src', 'config'], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/index.ts.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/index.ts.ts index 979b85a20..8c12c90bf 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/src/index.ts.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/src/index.ts.ts @@ -98,4 +98,3 @@ app.run(); return [['src'], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/plugins/project/framework/recore/template/files/tsconfig.json.ts b/packages/code-generator/src/plugins/project/framework/recore/template/files/tsconfig.json.ts index c30c3e46b..cb75cf556 100644 --- a/packages/code-generator/src/plugins/project/framework/recore/template/files/tsconfig.json.ts +++ b/packages/code-generator/src/plugins/project/framework/recore/template/files/tsconfig.json.ts @@ -50,4 +50,3 @@ export default function getFile(): [string[], IResultFile] { return [[], file]; } - \ No newline at end of file diff --git a/packages/code-generator/src/postprocessor/prettier/index.ts b/packages/code-generator/src/postprocessor/prettier/index.ts index 85c2f9741..082a3d022 100644 --- a/packages/code-generator/src/postprocessor/prettier/index.ts +++ b/packages/code-generator/src/postprocessor/prettier/index.ts @@ -7,7 +7,7 @@ const PARSERS = ['css', 'scss', 'less', 'json', 'html', 'vue']; type ProcessorConfig = { customFileTypeParser: Record; -} +}; const factory: PostProcessorFactory = (config?: ProcessorConfig) => { const cfg: ProcessorConfig = { @@ -23,7 +23,7 @@ const factory: PostProcessorFactory = (config?: ProcessorConfig parser = 'typescript'; } else if (PARSERS.indexOf(fileType) >= 0) { parser = fileType as prettier.BuiltInParserName; - } else if (cfg.customFileTypeParser[fileType]){ + } else if (cfg.customFileTypeParser[fileType]) { parser = cfg.customFileTypeParser[fileType] as prettier.BuiltInParserName; } else if (fileType === 'vx') { return mypretter(content, fileType); diff --git a/packages/code-generator/src/publisher/disk/index.ts b/packages/code-generator/src/publisher/disk/index.ts index b63649ab9..bc12ed96f 100644 --- a/packages/code-generator/src/publisher/disk/index.ts +++ b/packages/code-generator/src/publisher/disk/index.ts @@ -19,8 +19,8 @@ export interface IDiskPublisher extends IPublisher { } export const createDiskPublisher: PublisherFactory< - IDiskFactoryParams, - IDiskPublisher +IDiskFactoryParams, +IDiskPublisher > = (params: IDiskFactoryParams = {}): IDiskPublisher => { let { project, outputPath = './' } = params; diff --git a/packages/code-generator/src/publisher/disk/utils.ts b/packages/code-generator/src/publisher/disk/utils.ts index 35fbbc2ad..b07cb83c9 100644 --- a/packages/code-generator/src/publisher/disk/utils.ts +++ b/packages/code-generator/src/publisher/disk/utils.ts @@ -61,7 +61,7 @@ const createDirectory = (pathToDir: string): Promise => { const writeContentToFile = ( filePath: string, fileContent: string, - encoding: string = 'utf8', + encoding = 'utf8', ): Promise => { return new Promise((resolve, reject) => { writeFile(filePath, fileContent, encoding, err => { diff --git a/packages/code-generator/src/publisher/zip/index.ts b/packages/code-generator/src/publisher/zip/index.ts index c400c6849..9e2cbe36f 100644 --- a/packages/code-generator/src/publisher/zip/index.ts +++ b/packages/code-generator/src/publisher/zip/index.ts @@ -5,7 +5,7 @@ import { IPublisherFactoryParams, PublisherError, } from '../../types'; -import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils' +import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils'; // export type ZipBuffer = Buffer | Blob; export type ZipBuffer = Buffer; @@ -30,12 +30,12 @@ export const createZipPublisher: PublisherFactory project; const setProject = (projectToSet: IResultDir) => { project = projectToSet; - } + }; const getOutputPath = () => outputPath; const setOutputPath = (path: string) => { outputPath = path; - } + }; const publish = async (options: ZipFactoryParams = {}) => { const projectToPublish = options.project || project; @@ -57,7 +57,7 @@ export const createZipPublisher: PublisherFactory { typeof process.versions === 'object' && typeof process.versions.node !== 'undefined' ); -} +}; export const writeZipToDisk = ( zipFolderPath: string, @@ -27,7 +27,7 @@ export const writeZipToDisk = ( const writeStream = fs.createWriteStream(zipPath); writeStream.write(content); writeStream.end(); -} +}; export const generateProjectZip = async (project: IResultDir): Promise => { let zip = new JSZip(); @@ -35,12 +35,12 @@ export const generateProjectZip = async (project: IResultDir): Promise { const zipFolder = ignoreFolder ? parentFolder : parentFolder.folder(folder.name); if (zipFolder !== null) { @@ -57,4 +57,4 @@ const writeFolderToZip = ( } return parentFolder; -} +}; diff --git a/packages/code-generator/src/types/error.ts b/packages/code-generator/src/types/error.ts index 8c0393a88..7bfdfab69 100644 --- a/packages/code-generator/src/types/error.ts +++ b/packages/code-generator/src/types/error.ts @@ -7,21 +7,12 @@ export class CodeGeneratorError extends Error { // tslint:disable-next-line: max-classes-per-file export class ComponentValidationError extends CodeGeneratorError { - constructor(errorString: string) { - super(errorString); - } } // tslint:disable-next-line: max-classes-per-file export class CompatibilityError extends CodeGeneratorError { - constructor(errorString: string) { - super(errorString); - } } // tslint:disable-next-line: max-classes-per-file export class PublisherError extends CodeGeneratorError { - constructor(errorString: string) { - super(errorString); - } } diff --git a/packages/code-generator/src/types/intermediate.ts b/packages/code-generator/src/types/intermediate.ts index 317ef7843..5a9c2c8b1 100644 --- a/packages/code-generator/src/types/intermediate.ts +++ b/packages/code-generator/src/types/intermediate.ts @@ -4,7 +4,6 @@ import { IContainerNodeItem, IDependency, II18nMap, - IInternalDependency, INpmPackage, IUtilItem, } from './index'; diff --git a/packages/code-generator/src/types/schema.ts b/packages/code-generator/src/types/schema.ts index e102c54cd..44d4e3476 100644 --- a/packages/code-generator/src/types/schema.ts +++ b/packages/code-generator/src/types/schema.ts @@ -227,7 +227,7 @@ export interface IAppConfig { historyMode: 'brower' | 'hash'; // 浏览器路由:brower 哈希路由:hash targetRootID: string; // 渲染根节点 ID layout: IComponentNodeItem; - theme: object; // 主题配置,根据接入的主题模块不同 + theme: Record; // 主题配置,根据接入的主题模块不同 } export interface IAppMeta { diff --git a/packages/code-generator/src/utils/OrderedSet.ts b/packages/code-generator/src/utils/OrderedSet.ts new file mode 100644 index 000000000..cb5393b77 --- /dev/null +++ b/packages/code-generator/src/utils/OrderedSet.ts @@ -0,0 +1,34 @@ +export class OrderedSet { + private _set = new Set(); + + private _arr: T[] = []; + + constructor(items?: T[]) { + if (items) { + this._set = new Set(items); + this._arr = items.slice(0); + } + } + + add(item: T) { + if (!this._set.has(item)) { + this._set.add(item); + this._arr.push(item); + } + } + + delete(item: T) { + if (this._set.has(item)) { + this._set.delete(item); + this._arr.splice(this._arr.indexOf(item), 1); + } + } + + has(item: T) { + return this._set.has(item); + } + + toArray() { + return this._arr.slice(0); + } +} diff --git a/packages/code-generator/src/utils/ScopeBindings.ts b/packages/code-generator/src/utils/ScopeBindings.ts new file mode 100644 index 000000000..3b182ed01 --- /dev/null +++ b/packages/code-generator/src/utils/ScopeBindings.ts @@ -0,0 +1,56 @@ +import { OrderedSet } from './OrderedSet'; + +export interface IScopeBindings { + readonly parent: IScopeBindings | null; + + hasBinding(varName: string): boolean; + hasOwnBinding(varName: string): boolean; + + addBinding(varName: string): void; + removeBinding(varName: string): void; + + getAllBindings(): string[]; + getAllOwnedBindings(): string[]; +} + +export class ScopeBindings implements IScopeBindings { + readonly parent: IScopeBindings | null; + + private _bindings = new OrderedSet(); + + constructor(p: IScopeBindings | null = null) { + this.parent = p; + } + + hasBinding(varName: string): boolean { + return this._bindings.has(varName) || !!this.parent?.hasBinding(varName); + } + + hasOwnBinding(varName: string): boolean { + return this._bindings.has(varName); + } + + addBinding(varName: string): void { + this._bindings.add(varName); + } + + removeBinding(varName: string): void { + this._bindings.delete(varName); + } + + getAllBindings(): string[] { + const allBindings = new OrderedSet(this._bindings.toArray()); + + for (let { parent } = this; parent; parent = parent?.parent) { + parent.getAllOwnedBindings().forEach((varName) => { + allBindings.add(varName); + }); + } + + return allBindings.toArray(); + } + + getAllOwnedBindings(): string[] { + return this._bindings.toArray(); + } +} diff --git a/packages/code-generator/src/utils/common.ts b/packages/code-generator/src/utils/common.ts index 5d4619cdb..fe05ce423 100644 --- a/packages/code-generator/src/utils/common.ts +++ b/packages/code-generator/src/utils/common.ts @@ -24,7 +24,9 @@ export function upperCaseFirst(inputValue: string): string { export function uniqueArray(arr: T[], by: (i: T) => string) { const map: Record = {}; - arr.forEach((item) => (map[by(item)] = item)); + arr.forEach((item) => { + map[by(item)] = item; + }); const uniqueKeys = [...new Set(Object.keys(map))]; const uniqueItems = uniqueKeys.map((key) => map[key]); return uniqueItems; diff --git a/packages/code-generator/src/utils/expressionParser.ts b/packages/code-generator/src/utils/expressionParser.ts new file mode 100644 index 000000000..f47e4cd0f --- /dev/null +++ b/packages/code-generator/src/utils/expressionParser.ts @@ -0,0 +1,243 @@ +import * as parser from '@babel/parser'; +import generate from '@babel/generator'; +import traverse, { NodePath } from '@babel/traverse'; +import * as t from '@babel/types'; +import { isIdentifier, Node } from '@babel/types'; + +import { OrderedSet } from './OrderedSet'; + +export class ParseError extends Error { + constructor(expr: string | t.Expression) { + super(`Failed to parse expression "${typeof expr === 'string' ? expr : generate(expr)}"`); + Object.setPrototypeOf(this, new.target.prototype); + } +} + +const MAYBE_EXPRESSIONS: { + [k in Node['type']]?: { + // fields: Array + fields: string[] | ((node: Node) => string[]); + }; +} = { + ArrayExpression: { fields: ['elements'] }, + AssignmentExpression: { fields: ['left', 'right'] }, + BinaryExpression: { fields: ['left', 'right'] }, + CallExpression: { fields: ['arguments', 'callee'] }, + ConditionalExpression: { fields: ['test', 'consequent', 'alternate'] }, + DoWhileStatement: { fields: ['test'] }, + ExpressionStatement: { fields: ['expression'] }, + ForInStatement: { fields: ['right'] }, + ForStatement: { fields: ['init', 'test', 'update'] }, + IfStatement: { fields: ['test'] }, + LogicalExpression: { fields: ['left', 'right'] }, + MemberExpression: { + fields: (node) => { return (node.type === 'MemberExpression' && node.computed) ? ['object', 'property'] : ['object']; }, + }, + NewExpression: { fields: ['callee', 'arguments'] }, + ObjectMethod: { + fields: (node) => { return (node.type === 'ObjectMethod' && node.computed) ? ['key'] : []; }, + }, + ObjectProperty: { + fields: (node) => { return (node.type === 'ObjectProperty' && node.computed) ? ['key', 'value'] : ['value']; }, + }, + ReturnStatement: { fields: ['argument'] }, + SequenceExpression: { fields: ['expressions'] }, + ParenthesizedExpression: { fields: ['expression'] }, + SwitchCase: { fields: ['test'] }, + SwitchStatement: { fields: ['discriminant'] }, + ThrowStatement: { fields: ['argument'] }, + UnaryExpression: { fields: ['argument'] }, + UpdateExpression: { fields: ['argument'] }, + VariableDeclarator: { fields: ['init'] }, + WhileStatement: { fields: ['test'] }, + WithStatement: { fields: ['object'] }, + AssignmentPattern: { fields: ['right'] }, + ArrowFunctionExpression: { fields: ['body'] }, + ClassExpression: { fields: ['superClass'] }, + ClassDeclaration: { fields: ['superClass'] }, + ExportDefaultDeclaration: { fields: ['declaration'] }, + ForOfStatement: { fields: ['right'] }, + ClassMethod: { fields: (node) => { return (node.type === 'ClassMethod' && node.computed) ? ['key'] : []; } }, + SpreadElement: { fields: ['argument'] }, + TaggedTemplateExpression: { fields: ['tag'] }, + TemplateLiteral: { fields: ['expressions'] }, + YieldExpression: { fields: ['argument'] }, + AwaitExpression: { fields: ['argument'] }, + OptionalMemberExpression: { + fields: (node) => { return (node.type === 'OptionalMemberExpression' && node.computed) ? ['object', 'property'] : ['object']; }, + }, + OptionalCallExpression: { fields: ['callee', 'arguments'] }, + JSXSpreadAttribute: { fields: ['argument'] }, + BindExpression: { fields: ['object', 'callee'] }, + ClassProperty: { fields: (node) => { return (node.type === 'ClassProperty' && node.computed) ? ['key', 'value'] : ['value']; } }, + PipelineTopicExpression: { fields: ['expression'] }, + PipelineBareFunction: { fields: ['callee'] }, + ClassPrivateProperty: { fields: ['value'] }, + Decorator: { fields: ['expression'] }, + TupleExpression: { fields: ['elements'] }, + TSDeclareMethod: { fields: (node) => { return (node.type === 'TSDeclareMethod' && node.computed) ? ['key'] : []; } }, + TSPropertySignature: { + fields: (node) => { return (node.type === 'TSPropertySignature' && node.computed) ? ['key', 'initializer'] : ['initializer']; }, + }, + + TSMethodSignature: { + fields: (node) => { return (node.type === 'TSMethodSignature' && node.computed) ? ['key'] : []; }, + }, + TSAsExpression: { fields: ['expression'] }, + TSTypeAssertion: { fields: ['expression'] }, + TSEnumDeclaration: { fields: ['initializer'] }, + TSEnumMember: { fields: ['initializer'] }, + TSNonNullExpression: { fields: ['expression'] }, + TSExportAssignment: { fields: ['expression'] }, +}; + +export type ParseExpressionGetGlobalVariablesOptions = { filter?: (varName: string) => boolean }; + +const CROSS_THIS_SCOPE_TYPE_NODE: { + [k in Node['type']]?: boolean; +} = { + ArrowFunctionExpression: false, // 箭头函数不跨越 this 的 scope + FunctionExpression: true, + FunctionDeclaration: true, + // FunctionTypeAnnotation: false, // 这是 TS 定义 + // FunctionTypeParam: false, // 这是 TS 定义 + ClassDeclaration: true, + ClassExpression: true, + ClassBody: true, + ClassImplements: true, + ClassMethod: true, + ClassPrivateMethod: true, + ClassProperty: true, + ClassPrivateProperty: true, + DeclareClass: true, +}; + +export function parseExpressionGetGlobalVariables( + expr: string | null | undefined, + { filter = () => true }: ParseExpressionGetGlobalVariablesOptions = {}, +): string[] { + if (!expr) { + return []; + } + + try { + const undeclaredVars = new OrderedSet(); + + const ast = parser.parse(`!(${expr});`); + + const addUndeclaredIdentifierIfNeeded = + (x: Record | null | undefined, path: NodePath) => { + if (isIdentifier(x) && !path.scope.hasBinding(x.name)) { + undeclaredVars.add(x.name); + } + }; + + traverse(ast, { + enter(path) { + const { node } = path; + const expressionFields = MAYBE_EXPRESSIONS[node.type]?.fields; + if (expressionFields) { + (typeof expressionFields === 'function' ? expressionFields(node) : expressionFields).forEach((fieldName) => { + const fieldValue = node[fieldName as keyof typeof node]; + if (typeof fieldValue === 'object') { + if (Array.isArray(fieldValue)) { + fieldValue.forEach((item) => { + addUndeclaredIdentifierIfNeeded(item, path); + }); + } else { + addUndeclaredIdentifierIfNeeded(fieldValue, path); + } + } + }); + } + }, + }); + + return undeclaredVars.toArray().filter(filter); + } catch (e) { + throw new ParseError(expr); + } +} + +export function parseExpressionConvertThis2Context( + expr: string | t.Expression, + contextName = '__$$context', + localVariables: string[] = [], +): string { + if (!expr) { + return expr; + } + + try { + const exprAst = typeof expr === 'string' ? parser.parseExpression(expr) : expr; + const exprWrapAst = t.expressionStatement(exprAst); + const fileAst = t.file(t.program([exprWrapAst])); + + const localVariablesSet = new Set(localVariables); + + let thisScopeLevel = CROSS_THIS_SCOPE_TYPE_NODE[exprAst.type] ? -1 : 0; + traverse(fileAst, { + enter(path) { + if (CROSS_THIS_SCOPE_TYPE_NODE[path.node.type]) { + thisScopeLevel++; + } + }, + exit(path) { + if (CROSS_THIS_SCOPE_TYPE_NODE[path.node.type]) { + thisScopeLevel--; + } + }, + MemberExpression(path) { + if (!path.isMemberExpression()) { + return; + } + + const obj = path.get('object'); + if (!obj.isThisExpression()) { + return; + } + + // 处理局部变量 + if (!path.node.computed) { + const prop = path.get('property'); + if (prop.isIdentifier() && localVariablesSet.has(prop.node.name)) { + path.replaceWith(t.identifier(prop.node.name)); + return; + } + } + + // 替换 this (只在顶层替换) + if (thisScopeLevel <= 0) { + obj.replaceWith(t.identifier(contextName)); + } + }, + ThisExpression(path) { + if (!path.isThisExpression()) { + return; + } + + // MemberExpression 中的 this.xxx 已经处理过了 + if (path.parent.type === 'MemberExpression') { + return; + } + + if (thisScopeLevel <= 0) { + path.replaceWith(t.identifier(contextName)); + } + }, + }); + + const { code } = generate(exprWrapAst.expression, { sourceMaps: false }); + return code; + } catch (e) { + throw new ParseError(expr); + } +} + +export function parseExpression(expr: string) { + try { + return parser.parseExpression(expr); + } catch (e) { + throw new ParseError(expr); + } +} diff --git a/packages/code-generator/src/utils/nodeToJSX.ts b/packages/code-generator/src/utils/nodeToJSX.ts index 39791d7cd..a7edb8903 100644 --- a/packages/code-generator/src/utils/nodeToJSX.ts +++ b/packages/code-generator/src/utils/nodeToJSX.ts @@ -124,7 +124,9 @@ export function generateAttrs(ctx: INodeGeneratorContext, nodeItem: IComponentNo let pieces: CodePiece[] = []; Object.keys(props).forEach( - (propName: string) => (pieces = pieces.concat(generateAttr(ctx, propName, props[propName]))), + (propName: string) => { + pieces = pieces.concat(generateAttr(ctx, propName, props[propName])); + }, ); return pieces; @@ -236,7 +238,7 @@ export function linkPieces(pieces: CodePiece[]): string { .map((p) => p.value) .join(' '); - attrsParts = !!attrsParts ? ` ${attrsParts}` : ''; + attrsParts = attrsParts ? ` ${attrsParts}` : ''; if (childrenParts) { return `${beforeParts}<${tagName}${attrsParts}>${childrenParts}${afterParts}`; diff --git a/packages/code-generator/src/utils/schema.ts b/packages/code-generator/src/utils/schema.ts new file mode 100644 index 000000000..234297579 --- /dev/null +++ b/packages/code-generator/src/utils/schema.ts @@ -0,0 +1,87 @@ +import { + JSSlot, + JSExpression, + NodeData, + NodeSchema, + PropsMap, + isJSExpression, + isJSSlot, + isDOMText, + ContainerSchema, + NpmInfo, +} from '@ali/lowcode-types'; + +export function isContainerSchema(x: any): x is ContainerSchema { + return typeof x === 'object' && x && typeof x.componentName === 'string' && typeof x.fileName === 'string'; +} + +export function isNpmInfo(x: any): x is NpmInfo { + return typeof x === 'object' && x && typeof x.package === 'string'; +} + +// tslint:disable-next-line: no-empty +const noop = () => undefined; + +const handleChildrenDefaultOptions = { + rerun: false, +}; + +export function handleSubNodes( + children: unknown, + handlers: { + string?: (i: string) => T; + expression?: (i: JSExpression) => T; + node?: (i: NodeSchema) => T; + }, + options?: { + rerun?: boolean; + }, +): T[] { + const opt = { + ...handleChildrenDefaultOptions, + ...(options || {}), + }; + + if (Array.isArray(children)) { + const list: NodeData[] = children as NodeData[]; + return list.map( + (child) => handleSubNodes(child, handlers, opt), + ).reduce((p, c) => p.concat(c), []); + } + + let result: T | undefined; + const childrenRes: T[] = []; + if (isDOMText(children)) { + const handler = handlers.string || noop; + result = handler(children as string); + } else if (isJSExpression(children)) { + const handler = handlers.expression || noop; + result = handler(children as JSExpression); + } else { + const handler = handlers.node || noop; + const child = children as NodeSchema; + result = handler(child); + + if (opt.rerun && child.children) { + const childRes = handleSubNodes(child.children, handlers, opt); + childrenRes.push(...childRes); + } + if (child.props) { + // FIXME: currently only support PropsMap + const childProps = child.props as PropsMap; + Object.keys(childProps) + .filter((propName) => isJSSlot(childProps[propName])) + .forEach((propName) => { + const soltVals = (childProps[propName] as JSSlot).value; + const childRes = handleSubNodes(soltVals, handlers, opt); + childrenRes.push(...childRes); + }); + } + } + + if (result !== undefined) { + childrenRes.unshift(result); + } + + return childrenRes; +} diff --git a/packages/code-generator/tools/createTemplate.js b/packages/code-generator/tools/createTemplate.js index b7568f7a9..3b6a0799d 100644 --- a/packages/code-generator/tools/createTemplate.js +++ b/packages/code-generator/tools/createTemplate.js @@ -1,21 +1,21 @@ -const fs = require("fs"); +const fs = require('fs'); const path = require('path'); console.log(process.argv); -let root = ''; +let rootParams = ''; const pathArgIndex = process.argv.indexOf('--path'); if (pathArgIndex >= 0) { - root = process.argv[pathArgIndex + 1]; + rootParams = process.argv[pathArgIndex + 1]; } -if (!root) { +if (!rootParams) { throw new Error('Can\'t find path argument'); } function cloneStr(str, times) { let count = times; const arr = []; - while(count > 0) { + while (count > 0) { arr.push(str); count -= 1; } @@ -23,7 +23,7 @@ function cloneStr(str, times) { } function createTemplateFile(root, internalPath, fileName) { - //不是文件夹,则添加type属性为文件后缀名 + // 不是文件夹,则添加type属性为文件后缀名 const fileTypeSrc = path.extname(fileName); const fileType = fileTypeSrc.substring(1); const baseName = path.basename(fileName, fileTypeSrc); @@ -35,7 +35,7 @@ function createTemplateFile(root, internalPath, fileName) { encoding: 'utf8', }); const pathList = (internalPath.split(path.sep) || []).filter(p => !!p); - const modulePathStr = JSON.stringify(pathList).replace(/\"/g, '\''); + const modulePathStr = JSON.stringify(pathList).replace(/"/g, '\''); const templateContent = ` import ResultFile from '${depPrefix}model/ResultFile'; @@ -62,24 +62,24 @@ ${content} function fileDisplay(root, internalPath) { const dirPath = path.join(root, internalPath); const filesList = fs.readdirSync(dirPath); - for(let i = 0; i < filesList.length; i++){ - //描述此文件/文件夹的对象 + for (let i = 0; i < filesList.length; i++) { + // 描述此文件/文件夹的对象 const fileName = filesList[i]; - //拼接当前文件的路径(上一层路径+当前file的名字) + // 拼接当前文件的路径(上一层路径+当前file的名字) const filePath = path.join(dirPath, fileName); - //根据文件路径获取文件信息,返回一个fs.Stats对象 + // 根据文件路径获取文件信息,返回一个fs.Stats对象 const stats = fs.statSync(filePath); - if(stats.isDirectory()){ - //递归调用 + if (stats.isDirectory()) { + // 递归调用 fileDisplay(root, path.join(internalPath, fileName)); - }else{ + } else { createTemplateFile(root, internalPath, fileName); } } } -//调用函数遍历根目录,同时传递 文件夹路径和对应的数组 -//请使用同步读取 -fileDisplay(root, ''); -//读取完毕则写入到txt文件中 +// 调用函数遍历根目录,同时传递 文件夹路径和对应的数组 +// 请使用同步读取 +fileDisplay(rootParams, ''); +// 读取完毕则写入到txt文件中 // fs.writeFileSync('./data.txt', JSON.stringify(arr)); diff --git a/packages/datasource-engine/.eslintrc.js b/packages/datasource-engine/.eslintrc.js new file mode 100644 index 000000000..dd5b56a53 --- /dev/null +++ b/packages/datasource-engine/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: '../../.eslintrc.js', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + } +} \ No newline at end of file diff --git a/packages/datasource-engine/src/core/DataSourceEngine.ts b/packages/datasource-engine/src/core/DataSourceEngine.ts new file mode 100644 index 000000000..d24ef2420 --- /dev/null +++ b/packages/datasource-engine/src/core/DataSourceEngine.ts @@ -0,0 +1,124 @@ +import { + DataSourceConfig, + DataSourceEngineOptions, + IDataSourceEngine, + IDataSourceEngineFactory, + IRuntimeContext, +} from '../types'; +import { RuntimeDataSource } from './RuntimeDataSource'; + +export class DataSourceEngine implements IDataSourceEngine { + private _dataSourceMap: Record = {}; + + constructor( + private _dataSourceConfig: DataSourceConfig, + private _runtimeContext: IRuntimeContext, + private _options?: DataSourceEngineOptions, + ) { + // eslint-disable-next-line no-unused-expressions + _dataSourceConfig.list?.forEach((ds) => { + // 确保数据源都有处理器 + const requestHandler = ds.requestHandler || _options?.requestHandlersMap?.[ds.type]; + if (!requestHandler) { + throw new Error(`No request handler for "${ds.type}" data source`); + } + + this._dataSourceMap[ds.id] = new RuntimeDataSource( + ds.id, + ds.type, + getValue(ds.options) || {}, + requestHandler.bind(_runtimeContext), + ds.dataHandler ? ds.dataHandler.bind(_runtimeContext) : undefined, + (data) => { + _runtimeContext.setState({ [ds.id]: data }); + }, + ); + }); + } + + public get dataSourceMap() { + return this._dataSourceMap; + } + + public async reloadDataSource() { + try { + const allDataSourceConfigList = this._dataSourceConfig.list || []; + + // urlParams 类型的优先加载 + for (const ds of allDataSourceConfigList) { + if (ds.type === 'urlParams' && (getValue(ds.isInit) ?? true)) { + await this._dataSourceMap[ds.id].load(); + } + } + + // 然后是所有其他的 + const remainDataSourceConfigList = allDataSourceConfigList.filter((x) => x.type !== 'urlParams'); + + // 先发起异步的 + const asyncLoadings: Array> = []; + for (const ds of remainDataSourceConfigList) { + if (getValue(ds.isInit) ?? true) { + const options = getValue(ds.options); + if (options && !options.isSync) { + this._dataSourceMap[ds.id].setOptions(options); + asyncLoadings.push(this._dataSourceMap[ds.id].load(options?.params).catch(() => {})); + } + } + } + + try { + // 再按先后顺序发起同步请求 + for (const ds of remainDataSourceConfigList) { + if (getValue(ds.isInit) ?? true) { + const options = getValue(ds.options); + if (options && options.isSync) { + this._dataSourceMap[ds.id].setOptions(options); + await this._dataSourceMap[ds.id].load(options?.params); + await sleep(0); // TODO: 如何优雅地解决 setState 的异步问题? + } + } + } + } catch (e) { + // ignore error + } + + await Promise.all(asyncLoadings); + } finally { + const allDataHandler = this._dataSourceConfig.dataHandler; + if (allDataHandler) { + await allDataHandler(this._getDataMapOfAll()); + } + } + } + + private _getDataMapOfAll(): Record { + const dataMap: Record = {}; + + Object.entries(this._dataSourceMap).forEach(([dsId, ds]) => { + dataMap[dsId] = ds.data; + }); + + return dataMap; + } +} + +export const create: IDataSourceEngineFactory['create'] = (dataSourceConfig, runtimeContext, options) => { + return new DataSourceEngine(dataSourceConfig, runtimeContext, options); +}; + +function getValue(valueOrValueGetter: T | (() => T)): T; +function getValue(valueOrValueGetter: T | (() => T)): T | undefined { + if (typeof valueOrValueGetter === 'function') { + try { + return valueOrValueGetter(); + } catch (e) { + return undefined; + } + } else { + return valueOrValueGetter; + } +} + +function sleep(ms = 0) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/packages/datasource-engine/src/core/RuntimeDataSource.ts b/packages/datasource-engine/src/core/RuntimeDataSource.ts new file mode 100644 index 000000000..89ec2d930 --- /dev/null +++ b/packages/datasource-engine/src/core/RuntimeDataSource.ts @@ -0,0 +1,94 @@ +import { DataSourceOptions, IRuntimeDataSource, RequestHandler, RuntimeDataSourceStatus } from '../types'; +import { DataSourceResponse } from '../types/DataSourceResponse'; + +export class RuntimeDataSource< + TParams extends Record = Record, + TRequestResult = unknown, + TResultData = unknown +> implements IRuntimeDataSource { + private _status: RuntimeDataSourceStatus = RuntimeDataSourceStatus.Initial; + + private _data?: TResultData; + + private _error?: Error; + + private _latestOptions: DataSourceOptions; + + constructor( + private _id: string, + private _type: string, + private _initialOptions: DataSourceOptions, + private _requestHandler: RequestHandler, DataSourceResponse>, + private _dataHandler: + | (( + data: DataSourceResponse | undefined, + error: unknown | undefined, + ) => TResultData | Promise) + | undefined, + private _onLoaded: (data: TResultData) => void, + ) { + this._latestOptions = _initialOptions; + } + + public get status() { + return this._status; + } + + public get data() { + return this._data; + } + + public get error() { + return this._error; + } + + public async load(params?: TParams): Promise { + try { + this._latestOptions = { + ...this._latestOptions, + params: { + ...this._latestOptions.params, + ...params, + } as TParams, + }; + + this._status = RuntimeDataSourceStatus.Loading; + + const data = await this._request(this._latestOptions); + + this._status = RuntimeDataSourceStatus.Loaded; + + this._onLoaded(data); + + this._data = data; + return data; + } catch (err) { + this._error = err; + this._status = RuntimeDataSourceStatus.Error; + throw err; + } + } + + public setOptions(options: DataSourceOptions) { + this._latestOptions = options; + } + + private async _request(options: DataSourceOptions) { + try { + const response = await this._requestHandler(options); + + const data = this._dataHandler + ? await this._dataHandler(response, undefined) + : ((response.data as unknown) as TResultData); + + return data; + } catch (err) { + if (this._dataHandler) { + const data = await this._dataHandler(undefined, err); + return data; + } + + throw err; + } + } +} diff --git a/packages/datasource-engine/src/types/IRuntimeContext.ts b/packages/datasource-engine/src/types/IRuntimeContext.ts new file mode 100644 index 000000000..a0cc022c9 --- /dev/null +++ b/packages/datasource-engine/src/types/IRuntimeContext.ts @@ -0,0 +1,24 @@ +import { IRuntimeDataSource } from './IRuntimeDataSource'; + +/** 运行时上下文 */ +export interface IRuntimeContext< + TState = Record +> { + /** 当前容器的状态 */ + readonly state: TState; + + /** 设置状态(浅合并) */ + setState(state: Partial): void; + + /** 数据源, key 是数据源的 ID */ + dataSourceMap: Record; + + /** 重新加载所有的数据源 */ + reloadDataSource(): Promise; + + /** 页面容器 */ + readonly page: IRuntimeContext & { props: Record }; + + /** 低代码业务组件容器 */ + readonly component: IRuntimeContext & { props: Record }; +} diff --git a/packages/datasource-engine/src/types/index.ts b/packages/datasource-engine/src/types/index.ts new file mode 100644 index 000000000..ad237a0a0 --- /dev/null +++ b/packages/datasource-engine/src/types/index.ts @@ -0,0 +1 @@ +export * from './DataSourceConfig'; export * from './DataSourceConfigItem'; export * from './DataSourceEngineOptions'; export * from './DataSourceOptions'; export * from './IDataSourceEngine'; export * from './IDataSourceEngineFactory'; export * from './IRuntimeContext'; export * from './IRuntimeDataSource'; export * from './RequestHandler'; export * from './RuntimeDataSourceStatus'; diff --git a/packages/demo-server/.eslintrc.js b/packages/demo-server/.eslintrc.js deleted file mode 100644 index 0ae17cac2..000000000 --- a/packages/demo-server/.eslintrc.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - parserOptions: { - project: 'tsconfig.json', - sourceType: 'module', - }, - plugins: ['@typescript-eslint/eslint-plugin'], - extends: [ - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier', - 'prettier/@typescript-eslint', - ], - root: true, - env: { - node: true, - jest: true, - }, - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/no-explicit-any': 'off', - }, -}; diff --git a/packages/demo-server/.prettierrc b/packages/demo-server/.prettierrc deleted file mode 100644 index dcb72794f..000000000 --- a/packages/demo-server/.prettierrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "singleQuote": true, - "trailingComma": "all" -} \ No newline at end of file diff --git a/packages/demo-server/package.json b/packages/demo-server/package.json index 4a61251f7..5fc5e52da 100644 --- a/packages/demo-server/package.json +++ b/packages/demo-server/package.json @@ -5,8 +5,6 @@ "description": "低代码引擎 DEMO Server 端", "scripts": { "prebuild": "rimraf dist", - "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", - "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "start": "nest start", "start:debug": "nest start --debug --watch", "start:dev": "nest start --watch", @@ -49,13 +47,7 @@ "@types/jest": "25.2.3", "@types/node": "^13.9.1", "@types/supertest": "^2.0.8", - "@typescript-eslint/eslint-plugin": "3.0.2", - "@typescript-eslint/parser": "3.0.2", - "eslint": "7.1.0", - "eslint-config-prettier": "^6.10.0", - "eslint-plugin-import": "^2.20.1", "jest": "26.0.1", - "prettier": "^1.19.1", "supertest": "^4.0.2", "ts-jest": "26.1.0", "ts-loader": "^6.2.1", diff --git a/packages/demo-server/src/api/api.controller.ts b/packages/demo-server/src/api/api.controller.ts index c7a23ec5c..a09b9b162 100644 --- a/packages/demo-server/src/api/api.controller.ts +++ b/packages/demo-server/src/api/api.controller.ts @@ -5,7 +5,11 @@ import { GenerateProjectDto } from '../dto/generate-project.dto'; @Controller('api') export class ApiController { - constructor(private readonly apiService: ApiService) {} + private readonly apiService: ApiService; + + constructor(apiService: ApiService) { + this.apiService = apiService; + } @Get('generate/test') generateTest() { diff --git a/packages/demo-server/src/app.controller.ts b/packages/demo-server/src/app.controller.ts index cce879ee6..0d1d6c9d5 100644 --- a/packages/demo-server/src/app.controller.ts +++ b/packages/demo-server/src/app.controller.ts @@ -3,7 +3,11 @@ import { AppService } from './app.service'; @Controller() export class AppController { - constructor(private readonly appService: AppService) {} + private readonly appService: AppService; + + constructor(appService: AppService) { + this.appService = appService; + } @Get() getHello(): string { diff --git a/packages/demo-server/src/publisher/index.ts b/packages/demo-server/src/publisher/index.ts index 3bd62d4eb..828d7dc01 100644 --- a/packages/demo-server/src/publisher/index.ts +++ b/packages/demo-server/src/publisher/index.ts @@ -1,5 +1,5 @@ import { IResultDir } from '@ali/lowcode-code-generator'; -import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils' +import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils'; export type PublisherFactory = (configuration?: Partial) => U; @@ -17,7 +17,7 @@ export interface IPublisherResponse { payload?: T; } -declare type ZipPublisherResponse = string | Buffer | Blob +declare type ZipPublisherResponse = string | Buffer | Blob; export interface ZipFactoryParams extends IPublisherFactoryParams { outputPath?: string @@ -30,41 +30,41 @@ export interface ZipPublisher extends IPublisher = ( - params: ZipFactoryParams = {} + params: ZipFactoryParams = {}, ): ZipPublisher => { - let { project, outputPath } = params + let { project, outputPath } = params; - const getProject = () => project + const getProject = () => project; const setProject = (projectToSet: IResultDir) => { - project = projectToSet - } + project = projectToSet; + }; - const getOutputPath = () => outputPath + const getOutputPath = () => outputPath; const setOutputPath = (path: string) => { - outputPath = path - } + outputPath = path; + }; const publish = async (options: ZipFactoryParams = {}) => { - const projectToPublish = options.project || project + const projectToPublish = options.project || project; if (!projectToPublish) { throw new Error('MissingProject'); } - const zipName = options.projectSlug || params.projectSlug || projectToPublish.name + const zipName = options.projectSlug || params.projectSlug || projectToPublish.name; try { - const zipContent = await generateProjectZip(projectToPublish) + const zipContent = await generateProjectZip(projectToPublish); // If not output path is provided, zip is not written to disk - const projectOutputPath = options.outputPath || outputPath + const projectOutputPath = options.outputPath || outputPath; if (projectOutputPath && isNodeProcess()) { - await writeZipToDisk(projectOutputPath, zipContent, zipName) + await writeZipToDisk(projectOutputPath, zipContent, zipName); } - return { success: true, payload: zipContent } + return { success: true, payload: zipContent }; } catch (error) { throw new Error('ZipUnexpected'); } - } + }; return { publish, @@ -72,5 +72,5 @@ export const createZipPublisher: PublisherFactory { typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node !== 'undefined' - ) -} + ); +}; export const writeZipToDisk = ( zipFolderPath: string, content: Buffer | Blob, - zipName: string + zipName: string, ): void => { - const fs = require('fs') - const path = require('path') + const fs = require('fs'); + const path = require('path'); if (!fs.existsSync(zipFolderPath)) { - fs.mkdirSync(zipFolderPath, { recursive: true }) + fs.mkdirSync(zipFolderPath, { recursive: true }); } - const zipPath = path.join(zipFolderPath, `${zipName}.zip`) + const zipPath = path.join(zipFolderPath, `${zipName}.zip`); - const writeStream = fs.createWriteStream(zipPath) - writeStream.write(content) - writeStream.end() -} + const writeStream = fs.createWriteStream(zipPath); + writeStream.write(content); + writeStream.end(); +}; export const generateProjectZip = async (project: IResultDir): Promise => { - let zip = new JSZip() - zip = writeFolderToZip(project, zip, true) - const zipType = isNodeProcess() ? 'nodebuffer' : 'blob' - return zip.generateAsync({ type: zipType }) -} + let zip = new JSZip(); + zip = writeFolderToZip(project, zip, true); + const zipType = isNodeProcess() ? 'nodebuffer' : 'blob'; + return zip.generateAsync({ type: zipType }); +}; const writeFolderToZip = ( folder: IResultDir, parentFolder: JSZip, - ignoreFolder: boolean = false + ignoreFolder = false, ) => { - const zipFolder = ignoreFolder ? parentFolder : parentFolder.folder(folder.name) + const zipFolder = ignoreFolder ? parentFolder : parentFolder.folder(folder.name); folder.files.forEach((file: IResultFile) => { // const options = file.contentEncoding === 'base64' ? { base64: true } : {} const options = {}; - const fileName = file.ext ? `${file.name}.${file.ext}` : file.name - zipFolder.file(fileName, file.content, options) - }) + const fileName = file.ext ? `${file.name}.${file.ext}` : file.name; + zipFolder.file(fileName, file.content, options); + }); folder.dirs.forEach((subFolder: IResultDir) => { - writeFolderToZip(subFolder, zipFolder) - }) + writeFolderToZip(subFolder, zipFolder); + }); - return parentFolder -} + return parentFolder; +}; diff --git a/packages/demo/src/app/plugins/provider.ts b/packages/demo/src/app/plugins/provider.ts index 54bc61d23..474f7c774 100644 --- a/packages/demo/src/app/plugins/provider.ts +++ b/packages/demo/src/app/plugins/provider.ts @@ -34,7 +34,7 @@ export default class Preview extends ReactProvider { containerId, components: { ...builtInComps, ...buildComponents({ '@alifd/next': 'Next' }, componentsMap) }, componentsMap, - utils: utils, + utils, constants, }; } @@ -44,7 +44,7 @@ export default class Preview extends ReactProvider { const appSchemaStr = localStorage.getItem('lce-dev-store'); const appSchema = JSON.parse(appSchemaStr || ''); const idx = appSchema.componentsTree.findIndex( - (page: any, idx: number) => (page.fileName || `page${idx}`) === pageId, + (page: any, index: number) => (page.fileName || `page${index}`) === pageId, ); const schema = appSchema.componentsTree[idx]; return schema; diff --git a/packages/demo/src/editor/components.ts b/packages/demo/src/editor/components.ts index bf00bd149..bf5302491 100644 --- a/packages/demo/src/editor/components.ts +++ b/packages/demo/src/editor/components.ts @@ -2,7 +2,7 @@ import logo from '@ali/lowcode-plugin-sample-logo'; import samplePreview from '@ali/lowcode-plugin-sample-preview'; import undoRedo from '@ali/lowcode-plugin-undo-redo'; import componentsPane from '@ali/lowcode-plugin-components-pane'; -import outline, { OutlinePane } from '@ali/lowcode-plugin-outline-pane'; +import outline from '@ali/lowcode-plugin-outline-pane'; import zhEn from '@ali/lowcode-plugin-zh-en'; import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog'; import variableBindDialog from '@ali/lowcode-plugin-variable-bind-dialog'; diff --git a/packages/demo/src/editor/config.ts b/packages/demo/src/editor/config.ts index 6a3d83930..7223c6031 100644 --- a/packages/demo/src/editor/config.ts +++ b/packages/demo/src/editor/config.ts @@ -123,9 +123,6 @@ export default { const simulatorUrl = [ 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/0.9.50/react-simulator-renderer.css', 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/0.9.50/react-simulator-renderer.js', - // for debug simulator - // 'http://localhost:3333/js/react-simulator-renderer.js', - ]; editor.set('simulatorUrl', simulatorUrl); // editor.set('renderEnv', 'rax'); diff --git a/packages/demo/src/editor/index.tsx b/packages/demo/src/editor/index.tsx index b68f5d87a..041acd148 100644 --- a/packages/demo/src/editor/index.tsx +++ b/packages/demo/src/editor/index.tsx @@ -1,5 +1,5 @@ import { render } from 'react-dom'; -import GeneralWorkbench, { editor } from '@ali/lowcode-editor-preset-general'; +import GeneralWorkbench from '@ali/lowcode-editor-preset-general'; import config from './config'; import components from './components'; import './global.scss'; diff --git a/packages/demo/src/editor/plugins/codeout.tsx b/packages/demo/src/editor/plugins/codeout.tsx index c2046bd39..0a6777cc8 100644 --- a/packages/demo/src/editor/plugins/codeout.tsx +++ b/packages/demo/src/editor/plugins/codeout.tsx @@ -28,7 +28,7 @@ const Codeout = ({ editor }: PluginProps) => { const designer = editor.get(Designer); if (designer) { const assets = editor.get('assets') as { components: BasicSection[] }; - const components = assets.components; + const { components } = assets; const componentsMap = components .filter((c) => !!c.npm) diff --git a/packages/demo/src/editor/plugins/saveload.tsx b/packages/demo/src/editor/plugins/saveload.tsx index 75532802f..fe9dc817b 100644 --- a/packages/demo/src/editor/plugins/saveload.tsx +++ b/packages/demo/src/editor/plugins/saveload.tsx @@ -22,10 +22,7 @@ interface BasicSection { const Codeout = ({ editor }: PluginProps) => { const handleSaveClick = () => { - - debugger; - - let schema = editor.get('designer').project.getSchema(); + const schema = editor.get('designer').project.getSchema(); console.log(schema); diff --git a/packages/demo/src/vision/module.d.ts b/packages/demo/src/vision/module.d.ts index be53328de..7c7645ba6 100644 --- a/packages/demo/src/vision/module.d.ts +++ b/packages/demo/src/vision/module.d.ts @@ -9,5 +9,5 @@ declare module '@ali/ve-page-history'; declare module '@ali/ve-i18n-manage-pane'; declare module '@ali/ve-action-pane'; declare module '@ali/vu-legao-design-fetch-context'; -declare module "@ali/vu-function-parser"; -declare module "compare-versions"; +declare module '@ali/vu-function-parser'; +declare module 'compare-versions'; diff --git a/packages/designer/.eslintrc.js b/packages/designer/.eslintrc.js new file mode 100644 index 000000000..c6bbe2868 --- /dev/null +++ b/packages/designer/.eslintrc.js @@ -0,0 +1,16 @@ +module.exports = { + extends: '../../.eslintrc.js', + rules: { + 'react/no-multi-comp': 0, + 'no-unused-expressions': 1, + 'implicit-arrow-linebreak': 1, + 'no-nested-ternary': 1, + 'no-mixed-operators': 1, + '@typescript-eslint/no-parameter-properties': 1, + '@typescript-eslint/ban-types': 1, + 'no-shadow': 1, + 'no-prototype-builtins': 1, + 'no-useless-constructor': 1, + 'no-empty-function': 1, + } +} \ No newline at end of file diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx index f6bd20460..d757e7eb8 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx @@ -56,10 +56,10 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { } @computed get current() { - const host = this.props.host; + const { host } = this.props; const doc = host.document; - const selection = doc.selection; - const current = host.designer.detecting.current; + const { selection } = doc; + const { current } = host.designer.detecting; if (!current || current.document !== doc || selection.has(current.id)) { return null; } @@ -67,8 +67,8 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { } render() { - const host = this.props.host; - const current = this.current; + const { host } = this.props; + const { current } = this; if (!current || host.viewport.scrolling || host.liveEditing.editing) { return null; } diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx index a4947ad7d..118f0de63 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx @@ -23,7 +23,7 @@ export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost if (doc.suspensed) { return null; } - const selection = doc.selection; + const { selection } = doc; return this.dragging ? selection.getTopNodes() : selection.getNodes(); } @@ -37,7 +37,7 @@ export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost } render() { - const selecting = this.selecting; + const { selecting } = this; if (!selecting || selecting.length < 1) { // DIRTY FIX, recore has a bug! return ; @@ -79,7 +79,7 @@ export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost; render() { const { instances } = this; const { node } = this.props; - const designer = this.host.designer; + const { designer } = this.host; if (!instances || instances.length < 1) { return null; @@ -112,8 +112,11 @@ export class BoxResizingInstance extends Component<{ }> { // private outline: any; private willUnbind: () => any; + private outlineRight: any; + private outlineLeft: any; + private dragEngine: DragResizeEngine; constructor(props: any) { diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index 7341fc056..ae82e67b1 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -59,6 +59,7 @@ class Toolbar extends Component<{ observed: OffsetObserver }> { shouldComponentUpdate() { return false; } + render() { const { observed } = this.props; const { height, width } = observed.viewport; @@ -169,7 +170,7 @@ export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHo render() { const { instances } = this; const { node } = this.props; - const designer = this.host.designer; + const { designer } = this.host; if (!instances || instances.length < 1) { return null; @@ -206,7 +207,7 @@ export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> { if (doc.suspensed || this.host.liveEditing.editing) { return null; } - const selection = doc.selection; + const { selection } = doc; return this.dragging ? selection.getTopNodes() : selection.getNodes(); } @@ -215,7 +216,7 @@ export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> { } render() { - const selecting = this.selecting; + const { selecting } = this; if (!selecting || selecting.length < 1) { return null; } diff --git a/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts b/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts index 895084878..7586bd17f 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts +++ b/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts @@ -1,7 +1,7 @@ import { EventEmitter } from 'events'; -import { ISimulatorHost, isSimulatorHost } from '../../simulator'; +import { ISimulatorHost } from '../../simulator'; import { Designer, Point } from '../../designer'; -import { setNativeSelection, cursor } from '@ali/lowcode-utils'; +import { cursor } from '@ali/lowcode-utils'; // import Cursor from './cursor'; // import Pages from './pages'; @@ -19,7 +19,7 @@ function makeEventsHandler( // } docs.add(sourceDoc); // if (sourceDoc !== topDoc || isDragEvent(boostEvent)) { - sensors.forEach((sim) => { + sensors.forEach(sim => { const sdoc = sim.contentDocument; if (sdoc) { docs.add(sdoc); @@ -28,32 +28,21 @@ function makeEventsHandler( // } return (handle: (sdoc: Document) => void) => { - docs.forEach((doc) => handle(doc)); + docs.forEach(doc => handle(doc)); }; } // 拖动缩放 export default class DragResizeEngine { private emitter: EventEmitter; + private dragResizing = false; - constructor(readonly designer: Designer) { + constructor(designer: Designer) { this.designer = designer; this.emitter = new EventEmitter(); } - private getMasterSensors(): ISimulatorHost[] { - return this.designer.project.documents - .map((doc) => { - // TODO: not use actived, - if (doc.actived && doc.simulator?.sensorAvailable) { - return doc.simulator; - } - return null; - }) - .filter(Boolean) as any; - } - isDragResizing() { return this.dragResizing; } @@ -83,14 +72,12 @@ export default class DragResizeEngine { const masterSensors = this.getMasterSensors(); const createResizeEvent = (e: MouseEvent | DragEvent): Point => { - const evt: any = {}; - const sourceDocument = e.view?.document; if (!sourceDocument || sourceDocument === document) { return e; } - const srcSim = masterSensors.find((sim) => sim.contentDocument === sourceDocument); + const srcSim = masterSensors.find(sim => sim.contentDocument === sourceDocument); if (srcSim) { return srcSim.viewport.toGlobalPoint(e); } @@ -99,7 +86,7 @@ export default class DragResizeEngine { const over = (e: MouseEvent) => { const handleEvents = makeEventsHandler(e, masterSensors); - handleEvents((doc) => { + handleEvents(doc => { doc.removeEventListener('mousemove', move, true); doc.removeEventListener('mouseup', over, true); }); @@ -114,7 +101,7 @@ export default class DragResizeEngine { node = boost(e); startEvent = createResizeEvent(e); const handleEvents = makeEventsHandler(e, masterSensors); - handleEvents((doc) => { + handleEvents(doc => { doc.addEventListener('mousemove', move, true); doc.addEventListener('mouseup', over, true); }); @@ -136,7 +123,9 @@ export default class DragResizeEngine { }; } - onResize(func: (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => any) { + onResize( + func: (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => any, + ) { this.emitter.on('resize', func); return () => { this.emitter.removeListener('resize', func); @@ -149,6 +138,18 @@ export default class DragResizeEngine { this.emitter.removeListener('resizeEnd', func); }; } + + private getMasterSensors(): ISimulatorHost[] { + return this.designer.project.documents + .map(doc => { + // TODO: not use actived, + if (doc.actived && doc.simulator?.sensorAvailable) { + return doc.simulator; + } + return null; + }) + .filter(Boolean) as any; + } } // new DragResizeEngine(); diff --git a/packages/designer/src/builtin-simulator/bem-tools/index.tsx b/packages/designer/src/builtin-simulator/bem-tools/index.tsx index c22951c2f..c8c3ff909 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/index.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/index.tsx @@ -15,7 +15,7 @@ export class BemTools extends Component<{ host: BuiltinSimulatorHost }> { } render() { - const host = this.props.host; + const { host } = this.props; const { scrollX, scrollY, scale } = host.viewport; return (
diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx b/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx index 90b65ecc8..6ed6ef93d 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx @@ -1,15 +1,14 @@ import { Component } from 'react'; -import { computed, observer } from '@ali/lowcode-editor-core'; -import { SimulatorContext } from '../context'; +import { observer } from '@ali/lowcode-editor-core'; import { BuiltinSimulatorHost } from '../host'; import { DropLocation, Rect, isLocationChildrenDetail, LocationChildrenDetail, - isVertical + isVertical, } from '../../designer'; -import { ISimulatorHost, } from '../../simulator'; +import { ISimulatorHost } from '../../simulator'; import { ParentalNode } from '../../document'; import './insertion.less'; diff --git a/packages/designer/src/builtin-simulator/create-simulator.ts b/packages/designer/src/builtin-simulator/create-simulator.ts index ab20d4fa1..d517879b6 100644 --- a/packages/designer/src/builtin-simulator/create-simulator.ts +++ b/packages/designer/src/builtin-simulator/create-simulator.ts @@ -8,8 +8,8 @@ import { isAssetItem, AssetType, assetItem, -} from '@ali/lowcode-utils'; -import { isCSSUrl } from '@ali/lowcode-utils'; + isCSSUrl } from '@ali/lowcode-utils'; + import { BuiltinSimulatorRenderer } from './renderer'; export function createSimulator( @@ -65,7 +65,7 @@ export function createSimulator( const styleFrags = Object.keys(styles) .map((key) => { - return styles[key].join('\n') + ``; + return `${styles[key].join('\n') }`; }) .join(''); const scriptFrags = Object.keys(scripts) diff --git a/packages/designer/src/builtin-simulator/host-view.tsx b/packages/designer/src/builtin-simulator/host-view.tsx index 4b418ead0..4c3dda73e 100644 --- a/packages/designer/src/builtin-simulator/host-view.tsx +++ b/packages/designer/src/builtin-simulator/host-view.tsx @@ -2,7 +2,6 @@ import { Component } from 'react'; import { observer } from '@ali/lowcode-editor-core'; import { BuiltinSimulatorHost, BuiltinSimulatorProps } from './host'; import { DocumentModel } from '../document'; -import { SimulatorContext } from './context'; import { BemTools } from './bem-tools'; import './host.less'; @@ -22,25 +21,29 @@ type SimulatorHostProps = BuiltinSimulatorProps & { export class BuiltinSimulatorHostView extends Component { readonly host: BuiltinSimulatorHost; + constructor(props: any) { super(props); const { documentContext } = this.props; this.host = (documentContext.simulator as BuiltinSimulatorHost) || new BuiltinSimulatorHost(documentContext); this.host.setProps(this.props); } + shouldComponentUpdate(nextProps: BuiltinSimulatorProps) { this.host.setProps(nextProps); return false; } + componentDidMount() { if (this.props.onMount) { this.props.onMount(this.host); } } + render() { return (
- {/*progressing.visible ? : null*/} + {/* progressing.visible ? : null */}
); @@ -73,7 +76,7 @@ class Canvas extends Component<{ host: BuiltinSimulatorHost }> { class Content extends Component<{ host: BuiltinSimulatorHost }> { render() { const sim = this.props.host; - const viewport = sim.viewport; + const { viewport } = sim; const frameStyle = { transform: `scale(${viewport.scale})`, height: viewport.contentHeight, diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 01924b4e6..4679b3338 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -60,6 +60,7 @@ export interface BuiltinSimulatorProps { const defaultSimulatorUrl = (() => { const publicPath = getPublicPath(); let urls; + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, prefix = '', dev] = /^(.+?)(\/js)?\/?$/.exec(publicPath) || []; if (dev) { urls = [`${prefix}/css/react-simulator-renderer.css`, `${prefix}/js/react-simulator-renderer.js`]; @@ -74,6 +75,7 @@ const defaultSimulatorUrl = (() => { const defaultRaxSimulatorUrl = (() => { const publicPath = getPublicPath(); let urls; + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, prefix = '', dev] = /^(.+?)(\/js)?\/?$/.exec(publicPath) || []; if (dev) { urls = [`${prefix}/css/rax-simulator-renderer.css`, `${prefix}/js/rax-simulator-renderer.js`]; @@ -144,18 +146,21 @@ export class BuiltinSimulatorHost implements ISimulatorHost { doc.removeEventListener('mouseup', checkSelect, true); if (!isShaken(downEvent, e)) { - const id = node.id; + const { id } = node; designer.activeTracker.track({ node, instance: nodeInst?.instance }); if (isMulti && !isRootNode(node) && selection.has(id)) { selection.remove(id); @@ -411,12 +421,13 @@ export class BuiltinSimulatorHost implements ISimulatorHost void; + /** * 设置悬停处理 */ setupDetecting() { const doc = this.contentDocument!; - const detecting = this.document.designer.detecting; + const { detecting } = this.document.designer; const hover = (e: MouseEvent) => { if (!detecting.enable) { return; @@ -448,6 +459,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost(); + setInstance(id: string, instances: ComponentInstance[] | null) { if (instances == null) { this.instancesMap.delete(id); @@ -585,14 +596,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost last.r) { last.r = rect.right; - computed = true; + _computed = true; } if (rect.bottom > last.b) { last.b = rect.bottom; - computed = true; + _computed = true; } } if (last) { const r: any = new DOMRect(last.x, last.y, last.r - last.x, last.b - last.y); r.elements = elements; - r.computed = computed; + r.computed = _computed; return r; } @@ -719,10 +730,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost bounds.bottom) { scroll = true; } - }*/ + } */ } else { /* const rect = this.document.computeRect(node); @@ -768,7 +780,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost width ? rect.left > right || rect.right < left : rect.left < left || rect.right > right) { opt.left = Math.min(rect.left + rect.width / 2 + sl - left - width / 2, scrollWidth - width); scroll = true; - }*/ + } */ } if (scroll && this.scroller) { @@ -783,18 +795,21 @@ export class BuiltinSimulatorHost implements ISimulatorHost 1 - ? instances.find((inst) => this.getClosestNodeInstance(inst, container.id)?.instance === containerInstance) + ? instances.find((_inst) => this.getClosestNodeInstance(_inst, container.id)?.instance === containerInstance) : instances[0] : null; const rect = inst ? this.computeComponentInstanceRect(inst, node.componentMeta.rootSelector) : null; @@ -1014,7 +1031,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost(); if (isDragNodeObject(dragObject)) { - const nodes = dragObject.nodes; + const { nodes } = dragObject; let i = nodes.length; let p: any = container; while (i-- > 0) { @@ -1139,7 +1156,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost { matched = rule(target); - return matched ? true : false; + return !!matched; }); if (matched) { propTarget = matched.propTarget; @@ -79,15 +81,15 @@ export class LiveEditing { } } - if (!propTarget) { - // 自动纯文本编辑满足一下情况: - // 1. children 内容都是 Leaf 且都是文本(一期) - // 2. DOM 节点是单层容器,子集都是文本节点 (已满足) - const isAllText = node.children?.every(item => { - return item.isLeaf() && item.getProp('children')?.type === 'literal'; - }); - // TODO: - } + // if (!propTarget) { + // // 自动纯文本编辑满足一下情况: + // // 1. children 内容都是 Leaf 且都是文本(一期) + // // 2. DOM 节点是单层容器,子集都是文本节点 (已满足) + // const isAllText = node.children?.every(item => { + // return item.isLeaf() && item.getProp('children')?.type === 'literal'; + // }); + // // TODO: + // } if (propTarget && setterPropElement) { const prop = node.getProp(propTarget, true)!; @@ -119,8 +121,10 @@ export class LiveEditing { console.info(e.code); switch (e.code) { case 'Enter': + break; // TODO: check is richtext? case 'Escape': + break; case 'Tab': setterPropElement?.blur(); } @@ -128,7 +132,7 @@ export class LiveEditing { // enter // tab }; - const focusout = (e: FocusEvent) => { + const focusout = (/* e: FocusEvent */) => { this.saveAndDispose(); }; setterPropElement.addEventListener('focusout', focusout); @@ -147,8 +151,6 @@ export class LiveEditing { // TODO: process enter | esc events & joint the FocusTracker // TODO: upward testing for b/i/a html elements - - } get editing() { @@ -156,7 +158,9 @@ export class LiveEditing { } private _dispose?: () => void; + private _save?: () => void; + saveAndDispose() { if (this._save) { this._save(); diff --git a/packages/designer/src/builtin-simulator/node-selector/index.tsx b/packages/designer/src/builtin-simulator/node-selector/index.tsx index 554ef78e7..af1f6cb14 100644 --- a/packages/designer/src/builtin-simulator/node-selector/index.tsx +++ b/packages/designer/src/builtin-simulator/node-selector/index.tsx @@ -58,17 +58,20 @@ export default class InstanceNodeSelector extends React.Component (_: any, flag = true) => { if (node && typeof node.hover === 'function') { node.hover(flag); } }; + onMouseOut = (node: Node) => (_: any, flag = false) => { if (node && typeof node.hover === 'function') { node.hover(flag); } }; - renderNodes = (node: Node) => { + + renderNodes = (/* node: Node */) => { const nodes = this.state.parentNodes || []; const children = nodes.map((node, key) => { return ( diff --git a/packages/designer/src/builtin-simulator/resource-consumer.ts b/packages/designer/src/builtin-simulator/resource-consumer.ts index bf25d9068..38a1aa181 100644 --- a/packages/designer/src/builtin-simulator/resource-consumer.ts +++ b/packages/designer/src/builtin-simulator/resource-consumer.ts @@ -21,16 +21,19 @@ export type RendererConsumer = (renderer: BuiltinSimulatorRenderer, data: T) export default class ResourceConsumer { private emitter = new EventEmitter(); + @obx.ref private _data: T | typeof UNSET = UNSET; private _providing?: () => void; + + private _consuming?: () => void; + constructor(provider: () => T, private consumer?: RendererConsumer) { this._providing = autorun(() => { this._data = provider(); }); } - private _consuming?: () => void; consume(consumerOrRenderer: BuiltinSimulatorRenderer | ((data: T) => any)) { if (this._consuming) { return; @@ -72,6 +75,7 @@ export default class ResourceConsumer { } private _firstConsumed = false; + private resovleFirst?: () => void; waitFirstConsume(): Promise { diff --git a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts index 0e0078be6..3bcf9d6d4 100644 --- a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts +++ b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts @@ -16,6 +16,7 @@ export const primitiveTypes = [ 'any', ]; +// eslint-disable-next-line @typescript-eslint/ban-types function makeRequired(propType: any, lowcodeType: string | object) { function lowcodeCheckTypeIsRequired(...rest: any[]) { return propType.isRequired(...rest); @@ -32,6 +33,7 @@ function makeRequired(propType: any, lowcodeType: string | object) { return lowcodeCheckTypeIsRequired; } +// eslint-disable-next-line @typescript-eslint/ban-types function define(propType: any = PropTypes.any, lowcodeType: string | object = {}) { if (!propType._inner && propType.name !== 'lowcodeCheckType') { propType.lowcodeType = lowcodeType; @@ -136,7 +138,7 @@ export function parseProps(component: any): PropConfig[] { Object.keys(propTypes).forEach(key => { const propTypeItem = propTypes[key]; const defaultValue = defaultProps[key]; - const lowcodeType = propTypeItem.lowcodeType; + const { lowcodeType } = propTypeItem; if (lowcodeType) { result[key] = { name: key, diff --git a/packages/designer/src/builtin-simulator/utils/path.ts b/packages/designer/src/builtin-simulator/utils/path.ts index c9a32e353..49f0c71af 100644 --- a/packages/designer/src/builtin-simulator/utils/path.ts +++ b/packages/designer/src/builtin-simulator/utils/path.ts @@ -158,7 +158,7 @@ export function joinPath(...segments: string[]) { if (path === '') { path += seg; } else { - path += '/' + seg; + path += `/${ seg}`; } } } diff --git a/packages/designer/src/builtin-simulator/utils/throttle.ts b/packages/designer/src/builtin-simulator/utils/throttle.ts index c426837d6..9dcf78c01 100644 --- a/packages/designer/src/builtin-simulator/utils/throttle.ts +++ b/packages/designer/src/builtin-simulator/utils/throttle.ts @@ -1,5 +1,6 @@ const useRAF = typeof requestAnimationFrame === 'function'; +// eslint-disable-next-line @typescript-eslint/ban-types export function throttle(func: Function, delay: number) { let lastArgs: any; let lastThis: any; diff --git a/packages/designer/src/builtin-simulator/viewport.ts b/packages/designer/src/builtin-simulator/viewport.ts index 900620377..523933cc4 100644 --- a/packages/designer/src/builtin-simulator/viewport.ts +++ b/packages/designer/src/builtin-simulator/viewport.ts @@ -4,7 +4,9 @@ import { AutoFit, IViewport } from '../simulator'; export default class Viewport implements IViewport { @obx.ref private rect?: DOMRect; + private _bounds?: DOMRect; + get bounds(): DOMRect { if (this._bounds) { return this._bounds; @@ -17,12 +19,13 @@ export default class Viewport implements IViewport { } get contentBounds(): DOMRect { - const bounds = this.bounds; - const scale = this.scale; + const { bounds } = this; + const { scale } = this; return new DOMRect(0, 0, bounds.width / scale, bounds.height / scale); } private viewportElement?: HTMLElement; + mount(viewportElement: HTMLElement | null) { if (!viewportElement || this.viewportElement === viewportElement) { return; @@ -67,7 +70,7 @@ export default class Viewport implements IViewport { } } - @obx.ref private _scale: number = 1; + @obx.ref private _scale = 1; /** * 缩放比例 @@ -87,6 +90,7 @@ export default class Viewport implements IViewport { } @obx.ref private _contentWidth: number | AutoFit = AutoFit; + @obx.ref private _contentHeight: number | AutoFit = AutoFit; @computed get contentHeight(): number | AutoFit { @@ -106,15 +110,19 @@ export default class Viewport implements IViewport { } @obx.ref private _scrollX = 0; + @obx.ref private _scrollY = 0; + get scrollX() { return this._scrollX; } + get scrollY() { return this._scrollY; } private _scrollTarget?: ScrollTarget; + /** * 滚动对象 */ @@ -123,6 +131,7 @@ export default class Viewport implements IViewport { } @obx private _scrolling = false; + get scrolling(): boolean { return this._scrolling; } diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index f871ba5de..c14133262 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -13,7 +13,7 @@ import { FieldConfig, } from '@ali/lowcode-types'; import { computed } from '@ali/lowcode-editor-core'; -import { Node, ParentalNode, TransformStage } from './document'; +import { Node, ParentalNode } from './document'; import { Designer } from './designer'; import { intlNode } from './locale'; import { IconContainer } from './icons/container'; @@ -63,45 +63,62 @@ function buildFilter(rule?: string | string[] | RegExp | NestingFilter) { export class ComponentMeta { readonly isComponentMeta = true; + private _npm?: NpmInfo; + get npm() { return this._npm; } + private _componentName?: string; + get componentName(): string { return this._componentName!; } + private _isContainer?: boolean; + get isContainer(): boolean { return this._isContainer! || this.isRootComponent(); } + private _isModal?: boolean; + get isModal(): boolean { return this._isModal!; } + private _descriptor?: string; + get descriptor(): string | undefined { return this._descriptor; } + private _rootSelector?: string; + get rootSelector(): string | undefined { return this._rootSelector; } + private _transformedMetadata?: TransformedComponentMetadata; + get configure() { const config = this._transformedMetadata?.configure; return config?.combined || config?.props || []; } private _liveTextEditing?: LiveTextEditingConfig[]; + get liveTextEditing() { return this._liveTextEditing; } private parentWhitelist?: NestingFilter | null; + private childWhitelist?: NestingFilter | null; private _title?: TitleContent; + get title(): string | I18nData | ReactElement { // TODO: 标记下。这块需要康师傅加一下API,页面正常渲染。 // string | i18nData | ReactElement @@ -123,6 +140,7 @@ export class ComponentMeta { } private _acceptable?: boolean; + get acceptable(): boolean { return this._acceptable!; } @@ -145,7 +163,7 @@ export class ComponentMeta { // 额外转换逻辑 this._transformedMetadata = this.transformMetadata(metadata); - const title = this._transformedMetadata.title; + const { title } = this._transformedMetadata; if (title) { this._title = typeof title === 'string' @@ -182,8 +200,8 @@ export class ComponentMeta { const { component } = configure; if (component) { - this._isContainer = component.isContainer ? true : false; - this._isModal = component.isModal ? true : false; + this._isContainer = !!component.isContainer; + this._isModal = !!component.isModal; this._descriptor = component.descriptor; this._rootSelector = component.rootSelector; if (component.nestingRule) { @@ -208,11 +226,12 @@ export class ComponentMeta { return result as any; } - isRootComponent(includeBlock: boolean = true) { + isRootComponent(includeBlock = true) { return this.componentName === 'Page' || this.componentName === 'Component' || (includeBlock && this.componentName === 'Block'); } @computed get availableActions() { + // eslint-disable-next-line prefer-const let { disableBehaviors, actions } = this._transformedMetadata?.configure.component || {}; const disabled = ensureAList(disableBehaviors) || (this.isRootComponent(false) ? ['copy', 'remove'] : null); actions = builtinComponentActions.concat(this.designer.getGlobalComponentActions() || [], actions || []); @@ -313,6 +332,7 @@ registerMetadataTransducer((metadata) => { if (!component.nestingRule) { let m; // uri match xx.Group set subcontrolling: true, childWhiteList + // eslint-disable-next-line no-cond-assign if ((m = /^(.+)\.Group$/.exec(componentName))) { // component.subControlling = true; if (!component.nestingRule) { @@ -320,16 +340,16 @@ registerMetadataTransducer((metadata) => { childWhitelist: [`${m[1]}`], }; } - } - // uri match xx.Node set selfControlled: false, parentWhiteList - else if ((m = /^(.+)\.Node$/.exec(componentName))) { + // eslint-disable-next-line no-cond-assign + } else if ((m = /^(.+)\.Node$/.exec(componentName))) { + // uri match xx.Node set selfControlled: false, parentWhiteList // component.selfControlled = false; component.nestingRule = { parentWhitelist: [`${m[1]}`, componentName], }; - } - // uri match .Item .Node .Option set parentWhiteList - else if ((m = /^(.+)\.(Item|Node|Option)$/.exec(componentName))) { + // eslint-disable-next-line no-cond-assign + } else if ((m = /^(.+)\.(Item|Node|Option)$/.exec(componentName))) { + // uri match .Item .Node .Option set parentWhiteList component.nestingRule = { parentWhitelist: [`${m[1]}`], }; diff --git a/packages/designer/src/designer/active-tracker.ts b/packages/designer/src/designer/active-tracker.ts index 078969b65..7b9509251 100644 --- a/packages/designer/src/designer/active-tracker.ts +++ b/packages/designer/src/designer/active-tracker.ts @@ -1,6 +1,6 @@ import { EventEmitter } from 'events'; import { LocationDetail } from './location'; -import { Node, isNode } from '../document/node/node'; +import { Node, isNode } from '../document/node/node'; import { ComponentInstance } from '../simulator'; import { obx } from '@ali/lowcode-editor-core'; diff --git a/packages/designer/src/designer/builtin-hotkey.ts b/packages/designer/src/designer/builtin-hotkey.ts index 13bea87f4..bc8a698df 100644 --- a/packages/designer/src/designer/builtin-hotkey.ts +++ b/packages/designer/src/designer/builtin-hotkey.ts @@ -107,7 +107,7 @@ hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => { let selected = doc.selection.getTopNodes(true); selected = selected.filter((node) => { return node.canPerformAction('copy'); - }) + }); if (!selected || selected.length < 1) { return; } @@ -242,11 +242,10 @@ hotkey.bind(['option+left', 'option+right'], (e, action) => { parent.insertAfter(firstNode, silbing); } firstNode?.select(); - return; } }); -hotkey.bind(['option+up'], (e, action) => { +hotkey.bind(['option+up'], (e) => { const designer = focusing.focusDesigner; const doc = designer?.currentDocument; if (isFormEvent(e) || !doc) { @@ -275,7 +274,6 @@ hotkey.bind(['option+up'], (e, action) => { parent.insertBefore(firstNode, silbing); } firstNode?.select(); - return; } else { const place = parent.getSuitablePlace(firstNode, null); // upwards if (place) { @@ -285,7 +283,7 @@ hotkey.bind(['option+up'], (e, action) => { } }); -hotkey.bind(['option+down'], (e, action) => { +hotkey.bind(['option+down'], (e) => { const designer = focusing.focusDesigner; const doc = designer?.currentDocument; if (isFormEvent(e) || !doc) { @@ -315,7 +313,6 @@ hotkey.bind(['option+down'], (e, action) => { parent.insertAfter(firstNode, silbing); } firstNode?.select(); - return; } else { const place = parent.getSuitablePlace(firstNode, null); // upwards if (place) { diff --git a/packages/designer/src/designer/clipboard.ts b/packages/designer/src/designer/clipboard.ts index 921117f09..dcaa21c0f 100644 --- a/packages/designer/src/designer/clipboard.ts +++ b/packages/designer/src/designer/clipboard.ts @@ -1,5 +1,5 @@ function getDataFromPasteEvent(event: ClipboardEvent) { - const clipboardData = event.clipboardData; + const { clipboardData } = event; if (!clipboardData) { return null; } @@ -14,7 +14,7 @@ function getDataFromPasteEvent(event: ClipboardEvent) { return data; } else if (data.componentName) { return { - componentsTree: [ data ] + componentsTree: [data], }; } } catch (error) { @@ -34,12 +34,13 @@ function getDataFromPasteEvent(event: ClipboardEvent) { return { code: clipboardData.getData('text/plain'), maps: {}, - };*/ + }; */ } } class Clipboard { private copyPasters: HTMLTextAreaElement[] = []; + private waitFn?: (data: any, e: ClipboardEvent) => void; isCopyPasteEvent(e: Event) { diff --git a/packages/designer/src/designer/designer-view.tsx b/packages/designer/src/designer/designer-view.tsx index fa601a994..6ce25f606 100644 --- a/packages/designer/src/designer/designer-view.tsx +++ b/packages/designer/src/designer/designer-view.tsx @@ -24,7 +24,7 @@ export class DesignerView extends Component !!item).join('-') || parent?.componentMeta?.componentName || ''; + // eslint-disable-next-line no-unused-expressions this.editor?.emit('designer.drag', { time: (endTime - startTime).toFixed(2), selected: nodes @@ -139,6 +144,7 @@ export class Designer { if (!n) { return; } + // eslint-disable-next-line no-shadow const npm = n?.componentMeta?.npm; return ( [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || @@ -173,7 +179,7 @@ export class Designer { } this.postEvent('selection.change', this.currentSelection); if (this.currentSelection) { - const currentSelection = this.currentSelection; + const { currentSelection } = this; selectionDispose = currentSelection.onSelectionChange(() => { this.postEvent('selection.change', currentSelection); }); @@ -187,7 +193,7 @@ export class Designer { } this.postEvent('history.change', this.currentHistory); if (this.currentHistory) { - const currentHistory = this.currentHistory; + const { currentHistory } = this; historyDispose = currentHistory.onStateChange(() => { this.postEvent('history.change', currentHistory); }); @@ -217,6 +223,7 @@ export class Designer { get dropLocation() { return this._dropLocation; } + /** * 创建插入位置,考虑放到 dragon 中 */ @@ -246,6 +253,7 @@ export class Designer { } private oobxList: OffsetObserver[] = []; + createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null { const oobx = createOffsetObserver(nodeInstance); this.clearOobxList(); @@ -302,6 +310,7 @@ export class Designer { } private props?: DesignerProps; + setProps(nextProps: DesignerProps) { const props = this.props ? { ...this.props, ...nextProps } : nextProps; if (this.props) { @@ -380,6 +389,7 @@ export class Designer { } @obx.val private _componentMetasMap = new Map(); + private _lostComponentMetasMap = new Map(); private buildComponentMetasMap(metas: ComponentMetadata[]) { @@ -451,6 +461,7 @@ export class Designer { } private propsReducers = new Map(); + transformProps(props: CompositeObject | PropsList, node: Node, stage: TransformStage) { if (Array.isArray(props)) { // current not support, make this future @@ -464,7 +475,7 @@ export class Designer { return reducers.reduce((xprops, reducer) => { try { - return reducer(xprops, node) + return reducer(xprops, node); } catch (e) { // todo: add log console.warn(e); diff --git a/packages/designer/src/designer/detecting.ts b/packages/designer/src/designer/detecting.ts index 11492f937..273bad503 100644 --- a/packages/designer/src/designer/detecting.ts +++ b/packages/designer/src/designer/detecting.ts @@ -3,18 +3,22 @@ import { Node, DocumentModel } from '../document'; export class Detecting { @obx.ref private _enable = true; + get enable() { return this._enable; } + set enable(flag: boolean) { this._enable = flag; if (!flag) { this._current = null; } } + @obx.ref xRayMode = false; @obx.ref private _current: Node | null = null; + get current() { return this._current; } diff --git a/packages/designer/src/designer/drag-ghost/index.tsx b/packages/designer/src/designer/drag-ghost/index.tsx index d32ee526e..d54dd9bb0 100644 --- a/packages/designer/src/designer/drag-ghost/index.tsx +++ b/packages/designer/src/designer/drag-ghost/index.tsx @@ -9,9 +9,13 @@ type offBinding = () => any; @observer export default class DragGhost extends Component<{ designer: Designer }> { private dispose: offBinding[] = []; + @obx.ref private dragObject: DragObject | null = null; + @obx.ref private x = 0; + @obx.ref private y = 0; + private dragon = this.props.designer.dragon; constructor(props: any) { @@ -48,7 +52,7 @@ export default class DragGhost extends Component<{ designer: Designer }> { } renderGhostGroup() { - const dragObject = this.dragObject; + const { dragObject } = this; if (isDragNodeObject(dragObject)) { return dragObject.nodes.map(node => { const ghost = ( diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index 60ecef509..e8a696138 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -77,6 +77,7 @@ export interface ISensor { export type DragObject = DragNodeObject | DragNodeDataObject | DragAnyObject; export enum DragObjectType { + // eslint-disable-next-line no-shadow Node = 'node', NodeData = 'nodedata', } @@ -191,19 +192,20 @@ export class Dragon { * current actived sensor, 可用于感应区高亮 */ @obx.ref private _activeSensor: ISensor | undefined; + get activeSensor(): ISensor | undefined { return this._activeSensor; } @obx.ref private _dragging = false; + get dragging(): boolean { return this._dragging; } private emitter = new EventEmitter(); - constructor(readonly designer: Designer) { - } + constructor(readonly designer: Designer) {} /** * Quick listen a shell(container element) drag behavior @@ -238,7 +240,7 @@ export class Dragon { * @param boostEvent 拖拽初始时事件 */ boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent) { - const designer = this.designer; + const { designer } = this; const masterSensors = this.getMasterSensors(); const handleEvents = makeEventsHandler(boostEvent, masterSensors); const newBie = !isDragNodeObject(dragObject); diff --git a/packages/designer/src/designer/index.ts b/packages/designer/src/designer/index.ts index 8bcf028c9..79982c45b 100644 --- a/packages/designer/src/designer/index.ts +++ b/packages/designer/src/designer/index.ts @@ -1,4 +1,5 @@ import './builtin-hotkey'; + export * from './designer'; export * from './designer-view'; export * from './dragon'; diff --git a/packages/designer/src/designer/location.ts b/packages/designer/src/designer/location.ts index f26890357..eec210b35 100644 --- a/packages/designer/src/designer/location.ts +++ b/packages/designer/src/designer/location.ts @@ -127,9 +127,13 @@ export function getWindow(elem: Element | Document): Window { export class DropLocation { readonly target: ParentalNode; + readonly detail: LocationDetail; + readonly event: LocateEvent; + readonly source: string; + get document(): DocumentModel { return this.target.document; } diff --git a/packages/designer/src/designer/offset-observer.ts b/packages/designer/src/designer/offset-observer.ts index 4f72691af..7b4b8bebf 100644 --- a/packages/designer/src/designer/offset-observer.ts +++ b/packages/designer/src/designer/offset-observer.ts @@ -7,14 +7,23 @@ export class OffsetObserver { readonly id = uniqueId('oobx'); private lastOffsetLeft?: number; + private lastOffsetTop?: number; + private lastOffsetHeight?: number; + private lastOffsetWidth?: number; + @obx private _height = 0; + @obx private _width = 0; + @obx private _left = 0; + @obx private _top = 0; + @obx private _right = 0; + @obx private _bottom = 0; @computed get height() { @@ -42,6 +51,7 @@ export class OffsetObserver { } @obx hasOffset = false; + @computed get offsetLeft() { if (this.isRoot) { return this.viewport.scrollX * this.scale; @@ -51,6 +61,7 @@ export class OffsetObserver { } return this.lastOffsetLeft; } + @computed get offsetTop() { if (this.isRoot) { return this.viewport.scrollY * this.scale; @@ -60,12 +71,14 @@ export class OffsetObserver { } return this.lastOffsetTop; } + @computed get offsetHeight() { if (!this.viewport.scrolling || this.lastOffsetHeight == null) { this.lastOffsetHeight = this.isRoot ? this.viewport.height : this.height; } return this.lastOffsetHeight; } + @computed get offsetWidth() { if (!this.viewport.scrolling || this.lastOffsetWidth == null) { this.lastOffsetWidth = this.isRoot ? this.viewport.width : this.width; @@ -78,8 +91,11 @@ export class OffsetObserver { } private pid: number | undefined; + readonly viewport: IViewport; + private isRoot: boolean; + readonly node: Node; readonly compute: () => void; @@ -109,18 +125,17 @@ export class OffsetObserver { if (!rect) { this.hasOffset = false; - } else { - if (!this.viewport.scrolling || !this.hasOffset) { - this._height = rect.height; - this._width = rect.width; - this._left = rect.left; - this._top = rect.top; - this._right = rect.right; - this._bottom = rect.bottom; - this.hasOffset = true; - } + } else if (!this.viewport.scrolling || !this.hasOffset) { + this._height = rect.height; + this._width = rect.width; + this._left = rect.left; + this._top = rect.top; + this._right = rect.right; + this._bottom = rect.bottom; + this.hasOffset = true; } - this.pid = pid = (window as any).requestIdleCallback(compute); + this.pid = (window as any).requestIdleCallback(compute); + pid = this.pid; }; this.compute = compute; @@ -128,7 +143,8 @@ export class OffsetObserver { // try first compute(); // try second, ensure the dom mounted - this.pid = pid = (window as any).requestIdleCallback(compute); + this.pid = (window as any).requestIdleCallback(compute); + pid = this.pid; } purge() { diff --git a/packages/designer/src/designer/scroller.ts b/packages/designer/src/designer/scroller.ts index a7c93b91f..24070b306 100644 --- a/packages/designer/src/designer/scroller.ts +++ b/packages/designer/src/designer/scroller.ts @@ -4,9 +4,11 @@ export class ScrollTarget { get left() { return 'scrollX' in this.target ? this.target.scrollX : this.target.scrollLeft; } + get top() { return 'scrollY' in this.target ? this.target.scrollY : this.target.scrollTop; } + scrollTo(options: { left?: number; top?: number }) { this.target.scrollTo(options); } @@ -24,6 +26,7 @@ export class ScrollTarget { } private doe?: HTMLElement; + constructor(private target: Window | Element) { if (isWindow(target)) { this.doe = target.document.documentElement; @@ -50,6 +53,8 @@ export interface IScrollable { export class Scroller { private pid: number | undefined; + constructor(private scrollable: IScrollable) {} + get scrollTarget(): ScrollTarget | null { let target = this.scrollable.scrollTarget; if (!target) { @@ -62,19 +67,17 @@ export class Scroller { return target; } - constructor(private scrollable: IScrollable) {} - scrollTo(options: { left?: number; top?: number }) { this.cancel(); - const scrollTarget = this.scrollTarget; + const { scrollTarget } = this; if (!scrollTarget) { return; } let pid: number; - const left = scrollTarget.left; - const top = scrollTarget.top; + const { left } = scrollTarget; + const { top } = scrollTarget; const end = () => { this.cancel(); }; @@ -106,20 +109,22 @@ export class Scroller { scrollTarget.scrollTo(opt); if (time < 1) { - this.pid = pid = requestAnimationFrame(animate); + this.pid = requestAnimationFrame(animate); + pid = this.pid; } else { end(); } }; - this.pid = pid = requestAnimationFrame(animate); + this.pid = requestAnimationFrame(animate); + pid = this.pid; } scrolling(point: { globalX: number; globalY: number }) { this.cancel(); const { bounds, scale = 1 } = this.scrollable; - const scrollTarget = this.scrollTarget; + const { scrollTarget } = this; if (!scrollTarget || !bounds) { return; } diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index a70e83bb6..9ed826c06 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -19,29 +19,37 @@ function getSettingFieldCollectorKey(parent: SettingEntry, config: FieldConfig) export class SettingField extends SettingPropEntry implements SettingEntry { readonly isSettingField = true; + readonly isRequired: boolean; + readonly transducer: Transducer; + private _config: FieldConfig; + extraProps: FieldExtraProps; // ==== dynamic properties ==== private _title?: TitleContent; + get title() { // FIXME! intl return this._title || (typeof this.name === 'number' ? `项目 ${this.name}` : this.name); } + private _setter?: SetterType | DynamicSetter; + @computed get setter(): SetterType | null { if (!this._setter) { return null; } if (isDynamicSetter(this._setter)) { - return this._setter.call(this,this); + return this._setter.call(this, this); } return this._setter; } @obx.ref private _expanded = true; + get expanded(): boolean { return this._expanded; } @@ -62,7 +70,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { ...extraProps, }; this.isRequired = config.isRequired || (setter as any)?.isRequired; - this._expanded = extraProps?.defaultCollapsed ? false : true; + this._expanded = !extraProps?.defaultCollapsed; // initial items if (items && items.length > 0) { diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index 9c989411d..c219a3091 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -1,4 +1,4 @@ -import { obx, computed, autorun } from '@ali/lowcode-editor-core'; +import { obx, computed } from '@ali/lowcode-editor-core'; import { IEditor, isJSExpression } from '@ali/lowcode-types'; import { uniqueId } from '@ali/lowcode-utils'; import { SettingEntry } from './setting-entry'; @@ -10,24 +10,36 @@ import { EventEmitter } from 'events'; export class SettingPropEntry implements SettingEntry { // === static properties === readonly editor: IEditor; + readonly isSameComponent: boolean; + readonly isMultiple: boolean; + readonly isSingle: boolean; + readonly nodes: Node[]; + readonly componentMeta: ComponentMeta | null; + readonly designer: Designer; + readonly top: SettingEntry; + readonly isGroup: boolean; + readonly type: 'field' | 'group'; + readonly id = uniqueId('entry'); readonly emitter = new EventEmitter(); // ==== dynamic properties ==== @obx.ref private _name: string | number; + get name() { return this._name; } + @computed get path() { const path = this.parent.path.slice(); if (this.type === 'field') { @@ -133,7 +145,7 @@ export class SettingPropEntry implements SettingEntry { * 获取当前属性值 */ @computed getValue(): any { - let val: any = undefined; + let val: any; if (this.type === 'field') { val = this.parent.getPropValue(this.name); } @@ -271,6 +283,7 @@ export class SettingPropEntry implements SettingEntry { isIgnore() { return false; } + /* getConfig(configName?: K): IPropConfig[K] | IPropConfig { if (configName) { @@ -287,6 +300,7 @@ export class SettingPropEntry implements SettingEntry { } return ''; } + setVariableValue(value: string) { const v = this.getValue(); this.setValue({ @@ -295,6 +309,7 @@ export class SettingPropEntry implements SettingEntry { mock: isJSExpression(v) ? v.mock : v, }); } + setUseVariable(flag: boolean) { if (this.isUseVariable() === flag) { return; @@ -310,12 +325,15 @@ export class SettingPropEntry implements SettingEntry { }); } } + isUseVariable() { return isJSExpression(this.getValue()); } + get useVariable() { return this.isUseVariable(); } + getMockOrValue() { const v = this.getValue(); if (isJSExpression(v)) { diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts index 19c4c0fc9..507fc053c 100644 --- a/packages/designer/src/designer/setting/setting-top-entry.ts +++ b/packages/designer/src/designer/setting/setting-top-entry.ts @@ -2,7 +2,7 @@ import { EventEmitter } from 'events'; import { CustomView, isCustomView, IEditor } from '@ali/lowcode-types'; import { computed } from '@ali/lowcode-editor-core'; import { SettingEntry } from './setting-entry'; -import { SettingField, isSettingField } from './setting-field'; +import { SettingField } from './setting-field'; import { SettingPropEntry } from './setting-prop-entry'; import { Node } from '../../document'; import { ComponentMeta } from '../../component-meta'; @@ -17,12 +17,19 @@ function generateSessionId(nodes: Node[]) { export class SettingTopEntry implements SettingEntry { private emitter = new EventEmitter(); + private _items: Array = []; + private _componentMeta: ComponentMeta | null = null; - private _isSame: boolean = true; + + private _isSame = true; + private _settingFieldMap: { [prop: string]: SettingField } = {}; + readonly path = []; + readonly top = this; + readonly parent = this; get componentMeta() { @@ -55,7 +62,9 @@ export class SettingTopEntry implements SettingEntry { } readonly id: string; + readonly first: Node; + readonly designer: Designer; constructor(readonly editor: IEditor, readonly nodes: Node[]) { @@ -75,7 +84,7 @@ export class SettingTopEntry implements SettingEntry { private setupComponentMeta() { // todo: enhance compile a temp configure.compiled - const first = this.first; + const { first } = this; const meta = first.componentMeta; const l = this.nodes.length; let theSame = true; @@ -100,7 +109,7 @@ export class SettingTopEntry implements SettingEntry { const settingFieldMap: { [prop: string]: SettingField } = {}; const settingFieldCollector = (name: string | number, field: SettingField) => { settingFieldMap[name] = field; - } + }; this._items = this.componentMeta.configure.map((item) => { if (isCustomView(item)) { return item; @@ -209,18 +218,23 @@ export class SettingTopEntry implements SettingEntry { getStatus() { } + setStatus() { } + getChildren() { // this.nodes.map() } + getDOMNode() { } + getId() { return this.id; } + getPage() { return this.first.document; } @@ -231,6 +245,7 @@ export class SettingTopEntry implements SettingEntry { get node() { return this.getNode(); } + getNode() { return this.nodes[0]; } diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 9ec44fd1d..fab7bb49e 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -8,10 +8,8 @@ import { isDragNodeDataObject, DragNodeObject, DragNodeDataObject, DropLocation import { Node, insertChildren, insertChild, isNode, RootNode, ParentalNode } from './node/node'; import { Selection } from './selection'; import { History } from './history'; -import { TransformStage } from './node'; +import { TransformStage, ModalNodesManager } from './node'; import { uniqueId } from '@ali/lowcode-utils'; -import { ModalNodesManager } from './node'; -import { foreachReverse } from '../utils/tree'; export type GetDataType = T extends undefined ? NodeType extends { @@ -35,28 +33,37 @@ export class DocumentModel { * 根节点 类型有:Page/Component/Block */ rootNode: RootNode | null; + /** * 文档编号 */ id: string = uniqueId('doc'); + /** * 选区控制 */ readonly selection: Selection = new Selection(this); + /** * 操作记录控制 */ readonly history: History; + /** * 模态节点管理 */ readonly modalNodesManager: ModalNodesManager; private _nodesMap = new Map(); + @obx.val private nodes = new Set(); + private seqId = 0; + private _simulator?: ISimulatorHost; + private emitter: EventEmitter; + private rootNodeVisitorMap: { [visitorName: string]: any } = {}; /** @@ -84,7 +91,9 @@ export class DocumentModel { } private _modalNode?: ParentalNode; + private _blank?: boolean; + get modalNode() { return this._modalNode; } @@ -94,6 +103,7 @@ export class DocumentModel { } private inited = false; + constructor(readonly project: Project, schema?: RootSchema) { /* // TODO @@ -129,9 +139,11 @@ export class DocumentModel { } @obx.val private willPurgeSpace: Node[] = []; + addWillPurge(node: Node) { this.willPurgeSpace.push(node); } + removeWillPurge(node: Node) { const i = this.willPurgeSpace.indexOf(node); if (i > -1) { @@ -151,8 +163,8 @@ export class DocumentModel { nextId() { let id; do { - id = 'node_' + (this.id.slice(-10) + (++this.seqId).toString(36)).toLocaleLowerCase(); - } while (this.nodesMap.get(id)) + id = `node_${ (this.id.slice(-10) + (++this.seqId).toString(36)).toLocaleLowerCase()}`; + } while (this.nodesMap.get(id)); return id; } @@ -281,6 +293,7 @@ export class DocumentModel { } @obx.ref private _dropLocation: DropLocation | null = null; + /** * 内部方法,请勿调用 */ @@ -362,7 +375,7 @@ export class DocumentModel { * 提供给模拟器的参数 */ @computed get simulatorProps(): object { - let simulatorProps = this.designer.simulatorProps; + let { simulatorProps } = this.designer; if (typeof simulatorProps === 'function') { simulatorProps = simulatorProps(this); } @@ -392,6 +405,7 @@ export class DocumentModel { } @obx.ref private _opened = false; + @obx.ref private _suspensed = false; /** @@ -532,8 +546,8 @@ export class DocumentModel { const data = { componentsMap: this.getComponentsMap(extraComps), componentsTree: [node], - }; - return data; + }; + return data; } getHistory(): History { @@ -582,20 +596,21 @@ export class DocumentModel { acceptRootNodeVisitor( - visitorName: string = 'default', - visitorFn: (node: RootNode) => any ) { - let visitorResult = {}; - if (!visitorName) { - /* tslint:disable no-console */ - console.warn('Invalid or empty RootNodeVisitor name.'); - } - try { - visitorResult = visitorFn.call(this, this.rootNode); - this.rootNodeVisitorMap[visitorName] = visitorResult; - } catch (e) { - console.error('RootNodeVisitor is not valid.'); - } - return visitorResult; + visitorName = 'default', + visitorFn: (node: RootNode) => any, + ) { + let visitorResult = {}; + if (!visitorName) { + /* tslint:disable no-console */ + console.warn('Invalid or empty RootNodeVisitor name.'); + } + try { + visitorResult = visitorFn.call(this, this.rootNode); + this.rootNodeVisitorMap[visitorName] = visitorResult; + } catch (e) { + console.error('RootNodeVisitor is not valid.'); + } + return visitorResult; } getRootNodeVisitor(name: string) { @@ -606,7 +621,7 @@ export class DocumentModel { const componentsMap: ComponentMap[] = []; // 组件去重 const map: any = {}; - for (let node of this._nodesMap.values()) { + for (const node of this._nodesMap.values()) { const { componentName } = node || {}; if (!map[componentName] && node?.componentMeta?.npm?.package) { map[componentName] = true; @@ -657,7 +672,7 @@ export class DocumentModel { /** * @deprecated */ - onRefresh(func: () => void) { + onRefresh(/* func: () => void */) { console.warn('onRefresh method is deprecated'); } } diff --git a/packages/designer/src/document/document-view.tsx b/packages/designer/src/document/document-view.tsx index 2565f34fc..e5018f486 100644 --- a/packages/designer/src/document/document-view.tsx +++ b/packages/designer/src/document/document-view.tsx @@ -9,9 +9,10 @@ export class DocumentView extends Component<{ document: DocumentModel }> { shouldComponentUpdate() { return false; } + render() { const { document } = this.props; - const simulatorProps = document.simulatorProps; + const { simulatorProps } = document; const Simulator = document.designer.simulatorComponent || BuiltinSimulatorHostView; return (
any, private redoer: (data: NodeSchema) => void, private timeGap: number = 1000) { @@ -147,7 +152,7 @@ export class History { * | modified | redoable | undoable | */ getState(): number { - const cursor = this.session.cursor; + const { cursor } = this.session; let state = 7; // undoable ? if (cursor <= 0) { @@ -190,6 +195,7 @@ export class History { class Session { private _data: any; + private activedTimer: any; get data() { diff --git a/packages/designer/src/document/node/exclusive-group.ts b/packages/designer/src/document/node/exclusive-group.ts index cd4b46030..2f5a98cb2 100644 --- a/packages/designer/src/document/node/exclusive-group.ts +++ b/packages/designer/src/document/node/exclusive-group.ts @@ -8,22 +8,29 @@ import { intl } from '../../locale'; // if-else-if assoc conditionGroup value, should be the same level, and siblings, need renderEngine support export class ExclusiveGroup { readonly isExclusiveGroup = true; + readonly id = uniqueId('exclusive'); + @obx.val readonly children: Node[] = []; @obx private visibleIndex = 0; + @computed get document() { return this.visibleNode.document; } + @computed get zLevel() { return this.visibleNode.zLevel; } + @computed get length() { return this.children.length; } + @computed get visibleNode(): Node { return this.children[this.visibleIndex]; } + @computed get firstNode(): Node { return this.children[0]!; } diff --git a/packages/designer/src/document/node/modal-nodes-manager.ts b/packages/designer/src/document/node/modal-nodes-manager.ts index 563637101..b5cb96963 100644 --- a/packages/designer/src/document/node/modal-nodes-manager.ts +++ b/packages/designer/src/document/node/modal-nodes-manager.ts @@ -21,8 +21,11 @@ export class ModalNodesManager { public willDestroy: any; private page: DocumentModel; + private modalNodes: Node[]; + private nodeRemoveEvents: any; + private emitter: EventEmitter; constructor(page: DocumentModel) { @@ -44,8 +47,8 @@ export class ModalNodesManager { public getVisibleModalNode() { const visibleNode = this.modalNodes ? this.modalNodes.find((node: Node) => { - return node.getVisible(); - }) + return node.getVisible(); + }) : null; return visibleNode; } @@ -109,7 +112,7 @@ export class ModalNodesManager { private addNodeEvent(node: Node) { this.nodeRemoveEvents[node.getId()] = - node.onVisibleChange((flag) => { + node.onVisibleChange(() => { this.emitter.emit('visibleChange'); }); } diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index 3f4bc4a27..1a3be57f0 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -8,13 +8,13 @@ import { foreachReverse } from '../../utils/tree'; export class NodeChildren { @obx.val private children: Node[]; + private emitter = new EventEmitter(); constructor(readonly owner: ParentalNode, data: NodeData | NodeData[]) { this.children = (Array.isArray(data) ? data : [data]).map(child => { return this.owner.document.createNode(child); }); - } internalInitParent() { @@ -94,6 +94,7 @@ export class NodeChildren { } private purged = false; + /** * 回收销毁 */ @@ -114,6 +115,7 @@ export class NodeChildren { } this.children.splice(i, 1); } + /** * 删除一个节点 */ @@ -128,18 +130,18 @@ export class NodeChildren { node.internalSetParent(null, useMutator); try { node.purge(useMutator); - } catch(err) { + } catch (err) { console.error(err); } } - const document = node.document; + const { document } = node; document.unlinkNode(node); document.selection.remove(node.id); document.destroyNode(node); this.emitter.emit('change'); const i = this.children.indexOf(node); if (useMutator) { - this.reportModified(node, this.owner, {type: 'remove', removeIndex: i, removeNode: node}); + this.reportModified(node, this.owner, { type: 'remove', removeIndex: i, removeNode: node }); } if (i < 0) { return false; @@ -152,7 +154,7 @@ export class NodeChildren { * 插入一个节点,返回新长度 */ insert(node: Node, at?: number | null, useMutator = true): void { - const children = this.children; + const { children } = this; let index = at == null || at === -1 ? children.length : at; const i = children.indexOf(node); @@ -195,7 +197,7 @@ export class NodeChildren { } } if (node.prevSibling && node.nextSibling) { - const conditionGroup = node.prevSibling.conditionGroup; + const { conditionGroup } = node.prevSibling; // insert at condition group if (conditionGroup && conditionGroup === node.nextSibling.conditionGroup) { node.setConditionGroup(conditionGroup); @@ -236,7 +238,7 @@ export class NodeChildren { */ [Symbol.iterator](): { next(): { value: Node } } { let index = 0; - const children = this.children; + const { children } = this; const length = children.length || 0; return { next() { @@ -271,6 +273,7 @@ export class NodeChildren { return fn(child, index); }); } + every(fn: (item: Node, index: number) => any): boolean { return this.children.every((child, index) => fn(child, index)); } diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 230a7ba89..b2d2f4906 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -73,6 +73,7 @@ import { EventEmitter } from 'events'; */ export class Node { private emitter: EventEmitter; + /** * 是节点实例 */ @@ -94,28 +95,35 @@ export class Node { * * Slot 插槽节点,无 props,正常 children,有 slotArgs,有指令 */ readonly componentName: string; + /** * 属性抽象 */ props: Props; + protected _children?: NodeChildren; + /** * @deprecated */ private _addons: { [key: string]: { exportData: () => any; isProp: boolean; } } = {}; + @obx.ref private _parent: ParentalNode | null = null; + /** * 父级节点 */ get parent(): ParentalNode | null { return this._parent; } + /** * 当前节点子集 */ get children(): NodeChildren | null { return this._children || null; } + /** * 当前节点深度 */ @@ -165,18 +173,20 @@ export class Node { this.setupAutoruns(); } - this.settingEntry = this.document.designer.createSettingEntry([ this ]); + this.settingEntry = this.document.designer.createSettingEntry([this]); this.emitter = new EventEmitter(); } private initProps(props: any): any { return this.document.designer.transformProps(props, this, TransformStage.Init); } + private upgradeProps(props: any): any { return this.document.designer.transformProps(props, this, TransformStage.Upgrade); } private autoruns?: Array<() => void>; + private setupAutoruns() { const autoruns = this.componentMeta.getMetadata().experimental?.autoruns; if (!autoruns || autoruns.length < 1) { @@ -288,6 +298,7 @@ export class Node { } private _slotFor?: Prop | null = null; + internalSetSlotFor(slotFor: Prop | null | undefined) { this._slotFor = slotFor; } @@ -345,6 +356,7 @@ export class Node { } @obx.val _slots: Node[] = []; + @computed hasSlots() { return this._slots.length > 0; } @@ -354,6 +366,7 @@ export class Node { } @obx.ref private _conditionGroup: ExclusiveGroup | null = null; + get conditionGroup(): ExclusiveGroup | null { return this._conditionGroup; } @@ -418,7 +431,7 @@ export class Node { return false; } - wrapWith(schema: Schema) { + wrapWith(/* schema: Schema */) { // todo } @@ -507,7 +520,7 @@ export class Node { * 设置多个属性值,替换原有值 */ setProps(props?: PropsMap | PropsList | Props | null) { - if(props instanceof Props) { + if (props instanceof Props) { this.props = props; return; } @@ -531,7 +544,7 @@ export class Node { if (!this.parent) { return null; } - const index = this.index; + const { index } = this; if (index < 0) { return null; } @@ -545,7 +558,7 @@ export class Node { if (!this.parent) { return null; } - const index = this.index; + const { index } = this; if (index < 1) { return null; } @@ -680,6 +693,7 @@ export class Node { slotNode.internalSetParent(this as ParentalNode, true); this._slots.push(slotNode); } + /** * 当前node对应组件是否已注册可用 */ @@ -700,16 +714,18 @@ export class Node { } private purged = false; + /** * 是否已销毁 */ get isPurged() { return this.purged; } + /** * 销毁 */ - purge(useMutator = true) { + purge() { if (this.purged) { return; } @@ -731,9 +747,11 @@ export class Node { isEmpty(): boolean { return this.children ? this.children.isEmpty() : true; } + getChildren() { return this.children; } + getComponentName() { return this.componentName; } @@ -744,9 +762,11 @@ export class Node { insert(node: Node, ref?: Node, useMutator = true) { this.insertAfter(node, ref, useMutator); } + insertBefore(node: Node, ref?: Node, useMutator = true) { this.children?.insert(node, ref ? ref.index : null, useMutator); } + insertAfter(node: any, ref?: Node, useMutator = true) { if (!isNode(node)) { if (node.getComponentName) { @@ -759,21 +779,27 @@ export class Node { } this.children?.insert(node, ref ? ref.index + 1 : null, useMutator); } + getParent() { return this.parent; } + getId() { return this.id; } + getIndex() { return this.index; } + getNode() { return this; } + getRoot() { return this.document.rootNode; } + getProps() { return this.props; } @@ -802,6 +828,7 @@ export class Node { return this.status; } + /** * @deprecated */ @@ -814,6 +841,7 @@ export class Node { this.status[field] = flag; } } + /** * @deprecated */ @@ -824,6 +852,7 @@ export class Node { } return this.document.simulator?.findDOMNodes(instance)?.[0]; } + /** * @deprecated */ @@ -831,6 +860,7 @@ export class Node { console.warn('getPage is deprecated, use document instead'); return this.document; } + /** * @deprecated */ @@ -843,7 +873,7 @@ export class Node { const canDropIn = c.componentMeta?.prototype?.options?.canDropIn; if (typeof canDropIn === 'function') { return canDropIn(node); - } else if (typeof canDropIn === 'boolean'){ + } else if (typeof canDropIn === 'boolean') { return canDropIn; } return true; @@ -858,7 +888,7 @@ export class Node { if (this.isContainer()) { if (canDropIn === undefined || (typeof canDropIn === 'boolean' && canDropIn) || - (typeof canDropIn === 'function' && canDropIn(node))){ + (typeof canDropIn === 'function' && canDropIn(node))) { return { container: this, ref }; } } @@ -869,6 +899,7 @@ export class Node { return null; } + /** * @deprecated */ @@ -879,10 +910,11 @@ export class Node { } return this.getExtraProp(key)?.getValue(); } + /** * @deprecated */ - registerAddon(key: string, exportData: () => any, isProp: boolean = false) { + registerAddon(key: string, exportData: () => any, isProp = false) { // if (this._addons[key]) { // throw new Error(`node addon ${key} exist`); // } @@ -1034,7 +1066,7 @@ export function insertChildren( let index = at; let node: any; const results: Node[] = []; - // tslint:disable-next-line + // eslint-disable-next-line no-cond-assign while ((node = nodes.pop())) { node = insertChild(container, node, index, copy); results.push(node); diff --git a/packages/designer/src/document/node/props/prop-stash.ts b/packages/designer/src/document/node/props/prop-stash.ts index 1c62617ef..8e92956c7 100644 --- a/packages/designer/src/document/node/props/prop-stash.ts +++ b/packages/designer/src/document/node/props/prop-stash.ts @@ -6,6 +6,7 @@ import { Node } from '../node'; export type PendingItem = Prop[]; export class PropStash implements IPropParent { @obx.val private space: Set = new Set(); + @computed private get maps(): Map { const maps = new Map(); if (this.space.size > 0) { @@ -15,7 +16,9 @@ export class PropStash implements IPropParent { } return maps; } + private willPurge: () => void; + readonly owner: Node; constructor(readonly props: Props, write: (item: Prop) => void) { diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 5acfcc757..0671bffa9 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -20,6 +20,7 @@ export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | ' export class Prop implements IPropParent { readonly isProp = true; + readonly owner: Node; private stash: PropStash | undefined; @@ -28,12 +29,14 @@ export class Prop implements IPropParent { * 键值 */ @obx key: string | number | undefined; + /** * 扩展值 */ @obx spread: boolean; readonly props: Props; + readonly options: any; constructor( @@ -77,6 +80,7 @@ export class Prop implements IPropParent { readonly id = uniqueId('prop$'); @obx.ref private _type: ValueTypes = 'unset'; + /** * 属性类型 */ @@ -162,6 +166,7 @@ export class Prop implements IPropParent { } private _code: string | null = null; + /** * 获得表达式值 */ @@ -272,9 +277,11 @@ export class Prop implements IPropParent { } private _slotNode?: SlotNode; + get slotNode() { return this._slotNode; } + setAsSlot(data: JSSlot) { this._type = 'slot'; const slotSchema: SlotSchema = { @@ -287,7 +294,7 @@ export class Prop implements IPropParent { if (this._slotNode) { this._slotNode.import(slotSchema); } else { - const owner = this.props.owner; + const { owner } = this.props; this._slotNode = owner.document.createNode(slotSchema); owner.addSlot(this._slotNode); this._slotNode.internalSetSlotFor(this); @@ -336,7 +343,9 @@ export class Prop implements IPropParent { } @obx.val private _items: Prop[] | null = null; + @obx.val private _maps: Map | null = null; + @computed private get items(): Prop[] | null { let _items: any; untracked(() => { @@ -371,6 +380,7 @@ export class Prop implements IPropParent { } return _items; } + @computed private get maps(): Map | null { if (!this.items) { return null; @@ -382,7 +392,7 @@ export class Prop implements IPropParent { * 获取某个属性 * @param stash 如果不存在,临时获取一个待写入 */ - get(path: string | number, stash: boolean = true): Prop | null { + get(path: string | number, stash = true): Prop | null { const type = this._type; if (type !== 'map' && type !== 'list' && type !== 'unset' && !stash) { return null; @@ -524,7 +534,7 @@ export class Prop implements IPropParent { } items[key] = prop; } else if (this.maps) { - const maps = this.maps; + const { maps } = this; const orig = maps.get(key); if (orig) { // replace @@ -559,6 +569,7 @@ export class Prop implements IPropParent { } private purged = false; + /** * 回收销毁 */ @@ -584,7 +595,7 @@ export class Prop implements IPropParent { */ [Symbol.iterator](): { next(): { value: Prop } } { let index = 0; - const items = this.items; + const { items } = this; const length = items?.length || 0; return { next() { @@ -606,7 +617,7 @@ export class Prop implements IPropParent { * 遍历 */ forEach(fn: (item: Prop, key: number | string | undefined) => void): void { - const items = this.items; + const { items } = this; if (!items) { return; } @@ -620,7 +631,7 @@ export class Prop implements IPropParent { * 遍历 */ map(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { - const items = this.items; + const { items } = this; if (!items) { return null; } diff --git a/packages/designer/src/document/node/props/props.ts b/packages/designer/src/document/node/props/props.ts index e9c73ccd3..fa73e0190 100644 --- a/packages/designer/src/document/node/props/props.ts +++ b/packages/designer/src/document/node/props/props.ts @@ -23,7 +23,9 @@ export function getOriginalExtraKey(key: string): string { export class Props implements IPropParent { readonly id = uniqueId('props'); + @obx.val private items: Prop[] = []; + @computed private get maps(): Map { const maps = new Map(); if (this.items.length > 0) { @@ -151,41 +153,41 @@ export class Props implements IPropParent { query(path: string, stash = true): Prop | null { return this.get(path, stash); // todo: future support list search - let matchedLength = 0; - let firstMatched = null; - if (this.items) { - // target: a.b.c - // trys: a.b.c, a.b, a - let i = this.items.length; - while (i-- > 0) { - const expr = this.items[i]; - if (!expr.key) { - continue; - } - const name = String(expr.key); - if (name === path) { - // completely match - return expr; - } + // let matchedLength = 0; + // let firstMatched = null; + // if (this.items) { + // // target: a.b.c + // // trys: a.b.c, a.b, a + // let i = this.items.length; + // while (i-- > 0) { + // const expr = this.items[i]; + // if (!expr.key) { + // continue; + // } + // const name = String(expr.key); + // if (name === path) { + // // completely match + // return expr; + // } - // fisrt match - const l = name.length; - if (path.slice(0, l + 1) === `${name}.`) { - matchedLength = l; - firstMatched = expr; - } - } - } + // // fisrt match + // const l = name.length; + // if (path.slice(0, l + 1) === `${name}.`) { + // matchedLength = l; + // firstMatched = expr; + // } + // } + // } - let ret = null; - if (firstMatched) { - ret = firstMatched.get(path.slice(matchedLength + 1), true); - } - if (!ret && stash) { - return this.stash.get(path); - } + // let ret = null; + // if (firstMatched) { + // ret = firstMatched.get(path.slice(matchedLength + 1), true); + // } + // if (!ret && stash) { + // return this.stash.get(path); + // } - return ret; + // return ret; } /** @@ -257,7 +259,7 @@ export class Props implements IPropParent { */ [Symbol.iterator](): { next(): { value: Prop } } { let index = 0; - const items = this.items; + const { items } = this; const length = items.length || 0; return { next() { @@ -300,6 +302,7 @@ export class Props implements IPropParent { } private purged = false; + /** * 回收销毁 */ diff --git a/packages/designer/src/document/node/props/value-to-source.ts b/packages/designer/src/document/node/props/value-to-source.ts index 40cbecd61..77f5db856 100644 --- a/packages/designer/src/document/node/props/value-to-source.ts +++ b/packages/designer/src/document/node/props/value-to-source.ts @@ -4,6 +4,7 @@ function propertyNameRequiresQuotes(propertyName: string) { worksWithoutQuotes: false, }; + // eslint-disable-next-line no-new-func new Function('ctx', `ctx.worksWithoutQuotes = {${propertyName}: true}['${propertyName}']`)(); return !context.worksWithoutQuotes; @@ -57,15 +58,15 @@ export function valueToSource( if (value instanceof Map) { return value.size ? `${indentString.repeat(indentLevel)}new Map(${valueToSource([...value], { - circularReferenceToken, - doubleQuote, - includeFunctions, - includeUndefinedProperties, - indentLevel, - indentString, - lineEnding, - visitedObjects: new Set([value, ...visitedObjects]), - }).substr(indentLevel * indentString.length)})` + circularReferenceToken, + doubleQuote, + includeFunctions, + includeUndefinedProperties, + indentLevel, + indentString, + lineEnding, + visitedObjects: new Set([value, ...visitedObjects]), + }).substr(indentLevel * indentString.length)})` : `${indentString.repeat(indentLevel)}new Map()`; } @@ -76,15 +77,15 @@ export function valueToSource( if (value instanceof Set) { return value.size ? `${indentString.repeat(indentLevel)}new Set(${valueToSource([...value], { - circularReferenceToken, - doubleQuote, - includeFunctions, - includeUndefinedProperties, - indentLevel, - indentString, - lineEnding, - visitedObjects: new Set([value, ...visitedObjects]), - }).substr(indentLevel * indentString.length)})` + circularReferenceToken, + doubleQuote, + includeFunctions, + includeUndefinedProperties, + indentLevel, + indentString, + lineEnding, + visitedObjects: new Set([value, ...visitedObjects]), + }).substr(indentLevel * indentString.length)})` : `${indentString.repeat(indentLevel)}new Set()`; } @@ -94,8 +95,7 @@ export function valueToSource( } const itemsStayOnTheSameLine = value.every( - item => - typeof item === 'object' && + item => typeof item === 'object' && item && !(item instanceof Date) && !(item instanceof Map) && @@ -140,33 +140,33 @@ export function valueToSource( return itemsStayOnTheSameLine ? `${indentString.repeat(indentLevel)}[${value.join(', ')}]` : `${indentString.repeat(indentLevel)}[${lineEnding}${value.join( - `,${lineEnding}`, - )}${lineEnding}${indentString.repeat(indentLevel)}]`; + `,${lineEnding}`, + )}${lineEnding}${indentString.repeat(indentLevel)}]`; } value = Object.keys(value).reduce((entries, propertyName) => { - const propertyValue = value[propertyName], - propertyValueString = + const propertyValue = value[propertyName]; + const propertyValueString = typeof propertyValue !== 'undefined' || includeUndefinedProperties ? valueToSource(value[propertyName], { - circularReferenceToken, - doubleQuote, - includeFunctions, - includeUndefinedProperties, - indentLevel: indentLevel + 1, - indentString, - lineEnding, - visitedObjects: new Set([value, ...visitedObjects]), - }) + circularReferenceToken, + doubleQuote, + includeFunctions, + includeUndefinedProperties, + indentLevel: indentLevel + 1, + indentString, + lineEnding, + visitedObjects: new Set([value, ...visitedObjects]), + }) : null; if (propertyValueString) { const quotedPropertyName = propertyNameRequiresQuotes(propertyName) - ? quoteString(propertyName, { - doubleQuote, - }) - : propertyName, - trimmedPropertyValueString = propertyValueString.substr((indentLevel + 1) * indentString.length); + ? quoteString(propertyName, { + doubleQuote, + }) + : propertyName; + const trimmedPropertyValueString = propertyValueString.substr((indentLevel + 1) * indentString.length); if (typeof propertyValue === 'function' && trimmedPropertyValueString.startsWith(`${propertyName}()`)) { entries.push( @@ -184,8 +184,8 @@ export function valueToSource( return value.length ? `${indentString.repeat(indentLevel)}{${lineEnding}${value.join( - `,${lineEnding}`, - )}${lineEnding}${indentString.repeat(indentLevel)}}` + `,${lineEnding}`, + )}${lineEnding}${indentString.repeat(indentLevel)}}` : `${indentString.repeat(indentLevel)}{}`; case 'string': return `${indentString.repeat(indentLevel)}${quoteString(value, { @@ -226,7 +226,9 @@ export function getSource(value: any): string { if (value) { try { value.__source = source; - } catch (ex) {} + } catch (ex) { + console.error(ex); + } } return source; } diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index f1741b48b..c62f4be08 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -5,7 +5,11 @@ import { DocumentModel } from './document-model'; export class Selection { private emitter = new EventEmitter(); + @obx.val private _selected: string[] = []; + + constructor(readonly doc: DocumentModel) {} + /** * 选中的节点 id */ @@ -13,8 +17,6 @@ export class Selection { return this._selected; } - constructor(readonly doc: DocumentModel) {} - /** * 选中 */ diff --git a/packages/designer/src/icons/clone.tsx b/packages/designer/src/icons/clone.tsx index 844b3f5b0..baf6342cc 100644 --- a/packages/designer/src/icons/clone.tsx +++ b/packages/designer/src/icons/clone.tsx @@ -1,9 +1,9 @@ -import { SVGIcon, IconProps } from "@ali/lowcode-utils"; +import { SVGIcon, IconProps } from '@ali/lowcode-utils'; export function IconClone(props: IconProps) { return ( - + ); } diff --git a/packages/designer/src/icons/component.tsx b/packages/designer/src/icons/component.tsx index 78a3ba1f0..6804ca16b 100644 --- a/packages/designer/src/icons/component.tsx +++ b/packages/designer/src/icons/component.tsx @@ -1,4 +1,4 @@ -import { SVGIcon, IconProps } from "@ali/lowcode-utils"; +import { SVGIcon, IconProps } from '@ali/lowcode-utils'; export function IconComponent(props: IconProps) { return ( diff --git a/packages/designer/src/icons/container.tsx b/packages/designer/src/icons/container.tsx index 5c46b3f18..b4ccfcd73 100644 --- a/packages/designer/src/icons/container.tsx +++ b/packages/designer/src/icons/container.tsx @@ -1,4 +1,4 @@ -import { SVGIcon, IconProps } from "@ali/lowcode-utils"; +import { SVGIcon, IconProps } from '@ali/lowcode-utils'; export function IconContainer(props: IconProps) { return ( diff --git a/packages/designer/src/icons/hidden.tsx b/packages/designer/src/icons/hidden.tsx index 0f944cadf..081d64e08 100644 --- a/packages/designer/src/icons/hidden.tsx +++ b/packages/designer/src/icons/hidden.tsx @@ -1,4 +1,4 @@ -import { SVGIcon, IconProps } from "@ali/lowcode-utils"; +import { SVGIcon, IconProps } from '@ali/lowcode-utils'; export function IconHidden(props: IconProps) { return ( diff --git a/packages/designer/src/icons/page.tsx b/packages/designer/src/icons/page.tsx index a957239fe..6a8780099 100644 --- a/packages/designer/src/icons/page.tsx +++ b/packages/designer/src/icons/page.tsx @@ -1,4 +1,4 @@ -import { SVGIcon, IconProps } from "@ali/lowcode-utils"; +import { SVGIcon, IconProps } from '@ali/lowcode-utils'; export function IconPage(props: IconProps) { return ( diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index b4148ebff..fa2024525 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -6,6 +6,7 @@ import { ProjectSchema, RootSchema } from '@ali/lowcode-types'; export class Project { private emitter = new EventEmitter(); + @obx.val readonly documents: DocumentModel[] = []; private data: ProjectSchema = { version: '1.0.0', componentsMap: [], componentsTree: [] }; @@ -35,10 +36,10 @@ export class Project { /** * 替换当前document的schema,并触发渲染器的render - * @param schema + * @param schema */ - setSchema(schema?: ProjectSchema){ - let doc = this.documents.find((doc) => doc.actived); + setSchema(schema?: ProjectSchema) { + const doc = this.documents.find((doc) => doc.actived); doc && doc.import(schema?.componentsTree[0]); } @@ -90,16 +91,18 @@ export class Project { * 分字段设置储存数据,不记录操作记录 */ set( + // eslint-disable-next-line @typescript-eslint/no-unused-vars key: - | 'version' - | 'componentsTree' - | 'componentsMap' - | 'utils' - | 'constants' - | 'i18n' - | 'css' - | 'dataSource' - | string, + | 'version' + | 'componentsTree' + | 'componentsMap' + | 'utils' + | 'constants' + | 'i18n' + | 'css' + | 'dataSource' + | string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars value: any, ): void {} @@ -107,16 +110,17 @@ export class Project { * 分字段设置储存数据 */ get( + // eslint-disable-next-line @typescript-eslint/no-unused-vars key: - | 'version' - | 'componentsTree' - | 'componentsMap' - | 'utils' - | 'constants' - | 'i18n' - | 'css' - | 'dataSource' - | string, + | 'version' + | 'componentsTree' + | 'componentsMap' + | 'utils' + | 'constants' + | 'i18n' + | 'css' + | 'dataSource' + | string, ): any {} open(doc?: string | DocumentModel | RootSchema): DocumentModel { diff --git a/packages/designer/src/utils/tree.ts b/packages/designer/src/utils/tree.ts index 2cd8ff515..d850bb204 100644 --- a/packages/designer/src/utils/tree.ts +++ b/packages/designer/src/utils/tree.ts @@ -4,4 +4,4 @@ export function foreachReverse(arr: NodeChildren, fn: Function, context: any = { for (let i = arr.length - 1; i >= 0; i--) { fn.call(context, arr.get(i)); } -} \ No newline at end of file +} diff --git a/packages/editor-core/.eslintrc.js b/packages/editor-core/.eslintrc.js new file mode 100644 index 000000000..c4749b311 --- /dev/null +++ b/packages/editor-core/.eslintrc.js @@ -0,0 +1,14 @@ +module.exports = { + extends: '../../.eslintrc.js', + rules: { + 'react/no-multi-comp': 1, + 'no-unused-expressions': 1, + 'implicit-arrow-linebreak': 1, + 'no-nested-ternary': 1, + 'no-mixed-operators': 1, + '@typescript-eslint/no-parameter-properties': 1, + '@typescript-eslint/ban-types': 1, + 'no-shadow': 1, + 'no-prototype-builtins': 1, + } +} \ No newline at end of file diff --git a/packages/editor-core/build.plugin.js b/packages/editor-core/build.plugin.js index 980daf4f1..d24fe23ae 100644 --- a/packages/editor-core/build.plugin.js +++ b/packages/editor-core/build.plugin.js @@ -1,12 +1,11 @@ const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); -const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); module.exports = ({ onGetWebpackConfig }) => { onGetWebpackConfig((config) => { config.resolve .plugin('tsconfigpaths') .use(TsconfigPathsPlugin, [{ - configFile: "./tsconfig.json" + configFile: './tsconfig.json', }]); }); }; diff --git a/packages/editor-core/src/di/ioc-context.ts b/packages/editor-core/src/di/ioc-context.ts index 9be8707e6..27b854cab 100644 --- a/packages/editor-core/src/di/ioc-context.ts +++ b/packages/editor-core/src/di/ioc-context.ts @@ -1,4 +1,5 @@ import { IocContext } from 'power-di'; + export * from 'power-di'; export const globalContext = IocContext.DefaultInstance; diff --git a/packages/editor-core/src/di/setter.ts b/packages/editor-core/src/di/setter.ts index 428b0a7ea..b4d771f01 100644 --- a/packages/editor-core/src/di/setter.ts +++ b/packages/editor-core/src/di/setter.ts @@ -52,7 +52,7 @@ export function registerSetter( function getInitialFromSetter(setter: any) { return setter && ( - setter.initial || setter.Initial + setter.initial || setter.Initial || (setter.type && (setter.type.initial || setter.type.Initial)) ) || null; // eslint-disable-line } diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 6f8c22dc0..117b5c14d 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -11,7 +11,7 @@ import { import { IocContext, RegisterOptions } from './di'; import { globalLocale } from './intl'; import * as utils from './utils'; -import { tipHandler } from './widgets/tip/tip-handler'; +// import { tipHandler } from './widgets/tip/tip-handler'; EventEmitter.defaultMaxListeners = 100; @@ -22,7 +22,7 @@ export class Editor extends EventEmitter implements IEditor { * Ioc Container */ private context = new IocContext({ - notFoundHandler: (type: KeyType) => NOT_FOUND, + notFoundHandler: (/* type: KeyType */) => NOT_FOUND, }); get locale() { @@ -86,11 +86,13 @@ export class Editor extends EventEmitter implements IEditor { } config?: EditorConfig; + components?: PluginClassSet; + async init(config?: EditorConfig, components?: PluginClassSet): Promise { this.config = config || {}; this.components = components || {}; - const { shortCuts = [], hooks = [], lifeCycles } = this.config; + const { hooks = [], lifeCycles } = this.config; this.emit('editor.beforeInit'); const init = (lifeCycles && lifeCycles.init) || ((): void => {}); @@ -114,7 +116,7 @@ export class Editor extends EventEmitter implements IEditor { return; } try { - const { shortCuts = [], lifeCycles = {} } = this.config; + const { lifeCycles = {} } = this.config; // unRegistShortCuts(shortCuts); this.unregisterHooks(); @@ -152,12 +154,13 @@ export class Editor extends EventEmitter implements IEditor { }; private waits = new Map< - KeyType, - Array<{ - once?: boolean; - resolve: (data: any) => void; - }> + KeyType, + Array<{ + once?: boolean; + resolve:(data: any) => void; + }> >(); + private notifyGot(key: KeyType) { let waits = this.waits.get(key); if (!waits) { diff --git a/packages/editor-core/src/hotkey.ts b/packages/editor-core/src/hotkey.ts index f991aaeab..c4a25ff05 100644 --- a/packages/editor-core/src/hotkey.ts +++ b/packages/editor-core/src/hotkey.ts @@ -124,7 +124,7 @@ let REVERSE_MAP: CtrlKeyMap; * programatically */ for (let i = 1; i < 20; ++i) { - MAP[111 + i] = 'f' + i; + MAP[111 + i] = `f${ i}`; } /** @@ -346,22 +346,28 @@ function fireCallback(callback: HotkeyCallback, e: KeyboardEvent, combo?: string sequence, selected, }); - } catch(err) { + } catch (err) { console.error(err.message); } } export class Hotkey { private callBacks: HotkeyCallbacks = {}; + private directMap: HotkeyDirectMap = {}; + private sequenceLevels: SequenceLevels = {}; + private resetTimer = 0; + private ignoreNextKeyup: boolean | string = false; + private ignoreNextKeypress = false; + private nextExpectedAction: boolean | string = false; mount(window: Window) { - const document = window.document; + const { document } = window; const handleKeyEvent = this.handleKeyEvent.bind(this); document.addEventListener('keypress', handleKeyEvent, false); document.addEventListener('keydown', handleKeyEvent, false); @@ -582,7 +588,6 @@ export class Hotkey { combination = combination.replace(/\s+/g, ' '); const sequence: string[] = combination.split(' '); - let info: KeyInfo; // if this pattern is a sequence of keys then run through this method // to reprocess each pattern one key at a time @@ -591,7 +596,7 @@ export class Hotkey { return; } - info = getKeyInfo(combination, action); + const info: KeyInfo = getKeyInfo(combination, action); // make sure to initialize array if this is the first time // a callback is added for this key diff --git a/packages/editor-core/src/intl/ali-global-locale.ts b/packages/editor-core/src/intl/ali-global-locale.ts index 1f74d719b..a8ec7911a 100644 --- a/packages/editor-core/src/intl/ali-global-locale.ts +++ b/packages/editor-core/src/intl/ali-global-locale.ts @@ -1,5 +1,6 @@ import { EventEmitter } from 'events'; import { obx, computed } from '../utils/obx'; + const languageMap: { [key: string]: string } = { en: 'en-US', zh: 'zh-CN', @@ -30,7 +31,9 @@ const LowcodeConfigKey = 'ali-lowcode-config'; class AliGlobalLocale { private emitter = new EventEmitter(); + @obx.ref private _locale?: string; + @computed get locale() { if (this._locale != null) { return this._locale; @@ -67,7 +70,7 @@ class AliGlobalLocale { const it = navigator.browserLanguage.split('-'); locale = it[0]; if (it[1]) { - locale += '-' + it[1].toUpperCase(); + locale += `-${ it[1].toUpperCase()}`; } } diff --git a/packages/editor-core/src/intl/index.ts b/packages/editor-core/src/intl/index.ts index 88974b764..e4d6b4e37 100644 --- a/packages/editor-core/src/intl/index.ts +++ b/packages/editor-core/src/intl/index.ts @@ -34,7 +34,7 @@ function injectVars(msg: string, params: any, locale: string): string { return params[key]; } return $1; - });*/ + }); */ } export function intl(data: any, params?: object): ReactNode { @@ -92,11 +92,11 @@ class IntlElement extends Component<{ data: any; params?: object }> { export function createIntl( instance: string | object, ): { - intlNode(id: string, params?: object): ReactNode; - intl(id: string, params?: object): string; - getLocale(): string; - setLocale(locale: string): void; -} { + intlNode(id: string, params?: object): ReactNode; + intl(id: string, params?: object): string; + getLocale(): string; + setLocale(locale: string): void; + } { const data = computed(() => { const locale = globalLocale.getLocale(); if (typeof instance === 'string') { diff --git a/packages/editor-core/src/utils/app-preset.ts b/packages/editor-core/src/utils/app-preset.ts index f17a81458..72ae9321a 100644 --- a/packages/editor-core/src/utils/app-preset.ts +++ b/packages/editor-core/src/utils/app-preset.ts @@ -28,7 +28,7 @@ window.__newFunc = (funContext: string): ((...args: any[]) => any) => { }; // 关闭浏览器前提醒,只有产生过交互才会生效 -window.onbeforeunload = function(e: Event): string | void { +window.onbeforeunload = function (e: Event): string | void { const ev = e || window.event; // 本地调试不生效 if (location.href.indexOf('localhost') > 0) { diff --git a/packages/editor-core/src/utils/focus-tracker.ts b/packages/editor-core/src/utils/focus-tracker.ts index 6bfaa8581..61ecb3042 100644 --- a/packages/editor-core/src/utils/focus-tracker.ts +++ b/packages/editor-core/src/utils/focus-tracker.ts @@ -4,7 +4,7 @@ export class FocusTracker { if (this.checkModalDown(e)) { return; } - const first = this.first; + const { first } = this; if (first && !first.internalCheckInRange(e)) { this.internalSuspenseItem(first); first.internalTriggerBlur(); @@ -15,23 +15,30 @@ export class FocusTracker { win.document.removeEventListener('click', checkDown, true); }; } + private actives: Focusable[] = []; + get first() { return this.actives[0]; } + private modals: Array<{ checkDown: (e: MouseEvent) => boolean; checkOpen: () => boolean }> = []; + addModal(checkDown: (e: MouseEvent) => boolean, checkOpen: () => boolean) { this.modals.push({ checkDown, checkOpen, }); } + private checkModalOpen(): boolean { return this.modals.some(item => item.checkOpen()); } + private checkModalDown(e: MouseEvent): boolean { return this.modals.some(item => item.checkDown(e)); } + execSave() { // has Modal return; if (this.checkModalOpen()) { @@ -42,16 +49,19 @@ export class FocusTracker { this.first.internalTriggerSave(); } } + execEsc() { - const first = this.first; + const { first } = this; if (first) { this.internalSuspenseItem(first); first.internalTriggerEsc(); } } + create(config: FocusableConfig) { return new Focusable(this, config); } + internalActiveItem(item: Focusable) { const first = this.actives[0]; if (first === item) { @@ -69,6 +79,7 @@ export class FocusTracker { // trigger onActive item.internalTriggerActive(); } + internalSuspenseItem(item: Focusable) { const i = this.actives.indexOf(item); if (i > -1) { @@ -89,18 +100,23 @@ export interface FocusableConfig { export class Focusable { readonly isModal: boolean; + constructor(private tracker: FocusTracker, private config: FocusableConfig) { this.isModal = config.modal == null ? false : config.modal; } + active() { this.tracker.internalActiveItem(this); } + suspense() { this.tracker.internalSuspenseItem(this); } + purge() { this.tracker.internalSuspenseItem(this); } + internalCheckInRange(e: MouseEvent) { const { range } = this.config; if (!range) { @@ -111,11 +127,13 @@ export class Focusable { } return range.contains(e.target as HTMLElement); } + internalTriggerBlur() { if (this.config.onBlur) { this.config.onBlur(); } } + internalTriggerSave() { if (this.config.onSave) { this.config.onSave(); @@ -123,11 +141,13 @@ export class Focusable { } return false; } + internalTriggerEsc() { if (this.config.onEsc) { this.config.onEsc(); } } + internalTriggerActive() { if (this.config.onActive) { this.config.onActive(); diff --git a/packages/editor-core/src/utils/obx.ts b/packages/editor-core/src/utils/obx.ts index 3ab051f08..627a7e273 100644 --- a/packages/editor-core/src/utils/obx.ts +++ b/packages/editor-core/src/utils/obx.ts @@ -1,4 +1,5 @@ -export * from '@recore/obx'; import { observer } from '@recore/obx-react'; +export * from '@recore/obx'; + export { observer }; diff --git a/packages/editor-core/src/utils/request.ts b/packages/editor-core/src/utils/request.ts index 24cde7293..e7f4c41cf 100644 --- a/packages/editor-core/src/utils/request.ts +++ b/packages/editor-core/src/utils/request.ts @@ -1,4 +1,5 @@ import Debug from 'debug'; + const debug = Debug('request'); export function serialize(obj?: object): string { @@ -49,7 +50,7 @@ export function post(dataAPI: string, params?: object, headers?: object, otherPr export function request( dataAPI: string, - method: string = 'GET', + method = 'GET', data?: object | string, headers?: object, otherProps?: any, diff --git a/packages/editor-core/src/widgets/tip/tip-container.tsx b/packages/editor-core/src/widgets/tip/tip-container.tsx index 35ff58f14..81750bd6a 100644 --- a/packages/editor-core/src/widgets/tip/tip-container.tsx +++ b/packages/editor-core/src/widgets/tip/tip-container.tsx @@ -20,7 +20,7 @@ export class TipContainer extends Component { }; } - componentWillMount() { + UNSAFE_componentWillMount() { if (this.dispose) { this.dispose(); } diff --git a/packages/editor-core/src/widgets/tip/tip-handler.ts b/packages/editor-core/src/widgets/tip/tip-handler.ts index d528a52af..c0a806888 100644 --- a/packages/editor-core/src/widgets/tip/tip-handler.ts +++ b/packages/editor-core/src/widgets/tip/tip-handler.ts @@ -7,8 +7,11 @@ export interface TipOptions extends TipConfig { class TipHandler { tip: TipOptions | null = null; + private showDelay: number | null = null; + private hideDelay: number | null = null; + private emitter = new EventEmitter(); setTarget(target: HTMLElement) { @@ -107,7 +110,7 @@ function findTip(target: HTMLElement | null): TipOptions | null { while (child) { if (child.dataset && child.dataset.role === 'tip') { - const tipId = child.dataset.tipId; + const { tipId } = child.dataset; if (!tipId) { return null; } diff --git a/packages/editor-core/src/widgets/tip/tip-item.tsx b/packages/editor-core/src/widgets/tip/tip-item.tsx index 20ec87bea..58aed12b4 100644 --- a/packages/editor-core/src/widgets/tip/tip-item.tsx +++ b/packages/editor-core/src/widgets/tip/tip-item.tsx @@ -7,6 +7,7 @@ import { tipHandler } from './tip-handler'; export class TipItem extends Component { private dispose?: () => void; + constructor(props: any) { super(props); this.dispose = tipHandler.onChange(() => this.forceUpdate()); @@ -32,6 +33,7 @@ export class TipItem extends Component { } private timer: number | null = null; + clearTimer() { if (this.timer) { clearTimeout(this.timer); @@ -40,13 +42,14 @@ export class TipItem extends Component { } private shell: HTMLDivElement | null = null; - private originClassName: string = ''; + + private originClassName = ''; updateTip() { if (!this.shell) { return; } - const shell = this.shell; + const { shell } = this; const arrow = shell.querySelector('.lc-arrow') as HTMLElement; // reset @@ -55,7 +58,7 @@ export class TipItem extends Component { arrow.style.cssText = ''; this.clearTimer(); - const tip = tipHandler.tip; + const { tip } = tipHandler; if (!tip) { return; } diff --git a/packages/editor-core/src/widgets/title/index.tsx b/packages/editor-core/src/widgets/title/index.tsx index 1006935ed..5a8ac589b 100644 --- a/packages/editor-core/src/widgets/title/index.tsx +++ b/packages/editor-core/src/widgets/title/index.tsx @@ -11,6 +11,7 @@ export class Title extends Component<{ title: TitleContent; className?: string; super(props); this.handleClick = this.handleClick.bind(this); } + handleClick(e: React.MouseEvent) { const { title, onClick } = this.props as any; const url = title && (title.docUrl || title.url); @@ -22,7 +23,9 @@ export class Title extends Component<{ title: TitleContent; className?: string; // TODO: 操作交互冲突,目前 mixedSetter 仅有 2 个 setter 注册时用到了 onClick onClick && onClick(e); } + render() { + // eslint-disable-next-line prefer-const let { title, className } = this.props; if (title == null) { return null; @@ -53,7 +56,7 @@ export class Title extends Component<{ title: TitleContent; className?: string; diff --git a/packages/editor-preset-general/build.plugin.js b/packages/editor-preset-general/build.plugin.js index 1e9165eaf..ba3096f14 100644 --- a/packages/editor-preset-general/build.plugin.js +++ b/packages/editor-preset-general/build.plugin.js @@ -5,7 +5,7 @@ module.exports = ({ onGetWebpackConfig }) => { config.resolve .plugin('tsconfigpaths') .use(TsconfigPathsPlugin, [{ - configFile: "./tsconfig.json" + configFile: './tsconfig.json', }]); /* diff --git a/packages/editor-preset-general/src/index.ts b/packages/editor-preset-general/src/index.ts index 25de7f209..97f98db4b 100644 --- a/packages/editor-preset-general/src/index.ts +++ b/packages/editor-preset-general/src/index.ts @@ -1,11 +1,13 @@ import { render } from 'react-dom'; import { createElement } from 'react'; -import { Workbench, Skeleton, SettingsPrimaryPane, registerDefaults } from '@ali/lowcode-editor-skeleton'; -import { globalContext, Editor } from '@ali/lowcode-editor-core'; -import { Designer, LiveEditing, TransformStage, Node } from '@ali/lowcode-designer'; -import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane'; -import DesignerPlugin from '@ali/lowcode-plugin-designer'; import '@ali/lowcode-editor-setters'; +import DesignerPlugin from '@ali/lowcode-plugin-designer'; +import { Designer, LiveEditing } from '@ali/lowcode-designer'; +import { globalContext, Editor } from '@ali/lowcode-editor-core'; +import { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane'; +import { Workbench, Skeleton, SettingsPrimaryPane, registerDefaults } from '@ali/lowcode-editor-skeleton'; + +import { version } from '../package.json'; import { liveEditingRule, liveEditingSaveHander } from './live-editing'; export * from '@ali/lowcode-types'; @@ -22,7 +24,7 @@ editor.set(Skeleton, skeleton); editor.set('skeleton', skeleton); registerDefaults(); -export const designer = new Designer({ editor: editor }); +export const designer = new Designer({ editor }); editor.set(Designer, designer); editor.set('designer', designer); @@ -50,8 +52,6 @@ skeleton.add({ content: OutlineBackupPane, }); -const version = '0.9.0-beta'; - export default function GeneralWorkbench(props: any) { return createElement(Workbench, { skeleton, diff --git a/packages/editor-preset-general/src/live-editing.ts b/packages/editor-preset-general/src/live-editing.ts index de812d71e..0d6131e39 100644 --- a/packages/editor-preset-general/src/live-editing.ts +++ b/packages/editor-preset-general/src/live-editing.ts @@ -21,7 +21,7 @@ function getText(node: DocNode, prop: string) { export function liveEditingRule(target: EditingTarget) { // for vision components specific - const { node, rootElement, event } = target; + const { node, event } = target; const targetElement = event.target as HTMLElement; @@ -29,7 +29,7 @@ export function liveEditingRule(target: EditingTarget) { return null; } - const innerText = targetElement.innerText; + const { innerText } = targetElement; const propTarget = ['title', 'label', 'text', 'content', 'children'].find(prop => { return equalText(getText(node, prop), innerText); }); @@ -48,12 +48,12 @@ function equalText(v: any, innerText: string) { if (typeof v !== 'string') { return false; } - return v.trim() === innerText + return v.trim() === innerText; } export const liveEditingSaveHander: SaveHandler = { condition: (prop) => { - const v = prop.getValue(); + // const v = prop.getValue(); return prop.type === 'expression'; // || isI18nData(v); }, onSaveContent: (content, prop) => { @@ -72,8 +72,8 @@ export const liveEditingSaveHander: SaveHandler = { } else { prop.setValue(data); } - } -} + }, +}; // TODO: // 非文本编辑 // 国际化数据,改变当前 diff --git a/packages/editor-preset-vision/.eslintrc.js b/packages/editor-preset-vision/.eslintrc.js new file mode 100644 index 000000000..f3461d8f8 --- /dev/null +++ b/packages/editor-preset-vision/.eslintrc.js @@ -0,0 +1,20 @@ +module.exports = { + extends: '../../.eslintrc.js', + rules: { + 'react/no-multi-comp': 1, + 'no-unused-expressions': 1, + 'implicit-arrow-linebreak': 1, + 'no-nested-ternary': 1, + 'no-mixed-operators': 1, + '@typescript-eslint/no-parameter-properties': 1, + '@typescript-eslint/ban-types': 1, + 'no-shadow': 1, + 'no-prototype-builtins': 1, + '@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, + } +} \ No newline at end of file diff --git a/packages/editor-preset-vision/build.plugin.js b/packages/editor-preset-vision/build.plugin.js index 1e9165eaf..ba3096f14 100644 --- a/packages/editor-preset-vision/build.plugin.js +++ b/packages/editor-preset-vision/build.plugin.js @@ -5,7 +5,7 @@ module.exports = ({ onGetWebpackConfig }) => { config.resolve .plugin('tsconfigpaths') .use(TsconfigPathsPlugin, [{ - configFile: "./tsconfig.json" + configFile: './tsconfig.json', }]); /* diff --git a/packages/editor-preset-vision/src/base/base.ts b/packages/editor-preset-vision/src/base/base.ts index a19c1252a..3c3616a91 100644 --- a/packages/editor-preset-vision/src/base/base.ts +++ b/packages/editor-preset-vision/src/base/base.ts @@ -81,10 +81,13 @@ export function connectGeneralManagerList(managerList: any[], sourceManagerList: export class BaseManager implements INameable, IObservable { static EVENTS: IEventNameMap = {}; + static NAME = 'BaseManager'; private name: string; + private id: string; + private emitter: any; constructor(managerConfigs: IManagerConfigs = {}) { diff --git a/packages/editor-preset-vision/src/base/schemaManager.ts b/packages/editor-preset-vision/src/base/schemaManager.ts index 00ef16561..7a0a90867 100644 --- a/packages/editor-preset-vision/src/base/schemaManager.ts +++ b/packages/editor-preset-vision/src/base/schemaManager.ts @@ -11,7 +11,9 @@ import VisualManager from './visualManager'; export default class SchemaManager extends BaseManager implements IManagerController, ISchemaController { private schemaData: object = {}; + private visualManagerList: VisualManager[] = []; + private schemaManagerList: SchemaManager[] = []; getManager(): VisualManager { diff --git a/packages/editor-preset-vision/src/base/visualDesigner.ts b/packages/editor-preset-vision/src/base/visualDesigner.ts index a69018aba..a210b6737 100644 --- a/packages/editor-preset-vision/src/base/visualDesigner.ts +++ b/packages/editor-preset-vision/src/base/visualDesigner.ts @@ -22,16 +22,22 @@ interface IDesignerProps { export default class VisualDesigner extends Component implements IManagerController, IObservable, INameable { static NAME = 'VisualDesigner'; + static EVENTS: IEventNameMap = {}; + props: IDesignerProps = {}; + defaultProps: IDesignerProps = { name: 'defaultDesigner', visualManagers: [], }; private visualManagerList: VisualManager[] = []; + private name = ''; + private id = ''; + private emitter: IEmitter; constructor(props: IDesignerProps) { diff --git a/packages/editor-preset-vision/src/base/visualManager.ts b/packages/editor-preset-vision/src/base/visualManager.ts index e28b6b519..737120f20 100644 --- a/packages/editor-preset-vision/src/base/visualManager.ts +++ b/packages/editor-preset-vision/src/base/visualManager.ts @@ -11,6 +11,7 @@ import VisualDesigner from './visualDesigner'; export default class VisualManager extends BaseManager implements IManagerController, IDesignerController { private visualManagerList: VisualManager[] = []; + private visualDesignerList: VisualDesigner[] = []; getManager(): VisualManager { diff --git a/packages/editor-preset-vision/src/bundle/bundle.ts b/packages/editor-preset-vision/src/bundle/bundle.ts index 4e2cc3f6e..68fde2ea5 100644 --- a/packages/editor-preset-vision/src/bundle/bundle.ts +++ b/packages/editor-preset-vision/src/bundle/bundle.ts @@ -35,17 +35,25 @@ export interface ComponentViewBundle { export default class Bundle { static createPrototype = Prototype.create; + static addGlobalPropsReducer = Prototype.addGlobalPropsReducer; + static addGlobalPropsConfigure = Prototype.addGlobalPropsConfigure; + static addGlobalExtraActions = Prototype.addGlobalExtraActions; + static removeGlobalPropsConfigure = Prototype.removeGlobalPropsConfigure; + static overridePropsConfigure = Prototype.overridePropsConfigure; + static create(protos: ComponentProtoBundle[], views?: ComponentViewBundle[]) { return new Bundle(protos, views); } private viewsMap: { [componentName: string]: ComponentType } = {}; + private registry: { [componentName: string]: Prototype } = {}; + private prototypeList: Prototype[] = []; constructor(protos?: ComponentProtoBundle[], views?: ComponentViewBundle[]) { diff --git a/packages/editor-preset-vision/src/bundle/prototype.ts b/packages/editor-preset-vision/src/bundle/prototype.ts index d842563b1..b91554240 100644 --- a/packages/editor-preset-vision/src/bundle/prototype.ts +++ b/packages/editor-preset-vision/src/bundle/prototype.ts @@ -209,27 +209,37 @@ function isNewSpec(options: any): options is ComponentMetadata { class Prototype { static addGlobalPropsReducer = addGlobalPropsReducer; + static addGlobalPropsConfigure = addGlobalPropsConfigure; + static addGlobalExtraActions = addGlobalExtraActions; + static removeGlobalPropsConfigure = removeGlobalPropsConfigure; + static overridePropsConfigure = overridePropsConfigure; - static create(config: OldPrototypeConfig | ComponentMetadata | ComponentMeta, extraConfigs: any = null, lookup: boolean = false) { + + static create(config: OldPrototypeConfig | ComponentMetadata | ComponentMeta, extraConfigs: any = null, lookup = false) { return new Prototype(config, extraConfigs, lookup); } readonly isPrototype = true; + readonly meta: ComponentMeta; + readonly options: OldPrototypeConfig | ComponentMetadata; + get componentName() { return this.getId(); } + get packageName() { return this.meta.npm?.package; } + // 兼容原 vision 用法 view: ComponentType | undefined; - constructor(input: OldPrototypeConfig | ComponentMetadata | ComponentMeta, extraConfigs: any = null, lookup: boolean = false) { + constructor(input: OldPrototypeConfig | ComponentMetadata | ComponentMeta, extraConfigs: any = null, lookup = false) { if (lookup) { this.meta = designer.getComponentMeta(input.componentName); this.options = this.meta.getMetadata(); @@ -283,6 +293,7 @@ class Prototype { } private category?: string; + getCategory() { if (this.options.category != null) { return this.options.category; diff --git a/packages/editor-preset-vision/src/bundle/trunk.ts b/packages/editor-preset-vision/src/bundle/trunk.ts index e452a8b6e..5144275ad 100644 --- a/packages/editor-preset-vision/src/bundle/trunk.ts +++ b/packages/editor-preset-vision/src/bundle/trunk.ts @@ -8,8 +8,11 @@ import Prototype from './prototype'; export class Trunk { private trunk: any[] = []; + private emitter: EventEmitter = new EventEmitter(); + private metaBundle = new Bundle(); + private componentPrototypeMocker: any; isReady() { @@ -123,7 +126,7 @@ export class Trunk { console.warn('Trunk.setPackages is deprecated'); } - getSetter(type: string): any{ + getSetter(type: string): any { const setter = getSetter(type); if (setter?.component) { return setter.component; diff --git a/packages/editor-preset-vision/src/bundle/upgrade-metadata.ts b/packages/editor-preset-vision/src/bundle/upgrade-metadata.ts index c03b7f82e..b0931d6ca 100644 --- a/packages/editor-preset-vision/src/bundle/upgrade-metadata.ts +++ b/packages/editor-preset-vision/src/bundle/upgrade-metadata.ts @@ -308,7 +308,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec autorun: (field: Field) => { let fieldValue = untracked(() => field.getValue()); if (accessor) { - fieldValue = accessor.call(field, fieldValue) + fieldValue = accessor.call(field, fieldValue); } if (sync) { fieldValue = sync.call(field, fieldValue); @@ -318,7 +318,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec } else { field.setValue(fieldValue); } - } + }, }); } @@ -366,8 +366,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec let disabledValue: boolean; if (typeof disabled === 'function') { disabledValue = disabled.call(field, currentValue) === true; - } - else { + } else { disabledValue = disabled === true; } if (disabledValue) { @@ -377,7 +376,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec return ignore.call(field, currentValue) !== true; } return ignore !== true; - } + }, }); } @@ -437,8 +436,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec autorun: item.autorun, }); }, - }, - ) + }) : []; newConfig.items = objItems; @@ -475,8 +473,8 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec componentName: setter, condition: condition ? (field: Field) => { - return condition.call(field, field.getValue()); - } + return condition.call(field, field.getValue()); + } : null, }; }); @@ -520,11 +518,11 @@ type ConfigCollector = { addInitial: AddInitial; addFilter: AddFilter; addAutorun: AddAutorun; -} +}; function getInitialFromSetter(setter: any) { return setter && ( - setter.initial || setter.Initial + setter.initial || setter.Initial || (setter.type && (setter.type.initial || setter.type.Initial)) ) || null; // eslint-disable-line } @@ -719,8 +717,8 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) { experimental.initialChildren = typeof initialChildren === 'function' ? (node: any) => { - return initialChildren.call(node, node.settingEntry); - } + return initialChildren.call(node, node.settingEntry); + } : initialChildren; } if (view) { @@ -796,9 +794,8 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) { }, addAutorun: (item) => { autoruns.push(item); - } - } - ); + }, + }); experimental.initials = initials; experimental.filters = filters; experimental.autoruns = autoruns; diff --git a/packages/editor-preset-vision/src/components/index.tsx b/packages/editor-preset-vision/src/components/index.tsx index f32681dd0..77e24d70b 100644 --- a/packages/editor-preset-vision/src/components/index.tsx +++ b/packages/editor-preset-vision/src/components/index.tsx @@ -48,16 +48,19 @@ export class InstanceNodeSelector extends React.Component { node.select(); } }; + onMouseOver = (node: Node) => (_: any, flag = true) => { if (node && typeof node.hover === 'function') { node.hover(flag); } }; + onMouseOut = (node: Node) => (_: any, flag = false) => { if (node && typeof node.hover === 'function') { node.hover(flag); } }; + renderNodes = (node: Node) => { const nodes = this.state.parentNodes || []; const children = nodes.map((node, key) => { diff --git a/packages/editor-preset-vision/src/context.ts b/packages/editor-preset-vision/src/context.ts index 47a6917a4..d9171c07b 100644 --- a/packages/editor-preset-vision/src/context.ts +++ b/packages/editor-preset-vision/src/context.ts @@ -15,7 +15,9 @@ export type SetterProvider = (prop: any, componentPrototype: Prototype) => Compo export class VisualEngineContext { private managerMap: { [name: string]: VisualManager } = {}; + private moduleMap: { [name: string]: any } = {}; + private pluginsMap: { [name: string]: any } = {}; use(pluginName: string, plugin: any) { @@ -43,7 +45,9 @@ export class VisualEngineContext { } registerManager(managerMap?: { [name: string]: VisualManager }): this; + registerManager(name: string, manager: VisualManager): this; + registerManager(name?: any, manager?: VisualManager): this { if (name && typeof name === 'object') { this.managerMap = assign(this.managerMap, name); @@ -54,7 +58,9 @@ export class VisualEngineContext { } registerModule(moduleMap: { [name: string]: any }): this; + registerModule(name: string, module: any): this; + registerModule(name?: any, module?: any): this { if (typeof name === 'object') { this.moduleMap = Object.assign({}, this.moduleMap, name); diff --git a/packages/editor-preset-vision/src/drag-engine.ts b/packages/editor-preset-vision/src/drag-engine.ts index c1844c38a..303e56434 100644 --- a/packages/editor-preset-vision/src/drag-engine.ts +++ b/packages/editor-preset-vision/src/drag-engine.ts @@ -2,7 +2,7 @@ import { designer } from './editor'; import { DragObjectType, isNode, isDragNodeDataObject } from '@ali/lowcode-designer'; import { isPrototype } from './bundle/prototype'; -const dragon = designer.dragon; +const { dragon } = designer; const DragEngine = { from(shell: Element, boost: (e: MouseEvent) => any): any { return dragon.from(shell, (e) => { diff --git a/packages/editor-preset-vision/src/editor.ts b/packages/editor-preset-vision/src/editor.ts index a47c9eb76..96ecf7229 100644 --- a/packages/editor-preset-vision/src/editor.ts +++ b/packages/editor-preset-vision/src/editor.ts @@ -22,7 +22,7 @@ editor.set(Skeleton, skeleton); editor.set('skeleton', skeleton); registerDefaults(); -export const designer = new Designer({ editor: editor }); +export const designer = new Designer({ editor }); editor.set(Designer, designer); editor.set('designer', designer); @@ -142,7 +142,7 @@ designer.addPropsReducer((props: any, node: Node) => { return { ...props, lifeCycles: {}, - } + }; } return props; }, TransformStage.Render); @@ -223,8 +223,8 @@ designer.addPropsReducer((props: any, node: Node) => { // 设计器组件样式处理 function stylePropsReducer(props: any, node: any) { if (props && typeof props === 'object' && props.__style__) { - const cssId = '_style_pesudo_' + node.id.replace(/\$/g, '_'); - const cssClass = '_css_pesudo_' + node.id.replace(/\$/g, '_'); + const cssId = `_style_pesudo_${ node.id.replace(/\$/g, '_')}`; + const cssClass = `_css_pesudo_${ node.id.replace(/\$/g, '_')}`; const styleProp = props.__style__; appendStyleNode(props, styleProp, cssClass, cssId); } @@ -235,8 +235,8 @@ function stylePropsReducer(props: any, node: any) { appendStyleNode(props, styleProp, cssClass, cssId); } if (props && typeof props === 'object' && props.containerStyle) { - const cssId = '_style_pesudo_' + node.id; - const cssClass = '_css_pesudo_' + node.id.replace(/\$/g, '_'); + const cssId = `_style_pesudo_${ node.id}`; + const cssClass = `_css_pesudo_${ node.id.replace(/\$/g, '_')}`; const styleProp = props.containerStyle; appendStyleNode(props, styleProp, cssClass, cssId); } @@ -264,7 +264,7 @@ function appendStyleNode(props: any, styleProp: any, cssClass: string, cssId: st s.appendChild(doc.createTextNode(styleProp.replace(/(\d+)rpx/g, (a, b) => { return `${b / 2}px`; - }).replace(/:root/g, '.' + cssClass))); + }).replace(/:root/g, `.${ cssClass}`))); } } designer.addPropsReducer(stylePropsReducer, TransformStage.Render); diff --git a/packages/editor-preset-vision/src/env.ts b/packages/editor-preset-vision/src/env.ts index 8c7eae39b..4e267ee24 100644 --- a/packages/editor-preset-vision/src/env.ts +++ b/packages/editor-preset-vision/src/env.ts @@ -10,6 +10,7 @@ export class Env { @obx.val envs: ILiteralObject = {}; private emitter: EventEmitter; + private featureMap: ILiteralObject; constructor() { diff --git a/packages/editor-preset-vision/src/exchange.ts b/packages/editor-preset-vision/src/exchange.ts index 6e1f8c13e..350ccb5fe 100644 --- a/packages/editor-preset-vision/src/exchange.ts +++ b/packages/editor-preset-vision/src/exchange.ts @@ -20,5 +20,5 @@ export default { return () => { // this.emitter.removeListener('intoview', func); }; - } -} + }, +}; diff --git a/packages/editor-preset-vision/src/fields/field.tsx b/packages/editor-preset-vision/src/fields/field.tsx index 3fc13ea7e..ede347595 100644 --- a/packages/editor-preset-vision/src/fields/field.tsx +++ b/packages/editor-preset-vision/src/fields/field.tsx @@ -10,7 +10,7 @@ interface IHelpTip { } function splitWord(title: string): JSX.Element[] { - return (title || '').split('').map((w, i) => {w}); + return (title || '').split('').map((w, i) => {w}); } function getFieldTitle(title: string, tip: IHelpTip, compact?: boolean, propName?: string): JSX.Element { @@ -49,12 +49,12 @@ function getFieldTitle(title: string, tip: IHelpTip, compact?: boolean, propName return ( {titleContent || (typeof title === 'object' ? '' : title)} - {tipContent} + {tipContent} ); } @@ -92,6 +92,7 @@ export default class VEField extends Component { public static displayName = 'VEField'; public readonly props: IVEFieldProps; + public classNames: string[] = []; public state: IVEFieldState = { @@ -133,15 +134,15 @@ export default class VEField extends Component { } const headContent = headDIY ? this.renderHead() - :
{this.renderHead()}
; + :
{this.renderHead()}
; return ( -
+
{headContent} -
+
{this.renderBody()}
-
+
{this.renderFoot()}
diff --git a/packages/editor-preset-vision/src/fields/fields.tsx b/packages/editor-preset-vision/src/fields/fields.tsx index e106fe7f7..8f9d645c9 100644 --- a/packages/editor-preset-vision/src/fields/fields.tsx +++ b/packages/editor-preset-vision/src/fields/fields.tsx @@ -50,7 +50,7 @@ export class PlainField extends VEField { headDIY: true, }; - public static displayName: string = 'PlainField'; + public static displayName = 'PlainField'; public renderHead(): null { return null; @@ -59,6 +59,7 @@ export class PlainField extends VEField { export class InlineField extends VEField { public static displayName = 'InlineField'; + constructor(props: any) { super(props); this.classNames = ['engine-setting-field', 'engine-inline-field']; @@ -194,15 +195,14 @@ export class PopupField extends VEField { return (
- popups.popup({ - cancelOnBlur: true, - content: this.props.children, - position: 'left bottom', - showClose: true, - sizeFixed: true, - target: e.currentTarget, - }) + onClick={(e) => popups.popup({ + cancelOnBlur: true, + content: this.props.children, + position: 'left bottom', + showClose: true, + sizeFixed: true, + target: e.currentTarget, + }) } > {title} @@ -240,8 +240,11 @@ export class Stage extends Component { }; public stage: any; + public additionClassName: string; + public shell: Element | null = null; + private willDetach: () => any; public componentWillMount() { @@ -294,7 +297,7 @@ export class Stage extends Component { } public render() { - const stage = this.stage; + const { stage } = this; let content = null; let tabs = null; diff --git a/packages/editor-preset-vision/src/fields/inlinetip.tsx b/packages/editor-preset-vision/src/fields/inlinetip.tsx index f3344b1c3..6ba0ec658 100644 --- a/packages/editor-preset-vision/src/fields/inlinetip.tsx +++ b/packages/editor-preset-vision/src/fields/inlinetip.tsx @@ -19,7 +19,7 @@ export default class InlineTip extends Component { return (
diff --git a/packages/editor-preset-vision/src/fields/settingField.tsx b/packages/editor-preset-vision/src/fields/settingField.tsx index 4edd0c52d..3da6b8cff 100644 --- a/packages/editor-preset-vision/src/fields/settingField.tsx +++ b/packages/editor-preset-vision/src/fields/settingField.tsx @@ -7,8 +7,8 @@ import { EntryField, InlineField, PlainField, - PopupField -} from "./fields"; + PopupField, +} from './fields'; import { ComponentClass, Component, isValidElement, createElement } from 'react'; import { createSetterContent, getSetter } from '@ali/lowcode-editor-core'; @@ -37,7 +37,7 @@ const FIELD_TYPE_MAP: any = { inline: InlineField, plain: PlainField, popup: PopupField, - tab: AccordionField + tab: AccordionField, }; export class SettingField extends Component { @@ -67,7 +67,7 @@ export class SettingField extends Component { const { prop, selected, addonProps } = this.props; const display = this.props.forceDisplay || prop.getDisplay(); - if (display === "none") { + if (display === 'none') { return null; } @@ -82,7 +82,7 @@ export class SettingField extends Component { prop, setUseVariable: () => prop.setUseVariable(!prop.isUseVariable()), tip: prop.getTip(), - title: prop.getTitle() + title: prop.getTitle(), }; // 部分 Field 所需要的额外 fieldProps @@ -90,7 +90,7 @@ export class SettingField extends Component { const ctx = context; const plugin = ctx.getPlugin(VE_HOOKS.VE_SETTING_FIELD_PROVIDER); let Field; - if (typeof plugin === "function") { + if (typeof plugin === 'function') { Field = plugin(display, FIELD_TYPE_MAP, prop); } if (!Field) { @@ -98,7 +98,7 @@ export class SettingField extends Component { } this._prepareProps(display, extraProps); - if (display === "entry") { + if (display === 'entry') { return ; } @@ -110,7 +110,7 @@ export class SettingField extends Component { const fieldProps = { ...standardProps, ...extraProps }; if (prop.isUseVariable() && !this.variableSetter.isPopup) { - props.placeholder = "请输入表达式: ${var}"; + props.placeholder = '请输入表达式: ${var}'; props.key = `${prop.getId()}-variable`; setter = createElement(this.variableSetter, props); return {setter}; @@ -128,20 +128,20 @@ export class SettingField extends Component { setter = prop.getSetter(); if ( - typeof setter === "object" && - "componentName" in setter && + typeof setter === 'object' && + 'componentName' in setter && !(isValidElement(setter) || isReactClass(setter)) ) { const { componentName: setterType, props: setterProps } = setter as any; setter = createSetterContent(setterType, { ...addonProps, ...setterProps, - ...props + ...props, }); } else { setter = createSetterContent(setter, { ...addonProps, - ...props + ...props, }); } @@ -150,22 +150,22 @@ export class SettingField extends Component { private supportMultiSetter() { const { prop } = this.props; - const setter = prop && prop.getConfig && prop.getConfig("setter"); + const setter = prop && prop.getConfig && prop.getConfig('setter'); return prop.isSupportVariable() || Array.isArray(setter); } private _prepareProps(displayType: string, extraProps: IExtraProps): void { const { prop } = this.props; extraProps.propName = prop.isGroup() - ? "组合属性,无属性名称" + ? '组合属性,无属性名称' : prop.getName(); switch (displayType) { - case "title": + case 'title': break; - case "block": + case 'block': Object.assign(extraProps, { isGroup: prop.isGroup() }); break; - case "accordion": + case 'accordion': Object.assign(extraProps, { headDIY: true, isExpand: prop.isExpand(), @@ -173,10 +173,10 @@ export class SettingField extends Component { onExpandChange: () => prop.onExpandChange(() => this.forceUpdate()), toggleExpand: () => { prop.toggleExpand(); - } + }, }); break; - case "entry": + case 'entry': Object.assign(extraProps, { stageName: prop.getName() }); break; default: diff --git a/packages/editor-preset-vision/src/fields/variableSetter.tsx b/packages/editor-preset-vision/src/fields/variableSetter.tsx index 51643bd16..87842967e 100644 --- a/packages/editor-preset-vision/src/fields/variableSetter.tsx +++ b/packages/editor-preset-vision/src/fields/variableSetter.tsx @@ -22,13 +22,14 @@ class Input extends Component { } private domRef: HTMLTextAreaElement | null = null; + public adjustTextAreaHeight() { if (!this.domRef) { return; } this.domRef.style.height = '1px'; const calculatedHeight = this.domRef.scrollHeight; - this.domRef.style.height = calculatedHeight >= 200 ? '200px' : calculatedHeight + 'px'; + this.domRef.style.height = calculatedHeight >= 200 ? '200px' : `${calculatedHeight }px`; } public render() { @@ -50,7 +51,7 @@ class Input extends Component { onBlur={() => this.setState({ focused: false })} onFocus={() => this.setState({ focused: true })} onKeyUp={this.adjustTextAreaHeight.bind(this)} - > + />
); } @@ -73,7 +74,7 @@ export default class VariableSetter extends Component<{ } public render() { - const prop = this.props.prop; + const { prop } = this.props; return ( { private ref: HTMLElement | null = null; + private VariableSetter: any; constructor(props: IVEFieldProps) { @@ -34,9 +35,9 @@ export default class VariableSwitcher extends Component { return (
{ @@ -48,7 +49,8 @@ export default class VariableSwitcher extends Component { } else { prop.setUseVariable(!isUseVariable); } - }}> + }} + > 绑定变量
diff --git a/packages/editor-preset-vision/src/flags.ts b/packages/editor-preset-vision/src/flags.ts index 5e6174ff0..5c5aefec3 100644 --- a/packages/editor-preset-vision/src/flags.ts +++ b/packages/editor-preset-vision/src/flags.ts @@ -5,11 +5,14 @@ import { EventEmitter } from 'events'; const Shells = ['iphone6']; export class Flags { - public emitter: EventEmitter; + public flags: string[]; + public ready: boolean; + public lastFlags: string[]; + public lastShell: string; private lastSimulatorDevice: string; diff --git a/packages/editor-preset-vision/src/i18n-util/index.js b/packages/editor-preset-vision/src/i18n-util/index.js index 06bd973ac..f5d6d2cba 100644 --- a/packages/editor-preset-vision/src/i18n-util/index.js +++ b/packages/editor-preset-vision/src/i18n-util/index.js @@ -20,7 +20,7 @@ class DocItem { type: 'i18n', ...strings, }); - this.emitter = new EventEmitter; + this.emitter = new EventEmitter(); this.inited = unInitial !== true; } @@ -69,7 +69,7 @@ class DocItem { class I18nUtil { constructor() { - this.emitter = new EventEmitter; + this.emitter = new EventEmitter(); // original data source from remote this.i18nData = {}; // current i18n records on the left pane diff --git a/packages/editor-preset-vision/src/index.ts b/packages/editor-preset-vision/src/index.ts index 358ced1fe..30a3ddef1 100644 --- a/packages/editor-preset-vision/src/index.ts +++ b/packages/editor-preset-vision/src/index.ts @@ -8,7 +8,7 @@ import { hotkey as Hotkey, monitor } from '@ali/lowcode-editor-core'; import { createElement } from 'react'; import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS, VERSION as Version } from './base/const'; import Bus from './bus'; -import { skeleton } from './editor'; +import { skeleton, designer, editor } from './editor'; import { Workbench } from '@ali/lowcode-editor-skeleton'; import Panes from './panes'; import Exchange from './exchange'; @@ -24,7 +24,7 @@ import Env from './env'; import DragEngine from './drag-engine'; import Viewport from './viewport'; import Project from './project'; -import { designer, editor } from './editor'; + import Symbols from './symbols'; import './vision.less'; @@ -162,6 +162,6 @@ const version = '6.0.0(LowcodeEngine 0.9.3)'; console.log( `%c VisionEngine %c v${version} `, - "padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060;font-weight:bold;", - "padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e;font-weight:bold;" + 'padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060;font-weight:bold;', + 'padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e;font-weight:bold;', ); diff --git a/packages/editor-preset-vision/src/panes.ts b/packages/editor-preset-vision/src/panes.ts index 592e1f7c2..8c0776cab 100644 --- a/packages/editor-preset-vision/src/panes.ts +++ b/packages/editor-preset-vision/src/panes.ts @@ -25,12 +25,12 @@ export interface OldPaneConfig { place?: string; // align: left|right|top|center|bottom description?: string; // tip? tip?: - | string - | { - // as help tip - url?: string; - content?: string | JSX.Element; - }; // help + | string + | { + // as help tip + url?: string; + content?: string | JSX.Element; + }; // help init?: () => any; destroy?: () => any; diff --git a/packages/editor-preset-vision/src/prop.ts b/packages/editor-preset-vision/src/prop.ts index 8d9abdfbf..5ead648cf 100644 --- a/packages/editor-preset-vision/src/prop.ts +++ b/packages/editor-preset-vision/src/prop.ts @@ -54,7 +54,6 @@ export interface IVariableSettable { } export default class Prop implements IVariableSettable { - /** * Setters predefined as default options * can by selected by user for every prop @@ -65,20 +64,27 @@ export default class Prop implements IVariableSettable { public static INSET_SETTER = {}; public id: string; + public emitter: EventEmitter; public inited: boolean; + public i18nLink: any; + public loopLock: boolean; public props: any; + public parent: any; public config: IPropConfig; + public initial: any; + public initialData: any; public expanded: boolean; + public useVariable?: boolean; /** @@ -86,18 +92,24 @@ export default class Prop implements IVariableSettable { * prototype.js can config Transducer.toNative to generate value */ public value: any; + /** * value to be used in VisualDesigner more flexible * prototype.js can config Transducer.toHot to generate hotValue */ public hotValue: any; + /** * 启用变量之后,变量表达式字符串值 */ public variableValue: string; + public hotData: IMMap; + public defaultValue: any; + public transducer: any; + public inGroup: boolean; constructor(parent: any, config: IPropConfig, data?: any) { @@ -263,7 +275,7 @@ export default class Prop implements IVariableSettable { public getValue(disableCache?: boolean, options?: { disableAccessor?: boolean; }) { - const accessor = this.config.accessor; + const { accessor } = this.config; if (accessor && (!options || !options.disableAccessor)) { const value = accessor.call(this as any, this.value); if (!disableCache) { @@ -313,7 +325,7 @@ export default class Prop implements IVariableSettable { return; } - const sync = this.config.sync; + const { sync } = this.config; if (sync) { const value = sync.call(this as any, this.getValue(true)); if (value !== undefined) { @@ -356,7 +368,7 @@ export default class Prop implements IVariableSettable { } } - public setUseVariable(flag: boolean = false) { + public setUseVariable(flag = false) { if (this.useVariable === flag) { return; } const state = this.props.chainReach(this); @@ -412,7 +424,7 @@ export default class Prop implements IVariableSettable { this.i18nLink = I18nUtil.attach(this, this.value, ((val: any) => this.setValue(val, false, true)) as any); - const mutator = this.config.mutator; + const { mutator } = this.config; if (!extraOptions) { extraOptions = {}; @@ -484,7 +496,7 @@ export default class Prop implements IVariableSettable { this.resolveValue(); if (!options || !options.disableMutator) { - const mutator = this.config.mutator; + const { mutator } = this.config; if (mutator) { mutator.call(this as any, value); } @@ -511,7 +523,7 @@ export default class Prop implements IVariableSettable { return true; } - let hidden = this.config.hidden; + let { hidden } = this.config; if (typeof hidden === 'function') { hidden = hidden.call(this as any, this.getValue()); } @@ -519,7 +531,7 @@ export default class Prop implements IVariableSettable { } public isDisabled() { - let disabled = this.config.disabled; + let { disabled } = this.config; if (typeof disabled === 'function') { disabled = disabled.call(this as any, this.getValue()); } @@ -529,7 +541,7 @@ export default class Prop implements IVariableSettable { public isIgnore() { if (this.isDisabled()) { return true; } - let ignore = this.config.ignore; + let { ignore } = this.config; if (typeof ignore === 'function') { ignore = ignore.call(this as any, this.getValue()); } diff --git a/packages/editor-preset-vision/src/rootNodeVisitor.ts b/packages/editor-preset-vision/src/rootNodeVisitor.ts index 811aa5fd7..266ff7930 100644 --- a/packages/editor-preset-vision/src/rootNodeVisitor.ts +++ b/packages/editor-preset-vision/src/rootNodeVisitor.ts @@ -9,11 +9,15 @@ import { DocumentModel, Node, Root } from '@ali/lowcode-designer'; */ export default class RootNodeVisitor { public nodeIdMap: {[id: string]: Node} = {}; + public nodeFieldIdMap: {[fieldId: string]: Node} = {}; + public nodeList: Node[] = []; private page: DocumentModel; + private root: RootNode; + private cancelers: Function[] = []; constructor(page: DocumentModel, rootNode: RootNode) { diff --git a/packages/editor-preset-vision/src/vc-live-editing.ts b/packages/editor-preset-vision/src/vc-live-editing.ts index 3a03161a6..59cceb655 100644 --- a/packages/editor-preset-vision/src/vc-live-editing.ts +++ b/packages/editor-preset-vision/src/vc-live-editing.ts @@ -52,7 +52,7 @@ export function liveEditingRule(target: EditingTarget) { return null; } - const innerText = targetElement.innerText; + const { innerText } = targetElement; const propTarget = ['title', 'label', 'text', 'content'].find(prop => { return equalText(getText(node, prop), innerText); }); @@ -71,7 +71,7 @@ function equalText(v: any, innerText: string) { if (typeof v !== 'string') { return false; } - return v.trim() === innerText + return v.trim() === innerText; } export const liveEditingSaveHander: SaveHandler = { @@ -108,8 +108,8 @@ export const liveEditingSaveHander: SaveHandler = { } else { prop.setValue(data); } - } -} + }, +}; // TODO: // 非文本编辑 // 国际化数据,改变当前 diff --git a/packages/editor-preset-vision/src/viewport.ts b/packages/editor-preset-vision/src/viewport.ts index 9745e9ee9..da943bed1 100644 --- a/packages/editor-preset-vision/src/viewport.ts +++ b/packages/editor-preset-vision/src/viewport.ts @@ -1,9 +1,9 @@ import { EventEmitter } from 'events'; - -const domReady = require('domready'); import Flags from './flags'; import { designer } from './editor'; +const domReady = require('domready'); + function enterFullscreen() { const elem = document.documentElement; if (elem.requestFullscreen) { @@ -29,8 +29,11 @@ interface IStyleResourceConfig { class StyleResource { config: IStyleResourceConfig; + styleElement: HTMLStyleElement; + mounted: boolean; + inited: boolean; constructor(config: IStyleResourceConfig) { @@ -38,7 +41,7 @@ class StyleResource { } matchDevice(device: string) { - const media = this.config.media; + const { media } = this.config; if (!media || media === 'ALL' || media === '*') { return true; @@ -94,11 +97,17 @@ class StyleResource { export class Viewport { preview: boolean; + focused: boolean; + slateFixed: boolean; + emitter: EventEmitter; + device: string; + focusTarget: any; + cssResourceSet: StyleResource[]; constructor() { diff --git a/packages/editor-setters/src/color-setter/index.tsx b/packages/editor-setters/src/color-setter/index.tsx index 1ae6ada64..2415e8935 100644 --- a/packages/editor-setters/src/color-setter/index.tsx +++ b/packages/editor-setters/src/color-setter/index.tsx @@ -16,20 +16,24 @@ export interface PluginProps { export default class ColorPickerView extends PureComponent { static display = 'ColorPicker'; + static propTypes = { onChange: PropTypes.func, value: PropTypes.string, }; + static defaultProps = { onChange: () => {}, value: '', }; + constructor(props: Readonly<{ value: string; defaultValue: string }>) { super(props); this.state = { value: props.value || props.defaultValue, }; } + static getDerivedStateFromProps(props: { value: string }, state: { preValue: string }) { if (props.value != state.preValue) { return { @@ -39,10 +43,11 @@ export default class ColorPickerView extends PureComponent { } return null; } + onChangeComplete = (color: Color): void => { let value; if (color.rgb.a < 1) { - const rgb = color.rgb; + const { rgb } = color; const rgba = [rgb.r, rgb.g, rgb.b, rgb.a]; value = `rgba(${rgba.join(',')})`; } else { @@ -53,13 +58,15 @@ export default class ColorPickerView extends PureComponent { }); this.props.onChange && this.props.onChange(value); }; + onInputChange = (value: string): void => { - if (/^[0-9a-zA-Z]{6}$/.test(value)) value = '#' + value; + if (/^[0-9a-zA-Z]{6}$/.test(value)) value = `#${ value}`; this.setState({ value, }); this.props.onChange && this.props.onChange(value); }; + render(): React.ReactNode { const { value, onChange, ...restProps } = this.props; const boxStyle = { @@ -74,13 +81,13 @@ export default class ColorPickerView extends PureComponent { - + ); return ( diff --git a/packages/editor-setters/src/events-setter/index.tsx b/packages/editor-setters/src/events-setter/index.tsx index cf6b78a9f..b0d806ecb 100644 --- a/packages/editor-setters/src/events-setter/index.tsx +++ b/packages/editor-setters/src/events-setter/index.tsx @@ -1,9 +1,10 @@ -import { Component, isValidElement, ReactElement, ReactNode } from 'react'; -import { Radio, Menu, Table, Icon, Dialog } from '@alifd/next'; +import { Component } from 'react'; +import { Radio, Menu, Table, Icon } from '@alifd/next'; import nativeEvents from './native-events'; import './index.scss'; -const { SubMenu, Item, Group, Divider } = Menu; + +const { Item, Group } = Menu; const RadioGroup = Radio.Group; const EVENT_CONTENTS = { @@ -18,21 +19,19 @@ const DEFINITION_EVENT_TYPE = { LIFE_CYCLE_EVENT: 'lifeCycleEvent', }; -const SETTER_NAME = 'event-setter' +const SETTER_NAME = 'event-setter'; export default class EventsSetter extends Component<{ value: any[]; onChange: (eventList: any[]) => void; }> { state = { - showEventList: false, eventBtns: [], eventList: [], selectType: null, nativeEventList: [], lifeCycleEventList: [], eventDataList: (this.props?.value?.eventDataList ? this.props.value.eventDataList : this.props?.value) || [], - relatedEventName: '', }; // constructor (){ @@ -57,19 +56,17 @@ export default class EventsSetter extends Component<{ // return null; // } - private bindEventName:String; + private bindEventName: string; componentDidMount() { - console.log(this.state.eventDataList); - const {editor} = this.props.field; + const { editor } = this.props.field; this.initEventBtns(); this.initEventList(); - editor.on(`${SETTER_NAME}.bindEvent`,(relatedEventName,paramStr)=>{ - this.bindEvent(relatedEventName,paramStr); - }) - + editor.on(`${SETTER_NAME}.bindEvent`, (relatedEventName, paramStr) => { + this.bindEvent(relatedEventName, paramStr); + }); } /** @@ -88,6 +85,8 @@ export default class EventsSetter extends Component<{ if (item.type === DEFINITION_EVENT_TYPE.EVENTS) { isCustom = true; } + + return item; }); if (isRoot) { @@ -146,6 +145,8 @@ export default class EventsSetter extends Component<{ lifeCycleEventList: item.list, }); } + + return item; }); if (nativeEventList.length == 0) { @@ -156,7 +157,7 @@ export default class EventsSetter extends Component<{ } } - checkEventListStatus = (eventList: Array, eventType: String) => { + checkEventListStatus = (eventList: any[], eventType: string) => { const { eventDataList } = this.state; if ( eventType === DEFINITION_EVENT_TYPE.EVENTS || @@ -168,7 +169,11 @@ export default class EventsSetter extends Component<{ if (item.name === eventDataItem.name) { item.disabled = true; } + + return eventDataItem; }); + + return item; }); } else if (eventType === DEFINITION_EVENT_TYPE.NATIVE_EVENTS) { eventDataList.map(eventDataItem => { @@ -179,8 +184,12 @@ export default class EventsSetter extends Component<{ } else { item.disabled = false; } + return eventItem; }); + return item; }); + + return eventDataItem; }); } }; @@ -205,7 +214,7 @@ export default class EventsSetter extends Component<{
- this.onRelatedEventNameClick(record.relatedEventName)}> + this.onRelatedEventNameClick(record.relatedEventName)}> {record.relatedEventName || ''}
@@ -216,7 +225,7 @@ export default class EventsSetter extends Component<{ /** * 渲染事件操作项 */ - renderEventOperateCell = (eventName: String) => { + renderEventOperateCell = (eventName: string) => { return (
{ + updateEventListStatus = (eventName: string, unDisabled: boolean) => { const { eventList, nativeEventList, lifeCycleEventList } = this.state; eventList.map(item => { if (item.name === eventName) { item.disabled = !unDisabled; } + return item; }); lifeCycleEventList.map(item => { if (item.name === eventName) { item.disabled = !unDisabled; } + return item; }); nativeEventList.map(item => { @@ -253,7 +264,10 @@ export default class EventsSetter extends Component<{ if (itemData.name === eventName) { itemData.disabled = !unDisabled; } + return itemData; }); + + return item; }); }; @@ -264,8 +278,7 @@ export default class EventsSetter extends Component<{ }; - - onEventMenuClick = (eventName: String) => { + onEventMenuClick = (eventName: string) => { const { selectType, eventDataList } = this.state; eventDataList.push({ type: selectType, @@ -281,22 +294,22 @@ export default class EventsSetter extends Component<{ this.openDialog(eventName); }; - onRelatedEventNameClick = (eventName:String) => { - const {editor} = this.props.field; + onRelatedEventNameClick = (eventName: string) => { + const { editor } = this.props.field; editor.get('skeleton').getPanel('sourceEditor').show(); - setTimeout(()=>{ - editor.emit('sourceEditor.focusByFunction',{ - functionName:eventName - }) - },300) + setTimeout(() => { + editor.emit('sourceEditor.focusByFunction', { + functionName: eventName, + }); + }, 300); // editor.emit('sourceEditor.focusByFunction',{ // functionName:eventName // }) - } + }; closeEventMenu = () => { if (this.state.selectType !== null) { @@ -306,7 +319,7 @@ export default class EventsSetter extends Component<{ } }; - openDeleteEventDialog = (eventName: String) => { + openDeleteEventDialog = (eventName: string) => { this.deleteEvent(eventName); // Dialog.confirm({ // title: '删除事件', @@ -315,54 +328,59 @@ export default class EventsSetter extends Component<{ // }); }; - deleteEvent = (eventName: String) => { - const { eventDataList,eventList} = this.state; + deleteEvent = (eventName: string) => { + const { eventDataList, eventList } = this.state; eventDataList.map((item, index) => { if (item.name === eventName) { eventDataList.splice(index, 1); } + + return item; }); this.setState({ eventDataList, }); - this.props.onChange({eventDataList,eventList}); + this.props.onChange({ eventDataList, eventList }); this.updateEventListStatus(eventName, true); }; - openDialog = (bindEventName: String) => { - const {editor} = this.props.field; - const {eventDataList} = this.state; + openDialog = (bindEventName: string) => { + const { editor } = this.props.field; + const { eventDataList } = this.state; let paramStr; - eventDataList.map((item)=>{ - if (item.name == bindEventName){ + eventDataList.map((item) => { + if (item.name == bindEventName) { paramStr = item.paramStr; } - }) + return item; + }); this.bindEventName = bindEventName; - editor.emit('eventBindDialog.openDialog',bindEventName,SETTER_NAME,paramStr); + editor.emit('eventBindDialog.openDialog', bindEventName, SETTER_NAME, paramStr); }; - bindEvent = (relatedEventName: String,paramStr:String) => { - const {eventDataList,eventList} = this.state; + bindEvent = (relatedEventName: string, paramStr: string) => { + const { eventDataList, eventList } = this.state; eventDataList.map(item => { if (item.name === this.bindEventName) { item.relatedEventName = relatedEventName; - if (paramStr){ - item.paramStr = paramStr + if (paramStr) { + item.paramStr = paramStr; } } + + return item; }); this.setState({ - eventDataList - }) + eventDataList, + }); - this.props.onChange({eventDataList,eventList}); + this.props.onChange({ eventDataList, eventList }); - //this.closeDialog(); + // this.closeDialog(); }; render() { @@ -374,15 +392,14 @@ export default class EventsSetter extends Component<{ selectType, eventDataList, } = this.state; - const {editor} = this.props.field; - let showEventList = + const showEventList = lifeCycleEventList.length > 0 ? lifeCycleEventList : eventList; return (
{ - eventBtns.length>1 ?点击选择事件类型:点击绑定事件 + eventBtns.length > 1 ? 点击选择事件类型 : 点击绑定事件 }
@@ -400,7 +417,7 @@ export default class EventsSetter extends Component<{ className="event-menu" onItemClick={this.onEventMenuClick} > - {showEventList.map((item, index) => ( + {showEventList.map((item) => ( {nativeEventList.map((item, index) => ( - {item.eventList.map(item => ( - - {item.name} + {item.eventList.map(groupItem => ( + + {groupItem.name} ))} diff --git a/packages/editor-setters/src/expression-setter/index.tsx b/packages/editor-setters/src/expression-setter/index.tsx index 94b9a824e..d1df5ea1f 100644 --- a/packages/editor-setters/src/expression-setter/index.tsx +++ b/packages/editor-setters/src/expression-setter/index.tsx @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import { Select, Balloon, Icon } from '@alife/next'; +import { Select, Balloon } from '@alife/next'; import * as acorn from 'acorn'; import { isJSExpression, generateI18n } from './locale/utils'; @@ -12,15 +12,15 @@ const { Option, AutoComplete } = Select; const { Tooltip } = Balloon; const helpMap = { this: '容器上下文对象', - 'state': '容器的state', - 'props': '容器的props', - 'context': '容器的context', - 'schema': '页面上下文对象', - 'component': '组件上下文对象', - 'constants': '应用常量对象', - 'utils': '应用工具对象', - 'dataSourceMap': '容器数据源Map', - 'field': '表单Field对象' + state: '容器的state', + props: '容器的props', + context: '容器的context', + schema: '页面上下文对象', + component: '组件上下文对象', + constants: '应用常量对象', + utils: '应用工具对象', + dataSourceMap: '容器数据源Map', + field: '表单Field对象', }; export default class ExpressionView extends PureComponent { @@ -68,13 +68,12 @@ export default class ExpressionView extends PureComponent { return val; } - constructor(props: Readonly<{}>) { + constructor(props: any) { super(props); this.expression = React.createRef(); this.i18n = generateI18n(props.locale, props.messages); this.state = { value: ExpressionView.getInitValue(props.value), - context: props.context || {}, dataSource: props.dataSource || [], }; } @@ -126,31 +125,15 @@ export default class ExpressionView extends PureComponent { * @param {String} * @return {Array} */ - getDataSource(tempStr: string): any[] { - const {editor} = this.props.field; + getDataSource(): any[] { + const { editor } = this.props.field; const schema = editor.get('designer').project.getSchema(); const stateMap = schema.componentsTree[0].state; - let dataSource = []; + const dataSource = []; - for (let key in stateMap){ + for (const key in stateMap) { dataSource.push(`this.state.${key}`); } - // if (/[^\w\.]$/.test(tempStr)) { - // return []; - // } else if (tempStr === null || tempStr === '') { - // return this.getContextKeys([]); - // } else if (/\w\.$/.test(tempStr)) { - // const currentField = this.getCurrentFiled(tempStr); - // if (!currentField) return null; - // let tempKeys = this.getObjectKeys(currentField.str); - // tempKeys = this.getContextKeys(tempKeys); - // if (!tempKeys) return null; - // return tempKeys; - // } else if (/\.$/.test(tempStr)) { - // return []; - // } else { - // return null; - // } return dataSource; } @@ -283,12 +266,11 @@ export default class ExpressionView extends PureComponent { innerBefore={{'{{'}} innerAfter={{'}}'}} popupClassName="expression-setter-item-inner" - itemRender={({ value }) => { - console.log('111:'+value); + itemRender={({ itemValue }) => { return ( - ); }} @@ -312,6 +294,7 @@ export default class ExpressionView extends PureComponent { const isMoveKey = !!(event.type == 'keyup' && ~[37, 38, 39, 91].indexOf(event.keyCode)); const isMouseup = event.type == 'mouseup'; if (isMoveKey || isMouseup) { + // eslint-disable-next-line react/no-access-state-in-setstate const dataSource = this.getDataSource(this.state.value) || []; this.setState({ dataSource, diff --git a/packages/editor-setters/src/expression-setter/locale/snippets.ts b/packages/editor-setters/src/expression-setter/locale/snippets.ts index 7c8484c4f..2bcb0dd00 100644 --- a/packages/editor-setters/src/expression-setter/locale/snippets.ts +++ b/packages/editor-setters/src/expression-setter/locale/snippets.ts @@ -4,21 +4,21 @@ export default [ kind: 'Class', insertText: 'constants', detail: '应用全局常量', - documentation: '应用范围定义的通用常量' + documentation: '应用范围定义的通用常量', }, { label: 'utils', kind: 'Class', insertText: 'utils', detail: '应用全局公共函数', - documentation: '应用范围扩展的公共函数' + documentation: '应用范围扩展的公共函数', }, { label: 'state', kind: 'Enum', insertText: 'state', detail: '当前所在容器组件内部状态', - documentation: 'React Class内部状态state' + documentation: 'React Class内部状态state', }, { label: 'setState', @@ -26,7 +26,7 @@ export default [ insertText: 'setState({\n\t$0\n})', insertTextRules: 'InsertAsSnippet', detail: '设置当前所在容器组件的state数据', - documentation: '原生React方法,会自动更新组件视图' + documentation: '原生React方法,会自动更新组件视图', }, { label: 'reloadDataSource', @@ -34,45 +34,45 @@ export default [ insertText: 'reloadDataSource(${1:${2:namespace}, ${3:false}, ${4:callback}})', insertTextRules: 'InsertAsSnippet', detail: '刷新当前所在的容器组件', - documentation: '触发当前所在的容器组件,重新发送异步请求,并用最新数据更新视图' + documentation: '触发当前所在的容器组件,重新发送异步请求,并用最新数据更新视图', }, { label: 'location', kind: 'Class', insertText: 'location', - detail: '路由解析对象' + detail: '路由解析对象', }, { label: 'location.query', kind: 'Value', insertText: 'location.query.${1:xxxx}', insertTextRules: 'InsertAsSnippet', - detail: '从路由解析对象中获取参数信息' + detail: '从路由解析对象中获取参数信息', }, { label: 'history', kind: 'Class', insertText: 'history', - detail: '路由历史对象' + detail: '路由历史对象', }, { label: 'React', kind: 'Keyword', insertText: 'React', - detail: 'React对象' + detail: 'React对象', }, { label: 'ReactDOM', kind: 'Keyword', insertText: 'ReactDOM', - detail: 'ReactDom对象' + detail: 'ReactDom对象', }, { label: 'ReactDOM.findDOMNode', kind: 'Function', insertText: 'ReactDOM.findDOMNode(${1:this.refs.xxxx})', insertTextRules: 'InsertAsSnippet', - detail: 'ReactDom查找真实dom node' + detail: 'ReactDom查找真实dom node', }, { label: 'Dialog.alert', @@ -84,10 +84,10 @@ export default [ '\tonOk: () => {', '\t\t$3', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: 'alert弹框 By Fusion' + detail: 'alert弹框 By Fusion', }, { label: 'Dialog.confirm', @@ -102,52 +102,52 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '确认弹出框 By Fusion' + detail: '确认弹出框 By Fusion', }, { label: 'Message.success', kind: 'Method', insertText: 'Message.success(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '成功反馈提示 By Fusion' + detail: '成功反馈提示 By Fusion', }, { label: 'Message.error', kind: 'Method', insertText: 'Message.error(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '错误反馈提示 By Fusion' + detail: '错误反馈提示 By Fusion', }, { label: 'Message.help', kind: 'Method', insertText: 'Message.help(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '帮助反馈提示 By Fusion' + detail: '帮助反馈提示 By Fusion', }, { label: 'Message.loading', kind: 'Method', insertText: 'Message.loading(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: 'loading反馈提示 By Fusion' + detail: 'loading反馈提示 By Fusion', }, { label: 'Message.notice', kind: 'Method', insertText: 'Message.notice(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '注意反馈提示 By Fusion' + detail: '注意反馈提示 By Fusion', }, { label: 'Message.waining', kind: 'Method', insertText: 'Message.waining(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '警告反馈提示 By Fusion' + detail: '警告反馈提示 By Fusion', }, { label: 'Modal.confirm', @@ -162,10 +162,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '确认弹出框 By Antd' + detail: '确认弹出框 By Antd', }, { label: 'Modal.info', @@ -180,10 +180,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '信息弹出框 By Antd' + detail: '信息弹出框 By Antd', }, { label: 'Modal.success', @@ -198,10 +198,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '成功弹出框 By Antd' + detail: '成功弹出框 By Antd', }, { label: 'Modal.error', @@ -216,10 +216,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '错误弹出框 By Antd' + detail: '错误弹出框 By Antd', }, { label: 'Modal.warning', @@ -234,9 +234,9 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '警告弹出框 By Antd' - } -]; \ No newline at end of file + detail: '警告弹出框 By Antd', + }, +]; diff --git a/packages/editor-setters/src/expression-setter/locale/utils.ts b/packages/editor-setters/src/expression-setter/locale/utils.ts index a02a8dd06..d401ad511 100644 --- a/packages/editor-setters/src/expression-setter/locale/utils.ts +++ b/packages/editor-setters/src/expression-setter/locale/utils.ts @@ -1,11 +1,11 @@ import IntlMessageFormat from 'intl-messageformat'; export const isJSExpression = (obj = '') => { - if(obj && typeof obj === 'object' && obj.type === 'JSExpression') { + if (obj && typeof obj === 'object' && obj.type === 'JSExpression') { return true; } return false; -} +}; /** * 用于构造国际化字符串处理函数 @@ -18,4 +18,4 @@ export const generateI18n = (locale = 'zh-CN', messages = {}) => { const formater = new IntlMessageFormat(messages[key], locale); return formater.format(values); }; -} +}; diff --git a/packages/editor-setters/src/expression-setter/locale/zh-CN.ts b/packages/editor-setters/src/expression-setter/locale/zh-CN.ts index 951596009..f4f2e0630 100644 --- a/packages/editor-setters/src/expression-setter/locale/zh-CN.ts +++ b/packages/editor-setters/src/expression-setter/locale/zh-CN.ts @@ -33,4 +33,4 @@ export default { object: '对象ObjectButton', reactNode: '节点类型ReactNode', typeError: 'Minix组件属性Types配置错误,存在不支持类型[{type}],请检查组件属性配置', -}; \ No newline at end of file +}; diff --git a/packages/editor-setters/src/function-setter/index.tsx b/packages/editor-setters/src/function-setter/index.tsx index 397e131c5..003c45e68 100644 --- a/packages/editor-setters/src/function-setter/index.tsx +++ b/packages/editor-setters/src/function-setter/index.tsx @@ -1,12 +1,11 @@ import React, { PureComponent } from 'react'; // import PropTypes from 'prop-types'; -import { Button, Icon,Dialog } from '@alifd/next'; +import { Button, Icon, Dialog } from '@alifd/next'; import MonacoEditor from 'react-monaco-editor'; -import { js_beautify, css_beautify } from 'js-beautify'; +import { js_beautify } from 'js-beautify'; import './index.scss'; -import { timingSafeEqual } from 'crypto'; -const SETTER_NAME = 'function-setter' +const SETTER_NAME = 'function-setter'; const defaultEditorOption = { width: '100%', @@ -14,7 +13,7 @@ const defaultEditorOption = { options: { readOnly: false, automaticLayout: true, - folding: true, //默认开启折叠代码功能 + folding: true, // 默认开启折叠代码功能 lineNumbers: 'on', wordWrap: 'off', formatOnPaste: true, @@ -40,103 +39,100 @@ interface FunctionSetterProps { defaultValue: string; placeholder: string; hasClear: boolean; - onChange: (icon: string | object) => undefined; + onChange: (icon: string) => undefined; icons: string[]; } -export default class FunctionSetter extends PureComponent { +export default class FunctionSetter extends PureComponent { static defaultProps = { value: undefined, type: 'string', defaultValue: '', hasClear: true, placeholder: '请点击选择 Icon', - onChange: (icon: string | object) => undefined, + onChange: () => undefined, }; private emitEventName = ''; state = { - firstLoad: true, - isShowDialog:false, - functionCode:null + isShowDialog: false, }; componentDidMount() { const { editor } = this.props.field; this.emitEventName = `${SETTER_NAME}-${this.props.field.id}`; - editor.on(`${this.emitEventName}.bindEvent`, this.bindEvent) + editor.on(`${this.emitEventName}.bindEvent`, this.bindEvent); } bindEvent = (eventName) => { this.bindEventCallback(eventName); - } + }; componentWillUnmount() { const { editor } = this.props.field; - editor.off(`${this.emitEventName}.bindEvent`, this.bindEvent) + editor.off(`${this.emitEventName}.bindEvent`, this.bindEvent); } bindFunction = () => { - const { field, value } = this.props; + const { field } = this.props; field.editor.emit('eventBindDialog.openDialog', field.name, this.emitEventName); - } + }; openDialog = () => { - const {value={}} = this.props; + const { value = {} } = this.props; this.setState({ - isShowDialog:true - }) + isShowDialog: true, + }); this.functionCode = value.value; - - } + }; closeDialog = () => { this.setState({ - isShowDialog:false - }) - } + isShowDialog: false, + }); + }; removeFunctionBind = () => { - const { field ,removeProp} = this.props; + const { removeProp } = this.props; removeProp(); - } + }; - parseFunctionName = (functionString: String) => { + parseFunctionName = (functionString: string) => { // 因为函数格式是固定的,所以可以按照字符换去匹配获取函数名 - let funNameStr = functionString.split('this.')[1]; + const funNameStr = functionString.split('this.')[1]; - if (funNameStr){ - let endIndex = funNameStr.indexOf('('); + if (funNameStr) { + const endIndex = funNameStr.indexOf('('); return funNameStr.substr(0, endIndex); - }else{ - return '' + } else { + return ''; } - } + }; /** * 渲染按钮(初始状态) */ renderButton = () => { - return - } + return ; + }; updateCode = (newCode) => { this.functionCode = newCode; - } + }; onDialogOk = () => { - const {onChange} = this.props; + const { onChange } = this.props; onChange({ type: 'JSFunction', - value: this.functionCode + value: this.functionCode, }); this.closeDialog(); - } + }; focusFunctionName = (functionName) => { const { editor } = this.props.field; @@ -145,73 +141,90 @@ export default class FunctionSetter extends PureComponent { editor.emit('sourceEditor.focusByFunction', { - functionName - }) - }, 300) - } + functionName, + }); + }, 300); + }; /** * 渲染绑定函数 */ renderBindFunction = () => { const { value } = this.props; - + // 解析函数名 - let functionName = this.parseFunctionName(value.value); - return
- - this.focusFunctionName(functionName)}>{functionName} - - -
- } + const functionName = this.parseFunctionName(value.value); + return ( +
+ + this.focusFunctionName(functionName)}>{functionName} + + +
+ ); + }; /** * 渲染编辑函数按钮(可直接编辑函数内容) */ renderEditFunctionButton = () => { - return
- + return ( +
+
- } + ); + }; - bindEventCallback = (eventName: String) => { + bindEventCallback = (eventName: string) => { const { onChange } = this.props; onChange({ type: 'JSFunction', value: `function(){ this.${eventName}() }`, }); - } + }; render() { const { value } = this.props; - const {isShowDialog} = this.state; + const { isShowDialog } = this.state; let functionName = ''; - if (value && value.value){ + if (value && value.value) { functionName = this.parseFunctionName(value.value); } - return
- { - value ? (functionName?this.renderBindFunction():this.renderEditFunctionButton()) : this.renderButton() + + let renderFunction; + if (value) { + if (functionName) { + renderFunction = this.renderBindFunction; + } else { + renderFunction = this.renderEditFunctionButton; + } + } else { + renderFunction = this.renderButton; + } + + return ( +
+ { + renderFunction() } - { - value && value.value && {this.closeDialog()}}> -
- { this.closeDialog(); }}> +
+ this.updateCode(newCode)} /> -
+
} - - -
; +
+ ); } } diff --git a/packages/editor-setters/src/icon-setter/index.tsx b/packages/editor-setters/src/icon-setter/index.tsx index 0762b9ff3..f61c32271 100644 --- a/packages/editor-setters/src/icon-setter/index.tsx +++ b/packages/editor-setters/src/icon-setter/index.tsx @@ -68,18 +68,18 @@ interface IconSetterProps { defaultValue: string; placeholder: string; hasClear: boolean; - onChange: (icon: string | object) => undefined; + onChange: (icon: string) => undefined; icons: string[]; } -export default class IconSetter extends PureComponent { +export default class IconSetter extends PureComponent { static defaultProps = { value: undefined, type: 'string', defaultValue: '', hasClear: true, - icons: icons, + icons, placeholder: '请点击选择 Icon', - onChange: (icon: string | object) => undefined, + onChange: () => undefined, }; state = { @@ -109,7 +109,7 @@ export default class IconSetter extends PureComponent { }; render() { - const { icons, value, defaultValue, onChange, placeholder, hasClear, type } = this.props; + const { value, defaultValue, onChange, placeholder, hasClear } = this.props; const { firstLoad } = this.state; const _value = typeof value === 'object' ? value?.props?.type : value; if (firstLoad && defaultValue && typeof value === 'undefined') { @@ -149,7 +149,7 @@ export default class IconSetter extends PureComponent { { @@ -67,9 +68,11 @@ class StringDateSetter extends Component { ); } } + +// eslint-disable-next-line react/no-multi-comp class StringTimePicker extends Component { render() { - const { onChange, editor } = this.props; + const { onChange } = this.props; return ( { @@ -80,7 +83,7 @@ class StringTimePicker extends Component { } } -const VariableSetter ={ +const VariableSetter = { component: ExpressionSetter, condition: (field: any) => { const v = field.getValue(); @@ -99,7 +102,7 @@ const FunctionBindSetter = { const v = field.getValue(); return v == isJSFunction(v); }, -} +}; const builtinSetters: any = { StringSetter, @@ -120,7 +123,7 @@ const builtinSetters: any = { JsonSetter, StyleSetter, IconSetter, - FunctionSetter:FunctionBindSetter + FunctionSetter: FunctionBindSetter, }; registerSetter(builtinSetters); diff --git a/packages/editor-setters/src/json-setter/index.tsx b/packages/editor-setters/src/json-setter/index.tsx index 7ae9b80d0..ae08d750d 100644 --- a/packages/editor-setters/src/json-setter/index.tsx +++ b/packages/editor-setters/src/json-setter/index.tsx @@ -14,11 +14,12 @@ import Snippets from './locale/snippets'; import zhCN from './locale/zh-CN'; import './index.scss'; -let registerApiAndSnippetStatus = false; //判断注册api机制 +let registerApiAndSnippetStatus = false; // 判断注册api机制 window.bt = js_beautify; class MonacoEditorView extends PureComponent { static displayName = 'MonacoEditor'; + render() { const { type, ...restProps } = this.props; const Node = type == 'button' ? MonacoEditorButtonView : MonacoEditorDefaultView; @@ -28,30 +29,33 @@ class MonacoEditorView extends PureComponent { localeConfig('MonacoEditor', MonacoEditorView); -//monaco编辑器存在3种主题:vs、vs-dark、hc-black +// monaco编辑器存在3种主题:vs、vs-dark、hc-black +// eslint-disable-next-line react/no-multi-comp class MonacoEditorDefaultView extends PureComponent { static displayName = 'MonacoEditorDefault'; + static propTypes = { locale: PropTypes.string, messages: PropTypes.object, language: PropTypes.string, }; + static defaultProps = { locale: 'zh-CN', messages: zhCN, width: '100%', height: '300px', language: 'json', - autoFocus: false, //自动获得焦点 - autoSubmit: true, //自动提交 - placeholder: '', //默认占位内容 + autoFocus: false, // 自动获得焦点 + autoSubmit: true, // 自动提交 + placeholder: '', // 默认占位内容 btnText: '提交', btnSize: 'small', - rules: [], //校验规则 + rules: [], // 校验规则 options: { readOnly: false, automaticLayout: true, - folding: true, //默认开启折叠代码功能 + folding: true, // 默认开启折叠代码功能 lineNumbers: 'on', wordWrap: 'off', formatOnPaste: true, @@ -70,16 +74,26 @@ class MonacoEditorDefaultView extends PureComponent { }, }, }; + strValue: string; + i18n: any; + editorRef: React.RefObject; + options: any; + fullScreenOptions: any; + position: any; + editor: any; + editorNode: unknown; + editorParentNode: any; - constructor(props: Readonly<{}>) { + + constructor(props: Readonly) { super(props); this.strValue = ''; this.i18n = generateI18n(props.locale, props.messages); @@ -104,17 +118,18 @@ class MonacoEditorDefaultView extends PureComponent { } componentDidUpdate() { - //如果是全屏操作,获得焦点,光标保留在原来位置; + // 如果是全屏操作,获得焦点,光标保留在原来位置; if (this.position) { this.editor.focus(); this.editor.setPosition(this.position); delete this.position; } } + componentDidMount() { - this.editorNode = this.editorRef.current; //记录当前dom节点; - this.editorParentNode = this.editorNode.parentNode; //记录父节点; - //自动获得焦点, 格式化需要时间 + this.editorNode = this.editorRef.current; // 记录当前dom节点; + this.editorParentNode = this.editorNode.parentNode; // 记录父节点; + // 自动获得焦点, 格式化需要时间 if (this.props.autoFocus) { setTimeout(() => { this.editor.setPosition({ @@ -124,7 +139,7 @@ class MonacoEditorDefaultView extends PureComponent { this.editor.focus(); }, 100); } - //快捷键编码 + // 快捷键编码 const CtrlCmd = 2048; const KEY_S = 49; const Shift = 1024; @@ -133,28 +148,28 @@ class MonacoEditorDefaultView extends PureComponent { const Escape = 9; this.editor.addCommand(CtrlCmd | KEY_S, () => { - this.onSubmit(); //保存快捷键 + this.onSubmit(); // 保存快捷键 }); this.editor.addCommand(CtrlCmd | Shift | KEY_F, () => { - this.fullScreen(); //全屏快捷键 + this.fullScreen(); // 全屏快捷键 }); this.editor.addCommand(CtrlCmd | KEY_B, () => { - this.format(); //美化快捷键 + this.format(); // 美化快捷键 }); this.editor.addCommand(Escape, () => { this.props.onEscape && this.props.onEscape(); }); - //注册api + // 注册api this.editor.submit = this.onSubmit; this.editor.format = this.format; this.editor.fullScreen = this.fullScreen; this.editor.toJson = this.toJson; this.editor.toObject = this.toObject; this.editor.toFunction = this.toFunction; - //针对object情况,改写setValue和getValue api + // 针对object情况,改写setValue和getValue api if (this.props.language === 'object') { - const getValue = this.editor.getValue; - const setValue = this.editor.setValue; + const { getValue } = this.editor; + const { setValue } = this.editor; this.editor.getValue = () => { return getValue.call(this.editor).substring(this.valuePrefix.length); }; @@ -180,18 +195,18 @@ class MonacoEditorDefaultView extends PureComponent { } = this.props; const { isFullScreen } = this.state; - this.valuePrefix = ''; //值前缀 + this.valuePrefix = ''; // 值前缀 if (language === 'object') this.valuePrefix = 'export default '; if (!this.isFullScreenAction) { - //将值转换成目标值 + // 将值转换成目标值 const nowValue = this.valueHandler(value || placeholder, language); const curValue = this.valueHandler(this.strValue, language); if (nowValue !== curValue) this.strValue = nowValue; - if (language === 'object') this.strValue = this.strValue || placeholder || '{\n\t\n}'; //设置初始化值 + if (language === 'object') this.strValue = this.strValue || placeholder || '{\n\t\n}'; // 设置初始化值 if (language === 'json' && this.strValue === '{}') this.strValue = '{\n\t\n}'; } this.isFullScreenAction = false; - //真实高亮语言 + // 真实高亮语言 let tarLanguage = language; if (language === 'object' || language === 'function') { tarLanguage = 'javascript'; @@ -242,11 +257,11 @@ class MonacoEditorDefaultView extends PureComponent { ); } - //值变化 + // 值变化 onChange(curValue) { if (curValue === this.valuePrefix + this.strValue) return; const { onAfterChange, language, autoSubmit, onChange } = this.props; - this.strValue = curValue; //记录当前格式 + this.strValue = curValue; // 记录当前格式 if (this.ct) clearTimeout(this.ct); this.ct = setTimeout(() => { this.position = this.editor.getPosition(); @@ -256,7 +271,7 @@ class MonacoEditorDefaultView extends PureComponent { }, 300); } - //提交动作 + // 提交动作 onSubmit() { const { onSubmit, onChange, language } = this.props; const curValue = this.editor.getValue(); @@ -265,7 +280,7 @@ class MonacoEditorDefaultView extends PureComponent { onSubmit && onSubmit(ret.value, ret.error, this.editor); } - //值类型转换处理 + // 值类型转换处理 valueHandler(value, language) { let tarValue = value || ''; if (language === 'json') { @@ -274,8 +289,12 @@ class MonacoEditorDefaultView extends PureComponent { } else if (value && typeof value === 'string') { try { const ret = this.toJson(value); - if (!ret.error) tarValue = JSON.stringify(ret.value, null, 2); - } catch (err) {} + if (!ret.error) { + tarValue = JSON.stringify(ret.value, null, 2); + } + } catch (err) { + // empty + } } } else if (language === 'function') { if (typeof value === 'function') { @@ -285,25 +304,29 @@ class MonacoEditorDefaultView extends PureComponent { tarValue = js_beautify(tarValue, { indent_size: 2, indent_empty_lines: true }); } } else if (language === 'object') { - //先转成对象,在进行序列化和格式化; + // 先转成对象,在进行序列化和格式化; value = value || {}; if (value && typeof value === 'object') { try { tarValue = serialize(value, { unsafe: true }); tarValue = js_beautify(tarValue, { indent_size: 2, indent_empty_lines: true }); - } catch (err) {} + } catch (err) { + // empty + } } else if (typeof value === 'string') { try { const ret = this.resultHandler(value, 'object'); tarValue = ret.error ? ret.value : serialize(ret.value, { unsafe: true }); tarValue = js_beautify(tarValue, { indent_size: 2, indent_empty_lines: true }); - } catch (err) {} + } catch (err) { + // empty + } } } return tarValue; } - //结果处理 + // 结果处理 resultHandler(value, language) { let ret = { value }; if (language === 'json') { @@ -316,10 +339,10 @@ class MonacoEditorDefaultView extends PureComponent { return ret; } - //设置全屏时的动作 + // 设置全屏时的动作 fullScreen() { if (!this.editorRef) return; - //还原到原来位置; + // 还原到原来位置; this.position = this.editor.getPosition(); if (this.state.isFullScreen) { if (this.editorParentNode) { @@ -332,8 +355,9 @@ class MonacoEditorDefaultView extends PureComponent { } else { document.body.appendChild(this.editorNode); } + // eslint-disable-next-line react/no-access-state-in-setstate const nextFs = !this.state.isFullScreen; - this.isFullScreenAction = true; //记录是全屏幕操作 + this.isFullScreenAction = true; // 记录是全屏幕操作 this.setState( { isFullScreen: nextFs, @@ -344,9 +368,8 @@ class MonacoEditorDefaultView extends PureComponent { ); } - //美化代码 + // 美化代码 format() { - const { language } = this.props; if (!this.editor) return; if (/^\$_obj?\{.*?\}$/m.test(this.editor.getValue())) return; if (this.props.language === 'json' || this.props.language === 'object' || this.props.language === 'function') { @@ -360,11 +383,13 @@ class MonacoEditorDefaultView extends PureComponent { } } - //校验是否是json + // 校验是否是json toJson(value) { try { + // eslint-disable-next-line no-new-func const obj = new Function(`'use strict'; return ${value.replace(/[\r\n\t]/g, '')}`)(); if (typeof obj === 'object' && obj) { + // eslint-disable-next-line no-new-func const tarValue = new Function(`'use strict'; return ${value}`)(); return { value: JSON.parse(JSON.stringify(tarValue)) }; } @@ -374,9 +399,10 @@ class MonacoEditorDefaultView extends PureComponent { } } - //校验是否为object对象 + // 校验是否为object对象 toObject(value) { try { + // eslint-disable-next-line no-new-func const obj = new Function(`'use strict';return ${value}`)(); if (obj && typeof obj === 'object') { if (jsonuri.isCircular(obj)) return { error: this.i18n('circularRef'), value }; @@ -389,9 +415,10 @@ class MonacoEditorDefaultView extends PureComponent { } } - //校验是否为function + // 校验是否为function toFunction(value) { try { + // eslint-disable-next-line no-new-func const fun = new Function(`'use strict';return ${value}`)(); if (fun && typeof fun === 'function') { return { value: fun }; @@ -403,11 +430,11 @@ class MonacoEditorDefaultView extends PureComponent { } } - //注册api和代码片段 + // 注册api和代码片段 registerApiAndSnippet(monaco) { if (registerApiAndSnippetStatus) return; registerApiAndSnippetStatus = true; - //注册this.提示的方法; + // 注册this.提示的方法; const thisSuggestions = []; Snippets.map((item) => { if (!item.label || !item.kind || !item.insertText) return; @@ -416,9 +443,9 @@ class MonacoEditorDefaultView extends PureComponent { kind: monaco.languages.CompletionItemKind[item.kind], insertText: item.insertText, }); - if (item.insertTextRules) - tarItem.insertTextRules = monaco.languages.CompletionItemInsertTextRule[item.insertTextRules]; + if (item.insertTextRules) tarItem.insertTextRules = monaco.languages.CompletionItemInsertTextRule[item.insertTextRules]; thisSuggestions.push(tarItem); + return item; }); monaco.languages.registerCompletionItemProvider('javascript', { provideCompletionItems: (model, position) => { @@ -430,7 +457,7 @@ class MonacoEditorDefaultView extends PureComponent { }); const match = textUntilPosition.match(/(^this\.)|(\sthis\.)/); const suggestions = match ? thisSuggestions : []; - return { suggestions: suggestions }; + return { suggestions }; }, triggerCharacters: ['.'], }); @@ -439,7 +466,7 @@ class MonacoEditorDefaultView extends PureComponent { const prefix = 'data:text/javascript;charset=utf-8,'; const baseUrl = 'https://g.alicdn.com/iceluna/iceluna-vendor/0.0.1/'; window.MonacoEnvironment = { - getWorkerUrl: function(label: string) { + getWorkerUrl(label: string) { if (label === 'json') { return `${prefix}${encodeURIComponent(` importScripts('${baseUrl}json.worker.js');`)}`; @@ -461,33 +488,42 @@ window.MonacoEnvironment = { }, }; +// eslint-disable-next-line react/no-multi-comp export default class MonacoEditorButtonView extends PureComponent { static displayName = 'JsonSetter'; + static propTypes = { locale: PropTypes.string, messages: PropTypes.object, }; + static defaultProps = { locale: 'zh-CN', messages: zhCN, }; + i18n: any; + objectButtonRef: React.RefObject; - constructor(props: Readonly<{}>) { + + constructor(props: Readonly) { super(props); this.i18n = generateI18n(props.locale, props.messages); this.objectButtonRef = React.createRef(); // 兼容代码,待去除 window.__ctx.appHelper.constants = window.__ctx.appHelper.constants || {}; } + afterHandler(value: { nrs_temp_field: any }) { if (!value) return; return value.nrs_temp_field; } + beforeHandler(value: any) { if (!value) return; return { nrs_temp_field: value }; } + message(type: string, title: any, dom: Element | null) { Message.show({ type, @@ -499,6 +535,7 @@ export default class MonacoEditorButtonView extends PureComponent { }, }); } + componentDidMount() { const { registerApi } = this.props; const objectButtonThis = this.objectButtonRef; @@ -510,6 +547,7 @@ export default class MonacoEditorButtonView extends PureComponent { setValues: objectButtonThis.setValues, }); } + render() { const self = this; const { locale, messages, value, onChange, field, languages, ...restProps } = this.props; @@ -518,8 +556,8 @@ export default class MonacoEditorButtonView extends PureComponent { tarRestProps.autoSubmit = true; tarRestProps.autoFocus = true; const tarOnSubmit = tarRestProps.onSubmit; - //确保monaco快捷键保存,能出发最外层的保存 - tarRestProps.onSubmit = (value, error) => { + // 确保monaco快捷键保存,能出发最外层的保存 + tarRestProps.onSubmit = (editorValue, error) => { const msgDom = document.querySelector('.object-button-overlay .next-dialog-body'); if (error) return this.message('error', this.i18n('formatError'), msgDom); this.objectButtonRef && @@ -539,12 +577,12 @@ export default class MonacoEditorButtonView extends PureComponent { tarObjProps.value = value || ''; tarObjProps.onChange = onChange; const tarRule = []; - //判断,如果是json,function, object等类型,自动追加校验规则; + // 判断,如果是json,function, object等类型,自动追加校验规则; if (tarRestProps.language && ['json', 'function', 'object'].includes(tarRestProps.language)) { if (['json', 'object'].includes(tarRestProps.language)) { tarRule.push({ - validator: function(value: any, callback: (arg0: undefined) => void) { - if (typeof value !== 'object') { + validator(validatorValue: any, callback: (arg0: undefined) => void) { + if (typeof validatorValue !== 'object') { callback(self.i18n('formatError')); } else { callback(); @@ -553,8 +591,8 @@ export default class MonacoEditorButtonView extends PureComponent { }); } else { tarRule.push({ - validator: function(value: any, callback: (arg0: undefined) => void) { - if (typeof value !== 'function') { + validator(validatorValue: any, callback: (arg0: undefined) => void) { + if (typeof validatorValue !== 'function') { callback(self.i18n('formatError')); } else { callback(); diff --git a/packages/editor-setters/src/json-setter/locale/snippets.ts b/packages/editor-setters/src/json-setter/locale/snippets.ts index 7c8484c4f..2bcb0dd00 100644 --- a/packages/editor-setters/src/json-setter/locale/snippets.ts +++ b/packages/editor-setters/src/json-setter/locale/snippets.ts @@ -4,21 +4,21 @@ export default [ kind: 'Class', insertText: 'constants', detail: '应用全局常量', - documentation: '应用范围定义的通用常量' + documentation: '应用范围定义的通用常量', }, { label: 'utils', kind: 'Class', insertText: 'utils', detail: '应用全局公共函数', - documentation: '应用范围扩展的公共函数' + documentation: '应用范围扩展的公共函数', }, { label: 'state', kind: 'Enum', insertText: 'state', detail: '当前所在容器组件内部状态', - documentation: 'React Class内部状态state' + documentation: 'React Class内部状态state', }, { label: 'setState', @@ -26,7 +26,7 @@ export default [ insertText: 'setState({\n\t$0\n})', insertTextRules: 'InsertAsSnippet', detail: '设置当前所在容器组件的state数据', - documentation: '原生React方法,会自动更新组件视图' + documentation: '原生React方法,会自动更新组件视图', }, { label: 'reloadDataSource', @@ -34,45 +34,45 @@ export default [ insertText: 'reloadDataSource(${1:${2:namespace}, ${3:false}, ${4:callback}})', insertTextRules: 'InsertAsSnippet', detail: '刷新当前所在的容器组件', - documentation: '触发当前所在的容器组件,重新发送异步请求,并用最新数据更新视图' + documentation: '触发当前所在的容器组件,重新发送异步请求,并用最新数据更新视图', }, { label: 'location', kind: 'Class', insertText: 'location', - detail: '路由解析对象' + detail: '路由解析对象', }, { label: 'location.query', kind: 'Value', insertText: 'location.query.${1:xxxx}', insertTextRules: 'InsertAsSnippet', - detail: '从路由解析对象中获取参数信息' + detail: '从路由解析对象中获取参数信息', }, { label: 'history', kind: 'Class', insertText: 'history', - detail: '路由历史对象' + detail: '路由历史对象', }, { label: 'React', kind: 'Keyword', insertText: 'React', - detail: 'React对象' + detail: 'React对象', }, { label: 'ReactDOM', kind: 'Keyword', insertText: 'ReactDOM', - detail: 'ReactDom对象' + detail: 'ReactDom对象', }, { label: 'ReactDOM.findDOMNode', kind: 'Function', insertText: 'ReactDOM.findDOMNode(${1:this.refs.xxxx})', insertTextRules: 'InsertAsSnippet', - detail: 'ReactDom查找真实dom node' + detail: 'ReactDom查找真实dom node', }, { label: 'Dialog.alert', @@ -84,10 +84,10 @@ export default [ '\tonOk: () => {', '\t\t$3', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: 'alert弹框 By Fusion' + detail: 'alert弹框 By Fusion', }, { label: 'Dialog.confirm', @@ -102,52 +102,52 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '确认弹出框 By Fusion' + detail: '确认弹出框 By Fusion', }, { label: 'Message.success', kind: 'Method', insertText: 'Message.success(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '成功反馈提示 By Fusion' + detail: '成功反馈提示 By Fusion', }, { label: 'Message.error', kind: 'Method', insertText: 'Message.error(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '错误反馈提示 By Fusion' + detail: '错误反馈提示 By Fusion', }, { label: 'Message.help', kind: 'Method', insertText: 'Message.help(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '帮助反馈提示 By Fusion' + detail: '帮助反馈提示 By Fusion', }, { label: 'Message.loading', kind: 'Method', insertText: 'Message.loading(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: 'loading反馈提示 By Fusion' + detail: 'loading反馈提示 By Fusion', }, { label: 'Message.notice', kind: 'Method', insertText: 'Message.notice(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '注意反馈提示 By Fusion' + detail: '注意反馈提示 By Fusion', }, { label: 'Message.waining', kind: 'Method', insertText: 'Message.waining(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '警告反馈提示 By Fusion' + detail: '警告反馈提示 By Fusion', }, { label: 'Modal.confirm', @@ -162,10 +162,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '确认弹出框 By Antd' + detail: '确认弹出框 By Antd', }, { label: 'Modal.info', @@ -180,10 +180,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '信息弹出框 By Antd' + detail: '信息弹出框 By Antd', }, { label: 'Modal.success', @@ -198,10 +198,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '成功弹出框 By Antd' + detail: '成功弹出框 By Antd', }, { label: 'Modal.error', @@ -216,10 +216,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '错误弹出框 By Antd' + detail: '错误弹出框 By Antd', }, { label: 'Modal.warning', @@ -234,9 +234,9 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '警告弹出框 By Antd' - } -]; \ No newline at end of file + detail: '警告弹出框 By Antd', + }, +]; diff --git a/packages/editor-setters/src/json-setter/locale/utils.ts b/packages/editor-setters/src/json-setter/locale/utils.ts index a02a8dd06..d401ad511 100644 --- a/packages/editor-setters/src/json-setter/locale/utils.ts +++ b/packages/editor-setters/src/json-setter/locale/utils.ts @@ -1,11 +1,11 @@ import IntlMessageFormat from 'intl-messageformat'; export const isJSExpression = (obj = '') => { - if(obj && typeof obj === 'object' && obj.type === 'JSExpression') { + if (obj && typeof obj === 'object' && obj.type === 'JSExpression') { return true; } return false; -} +}; /** * 用于构造国际化字符串处理函数 @@ -18,4 +18,4 @@ export const generateI18n = (locale = 'zh-CN', messages = {}) => { const formater = new IntlMessageFormat(messages[key], locale); return formater.format(values); }; -} +}; diff --git a/packages/editor-setters/src/json-setter/locale/zh-CN.ts b/packages/editor-setters/src/json-setter/locale/zh-CN.ts index 951596009..f4f2e0630 100644 --- a/packages/editor-setters/src/json-setter/locale/zh-CN.ts +++ b/packages/editor-setters/src/json-setter/locale/zh-CN.ts @@ -33,4 +33,4 @@ export default { object: '对象ObjectButton', reactNode: '节点类型ReactNode', typeError: 'Minix组件属性Types配置错误,存在不支持类型[{type}],请检查组件属性配置', -}; \ No newline at end of file +}; diff --git a/packages/editor-setters/src/locale/snippets.ts b/packages/editor-setters/src/locale/snippets.ts index 7c8484c4f..2bcb0dd00 100644 --- a/packages/editor-setters/src/locale/snippets.ts +++ b/packages/editor-setters/src/locale/snippets.ts @@ -4,21 +4,21 @@ export default [ kind: 'Class', insertText: 'constants', detail: '应用全局常量', - documentation: '应用范围定义的通用常量' + documentation: '应用范围定义的通用常量', }, { label: 'utils', kind: 'Class', insertText: 'utils', detail: '应用全局公共函数', - documentation: '应用范围扩展的公共函数' + documentation: '应用范围扩展的公共函数', }, { label: 'state', kind: 'Enum', insertText: 'state', detail: '当前所在容器组件内部状态', - documentation: 'React Class内部状态state' + documentation: 'React Class内部状态state', }, { label: 'setState', @@ -26,7 +26,7 @@ export default [ insertText: 'setState({\n\t$0\n})', insertTextRules: 'InsertAsSnippet', detail: '设置当前所在容器组件的state数据', - documentation: '原生React方法,会自动更新组件视图' + documentation: '原生React方法,会自动更新组件视图', }, { label: 'reloadDataSource', @@ -34,45 +34,45 @@ export default [ insertText: 'reloadDataSource(${1:${2:namespace}, ${3:false}, ${4:callback}})', insertTextRules: 'InsertAsSnippet', detail: '刷新当前所在的容器组件', - documentation: '触发当前所在的容器组件,重新发送异步请求,并用最新数据更新视图' + documentation: '触发当前所在的容器组件,重新发送异步请求,并用最新数据更新视图', }, { label: 'location', kind: 'Class', insertText: 'location', - detail: '路由解析对象' + detail: '路由解析对象', }, { label: 'location.query', kind: 'Value', insertText: 'location.query.${1:xxxx}', insertTextRules: 'InsertAsSnippet', - detail: '从路由解析对象中获取参数信息' + detail: '从路由解析对象中获取参数信息', }, { label: 'history', kind: 'Class', insertText: 'history', - detail: '路由历史对象' + detail: '路由历史对象', }, { label: 'React', kind: 'Keyword', insertText: 'React', - detail: 'React对象' + detail: 'React对象', }, { label: 'ReactDOM', kind: 'Keyword', insertText: 'ReactDOM', - detail: 'ReactDom对象' + detail: 'ReactDom对象', }, { label: 'ReactDOM.findDOMNode', kind: 'Function', insertText: 'ReactDOM.findDOMNode(${1:this.refs.xxxx})', insertTextRules: 'InsertAsSnippet', - detail: 'ReactDom查找真实dom node' + detail: 'ReactDom查找真实dom node', }, { label: 'Dialog.alert', @@ -84,10 +84,10 @@ export default [ '\tonOk: () => {', '\t\t$3', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: 'alert弹框 By Fusion' + detail: 'alert弹框 By Fusion', }, { label: 'Dialog.confirm', @@ -102,52 +102,52 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '确认弹出框 By Fusion' + detail: '确认弹出框 By Fusion', }, { label: 'Message.success', kind: 'Method', insertText: 'Message.success(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '成功反馈提示 By Fusion' + detail: '成功反馈提示 By Fusion', }, { label: 'Message.error', kind: 'Method', insertText: 'Message.error(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '错误反馈提示 By Fusion' + detail: '错误反馈提示 By Fusion', }, { label: 'Message.help', kind: 'Method', insertText: 'Message.help(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '帮助反馈提示 By Fusion' + detail: '帮助反馈提示 By Fusion', }, { label: 'Message.loading', kind: 'Method', insertText: 'Message.loading(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: 'loading反馈提示 By Fusion' + detail: 'loading反馈提示 By Fusion', }, { label: 'Message.notice', kind: 'Method', insertText: 'Message.notice(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '注意反馈提示 By Fusion' + detail: '注意反馈提示 By Fusion', }, { label: 'Message.waining', kind: 'Method', insertText: 'Message.waining(${1:content})', insertTextRules: 'InsertAsSnippet', - detail: '警告反馈提示 By Fusion' + detail: '警告反馈提示 By Fusion', }, { label: 'Modal.confirm', @@ -162,10 +162,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '确认弹出框 By Antd' + detail: '确认弹出框 By Antd', }, { label: 'Modal.info', @@ -180,10 +180,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '信息弹出框 By Antd' + detail: '信息弹出框 By Antd', }, { label: 'Modal.success', @@ -198,10 +198,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '成功弹出框 By Antd' + detail: '成功弹出框 By Antd', }, { label: 'Modal.error', @@ -216,10 +216,10 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '错误弹出框 By Antd' + detail: '错误弹出框 By Antd', }, { label: 'Modal.warning', @@ -234,9 +234,9 @@ export default [ '\tonCancel: () => {', '\t\t$4', '\t}', - '})' + '})', ].join('\n'), insertTextRules: 'InsertAsSnippet', - detail: '警告弹出框 By Antd' - } -]; \ No newline at end of file + detail: '警告弹出框 By Antd', + }, +]; diff --git a/packages/editor-setters/src/locale/utils.ts b/packages/editor-setters/src/locale/utils.ts index a02a8dd06..d401ad511 100644 --- a/packages/editor-setters/src/locale/utils.ts +++ b/packages/editor-setters/src/locale/utils.ts @@ -1,11 +1,11 @@ import IntlMessageFormat from 'intl-messageformat'; export const isJSExpression = (obj = '') => { - if(obj && typeof obj === 'object' && obj.type === 'JSExpression') { + if (obj && typeof obj === 'object' && obj.type === 'JSExpression') { return true; } return false; -} +}; /** * 用于构造国际化字符串处理函数 @@ -18,4 +18,4 @@ export const generateI18n = (locale = 'zh-CN', messages = {}) => { const formater = new IntlMessageFormat(messages[key], locale); return formater.format(values); }; -} +}; diff --git a/packages/editor-setters/src/locale/zh-CN.ts b/packages/editor-setters/src/locale/zh-CN.ts index 951596009..f4f2e0630 100644 --- a/packages/editor-setters/src/locale/zh-CN.ts +++ b/packages/editor-setters/src/locale/zh-CN.ts @@ -33,4 +33,4 @@ export default { object: '对象ObjectButton', reactNode: '节点类型ReactNode', typeError: 'Minix组件属性Types配置错误,存在不支持类型[{type}],请检查组件属性配置', -}; \ No newline at end of file +}; diff --git a/packages/editor-setters/src/mixed-setter/index.tsx b/packages/editor-setters/src/mixed-setter/index.tsx index 7d288cc93..f99c1bec3 100644 --- a/packages/editor-setters/src/mixed-setter/index.tsx +++ b/packages/editor-setters/src/mixed-setter/index.tsx @@ -10,6 +10,7 @@ import './index.scss'; export default class Mixed extends PureComponent { static displayName = 'Mixed'; + static propTypes = { locale: PropTypes.string, messages: PropTypes.object, @@ -22,6 +23,7 @@ export default class Mixed extends PureComponent { selectProps: PropTypes.object, radioGroupProps: PropTypes.object, }; + static defaultProps = { locale: 'zh-CN', messages: zhCN, @@ -32,22 +34,25 @@ export default class Mixed extends PureComponent { }, ], }; + typeMap: any; - i18n: (key: any, values?: {}) => string | void | Array; - constructor(props: Readonly<{}>) { + + i18n: (key: any, values) => string | void | Array; + + constructor(props: Readonly) { super(props); const type = props.defaultType; // judgeTypeHandler(props, {}); this.i18n = generateI18n(props.locale, props.messages); this.state = { - preType: type, type, }; } + changeType(type: string) { if (typeof type === 'object' || type === this.state.type) return; const { onChange } = this.props; - let newValue = undefined; - const setterProps = this.typeMap[type]['props']; + let newValue; + const setterProps = this.typeMap[type].props; if (setterProps) { if (setterProps.value !== undefined) { newValue = setterProps.value; @@ -56,11 +61,12 @@ export default class Mixed extends PureComponent { } } if (type === 'BoolSetter' && newValue === undefined) { - newValue = false; //给切换到switch默认值为false + newValue = false; // 给切换到switch默认值为false } this.setState({ type }); onChange && onChange(newValue); } + render() { const { style = {}, className, locale, messages, types = [], defaultType, ...restProps } = this.props; this.typeMap = {}; @@ -78,7 +84,7 @@ export default class Mixed extends PureComponent { realTypes.push(name); }); let moreBtnNode = null; - //如果只有2种,且有变量表达式,则直接展示变量按钮 + // 如果只有2种,且有变量表达式,则直接展示变量按钮 if (realTypes.length > 1) { const isTwoType = !!(realTypes.length === 2 && ~realTypes.indexOf('ExpressionSetter')); const btnProps = { @@ -108,10 +114,11 @@ export default class Mixed extends PureComponent { if (isTwoType) { moreBtnNode = triggerNode; } else { + // eslint-disable-next-line @typescript-eslint/ban-types const MenuItems: {} | null | undefined = []; realTypes.map((type) => { if (this.typeMap[type]) { - MenuItems.push({this.typeMap[type]['label']}); + MenuItems.push({this.typeMap[type].label}); } else { console.error( this.i18n('typeError', { @@ -119,6 +126,7 @@ export default class Mixed extends PureComponent { }), ); } + return type; }); const MenuNode = ( { - if(obj && typeof obj === 'object' && obj.type === 'JSExpression') { + if (obj && typeof obj === 'object' && obj.type === 'JSExpression') { return true; } return false; -} +}; /** * 用于构造国际化字符串处理函数 @@ -18,4 +18,4 @@ export const generateI18n = (locale = 'zh-CN', messages = {}) => { const formater = new IntlMessageFormat(messages[key], locale); return formater.format(values); }; -} +}; diff --git a/packages/editor-setters/src/mixed-setter/locale/zh-CN.ts b/packages/editor-setters/src/mixed-setter/locale/zh-CN.ts index 951596009..f4f2e0630 100644 --- a/packages/editor-setters/src/mixed-setter/locale/zh-CN.ts +++ b/packages/editor-setters/src/mixed-setter/locale/zh-CN.ts @@ -33,4 +33,4 @@ export default { object: '对象ObjectButton', reactNode: '节点类型ReactNode', typeError: 'Minix组件属性Types配置错误,存在不支持类型[{type}],请检查组件属性配置', -}; \ No newline at end of file +}; diff --git a/packages/editor-setters/src/style-setter/index.tsx b/packages/editor-setters/src/style-setter/index.tsx index b6a75679c..004fe2bf1 100644 --- a/packages/editor-setters/src/style-setter/index.tsx +++ b/packages/editor-setters/src/style-setter/index.tsx @@ -5,25 +5,26 @@ import LowStyleSetter from '@ali/lc-style-setter'; import { globalLocale } from '@ali/lowcode-editor-core'; export default class StyleSetter extends Component { - static displayName = 'StyleSetter'; + static propTypes = { value: PropTypes.object, onChange: PropTypes.func, placeholder: PropTypes.string, - locale: PropTypes.string + locale: PropTypes.string, }; + static defaultProps = { value: {}, onChange: () => { }, placeholder: '', - locale: globalLocale.getLocale() || 'en-US' + locale: globalLocale.getLocale() || 'en-US', }; onChange = (val: any) => { const { onChange } = this.props; onChange(val.native); - } + }; render() { const { value } = this.props; @@ -33,5 +34,4 @@ export default class StyleSetter extends Component {
); } - } diff --git a/packages/editor-skeleton/.eslintrc.js b/packages/editor-skeleton/.eslintrc.js new file mode 100644 index 000000000..0430ed0a5 --- /dev/null +++ b/packages/editor-skeleton/.eslintrc.js @@ -0,0 +1,16 @@ +module.exports = { + extends: '../../.eslintrc.js', + rules: { + 'react/no-multi-comp': 1, + 'no-unused-expressions': 1, + 'implicit-arrow-linebreak': 1, + 'no-nested-ternary': 1, + 'no-mixed-operators': 1, + '@typescript-eslint/no-parameter-properties': 1, + '@typescript-eslint/ban-types': 1, + 'no-shadow': 1, + 'no-prototype-builtins': 1, + 'no-confusing-arrow': 1, + 'no-case-declarations': 1, + } +} \ No newline at end of file diff --git a/packages/editor-skeleton/src/area.ts b/packages/editor-skeleton/src/area.ts index d0f4b0f4f..6ff3b6e07 100644 --- a/packages/editor-skeleton/src/area.ts +++ b/packages/editor-skeleton/src/area.ts @@ -5,7 +5,7 @@ import { IWidget } from './widget/widget'; import { IWidgetBaseConfig } from './types'; export default class Area { - @obx private _visible: boolean = true; + @obx private _visible = true; @computed get visible() { if (this.exclusive) { @@ -22,7 +22,8 @@ export default class Area; - constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent: boolean = false) { + + constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) { this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent); } @@ -43,11 +44,12 @@ export default class Area { onSort(sortedIds: Array) { const { itemsMap } = this.state; - const { onChange ,itemSetter,field} = this.props; - const items = sortedIds.map((id, index) => { + const { onChange, itemSetter, field } = this.props; + const items = sortedIds.map((id) => { const item = itemsMap.get(id)!; // item.setKey(index); return item; @@ -85,7 +85,8 @@ export class ListSetter extends Component { }); // 对itemsMap重新生成并刷新当前setter数据 - let newItems = [],newItemsMap = {} + const newItems = []; + // const newItemsMap = {}; itemsMap.clear(); for (let i = 0; i < items.length; i++) { const newItem = field.createField({ @@ -101,12 +102,13 @@ export class ListSetter extends Component { onChange(values); this.setState({ - items:newItems, - itemsMap + items: newItems, + itemsMap, }); } private scrollToLast = false; + onAdd() { const { items, itemsMap } = this.state; const { itemSetter } = this.props; @@ -127,7 +129,7 @@ export class ListSetter extends Component { } onRemove(field: SettingField) { - const {onChange, itemSetter} = this.props; + const { onChange } = this.props; const { items, itemsMap } = this.state; let i = items.indexOf(field); const values = items.map((item) => { @@ -145,7 +147,7 @@ export class ListSetter extends Component { } itemsMap.delete(field.id); field.remove(); - onChange(values) + onChange(values); this.setState({ items: items.slice() }); } @@ -171,7 +173,7 @@ export class ListSetter extends Component { } const { items } = this.state; - const scrollToLast = this.scrollToLast; + const { scrollToLast } = this; this.scrollToLast = false; const lastIndex = items.length - 1; @@ -197,12 +199,12 @@ export class ListSetter extends Component { return (
- {/*
+ {/*
-
*/} +
*/} {columns &&
{columns}
} {content}