From 04adda02fb415e2f56e6ee3e7f20652c2de20668 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 13 Nov 2023 12:30:47 +0800 Subject: [PATCH 01/61] =?UTF-8?q?docs:=20add=20faq-Slot=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/faq/faq023.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/docs/faq/faq023.md diff --git a/docs/docs/faq/faq023.md b/docs/docs/faq/faq023.md new file mode 100644 index 000000000..e03f7118e --- /dev/null +++ b/docs/docs/faq/faq023.md @@ -0,0 +1,31 @@ +--- +title: Slot组件渲染报错问题 +sidebar_position: 23 +tags: [FAQ] +--- + +## 问题描述 +在低代码引擎的页面渲染过程中,可能会遇到一个关于Slot组件的报错,提示“Slot找不到”。实际上,在渲染态时不应使用Slot组件。 + +## 问题原因 +低代码引擎渲染分为两个状态:设计态和渲染态。 +- **设计态**:为了帮助插槽进行可视化设计,引入了Slot组件。 +- **渲染态**:在此状态下,不需要使用Slot组件。 + +这个问题通常是因为在渲染态错误地使用了设计态的schema。 + +## 解决方案 +1. **区分设计态和渲染态**:通过`project.exportSchema(TransformStage.Save)`的参数来区分。 + - `TransformStage.Save`代表渲染态的schema,其中不包含Slot组件。 + - 【默认值】`TransformStage.Render`代表设计态的schema,其中包含Slot组件。 +2. **使用正确的API和参数**:确保在渲染态使用正确的schema,避免引用设计态的Slot组件。 +3. **处理脏数据问题**:如果问题是由脏数据导致,清除数据并重新拖拽组件以恢复正常。 + +## 注意事项 +- 确保在代码和配置中正确区分设计态和渲染态。 +- 如果遇到持续的问题,检查是否有脏数据或配置错误,并进行相应的清理和调整。 + +## 相关链接 +- Issue链接:[Issue #1798](https://github.com/alibaba/lowcode-engine/issues/1798) + +--- From 938c71fb462b37fb154e1b8fdfaa0319d4f0f075 Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 13 Nov 2023 12:57:02 +0800 Subject: [PATCH 02/61] chore(docs): publish docs 1.1.15 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 7479c7c84..27d1a17d0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.14", + "version": "1.1.15", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 621245393f5ca405d86c90501e51288f2f324d5c Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 13 Nov 2023 12:25:50 +0800 Subject: [PATCH 03/61] test(utils): add ut to package/utils --- packages/utils/jest.config.js | 1 + packages/utils/jest.setup.js | 1 + packages/utils/package.json | 7 +- .../check-types/is-action-content-object.ts | 3 +- .../utils/src/check-types/is-custom-view.ts | 6 +- .../src/check-types/is-drag-any-object.ts | 6 +- .../check-types/is-drag-node-data-object.ts | 6 +- .../src/check-types/is-drag-node-object.ts | 6 +- .../src/check-types/is-dynamic-setter.ts | 7 +- packages/utils/src/check-types/is-function.ts | 3 + .../utils/src/check-types/is-i18n-data.ts | 11 +- .../utils/src/check-types/is-isfunction.ts | 24 +- packages/utils/src/check-types/is-jsblock.ts | 9 +- .../utils/src/check-types/is-jsexpression.ts | 6 +- packages/utils/src/check-types/is-jsslot.ts | 6 +- .../is-location-children-detail.ts | 6 +- .../utils/src/check-types/is-location-data.ts | 6 +- .../check-types/is-lowcode-project-schema.ts | 15 +- .../utils/src/check-types/is-node-schema.ts | 6 +- packages/utils/src/check-types/is-node.ts | 6 +- packages/utils/src/check-types/is-object.ts | 3 + .../check-types/is-procode-component-type.ts | 6 +- .../src/check-types/is-project-schema.ts | 8 +- .../utils/src/check-types/is-setter-config.ts | 7 +- .../utils/src/check-types/is-setting-field.ts | 9 +- .../utils/src/clone-enumerable-property.ts | 4 +- packages/utils/src/is-object.ts | 2 +- packages/utils/src/is-react.ts | 38 +- packages/utils/src/logger.ts | 4 +- packages/utils/src/misc.ts | 15 +- packages/utils/src/navtive-selection.ts | 3 +- packages/utils/src/script.ts | 5 +- packages/utils/src/svg-icon.tsx | 2 +- .../src/__snapshots__/is-react.test.tsx.snap | 10 + .../build-components/buildComponents.test.ts | 342 ---------- .../build-components/buildComponents.test.tsx | 616 ++++++++++++++++++ .../is-action-content-object.test.ts | 20 + .../src/check-types/is-custom-view.test.tsx | 26 + .../test/src/check-types/is-dom-text.test.ts | 13 + .../check-types/is-drag-any-object.test.ts | 32 + .../is-drag-node-data-object.test.ts | 29 + .../check-types/is-drag-node-object.test.ts | 36 + .../src/check-types/is-dynamic-setter.test.ts | 28 + .../test/src/check-types/is-i18n-data.test.ts | 27 + .../src/check-types/is-isfunction.test.ts | 61 ++ .../test/src/check-types/is-jsblock.test.ts | 22 + .../src/check-types/is-jsexpression.test.ts | 39 ++ .../test/src/check-types/is-jsslot.test.ts | 37 ++ .../is-location-children-detail.test.ts | 27 + .../src/check-types/is-location-data.test.ts | 44 ++ .../is-lowcode-component-type.test.ts | 21 + .../is-lowcode-project-schema.test.ts | 42 ++ .../src/check-types/is-node-schema.test.ts | 43 ++ .../test/src/check-types/is-node.test.ts | 19 + .../is-procode-component-type.test.ts | 13 + .../src/check-types/is-project-schema.test.ts | 28 + .../src/check-types/is-setter-config.test.ts | 26 + .../src/check-types/is-setting-field.test.ts | 18 + .../src/check-types/is-title-config.test.ts | 18 + packages/utils/test/src/clone-deep.test.ts | 30 + .../src/clone-enumerable-property.test.ts | 30 + .../utils/test/src/create-content.test.tsx | 38 ++ packages/utils/test/src/create-defer.test.ts | 16 + packages/utils/test/src/is-object.test.ts | 45 ++ packages/utils/test/src/is-react.test.ts | 38 -- packages/utils/test/src/is-react.test.tsx | 316 +++++++++ packages/utils/test/src/is-shaken.test.ts | 45 ++ packages/utils/test/src/misc.test.ts | 319 ++++++++- .../utils/test/src/navtive-selection.test.ts | 18 + packages/utils/test/src/schema.test.ts | 130 +++- packages/utils/test/src/script.test.ts | 47 ++ packages/utils/test/src/svg-icon.test.tsx | 35 + .../test/src/transaction-manager.test.ts | 58 ++ packages/utils/test/src/unique-id.test.ts | 11 + 74 files changed, 2621 insertions(+), 439 deletions(-) create mode 100644 packages/utils/jest.setup.js create mode 100644 packages/utils/src/check-types/is-function.ts create mode 100644 packages/utils/src/check-types/is-object.ts create mode 100644 packages/utils/test/src/__snapshots__/is-react.test.tsx.snap delete mode 100644 packages/utils/test/src/build-components/buildComponents.test.ts create mode 100644 packages/utils/test/src/build-components/buildComponents.test.tsx create mode 100644 packages/utils/test/src/check-types/is-action-content-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-custom-view.test.tsx create mode 100644 packages/utils/test/src/check-types/is-dom-text.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-any-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-node-data-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-node-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-dynamic-setter.test.ts create mode 100644 packages/utils/test/src/check-types/is-i18n-data.test.ts create mode 100644 packages/utils/test/src/check-types/is-isfunction.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsblock.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsexpression.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsslot.test.ts create mode 100644 packages/utils/test/src/check-types/is-location-children-detail.test.ts create mode 100644 packages/utils/test/src/check-types/is-location-data.test.ts create mode 100644 packages/utils/test/src/check-types/is-lowcode-component-type.test.ts create mode 100644 packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-node-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-node.test.ts create mode 100644 packages/utils/test/src/check-types/is-procode-component-type.test.ts create mode 100644 packages/utils/test/src/check-types/is-project-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-setter-config.test.ts create mode 100644 packages/utils/test/src/check-types/is-setting-field.test.ts create mode 100644 packages/utils/test/src/check-types/is-title-config.test.ts create mode 100644 packages/utils/test/src/clone-deep.test.ts create mode 100644 packages/utils/test/src/clone-enumerable-property.test.ts create mode 100644 packages/utils/test/src/create-content.test.tsx create mode 100644 packages/utils/test/src/create-defer.test.ts create mode 100644 packages/utils/test/src/is-object.test.ts delete mode 100644 packages/utils/test/src/is-react.test.ts create mode 100644 packages/utils/test/src/is-react.test.tsx create mode 100644 packages/utils/test/src/is-shaken.test.ts create mode 100644 packages/utils/test/src/navtive-selection.test.ts create mode 100644 packages/utils/test/src/script.test.ts create mode 100644 packages/utils/test/src/svg-icon.test.tsx create mode 100644 packages/utils/test/src/transaction-manager.test.ts create mode 100644 packages/utils/test/src/unique-id.test.ts diff --git a/packages/utils/jest.config.js b/packages/utils/jest.config.js index 328ea622e..0631fa00c 100644 --- a/packages/utils/jest.config.js +++ b/packages/utils/jest.config.js @@ -11,6 +11,7 @@ const jestConfig = { '!**/node_modules/**', '!**/vendor/**', ], + setupFilesAfterEnv: ['./jest.setup.js'], }; // 只对本仓库内的 pkg 做 mapping diff --git a/packages/utils/jest.setup.js b/packages/utils/jest.setup.js new file mode 100644 index 000000000..7b0828bfa --- /dev/null +++ b/packages/utils/jest.setup.js @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/packages/utils/package.json b/packages/utils/package.json index fab7828f1..af76e9e2f 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -9,7 +9,7 @@ "main": "lib/index.js", "module": "es/index.js", "scripts": { - "test": "build-scripts test --config build.test.json", + "test": "build-scripts test --config build.test.json --jest-coverage", "build": "build-scripts build" }, "dependencies": { @@ -21,8 +21,11 @@ }, "devDependencies": { "@alib/build-scripts": "^0.1.18", + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^11.2.7", "@types/node": "^13.7.1", - "@types/react": "^16" + "@types/react": "^16", + "react-dom": "^16.14.0" }, "publishConfig": { "access": "public", diff --git a/packages/utils/src/check-types/is-action-content-object.ts b/packages/utils/src/check-types/is-action-content-object.ts index 4e9a6545a..8fe31b5bd 100644 --- a/packages/utils/src/check-types/is-action-content-object.ts +++ b/packages/utils/src/check-types/is-action-content-object.ts @@ -1,5 +1,6 @@ import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isActionContentObject(obj: any): obj is IPublicTypeActionContentObject { - return obj && typeof obj === 'object'; + return isObject(obj); } diff --git a/packages/utils/src/check-types/is-custom-view.ts b/packages/utils/src/check-types/is-custom-view.ts index 89ea9f10e..4cf921d9c 100644 --- a/packages/utils/src/check-types/is-custom-view.ts +++ b/packages/utils/src/check-types/is-custom-view.ts @@ -2,7 +2,9 @@ import { isValidElement } from 'react'; import { isReactComponent } from '../is-react'; import { IPublicTypeCustomView } from '@alilc/lowcode-types'; - export function isCustomView(obj: any): obj is IPublicTypeCustomView { - return obj && (isValidElement(obj) || isReactComponent(obj)); + if (!obj) { + return false; + } + return isValidElement(obj) || isReactComponent(obj); } diff --git a/packages/utils/src/check-types/is-drag-any-object.ts b/packages/utils/src/check-types/is-drag-any-object.ts index 34f140f4a..8711b4e33 100644 --- a/packages/utils/src/check-types/is-drag-any-object.ts +++ b/packages/utils/src/check-types/is-drag-any-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragAnyObject(obj: any): boolean { - return obj && obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node; + if (!isObject(obj)) { + return false; + } + return obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-drag-node-data-object.ts b/packages/utils/src/check-types/is-drag-node-data-object.ts index 4b08f67fa..aa62f5b1c 100644 --- a/packages/utils/src/check-types/is-drag-node-data-object.ts +++ b/packages/utils/src/check-types/is-drag-node-data-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataObject { - return obj && obj.type === IPublicEnumDragObjectType.NodeData; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicEnumDragObjectType.NodeData; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-drag-node-object.ts b/packages/utils/src/check-types/is-drag-node-object.ts index 1b6c131e9..3a29ec967 100644 --- a/packages/utils/src/check-types/is-drag-node-object.ts +++ b/packages/utils/src/check-types/is-drag-node-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType, IPublicModelNode, IPublicTypeDragNodeObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragNodeObject(obj: any): obj is IPublicTypeDragNodeObject { - return obj && obj.type === IPublicEnumDragObjectType.Node; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicEnumDragObjectType.Node; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-dynamic-setter.ts b/packages/utils/src/check-types/is-dynamic-setter.ts index 43a8cb8be..35f8ff389 100644 --- a/packages/utils/src/check-types/is-dynamic-setter.ts +++ b/packages/utils/src/check-types/is-dynamic-setter.ts @@ -1,7 +1,10 @@ +import { isFunction } from '../is-function'; import { isReactClass } from '../is-react'; import { IPublicTypeDynamicSetter } from '@alilc/lowcode-types'; - export function isDynamicSetter(obj: any): obj is IPublicTypeDynamicSetter { - return obj && typeof obj === 'function' && !isReactClass(obj); + if (!isFunction(obj)) { + return false; + } + return !isReactClass(obj); } diff --git a/packages/utils/src/check-types/is-function.ts b/packages/utils/src/check-types/is-function.ts new file mode 100644 index 000000000..d7d3b4c27 --- /dev/null +++ b/packages/utils/src/check-types/is-function.ts @@ -0,0 +1,3 @@ +export function isFunction(obj: any): obj is Function { + return obj && typeof obj === 'function'; +} \ No newline at end of file diff --git a/packages/utils/src/check-types/is-i18n-data.ts b/packages/utils/src/check-types/is-i18n-data.ts index f4a7b6f7a..793295d24 100644 --- a/packages/utils/src/check-types/is-i18n-data.ts +++ b/packages/utils/src/check-types/is-i18n-data.ts @@ -1,8 +1,9 @@ - -// type checks - -import { IPublicTypeI18nData } from "@alilc/lowcode-types"; +import { IPublicTypeI18nData } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isI18nData(obj: any): obj is IPublicTypeI18nData { - return obj && obj.type === 'i18n'; + if (!isObject(obj)) { + return false; + } + return obj.type === 'i18n'; } diff --git a/packages/utils/src/check-types/is-isfunction.ts b/packages/utils/src/check-types/is-isfunction.ts index a6d5da900..64b867663 100644 --- a/packages/utils/src/check-types/is-isfunction.ts +++ b/packages/utils/src/check-types/is-isfunction.ts @@ -1,10 +1,26 @@ +import { IPublicTypeJSFunction } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; + +interface InnerJsFunction { + type: 'JSExpression'; + source: string; + value: string; + extType: 'function'; +} + /** * 内部版本 的 { type: 'JSExpression', source: '', value: '', extType: 'function' } 能力上等同于 JSFunction */ -export function isInnerJsFunction(data: any) { - return data && data.type === 'JSExpression' && data.extType === 'function'; +export function isInnerJsFunction(data: any): data is InnerJsFunction { + if (!isObject(data)) { + return false; + } + return data.type === 'JSExpression' && data.extType === 'function'; } -export function isJSFunction(data: any): boolean { - return typeof data === 'object' && data && data.type === 'JSFunction' || isInnerJsFunction(data); +export function isJSFunction(data: any): data is IPublicTypeJSFunction { + if (!isObject(data)) { + return false; + } + return data.type === 'JSFunction' || isInnerJsFunction(data); } diff --git a/packages/utils/src/check-types/is-jsblock.ts b/packages/utils/src/check-types/is-jsblock.ts index 4c3b28f52..858f5c09c 100644 --- a/packages/utils/src/check-types/is-jsblock.ts +++ b/packages/utils/src/check-types/is-jsblock.ts @@ -1,4 +1,9 @@ +import { IPublicTypeJSBlock } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; -export function isJSBlock(data: any): boolean { - return data && data.type === 'JSBlock'; +export function isJSBlock(data: any): data is IPublicTypeJSBlock { + if (!isObject(data)) { + return false; + } + return data.type === 'JSBlock'; } diff --git a/packages/utils/src/check-types/is-jsexpression.ts b/packages/utils/src/check-types/is-jsexpression.ts index 949d0f00d..16b8f4ac2 100644 --- a/packages/utils/src/check-types/is-jsexpression.ts +++ b/packages/utils/src/check-types/is-jsexpression.ts @@ -1,4 +1,5 @@ import { IPublicTypeJSExpression } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; /** * 为了避免把 { type: 'JSExpression', extType: 'function' } 误判为表达式,故增加如下逻辑。 @@ -11,5 +12,8 @@ import { IPublicTypeJSExpression } from '@alilc/lowcode-types'; * @returns */ export function isJSExpression(data: any): data is IPublicTypeJSExpression { - return data && data.type === 'JSExpression' && data.extType !== 'function'; + if (!isObject(data)) { + return false; + } + return data.type === 'JSExpression' && data.extType !== 'function'; } diff --git a/packages/utils/src/check-types/is-jsslot.ts b/packages/utils/src/check-types/is-jsslot.ts index 1a8f09def..1fb1d819d 100644 --- a/packages/utils/src/check-types/is-jsslot.ts +++ b/packages/utils/src/check-types/is-jsslot.ts @@ -1,5 +1,9 @@ import { IPublicTypeJSSlot } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isJSSlot(data: any): data is IPublicTypeJSSlot { - return data && data.type === 'JSSlot'; + if (!isObject(data)) { + return false; + } + return data.type === 'JSSlot'; } diff --git a/packages/utils/src/check-types/is-location-children-detail.ts b/packages/utils/src/check-types/is-location-children-detail.ts index c6d2819d3..cc093c4e4 100644 --- a/packages/utils/src/check-types/is-location-children-detail.ts +++ b/packages/utils/src/check-types/is-location-children-detail.ts @@ -1,5 +1,9 @@ import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isLocationChildrenDetail(obj: any): obj is IPublicTypeLocationChildrenDetail { - return obj && obj.type === IPublicTypeLocationDetailType.Children; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicTypeLocationDetailType.Children; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-location-data.ts b/packages/utils/src/check-types/is-location-data.ts index 8bb310346..dabd493fa 100644 --- a/packages/utils/src/check-types/is-location-data.ts +++ b/packages/utils/src/check-types/is-location-data.ts @@ -1,5 +1,9 @@ import { IPublicTypeLocationData } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isLocationData(obj: any): obj is IPublicTypeLocationData { - return obj && obj.target && obj.detail; + if (!isObject(obj)) { + return false; + } + return 'target' in obj && 'detail' in obj; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-lowcode-project-schema.ts b/packages/utils/src/check-types/is-lowcode-project-schema.ts index 0fffaea2f..230911f0f 100644 --- a/packages/utils/src/check-types/is-lowcode-project-schema.ts +++ b/packages/utils/src/check-types/is-lowcode-project-schema.ts @@ -1,6 +1,15 @@ -import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from "@alilc/lowcode-types"; -import { isComponentSchema } from "./is-component-schema"; +import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from '@alilc/lowcode-types'; +import { isComponentSchema } from './is-component-schema'; +import { isObject } from '../is-object'; export function isLowcodeProjectSchema(data: any): data is IPublicTypeProjectSchema { - return data && data.componentsTree && data.componentsTree.length && isComponentSchema(data.componentsTree[0]); + if (!isObject(data)) { + return false; + } + + if (!('componentsTree' in data) || data.componentsTree.length === 0) { + return false; + } + + return isComponentSchema(data.componentsTree[0]); } diff --git a/packages/utils/src/check-types/is-node-schema.ts b/packages/utils/src/check-types/is-node-schema.ts index bfc3ff3f2..253c05a08 100644 --- a/packages/utils/src/check-types/is-node-schema.ts +++ b/packages/utils/src/check-types/is-node-schema.ts @@ -1,5 +1,9 @@ import { IPublicTypeNodeSchema } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isNodeSchema(data: any): data is IPublicTypeNodeSchema { - return data && data.componentName && !data.isNode; + if (!isObject(data)) { + return false; + } + return 'componentName' in data && !data.isNode; } diff --git a/packages/utils/src/check-types/is-node.ts b/packages/utils/src/check-types/is-node.ts index 14c2e2f74..b4690ddff 100644 --- a/packages/utils/src/check-types/is-node.ts +++ b/packages/utils/src/check-types/is-node.ts @@ -1,5 +1,9 @@ import { IPublicModelNode } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isNode(node: any): node is Node { - return node && node.isNode; + if (!isObject(node)) { + return false; + } + return node.isNode; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-object.ts b/packages/utils/src/check-types/is-object.ts new file mode 100644 index 000000000..56ceb7d97 --- /dev/null +++ b/packages/utils/src/check-types/is-object.ts @@ -0,0 +1,3 @@ +export function isObject(obj: any): boolean { + return obj && typeof obj === 'object'; +} \ No newline at end of file diff --git a/packages/utils/src/check-types/is-procode-component-type.ts b/packages/utils/src/check-types/is-procode-component-type.ts index 5c768dd94..46618dcd5 100644 --- a/packages/utils/src/check-types/is-procode-component-type.ts +++ b/packages/utils/src/check-types/is-procode-component-type.ts @@ -1,6 +1,10 @@ import { IPublicTypeComponentMap, IPublicTypeProCodeComponent } from '@alilc/lowcode-types'; - +import { isObject } from '../is-object'; export function isProCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeProCodeComponent { + if (!isObject(desc)) { + return false; + } + return 'package' in desc; } diff --git a/packages/utils/src/check-types/is-project-schema.ts b/packages/utils/src/check-types/is-project-schema.ts index b228d481e..d217acd9e 100644 --- a/packages/utils/src/check-types/is-project-schema.ts +++ b/packages/utils/src/check-types/is-project-schema.ts @@ -1,5 +1,9 @@ -import { IPublicTypeProjectSchema } from "@alilc/lowcode-types"; +import { IPublicTypeProjectSchema } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isProjectSchema(data: any): data is IPublicTypeProjectSchema { - return data && data.componentsTree; + if (!isObject(data)) { + return false; + } + return 'componentsTree' in data; } diff --git a/packages/utils/src/check-types/is-setter-config.ts b/packages/utils/src/check-types/is-setter-config.ts index d631d237f..98d835f32 100644 --- a/packages/utils/src/check-types/is-setter-config.ts +++ b/packages/utils/src/check-types/is-setter-config.ts @@ -1,7 +1,10 @@ import { IPublicTypeSetterConfig } from '@alilc/lowcode-types'; import { isCustomView } from './is-custom-view'; - +import { isObject } from '../is-object'; export function isSetterConfig(obj: any): obj is IPublicTypeSetterConfig { - return obj && typeof obj === 'object' && 'componentName' in obj && !isCustomView(obj); + if (!isObject(obj)) { + return false; + } + return 'componentName' in obj && !isCustomView(obj); } diff --git a/packages/utils/src/check-types/is-setting-field.ts b/packages/utils/src/check-types/is-setting-field.ts index 67a183a95..0d6e21d84 100644 --- a/packages/utils/src/check-types/is-setting-field.ts +++ b/packages/utils/src/check-types/is-setting-field.ts @@ -1,5 +1,10 @@ -import { IPublicModelSettingField } from "@alilc/lowcode-types"; +import { IPublicModelSettingField } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isSettingField(obj: any): obj is IPublicModelSettingField { - return obj && obj.isSettingField; + if (!isObject(obj)) { + return false; + } + + return 'isSettingField' in obj && obj.isSettingField; } diff --git a/packages/utils/src/clone-enumerable-property.ts b/packages/utils/src/clone-enumerable-property.ts index 414f8dccd..eb09e177f 100644 --- a/packages/utils/src/clone-enumerable-property.ts +++ b/packages/utils/src/clone-enumerable-property.ts @@ -11,8 +11,8 @@ const excludePropertyNames = [ 'arguments', ]; -export function cloneEnumerableProperty(target: any, origin: any) { - const compExtraPropertyNames = Object.keys(origin).filter(d => !excludePropertyNames.includes(d)); +export function cloneEnumerableProperty(target: any, origin: any, excludes = excludePropertyNames) { + const compExtraPropertyNames = Object.keys(origin).filter(d => !excludes.includes(d)); compExtraPropertyNames.forEach((d: string) => { (target as any)[d] = origin[d]; diff --git a/packages/utils/src/is-object.ts b/packages/utils/src/is-object.ts index 50b580e5a..c8d764458 100644 --- a/packages/utils/src/is-object.ts +++ b/packages/utils/src/is-object.ts @@ -1,4 +1,4 @@ -export function isObject(value: any): value is Record { +export function isObject(value: any): value is Record { return value !== null && typeof value === 'object'; } diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index b19f043f1..1d6c939ea 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -2,27 +2,49 @@ import { ComponentClass, Component, FunctionComponent, ComponentType, createElem import { cloneEnumerableProperty } from './clone-enumerable-property'; const hasSymbol = typeof Symbol === 'function' && Symbol.for; -const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; -const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; +export const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; +export const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; export function isReactClass(obj: any): obj is ComponentClass { - return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component); + if (!obj) { + return false; + } + if (obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component)) { + return true; + } + return false; } export function acceptsRef(obj: any): boolean { - return obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj); + if (!obj) { + return false; + } + if (obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj)) { + return true; + } + + return false; } export function isForwardRefType(obj: any): boolean { - return obj?.$$typeof && obj?.$$typeof === REACT_FORWARD_REF_TYPE; + if (!obj || !obj?.$$typeof) { + return false; + } + return obj?.$$typeof === REACT_FORWARD_REF_TYPE; } -function isMemoType(obj: any): boolean { - return obj?.$$typeof && obj.$$typeof === REACT_MEMO_TYPE; +export function isMemoType(obj: any): boolean { + if (!obj || !obj?.$$typeof) { + return false; + } + return obj.$$typeof === REACT_MEMO_TYPE; } export function isForwardOrMemoForward(obj: any): boolean { - return obj?.$$typeof && ( + if (!obj || !obj?.$$typeof) { + return false; + } + return ( // React.forwardRef(..) isForwardRefType(obj) || // React.memo(React.forwardRef(..)) diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 4c8f375ec..3eb43eedb 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -88,7 +88,7 @@ const shouldOutput = ( const output = (logLevel: string, bizName: string) => { return (...args: any[]) => { - return outputFunction[logLevel].apply(console, getLogArgs(args, bizName, logLevel)); + return outputFunction[logLevel]?.apply(console, getLogArgs(args, bizName, logLevel)); }; }; @@ -142,7 +142,6 @@ const defaultOptions: Options = { bizName: '*', }; - class Logger { bizName: string; targetBizName: string; @@ -192,7 +191,6 @@ class Logger { } } - export { Logger }; export function getLogger(config: { level: Level; bizName: string }): Logger { diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index 89f121065..28833ef32 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -2,6 +2,9 @@ import { isI18NObject } from './is-object'; import { get } from 'lodash'; import { IPublicEnumTransformStage, IPublicModelComponentMeta } from '@alilc/lowcode-types'; +import { Logger } from './logger'; + +const logger = new Logger({ level: 'warn', bizName: 'utils' }); interface Variable { type: 'variable'; @@ -10,7 +13,10 @@ interface Variable { } export function isVariable(obj: any): obj is Variable { - return obj && obj.type === 'variable'; + if (!obj || typeof obj !== 'object') { + return false; + } + return obj.type === 'variable'; } export function isUseI18NSetter(prototype: any, propName: string) { @@ -103,12 +109,15 @@ export function invariant(check: any, message: string, thing?: any) { export function deprecate(fail: any, message: string, alterative?: string) { if (fail) { - console.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : '')); + logger.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : '')); } } export function isRegExp(obj: any): obj is RegExp { - return obj && obj.test && obj.exec && obj.compile; + if (!obj || typeof obj !== 'object') { + return false; + } + return 'test' in obj && 'exec' in obj && 'compile' in obj; } /** diff --git a/packages/utils/src/navtive-selection.ts b/packages/utils/src/navtive-selection.ts index 76f51f48a..b8e525773 100644 --- a/packages/utils/src/navtive-selection.ts +++ b/packages/utils/src/navtive-selection.ts @@ -1,4 +1,5 @@ -let nativeSelectionEnabled = true; +export let nativeSelectionEnabled = true; + const preventSelection = (e: Event) => { if (nativeSelectionEnabled) { return null; diff --git a/packages/utils/src/script.ts b/packages/utils/src/script.ts index 25159b198..c4c476fac 100644 --- a/packages/utils/src/script.ts +++ b/packages/utils/src/script.ts @@ -1,4 +1,7 @@ import { createDefer } from './create-defer'; +import { Logger } from './logger'; + +const logger = new Logger({ level: 'warn', bizName: 'utils' }); export function evaluate(script: string, scriptType?: string) { const scriptEl = document.createElement('script'); @@ -53,7 +56,7 @@ export function newFunction(args: string, code: string) { // eslint-disable-next-line no-new-func return new Function(args, code); } catch (e) { - console.warn('Caught error, Cant init func'); + logger.warn('Caught error, Cant init func'); return null; } } diff --git a/packages/utils/src/svg-icon.tsx b/packages/utils/src/svg-icon.tsx index f75724b06..2513f7bca 100644 --- a/packages/utils/src/svg-icon.tsx +++ b/packages/utils/src/svg-icon.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from 'react'; +import React, { ReactNode } from 'react'; const SizePresets: any = { xsmall: 8, diff --git a/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap b/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap new file mode 100644 index 000000000..14ef39453 --- /dev/null +++ b/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`wrapReactClass should render the FunctionComponent with props 1`] = ` + + Child Text + +`; diff --git a/packages/utils/test/src/build-components/buildComponents.test.ts b/packages/utils/test/src/build-components/buildComponents.test.ts deleted file mode 100644 index e854890da..000000000 --- a/packages/utils/test/src/build-components/buildComponents.test.ts +++ /dev/null @@ -1,342 +0,0 @@ - -import { buildComponents } from "../../../src/build-components"; - -function Button() {}; - -function WrapButton() {}; - -function ButtonGroup() {}; - -function WrapButtonGroup() {}; - -ButtonGroup.Button = Button; - -Button.displayName = "Button"; -ButtonGroup.displayName = "ButtonGroup"; -ButtonGroup.prototype.isReactComponent = true; -Button.prototype.isReactComponent = true; - -jest.mock('../../../src/is-react', () => { - const original = jest.requireActual('../../../src/is-react'); - return { - ...original, - wrapReactClass(view) { - return view; - } - } -}) - -describe('build-component', () => { - it('basic button', () => { - expect( - buildComponents( - { - '@alilc/button': { - Button, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - it('component is a __esModule', () => { - expect( - buildComponents( - { - '@alilc/button': { - __esModule: true, - default: Button, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }) - - it('basic warp button', () => { - expect( - buildComponents( - { - '@alilc/button': { - WrapButton, - } - }, - { - WrapButton: { - componentName: 'WrapButton', - package: '@alilc/button', - destructuring: true, - exportName: 'WrapButton', - subName: 'WrapButton', - } - }, - () => {}, - )) - .toEqual({ - WrapButton, - }); - }); - - it('destructuring is false button', () => { - expect( - buildComponents( - { - '@alilc/button': Button - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: false, - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - it('Button and ButtonGroup', () => { - expect( - buildComponents( - { - '@alilc/button': { - Button, - ButtonGroup, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('ButtonGroup and ButtonGroup.Button', () => { - expect( - buildComponents( - { - '@alilc/button': { - ButtonGroup, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup.Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('ButtonGroup.default and ButtonGroup.Button', () => { - expect( - buildComponents( - { - '@alilc/button': ButtonGroup, - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'default', - subName: 'default', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('no npm component', () => { - expect( - buildComponents( - { - '@alilc/button': Button, - }, - { - Button: null, - }, - () => {}, - )) - .toEqual({}); - }); - - it('no npm component and global button', () => { - window.Button = Button; - expect( - buildComponents( - {}, - { - Button: null, - }, - () => {}, - )) - .toEqual({ - Button, - }); - window.Button = null; - }); - - it('componentsMap value is component funtion', () => { - expect( - buildComponents( - {}, - { - Button, - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - - it('componentsMap value is component', () => { - expect( - buildComponents( - {}, - { - Button: WrapButton, - }, - () => {}, - )) - .toEqual({ - Button: WrapButton, - }); - }); - - it('componentsMap value is mix component', () => { - expect( - buildComponents( - {}, - { - Button: { - WrapButton, - Button, - ButtonGroup, - }, - }, - () => {}, - )) - .toEqual({ - Button: { - WrapButton, - Button, - ButtonGroup, - }, - }); - }); - - it('componentsMap value is Lowcode Component', () => { - expect( - buildComponents( - {}, - { - Button: { - componentName: 'Component', - schema: {}, - }, - }, - (component) => { - return component as any; - }, - )) - .toEqual({ - Button: { - componentsMap: [], - componentsTree: [ - { - componentName: 'Component', - schema: {}, - } - ], - version: "", - }, - }); - }) -}); - -describe('build div component', () => { - it('build div component', () => { - const components = buildComponents( - { - '@alilc/div': 'div' - }, - { - div: { - componentName: 'div', - package: '@alilc/div' - } - }, - () => {}, - ); - - expect(components['div']).not.toBeNull(); - }) -}) \ No newline at end of file diff --git a/packages/utils/test/src/build-components/buildComponents.test.tsx b/packages/utils/test/src/build-components/buildComponents.test.tsx new file mode 100644 index 000000000..a50a68b39 --- /dev/null +++ b/packages/utils/test/src/build-components/buildComponents.test.tsx @@ -0,0 +1,616 @@ +import React from 'react'; +import { + accessLibrary, + generateHtmlComp, + getSubComponent, + buildComponents, + getProjectUtils, +} from "../../../src/build-components"; + +function Button() {}; + +function WrapButton() {}; + +function ButtonGroup() {}; + +function WrapButtonGroup() {}; + +ButtonGroup.Button = Button; + +Button.displayName = "Button"; +ButtonGroup.displayName = "ButtonGroup"; +ButtonGroup.prototype.isReactComponent = true; +Button.prototype.isReactComponent = true; + +jest.mock('../../../src/is-react', () => { + const original = jest.requireActual('../../../src/is-react'); + return { + ...original, + wrapReactClass(view) { + return view; + } + } +}); + +describe('accessLibrary', () => { + it('should return a library object when given a library object', () => { + const libraryObject = { key: 'value' }; + const result = accessLibrary(libraryObject); + expect(result).toEqual(libraryObject); + }); + + it('should generate an HTML component when given a string library name', () => { + const libraryName = 'div'; + const result = accessLibrary(libraryName); + + // You can write more specific assertions to validate the generated component + expect(result).toBeDefined(); + }); + + // Add more test cases to cover other scenarios +}); + +describe('generateHtmlComp', () => { + it('should generate an HTML component for valid HTML tags', () => { + const htmlTags = ['a', 'img', 'div', 'span', 'svg']; + htmlTags.forEach((tag) => { + const result = generateHtmlComp(tag); + + // You can write more specific assertions to validate the generated component + expect(result).toBeDefined(); + }); + }); + + it('should return undefined for an invalid HTML tag', () => { + const invalidTag = 'invalidtag'; + const result = generateHtmlComp(invalidTag); + expect(result).toBeUndefined(); + }); + + // Add more test cases to cover other scenarios +}); + +describe('getSubComponent', () => { + it('should return the root library if paths are empty', () => { + const library = { component: 'RootComponent' }; + const paths = []; + const result = getSubComponent(library, paths); + expect(result).toEqual(library); + }); + + it('should return the specified sub-component', () => { + const library = { + components: { + Button: 'ButtonComponent', + Text: 'TextComponent', + }, + }; + const paths = ['components', 'Button']; + const result = getSubComponent(library, paths); + expect(result).toEqual('ButtonComponent'); + }); + + it('should handle missing keys in the path', () => { + const library = { + components: { + Button: 'ButtonComponent', + }, + }; + const paths = ['components', 'Text']; + const result = getSubComponent(library, paths); + expect(result).toEqual({ + Button: 'ButtonComponent', + }); + }); + + it('should handle exceptions and return null', () => { + const library = 'ButtonComponent'; + const paths = ['components', 'Button']; + // Simulate an exception by providing a non-object in place of 'ButtonComponent' + const result = getSubComponent(library, paths); + expect(result).toBeNull(); + }); + + it('should handle the "default" key as the first path element', () => { + const library = { + default: 'DefaultComponent', + }; + const paths = ['default']; + const result = getSubComponent(library, paths); + expect(result).toEqual('DefaultComponent'); + }); +}); + +describe('getProjectUtils', () => { + it('should return an empty object when given empty metadata and library map', () => { + const libraryMap = {}; + const utilsMetadata = []; + const result = getProjectUtils(libraryMap, utilsMetadata); + expect(result).toEqual({}); + }); + + it('should return project utilities based on metadata and library map', () => { + const libraryMap = { + 'package1': 'library1', + 'package2': 'library2', + }; + + const utilsMetadata = [ + { + name: 'util1', + npm: { + package: 'package1', + }, + }, + { + name: 'util2', + npm: { + package: 'package2', + }, + }, + ]; + + global['library1'] = { name: 'library1' }; + global['library2'] = { name: 'library2' }; + + const result = getProjectUtils(libraryMap, utilsMetadata); + + // Define the expected output based on the mocked accessLibrary + const expectedOutput = { + 'util1': { name: 'library1' }, + 'util2': { name: 'library2' }, + }; + + expect(result).toEqual(expectedOutput); + + global['library1'] = null; + global['library1'] = null; + }); + + it('should handle metadata with destructuring', () => { + const libraryMap = { + 'package1': { destructuring: true, util1: 'library1', util2: 'library2' }, + }; + + const utilsMetadata = [ + { + name: 'util1', + npm: { + package: 'package1', + destructuring: true, + }, + }, + ]; + + const result = getProjectUtils(libraryMap, utilsMetadata); + + // Define the expected output based on the mocked accessLibrary + const expectedOutput = { + 'util1': 'library1', + 'util2': 'library2', + }; + + expect(result).toEqual(expectedOutput); + }); +}); + +describe('buildComponents', () => { + it('should create components from component map with React components', () => { + const libraryMap = {}; + const componentsMap = { + Button: () => , + Text: () =>

Text

, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with component schemas', () => { + const libraryMap = {}; + const componentsMap = { + Button: { + componentsTree: [ + { + componentName: 'Component' + } + ] + }, + Text: { + componentsTree: [ + { + componentName: 'Component' + } + ] + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with React components and schemas', () => { + const libraryMap = {}; + const componentsMap = { + Button: () => , + Text: { + type: 'ComponentSchema', + // Add component schema properties here + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with library mappings', () => { + const libraryMap = { + 'libraryName1': 'library1', + 'libraryName2': 'library2', + }; + const componentsMap = { + Button: { + package: 'libraryName1', + version: '1.0', + exportName: 'ButtonComponent', + }, + Text: { + package: 'libraryName2', + version: '2.0', + exportName: 'TextComponent', + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + global['library1'] = () => ; + global['library2'] = () => () =>

TextComponent

; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + + global['library1'] = null; + global['library2'] = null; + }); +}); + +describe('build-component', () => { + it('basic button', () => { + expect( + buildComponents( + { + '@alilc/button': { + Button, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + it('component is a __esModule', () => { + expect( + buildComponents( + { + '@alilc/button': { + __esModule: true, + default: Button, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }) + + it('basic warp button', () => { + expect( + buildComponents( + { + '@alilc/button': { + WrapButton, + } + }, + { + WrapButton: { + componentName: 'WrapButton', + package: '@alilc/button', + destructuring: true, + exportName: 'WrapButton', + subName: 'WrapButton', + } + }, + () => {}, + )) + .toEqual({ + WrapButton, + }); + }); + + it('destructuring is false button', () => { + expect( + buildComponents( + { + '@alilc/button': Button + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: false, + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + it('Button and ButtonGroup', () => { + expect( + buildComponents( + { + '@alilc/button': { + Button, + ButtonGroup, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('ButtonGroup and ButtonGroup.Button', () => { + expect( + buildComponents( + { + '@alilc/button': { + ButtonGroup, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup.Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('ButtonGroup.default and ButtonGroup.Button', () => { + expect( + buildComponents( + { + '@alilc/button': ButtonGroup, + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'default', + subName: 'default', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('no npm component', () => { + expect( + buildComponents( + { + '@alilc/button': Button, + }, + { + Button: null, + }, + () => {}, + )) + .toEqual({}); + }); + + it('no npm component and global button', () => { + window.Button = Button; + expect( + buildComponents( + {}, + { + Button: null, + }, + () => {}, + )) + .toEqual({ + Button, + }); + window.Button = null; + }); + + it('componentsMap value is component funtion', () => { + expect( + buildComponents( + {}, + { + Button, + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + + it('componentsMap value is component', () => { + expect( + buildComponents( + {}, + { + Button: WrapButton, + }, + () => {}, + )) + .toEqual({ + Button: WrapButton, + }); + }); + + it('componentsMap value is mix component', () => { + expect( + buildComponents( + {}, + { + Button: { + WrapButton, + Button, + ButtonGroup, + }, + }, + () => {}, + )) + .toEqual({ + Button: { + WrapButton, + Button, + ButtonGroup, + }, + }); + }); + + it('componentsMap value is Lowcode Component', () => { + expect( + buildComponents( + {}, + { + Button: { + componentName: 'Component', + schema: {}, + }, + }, + (component) => { + return component as any; + }, + )) + .toEqual({ + Button: { + componentsMap: [], + componentsTree: [ + { + componentName: 'Component', + schema: {}, + } + ], + version: "", + }, + }); + }) +}); + +describe('build div component', () => { + it('build div component', () => { + const components = buildComponents( + { + '@alilc/div': 'div' + }, + { + div: { + componentName: 'div', + package: '@alilc/div' + } + }, + () => {}, + ); + + expect(components['div']).not.toBeNull(); + }) +}) \ No newline at end of file diff --git a/packages/utils/test/src/check-types/is-action-content-object.test.ts b/packages/utils/test/src/check-types/is-action-content-object.test.ts new file mode 100644 index 000000000..08b95788d --- /dev/null +++ b/packages/utils/test/src/check-types/is-action-content-object.test.ts @@ -0,0 +1,20 @@ +import { isActionContentObject } from '../../../src/check-types/is-action-content-object'; + +describe('isActionContentObject', () => { + test('should return true for an object', () => { + const obj = { prop: 'value' }; + expect(isActionContentObject(obj)).toBe(true); + }); + + test('should return false for a non-object', () => { + expect(isActionContentObject('not an object')).toBe(false); + expect(isActionContentObject(123)).toBe(false); + expect(isActionContentObject(null)).toBe(false); + expect(isActionContentObject(undefined)).toBe(false); + }); + + test('should return false for an empty object', () => { + const obj = {}; + expect(isActionContentObject(obj)).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-custom-view.test.tsx b/packages/utils/test/src/check-types/is-custom-view.test.tsx new file mode 100644 index 000000000..62c08780e --- /dev/null +++ b/packages/utils/test/src/check-types/is-custom-view.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { isCustomView } from '../../../src/check-types/is-custom-view'; +import { IPublicTypeCustomView } from '@alilc/lowcode-types'; + +describe('isCustomView', () => { + test('should return true when obj is a valid React element', () => { + const obj: IPublicTypeCustomView =
Hello, World!
; + expect(isCustomView(obj)).toBe(true); + }); + + test('should return true when obj is a valid React component', () => { + const MyComponent: React.FC = () =>
Hello, World!
; + const obj: IPublicTypeCustomView = MyComponent; + expect(isCustomView(obj)).toBe(true); + }); + + test('should return false when obj is null or undefined', () => { + expect(isCustomView(null)).toBe(false); + expect(isCustomView(undefined)).toBe(false); + }); + + test('should return false when obj is not a valid React element or component', () => { + const obj: IPublicTypeCustomView = 'not a valid object'; + expect(isCustomView(obj)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-dom-text.test.ts b/packages/utils/test/src/check-types/is-dom-text.test.ts new file mode 100644 index 000000000..50dce0fb7 --- /dev/null +++ b/packages/utils/test/src/check-types/is-dom-text.test.ts @@ -0,0 +1,13 @@ +import { isDOMText } from '../../../src/check-types/is-dom-text'; + +describe('isDOMText', () => { + it('should return true when the input is a string', () => { + const result = isDOMText('Hello World'); + expect(result).toBe(true); + }); + + it('should return false when the input is not a string', () => { + const result = isDOMText(123); + expect(result).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-drag-any-object.test.ts b/packages/utils/test/src/check-types/is-drag-any-object.test.ts new file mode 100644 index 000000000..6a835f2be --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-any-object.test.ts @@ -0,0 +1,32 @@ +import { isDragAnyObject } from '../../../src/check-types/is-drag-any-object'; +import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; + +describe('isDragAnyObject', () => { + it('should return false if obj is null', () => { + const result = isDragAnyObject(null); + expect(result).toBe(false); + }); + + it('should return false if obj is number', () => { + const result = isDragAnyObject(2); + expect(result).toBe(false); + }); + + it('should return false if obj.type is NodeData', () => { + const obj = { type: IPublicEnumDragObjectType.NodeData }; + const result = isDragAnyObject(obj); + expect(result).toBe(false); + }); + + it('should return false if obj.type is Node', () => { + const obj = { type: IPublicEnumDragObjectType.Node }; + const result = isDragAnyObject(obj); + expect(result).toBe(false); + }); + + it('should return true if obj.type is anything else', () => { + const obj = { type: 'SomeOtherType' }; + const result = isDragAnyObject(obj); + expect(result).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts b/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts new file mode 100644 index 000000000..92867843a --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts @@ -0,0 +1,29 @@ +import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types'; +import { isDragNodeDataObject } from '../../../src/check-types/is-drag-node-data-object'; + +describe('isDragNodeDataObject', () => { + test('should return true for valid IPublicTypeDragNodeDataObject', () => { + const obj: IPublicTypeDragNodeDataObject = { + type: IPublicEnumDragObjectType.NodeData, + // 其他属性... + }; + + expect(isDragNodeDataObject(obj)).toBe(true); + }); + + test('should return false for invalid IPublicTypeDragNodeDataObject', () => { + const obj: any = { + type: 'InvalidType', + // 其他属性... + }; + + expect(isDragNodeDataObject(obj)).toBe(false); + }); + + test('should return false for null or undefined', () => { + expect(isDragNodeDataObject(null)).toBe(false); + expect(isDragNodeDataObject(undefined)).toBe(false); + }); + + // 可以添加更多测试用例... +}); diff --git a/packages/utils/test/src/check-types/is-drag-node-object.test.ts b/packages/utils/test/src/check-types/is-drag-node-object.test.ts new file mode 100644 index 000000000..3561c8788 --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-node-object.test.ts @@ -0,0 +1,36 @@ +import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; +import { isDragNodeObject } from '../../../src/check-types/is-drag-node-object'; + +describe('isDragNodeObject', () => { + it('should return true if the object is of IPublicTypeDragNodeObject type and has type IPublicEnumDragObjectType.Node', () => { + const obj = { + type: IPublicEnumDragObjectType.Node, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(true); + }); + + it('should return false if the object is not of IPublicTypeDragNodeObject type', () => { + const obj = { + type: IPublicEnumDragObjectType.OtherType, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(false); + }); + + it('should return false if the object is of IPublicTypeDragNodeObject type but type is not IPublicEnumDragObjectType.Node', () => { + const obj = { + type: IPublicEnumDragObjectType.OtherType, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(false); + }); + + it('should return false if the object is null or undefined', () => { + expect(isDragNodeObject(null)).toBe(false); + expect(isDragNodeObject(undefined)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-dynamic-setter.test.ts b/packages/utils/test/src/check-types/is-dynamic-setter.test.ts new file mode 100644 index 000000000..72f55367d --- /dev/null +++ b/packages/utils/test/src/check-types/is-dynamic-setter.test.ts @@ -0,0 +1,28 @@ +import { Component } from 'react'; +import { isDynamicSetter } from '../../../src/check-types/is-dynamic-setter'; + +describe('isDynamicSetter', () => { + it('returns true if input is a dynamic setter function', () => { + const dynamicSetter = (value: any) => { + // some implementation + }; + + expect(isDynamicSetter(dynamicSetter)).toBeTruthy(); + }); + + it('returns false if input is not a dynamic setter function', () => { + expect(isDynamicSetter('not a function')).toBeFalsy(); + expect(isDynamicSetter(null)).toBeFalsy(); + expect(isDynamicSetter(undefined)).toBeFalsy(); + expect(isDynamicSetter(2)).toBeFalsy(); + expect(isDynamicSetter(0)).toBeFalsy(); + }); + + it('returns false if input is a React class', () => { + class ReactClass extends Component { + // some implementation + } + + expect(isDynamicSetter(ReactClass)).toBeFalsy(); + }); +}); diff --git a/packages/utils/test/src/check-types/is-i18n-data.test.ts b/packages/utils/test/src/check-types/is-i18n-data.test.ts new file mode 100644 index 000000000..2e903a2ed --- /dev/null +++ b/packages/utils/test/src/check-types/is-i18n-data.test.ts @@ -0,0 +1,27 @@ +import { isI18nData } from '../../../src/check-types/is-i18n-data'; +import { IPublicTypeI18nData } from "@alilc/lowcode-types"; + +describe('isI18nData', () => { + it('should return true for valid i18n data', () => { + const i18nData: IPublicTypeI18nData = { + type: 'i18n', + // add any other required properties here + }; + + expect(isI18nData(i18nData)).toBe(true); + }); + + it('should return false for invalid i18n data', () => { + const invalidData = { + type: 'some-other-type', + // add any other properties here + }; + + expect(isI18nData(invalidData)).toBe(false); + }); + + it('should return false for undefined or null', () => { + expect(isI18nData(undefined)).toBe(false); + expect(isI18nData(null)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-isfunction.test.ts b/packages/utils/test/src/check-types/is-isfunction.test.ts new file mode 100644 index 000000000..515428228 --- /dev/null +++ b/packages/utils/test/src/check-types/is-isfunction.test.ts @@ -0,0 +1,61 @@ +import { isInnerJsFunction, isJSFunction } from '../../../src/check-types/is-isfunction'; + +describe('isInnerJsFunction', () => { + test('should return true for valid input', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'function' + }; + + expect(isInnerJsFunction(data)).toBe(true); + }); + + test('should return false for invalid input', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'object' + }; + + expect(isInnerJsFunction(data)).toBe(false); + expect(isInnerJsFunction(null)).toBe(false); + expect(isInnerJsFunction(undefined)).toBe(false); + expect(isInnerJsFunction(1)).toBe(false); + expect(isInnerJsFunction(0)).toBe(false); + expect(isInnerJsFunction('string')).toBe(false); + expect(isInnerJsFunction('')).toBe(false); + }); +}); + +describe('isJSFunction', () => { + test('should return true for valid input', () => { + const data = { + type: 'JSFunction', + }; + + expect(isJSFunction(data)).toBe(true); + }); + + test('should return true for inner js function', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'function' + }; + + expect(isJSFunction(data)).toBe(true); + }); + + test('should return false for invalid input', () => { + expect(isJSFunction(null)).toBe(false); + expect(isJSFunction(undefined)).toBe(false); + expect(isJSFunction('string')).toBe(false); + expect(isJSFunction('')).toBe(false); + expect(isJSFunction(0)).toBe(false); + expect(isJSFunction(2)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-jsblock.test.ts b/packages/utils/test/src/check-types/is-jsblock.test.ts new file mode 100644 index 000000000..e44e9eb70 --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsblock.test.ts @@ -0,0 +1,22 @@ +import { isJSBlock } from '../../../src/check-types/is-jsblock'; + +describe('isJSBlock', () => { + it('should return false if data is null or undefined', () => { + expect(isJSBlock(null)).toBe(false); + expect(isJSBlock(undefined)).toBe(false); + }); + + it('should return false if data is not an object', () => { + expect(isJSBlock('JSBlock')).toBe(false); + expect(isJSBlock(123)).toBe(false); + expect(isJSBlock(true)).toBe(false); + }); + + it('should return false if data.type is not "JSBlock"', () => { + expect(isJSBlock({ type: 'InvalidType' })).toBe(false); + }); + + it('should return true if data is an object and data.type is "JSBlock"', () => { + expect(isJSBlock({ type: 'JSBlock' })).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-jsexpression.test.ts b/packages/utils/test/src/check-types/is-jsexpression.test.ts new file mode 100644 index 000000000..dd8509a3b --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsexpression.test.ts @@ -0,0 +1,39 @@ +import { isJSExpression } from '../../../src/check-types/is-jsexpression'; + +describe('isJSExpression', () => { + it('should return true if the input is a valid JSExpression object', () => { + const validJSExpression = { + type: 'JSExpression', + extType: 'variable', + }; + + const result = isJSExpression(validJSExpression); + + expect(result).toBe(true); + }); + + it('should return false if the input is not a valid JSExpression object', () => { + const invalidJSExpression = { + type: 'JSExpression', + extType: 'function', + }; + + const result = isJSExpression(invalidJSExpression); + + expect(result).toBe(false); + }); + + it('should return false if the input is null', () => { + const result = isJSExpression(null); + + expect(result).toBe(false); + }); + + it('should return false if the input is undefined', () => { + const result = isJSExpression(undefined); + + expect(result).toBe(false); + }); + + // 添加其他需要的测试 +}); diff --git a/packages/utils/test/src/check-types/is-jsslot.test.ts b/packages/utils/test/src/check-types/is-jsslot.test.ts new file mode 100644 index 000000000..5c130cddf --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsslot.test.ts @@ -0,0 +1,37 @@ +import { isJSSlot } from '../../../src/check-types/is-jsslot'; +import { IPublicTypeJSSlot } from '@alilc/lowcode-types'; + +describe('isJSSlot', () => { + it('should return true when input is of type IPublicTypeJSSlot', () => { + const input: IPublicTypeJSSlot = { + type: 'JSSlot', + // other properties of IPublicTypeJSSlot + }; + + const result = isJSSlot(input); + + expect(result).toBe(true); + }); + + it('should return false when input is not of type IPublicTypeJSSlot', () => { + const input = { + type: 'OtherType', + // other properties + }; + + const result = isJSSlot(input); + + expect(result).toBe(false); + }); + + it('should return false when input is null or undefined', () => { + const input1 = null; + const input2 = undefined; + + const result1 = isJSSlot(input1); + const result2 = isJSSlot(input2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-location-children-detail.test.ts b/packages/utils/test/src/check-types/is-location-children-detail.test.ts new file mode 100644 index 000000000..f209e8e63 --- /dev/null +++ b/packages/utils/test/src/check-types/is-location-children-detail.test.ts @@ -0,0 +1,27 @@ +import { isLocationChildrenDetail } from '../../../src/check-types/is-location-children-detail'; +import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; + +describe('isLocationChildrenDetail', () => { + it('should return true when obj is IPublicTypeLocationChildrenDetail', () => { + const obj: IPublicTypeLocationChildrenDetail = { + type: IPublicTypeLocationDetailType.Children, + // 添加其他必要的属性 + }; + + expect(isLocationChildrenDetail(obj)).toBe(true); + }); + + it('should return false when obj is not IPublicTypeLocationChildrenDetail', () => { + const obj = { + type: 'other', + // 添加其他必要的属性 + }; + + expect(isLocationChildrenDetail(obj)).toBe(false); + expect(isLocationChildrenDetail(null)).toBe(false); + expect(isLocationChildrenDetail(undefined)).toBe(false); + expect(isLocationChildrenDetail('string')).toBe(false); + expect(isLocationChildrenDetail(0)).toBe(false); + expect(isLocationChildrenDetail(2)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-location-data.test.ts b/packages/utils/test/src/check-types/is-location-data.test.ts new file mode 100644 index 000000000..ba2e2c8be --- /dev/null +++ b/packages/utils/test/src/check-types/is-location-data.test.ts @@ -0,0 +1,44 @@ +import { isLocationData } from '../../../src/check-types/is-location-data'; +import { IPublicTypeLocationData } from '@alilc/lowcode-types'; + +describe('isLocationData', () => { + it('should return true when obj is valid location data', () => { + const obj: IPublicTypeLocationData = { + target: 'some target', + detail: 'some detail', + }; + + const result = isLocationData(obj); + + expect(result).toBe(true); + }); + + it('should return false when obj is missing target or detail', () => { + const obj1 = { + target: 'some target', + // missing detail + }; + + const obj2 = { + // missing target + detail: 'some detail', + }; + + const result1 = isLocationData(obj1); + const result2 = isLocationData(obj2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); + + it('should return false when obj is null or undefined', () => { + const obj1 = null; + const obj2 = undefined; + + const result1 = isLocationData(obj1); + const result2 = isLocationData(obj2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts b/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts new file mode 100644 index 000000000..35b76f00b --- /dev/null +++ b/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts @@ -0,0 +1,21 @@ +import { isLowCodeComponentType } from '../../../src/check-types/is-lowcode-component-type'; +import { IPublicTypeLowCodeComponent, IPublicTypeProCodeComponent } from '@alilc/lowcode-types'; + +describe('isLowCodeComponentType', () => { + test('should return true for a low code component type', () => { + const desc: IPublicTypeLowCodeComponent = { + // create a valid low code component description + }; + + expect(isLowCodeComponentType(desc)).toBe(true); + }); + + test('should return false for a pro code component type', () => { + const desc: IPublicTypeProCodeComponent = { + // create a valid pro code component description + package: 'pro-code' + }; + + expect(isLowCodeComponentType(desc)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts b/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts new file mode 100644 index 000000000..bb750ed88 --- /dev/null +++ b/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts @@ -0,0 +1,42 @@ +import { isLowcodeProjectSchema } from "../../../src/check-types/is-lowcode-project-schema"; + +describe("isLowcodeProjectSchema", () => { + it("should return false when data is null", () => { + const result = isLowcodeProjectSchema(null); + expect(result).toBe(false); + }); + + it("should return false when data is undefined", () => { + const result = isLowcodeProjectSchema(undefined); + expect(result).toBe(false); + }); + + it("should return false when data is not an object", () => { + const result = isLowcodeProjectSchema("not an object"); + expect(result).toBe(false); + }); + + it("should return false when componentsTree is missing", () => { + const data = { someKey: "someValue" }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return false when componentsTree is an empty array", () => { + const data = { componentsTree: [] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return false when the first element of componentsTree is not a component schema", () => { + const data = { componentsTree: [{}] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return true when all conditions are met", () => { + const data = { componentsTree: [{ prop: "value", componentName: 'Component' }] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-node-schema.test.ts b/packages/utils/test/src/check-types/is-node-schema.test.ts new file mode 100644 index 000000000..b5a4e39ac --- /dev/null +++ b/packages/utils/test/src/check-types/is-node-schema.test.ts @@ -0,0 +1,43 @@ +import { isNodeSchema } from '../../../src/check-types/is-node-schema'; + +describe('isNodeSchema', () => { + // 测试正常情况 + it('should return true for valid IPublicTypeNodeSchema', () => { + const validData = { + componentName: 'Component', + isNode: false, + }; + expect(isNodeSchema(validData)).toBe(true); + }); + + // 测试 null 或 undefined + it('should return false for null or undefined', () => { + expect(isNodeSchema(null)).toBe(false); + expect(isNodeSchema(undefined)).toBe(false); + }); + + // 测试没有componentName属性的情况 + it('should return false if componentName is missing', () => { + const invalidData = { + isNode: false, + }; + expect(isNodeSchema(invalidData)).toBe(false); + }); + + // 测试isNode为true的情况 + it('should return false if isNode is true', () => { + const invalidData = { + componentName: 'Component', + isNode: true, + }; + expect(isNodeSchema(invalidData)).toBe(false); + }); + + // 测试其他数据类型的情况 + it('should return false for other data types', () => { + expect(isNodeSchema('string')).toBe(false); + expect(isNodeSchema(123)).toBe(false); + expect(isNodeSchema([])).toBe(false); + expect(isNodeSchema({})).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-node.test.ts b/packages/utils/test/src/check-types/is-node.test.ts new file mode 100644 index 000000000..d6d8dfc03 --- /dev/null +++ b/packages/utils/test/src/check-types/is-node.test.ts @@ -0,0 +1,19 @@ +import { isNode } from '../../../src/check-types/is-node'; + +describe('isNode', () => { + it('should return true for a valid node', () => { + const node = { isNode: true }; + expect(isNode(node)).toBeTruthy(); + }); + + it('should return false for an invalid node', () => { + const node = { isNode: false }; + expect(isNode(node)).toBeFalsy(); + }); + + it('should return false for an undefined node', () => { + expect(isNode(undefined)).toBeFalsy(); + }); + + // Add more test cases if needed +}); diff --git a/packages/utils/test/src/check-types/is-procode-component-type.test.ts b/packages/utils/test/src/check-types/is-procode-component-type.test.ts new file mode 100644 index 000000000..58f435b98 --- /dev/null +++ b/packages/utils/test/src/check-types/is-procode-component-type.test.ts @@ -0,0 +1,13 @@ +import { isProCodeComponentType } from '../../../src/check-types/is-procode-component-type'; + +describe('isProCodeComponentType', () => { + it('should return true if the given desc object contains "package" property', () => { + const desc = { package: 'packageName' }; + expect(isProCodeComponentType(desc)).toBe(true); + }); + + it('should return false if the given desc object does not contain "package" property', () => { + const desc = { name: 'componentName' }; + expect(isProCodeComponentType(desc)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-project-schema.test.ts b/packages/utils/test/src/check-types/is-project-schema.test.ts new file mode 100644 index 000000000..0ec3f4740 --- /dev/null +++ b/packages/utils/test/src/check-types/is-project-schema.test.ts @@ -0,0 +1,28 @@ +import { IPublicTypeProjectSchema } from "@alilc/lowcode-types"; +import { isProjectSchema } from "../../../src/check-types/is-project-schema"; + +describe("isProjectSchema", () => { + it("should return true if data has componentsTree property", () => { + const data: IPublicTypeProjectSchema = { + // ... + componentsTree: { + // ... + }, + }; + expect(isProjectSchema(data)).toBe(true); + }); + + it("should return false if data does not have componentsTree property", () => { + const data = { + // ... + }; + expect(isProjectSchema(data)).toBe(false); + }); + + it("should return false if data is null or undefined", () => { + expect(isProjectSchema(null)).toBe(false); + expect(isProjectSchema(undefined)).toBe(false); + }); + + // 更多的测试用例... +}); diff --git a/packages/utils/test/src/check-types/is-setter-config.test.ts b/packages/utils/test/src/check-types/is-setter-config.test.ts new file mode 100644 index 000000000..eee234658 --- /dev/null +++ b/packages/utils/test/src/check-types/is-setter-config.test.ts @@ -0,0 +1,26 @@ +import { isSetterConfig } from '../../../src/check-types/is-setter-config'; + +describe('isSetterConfig', () => { + test('should return true for valid setter config', () => { + const config = { + componentName: 'MyComponent', + // Add other required properties here + }; + + expect(isSetterConfig(config)).toBe(true); + }); + + test('should return false for invalid setter config', () => { + const config = { + // Missing componentName property + }; + + expect(isSetterConfig(config)).toBe(false); + expect(isSetterConfig(null)).toBe(false); + expect(isSetterConfig(undefined)).toBe(false); + expect(isSetterConfig(0)).toBe(false); + expect(isSetterConfig(2)).toBe(false); + }); + + // Add more test cases for different scenarios you want to cover +}); diff --git a/packages/utils/test/src/check-types/is-setting-field.test.ts b/packages/utils/test/src/check-types/is-setting-field.test.ts new file mode 100644 index 000000000..5f9bbd623 --- /dev/null +++ b/packages/utils/test/src/check-types/is-setting-field.test.ts @@ -0,0 +1,18 @@ +import { isSettingField } from "../../../src/check-types/is-setting-field"; + +describe("isSettingField", () => { + it("should return true for an object that has isSettingField property", () => { + const obj = { isSettingField: true }; + expect(isSettingField(obj)).toBe(true); + }); + + it("should return false for an object that does not have isSettingField property", () => { + const obj = { foo: "bar" }; + expect(isSettingField(obj)).toBe(false); + }); + + it("should return false for a falsy value", () => { + const obj = null; + expect(isSettingField(obj)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-title-config.test.ts b/packages/utils/test/src/check-types/is-title-config.test.ts new file mode 100644 index 000000000..4aa6d219c --- /dev/null +++ b/packages/utils/test/src/check-types/is-title-config.test.ts @@ -0,0 +1,18 @@ +import { isTitleConfig } from '../../../src/check-types/is-title-config'; + +describe('isTitleConfig', () => { + it('should return true for valid config object', () => { + const config = { title: 'My Title' }; + expect(isTitleConfig(config)).toBe(true); + }); + + it('should return false for invalid config object', () => { + const config = { title: 'My Title', type: 'i18n' , i18nData: {} }; + expect(isTitleConfig(config)).toBe(false); + }); + + it('should return false for non-object input', () => { + const config = 'invalid'; + expect(isTitleConfig(config)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/clone-deep.test.ts b/packages/utils/test/src/clone-deep.test.ts new file mode 100644 index 000000000..58fabc6f6 --- /dev/null +++ b/packages/utils/test/src/clone-deep.test.ts @@ -0,0 +1,30 @@ +import { cloneDeep } from '../../src/clone-deep'; + +describe('cloneDeep', () => { + it('should clone null', () => { + const src = null; + expect(cloneDeep(src)).toBeNull(); + }); + + it('should clone undefined', () => { + const src = undefined; + expect(cloneDeep(src)).toBeUndefined(); + }); + + it('should clone an array', () => { + const src = [1, 2, 3, 4]; + expect(cloneDeep(src)).toEqual(src); + }); + + it('should clone an object', () => { + const src = { name: 'John', age: 25 }; + expect(cloneDeep(src)).toEqual(src); + }); + + it('should deep clone nested objects', () => { + const src = { person: { name: 'John', age: 25 } }; + const cloned = cloneDeep(src); + expect(cloned).toEqual(src); + expect(cloned.person).not.toBe(src.person); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/clone-enumerable-property.test.ts b/packages/utils/test/src/clone-enumerable-property.test.ts new file mode 100644 index 000000000..2eff09e44 --- /dev/null +++ b/packages/utils/test/src/clone-enumerable-property.test.ts @@ -0,0 +1,30 @@ +import { cloneEnumerableProperty } from '../../src/clone-enumerable-property'; + +describe('cloneEnumerableProperty', () => { + test('should clone enumerable properties from origin to target', () => { + // Arrange + const target = {}; + const origin = { prop1: 1, prop2: 'hello', prop3: true }; + + // Act + const result = cloneEnumerableProperty(target, origin); + + // Assert + expect(result).toBe(target); + expect(result).toEqual(origin); + }); + + test('should exclude properties specified in excludePropertyNames', () => { + // Arrange + const target = {}; + const origin = { prop1: 1, prop2: 'hello', prop3: true }; + const excludePropertyNames = ['prop2']; + + // Act + const result = cloneEnumerableProperty(target, origin, excludePropertyNames); + + // Assert + expect(result).toBe(target); + expect(result).toEqual({ prop1: 1, prop3: true }); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/create-content.test.tsx b/packages/utils/test/src/create-content.test.tsx new file mode 100644 index 000000000..c41fb0f0d --- /dev/null +++ b/packages/utils/test/src/create-content.test.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { createContent } from '../../src/create-content'; + +const MyComponent = () => { + return
MyComponent
+} +describe('createContent', () => { + test('should return the same content if it is a valid React element', () => { + const content =
Hello
; + const result = createContent(content); + + expect(result).toEqual(content); + }); + + test('should clone the element with props if props are provided', () => { + const content =
; + const props = { className: 'my-class' }; + const result = createContent(content, props); + + expect(result.props).toEqual(props); + }); + + test('should create an element with props if the content is a React component', () => { + const content = MyComponent; + const props = { className: 'my-class' }; + const result = createContent(content, props); + + expect(result.type).toEqual(content); + expect(result.props).toEqual(props); + }); + + test('should return the content if it is not a React element or a React component', () => { + const content = 'Hello'; + const result = createContent(content); + + expect(result).toEqual(content); + }); +}); diff --git a/packages/utils/test/src/create-defer.test.ts b/packages/utils/test/src/create-defer.test.ts new file mode 100644 index 000000000..c6ab9207a --- /dev/null +++ b/packages/utils/test/src/create-defer.test.ts @@ -0,0 +1,16 @@ +import { createDefer } from '../../src/create-defer'; + +describe('createDefer', () => { + it('should resolve with given value', async () => { + const defer = createDefer(); + defer.resolve(42); + const result = await defer.promise(); + expect(result).toBe(42); + }); + + it('should reject with given reason', async () => { + const defer = createDefer(); + defer.reject('error'); + await expect(defer.promise()).rejects.toEqual('error'); + }); +}); diff --git a/packages/utils/test/src/is-object.test.ts b/packages/utils/test/src/is-object.test.ts new file mode 100644 index 000000000..7ae984b8f --- /dev/null +++ b/packages/utils/test/src/is-object.test.ts @@ -0,0 +1,45 @@ +import { isObject, isI18NObject } from '../../src/is-object'; + +describe('isObject', () => { + it('should return true for an object', () => { + const obj = { key: 'value' }; + const result = isObject(obj); + expect(result).toBe(true); + }); + + it('should return false for null', () => { + const result = isObject(null); + expect(result).toBe(false); + }); + + it('should return false for a non-object value', () => { + const value = 42; // Not an object + const result = isObject(value); + expect(result).toBe(false); + }); +}); + +describe('isI18NObject', () => { + it('should return true for an I18N object', () => { + const i18nObject = { type: 'i18n', data: 'some data' }; + const result = isI18NObject(i18nObject); + expect(result).toBe(true); + }); + + it('should return false for a non-I18N object', () => { + const nonI18nObject = { type: 'other', data: 'some data' }; + const result = isI18NObject(nonI18nObject); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isI18NObject(null); + expect(result).toBe(false); + }); + + it('should return false for a non-object value', () => { + const value = 42; // Not an object + const result = isI18NObject(value); + expect(result).toBe(false); + }); +}); diff --git a/packages/utils/test/src/is-react.test.ts b/packages/utils/test/src/is-react.test.ts deleted file mode 100644 index 74c88c933..000000000 --- a/packages/utils/test/src/is-react.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import { isReactComponent, wrapReactClass } from "../../src/is-react"; - -class reactDemo extends React.Component { - -} - -const reactMemo = React.memo(reactDemo); - -const reactForwardRef = React.forwardRef((props, ref): any => { - return ''; -}); - -describe('is-react-ut', () => { - it('isReactComponent', () => { - expect(isReactComponent(null)).toBeFalsy(); - expect(isReactComponent(() => {})).toBeTruthy(); - expect(isReactComponent({ - $$typeof: Symbol.for('react.memo') - })).toBeTruthy(); - expect(isReactComponent({ - $$typeof: Symbol.for('react.forward_ref') - })).toBeTruthy(); - expect(isReactComponent(reactDemo)).toBeTruthy(); - expect(isReactComponent(reactMemo)).toBeTruthy(); - expect(isReactComponent(reactForwardRef)).toBeTruthy(); - - }); - - it('wrapReactClass', () => { - const wrap = wrapReactClass(() => {}); - expect(isReactComponent(wrap)).toBeTruthy(); - - const fun = () => {}; - fun.displayName = 'mock'; - expect(wrapReactClass(fun).displayName).toBe('mock'); - }) -}) \ No newline at end of file diff --git a/packages/utils/test/src/is-react.test.tsx b/packages/utils/test/src/is-react.test.tsx new file mode 100644 index 000000000..9ed2bd6c3 --- /dev/null +++ b/packages/utils/test/src/is-react.test.tsx @@ -0,0 +1,316 @@ +import React, { Component, createElement } from "react"; +import { + isReactComponent, + wrapReactClass, + isForwardOrMemoForward, + isMemoType, + isForwardRefType, + acceptsRef, + isReactClass, + REACT_MEMO_TYPE, + REACT_FORWARD_REF_TYPE, + } from "../../src/is-react"; + +class reactDemo extends React.Component { + +} + +const reactMemo = React.memo(reactDemo); + +const reactForwardRef = React.forwardRef((props, ref): any => { + return ''; +}); + +describe('is-react-ut', () => { + it('isReactComponent', () => { + expect(isReactComponent(null)).toBeFalsy(); + expect(isReactComponent(() => {})).toBeTruthy(); + expect(isReactComponent({ + $$typeof: Symbol.for('react.memo') + })).toBeTruthy(); + expect(isReactComponent({ + $$typeof: Symbol.for('react.forward_ref') + })).toBeTruthy(); + expect(isReactComponent(reactDemo)).toBeTruthy(); + expect(isReactComponent(reactMemo)).toBeTruthy(); + expect(isReactComponent(reactForwardRef)).toBeTruthy(); + + }); + + it('wrapReactClass', () => { + const wrap = wrapReactClass(() => {}); + expect(isReactComponent(wrap)).toBeTruthy(); + + const fun = () => {}; + fun.displayName = 'mock'; + expect(wrapReactClass(fun).displayName).toBe('mock'); + }) +}) + +describe('wrapReactClass', () => { + it('should wrap a FunctionComponent', () => { + // Create a mock FunctionComponent + const MockComponent: React.FunctionComponent = (props) => { + return
{props.children}
; + }; + + // Wrap the FunctionComponent using wrapReactClass + const WrappedComponent = wrapReactClass(MockComponent); + const instance = new WrappedComponent(); + + // Check if the WrappedComponent extends Component + expect(instance instanceof React.Component).toBe(true); + }); + + it('should render the FunctionComponent with props', () => { + // Create a mock FunctionComponent + const MockComponent: React.FunctionComponent = (props) => { + return
{props.children}
; + }; + + MockComponent.displayName = 'FunctionComponent'; + + // Wrap the FunctionComponent using wrapReactClass + const WrappedComponent = wrapReactClass(MockComponent); + + // Create some test props + const testProps = { prop1: 'value1', prop2: 'value2' }; + + // Render the WrappedComponent with test props + const rendered = createElement(WrappedComponent, testProps, 'Child Text'); + + // Check if the WrappedComponent renders the FunctionComponent with props + expect(rendered).toMatchSnapshot(); + }); +}); + +describe('isReactComponent', () => { + it('should identify a class component as a React component', () => { + class ClassComponent extends React.Component { + render() { + return
Class Component
; + } + } + + expect(isReactComponent(ClassComponent)).toBe(true); + }); + + it('should identify a functional component as a React component', () => { + const FunctionalComponent = () => { + return
Functional Component
; + }; + + expect(isReactComponent(FunctionalComponent)).toBe(true); + }); + + it('should identify a forward ref component as a React component', () => { + const ForwardRefComponent = React.forwardRef((props, ref) => { + return
Forward Ref Component
; + }); + + expect(isReactComponent(ForwardRefComponent)).toBe(true); + }); + + it('should identify a memo component as a React component', () => { + const MemoComponent = React.memo(() => { + return
Memo Component
; + }); + + expect(isReactComponent(MemoComponent)).toBe(true); + }); + + it('should return false for non-React components', () => { + const plainObject = { prop: 'value' }; + const notAComponent = 'Not a component'; + + expect(isReactComponent(plainObject)).toBe(false); + expect(isReactComponent(notAComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isReactComponent(nullValue)).toBe(false); + expect(isReactComponent(undefinedValue)).toBe(false); + }); +}); + +describe('isForwardOrMemoForward', () => { + it('should return true for a forwardRef component', () => { + const forwardRefComponent = React.forwardRef(() => { + return
ForwardRef Component
; + }); + + expect(isForwardOrMemoForward(forwardRefComponent)).toBe(true); + }); + + it('should return true for a memoized forwardRef component', () => { + const forwardRefComponent = React.forwardRef(() => { + return
ForwardRef Component
; + }); + + const memoizedComponent = React.memo(forwardRefComponent); + + expect(isForwardOrMemoForward(memoizedComponent)).toBe(true); + }); + + it('should return false for a memoized component that is not a forwardRef', () => { + const memoizedComponent = React.memo(() => { + return
Memoized Component
; + }); + + expect(isForwardOrMemoForward(memoizedComponent)).toBe(false); + }); + + it('should return false for a plain object', () => { + const plainObject = { prop: 'value' }; + + expect(isForwardOrMemoForward(plainObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isForwardOrMemoForward(nullValue)).toBe(false); + expect(isForwardOrMemoForward(undefinedValue)).toBe(false); + }); +}); + +describe('isMemoType', () => { + it('should return true for an object with $$typeof matching REACT_MEMO_TYPE', () => { + const memoTypeObject = { $$typeof: REACT_MEMO_TYPE }; + + expect(isMemoType(memoTypeObject)).toBe(true); + }); + + it('should return false for an object with $$typeof not matching REACT_MEMO_TYPE', () => { + const otherTypeObject = { $$typeof: Symbol.for('other.type') }; + + expect(isMemoType(otherTypeObject)).toBe(false); + }); + + it('should return false for an object with no $$typeof property', () => { + const noTypeObject = { key: 'value' }; + + expect(isMemoType(noTypeObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isMemoType(nullValue)).toBe(false); + expect(isMemoType(undefinedValue)).toBe(false); + }); +}); + +describe('isForwardRefType', () => { + it('should return true for an object with $$typeof matching REACT_FORWARD_REF_TYPE', () => { + const forwardRefTypeObject = { $$typeof: REACT_FORWARD_REF_TYPE }; + + expect(isForwardRefType(forwardRefTypeObject)).toBe(true); + }); + + it('should return false for an object with $$typeof not matching REACT_FORWARD_REF_TYPE', () => { + const otherTypeObject = { $$typeof: Symbol.for('other.type') }; + + expect(isForwardRefType(otherTypeObject)).toBe(false); + }); + + it('should return false for an object with no $$typeof property', () => { + const noTypeObject = { key: 'value' }; + + expect(isForwardRefType(noTypeObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isForwardRefType(nullValue)).toBe(false); + expect(isForwardRefType(undefinedValue)).toBe(false); + }); +}); + +describe('acceptsRef', () => { + it('should return true for an object with isReactComponent in its prototype', () => { + const objWithIsReactComponent = { + prototype: { + isReactComponent: true, + }, + }; + + expect(acceptsRef(objWithIsReactComponent)).toBe(true); + }); + + it('should return true for an object that is forwardRef or memoized forwardRef', () => { + const forwardRefObject = React.forwardRef(() => { + return null; + }); + + const memoizedForwardRefObject = React.memo(forwardRefObject); + + expect(acceptsRef(forwardRefObject)).toBe(true); + expect(acceptsRef(memoizedForwardRefObject)).toBe(true); + }); + + it('should return false for an object without isReactComponent in its prototype', () => { + const objWithoutIsReactComponent = { + prototype: { + someOtherProperty: true, + }, + }; + + expect(acceptsRef(objWithoutIsReactComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(acceptsRef(nullValue)).toBe(false); + expect(acceptsRef(undefinedValue)).toBe(false); + }); +}); + +describe('isReactClass', () => { + it('should return true for an object with isReactComponent in its prototype', () => { + class ReactClassComponent extends Component { + render() { + return null; + } + } + + expect(isReactClass(ReactClassComponent)).toBe(true); + }); + + it('should return true for an object with Component in its prototype chain', () => { + class CustomComponent extends Component { + render() { + return null; + } + } + + expect(isReactClass(CustomComponent)).toBe(true); + }); + + it('should return false for an object without isReactComponent in its prototype', () => { + class NonReactComponent { + render() { + return null; + } + } + + expect(isReactClass(NonReactComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isReactClass(nullValue)).toBe(false); + expect(isReactClass(undefinedValue)).toBe(false); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/is-shaken.test.ts b/packages/utils/test/src/is-shaken.test.ts new file mode 100644 index 000000000..35a27af5f --- /dev/null +++ b/packages/utils/test/src/is-shaken.test.ts @@ -0,0 +1,45 @@ +import { isShaken } from '../../src/is-shaken'; + +describe('isShaken', () => { + it('should return true if e1 has shaken property', () => { + const e1: any = { shaken: true }; + const e2: MouseEvent | DragEvent = { target: null } as MouseEvent | DragEvent; + + expect(isShaken(e1, e2)).toBe(true); + }); + + it('should return true if e1.target and e2.target are different', () => { + const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + + expect(isShaken(e1, e2)).toBe(true); + }); + + it('should return false if e1 and e2 targets are the same and distance is less than SHAKE_DISTANCE', () => { + const target = {}; + const e1: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent; + + // Assuming SHAKE_DISTANCE is 100 + e1.clientY = 50; + e2.clientY = 50; + + e1.clientX = 60; + e2.clientX = 60; + + expect(isShaken(e1, e2)).toBe(false); + }); + + it('should return true if e1 and e2 targets are the same and distance is greater than SHAKE_DISTANCE', () => { + const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + + // Assuming SHAKE_DISTANCE is 100 + e1.clientY = 50; + e1.clientX = 50; + e2.clientY = 200; + e2.clientX = 200; + + expect(isShaken(e1, e2)).toBe(true); + }); +}); diff --git a/packages/utils/test/src/misc.test.ts b/packages/utils/test/src/misc.test.ts index 8873dc4c8..251466150 100644 --- a/packages/utils/test/src/misc.test.ts +++ b/packages/utils/test/src/misc.test.ts @@ -1,4 +1,321 @@ -import { shouldUseVariableSetter } from '../../src/misc'; +import { + isVariable, + isUseI18NSetter, + convertToI18NObject, + isString, + waitForThing, + arrShallowEquals, + isFromVC, + executePendingFn, + compatStage, + invariant, + isRegExp, + shouldUseVariableSetter, +} from '../../src/misc'; +import { IPublicModelComponentMeta } from '@alilc/lowcode-types'; + +describe('isVariable', () => { + it('should return true for a variable object', () => { + const variable = { type: 'variable', variable: 'foo', value: 'bar' }; + const result = isVariable(variable); + expect(result).toBe(true); + }); + + it('should return false for non-variable objects', () => { + const obj = { type: 'object' }; + const result = isVariable(obj); + expect(result).toBe(false); + }); +}); + +describe('isUseI18NSetter', () => { + it('should return true for a property with I18nSetter', () => { + const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'I18nSetter' } } }] } }; + const propName = 'propName'; + const result = isUseI18NSetter(prototype, propName); + expect(result).toBe(true); + }); + + it('should return false for a property without I18nSetter', () => { + const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'OtherSetter' } } }] } }; + const propName = 'propName'; + const result = isUseI18NSetter(prototype, propName); + expect(result).toBe(false); + }); +}); + +describe('convertToI18NObject', () => { + it('should return the input if it is already an I18N object', () => { + const i18nObject = { type: 'i18n', use: 'en', en: 'Hello' }; + const result = convertToI18NObject(i18nObject); + expect(result).toEqual(i18nObject); + }); + + it('should convert a string to an I18N object', () => { + const inputString = 'Hello'; + const result = convertToI18NObject(inputString); + const expectedOutput = { type: 'i18n', use: 'zh-CN', 'zh-CN': inputString }; + expect(result).toEqual(expectedOutput); + }); +}); + +describe('isString', () => { + it('should return true for a string', () => { + const stringValue = 'Hello, world!'; + const result = isString(stringValue); + expect(result).toBe(true); + }); + + it('should return true for an empty string', () => { + const emptyString = ''; + const result = isString(emptyString); + expect(result).toBe(true); + }); + + it('should return false for a number', () => { + const numberValue = 42; // Not a string + const result = isString(numberValue); + expect(result).toBe(false); + }); + + it('should return false for an object', () => { + const objectValue = { key: 'value' }; // Not a string + const result = isString(objectValue); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isString(null); + expect(result).toBe(false); + }); + + it('should return false for undefined', () => { + const undefinedValue = undefined; + const result = isString(undefinedValue); + expect(result).toBe(false); + }); + + it('should return false for a boolean', () => { + const booleanValue = true; // Not a string + const result = isString(booleanValue); + expect(result).toBe(false); + }); +}); + +describe('waitForThing', () => { + it('should resolve immediately if the thing is available', async () => { + const obj = { prop: 'value' }; + const path = 'prop'; + const result = await waitForThing(obj, path); + expect(result).toBe('value'); + }); + + it('should resolve after a delay if the thing becomes available', async () => { + const obj = { prop: undefined }; + const path = 'prop'; + const delay = 100; // Adjust the delay as needed + setTimeout(() => { + obj.prop = 'value'; + }, delay); + + const result = await waitForThing(obj, path); + expect(result).toBe('value'); + }); +}); + +describe('arrShallowEquals', () => { + it('should return true for two empty arrays', () => { + const arr1 = []; + const arr2 = []; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return true for two arrays with the same elements in the same order', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2, 3]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return true for two arrays with the same elements in a different order', () => { + const arr1 = [1, 2, 3]; + const arr2 = [3, 2, 1]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return false for two arrays with different lengths', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(false); + }); + + it('should return false for one array and a non-array', () => { + const arr1 = [1, 2, 3]; + const nonArray = 'not an array'; + const result = arrShallowEquals(arr1, nonArray); + expect(result).toBe(false); + }); + + it('should return false for two arrays with different elements', () => { + const arr1 = [1, 2, 3]; + const arr2 = [3, 4, 5]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(false); + }); + + it('should return true for arrays with duplicate elements', () => { + const arr1 = [1, 2, 2, 3]; + const arr2 = [2, 3, 3, 1]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); +}); + +describe('isFromVC', () => { + it('should return true when advanced configuration is present', () => { + // Create a mock meta object with advanced configuration + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: { advanced: true } }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(true); + }); + + it('should return false when advanced configuration is not present', () => { + // Create a mock meta object without advanced configuration + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: { advanced: false } }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when meta is undefined', () => { + const meta: IPublicModelComponentMeta | undefined = undefined; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when meta does not have configure information', () => { + // Create a mock meta object without configure information + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({}), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when configure.advanced is not present', () => { + // Create a mock meta object with incomplete configure information + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: {} }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); +}); + +describe('executePendingFn', () => { + it('should execute the provided function after the specified timeout', async () => { + // Mock the function to execute + const fn = jest.fn(); + + // Call executePendingFn with the mocked function and a short timeout + executePendingFn(fn, 100); + + // Ensure the function has not been called immediately + expect(fn).not.toHaveBeenCalled(); + + // Wait for the specified timeout + await new Promise(resolve => setTimeout(resolve, 100)); + + // Ensure the function has been called after the timeout + expect(fn).toHaveBeenCalled(); + }); + + it('should execute the provided function with a default timeout if not specified', async () => { + // Mock the function to execute + const fn = jest.fn(); + + // Call executePendingFn with the mocked function without specifying a timeout + executePendingFn(fn); + + // Ensure the function has not been called immediately + expect(fn).not.toHaveBeenCalled(); + + // Wait for the default timeout (2000 milliseconds) + await new Promise(resolve => setTimeout(resolve, 2000)); + + // Ensure the function has been called after the default timeout + expect(fn).toHaveBeenCalled(); + }); +}); + +describe('compatStage', () => { + it('should convert a number to an enum stage', () => { + const result = compatStage(3); + expect(result).toBe('save'); + }); + + it('should warn about the deprecated usage', () => { + const warnSpy = jest.spyOn(console, 'warn'); + const result = compatStage(2); + expect(result).toBe('serilize'); + expect(warnSpy).toHaveBeenCalledWith( + 'stage 直接指定为数字的使用方式已经过时,将在下一版本移除,请直接使用 IPublicEnumTransformStage.Render|Serilize|Save|Clone|Init|Upgrade' + ); + warnSpy.mockRestore(); + }); + + it('should return the enum stage if it is already an enum', () => { + const result = compatStage('render'); + expect(result).toBe('render'); + }); +}); + +describe('invariant', () => { + it('should not throw an error if the check is true', () => { + expect(() => invariant(true, 'Test invariant', 'thing')).not.toThrow(); + }); + + it('should throw an error if the check is false', () => { + expect(() => invariant(false, 'Test invariant', 'thing')).toThrowError( + "Invariant failed: Test invariant in 'thing'" + ); + }); +}); + +describe('isRegExp', () => { + it('should return true for a valid RegExp', () => { + const regex = /test/; + const result = isRegExp(regex); + expect(result).toBe(true); + }); + + it('should return false for a non-RegExp object', () => { + const nonRegExp = { test: /test/ }; + const result = isRegExp(nonRegExp); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isRegExp(null); + expect(result).toBe(false); + }); +}); it('shouldUseVariableSetter', () => { expect(shouldUseVariableSetter(false, true)).toBeFalsy(); diff --git a/packages/utils/test/src/navtive-selection.test.ts b/packages/utils/test/src/navtive-selection.test.ts new file mode 100644 index 000000000..f45d0e1b2 --- /dev/null +++ b/packages/utils/test/src/navtive-selection.test.ts @@ -0,0 +1,18 @@ +import { setNativeSelection, nativeSelectionEnabled } from '../../src/navtive-selection'; + +describe('setNativeSelection', () => { + beforeEach(() => { + // 在每个测试运行之前重置nativeSelectionEnabled的值 + setNativeSelection(true); + }); + + test('should enable native selection', () => { + setNativeSelection(true); + expect(nativeSelectionEnabled).toBe(true); + }); + + test('should disable native selection', () => { + setNativeSelection(false); + expect(nativeSelectionEnabled).toBe(false); + }); +}); diff --git a/packages/utils/test/src/schema.test.ts b/packages/utils/test/src/schema.test.ts index 138dd7a82..8d03f5811 100644 --- a/packages/utils/test/src/schema.test.ts +++ b/packages/utils/test/src/schema.test.ts @@ -1,4 +1,132 @@ -import { compatibleLegaoSchema } from '../../src/schema'; +import { + compatibleLegaoSchema, + getNodeSchemaById, + applyActivities, +} from '../../src/schema'; +import { ActivityType } from '@alilc/lowcode-types'; + +describe('compatibleLegaoSchema', () => { + it('should handle null input', () => { + const result = compatibleLegaoSchema(null); + expect(result).toBeNull(); + }); + + it('should convert Legao schema to JSExpression', () => { + // Create your test input + const legaoSchema = { + type: 'LegaoType', + source: 'LegaoSource', + compiled: 'LegaoCompiled', + }; + const result = compatibleLegaoSchema(legaoSchema); + + // Define the expected output + const expectedOutput = { + type: 'JSExpression', + value: 'LegaoCompiled', + extType: 'function', + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other scenarios +}); + +describe('getNodeSchemaById', () => { + it('should find a node in the schema', () => { + // Create your test schema and node ID + const testSchema = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'child1.1', + }, + ], + }, + ], + }; + const nodeId = 'child1.1'; + + const result = getNodeSchemaById(testSchema, nodeId); + + // Define the expected output + const expectedOutput = { + id: 'child1.1', + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other scenarios +}); + +describe('applyActivities', () => { + it('should apply ADD activity', () => { + // Create your test schema and activities + const testSchema = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'child1.1', + }, + ], + }, + ], + }; + const activities = [ + { + type: ActivityType.ADDED, + payload: { + location: { + parent: { + nodeId: 'child1', + index: 0, + }, + }, + schema: { + id: 'newChild', + }, + }, + }, + ]; + + const result = applyActivities(testSchema, activities); + + // Define the expected output + const expectedOutput = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'newChild', + }, + { + id: 'child1.1', + }, + ], + }, + ], + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other activity types and scenarios +}); + + describe('Schema Ut', () => { it('props', () => { const schema = { diff --git a/packages/utils/test/src/script.test.ts b/packages/utils/test/src/script.test.ts new file mode 100644 index 000000000..d3d4ffd59 --- /dev/null +++ b/packages/utils/test/src/script.test.ts @@ -0,0 +1,47 @@ +import { + evaluate, + evaluateExpression, + newFunction, +} from '../../src/script'; + +describe('evaluate', () => { + test('should evaluate the given script', () => { + const script = 'console.log("Hello, world!");'; + global.console = { log: jest.fn() }; + + evaluate(script); + + expect(global.console.log).toHaveBeenCalledWith('Hello, world!'); + }); +}); + +describe('evaluateExpression', () => { + test('should evaluate the given expression', () => { + const expr = 'return 1 + 2'; + + const result = evaluateExpression(expr); + + expect(result).toBe(3); + }); +}); + +describe('newFunction', () => { + test('should create a new function with the given arguments and code', () => { + const args = 'a, b'; + const code = 'return a + b'; + + const result = newFunction(args, code); + + expect(result).toBeInstanceOf(Function); + expect(result(1, 2)).toBe(3); + }); + + test('should return null if an error occurs', () => { + const args = 'a, b'; + const code = 'return a +;'; // Invalid code + + const result = newFunction(args, code); + + expect(result).toBeNull(); + }); +}); diff --git a/packages/utils/test/src/svg-icon.test.tsx b/packages/utils/test/src/svg-icon.test.tsx new file mode 100644 index 000000000..bbb6e18b7 --- /dev/null +++ b/packages/utils/test/src/svg-icon.test.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { SVGIcon, IconProps } from '../../src/svg-icon'; + +describe('SVGIcon', () => { + it('should render SVG element with correct size', () => { + const iconProps: IconProps = { + size: 'small', + viewBox: '0 0 24 24', + }; + + const { container } = render(); + + const svgElement = container.querySelector('svg'); + + expect(svgElement).toHaveAttribute('width', '12'); + expect(svgElement).toHaveAttribute('height', '12'); + }); + + it('should render SVG element with custom size', () => { + const iconProps: IconProps = { + size: 24, + viewBox: '0 0 24 24', + }; + + const { container } = render(); + + const svgElement = container.querySelector('svg'); + + expect(svgElement).toHaveAttribute('width', '24'); + expect(svgElement).toHaveAttribute('height', '24'); + }); + + // Add more tests for other scenarios if needed +}); diff --git a/packages/utils/test/src/transaction-manager.test.ts b/packages/utils/test/src/transaction-manager.test.ts new file mode 100644 index 000000000..42c7fa8bf --- /dev/null +++ b/packages/utils/test/src/transaction-manager.test.ts @@ -0,0 +1,58 @@ +import { transactionManager } from '../../src/transaction-manager'; +import { IPublicEnumTransitionType } from '@alilc/lowcode-types'; + +const type = IPublicEnumTransitionType.REPAINT; + +describe('TransactionManager', () => { + let fn1: jest.Mock; + let fn2: jest.Mock; + + beforeEach(() => { + fn1 = jest.fn(); + fn2 = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('executeTransaction should emit startTransaction and endTransaction events', () => { + const startTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit'); + const endTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit'); + + transactionManager.executeTransaction(() => { + // Perform some action within the transaction + }); + + expect(startTransactionSpy).toHaveBeenCalledWith(`[${type}]startTransaction`); + expect(endTransactionSpy).toHaveBeenCalledWith(`[${type}]endTransaction`); + }); + + test('onStartTransaction should register the provided function for startTransaction event', () => { + const offSpy = jest.spyOn(transactionManager.emitter, 'off'); + + const offFunction = transactionManager.onStartTransaction(fn1); + + expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(1); + expect(offSpy).not.toHaveBeenCalled(); + + offFunction(); + + expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(0); + expect(offSpy).toHaveBeenCalledWith(`[${type}]startTransaction`, fn1); + }); + + test('onEndTransaction should register the provided function for endTransaction event', () => { + const offSpy = jest.spyOn(transactionManager.emitter, 'off'); + + const offFunction = transactionManager.onEndTransaction(fn2); + + expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(1); + expect(offSpy).not.toHaveBeenCalled(); + + offFunction(); + + expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(0); + expect(offSpy).toHaveBeenCalledWith(`[${type}]endTransaction`, fn2); + }); +}); diff --git a/packages/utils/test/src/unique-id.test.ts b/packages/utils/test/src/unique-id.test.ts new file mode 100644 index 000000000..2b4b6e9e0 --- /dev/null +++ b/packages/utils/test/src/unique-id.test.ts @@ -0,0 +1,11 @@ +import { uniqueId } from '../../src/unique-id'; + +test('uniqueId should return a unique id with prefix', () => { + const id = uniqueId('test'); + expect(id.startsWith('test')).toBeTruthy(); +}); + +test('uniqueId should return a unique id without prefix', () => { + const id = uniqueId(); + expect(id).not.toBeFalsy(); +}); From 151748dbab0989555c1161721044ad4a2d29a2ff Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 13 Nov 2023 13:36:07 +0800 Subject: [PATCH 04/61] docs: add before start doc --- docs/docs/guide/quickStart/demo.md | 2 +- docs/docs/guide/quickStart/intro.md | 17 ++++++++++++++++- docs/docs/guide/quickStart/start.md | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/docs/guide/quickStart/demo.md b/docs/docs/guide/quickStart/demo.md index a05a42486..ee76d5aa1 100644 --- a/docs/docs/guide/quickStart/demo.md +++ b/docs/docs/guide/quickStart/demo.md @@ -1,6 +1,6 @@ --- title: 试用低代码引擎 Demo -sidebar_position: 1 +sidebar_position: 2 --- ## 访问地址 diff --git a/docs/docs/guide/quickStart/intro.md b/docs/docs/guide/quickStart/intro.md index 661f5912f..b65baac26 100644 --- a/docs/docs/guide/quickStart/intro.md +++ b/docs/docs/guide/quickStart/intro.md @@ -1,6 +1,6 @@ --- title: 简介 -sidebar_position: 0 +sidebar_position: 1 --- # 阿里低代码引擎简介 @@ -46,3 +46,18 @@ sidebar_position: 0 **低代码设计器研发框架** 低代码引擎的核心是设计器,通过扩展、周边生态等可以产出各式各样的设计器。它不是一套可以适合所有人的低代码平台,而是帮助低代码平台的开发者,快速生产低代码平台的工具。 + +## 寻找适合您的低代码解决方案 + +帮助用户根据个人或企业需求选择合适的低代码产品。 + +| 特性/产品 | 低代码引擎 | Lab平台 | UIPaaS | +|-----------------|-----------------------------------------|-----------------------------------------|--------------------------------------------| +| **适用用户** | 前端开发者 | 需要快速搭建应用/页面的用户 | 企业用户,需要大规模部署低代码解决方案的组织 | +| **产品特点** | 设计器研发框架,适合定制开发 | 低代码平台, 可视化操作界面,易于上手 | 低代码平台孵化器,企业级功能 | +| **使用场景** | 定制和开发低代码平台的设计器部分 | 通过可视化, 快速开发应用或页面 | 帮助具有一定规模软件研发团队的的企业低成本定制低代码平台 | +| **产品关系** | 开源产品 | 基于UIPaaS技术实现, 展示了UIPaaS的部分能力 | 提供完整的低代码平台解决方案,商业产品 | +| **收费情况** | 免费 | 可免费使用(有额度限制),不提供私有化部署售卖 | 仅提供私有化部署售卖 | +| **官方网站** | [低代码引擎官网](https://lowcode-engine.cn/) | [Lab平台官网](https://lab.lowcode-engine.cn/) | [UIPaaS官网](https://uipaas.net/) | + +*注:请根据您的具体需求和条件选择合适的产品。如需更详细的信息,请访问各产品的官方网站。* diff --git a/docs/docs/guide/quickStart/start.md b/docs/docs/guide/quickStart/start.md index b2b728b9f..356f50176 100644 --- a/docs/docs/guide/quickStart/start.md +++ b/docs/docs/guide/quickStart/start.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 title: 快速开始 --- From ef6a203a45ae7d8d0d4708bac28d36d10d7d4b07 Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 13 Nov 2023 14:09:58 +0800 Subject: [PATCH 05/61] chore(docs): publish docs 1.1.16 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 27d1a17d0..c206cdf16 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.15", + "version": "1.1.16", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 9108e8cfabdb442064f43be0533538ebbaff7f4a Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 13 Nov 2023 18:46:17 +0800 Subject: [PATCH 06/61] feat(types): add IPublicTypeInstanceOf to prop-types --- packages/types/src/shell/type/prop-types.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/types/src/shell/type/prop-types.ts b/packages/types/src/shell/type/prop-types.ts index a3344b059..22d84c86f 100644 --- a/packages/types/src/shell/type/prop-types.ts +++ b/packages/types/src/shell/type/prop-types.ts @@ -3,7 +3,7 @@ import { IPublicTypePropConfig } from './'; export type IPublicTypePropType = IPublicTypeBasicType | IPublicTypeRequiredType | IPublicTypeComplexType; export type IPublicTypeBasicType = 'array' | 'bool' | 'func' | 'number' | 'object' | 'string' | 'node' | 'element' | 'any'; -export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact; +export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact | IPublicTypeInstanceOf; export interface IPublicTypeRequiredType { type: IPublicTypeBasicType; @@ -40,3 +40,9 @@ export interface IPublicTypeExact { value: IPublicTypePropConfig[]; isRequired?: boolean; } + +export interface IPublicTypeInstanceOf { + type: 'instanceOf'; + value: IPublicTypePropConfig; + isRequired?: boolean; +} From 1020f98756c6a4886f8dd755c5fca3ff6f374876 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <66351806+beautiful-boyyy@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:48:36 +0800 Subject: [PATCH 07/61] chore: remove useless code (#2643) --- .../editor-skeleton/src/components/widget-views/index.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index 513fc1bdd..ba49b3d1a 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -232,12 +232,8 @@ export class PanelView extends Component<{ this.lastVisible = currentVisible; if (this.lastVisible) { panel.skeleton.postEvent(SkeletonEvents.PANEL_SHOW, panel.name, panel); - // FIXME! remove this line - panel.skeleton.postEvent('leftPanel.show' as any, panel.name, panel); } else { panel.skeleton.postEvent(SkeletonEvents.PANEL_HIDE, panel.name, panel); - // FIXME! remove this line - panel.skeleton.postEvent('leftPanel.hide' as any, panel.name, panel); } } } From b697ea9ad4399a90cf2560b45beb4ae669700fbc Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 14 Nov 2023 09:55:58 +0800 Subject: [PATCH 08/61] feat(render-core): update logger to console --- .../designer/src/builtin-simulator/index.ts | 1 + .../builtin-simulator/utils/parse-metadata.ts | 6 ++- packages/renderer-core/babel.config.js | 1 + packages/renderer-core/src/hoc/leaf.tsx | 3 +- packages/renderer-core/src/renderer/addon.tsx | 3 +- packages/renderer-core/src/renderer/base.tsx | 14 +++---- packages/renderer-core/src/renderer/temp.tsx | 3 +- packages/renderer-core/src/utils/common.ts | 6 +-- .../renderer-core/src/utils/data-helper.ts | 10 ++--- .../renderer-core/tests/utils/common.test.ts | 40 ++++++++++++++++++- .../tests/utils/data-helper.test.ts | 10 ----- 11 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 packages/renderer-core/babel.config.js diff --git a/packages/designer/src/builtin-simulator/index.ts b/packages/designer/src/builtin-simulator/index.ts index 6bcee7eb7..6977fd66c 100644 --- a/packages/designer/src/builtin-simulator/index.ts +++ b/packages/designer/src/builtin-simulator/index.ts @@ -2,3 +2,4 @@ export * from './host'; export * from './host-view'; export * from './renderer'; export * from './live-editing/live-editing'; +export { LowcodeTypes } from './utils/parse-metadata'; diff --git a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts index b84e4e698..5c81340a1 100644 --- a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts +++ b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts @@ -46,13 +46,15 @@ function define(propType: any = PropTypes.any, lowcodeType: string | object = {} return lowcodeCheckType; } -const LowcodeTypes: any = { +export const LowcodeTypes: any = { ...PropTypes, define, }; (window as any).PropTypes = LowcodeTypes; -(window as any).React.PropTypes = LowcodeTypes; +if ((window as any).React) { + (window as any).React.PropTypes = LowcodeTypes; +} // override primitive type checkers primitiveTypes.forEach((type) => { diff --git a/packages/renderer-core/babel.config.js b/packages/renderer-core/babel.config.js new file mode 100644 index 000000000..c5986f2bc --- /dev/null +++ b/packages/renderer-core/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 1ff91cb14..2bb3c0b36 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -4,6 +4,7 @@ import { isReactComponent, cloneEnumerableProperty } from '@alilc/lowcode-utils' import { debounce } from '../utils/common'; import adapter from '../adapter'; import * as types from '../types/index'; +import logger from '../utils/logger'; export interface IComponentHocInfo { schema: any; @@ -183,7 +184,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } if (!isReactComponent(Comp)) { - console.error(`${schema.componentName} component may be has errors: `, Comp); + logger.error(`${schema.componentName} component may be has errors: `, Comp); } initRerenderEvent({ diff --git a/packages/renderer-core/src/renderer/addon.tsx b/packages/renderer-core/src/renderer/addon.tsx index 9cb114bee..211ec182f 100644 --- a/packages/renderer-core/src/renderer/addon.tsx +++ b/packages/renderer-core/src/renderer/addon.tsx @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import baseRendererFactory from './base'; import { isEmpty } from '../utils'; import { IRendererAppHelper, IBaseRendererProps, IBaseRenderComponent } from '../types'; +import logger from '../utils/logger'; export default function addonRendererFactory(): IBaseRenderComponent { const BaseRenderer = baseRendererFactory(); @@ -32,7 +33,7 @@ export default function addonRendererFactory(): IBaseRenderComponent { const schema = props.__schema || {}; this.state = this.__parseData(schema.state || {}); if (isEmpty(props.config) || !props.config?.addonKey) { - console.warn('lce addon has wrong config'); + logger.warn('lce addon has wrong config'); this.setState({ __hasError: true, }); diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 1980734e4..6c2a04aa7 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -56,14 +56,14 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche } if (typeof fn !== 'function') { - console.error(`生命周期${method}类型不符`, fn); + logger.error(`生命周期${method}类型不符`, fn); return; } try { return fn.apply(context, args); } catch (e) { - console.error(`[${schema.componentName}]生命周期${method}出错`, e); + logger.error(`[${schema.componentName}]生命周期${method}出错`, e); } } @@ -208,7 +208,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { async componentDidCatch(...args: any[]) { this.__executeLifeCycleMethod('componentDidCatch', args); - console.warn(args); + logger.warn(args); } reloadDataSource = () => new Promise((resolve, reject) => { @@ -278,7 +278,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { value = this.__parseExpression(value, this); } if (typeof value !== 'function') { - console.error(`custom method ${key} can not be parsed to a valid function`, value); + logger.error(`custom method ${key} can not be parsed to a valid function`, value); return; } this[key] = value.bind(this); @@ -369,7 +369,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { this.setLocale = (loc: string) => { const setLocaleFn = this.appHelper?.utils?.i18n?.setLocale; if (!setLocaleFn || typeof setLocaleFn !== 'function') { - console.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists'); + logger.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists'); return undefined; } return setLocaleFn(loc); @@ -527,7 +527,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { : {}; if (!Comp) { - console.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components); + logger.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components); return engine.createElement( engine.getNotFoundComponent(), { @@ -749,7 +749,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __createLoopVirtualDom = (schema: IPublicTypeNodeSchema, scope: any, parentInfo: INodeInfo, idx: number | string) => { if (isFileSchema(schema)) { - console.warn('file type not support Loop'); + logger.warn('file type not support Loop'); return null; } if (!Array.isArray(schema.loop)) { diff --git a/packages/renderer-core/src/renderer/temp.tsx b/packages/renderer-core/src/renderer/temp.tsx index 83adef7e3..1432da5fd 100644 --- a/packages/renderer-core/src/renderer/temp.tsx +++ b/packages/renderer-core/src/renderer/temp.tsx @@ -1,4 +1,5 @@ import { IBaseRenderComponent } from '../types'; +import logger from '../utils/logger'; import baseRendererFactory from './base'; export default function tempRendererFactory(): IBaseRenderComponent { @@ -41,7 +42,7 @@ export default function tempRendererFactory(): IBaseRenderComponent { } async componentDidCatch(e: any) { - console.warn(e); + logger.warn(e); this.__debug(`componentDidCatch - ${this.props.__schema.fileName}`); } diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 29381b547..495744acd 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -183,13 +183,13 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) { return res; } -export function checkPropTypes(value: any, name: string, rule: any, componentName: string) { +export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { let ruleFunction = rule; if (typeof rule === 'string') { ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); } if (!ruleFunction || typeof ruleFunction !== 'function') { - console.warn('checkPropTypes should have a function type rule argument'); + logger.warn('checkPropTypes should have a function type rule argument'); return true; } const err = ruleFunction( @@ -203,7 +203,7 @@ export function checkPropTypes(value: any, name: string, rule: any, componentNam ReactPropTypesSecret, ); if (err) { - console.warn(err); + logger.warn(err); } return !err; } diff --git a/packages/renderer-core/src/utils/data-helper.ts b/packages/renderer-core/src/utils/data-helper.ts index d884c13c9..41bcb9bfa 100644 --- a/packages/renderer-core/src/utils/data-helper.ts +++ b/packages/renderer-core/src/utils/data-helper.ts @@ -186,7 +186,7 @@ export class DataHelper { } const { headers, ...otherProps } = otherOptionsObj || {}; if (!req) { - console.warn(`getDataSource API named ${id} not exist`); + logger.warn(`getDataSource API named ${id} not exist`); return; } @@ -215,7 +215,7 @@ export class DataHelper { try { callbackFn && callbackFn(res && res[id]); } catch (e) { - console.error('load请求回调函数报错', e); + logger.error('load请求回调函数报错', e); } return res && res[id]; }) @@ -223,7 +223,7 @@ export class DataHelper { try { callbackFn && callbackFn(null, err); } catch (e) { - console.error('load请求回调函数报错', e); + logger.error('load请求回调函数报错', e); } return err; }); @@ -300,9 +300,9 @@ export class DataHelper { return dataHandlerFun.call(this.host, data, error); } catch (e) { if (id) { - console.error(`[${id}]单个请求数据处理函数运行出错`, e); + logger.error(`[${id}]单个请求数据处理函数运行出错`, e); } else { - console.error('请求数据处理函数运行出错', e); + logger.error('请求数据处理函数运行出错', e); } } } diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 995e55642..2ee3ed4dc 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -1,4 +1,4 @@ -// @ts-nocheck +import factoryWithTypeCheckers from 'prop-types/factoryWithTypeCheckers'; import { isSchema, isFileSchema, @@ -18,9 +18,14 @@ import { parseThisRequiredExpression, parseI18n, parseData, + checkPropTypes, } from '../../src/utils/common'; import logger from '../../src/utils/logger'; +var ReactIs = require('react-is'); + +const PropTypes = factoryWithTypeCheckers(ReactIs.isElement, true); + describe('test isSchema', () => { it('should be false when empty value is passed', () => { expect(isSchema(null)).toBeFalsy(); @@ -461,4 +466,37 @@ describe('test parseData ', () => { expect(result.__privateKey).toBeUndefined(); }); +}); + +describe('checkPropTypes', () => { + it('should validate correctly with valid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); + expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true); + }); + + it('should log a warning and return false with invalid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false); + expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); + }); + + it('should handle custom rule functions correctly', () => { + const customRule = (props, propName) => { + if (props[propName] !== 123) { + return new Error('Invalid value'); + } + }; + const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent'); + expect(result).toBe(true); + }); + + + it('should interpret and validate a rule given as a string', () => { + const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent'); + expect(result).toBe(true); + }); + + it('should log a warning for invalid rule type', () => { + const result = checkPropTypes(123, 'age', 123, 'TestComponent'); + expect(result).toBe(true); + }); }); \ No newline at end of file diff --git a/packages/renderer-core/tests/utils/data-helper.test.ts b/packages/renderer-core/tests/utils/data-helper.test.ts index cd4508ea8..f4b388ce9 100644 --- a/packages/renderer-core/tests/utils/data-helper.test.ts +++ b/packages/renderer-core/tests/utils/data-helper.test.ts @@ -346,11 +346,6 @@ describe('test DataHelper ', () => { result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toStrictEqual({ data: 'mockDataValue' }); - // test exception - const mockError = jest.fn(); - const orginalConsole = global.console; - global.console = { error: mockError }; - // exception with id mockDataHandler = { type: 'JSFunction', @@ -358,7 +353,6 @@ describe('test DataHelper ', () => { }; result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toBeUndefined(); - expect(mockError).toBeCalledWith('[fullConfigGet]单个请求数据处理函数运行出错', expect.anything()); // exception without id mockDataHandler = { @@ -367,12 +361,8 @@ describe('test DataHelper ', () => { }; result = dataHelper.handleData(null, mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toBeUndefined(); - expect(mockError).toBeCalledWith('请求数据处理函数运行出错', expect.anything()); - - global.console = orginalConsole; }); - it('updateConfig should work', () => { const mockHost = { stateA: 'aValue'}; const mockDataSourceConfig = { From 944012ab3ff56bb9ec5781b1c9ecb0d14a165581 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 14 Nov 2023 11:46:13 +0800 Subject: [PATCH 09/61] test(designer): add test ut to sequencify --- packages/designer/jest.config.js | 1 + packages/designer/src/plugin/sequencify.ts | 58 ++++++-- .../designer/tests/plugin/sequencify.test.ts | 128 ++++++++++++++++++ 3 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 packages/designer/tests/plugin/sequencify.test.ts diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 1ecebd938..f0ad2e861 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -20,6 +20,7 @@ const jestConfig = { // testMatch: ['**/node.test.ts'], // testMatch: ['**/builtin-hotkey.test.ts'], // testMatch: ['**/selection.test.ts'], + // testMatch: ['**/plugin/sequencify.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/plugin/sequencify.ts b/packages/designer/src/plugin/sequencify.ts index a312df207..9084b0a0e 100644 --- a/packages/designer/src/plugin/sequencify.ts +++ b/packages/designer/src/plugin/sequencify.ts @@ -1,19 +1,50 @@ -function sequence(tasks, names, results, missing, recursive, nest) { +interface ITaks { + [key: string]: { + name: string; + dep: string[]; + }; +} + +export function sequence({ + tasks, + names, + results, + missing, + recursive, + nest, + parentName, +}: { + tasks: ITaks; + names: string[]; + results: string[]; + missing: string[]; + recursive: string[][]; + nest: string[]; + parentName: string; +}) { names.forEach((name) => { if (results.indexOf(name) !== -1) { return; // de-dup results } const node = tasks[name]; if (!node) { - missing.push(name); + missing.push([parentName, name].filter((d => !!d)).join('.')); } else if (nest.indexOf(name) > -1) { nest.push(name); recursive.push(nest.slice(0)); - nest.pop(name); + nest.pop(); } else if (node.dep.length) { nest.push(name); - sequence(tasks, node.dep, results, missing, recursive, nest); // recurse - nest.pop(name); + sequence({ + tasks, + parentName: name, + names: node.dep, + results, + missing, + recursive, + nest, + }); // recurse + nest.pop(); } results.push(name); }); @@ -21,12 +52,19 @@ function sequence(tasks, names, results, missing, recursive, nest) { // tasks: object with keys as task names // names: array of task names -export default function (tasks, names) { - let results = []; // the final sequence - const missing = []; // missing tasks - const recursive = []; // recursive task dependencies +export default function (tasks: ITaks, names: string[]) { + let results: string[] = []; // the final sequence + const missing: string[] = []; // missing tasks + const recursive: string[][] = []; // recursive task dependencies - sequence(tasks, names, results, missing, recursive, []); + sequence({ + tasks, + names, + results, + missing, + recursive, + nest: [], + }); if (missing.length || recursive.length) { results = []; // results are incomplete at best, completely wrong at worst, remove them to avoid confusion diff --git a/packages/designer/tests/plugin/sequencify.test.ts b/packages/designer/tests/plugin/sequencify.test.ts new file mode 100644 index 000000000..89140e279 --- /dev/null +++ b/packages/designer/tests/plugin/sequencify.test.ts @@ -0,0 +1,128 @@ +import sequencify, { sequence } from '../../src/plugin/sequencify'; + +describe('sequence', () => { + it('handles tasks with no dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: [] } + }; + const results = []; + const missing = []; + const recursive = []; + sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest: [] }); + + expect(results).toEqual(['task1', 'task2']); + expect(missing).toEqual([]); + expect(recursive).toEqual([]); + }); + + it('correctly orders tasks based on dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task1'] } + }; + const results = []; + const missing = []; + const recursive = []; + sequence({ tasks, names: ['task2', 'task1'], results, missing, recursive, nest: [] }); + + expect(results).toEqual(['task1', 'task2']); + expect(missing).toEqual([]); + expect(recursive).toEqual([]); + }); + + it('identifies missing tasks', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] } + }; + const results = []; + const missing = []; + const recursive = []; + const nest = [] + sequence({ tasks, names: ['task2'], results, missing, recursive, nest }); + + expect(results).toEqual(['task2']); + expect(missing).toEqual(['task2']); + expect(recursive).toEqual([]); + expect(nest).toEqual([]); + }); + + it('detects recursive dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: ['task2'] }, + task2: { name: 'Task 2', dep: ['task1'] } + }; + const results = []; + const missing = []; + const recursive = []; + const nest = [] + sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest }); + + expect(results).toEqual(['task1', 'task2', 'task1']); + expect(missing).toEqual([]); + expect(recursive).toEqual([['task1', 'task2', 'task1']]); + expect(nest).toEqual([]); + }); +}); + +describe('sequence', () => { + + it('should return tasks in sequence without dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: [] }, + task3: { name: 'Task 3', dep: [] } + }; + const names = ['task1', 'task2', 'task3']; + const expected = { + sequence: ['task1', 'task2', 'task3'], + missingTasks: [], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should handle tasks with dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task1'] }, + task3: { name: 'Task 3', dep: ['task2'] } + }; + const names = ['task3', 'task2', 'task1']; + const expected = { + sequence: ['task1', 'task2', 'task3'], + missingTasks: [], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should identify missing tasks', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task3'] } // task3 is missing + }; + const names = ['task1', 'task2']; + const expected = { + sequence: [], + missingTasks: ['task2.task3'], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should detect recursive dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: ['task2'] }, + task2: { name: 'Task 2', dep: ['task1'] } // Recursive dependency + }; + const names = ['task1', 'task2']; + const expected = { + sequence: [], + missingTasks: [], + recursiveDependencies: [['task1', 'task2', 'task1']] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + +}); \ No newline at end of file From 736cb0e96552c557aa3f2c6d290cc3c915fb8adb Mon Sep 17 00:00:00 2001 From: beautiful-boyyy Date: Wed, 15 Nov 2023 12:09:55 +0800 Subject: [PATCH 10/61] docs: update prepare.md --- docs/docs/participate/prepare.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md index c0e1d5880..acb0947f2 100644 --- a/docs/docs/participate/prepare.md +++ b/docs/docs/participate/prepare.md @@ -33,27 +33,27 @@ npm install && npm start "proxy": [ [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/js/engine-core.js" + "http://localhost:5555/js/AliLowCodeEngine.js" ], [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", - "http://localhost:5555/css/engine-core.css" + "http://localhost:5555/css/AliLowCodeEngine.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", - "http://localhost:5555/js/react-simulator-renderer.js" + "http://localhost:5555/js/ReactSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", - "http://localhost:5555/css/react-simulator-renderer.css" + "http://localhost:5555/css/ReactSimulatorRenderer.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/rax-simulator-renderer.js" + "http://localhost:5555/js/RaxSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/rax-simulator-renderer.css" + "http://localhost:5555/css/RaxSimulatorRenderer.css" ], ] } From 6cba4bcc206c148ec87aa2aed5ffd382ae3fe438 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy Date: Wed, 15 Nov 2023 12:09:55 +0800 Subject: [PATCH 11/61] docs: update prepare.md --- docs/docs/participate/prepare.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md index c0e1d5880..acb0947f2 100644 --- a/docs/docs/participate/prepare.md +++ b/docs/docs/participate/prepare.md @@ -33,27 +33,27 @@ npm install && npm start "proxy": [ [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/js/engine-core.js" + "http://localhost:5555/js/AliLowCodeEngine.js" ], [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", - "http://localhost:5555/css/engine-core.css" + "http://localhost:5555/css/AliLowCodeEngine.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", - "http://localhost:5555/js/react-simulator-renderer.js" + "http://localhost:5555/js/ReactSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", - "http://localhost:5555/css/react-simulator-renderer.css" + "http://localhost:5555/css/ReactSimulatorRenderer.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/rax-simulator-renderer.js" + "http://localhost:5555/js/RaxSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/rax-simulator-renderer.css" + "http://localhost:5555/css/RaxSimulatorRenderer.css" ], ] } From e7884fdb5a9b448aa92ca3e897def4c05bc8caa6 Mon Sep 17 00:00:00 2001 From: Super-Rz <41566502+Super-Rz@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:23:07 +0800 Subject: [PATCH 12/61] fix: createIcon props (#2629) * fix: createIcon props * fix: createIcon props --- .../src/builtin-simulator/bem-tools/border-selecting.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0e9d734b6..4f452727d 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -143,7 +143,7 @@ function createAction(content: ReactNode | ComponentType | IPublicTypeActio }); }} > - {icon && createIcon(icon)} + {icon && createIcon(icon, { key, node: node.internalToShellNode() })} {title} ); From 058e184b21b15bcf512d796aea825b69756db537 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy Date: Wed, 15 Nov 2023 15:18:18 +0800 Subject: [PATCH 13/61] fix: fixed string trim issue --- packages/renderer-core/src/renderer/base.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 6c2a04aa7..ac4b1de12 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -901,9 +901,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); return checkProps(res); } - if (typeof props === 'string') { - return checkProps(props.trim()); - } return checkProps(props); }; From 8898f1c4a7bb9766a0ce78632501b98942070ab4 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 15 Nov 2023 15:23:03 +0800 Subject: [PATCH 14/61] fix: fix engine-core classes is undefined --- packages/engine/src/engine-core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 204b9b30a..2b59ba1b6 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -54,7 +54,7 @@ import { } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; -import classes from './modules/classes'; +import * as classes from './modules/classes'; import symbols from './modules/symbols'; import { componentMetaParser } from './inner-plugins/component-meta-parser'; import { setterRegistry } from './inner-plugins/setter-registry'; From 0f8bc8228236439775a0429c488308ba32ab7a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 20 Nov 2023 16:04:26 +0800 Subject: [PATCH 15/61] Update index.md --- docs/docs/article/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index e62f8f9d8..2de0b059e 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -6,6 +6,7 @@ - [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q) - [2022/11/24 低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409) - [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ) +- [基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) - [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA) - [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig) - [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) From 8208dd3a324081eeed3718d0924a397142c0c950 Mon Sep 17 00:00:00 2001 From: AprChell Date: Mon, 20 Nov 2023 16:24:27 +0800 Subject: [PATCH 16/61] fix(exportschema): exportSchema(IPublicEnumTransformStage.Save) type conver (#2661) * fix(exportschema): exportSchema(IPublicEnumTransformStage.Save) type conver * test(prop): nullProp equals null, not --- .../designer/src/document/node/props/prop.ts | 4 ---- .../tests/document/node/props/prop.test.ts | 2 +- packages/designer/tests/fixtures/schema/form.ts | 16 ++++++++-------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 01b2dc26b..e2d9f12e8 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -290,10 +290,6 @@ export class Prop implements IProp, IPropParent { } if (type === 'literal' || type === 'expression') { - // TODO 后端改造之后删除此逻辑 - if (this._value === null && stage === IPublicEnumTransformStage.Save) { - return ''; - } return this._value; } diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 58c24a4ea..4424eb601 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -136,7 +136,7 @@ describe('Prop 类测试', () => { expect(boolProp.export(IPublicEnumTransformStage.Save)).toBe(true); expect(strProp.export(IPublicEnumTransformStage.Save)).toBe('haha'); expect(numProp.export(IPublicEnumTransformStage.Save)).toBe(1); - expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(''); + expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(null); expect(nullProp.export(IPublicEnumTransformStage.Serilize)).toBe(null); expect(expProp.export(IPublicEnumTransformStage.Save)).toEqual({ type: 'JSExpression', diff --git a/packages/designer/tests/fixtures/schema/form.ts b/packages/designer/tests/fixtures/schema/form.ts index 8da6faf9e..e8479629f 100644 --- a/packages/designer/tests/fixtures/schema/form.ts +++ b/packages/designer/tests/fixtures/schema/form.ts @@ -267,7 +267,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -337,7 +337,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -407,7 +407,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -489,7 +489,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -578,7 +578,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, searchDelay: 300, @@ -697,7 +697,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -789,7 +789,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -871,7 +871,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, From 3c4bd1d2d0321453b3a1fa5253b0340c3dde8afc Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 20 Nov 2023 16:45:11 +0800 Subject: [PATCH 17/61] chore(docs): publish docs 1.1.17 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c206cdf16..81703741a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.16", + "version": "1.1.17", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 396e99aa11d442f1ace9ff138b2d4698ef57d9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 20 Nov 2023 17:00:36 +0800 Subject: [PATCH 18/61] docs: update index.md --- docs/docs/article/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 2de0b059e..c223137b2 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -6,7 +6,7 @@ - [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q) - [2022/11/24 低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409) - [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ) -- [基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) +- [2022/08/23 基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) - [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA) - [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig) - [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) From bf50071cc8ca2c06b70f03c16347fc85533bd8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 20 Nov 2023 17:03:11 +0800 Subject: [PATCH 19/61] docs: update index.md --- docs/docs/video/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 9f348e4e6..2f8a5f49c 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -1,4 +1,5 @@ # 官方视频 +- [2023/11/17 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Qw411H7DH) - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 From d47df9dc441cfc5f0a3490e2243e90473e3469e1 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 20 Nov 2023 17:33:53 +0800 Subject: [PATCH 20/61] style: add --workspace-left-area-width --- docs/docs/guide/expand/editor/theme.md | 1 + packages/editor-skeleton/src/layouts/workbench.less | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index b62fb4f28..94e434580 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -72,6 +72,7 @@ sidebar_position: 9 - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding +- `--workspace-left-area-width`: 应用级 leftArea width ### 生态使用主题色变量 diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 6d0604a1f..eb86bfe04 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -13,6 +13,7 @@ --popup-border-radius: @popup-border-radius; --left-area-width: 48px; + --workspace-left-area-width: 48px; --right-area-width: 300px; --top-area-height: 48px; --toolbar-height: 36px; @@ -273,7 +274,7 @@ body { } .lc-left-area, .lc-workspace-left-area { height: 100%; - width: var(--left-area-width); + width: var(--workspace-left-area-width, --left-area-width); display: none; flex-shrink: 0; flex-direction: column; From 322313ceada4bf3d2011a0032f0be598c73ebeab Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 20 Nov 2023 18:14:15 +0800 Subject: [PATCH 21/61] docs: update faq list --- docs/docs/faq/index.md | 43 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/docs/faq/index.md b/docs/docs/faq/index.md index ed31bad28..5e5eee8ac 100644 --- a/docs/docs/faq/index.md +++ b/docs/docs/faq/index.md @@ -1,7 +1,46 @@ --- title: FAQ 概述 -sidebar_position: 1 +sidebar_position: -1 tags: [FAQ] --- -不定期将社区常见问题及答案维护到此处 \ No newline at end of file +不定期将社区常见问题及答案维护到此处 + +## Demo 使用 +- [渲染唯一标识(key)](/site/docs/faq/faq002) +- [点击事件如何添加参数](/site/docs/faq/faq003) +- [如何通过 API 手动调用数据源请求](/site/docs/faq/faq006) + +## 设计器定制 +- [如何通过 this.utils 使用第三方工具扩展](/site/docs/faq/faq005) +- [设置面板中的高级 tab 如何配置](/site/docs/faq/faq007) +- [插件面板如何调整位置](/site/docs/faq/faq010) + +## 源码和依赖 +- [某某 npm 包对应的源码在哪里?](/site/docs/faq/faq008) + +## 错误和报错 +- [物料出现 Component Not Found 相关报错](/site/docs/faq/faq009) +- [VERSION_PLACEHOLDER is not defined](/site/docs/faq/faq014) +- [Cannot read property 'Icon' of Undefined](/site/docs/faq/faq016) +- [windows 下运行低代码引擎源码出现报错](/site/docs/faq/faq019) +- [Can't import the named export from non ECMAScript module](/site/docs/faq/faq020) +- [Slot组件渲染报错问题](/site/docs/faq/faq023) + +## 物料相关问题 +- [如何获取物料当前处于编辑态还是渲染态](/site/docs/faq/faq011) +- [Procode 物料如何调用数据源方法](/site/docs/faq/faq012) +- [已有组件如何快速接入引擎](/site/docs/faq/faq015) +- [Modal 类组件 hidden 属性被强制设置 true](/site/docs/faq/faq013) +- [最小渲染单元配置](/site/docs/faq/faq004) +- [节点无法拖拽到 Page 下](/site/docs/faq/faq022) + +## 其他说明 +- [vue 画布支持说明](/site/docs/faq/faq017) +- [是否可以生成 Vue 页面代码?](/site/docs/faq/faq018) + +## 参与贡献 +- [提交 PR 时,明明签署过 CLA,仍被提示需要签署](/site/docs/faq/faq021) + +## 相关依赖文档 +- [build-scripts 的使用文档](/site/docs/faq/faq001) From e35c672a50dc877f5768c1092e330bfb0424cfe2 Mon Sep 17 00:00:00 2001 From: "chenkeyao.chenkeya" Date: Mon, 20 Nov 2023 21:02:05 +0800 Subject: [PATCH 22/61] feat: add new video --- docs/docs/video/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 2f8a5f49c..8ae21620b 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -1,5 +1,5 @@ # 官方视频 -- [2023/11/17 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Qw411H7DH) +- [2023/11/20 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Ku4y1w7Zr) - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 From 7c72261fef0324cb57fd3e42331ede0f5b680573 Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 21 Nov 2023 10:28:27 +0800 Subject: [PATCH 23/61] chore(docs): publish docs 1.2.0 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 81703741a..cb3cb946d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.17", + "version": "1.2.0", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 394b56d0cef70101709802fb6ab1fda8f0ec2e3a Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Wed, 22 Nov 2023 19:50:22 +0800 Subject: [PATCH 24/61] fix: recover component lifecycle and avoid execute from scope __proto__ --- packages/renderer-core/src/renderer/base.tsx | 5 +++++ .../renderer-core/src/renderer/component.tsx | 21 ------------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index ac4b1de12..dddc55e83 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -50,6 +50,11 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche return; } + // avoid execute lifeCycle method from __proto__'s method (it is React class Component Class lifeCycle) + if (!Object.prototype.hasOwnProperty.call(context, method) && method !== 'constructor') { + return; + } + // TODO: cache if (isJSExpression(fn) || isJSFunction(fn)) { fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context); diff --git a/packages/renderer-core/src/renderer/component.tsx b/packages/renderer-core/src/renderer/component.tsx index f9f6e8f96..3dfc1df33 100644 --- a/packages/renderer-core/src/renderer/component.tsx +++ b/packages/renderer-core/src/renderer/component.tsx @@ -46,26 +46,5 @@ export default function componentRendererFactory(): IBaseRenderComponent { return this.__renderComp(Component, this.__renderContextProvider({ compContext: this })); } - - getComponentName() { - return this.props?.componentName; - } - - /** 需要重载下面几个方法,如果在低代码组件中绑定了对应的生命周期时会出现死循环 */ - componentDidMount() { - this.__debug(`componentDidMount - ${this.getComponentName()}`); - } - getSnapshotBeforeUpdate() { - this.__debug(`getSnapshotBeforeUpdate - ${this.getComponentName()}`); - } - componentDidUpdate() { - this.__debug(`componentDidUpdate - ${this.getComponentName()}`); - } - componentWillUnmount() { - this.__debug(`componentWillUnmount - ${this.getComponentName()}`); - } - componentDidCatch() { - this.__debug(`componentDidCatch - ${this.getComponentName()}`); - } }; } From 27e914cecee34a886680db3f2bc0c69f2b62c726 Mon Sep 17 00:00:00 2001 From: andylili21 <101868030+andylili21@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:05:07 +0800 Subject: [PATCH 25/61] fix: Improve code and simplify logic (#2651) * fix: Improve code and simplify logic --- packages/designer/src/document/node/node.ts | 18 +++--- .../designer/tests/document/node/node.test.ts | 61 +++++++++++++++++-- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 9effc341d..145a5a85e 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -440,23 +440,23 @@ export class Node } private initialChildren(children: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined): IPublicTypeNodeData[] { - // FIXME! this is dirty code + const { initialChildren } = this.componentMeta.advanced; + if (children == null) { - const { initialChildren } = this.componentMeta.advanced; if (initialChildren) { if (typeof initialChildren === 'function') { return initialChildren(this.internalToShellNode()!) || []; } return initialChildren; } - } - if (Array.isArray(children)) { - return children; - } else if (children) { - return [children]; - } else { return []; } + + if (Array.isArray(children)) { + return children; + } + + return [children]; } isContainer(): boolean { @@ -1094,7 +1094,7 @@ export class Node } /** - * 是否可执行某action + * 是否可执行某 action */ canPerformAction(actionName: string): boolean { const availableActions = diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts index c4717b3a0..2695d6c83 100644 --- a/packages/designer/tests/document/node/node.test.ts +++ b/packages/designer/tests/document/node/node.test.ts @@ -54,7 +54,60 @@ describe('Node 方法测试', () => { project = null; }); - it('condition group', () => {}); + // Case 1: When children is null + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const result = node.initialChildren(null); + // 预期结果是一个空数组 + expect(result).toEqual([]); + }); + + // Case 2: When children is undefined + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const result = node.initialChildren(undefined); + // 预期结果是一个空数组 + expect(result).toEqual([]); + }); + + // Case 3: When children is array + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childrenArray = [{ id: 1, name: 'Child 1' }, { id: 2, name: 'Child 2' }]; + const result = node.initialChildren(childrenArray); + // 预期结果是一个数组 + expect(result).toEqual(childrenArray); + }); + + // Case 4: When children is not null and not an array + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = { id: 1, name: 'Child 1' }; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([childObject]); + }); + + // Case 5: When children 0 + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = 0; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([0]); + }); + + // Case 6: When children false + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = false; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([false]); + }); + + + it('condition group', () => { }); it('getExtraProp / setExtraProp', () => { const firstBtn = doc.getNode('node_k1ow3cbn')!; @@ -367,7 +420,7 @@ describe('Node 方法测试', () => { expect(mockFn).not.toHaveBeenCalled(); }); - it('addSlot / unlinkSlot / removeSlot', () => {}); + it('addSlot / unlinkSlot / removeSlot', () => { }); it('setProps', () => { const firstBtn = doc.getNode('node_k1ow3cbn')!; @@ -407,7 +460,7 @@ describe('Node 方法测试', () => { designer.createComponentMeta(btnMetadata); const btn = doc.getNode('node_k1ow3cbn'); // 从 componentMeta 中获取到 title 值 - expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' } ); + expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' }); // 从 extraProp 中获取值 btn.setExtraProp('title', 'hello button'); expect(btn.title).toBe('hello button'); @@ -546,7 +599,7 @@ describe('Node 方法测试', () => { expect(comparePosition(firstBtn, firstCard)).toBe(PositionNO.BeforeOrAfter); }); - it('getZLevelTop', () => {}); + it('getZLevelTop', () => { }); it('propsData', () => { expect(new Node(doc, { componentName: 'Leaf' }).propsData).toBeNull(); expect(new Node(doc, { componentName: 'Fragment' }).propsData).toBeNull(); From ad044f49ed9064fe1afa5195f68759a76bda5f5e Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 23 Nov 2023 11:01:50 +0800 Subject: [PATCH 26/61] feat(utils): add workspace utils --- packages/designer/src/plugin/plugin-types.ts | 1 + packages/engine/src/engine-core.ts | 1 + .../types/src/shell/model/plugin-context.ts | 2 + packages/utils/src/index.ts | 1 + packages/utils/src/workspace.tsx | 54 +++++++++++++++++++ .../workspace/src/context/base-context.ts | 1 + 6 files changed, 60 insertions(+) create mode 100644 packages/utils/src/workspace.tsx diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index ac08d7d0c..6091170f0 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -60,6 +60,7 @@ export interface ILowCodePluginContextPrivate { set workspace(workspace: IPublicApiWorkspace); set editorWindow(window: IPublicModelWindow); set registerLevel(level: IPublicEnumPluginRegisterLevel); + set isPluginRegisteredInWorkspace(flag: boolean); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 2b59ba1b6..3ac4c32a7 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -139,6 +139,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; context.registerLevel = IPublicEnumPluginRegisterLevel.Default; + context.isPluginRegisteredInWorkspace = false; }, }; diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 1f3d3b5e8..35e7e38af 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -108,6 +108,8 @@ export interface IPublicModelPluginContext { */ get registerLevel(): IPublicEnumPluginRegisterLevel; + get isPluginRegisteredInWorkspace(): boolean; + get editorWindow(): IPublicModelWindow; } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index e3f70ff80..3e37f46ba 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -30,3 +30,4 @@ export * from './is-plugin-event-name'; export * as css from './css-helper'; export { transactionManager } from './transaction-manager'; export * from './check-types'; +export * from './workspace'; diff --git a/packages/utils/src/workspace.tsx b/packages/utils/src/workspace.tsx new file mode 100644 index 000000000..446530ce8 --- /dev/null +++ b/packages/utils/src/workspace.tsx @@ -0,0 +1,54 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { IPublicModelPluginContext, IPublicEnumPluginRegisterLevel, IPublicModelWindow, IPublicModelEditorView } from '@alilc/lowcode-types'; + +/** + * 高阶组件(HOC):为组件提供 view 插件上下文。 + * + * @param {React.ComponentType} Component - 需要被封装的组件。 + * @param {string|string[]} viewName - 视图名称或视图名称数组,用于过滤特定的视图插件上下文。 + * @returns {React.ComponentType} 返回封装后的组件。 + * + * @example + * // 用法示例(函数组件): + * const EnhancedComponent = ProvideViewPluginContext(MyComponent, "viewName"); + */ +export const ProvideViewPluginContext = (Component: any, viewName?: string | string[]) => { + // 创建一个新的函数组件,以便在其中使用 Hooks + return function WithPluginContext(props: { + [key: string]: any; + + pluginContext?: IPublicModelPluginContext; + }) { + const getPluginContextFun = useCallback((editorWindow?: IPublicModelWindow | null) => { + if (!editorWindow?.currentEditorView) { + return null; + } + if (viewName) { + const items = editorWindow?.editorViews.filter(d => (d as any).viewName === viewName || (Array.isArray(viewName) && viewName.includes((d as any).viewName))); + return items[0]; + } else { + return editorWindow.currentEditorView; + } + }, []); + + const { workspace } = props.pluginContext || {}; + const [pluginContext, setPluginContext] = useState(getPluginContextFun(workspace?.window)); + + useEffect(() => { + if (workspace?.window) { + const ctx = getPluginContextFun(workspace.window); + ctx && setPluginContext(ctx); + } + return workspace?.onChangeActiveEditorView(() => { + const ctx = getPluginContextFun(workspace.window); + ctx && setPluginContext(ctx); + }); + }, [workspace, getPluginContextFun]); + + if (props.pluginContext?.registerLevel !== IPublicEnumPluginRegisterLevel.Workspace || !props.pluginContext) { + return ; + } + + return ; + }; +}; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index b359a6139..78f32079f 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -170,6 +170,7 @@ export class BasicContext implements IBasicContext { context.editorWindow = new Window(editorWindow); } context.registerLevel = registerLevel; + context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace; }, }; From 029fd1ce67739e85dd669c61ebfedf52199c2d11 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 23 Nov 2023 11:23:34 +0800 Subject: [PATCH 27/61] feat(outline-pane): suport registry in workspace level --- .../src/controllers/tree-master.ts | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index 40162d808..ede5f0f5f 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -41,22 +41,19 @@ export class TreeMaster { this.initEvent(); if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) { this.setPluginContext(workspace.window?.currentEditorView); - workspace.onWindowRendererReady(() => { - this.setPluginContext(workspace.window?.currentEditorView); - let dispose: IPublicTypeDisposable | undefined; - const windowViewTypeChangeEvent = () => { - dispose = workspace.window?.onChangeViewType(() => { - this.setPluginContext(workspace.window?.currentEditorView); - }); - }; - - windowViewTypeChangeEvent(); - - workspace.onChangeActiveWindow(() => { - windowViewTypeChangeEvent(); + let dispose: IPublicTypeDisposable | undefined; + const windowViewTypeChangeEvent = () => { + dispose = workspace.window?.onChangeViewType(() => { this.setPluginContext(workspace.window?.currentEditorView); - dispose && dispose(); }); + }; + + windowViewTypeChangeEvent(); + + workspace.onChangeActiveWindow(() => { + windowViewTypeChangeEvent(); + this.setPluginContext(workspace.window?.currentEditorView); + dispose && dispose(); }); } } From a3fef9c13d39ac1b35b200cf0f711cf7c7c233d8 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 23 Nov 2023 15:32:54 +0800 Subject: [PATCH 28/61] feat(skeleton): add registerConfigTransducer API --- docs/docs/api/skeleton.md | 62 +++++++++++++++++++ packages/editor-skeleton/src/skeleton.ts | 31 +++++++++- packages/shell/src/api/skeleton.ts | 6 +- packages/types/src/shell/api/skeleton.ts | 19 +++++- .../types/src/shell/type/config-transducer.ts | 9 +++ packages/types/src/shell/type/index.ts | 1 + 6 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 packages/types/src/shell/type/config-transducer.ts diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index c378792de..90cf1a2c1 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -295,6 +295,68 @@ showArea(areaName: string): void; */ hideArea(areaName: string): void; ``` + +### registerConfigTransducer +注册一个面板的配置转换器(transducer)。 + +```typescript +/** + * 注册一个面板的配置转换器(transducer)。 + * Registers a configuration transducer for a panel. + * @param {IPublicTypeConfigTransducer} transducer + * - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。 + * - The transducer function to be registered. This function takes a configuration object + * + * @param {number} level + * - 转换器的优先级。优先级较高的转换器会先执行。 + * - The priority level of the transducer. Transducers with higher priority levels are executed first. + * + * @param {string} [id] + * - (可选)转换器的唯一标识符。用于在需要时引用或操作特定的转换器。 + * - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed. + */ +registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void; +``` + +使用示例 + +```typescript +import { IPublicModelPluginContext, IPublicTypeSkeletonConfig } from '@alilc/lowcode-types'; + +function updatePanelWidth(config: IPublicTypeSkeletonConfig) { + if (config.type === 'PanelDock') { + return { + ...config, + panelProps: { + ...(config.panelProps || {}), + width: 240, + }, + } + } + + return config; +} + +const controlPanelWidthPlugin = (ctx: IPublicModelPluginContext) => { + const { skeleton } = ctx; + (skeleton as any).registerConfigTransducer?.(updatePanelWidth, 1, 'update-panel-width'); + + return { + init() {}, + }; +}; + +controlPanelWidthPlugin.pluginName = 'controlPanelWidthPlugin'; +controlPanelWidthPlugin.meta = { + dependencies: [], + engines: { + lowcodeEngine: '^1.2.3', // 插件需要配合 ^1.0.0 的引擎才可运行 + }, +}; + +export default controlPanelWidthPlugin; +``` + ## 事件 ### onShowPanel diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 89bffc4cf..13967e94d 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -28,6 +28,7 @@ import { IPublicTypeWidgetConfigArea, IPublicTypeSkeletonConfig, IPublicApiSkeleton, + IPublicTypeConfigTransducer, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -111,6 +112,8 @@ export interface ISkeleton extends Omit(); + private configTransducers: IPublicTypeConfigTransducer[] = []; + private containers = new Map>(); readonly leftArea: Area; @@ -448,11 +451,35 @@ export class Skeleton implements ISkeleton { return restConfig; } + registerConfigTransducer( + transducer: IPublicTypeConfigTransducer, + level = 100, + id?: string, + ) { + transducer.level = level; + transducer.id = id; + const i = this.configTransducers.findIndex((item) => item.level != null && item.level > level); + if (i < 0) { + this.configTransducers.push(transducer); + } else { + this.configTransducers.splice(i, 0, transducer); + } + } + + getRegisteredConfigTransducers(): IPublicTypeConfigTransducer[] { + return this.configTransducers; + } + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined { - const parsedConfig = { + const registeredTransducers = this.getRegisteredConfigTransducers(); + + const parsedConfig = registeredTransducers.reduce((prevConfig, current) => { + return current(prevConfig); + }, { ...this.parseConfig(config), ...extraConfig, - }; + }); + let { area } = parsedConfig; if (!area) { if (parsedConfig.type === 'Panel') { diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 0d1707525..07a1727dd 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -4,7 +4,7 @@ import { SkeletonEvents, } from '@alilc/lowcode-editor-skeleton'; import { skeletonSymbol } from '../symbols'; -import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; +import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; import { getLogger } from '@alilc/lowcode-utils'; import { SkeletonItem } from '../model/skeleton-item'; @@ -208,6 +208,10 @@ export class Skeleton implements IPublicApiSkeleton { }); return () => editor.eventBus.off(SkeletonEvents.WIDGET_HIDE, listener); } + + registerConfigTransducer(fn: IPublicTypeConfigTransducer, level: number, id?: string) { + this[skeletonSymbol].registerConfigTransducer(fn, level, id); + } } function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' | 'subTopArea' { diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 2ad561518..9a36aa469 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,5 +1,5 @@ import { IPublicModelSkeletonItem } from '../model'; -import { IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; +import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; export interface IPublicApiSkeleton { @@ -114,4 +114,21 @@ export interface IPublicApiSkeleton { * @returns */ onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; + + /** + * 注册一个面板的配置转换器(transducer)。 + * Registers a configuration transducer for a panel. + * @param {IPublicTypeConfigTransducer} transducer + * - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。 + * - The transducer function to be registered. This function takes a configuration object (of type IPublicTypeSkeletonConfig) as input and returns a modified configuration object. + * + * @param {number} level + * - 转换器的优先级。优先级较高的转换器会先执行。 + * - The priority level of the transducer. Transducers with higher priority levels are executed first. + * + * @param {string} [id] + * - (可选)转换器的唯一标识符。用于在需要时引用或操作特定的转换器。 + * - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed. + */ + registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void; } diff --git a/packages/types/src/shell/type/config-transducer.ts b/packages/types/src/shell/type/config-transducer.ts new file mode 100644 index 000000000..64c33a5c4 --- /dev/null +++ b/packages/types/src/shell/type/config-transducer.ts @@ -0,0 +1,9 @@ +import { IPublicTypeSkeletonConfig } from '.'; + +export interface IPublicTypeConfigTransducer { + (prev: IPublicTypeSkeletonConfig): IPublicTypeSkeletonConfig; + + level?: number; + + id?: string; +} diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index 7232ffbbd..b2fd3313f 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -91,3 +91,4 @@ export * from './hotkey-callback-config'; export * from './hotkey-callbacks'; export * from './scrollable'; export * from './simulator-renderer'; +export * from './config-transducer'; \ No newline at end of file From 7e80d1f863f934720915df35db3b27415a11ebb7 Mon Sep 17 00:00:00 2001 From: JackLian Date: Thu, 23 Nov 2023 16:33:45 +0800 Subject: [PATCH 29/61] chore(docs): publish docs 1.2.1 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index cb3cb946d..14d0c99e5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.0", + "version": "1.2.1", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From dc1e0f5a49a81b3fb8c47b4a1495d06e16798fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 18:58:24 +0800 Subject: [PATCH 30/61] Fix/component lifecycle not execute (#2690) * fix: recover component lifecycle and avoid execute from scope __proto__ From 6c7a52652131b0a18a03bf6f90b8730544b8be34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:28:41 +0800 Subject: [PATCH 31/61] Fix/component lifecycle not execute (#2692) * fix: recover component lifecycle and avoid execute from scope __proto__ From c643c0fc4f4c9eb90b8d273447fef04d28cfe13d Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:35:37 +0800 Subject: [PATCH 32/61] fix(renderer-core): remove compatibility with uipaas --- packages/renderer-core/src/renderer/base.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index dddc55e83..ac4b1de12 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -50,11 +50,6 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche return; } - // avoid execute lifeCycle method from __proto__'s method (it is React class Component Class lifeCycle) - if (!Object.prototype.hasOwnProperty.call(context, method) && method !== 'constructor') { - return; - } - // TODO: cache if (isJSExpression(fn) || isJSFunction(fn)) { fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context); From 1c2f195e8bce05284419eb7bbbba33bb97acf30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 27 Nov 2023 16:22:29 +0800 Subject: [PATCH 33/61] docs: update skeleton.md --- docs/docs/api/skeleton.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 90cf1a2c1..5bfa23972 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -69,6 +69,7 @@ skeleton.add({ props: { align: "left", icon: "wenjian", + title: '标题', // 图标下方展示的标题 description: "JS 面板", }, panelProps: { From 20bf62aed3c67753c265c38dffaa5e5a31c2b4ee Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 27 Nov 2023 17:50:48 +0800 Subject: [PATCH 34/61] chore(docs): publish docs 1.2.2 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 14d0c99e5..e9d5b87b4 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.1", + "version": "1.2.2", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From d41f2c13d24a0270616ae4d2d2484e347ca02573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 27 Nov 2023 21:40:25 +0800 Subject: [PATCH 35/61] docs: update material.md --- docs/docs/api/material.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 8b1214476..51ed4e305 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -116,6 +116,21 @@ material.setAssets(assets1); material.loadIncrementalAssets(assets2); ``` +更新特定物料的描述文件 + +```typescript +import { material } from '@alilc/lowcode-engine'; +material.loadIncrementalAssets({ + version: '', + components: [ + { + "componentName": 'Button', + "props": [{ name: 'new', title: 'new', propType: 'string' }] + } + ], +}) +``` + ### 设计器辅助层 #### addBuiltinComponentAction 在设计器辅助层增加一个扩展 action From f75b9ae61cdc46618038b3fe43e6744aa8d56f5c Mon Sep 17 00:00:00 2001 From: owenchen1004 Date: Tue, 28 Nov 2023 10:50:38 +0800 Subject: [PATCH 36/61] fix: executeLifeCycleMethod return bug in renderer --- packages/renderer-core/src/renderer/base.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 1980734e4..640763538 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -182,7 +182,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE) || null; } async getSnapshotBeforeUpdate(...args: any[]) { From b786c8fcaad1376d1d4d1316f75e283418f93913 Mon Sep 17 00:00:00 2001 From: owenchen1004 Date: Tue, 28 Nov 2023 11:04:37 +0800 Subject: [PATCH 37/61] fix: coding style update --- packages/renderer-core/src/renderer/base.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 640763538..ebaa8eadc 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -182,7 +182,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE) || null; + const result = executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return result === undefined ? null : result; } async getSnapshotBeforeUpdate(...args: any[]) { From d199b44eca0b1fe47d1744421a275188f69533e1 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 28 Nov 2023 16:11:04 +0800 Subject: [PATCH 38/61] style: add --color-toolbar-background --- docs/docs/guide/expand/editor/theme.md | 73 +++++++++++++++---- .../src/layouts/workbench.less | 2 +- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 94e434580..16bcf04b0 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -3,23 +3,46 @@ title: 主题色扩展 sidebar_position: 9 --- -## 主题色扩展简述 +## 简介 -通过主题色扩展,可以定制多种设计器主题。 +主题色扩展允许用户定制多样的设计器主题,增加界面的个性化和品牌识别度。 -## 主题色扩展说明 +## 设计器主题色定制 + +在 CSS 的根级别定义主题色变量可以确保这些变量在整个应用中都可用。例如: + +```css +:root { + --color-brand: rgba(0, 108, 255, 1); /* 主品牌色 */ + --color-brand-light: rgba(25, 122, 255, 1); /* 浅色品牌色 */ + --color-brand-dark: rgba(0, 96, 229, 1); /* 深色品牌色 */ +} + +``` + +将样式文件引入到你的设计器中,定义的 CSS 变量就可以改变设计器的主题色了。 ### 主题色变量 -- `--color-brand`: 品牌色 -- `--color-brand-light`: 品牌色(light) -- `--color-brand-dark`: 品牌色(dark) -- `--color-icon-normal`: 正常 icon 颜色 -- `--color-icon-hover`: icon hover 态颜色 -- `--color-icon-active`: icon active 态颜色 -- `--color-icon-reverse`: icon 反色 -- `--color-icon-disabled`: icon 禁用态颜色 -- `--color-icon-pane`: icon 面板颜色 +以下是低代码引擎设计器支持的主题色变量列表,以及它们的用途说明: + +#### 品牌相关颜色 + +- `--color-brand`: 主品牌色 +- `--color-brand-light`: 浅色品牌色 +- `--color-brand-dark`: 深色品牌色 + +#### Icon 相关颜色 + +- `--color-icon-normal`: 默认状态 +- `--color-icon-hover`: 鼠标悬停状态 +- `--color-icon-active`: 激活状态 +- `--color-icon-reverse`: 反色状态 +- `--color-icon-disabled`: 禁用状态 +- `--color-icon-pane`: 面板颜色 + +#### 线条和文本颜色 + - `--color-line-normal`: 线条颜色 - `--color-line-darken`: 线条颜色(darken) - `--color-title`: 标题颜色 @@ -29,6 +52,9 @@ sidebar_position: 9 - `--color-text-reverse`: 反色情况下,文字颜色 - `--color-text-regular`: 文字颜色(regular) - `--color-text-disabled`: 禁用态文字颜色 + +#### 字段和边框颜色 + - `--color-field-label`: field 标签颜色 - `--color-field-text`: field 文本颜色 - `--color-field-placeholder`: field placeholder 颜色 @@ -36,6 +62,9 @@ sidebar_position: 9 - `--color-field-border-hover`: hover 态下,field 边框颜色 - `--color-field-border-active`: active 态下,field 边框颜色 - `--color-field-background`: field 背景色 + +#### 状态颜色 + - `--color-success`: success 颜色 - `--colo-success-dark`: success 颜色(dark) - `--color-success-light`: success 颜色(light) @@ -50,7 +79,9 @@ sidebar_position: 9 - `--color-error-light`: error 颜色(light) - `--color-purple`: purple 颜色 - `--color-brown`: brown 颜色 -- `--color-pane-background`: 面板背景色 + +#### 区块背景色 + - `--color-block-background-normal`: 区块背景色 - `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 - `--color-block-background-shallow`: 区块背景色 shallow @@ -61,20 +92,30 @@ sidebar_position: 9 - `--color-block-background-error`: 区块背景色(error) - `--color-block-background-success`: 区块背景色(success) - `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。 + +#### 其他区域背景色 + - `--color-layer-mask-background`: 拖拽元素时,元素原来位置的遮罩背景色 - `--color-layer-tooltip-background`: tooltip 背景色 +- `--color-pane-background`: 面板背景色 - `--color-background`: 设计器主要背景色 - `--color-top-area-background`: topArea 背景色,优先级大于 `--color-pane-background` - `--color-left-area-background`: leftArea 背景色,优先级大于 `--color-pane-background` +- `--color-toolbar-background`: toolbar 背景色,优先级大于 `--color-pane-background` - `--color-workspace-left-area-background`: 应用级 leftArea 背景色,优先级大于 `--color-pane-background` - `--color-workspace-top-area-background`: 应用级 topArea 背景色,优先级大于 `--color-pane-background` - `--color-workspace-sub-top-area-background`: 应用级二级 topArea 背景色,优先级大于 `--color-pane-background` + +#### 其他变量 + - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width -### 生态使用主题色变量 + + +### 低代码引擎生态主题色定制 插件、物料、设置器等生态为了支持主题色需要对样式进行改造,需要对生态中的样式升级为 css 变量。例如: @@ -87,6 +128,8 @@ background: var(--color-brand, #006cff); ``` +这里 `var(--color-brand, #默认色)` 表示使用 `--color-brand` 变量,如果该变量未定义,则使用默认颜色(#默认色)。 + ### fusion 物料进行主题色扩展 -如果使用了 fusion 组件,可以通过 https://fusion.alibaba-inc.com/ 平台进行主题色定制。 \ No newline at end of file +如果使用了 fusion 组件时,可以通过 [fusion 平台](https://fusion.design/) 进行主题色定制。在平台上,您可以选择不同的主题颜色,并直接应用于您的 fusion 组件,这样可以无缝地集成到您的应用设计中。 \ No newline at end of file diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index eb86bfe04..1f0eae8ec 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -366,7 +366,7 @@ body { .lc-toolbar { display: flex; height: var(--toolbar-height); - background-color: var(--color-pane-background); + background-color: var(--color-toolbar-background, var(--color-pane-background)); padding: 8px 16px; .lc-toolbar-center { display: flex; From d703e64ac958de5e91d34f4741b49b94a6b467ea Mon Sep 17 00:00:00 2001 From: JackLian Date: Wed, 29 Nov 2023 11:10:29 +0800 Subject: [PATCH 39/61] chore(docs): publish docs 1.2.3 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index e9d5b87b4..00887a758 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.2", + "version": "1.2.3", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 19bf6ad28456feab9b58de3a00023898c72d8fde Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 29 Nov 2023 11:29:33 +0800 Subject: [PATCH 40/61] style: add --color-toolbar-background --- packages/editor-skeleton/src/layouts/workbench.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 1f0eae8ec..2cddb2537 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -452,7 +452,7 @@ body { .lc-toolbar { display: flex; height: var(--toolbar-height); - background-color: var(--color-pane-background); + background-color: var(--color-toolbar-background, var(--color-pane-background)); padding: 8px 16px; .lc-toolbar-center { display: flex; From 1a328bd1f63a27074ba4b07c9b866ef85038e6e2 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 30 Nov 2023 17:36:55 +0800 Subject: [PATCH 41/61] style: fix --workspace-left-area-width style bug --- docs/docs/guide/expand/editor/theme.md | 1 + packages/editor-skeleton/src/layouts/workbench.less | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 16bcf04b0..35a77f2ac 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -112,6 +112,7 @@ sidebar_position: 9 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width +- `--left-area-width`: leftArea width diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 2cddb2537..565b6f07d 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -443,6 +443,10 @@ body { min-height: 0; position: relative; + > .lc-left-float-pane { + left: calc(var(--workspace-left-area-width, var(--left-area-width)) + 1px); + } + .lc-workspace-workbench-center { flex: 1; display: flex; From 8f5ba69813bf4cf1a3b084c2a1eb24f2dbc8be35 Mon Sep 17 00:00:00 2001 From: liujuping Date: Fri, 1 Dec 2023 14:23:29 +0800 Subject: [PATCH 42/61] docs: add meet docs --- docs/docs/participate/meet.md | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/docs/participate/meet.md diff --git a/docs/docs/participate/meet.md b/docs/docs/participate/meet.md new file mode 100644 index 000000000..23226bf1c --- /dev/null +++ b/docs/docs/participate/meet.md @@ -0,0 +1,55 @@ +--- +title: 开源社区例会 +sidebar_position: 0 +--- + +## **简介** + +低代码引擎开源社区致力于共同推动低代码技术的发展和创新。本社区汇集了低代码技术领域的开发者、技术专家和行业观察者,通过定期的例会来交流思想、分享经验、讨论新技术,并探索低代码技术的未来发展方向。 + +## 参与要求 + +为了确保例会的质量和效果,我们建议以下人员参加: + +- **已参与低代码引擎贡献的成员**:那些对低代码引擎有实际贡献的社区成员。 +- **参考贡献指南**:可查阅[贡献指南](https://lowcode-engine.cn/site/docs/participate/)获取更多信息。 +- **提供过优秀建议的成员**:那些在过去为低代码引擎提供过有价值建议的成员。 + +## **时间周期** + +- **周期性**:月例会 + +### **特别说明** + +- 例会周期可根据成员反馈进行调整。如果讨论的议题较多,可增加例会频率;若议题较少,单次例会可能取消。若多次取消,可能会暂停例会。 + +## **例会流程** + +### **准备阶段** + +- **定期确定议题**:会前一周确定下一次会议的议题。 +- **分发会议通知**:提前发送会议时间、议程和参与方式。 + +### **会议阶段** + +- **开场和介绍**:简短开场和自我介绍,特别是新成员加入时。 +- **议题讨论**:按照议程进行议题讨论,每个议题分配一定时间,并留足够时间供讨论和提问。 +- **记录要点和决定**:记录讨论要点、决策和任何行动事项。 + +### **后续阶段** + +- **分享会议纪要**:会后将会议纪要和行动计划分发给所有成员。 +- **执行和跟进**:根据会议中的讨论和决策执行相关任务,并在下次会议中进行跟进汇报。 + +## **开源例会议题** + +开源例会议题包括但不限于: + +- **共建低代码行业发展**:探讨通过开源社区合作加速低代码行业发展。 +- **改进建议和反馈收集**:讨论社区成员对低代码引擎的使用体验和改进建议。 +- **前端技术与低代码的结合**:针对前端开发者,讨论将前端技术与低代码引擎结合的方式。 +- **低代码业务场景和经验分享**:邀请社区成员分享低代码引擎的实际应用经验。 +- **低代码技术原理介绍**:深入理解低代码引擎的技术原理和实现方式。 +- **低代码引擎的最新进展**:分享低代码引擎的最新进展,包括新版本发布和新功能实现等。 +- **低代码技术的未来展望**:讨论低代码技术的未来发展方向。 +- **最新低代码平台功能和趋势分析**:分享和讨论当前低代码平台的新功能、趋势和发展方向。 \ No newline at end of file From ebdcc4146135ae3d41c8cf79024e9247238a8c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Fri, 1 Dec 2023 15:27:30 +0800 Subject: [PATCH 43/61] fix: scope props merge defaultProps (#2716) --- packages/renderer-core/src/renderer/base.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index f6930e86d..9d9e88ab5 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -429,7 +429,14 @@ export default function baseRendererFactory(): IBaseRenderComponent { __createDom = () => { const { __schema, __ctx, __components = {} } = this.props; - const scope: any = {}; + // merge defaultProps + const scopeProps = { + ...__schema.defaultProps, + ...this.props, + }; + const scope: any = { + props: scopeProps, + }; scope.__proto__ = __ctx || this; const _children = getSchemaChildren(__schema); From 4d03610fd3b6d056fa7ce35f127cf7a90f99dd6c Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 30 Nov 2023 20:38:12 +0800 Subject: [PATCH 44/61] feat: update types define --- packages/types/src/shell/type/plugin-config.ts | 4 ++-- packages/types/src/shell/type/resource-type-config.ts | 3 ++- packages/types/src/shell/type/resource-type.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/types/src/shell/type/plugin-config.ts b/packages/types/src/shell/type/plugin-config.ts index e9e65192e..2d841dd80 100644 --- a/packages/types/src/shell/type/plugin-config.ts +++ b/packages/types/src/shell/type/plugin-config.ts @@ -1,5 +1,5 @@ export interface IPublicTypePluginConfig { - init(): Promise; - destroy?(): Promise; + init(): Promise | void; + destroy?(): Promise | void; exports?(): any; } diff --git a/packages/types/src/shell/type/resource-type-config.ts b/packages/types/src/shell/type/resource-type-config.ts index 474987b52..01b49aa2b 100644 --- a/packages/types/src/shell/type/resource-type-config.ts +++ b/packages/types/src/shell/type/resource-type-config.ts @@ -1,3 +1,4 @@ +import React from 'react'; import { IPublicTypeEditorView } from './editor-view'; export interface IPublicResourceTypeConfig { @@ -6,7 +7,7 @@ export interface IPublicResourceTypeConfig { description?: string; /** 资源 icon 标识 */ - icon?: React.ReactElement; + icon?: React.ReactElement | React.FunctionComponent | React.ComponentClass; /** * 默认视图类型 diff --git a/packages/types/src/shell/type/resource-type.ts b/packages/types/src/shell/type/resource-type.ts index 7cfb125aa..7d64a4463 100644 --- a/packages/types/src/shell/type/resource-type.ts +++ b/packages/types/src/shell/type/resource-type.ts @@ -4,7 +4,7 @@ import { IPublicResourceTypeConfig } from './resource-type-config'; export interface IPublicTypeResourceType { resourceName: string; - resourceType: 'editor' | 'webview'; + resourceType: 'editor' | 'webview' | string; (ctx: IPublicModelPluginContext, options: Object): IPublicResourceTypeConfig; } \ No newline at end of file From 70845a1eca349c5786101119537ff9664fbe9056 Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 5 Dec 2023 09:32:21 +0800 Subject: [PATCH 45/61] chore(docs): publish docs 1.2.4 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 00887a758..d5d42cf96 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.3", + "version": "1.2.4", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 0a50cf5a0d351fd3f140f4893140193f6aa5231c Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 5 Dec 2023 13:05:08 +0800 Subject: [PATCH 46/61] docs: update participate docs --- docs/docs/participate/config.md | 88 ------------------- docs/docs/participate/doc.md | 25 ------ docs/docs/participate/index.md | 143 +++++++++++++++++++++++++------ docs/docs/participate/prepare.md | 64 -------------- 4 files changed, 119 insertions(+), 201 deletions(-) delete mode 100644 docs/docs/participate/config.md delete mode 100644 docs/docs/participate/doc.md delete mode 100644 docs/docs/participate/prepare.md diff --git a/docs/docs/participate/config.md b/docs/docs/participate/config.md deleted file mode 100644 index 1d70a7a89..000000000 --- a/docs/docs/participate/config.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: 工程化配置 -sidebar_position: 3 ---- -目前引擎体系共包含 2 个 js 文件 (配套 2 个 css),即: - - -```html - - - - - - - - - -``` - -> 注,这里的版本号是示例,请尽量选用最新版 - -工程化配置我们进行了统一,具体如下: -```shell -{ - "entry": { - ... - }, - "library": "...", - "libraryTarget": "umd", - "externals": { - "react": "var window.React", - "react-dom": "var window.ReactDOM", - "prop-types": "var window.PropTypes", - "@alilc/lowcode-engine": "var window.AliLowCodeEngine", - "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt", - "moment": "var moment", - "lodash": "var _", - "@alifd/next": "var Next" - }, - "polyfill": false, - "outputDir": "dist", - "vendor": false, - "ignoreHtmlTemplate": true, - "sourceMap": true, - "plugins": [ - "build-plugin-react-app", - ["build-plugin-fusion", { - }], - ["build-plugin-moment-locales", { - "locales": ["zh-CN"] - }], - "./build.plugin.js" - ] -} - -``` -总结一下,有 2 点: - -1. **都不包含 polyfill,**需要应用级别单独引入 polyfill,推荐动态 polyfill -2. **都不包含 lodash / moment / next** - - -#### 前置依赖资源: -```html - - - - - - -``` - - -#### 所有资源: -```html - - - - - - - - - - - - -``` diff --git a/docs/docs/participate/doc.md b/docs/docs/participate/doc.md deleted file mode 100644 index 1e19918db..000000000 --- a/docs/docs/participate/doc.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: 参与文档贡献 -sidebar_position: 3 ---- - -## 基本原则 - -### 维护方式 - -- 官方文档通过 github 管理文档源,官网文档与[主仓库 develop 分支](https://github.com/alibaba/lowcode-engine/tree/develop/docs)保持同步。 -- 点击每篇文档下发的 `编辑此页` 可直接定位到 github 中位置。 -- 欢迎 PR,文档 PR 也会作为贡献者贡献,会用于贡献度统计。 -- **文档同步到官方网站由官方人员进行操作**,如有需要可以通过 issue 或 贡献者群与相关人员沟通。 -- 为了提供更好的阅读和使用体验,文档中的图片文件会定期转换成可信的 CDN 地址。 - -### PR 提交注意事项 - -- 指向 develop 分支。 -- 涉及到图片的,需附在文档同级的 img 目录下,通过相对地址引用。 - -### 文档格式 - -本项目文档参考[文档编写指南](https://github.com/sparanoid/chinese-copywriting-guidelines)。 - -使用 vscode 进行编辑的朋友可以安装 vscode 插件 [huacnlee.autocorrect](https://github.com/huacnlee/autocorrect) 辅助文档 lint。 diff --git a/docs/docs/participate/index.md b/docs/docs/participate/index.md index ea87651ff..4540fa640 100644 --- a/docs/docs/participate/index.md +++ b/docs/docs/participate/index.md @@ -1,31 +1,126 @@ --- -title: 贡献者指南 +title: 参与贡献 sidebar_position: 0 --- -### 首个 Pull Request -在写第一个 Pull Request?你可以从这一系列视频中学习怎么做: -[How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) + +### 环境准备 + +开发 LowcodeEngine 需要 Node.js 16+。 + +推荐使用 nvm 管理 Node.js,避免权限问题的同时,还能够随时切换当前使用的 Node.js 的版本。 + +### 贡献低代码引擎 + +#### clone 项目 + +``` +git clone git@github.com:alibaba/lowcode-engine.git +cd lowcode-engine +``` + +#### 安装依赖并构建 + +``` +npm install && npm run setup +``` + +#### 调试环境配置 + +本质上是将 demo 页面引入的几个 js/css 代理到 engine 项目,可以使用趁手的代理工具,这里推荐 [XSwitch](https://chrome.google.com/webstore/detail/xswitch/idkjhjggpffolpidfkikidcokdkdaogg?hl=en-US)。 + +本地开发代理规则如下: +```json +{ + "proxy": [ + [ + "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", + "http://localhost:5555/js/AliLowCodeEngine.js" + ], + [ + "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", + "http://localhost:5555/css/AliLowCodeEngine.css" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", + "http://localhost:5555/js/ReactSimulatorRenderer.js" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", + "http://localhost:5555/css/ReactSimulatorRenderer.css" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", + "http://localhost:5555/js/RaxSimulatorRenderer.js" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", + "http://localhost:5555/css/RaxSimulatorRenderer.css" + ], + ] +} +``` + +#### 开发 + +``` +npm start +``` + +选择一个环境进行调试,例如[低代码引擎在线 DEMO](https://lowcode-engine.cn/demo/demo-general/index.html) + +开启代理之后,就可以进行开发调试了。 + + +### 贡献低代码引擎文档 + +#### 开发文档 + +在 lowcode-engine 目录下执行下面命令 +``` +cd docs + +npm start +``` + +#### 维护方式 +- 官方文档通过 github 管理文档源,官网文档与[主仓库 develop 分支](https://github.com/alibaba/lowcode-engine/tree/develop/docs)保持同步。 +- 点击每篇文档下发的 `编辑此页` 可直接定位到 github 中位置。 +- 欢迎 PR,文档 PR 也会作为贡献者贡献,会用于贡献度统计。 +- **文档同步到官方网站由官方人员进行操作**,如有需要可以通过 issue 或 贡献者群与相关人员沟通。 +- 为了提供更好的阅读和使用体验,文档中的图片文件会定期转换成可信的 CDN 地址。 + +#### 文档格式 + +本项目文档参考[文档编写指南](https://github.com/sparanoid/chinese-copywriting-guidelines)。 + +使用 vscode 进行编辑的朋友可以安装 vscode 插件 [huacnlee.autocorrect](https://github.com/huacnlee/autocorrect) 辅助文档 lint。 + + +### 贡献低代码引擎生态 + +相关源码详见[NPM 包对应源码位置汇总](/site/docs/guide/appendix/npms) + +开发调试方式详见[低代码生态脚手架 & 调试机制](/site/docs/guide/expand/editor/cli) + +### 发布 + +PR 被合并之后,我们会尽快发布相关的正式版本或者 beta 版本。 + +### 加入 Contributor 群 +提交过 Bugfix 或 Feature 类 PR 的同学,如果有兴趣一起参与维护 LowcodeEngine,我们提供了一个核心贡献者交流群。 + +1. 可以通过[填写问卷](https://survey.taobao.com/apps/zhiliao/4YEtu9gHF)的方式,参与到其中。 +2. 填写问卷后加微信号 `wxidvlalalalal` (注明 github id)我们会拉你到群里。 + +如果你不知道可以贡献什么,可以到源码里搜 TODO 或 FIXME 找找。 为了使你能够快速上手和熟悉贡献流程,我们这里有个列表 [good first issues](https://github.com/alibaba/lowcode-engine/issues?q=is:open+is:issue+label:%22good+first+issue%22),里面有相对没那么笼统的漏洞,从这开始是个不错的选择。 -如果你想解决一个 issue,请确定检查了该 issue 下的评论以防有人正在处理它。如果目前没人在处理该 issue,那么请留下评论去表明你想处理该 issue 以便其他人不会意外重复你的工作。 +### PR 提交注意事项 -如果有人留言表明要处理该 issue 但是超过两周没有跟进,你可以接手工作,不过也应该留言说明。 - -### 提交 Pull Request -核心团队时刻关注 pull requests,我们会先评审你的 pull request,之后可能会合并,可能会要求再次更改,也可能会关闭该 pull request 并对此作出解释。我们会尽力全程更新和反馈。 - -**提交 pull request 前**,请确保完成以下步骤: - -1. Fork [此仓库](https://github.com/alibaba/lowcode-engine),从 main 创建分支。 -2. 在仓库根目录下执行 yarn。 -3. 如果你修复了 bug 或者添加了代码,而这些内容需要测试,请添加测试! -4. 确保通过测试套件(yarn test)。 -5. 请签订贡献者许可证协议(Contributor License Agreement)。 - > 如已签署 CLA 仍被提示需要签署,[解决办法](/site/docs/faq/faq021) - -### 核心贡献者交流 -如果你想长期参与到项目维护中,我们提供了一个核心贡献者交流群。 - -1. 可以通过[填写问卷](https://survey.taobao.com/apps/zhiliao/4YEtu9gHF)的方式,参与到其中。 -2. 填写问卷后加微信号 `wxidvlalalalal` 说明一下。 +- lowcode-engine 仓库建议从 develop 创建分支,PR 指向 develop 分支。 +- 其他仓库从 main 分支创建分支,PR 指向 main 分支 +- 如果你修复了 bug 或者添加了代码,而这些内容需要测试,请添加测试! +- 确保通过测试套件(yarn test)。 +- 请签订贡献者许可证协议(Contributor License Agreement)。 + > 如已签署 CLA 仍被提示需要签署,[解决办法](/site/docs/faq/faq021) \ No newline at end of file diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md deleted file mode 100644 index acb0947f2..000000000 --- a/docs/docs/participate/prepare.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: 调试环境配置 -sidebar_position: 1 ---- -低代码引擎的核心仓库是不包含任何物料、插件、setter 的,它本身用于生成低代码引擎的主包。 - -如果您需要对低代码的主包进行开发和调试,需要用到本文里介绍的知识。 - -如果您需要对低代码编辑器进行定制,您可能只需要 clone [lowcode-demo 项目](https://github.com/alibaba/lowcode-demo)并进行修改,参考“[配置低代码扩展点](/site/docs/guide/expand/editor/summary)”章节。 - -> 前置条件: -> node 推荐使用 16.18.0(14.x 也可以) - -### 1. 拉取代码,启动项目 -```bash -git clone git@github.com:alibaba/lowcode-engine.git -cd lowcode-engine -npm install && npm run setup -npm start - - -git clone git@github.com:alibaba/lowcode-demo.git -cd lowcode-demo -npm install && npm start -``` - -### 2. 配置资源代理 -本质上是将 demo 页面引入的几个 js/css 代理到 engine 项目,可以使用趁手的代理工具,这里推荐 [XSwitch](https://chrome.google.com/webstore/detail/xswitch/idkjhjggpffolpidfkikidcokdkdaogg?hl=en-US)。 - -本地开发代理规则如下: -```json -{ - "proxy": [ - [ - "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/js/AliLowCodeEngine.js" - ], - [ - "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", - "http://localhost:5555/css/AliLowCodeEngine.css" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", - "http://localhost:5555/js/ReactSimulatorRenderer.js" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", - "http://localhost:5555/css/ReactSimulatorRenderer.css" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/RaxSimulatorRenderer.js" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/RaxSimulatorRenderer.css" - ], - ] -} -``` - -### 3. 本地调试物料/插件/设置器 - -详见[低代码生态脚手架 & 调试机制](/site/docs/guide/expand/editor/cli) From 28fdf9a37d04fc4c5d942aca4f87511bb0f901fe Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 5 Dec 2023 13:29:16 +0800 Subject: [PATCH 47/61] chore(docs): publish docs 1.2.5 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index d5d42cf96..75704e688 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.4", + "version": "1.2.5", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From a87dcaada18eb28d0b67fa99e4ab82ca1d552d7d Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 5 Dec 2023 15:25:28 +0800 Subject: [PATCH 48/61] chore: create publish docs.yml --- .github/workflows/publish docs.yml | 51 ++++++++++++++++++++++++++++++ docs/package.json | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish docs.yml diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml new file mode 100644 index 000000000..dcbeec384 --- /dev/null +++ b/.github/workflows/publish docs.yml @@ -0,0 +1,51 @@ +name: Update and Publish Docs + +on: + push: + branches: + - develop + paths: + - 'docs/**' + +jobs: + publish-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' + registry-url: 'https://registry.npmjs.org' + - run: cd docs && npm install + - run: | + cd docs + npm version patch + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add package.json + git commit -m "Update package version" + git push + - run: cd docs && npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + + comment-pr: + needs: publish-docs + runs-on: ubuntu-latest + steps: + - name: Comment on PR + if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true + uses: actions/github-script@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: '🚀 New version has been released: ' + '${{ needs.publish-docs.outputs.version }}' + }) \ No newline at end of file diff --git a/docs/package.json b/docs/package.json index 75704e688..8af810d33 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.5", + "version": "1.2.6", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 77aea1bfbafe4315e8488417d862d820e81dd573 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 5 Dec 2023 07:29:34 +0000 Subject: [PATCH 49/61] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 8af810d33..634f73bee 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.6", + "version": "1.2.7", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 398f06974571a05af5b03b3d7c651c3f604f5967 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 5 Dec 2023 14:42:28 +0800 Subject: [PATCH 50/61] style: add css themes vars --- docs/docs/guide/expand/editor/theme.md | 11 ++++++++++- .../designer/src/builtin-simulator/host.less | 8 ++++---- packages/editor-skeleton/src/layouts/theme.less | 2 +- .../editor-skeleton/src/layouts/workbench.less | 16 ++++++++-------- .../types/src/shell/type/widget-base-config.ts | 5 +++++ 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 35a77f2ac..36500cb45 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -50,7 +50,6 @@ sidebar_position: 9 - `--color-text-dark`: 文字颜色(dark) - `--color-text-light`: 文字颜色(light) - `--color-text-reverse`: 反色情况下,文字颜色 -- `--color-text-regular`: 文字颜色(regular) - `--color-text-disabled`: 禁用态文字颜色 #### 字段和边框颜色 @@ -109,10 +108,20 @@ sidebar_position: 9 #### 其他变量 - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 +- `--top-area-height`: 顶部区域的高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width - `--left-area-width`: leftArea width +- `--simulator-top-distance`: simulator 距离容器顶部的距离 +- `--simulator-bottom-distance`: simulator 距离容器底部的距离 +- `--simulator-left-distance`: simulator 距离容器左边的距离 +- `--simulator-right-distance`: simulator 距离容器右边的距离 +- `--toolbar-padding`: toolbar 的 padding +- `--toolbar-height`: toolbar 的高度 +- `--pane-title-height`: 面板标题高度 +- `--pane-title-font-size`: 面板标题字体大小 +- `--pane-title-padding`: 面板标题边距 diff --git a/packages/designer/src/builtin-simulator/host.less b/packages/designer/src/builtin-simulator/host.less index 7130c4297..9a00963f2 100644 --- a/packages/designer/src/builtin-simulator/host.less +++ b/packages/designer/src/builtin-simulator/host.less @@ -73,10 +73,10 @@ } &-device-default { - top: 16px; - right: 16px; - bottom: 16px; - left: 16px; + top: var(--simulator-top-distance, 16px); + right: var(--simulator-right-distance, 16px); + bottom: var(--simulator-bottom-distance, 16px); + left: var(--simulator-left-distance, 16px); width: auto; box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.125)); } diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 716ab3a99..78c6fa5fd 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -27,7 +27,6 @@ --color-text-dark: darken(@dark-alpha-3, 10%); --color-text-light: lighten(@dark-alpha-3, 10%); --color-text-reverse: @white-alpha-2; - --color-text-regular: @normal-alpha-2; --color-text-disabled: @gray-light; --color-field-label: @dark-alpha-4; @@ -87,4 +86,5 @@ --color-function-error-light: lighten(@brand-danger, 10%); --color-function-purple: rgb(144, 94, 190); --color-function-brown: #7b605b; + --color-text-regular: @normal-alpha-2; } diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 565b6f07d..596ea69f6 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -66,16 +66,16 @@ body { } } > .lc-panel-title { - height: 48px; - font-size: 16px; - padding: 0 15px; + height: var(--pane-title-height, 48px); + font-size: var(--pane-title-font-size, 16px); + padding: var(--pane-title-padding, 0 15px); color: var(--color-title, #0f1726); font-weight: bold; } .lc-panel-body { position: absolute; - top: 48px; + top: var(--pane-title-height, 48px); bottom: 0; left: 0; right: 0; @@ -234,7 +234,7 @@ body { .lc-pane-icon-close { position: absolute; right: 16px; - top: 14px; + top: calc(var(--pane-title-height, 48px) / 2 - 10px); height: auto; z-index: 2; .next-icon { @@ -247,7 +247,7 @@ body { .lc-pane-icon-float { position: absolute; right: 38px; - top: 14px; + top: calc(var(--pane-title-height, 48px) / 2 - 10px); height: auto; z-index: 2; svg { @@ -367,7 +367,7 @@ body { display: flex; height: var(--toolbar-height); background-color: var(--color-toolbar-background, var(--color-pane-background)); - padding: 8px 16px; + padding: var(--toolbar-padding, 8px 16px); .lc-toolbar-center { display: flex; justify-content: center; @@ -457,7 +457,7 @@ body { display: flex; height: var(--toolbar-height); background-color: var(--color-toolbar-background, var(--color-pane-background)); - padding: 8px 16px; + padding: var(--toolbar-padding, 8px 16px); .lc-toolbar-center { display: flex; justify-content: center; diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index edddf2d68..b23ba0f13 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -15,6 +15,11 @@ export interface IPublicTypeWidgetBaseConfig { props?: Record; content?: any; contentProps?: Record; + + /** + * 优先级,值越小,优先级越高,优先级高的会排在前面 + */ + index?: number; } export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig { From 3786b3a7ff09c4223f0b84fc15da58356c123694 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 5 Dec 2023 07:38:51 +0000 Subject: [PATCH 51/61] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 634f73bee..f175552e5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.7", + "version": "1.2.8", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 1f214918bb5ce4d03132b78081eb63c815b0c347 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 7 Dec 2023 11:03:07 +0800 Subject: [PATCH 52/61] style: add css themes vars --- docs/docs/guide/expand/editor/theme.md | 8 +++++++- .../designer/src/builtin-simulator/bem-tools/borders.less | 2 +- packages/editor-skeleton/src/layouts/theme.less | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 36500cb45..ef0e04d28 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -35,6 +35,7 @@ sidebar_position: 9 #### Icon 相关颜色 - `--color-icon-normal`: 默认状态 +- `--color-icon-light`: icon light 状态 - `--color-icon-hover`: 鼠标悬停状态 - `--color-icon-active`: 激活状态 - `--color-icon-reverse`: 反色状态 @@ -82,16 +83,21 @@ sidebar_position: 9 #### 区块背景色 - `--color-block-background-normal`: 区块背景色 -- `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 +- `--color-block-background-light`: 区块背景色(light)。 - `--color-block-background-shallow`: 区块背景色 shallow - `--color-block-background-dark`: 区块背景色(dark) - `--color-block-background-disabled`: 区块背景色(disabled) - `--color-block-background-active`: 区块背景色(active) +- `--color-block-background-active-light`: 区块背景色(active light) - `--color-block-background-warning`: 区块背景色(warning) - `--color-block-background-error`: 区块背景色(error) - `--color-block-background-success`: 区块背景色(success) - `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。 +#### 引擎相关颜色 + +- `--color-canvas-detecting-background`: 画布组件 hover 时遮罩背景色。 + #### 其他区域背景色 - `--color-layer-mask-background`: 拖拽元素时,元素原来位置的遮罩背景色 diff --git a/packages/designer/src/builtin-simulator/bem-tools/borders.less b/packages/designer/src/builtin-simulator/bem-tools/borders.less index 43fba6a2b..cb83d36f3 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/borders.less +++ b/packages/designer/src/builtin-simulator/bem-tools/borders.less @@ -100,7 +100,7 @@ &&-detecting { z-index: 1; border-style: dashed; - background: var(--color-block-background-light, rgba(0,121,242,.04)); + background: var(--color-canvas-detecting-background, rgba(0,121,242,.04)); } &&-selecting { diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 78c6fa5fd..01542c758 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -14,6 +14,7 @@ --color-icon-normal: @normal-alpha-4; --color-icon-hover: @normal-alpha-3; + --color-icon-light: @normal-alpha-5; --color-icon-active: @brand-color-1; --color-icon-reverse: @white-alpha-1; --color-icon-disabled: @normal-alpha-6; @@ -55,10 +56,11 @@ --color-pane-background: @white-alpha-1; --color-block-background-normal: @white-alpha-1; --color-block-background-light: @normal-alpha-9; - --color-block-background-shallow: @normal-alpha-8; --color-block-background-dark: @normal-alpha-7; + --color-block-background-shallow: @normal-alpha-8; --color-block-background-disabled: @normal-alpha-6; - --color-block-background-active: @brand-color-1-7; + --color-block-background-active: @brand-color-1; + --color-block-background-active-light: @brand-color-1-7; --color-block-background-warning: @brand-warning-alpha-7; --color-block-background-error: @brand-danger-alpha-7; --color-block-background-success: @brand-success-alpha-7; @@ -67,6 +69,8 @@ --color-layer-tooltip-background: rgba(44,47,51,0.8); --color-background: #edeff3; + --color-canvas-detecting-background: rgba(0,121,242,.04); + --pane-title-bg-color: rgba(31,56,88,.04); } From 6932c3bdc7def44a7db971672469c18e5fbc2e63 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 7 Dec 2023 05:49:17 +0000 Subject: [PATCH 53/61] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index f175552e5..a1b6d646f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.8", + "version": "1.2.9", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 014834a31f1ebbcfb21c8993534046d753540b99 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 13 Dec 2023 12:16:28 +0800 Subject: [PATCH 54/61] style(outline): update outline-filter-icon style --- packages/plugin-outline-pane/src/views/style.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 15f115ea6..8521883b4 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -28,7 +28,7 @@ } .lc-outline-filter-icon { - background: var(--color-block-background-shallow, #ebecf0); + background: var(--color-block-background-light, #ebecf0); border: 1px solid var(--color-field-border, #c4c6cf); display: flex; align-items: center; From a0975428c4c7301b9d678cf0c19e6e49c241ee79 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 13 Dec 2023 14:21:59 +0800 Subject: [PATCH 55/61] docs: add faq024 --- docs/docs/faq/faq024.md | 133 ++++++++++++++++++++++++++++++++++++++++ docs/docs/faq/index.md | 1 + 2 files changed, 134 insertions(+) create mode 100644 docs/docs/faq/faq024.md diff --git a/docs/docs/faq/faq024.md b/docs/docs/faq/faq024.md new file mode 100644 index 000000000..ab1b68f5d --- /dev/null +++ b/docs/docs/faq/faq024.md @@ -0,0 +1,133 @@ +--- +title: workspace 模式常见问题 +sidebar_position: 23 +tags: [FAQ] +--- + +#### 如何判断是否开启了IDE模式? + +- **通过官方API判断**:您可以通过访问 [workspace.isActive](/site/docs/api/workspace#isactive) 来判断当前是否处于IDE模式。这是阿里低代码引擎提供的一个官方API,专门用于确认是否处于集成开发环境。 + + + +#### 如何使用插件的ctx来做判断在哪个模式下? + +- **插件是否为应用级别**:可以通过 **ctx.isPluginRegisteredInWorkspace** 方法来判断一个插件是否是应用级别的插件。这有助于理解插件在阿里低代码引擎中的作用域和潜在的使用场景。 +- **插件的注册级别**:您可以使用 **ctx.registerLevel** 属性来判断插件处于哪个级别。插件级别的值包括: + - **Default**:默认级别。非 IDE 模式下的值 + - **Workspace**:应用级别。 + - **Resource**:资源级别。 + - **EditorView**:编辑视图级别。 这些级别代表了插件可能的作用域和使用场景,有助于在开发和管理低代码应用时对插件进行更精确的控制和配置。 + + + +#### 如何在IDE模式下设置资源列表? + +- **设置资源列表API**:在IDE模式下,可以通过访问 [workspace.setResourceList](/site/docs/api/workspace#setresourcelist) 来设置或更新IDE中的资源列表。这确保您在编辑器窗口中打开的资源是最新且可访问的。 + + + +#### 如何打开视图窗口? + +- **使用推荐的方法**:使用 `openEditorWindow(resource: Resource, sleep?: boolean): Promise;` 来打开视图窗口。这里的 **resource** 参数指的是您要打开的特定资源,可通过 [workspace.resourceList](/site/docs/api/workspace#resourcelist) 获取。 +- **不推荐使用的过时方法**:有一个过时的方法 `openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise;` 也用于打开视图窗口。虽然仍然可用,但官方不推荐使用此方法,并计划在后续版本中废弃,因为它在维护和可扩展性方面存在限制。 + + + +#### 如何在全局插件中获取视图的上下文? + +- 在阿里低代码引擎的全局插件中获取视图的上下文,可以通过使用 **ProvideViewPluginContext** 函数实现。这个函数来自 **@alilc/lowcode-utils** 库,它使得您的 React 组件能够接收 **pluginContext** 作为 props,进而访问和操作当前视图的状态和属性。 + +**步骤** + +**引入依赖**:首先,确保您的插件文件中已经引入了 **ProvideViewPluginContext** 以及其他必要的依赖。 + +``` +import { ProvideViewPluginContext } from '@alilc/lowcode-utils'; +``` + +**定义 React 组件**:创建一个 React 组件,它将使用来自 **ProvideViewPluginContext** 的 **pluginContext**。 + +```typescript +const MyComponent = (props) => { + const { pluginContext } = props; + // 组件逻辑 + return
/* 组件内容 */
; +}; +``` + +**定义全局插件**:定义一个函数,这个函数会在插件被注册时调用。这个函数通常接受一个上下文对象 **ctx**,它提供了对引擎功能的访问。 + +```javascript +const globalPlugin = (ctx) => { + const { skeleton } = ctx; + + skeleton.add({ + type: 'PanelDock', + name: 'datapool', + content: ProvideViewPluginContext((props) => { + // 组件内容 + return ( + + ) + }), + // 其他配置 + contentProps: { + // 需要提供 pluginContext 作为参数 + pluginContext: ctx, + } + }); +}; +``` + +通过这些步骤,您的全局插件中的 React 组件就能够获取并使用视图的上下文了。这为您在插件中实现更复杂的功能和交互提供了基础。 + + + +**注意事项** + +- **组件重渲染**:正常情况下,**pluginsContext** 是视图的上下文。当视图切换时,组件会重新渲染。如果需要在组件中处理视图切换导致的重新渲染,可以利用 React 的 **key** 属性。 + +**示例代码** + +```typescript +ProvideViewPluginContext(props => { + return ( + Date: Wed, 13 Dec 2023 06:37:30 +0000 Subject: [PATCH 56/61] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index a1b6d646f..eaf87ac21 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.9", + "version": "1.2.10", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 271aef4fb964f2fab74f1a70b020ab679564a10f Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 13 Dec 2023 16:12:15 +0800 Subject: [PATCH 57/61] chore: add publish engine actions --- .github/workflows/publish docs.yml | 2 +- .github/workflows/publish engine beta.yml | 30 +++++++++++++++++++ .github/workflows/publish engine.yml | 26 ++++++++++++++++ package.json | 4 +-- .../src/layouts/workbench.less | 1 + 5 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/publish engine beta.yml create mode 100644 .github/workflows/publish engine.yml diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index dcbeec384..ed16bb869 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -5,7 +5,7 @@ on: branches: - develop paths: - - 'docs/**' + - 'docs/docs/**' jobs: publish-docs: diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml new file mode 100644 index 000000000..ab498c8df --- /dev/null +++ b/.github/workflows/publish engine beta.yml @@ -0,0 +1,30 @@ +name: Update and Publish Docs + +on: + push: + branches: + - 'release/[0-9]+.[0-9]+.[0-9]+-beta' + paths: + - 'packages/**' + +jobs: + publish-engine: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' + registry-url: 'https://registry.npmjs.org' + - run: npm install && npm run setup + - run: | + npm run build + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + - run: npm run pub:prerelease + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml new file mode 100644 index 000000000..3710cf816 --- /dev/null +++ b/.github/workflows/publish engine.yml @@ -0,0 +1,26 @@ +name: Update and Publish Docs + +on: + workflow_dispatch: + +jobs: + publish-engine: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' + registry-url: 'https://registry.npmjs.org' + - run: npm install && npm run setup + - run: | + npm run build + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + - run: npm run pub + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" diff --git a/package.json b/package.json index aded2a301..caabbeeb1 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@ "lint:fix": "f2elint fix -i ./packages/*/src", "lint:modules": "f2elint scan -q -i ./modules/*/src", "lint:modules:fix": "f2elint fix -i ./modules/*/src", - "pub": "npm run watchdog:build && lerna publish patch --force-publish --exact --no-changelog", + "pub": "npm run watchdog:build && lerna publish patch --yes --force-publish --exact --no-changelog", "pub:premajor": "npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:preminor": "npm run watchdog:build && lerna publish preminor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:prepatch": "npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog", - "pub:prerelease": "npm run watchdog:build && lerna publish prerelease --force-publish --exact --dist-tag beta --preid beta --no-changelog", + "pub:prerelease": "npm run watchdog:build && lerna publish prerelease --yes --force-publish --exact --dist-tag beta --preid beta --no-changelog", "setup": "node ./scripts/setup.js", "setup:test": "./scripts/setup-for-test.sh", "setup:skip-build": "./scripts/setup-skip-build.sh", diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 596ea69f6..97a017523 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -105,6 +105,7 @@ body { right: 0; bottom: 0; z-index: -1; + overflow: hidden; &.active { z-index: 999; From a25aad4975231706a9e47ba3e62e17034ce18846 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 13 Dec 2023 16:43:51 +0800 Subject: [PATCH 58/61] fix(outline): fix view change bugs in workspace mode --- .github/workflows/publish engine beta.yml | 4 ++-- .github/workflows/publish engine.yml | 4 ++-- packages/plugin-outline-pane/src/controllers/tree-master.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml index ab498c8df..32c5b4c15 100644 --- a/.github/workflows/publish engine beta.yml +++ b/.github/workflows/publish engine beta.yml @@ -1,4 +1,4 @@ -name: Update and Publish Docs +name: Publish Engine Beta on: push: @@ -27,4 +27,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + run: echo "::set-output name=version::$(node -p "require('./package.json').version")" diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 3710cf816..f9206d4cb 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -1,4 +1,4 @@ -name: Update and Publish Docs +name: Publish Engine on: workflow_dispatch: @@ -23,4 +23,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + run: echo "::set-output name=version::$(node -p "require('./package.json').version")" diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index ede5f0f5f..f86ce3dec 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -51,9 +51,9 @@ export class TreeMaster { windowViewTypeChangeEvent(); workspace.onChangeActiveWindow(() => { - windowViewTypeChangeEvent(); this.setPluginContext(workspace.window?.currentEditorView); dispose && dispose(); + windowViewTypeChangeEvent(); }); } } From 2e604c99109b82d2dc1f447ab1de37f623e3188d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 18:58:24 +0800 Subject: [PATCH 59/61] Fix/component lifecycle not execute (#2690) * fix: recover component lifecycle and avoid execute from scope __proto__ From c3d0ffb62cd03d81f4fc46d01b1714eb1dd79a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:28:41 +0800 Subject: [PATCH 60/61] Fix/component lifecycle not execute (#2692) * fix: recover component lifecycle and avoid execute from scope __proto__ From f418e5b2c18ddb5299a575f0888ad67de642bcf2 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 13 Dec 2023 09:34:24 +0000 Subject: [PATCH 61/61] chore(release): publish 1.2.3 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 34be89faa..98ef80f13 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.2", + "version": "1.2.3", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 69a402ed2..e961451d8 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.2", + "version": "1.2.3", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index de9d30bc8..345783c80 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.2", + "version": "1.2.3", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index fe2d0d43f..fa5c1e13e 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.2", + "version": "1.2.3", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 3ea47f79d..c9eef3534 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.2", + "version": "1.2.3", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.2", - "@alilc/lowcode-plugin-outline-pane": "1.2.2", - "@alilc/lowcode-shell": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", - "@alilc/lowcode-workspace": "1.2.2", + "@alilc/lowcode-plugin-designer": "1.2.3", + "@alilc/lowcode-plugin-outline-pane": "1.2.3", + "@alilc/lowcode-shell": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-workspace": "1.2.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index d737a7c86..71a21484c 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.2", + "version": "1.2.3", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index fe653568b..500c0c961 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.2", + "version": "1.2.3", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 2540ca5ad..5a2ef38a4 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.2", + "version": "1.2.3", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 60ea0c698..837aebc85 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-renderer-core": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 520ff32c8..dc9b7b147 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-rax-renderer": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-rax-renderer": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index a35039fc3..1dceb9c2e 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.2" + "@alilc/lowcode-renderer-core": "1.2.3" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 413b1825f..8935c92ee 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-react-renderer": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-react-renderer": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 3b96ef40b..4774ae368 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.2", + "version": "1.2.3", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 7e2019235..2ebf14bbc 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.2", + "version": "1.2.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", - "@alilc/lowcode-workspace": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-workspace": "1.2.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index c4fa29003..c0b8e203f 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.2", + "version": "1.2.3", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index af76e9e2f..00efffb8d 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.2", + "version": "1.2.3", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-types": "1.2.3", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 472432379..8c09a93b6 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.2", + "version": "1.2.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5",