From 56eaff52c832f53ef293ccf3ca773df634e75049 Mon Sep 17 00:00:00 2001 From: "muyun.my" Date: Tue, 15 Sep 2020 13:55:35 +0800 Subject: [PATCH 01/34] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E6=BA=90?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/demo/public/schema.json | 18 +- packages/demo/src/editor/components.ts | 2 + packages/demo/src/editor/config.js | 56 +++ packages/plugin-datasource-pane/README.md | 71 ++++ packages/plugin-datasource-pane/build.json | 7 + packages/plugin-datasource-pane/package.json | 44 +++ .../src/datasource-form.tsx | 273 ++++++++++++++ .../src/form-components/expression.tsx | 122 +++++++ .../src/form-components/index.ts | 2 + .../src/form-components/jsfunction.tsx | 66 ++++ .../src/form-components/param-value.tsx | 103 ++++++ .../src/import-plugins/code.tsx | 138 +++++++ .../src/import-plugins/index.ts | 1 + .../plugin-datasource-pane/src/index.scss | 18 + packages/plugin-datasource-pane/src/index.tsx | 114 ++++++ packages/plugin-datasource-pane/src/list.tsx | 143 ++++++++ .../src/locale/en-US.json | 3 + .../src/locale/index.ts | 10 + .../src/locale/zh-CN.json | 3 + packages/plugin-datasource-pane/src/pane.tsx | 344 ++++++++++++++++++ .../src/types/datasource-type.ts | 6 + .../src/types/import-plugin.ts | 20 + .../plugin-datasource-pane/src/types/index.ts | 2 + .../plugin-datasource-pane/test/foobar.ts | 5 + packages/plugin-datasource-pane/tsconfig.json | 10 + 25 files changed, 1579 insertions(+), 2 deletions(-) create mode 100644 packages/plugin-datasource-pane/README.md create mode 100644 packages/plugin-datasource-pane/build.json create mode 100644 packages/plugin-datasource-pane/package.json create mode 100644 packages/plugin-datasource-pane/src/datasource-form.tsx create mode 100644 packages/plugin-datasource-pane/src/form-components/expression.tsx create mode 100644 packages/plugin-datasource-pane/src/form-components/index.ts create mode 100644 packages/plugin-datasource-pane/src/form-components/jsfunction.tsx create mode 100644 packages/plugin-datasource-pane/src/form-components/param-value.tsx create mode 100644 packages/plugin-datasource-pane/src/import-plugins/code.tsx create mode 100644 packages/plugin-datasource-pane/src/import-plugins/index.ts create mode 100644 packages/plugin-datasource-pane/src/index.scss create mode 100644 packages/plugin-datasource-pane/src/index.tsx create mode 100644 packages/plugin-datasource-pane/src/list.tsx create mode 100644 packages/plugin-datasource-pane/src/locale/en-US.json create mode 100644 packages/plugin-datasource-pane/src/locale/index.ts create mode 100644 packages/plugin-datasource-pane/src/locale/zh-CN.json create mode 100644 packages/plugin-datasource-pane/src/pane.tsx create mode 100644 packages/plugin-datasource-pane/src/types/datasource-type.ts create mode 100644 packages/plugin-datasource-pane/src/types/import-plugin.ts create mode 100644 packages/plugin-datasource-pane/src/types/index.ts create mode 100644 packages/plugin-datasource-pane/test/foobar.ts create mode 100644 packages/plugin-datasource-pane/tsconfig.json diff --git a/packages/demo/public/schema.json b/packages/demo/public/schema.json index 616ff3bef..49f07baba 100644 --- a/packages/demo/public/schema.json +++ b/packages/demo/public/schema.json @@ -10,7 +10,21 @@ }, "fileName": "test", "dataSource": { - "list": [] + "list": [ + { + "type": "http", + "id": "http1", + "isInit": true, + "options": { + "uri": "https://www.taobao.com", + "params": { + "a": 1, + "b": true, + "c": "3" + } + } + } + ] }, "state": { "text": "outter", @@ -578,4 +592,4 @@ ] } ] - } \ No newline at end of file + } diff --git a/packages/demo/src/editor/components.ts b/packages/demo/src/editor/components.ts index bf00bd149..caa52a36f 100644 --- a/packages/demo/src/editor/components.ts +++ b/packages/demo/src/editor/components.ts @@ -3,6 +3,7 @@ import samplePreview from '@ali/lowcode-plugin-sample-preview'; import undoRedo from '@ali/lowcode-plugin-undo-redo'; import componentsPane from '@ali/lowcode-plugin-components-pane'; import outline, { OutlinePane } from '@ali/lowcode-plugin-outline-pane'; +import dataSourcePane from '@ali/lowcode-plugin-datasource-pane'; import zhEn from '@ali/lowcode-plugin-zh-en'; import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog'; import variableBindDialog from '@ali/lowcode-plugin-variable-bind-dialog'; @@ -23,4 +24,5 @@ export default { sourceEditor, codeout, saveload, + dataSourcePane, }; diff --git a/packages/demo/src/editor/config.js b/packages/demo/src/editor/config.js index 7223c6031..5965260f8 100644 --- a/packages/demo/src/editor/config.js +++ b/packages/demo/src/editor/config.js @@ -1,3 +1,5 @@ +import { DataSourceImportPluginCode } from '@ali/lowcode-plugin-datasource-pane'; + export default { plugins: { topArea: [ @@ -97,6 +99,60 @@ export default { }, }, }, + { + pluginKey: 'dataSourcePane', + pluginProps: { + importPlugins: [ + { + name: 'code2', + title: '源码2', + content: DataSourceImportPluginCode, + }, + ], + dataSourceTypes: [ + { + type: 'mopen', + schema: { + type: 'object', + properties: { + options: { + type: 'object', + properties: { + uri: { + title: 'api', + }, + v: { + title: 'v', + type: 'string', + }, + appKey: { + title: 'appKey', + type: 'string', + }, + }, + }, + }, + }, + }, + ], + }, + type: 'PanelIcon', + props: { + align: 'top', + icon: 'wenjian', + description: '数据源面板', + panelProps: { + floatable: true, + height: 300, + help: undefined, + hideTitleBar: false, + maxHeight: 800, + maxWidth: 1200, + title: '数据源面板', + width: 600, + }, + }, + }, { pluginKey: 'zhEn', type: 'Custom', diff --git a/packages/plugin-datasource-pane/README.md b/packages/plugin-datasource-pane/README.md new file mode 100644 index 000000000..ea5630f97 --- /dev/null +++ b/packages/plugin-datasource-pane/README.md @@ -0,0 +1,71 @@ +TODO +--- + +* 多语言 +* [later]表达式和其他类型的切换 +* 现有场景代码的兼容 +* class publich method bind issue +* ICON +* 支持变量 + +## 数据源面板 + +数据源管理 + +* 新建 +* 编辑 +* 导入 +* 指定数据源类型 +* 定制数据源导入插件 + +## 数据源类型定义 + +内置变量,http 和 mtop 类型,支持传入自定义类型。 + +``` +type DataSourceType = { + type: string; + optionsSchema: JSONSchema6 +}; +``` + +数据源类型需要在集团规范约束下扩展。 + +目前只允许在 options 下添加扩展字段。 + +比如 mtop 类型,需要添加 options.v (版本)字段。 + +## 导入插件 + +默认支持源码导入,可以传入自定义插件。 + +``` +interface DataSourcePaneImportPlugin { + name: string; + title: string; + component: React.ReactNode; + componentProps?: DataSourcePaneImportPluginCustomProps; +} + +interface DataSourcePaneImportPluginCustomProps { + [customPropName: string]: any; +} + +interface DataSourcePaneImportPluginComponentProps extends DataSourcePaneImportPluginCustomProps { + onChange: (dataSourceList: DataSourceConfig[]) => void; +} +``` + +## 问题 + +* 变量,上下文放数据源里管理是否合适 +* mockUrl 和 mockData +* 设计器的设计语言无法统一 + +## 插件开发 + + + +## node 版本 + +v14.4.0 diff --git a/packages/plugin-datasource-pane/build.json b/packages/plugin-datasource-pane/build.json new file mode 100644 index 000000000..49a393b6b --- /dev/null +++ b/packages/plugin-datasource-pane/build.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + [ + "build-plugin-component" + ] + ] +} diff --git a/packages/plugin-datasource-pane/package.json b/packages/plugin-datasource-pane/package.json new file mode 100644 index 000000000..467a74399 --- /dev/null +++ b/packages/plugin-datasource-pane/package.json @@ -0,0 +1,44 @@ +{ + "name": "@ali/lowcode-plugin-datasource-pane", + "version": "1.0.7-0", + "description": "低代码引擎数据源面板", + "main": "lib/index.js", + "files": [ + "lib" + ], + "scripts": { + "build": "tsc", + "test": "ava", + "test:snapshot": "ava --update-snapshots" + }, + "ava": { + "compileEnhancements": false, + "snapshotDir": "test/fixtures/__snapshots__", + "extensions": [ + "ts" + ], + "require": [ + "ts-node/register" + ] + }, + "license": "MIT", + "devDependencies": { + "@types/json-schema": "^7.0.6", + "@types/react": "^16.9.49", + "@types/traverse": "^0.6.32", + "monaco-editor": "^0.20.0" + }, + "dependencies": { + "@ali/lowcode-editor-setters": "^1.0.7-0", + "@alifd/next": "^1.20.28", + "@formily/next": "^1.3.2", + "@formily/next-components": "^1.3.2", + "@formily/react-schema-renderer": "^1.3.2", + "@types/traverse": "^0.6.32", + "ajv": "^6.12.4", + "lodash": "^4.17.20", + "react-monaco-editor": "^0.40.0", + "styled-components": "^5.2.0", + "traverse": "^0.6.6" + } +} diff --git a/packages/plugin-datasource-pane/src/datasource-form.tsx b/packages/plugin-datasource-pane/src/datasource-form.tsx new file mode 100644 index 000000000..7fc5e9ab6 --- /dev/null +++ b/packages/plugin-datasource-pane/src/datasource-form.tsx @@ -0,0 +1,273 @@ +// @todo schema default +import React, { PureComponent, ReactElement, FC } from 'react'; +import { SchemaForm, FormButtonGroup, Submit } from '@formily/next'; +import { ArrayTable, Input, Switch, NumberPicker } from '@formily/next-components'; +import _isPlainObject from 'lodash/isPlainObject'; +import _isArray from 'lodash/isArray'; +import _isNumber from 'lodash/isNumber'; +import _isString from 'lodash/isString'; +import _isBoolean from 'lodash/isBoolean'; +import _cloneDeep from 'lodash/cloneDeep'; +import _mergeWith from 'lodash/mergeWith'; +import _get from 'lodash/get'; +import _tap from 'lodash/tap'; +import traverse from 'traverse'; +import { ParamValue, JSFunction } from './form-components'; +import { DataSourceType, DataSourceConfig } from './types'; + +// @todo $ref + +const SCHEMA = { + type: 'object', + properties: { + type: { + title: '类型', + type: 'string', + editable: false, + }, + id: { + type: 'string', + title: '数据源 ID', + required: true, + }, + isInit: { + title: '是否自动请求', + type: 'boolean', + default: true, + }, + dataHandler: { + type: 'string', + title: '单个数据结果处理函数', + required: true, + 'x-component': 'JSFunction', + default: 'function() {}', + }, + options: { + type: 'object', + title: '请求参数', + required: true, + properties: { + uri: { + type: 'string', + title: '请求地址', + required: true, + }, + params: { + title: '请求参数', + type: 'object', + default: {}, + }, + method: { + type: 'string', + title: '请求方法', + required: true, + enum: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE'], + default: 'GET', + }, + isCors: { + type: 'boolean', + title: '是否支持跨域', + required: true, + default: true, + }, + timeout: { + type: 'number', + title: '超时时长(毫秒)', + default: 5000, + }, + headers: { + type: 'object', + title: '请求头信息', + default: {}, + }, + }, + }, + }, +}; + +export interface DataSourceFormProps { + dataSourceType: DataSourceType; + dataSource?: DataSourceConfig; + omComplete?: (dataSource: DataSourceConfig) => void; +} + +export interface DataSourceFormState { +} + +/** + * 通过是否存在 ID 来决定读写状态 + */ +export class DataSourceForm extends PureComponent { + state = {}; + + handleFormSubmit = (formData) => { + // @todo mutable? + if (_isArray(_get(formData, 'options.params'))) { + formData.options.params = formData.options.params.reduce((acc, cur) => { + if (!cur.name) return; + acc[cur.name] = cur.value; + return acc; + }, {}); + } + if (_isArray(_get(formData, 'options.headers'))) { + formData.options.headers = formData.options.headers.reduce((acc, cur) => { + if (!cur.name) return; + acc[cur.name] = cur.value; + return acc; + }, {}); + } + console.log('submit', formData); + this.props?.onComplete(formData); + }; + + deriveInitialData = (dataSource = {}) => { + const { dataSourceType } = this.props; + const result = _cloneDeep(dataSource); + + if (_isPlainObject(_get(result, 'options.params'))) { + result.options.params = Object.keys(result.options.params).reduce( + (acc, cur) => { + acc.push({ + name: cur, + value: result.options.params[cur] + }); + return acc; + }, + [] + ); + } + if (_isPlainObject(_get(result, 'options.headers'))) { + result.options.headers = Object.keys(result.options.headers).reduce( + (acc, cur) => { + acc.push({ + name: cur, + value: result.options.headers[cur] + }); + return acc; + }, + [] + ); + } + + result.type = dataSourceType.type; + + return result; + } + + deriveSchema = () => { + const { dataSourceType } = this.props; + + // @todo 减小覆盖的风险 + const formSchema = _mergeWith({}, SCHEMA, dataSourceType.schema, (objValue, srcValue) => { + if (_isArray(objValue)) { + return srcValue; + } + }); + + debugger; + + if (_get(formSchema, 'properties.options.properties.params')) { + formSchema.properties.options.properties.params = { + ...formSchema.properties.options.properties.params, + type: 'array', + 'x-component': 'ArrayTable', + 'x-component-props': { + operationsWidth: 100, + }, + items: { + type: 'object', + properties: { + name: { + title: '参数名', + type: 'string', + }, + value: { + title: '参数值', + type: 'string', + 'x-component': 'ParamValue', + 'x-component-props': { + types: [ + 'string', + 'boolean', + 'expression', + 'number' + ], + }, + }, + }, + } + }; + delete formSchema.properties.options.properties.params.properties; + } + if (_get(formSchema, 'properties.options.properties.headers')) { + formSchema.properties.options.properties.headers = { + ...formSchema.properties.options.properties.headers, + type: 'array', + 'x-component': 'ArrayTable', + 'x-component-props': { + operationsWidth: 100, + }, + items: { + type: 'object', + properties: { + name: { + title: '参数名', + type: 'string', + }, + value: { + title: '参数值', + type: 'string', + 'x-component': 'ParamValue', + 'x-component-props': { + types: [ + 'string' + ], + }, + }, + }, + }, + }; + delete formSchema.properties.options.properties.headers.properties; + } + + return traverse(formSchema).forEach(function(node) { + if (node?.type && !node['x-component']) { + if (node.type === 'string') { + node['x-component'] = 'Input'; + } else if (node.type === 'number') { + node['x-component'] = 'NumberPicker'; + } else if (node.type === 'boolean') { + node['x-component'] = 'Switch'; + } + } + }); + }; + + render() { + const { dataSource } = this.props; + + return ( +
+ + + 提交 + + +
+ ); + } +} diff --git a/packages/plugin-datasource-pane/src/form-components/expression.tsx b/packages/plugin-datasource-pane/src/form-components/expression.tsx new file mode 100644 index 000000000..59da91da6 --- /dev/null +++ b/packages/plugin-datasource-pane/src/form-components/expression.tsx @@ -0,0 +1,122 @@ +/** + * 表达式控件,在原类型基础上切换成表达式模式 + */ +/* import React, { PureComponent, ReactElement, FC } from 'react'; +import { Button, Input, Radio, NumberPicker, Switch, Icon } from '@alifd/next'; +import { ArrayTable } from '@formily/next-components'; +import { connect } from '@formily/react-schema-renderer'; +import _isPlainObject from 'lodash/isPlainObject'; +import _isArray from 'lodash/isArray'; +import _isNumber from 'lodash/isNumber'; +import _isString from 'lodash/isString'; +import _isBoolean from 'lodash/isBoolean'; +import _get from 'lodash/get'; +import _tap from 'lodash/tap'; +import { ExpressionSetter } from '@ali/lowcode-editor-setters'; + +const { Group: RadioGroup } = Radio; + +export interface ExpressionProps { + className: string; + value: any; + onChange?: () => void; + type: 'string' | 'number' | 'boolan' | 'array'; +} + +export interface ExpressionState { + useExpression: false; +} + +class ExpressionComp extends PureComponent { + static isFieldComponent = true; + + state = { + useExpression: '', + }; + + constructor(props) { + super(props); + this.state.useExpression = this.isUseExpression(this.props.value); + this.handleChange = this.handleChange; + } + + isUseExpression = (value: any) => { + if (_isPlainObject(value) && value.type === 'JSFunction') { + return true; + } + return false; + }; + + // @todo 需要再 bind 一次? + handleChange = (value) => { + this.props?.onChange(value); + } + + componentDidUpdate(prevProps) { + if (this.props.value !== prevProps.value) { + this.setState({ + value: this.props.value, + useExpression: this.isUseExpression(this.props.value), + }); + } + } + + handleUseExpressionChange = (useExpression) => { + this.setState(({ value }) => { + let nextValue = value || ''; + if (useExpression) { + nextValue = { + type: 'JSFunction', + value: '' + }; + } else { + nextVaule = null; + } + return { + value: nextValue, + useExpression, + }; + }); + }; + + renderOriginal = () => { + const { value, type } = this.props; + + if (type === 'string') { + return ; + } else if (type === 'boolean') { + return ; + } else if (type === 'number') { + return ; + } else if (type === 'array') { + return ; + } + return null; + }; + + renderExpression = () => { + const { value, type } = this.props; + + // @todo 传入上下文才有智能提示 + return ( + + ); + }; + + render() { + const { useExpression } = this.state; + return ( +
+ {!useExpression && this.renderOriginal()} + {useExpression && this.renderExpression()} + +
+ ); + } +} + +export const Expression = connect({ + getProps: (componentProps, fieldProps) => { + debugger; + } +})(ExpressionComp); */ diff --git a/packages/plugin-datasource-pane/src/form-components/index.ts b/packages/plugin-datasource-pane/src/form-components/index.ts new file mode 100644 index 000000000..9560f79da --- /dev/null +++ b/packages/plugin-datasource-pane/src/form-components/index.ts @@ -0,0 +1,2 @@ +export * from './param-value'; +export * from './jsfunction'; diff --git a/packages/plugin-datasource-pane/src/form-components/jsfunction.tsx b/packages/plugin-datasource-pane/src/form-components/jsfunction.tsx new file mode 100644 index 000000000..03dbb5cfe --- /dev/null +++ b/packages/plugin-datasource-pane/src/form-components/jsfunction.tsx @@ -0,0 +1,66 @@ +import React, { PureComponent, createRef } from 'react'; +import { Button, Input, Radio, NumberPicker, Switch } from '@alifd/next'; +import { connect } from '@formily/react-schema-renderer'; +import _isPlainObject from 'lodash/isPlainObject'; +import _isArray from 'lodash/isArray'; +import _isNumber from 'lodash/isNumber'; +import _isString from 'lodash/isString'; +import _isBoolean from 'lodash/isBoolean'; +import _get from 'lodash/get'; +import _tap from 'lodash/tap'; +import MonacoEditor, { EditorWillMount } from 'react-monaco-editor'; + +const { Group: RadioGroup } = Radio; + +export interface JSFunctionProps { + className: string; + value: any; + onChange?: () => void; +} + +export interface JSFunctionState { +} + +class JSFunctionComp extends PureComponent { + static isFieldComponent = true; + + private monacoRef = createRef(); + + constructor(props) { + super(props); + this.handleEditorChange = this.handleEditorChange.bind(this); + } + + handleEditorChange = () => { + if (this.monacoRef.current) { + if ( + !(this.monacoRef.current as editor.IStandaloneCodeEditor) + .getModelMarkers() + .find((marker: editor.IMarker) => marker.owner === 'json') + ) { + this.props?.onChange(this.monacoRef.current?.getModels()?.[0]?.getValue()); + } + } + }; + + handleEditorWillMount: EditorWillMount = (editor) => { + (this.monacoRef as MutableRefObject).current = editor?.editor; + }; + + render() { + const { value, onChange } = this.props; + return ( + + ); + } +} + +export const JSFunction = connect()(JSFunctionComp); diff --git a/packages/plugin-datasource-pane/src/form-components/param-value.tsx b/packages/plugin-datasource-pane/src/form-components/param-value.tsx new file mode 100644 index 000000000..2cb723b37 --- /dev/null +++ b/packages/plugin-datasource-pane/src/form-components/param-value.tsx @@ -0,0 +1,103 @@ +import React, { PureComponent, ReactElement, FC } from 'react'; +import { Button, Input, Radio, NumberPicker, Switch } from '@alifd/next'; +import { connect } from '@formily/react-schema-renderer'; +import _isPlainObject from 'lodash/isPlainObject'; +import _isArray from 'lodash/isArray'; +import _isNumber from 'lodash/isNumber'; +import _isString from 'lodash/isString'; +import _isBoolean from 'lodash/isBoolean'; +import _get from 'lodash/get'; +import _tap from 'lodash/tap'; +import { ExpressionSetter } from '@ali/lowcode-editor-setters'; + +const { Group: RadioGroup } = Radio; + +export interface ParamValueProps { + className: string; + value: any; + onChange?: () => void; +} + +export interface ParamValueState { + type: 'string' | 'number' | 'boolean' | ''; +} + +class ParamValueComp extends PureComponent { + static isFieldComponent = true; + + state = { + type: '', + }; + + constructor(props) { + super(props); + this.state.type = this.getTypeFromValue(this.props.value); + } + + getTypeFromValue = (value) => { + if (_isBoolean(value)) { + return 'boolean'; + } else if (_isNumber(value)) { + return 'number'; + } else if (_isPlainObject(value) && value.type === 'JSFunction') { + return 'expression'; + } + return 'string'; + }; + + // @todo 需要再 bind 一次? + handleChange = (value) => { + this.props?.onChange(value); + } + + componentDidUpdate(prevProps) { + if (this.props.value !== prevProps.value) { + this.setState({ + value: this.props.value, + type: this.getTypeFromValue(this.props.value), + }); + } + } + + handleTypeChange = (type) => { + this.setState(({ value }) => { + let nextValue = value || ''; + if (type === 'string') { + nextValue = nextValue.toString(); + } else if (type === 'number') { + nextValue = nextValue * 1; + } else if (type === 'boolean') { + nextValue = nextValue === 'true' || nextValue; + } else if (type === 'expression') { + nextValue = ''; + } + return { + value: nextValue, + type, + }; + }); + }; + + render() { + const { type } = this.state; + const { value } = this.props; + return ( +
+ { + + 字符串 + 布尔 + 数字 + 表达式 + + } + {type === 'string' && } + {type === 'boolean' && } + {type === 'number' && } + {type === 'expression' && } +
+ ); + } +} + +export const ParamValue = connect()(ParamValueComp); diff --git a/packages/plugin-datasource-pane/src/import-plugins/code.tsx b/packages/plugin-datasource-pane/src/import-plugins/code.tsx new file mode 100644 index 000000000..a8f1d10ff --- /dev/null +++ b/packages/plugin-datasource-pane/src/import-plugins/code.tsx @@ -0,0 +1,138 @@ +/** + * 源码导入插件 + * @todo editor 关联 types,并提供详细的出错信息 + */ +import React, { PureComponent, createRef, MutableRefObject } from 'react'; +import { Button } from '@alifd/next'; +import _noop from 'lodash/noop'; +import _isArray from 'lodash/isArray'; +import _last from 'lodash/last'; +import _isPlainObject from 'lodash/isPlainObject'; +import MonacoEditor, { EditorWillMount } from 'react-monaco-editor'; +import { editor } from 'monaco-editor'; +import { DataSourceConfig } from '@ali/lowcode-types'; +import Ajv from 'ajv'; +import { DataSourcePaneImportPluginComponentProps } from '../types'; + +export interface DataSourceImportPluginCodeProps extends DataSourcePaneImportPluginComponentProps { + defaultValue?: DataSourceConfig[]; +} + +export interface DataSourceImportPluginCodeState { + code: string; + isCodeValid: boolean; +} + +export class DataSourceImportPluginCode extends PureComponent< + DataSourceImportPluginCodeProps, + DataSourceImportPluginCodeState +> { + static defaultProps = { + defaultValue: [ + { + type: 'http', + id: 'test', + }, + ] + }; + + state = { + code: '', + isCodeValid: true, + }; + + private monacoRef = createRef(); + + constructor(props: DataSourceImportPluginCodeProps) { + super(props); + this.state.code = JSON.stringify(this.deriveValue(this.props.defaultValue)); + this.handleEditorWillMount = this.handleEditorWillMount.bind(this); + this.handleEditorChange = this.handleEditorChange.bind(this); + this.handleComplete = this.handleComplete.bind(this); + } + + deriveValue = (value: any) => { + const { dataSourceTypes } = this.props; + + if (!_isArray(dataSourceTypes) || dataSourceTypes.length === 0) return []; + + let result = value; + if (_isPlainObject(result)) { + // 如果是对象则转化成数组 + result = [result]; + } else if (!_isArray(result)) { + return []; + } + + const ajv = new Ajv(); + + return (result as DataSourceConfig[]).filter((dataSource) => { + if (!dataSource.type) return false; + const dataSourceType = dataSourceTypes.find((type) => type.type === dataSource.type); + if (!dataSourceType) return false; + return ajv.validate(dataSourceType.schema, dataSource); + }); + }; + + handleComplete = () => { + if (this.monacoRef.current) { + if ( + !(this.monacoRef.current as editor.IStandaloneCodeEditor) + .getModelMarkers() + .find((marker: editor.IMarker) => marker.owner === 'json') + ) { + this.setState({ isCodeValid: true }); + this.props?.onImport(this.deriveValue(JSON.parse(_last(this.monacoRef.current.getModels()).getValue()))); + return; + } + } + this.setState({ isCodeValid: false }); + }; + + handleEditorChange = () => { + if (this.monacoRef.current) { + if ( + !(this.monacoRef.current as editor.IStandaloneCodeEditor) + .getModelMarkers() + .find((marker: editor.IMarker) => marker.owner === 'json') + ) { + this.setState({ isCodeValid: true }); + } + } + }; + + handleEditorWillMount: EditorWillMount = (editor) => { + (this.monacoRef as MutableRefObject).current = editor?.editor; + // @todo 格式化一次 + }; + + handleCodeChagne = (code) => { + this.setState({ code }); + } + + render() { + const { onCancel = _noop } = this.props; + const { code, isCodeValid } = this.state; + + return ( +
+ + {!isCodeValid &&

格式有误

} +

+ + +

+
+ ); + } +} diff --git a/packages/plugin-datasource-pane/src/import-plugins/index.ts b/packages/plugin-datasource-pane/src/import-plugins/index.ts new file mode 100644 index 000000000..d18a4e09a --- /dev/null +++ b/packages/plugin-datasource-pane/src/import-plugins/index.ts @@ -0,0 +1 @@ +export * from './code'; diff --git a/packages/plugin-datasource-pane/src/index.scss b/packages/plugin-datasource-pane/src/index.scss new file mode 100644 index 000000000..67d1208f6 --- /dev/null +++ b/packages/plugin-datasource-pane/src/index.scss @@ -0,0 +1,18 @@ +.lowcode-plugin-datasource-pane { + margin: 0 8px; + >.next-tabs { + >.next-tabs-bar { + .next-tabs-nav-extra { + .next-btn { + margin-left: 4px; + } + } + } + } +} + +.lowcode-plugin-datasource-pane-list { + .next-virtual-list-wrapper { + min-height: 400px; + } +} diff --git a/packages/plugin-datasource-pane/src/index.tsx b/packages/plugin-datasource-pane/src/index.tsx new file mode 100644 index 000000000..ccde8d705 --- /dev/null +++ b/packages/plugin-datasource-pane/src/index.tsx @@ -0,0 +1,114 @@ +import React, { PureComponent } from 'react'; +import { PluginProps } from '@ali/lowcode-types'; +import { DataSourcePane } from './pane'; +import { DataSourcePaneImportPlugin, DataSourceType } from './types'; +import { DataSourceImportPluginCode } from './import-plugins'; + +export { DataSourceImportPluginCode }; + +const PLUGIN_NAME = 'dataSourcePane'; + +export interface DataSourcePaneProps extends PluginProps { + importPlugins: DataSourcePaneImportPlugin[]; + dataSourceTypes?: DataSourceType[]; +} + +export interface DataSourcePaneState { + active: boolean; +} + +const BUILTIN_DATASOURCE_TYPES = [ + { + type: 'http', + schema: { + type: 'object', + properties: { + options: { + type: 'object', + properties: {}, + }, + }, + }, + }, + { + type: 'mtop', + schema: { + type: 'object', + properties: { + options: { + type: 'object', + properties: { + uri: { + title: 'api', + }, + v: { + title: 'v', + type: 'string', + }, + appKey: { + title: 'appKey', + type: 'string', + }, + }, + }, + }, + }, + }, +]; + +const BUILTIN_IMPORT_PLUGINS = [ + { + name: 'default', + title: '源码', + component: DataSourceImportPluginCode, + }, +]; + +export default class DataSourcePanePlugin extends PureComponent { + static displayName = 'DataSourcePanePlugin'; + + static defaultProps = { + dataSourceTypes: [], + importPlugins: [], + }; + + state = { + active: false, + }; + + constructor(props: DataSourcePaneProps) { + super(props); + this.state.active = true; + + const { editor } = this.props; + // @todo pluginName, to unsubscribe + // 第一次 active 事件不会触发监听器 + editor.on('skeleton.panel-dock.active', (pluginName, dock) => { + if (pluginName === PLUGIN_NAME) { + this.setState({ active: true }); + } + }); + editor.on('skeleton.panel-dock.unactive', (pluginName, dock) => { + if (pluginName === PLUGIN_NAME) { + this.setState({ active: false }); + } + }); + } + + render() { + const { importPlugins, dataSourceTypes, editor } = this.props; + const { active } = this.state; + + if (!active) return null; + + const defaultSchema = editor.get('designer').project?.currentDocument?.schema?.dataSource ?? {}; + + return ( + + ); + } +} diff --git a/packages/plugin-datasource-pane/src/list.tsx b/packages/plugin-datasource-pane/src/list.tsx new file mode 100644 index 000000000..4f0ace919 --- /dev/null +++ b/packages/plugin-datasource-pane/src/list.tsx @@ -0,0 +1,143 @@ +import React, { PureComponent, ReactElement, FC } from 'react'; +import { Button, Search, VirtualList, Tag, Balloon, Table } from '@alifd/next'; +import { DataSourceConfig } from '@ali/lowcode-types'; +import _isPlainObject from 'lodash/isPlainObject'; +import _isNumber from 'lodash/isNumber'; +import _isBoolean from 'lodash/isBoolean'; +import _isNil from 'lodash/isNil'; +import _tap from 'lodash/tap'; +import { DataSourceType } from './types'; + +const { Column: TableCol } = Table; + +export interface DataSourceListProps { + dataSourceTypes: DataSourceType[]; + dataSource: DataSourceConfig[]; + onEditDataSource?: (dataSourceId: string) => void; + onDuplicateDataSource?: (dataSourceId: string) => void; + onRemoveDataSource?: (dataSourceId: string) => void; +} + +export interface DataSourceListState { + filteredType: string; + keyword: string; +} + +type TableRow = { + label: string; + value: any; +}; + +export default class DataSourceList extends PureComponent { + state = { + filteredType: '', + keyword: '', + }; + + handleSearchFilterChange = (filteredType: any) => { + this.setState({ filteredType }); + }; + + handleSearch = (keyword: any) => { + this.setState({ keyword }); + }; + + handleEditDataSource = (id: any) => { + this.props.onEditDataSource?.(id); + }; + + handleDuplicateDataSource = (id: any) => { + this.props.onDuplicateDataSource?.(id); + }; + + handleRemoveDataSource = (id: any) => { + this.props.onRemoveDataSource?.(id); + }; + + deriveListDataSource = () => { + const { filteredType, keyword } = this.state; + const { dataSource } = this.props; + + return ( + dataSource + ?.filter((item) => (filteredType ? item.type === filteredType : true)) + ?.filter((item) => (keyword ? item.id.indexOf(keyword) !== -1 : true)) + ?.map((item) => ( +
  • + + {item.type} + {item.isInit ? '自动' : '手动'} + {item.id} + + + + + } + align="r" + alignEdge + triggerType="hover" + style={{ width: 300 }} + > + ((acc, cur) => { + // @todo 这里的 ts 处理得不好 + if (_isPlainObject(item.options[cur])) { + Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => { + acc.push({ + label: `${cur}.${curInOption}`, + value: (item?.options?.[cur] as any)?.[curInOption], + }); + }); + } else if (!_isNil(item.options[cur])) { + // @todo 排除 null + acc.push({ + label: cur, + value: item.options[cur], + }); + } + return acc; + }, []), console.log)} + > + + ( +
    + + {_isBoolean(val) ? 'bool' : _isNumber(val) ? 'number' : _isPlainObject(val) ? 'obj' : 'string'} + + {val.toString()} +
    + )} + /> +
    +
    +
  • + )) || [] + ); + }; + + render() { + const { dataSourceTypes } = this.props; + + return ( +
    + ({ + label: type?.type, + value: type?.type, + }))} + onFilterChange={this.handleSearchFilterChange} + /> + {this.deriveListDataSource()} +
    + ); + } +} diff --git a/packages/plugin-datasource-pane/src/locale/en-US.json b/packages/plugin-datasource-pane/src/locale/en-US.json new file mode 100644 index 000000000..5b7636ab3 --- /dev/null +++ b/packages/plugin-datasource-pane/src/locale/en-US.json @@ -0,0 +1,3 @@ +{ + "DataSourcePane": "DataSource Pane" +} diff --git a/packages/plugin-datasource-pane/src/locale/index.ts b/packages/plugin-datasource-pane/src/locale/index.ts new file mode 100644 index 000000000..26507f0ef --- /dev/null +++ b/packages/plugin-datasource-pane/src/locale/index.ts @@ -0,0 +1,10 @@ +import { createIntl } from '@ali/lowcode-editor-core'; +import en_US from './en-US.json'; +import zh_CN from './zh-CN.json'; + +const { intl, intlNode, getLocale, setLocale } = createIntl({ + 'en-US': en_US, + 'zh-CN': zh_CN, +}); + +export { intl, intlNode, getLocale, setLocale }; diff --git a/packages/plugin-datasource-pane/src/locale/zh-CN.json b/packages/plugin-datasource-pane/src/locale/zh-CN.json new file mode 100644 index 000000000..dba113fb6 --- /dev/null +++ b/packages/plugin-datasource-pane/src/locale/zh-CN.json @@ -0,0 +1,3 @@ +{ + "DataSourcePane": "数据源面板" +} diff --git a/packages/plugin-datasource-pane/src/pane.tsx b/packages/plugin-datasource-pane/src/pane.tsx new file mode 100644 index 000000000..de1b41725 --- /dev/null +++ b/packages/plugin-datasource-pane/src/pane.tsx @@ -0,0 +1,344 @@ +/** + * 面板,先通过 Dialog 呈现 + */ +import React, { PureComponent } from 'react'; +import { DataSource, DataSourceConfig } from '@ali/lowcode-types'; +import { Tab, Button, MenuButton, Message } from '@alifd/next'; +import _cloneDeep from 'lodash/cloneDeep'; +import _uniqueId from 'lodash/uniqueId'; +import _startsWith from 'lodash/startsWith'; +import _isArray from 'lodash/isArray'; +import _get from 'lodash/get'; +import List from './list'; +// import { DataSourceImportButton, DataSourceImportPluginCode } from './import'; +import { DataSourceForm } from './datasource-form'; +import { DataSourcePaneImportPlugin, DataSourceType } from './types'; + +const { Item: TabItem } = Tab; +const { Item: MenuButtonItem } = MenuButton; + +const TAB_ITEM_LIST = 'list'; +const TAB_ITEM_IMPORT = 'import'; +const TAB_ITEM_CREATE = 'create'; +const TAB_ITEM_EDIT = 'edit'; + +export interface DataSourcePaneProps { + dataSourceTypes?: DataSourceType[]; + importPlugins?: DataSourcePaneImportPlugin[]; + defaultSchema?: DataSource; + onSchemaChange?: (schema: DataSource) => void; +} + +export interface TabItemProps { + key: string; + title: string; + closeable: boolean; + data: any; +} + +export interface TabItem { + tabItemProps: TabItemProps; +} + +export interface DataSourcePaneState { + dataSourceList: DataSourceConfig[]; + tabItems: TabItem[]; + activeTabKey: string; +} + +export class DataSourcePane extends PureComponent { + state = { + dataSourceList: [...(this.props.defaultSchema?.list || [])], + tabItems: [ + { + tabItemProps: { + key: TAB_ITEM_LIST, + title: '数据源列表', + closeable: false, + }, + }, + ], + activeTabKey: TAB_ITEM_LIST, + }; + + constructor(props) { + super(props); + this.handleDataSourceListChange = this.handleDataSourceListChange.bind(this); + this.handleImportDataSourceList = this.handleImportDataSourceList.bind(this); + this.handleCreateDataSource = this.handleCreateDataSource.bind(this); + this.handleUpdateDataSource = this.handleUpdateDataSource.bind(this); + this.handleRemoveDataSource = this.handleRemoveDataSource.bind(this); + this.handleDuplicateDataSource = this.handleDuplicateDataSource.bind(this); + this.handleEditDataSource = this.handleEditDataSource.bind(this); + this.handleTabChange = this.handleTabChange.bind(this); + } + + handleDataSourceListChange = (dataSourceList?: DataSourceConfig[]) => { + if (dataSourceList) { + this.setState({ dataSourceList }); + } + this.props.onSchemaChange?.({ + list: this.state.dataSourceList, + }); + }; + + handleImportDataSourceList = (toImport: DataSourceConfig[]) => { + this.closeTab(TAB_ITEM_IMPORT); + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.concat(toImport), + }), + () => { + this.handleDataSourceListChange(); + }, + ); + }; + + handleCreateDataSource = (toCreate: DataSourceConfig) => { + this.closeTab(TAB_ITEM_CREATE); + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.concat([ + { + ...toCreate, + }, + ]), + }), + () => { + this.handleDataSourceListChange(); + }, + ); + }; + + handleUpdateDataSource = (toUpdate: DataSourceConfig) => { + this.closeTab(TAB_ITEM_EDIT); + this.setState( + ({ dataSourceList }) => { + const nextDataSourceList = [...dataSourceList]; + const dataSourceUpdate = nextDataSourceList.find((dataSource) => dataSource.id === toUpdate.id); + if (dataSourceUpdate) { + Object.assign(dataSourceUpdate, toUpdate); + } + return { + dataSourceList: nextDataSourceList, + }; + }, + () => { + this.handleDataSourceListChange(); + }, + ); + }; + + handleRemoveDataSource = (dataSourceId: string) => { + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId), + }), + () => { + this.handleDataSourceListChange(); + }, + ); + }; + + handleDuplicateDataSource = (dataSourceId: string) => { + const target = this.state.dataSourceList.find((item) => item.id === dataSourceId); + const cloned = _cloneDeep(target); + + this.openCreateDataSourceTab({ + ...cloned, + id: _uniqueId(`${cloned.id}_`), + }); + }; + + handleEditDataSource = (dataSourceId: string) => { + const target = this.state.dataSourceList.find((item) => item.id === dataSourceId); + const cloned = _cloneDeep(target); + + this.openEditDataSourceTab({ + ...cloned, + }); + }; + + // @todo 没有识别出类型 + handleTabChange = (activeTabKey: any) => { + this.setState({ activeTabKey }); + }; + + openCreateDataSourceTab = (dataSourceTypeName: string) => { + const { tabItems } = this.state; + const { dataSourceTypes } = this.props; + + if (!tabItems.find((item) => item.tabItemProps.key === TAB_ITEM_CREATE)) { + this.setState(({ tabItems }) => ({ + tabItems: tabItems.concat({ + tabItemProps: { + key: TAB_ITEM_CREATE, + title: `添加数据源`, + closeable: true, + data: { + dataSourceType: dataSourceTypes?.find( + type => type.type === dataSourceTypeName + ), + }, + }, + }), + })); + this.setState({ activeTabKey: TAB_ITEM_CREATE }); + } else { + Message.notice('当前已有一个新建数据源的 TAB 被大家'); + } + }; + + openEditDataSourceTab = (dataSource: DataSourceConfig) => { + const { tabItems } = this.state; + const { dataSourceTypes } = this.props; + + if (!tabItems.find((item) => item.tabItemProps.key === TAB_ITEM_EDIT)) { + this.setState(({ tabItems }) => ({ + tabItems: tabItems.concat({ + tabItemProps: { + key: TAB_ITEM_EDIT, + title: '修改数据源', + closeable: true, + data: { + dataSource, + dataSourceType: dataSourceTypes?.find( + type => type.type === dataSource.type + ), + }, + }, + }), + })); + } + this.setState({ activeTabKey: TAB_ITEM_EDIT }); + }; + + openImportDataSourceTab = (selectedImportPluginName) => { + const { tabItems } = this.state; + const { importPlugins } = this.props; + + if (!tabItems.find((item) => item.tabItemProps.key === `${TAB_ITEM_IMPORT}_${selectedImportPluginName}`)) { + this.setState(({ tabItems }) => ({ + tabItems: tabItems.concat({ + tabItemProps: { + key: TAB_ITEM_IMPORT, + title: `导入数据源-${selectedImportPluginName}`, + closeable: true, + content: _get( + importPlugins?.find((plugin) => selectedImportPluginName === plugin.name), + 'component', + ), + }, + }), + })); + this.setState({ activeTabKey: TAB_ITEM_IMPORT }); + } else { + Message.notice('当前已有一个导入数据源的 TAB 被大家'); + } + }; + + closeTab = (tabKey: any) => { + this.setState( + ({ tabItems }) => ({ + tabItems: tabItems.filter((item) => item.tabItemProps.key !== tabKey), + }), + () => { + this.setState(({ tabItems }) => ({ + activeTabKey: _get(tabItems, '[0].tabItemProps.key') + })); + }, + ); + }; + + renderTabExtraContent = () => { + const { importPlugins, dataSourceTypes } = this.props; + + // @todo onSelect 不行? + return [ + _isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? ( + + {dataSourceTypes.map((type) => ( + {type.type} + ))} + + ) : _isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? ( + + ) : null, + _isArray(importPlugins) && importPlugins.length > 1 ? ( + + {importPlugins.map((plugin) => ( + {plugin.name} + ))} + + ) : _isArray(importPlugins) && importPlugins.length > 1 ? ( + + ) : null, + ]; + }; + + // 更通用的处理 + renderTabItemContentByKey = (tabItemKey: any, data: any) => { + const { dataSourceList, tabItems } = this.state; + const { dataSourceTypes } = this.props; + + if (tabItemKey === TAB_ITEM_LIST) { + return ( + + ); + } else if (tabItemKey === TAB_ITEM_EDIT) { + const dataSourceType = dataSourceTypes.find((type) => type.type === data?.dataSource.type); + return ( + + ); + } else if (tabItemKey === TAB_ITEM_CREATE) { + const tabItemData = tabItems.find((tabItem) => tabItem.tabItemProps.key === tabItemKey); + return ( + + ); + } else if (tabItemKey === TAB_ITEM_IMPORT) { + const tabItemData = tabItems.find((tabItem) => tabItem.tabItemProps.key === tabItemKey); + if (tabItemData) { + const Content = tabItemData.tabItemProps.content; + return ; + } + } + return null; + }; + + render() { + const { dataSourceList, activeTabKey, tabItems } = this.state; + const { importPlugins, dataSourceTypes } = this.props; + + return ( +
    + + {tabItems.map((item) => ( + + {this.renderTabItemContentByKey(item.tabItemProps.key, item.tabItemProps.data)} + + ))} + +
    + ); + } +} diff --git a/packages/plugin-datasource-pane/src/types/datasource-type.ts b/packages/plugin-datasource-pane/src/types/datasource-type.ts new file mode 100644 index 000000000..88533593f --- /dev/null +++ b/packages/plugin-datasource-pane/src/types/datasource-type.ts @@ -0,0 +1,6 @@ +import { JSONSchema4 } from '@types/json-schema'; + +export type DataSourceType = { + type: string; + schema: JSONSchema4 +}; diff --git a/packages/plugin-datasource-pane/src/types/import-plugin.ts b/packages/plugin-datasource-pane/src/types/import-plugin.ts new file mode 100644 index 000000000..f3a999241 --- /dev/null +++ b/packages/plugin-datasource-pane/src/types/import-plugin.ts @@ -0,0 +1,20 @@ +import { DataSourceConfig } from '@ali/lowcode-types'; +import { DataSourceType } from './datasource-type'; + +// 导入插件 +export interface DataSourcePaneImportPlugin { + name: string; + title: string; + component: React.ReactNode; + componentProps?: DataSourcePaneImportPluginCustomProps; +} + +export interface DataSourcePaneImportPluginCustomProps { + [customPropName: string]: any; +} + +export interface DataSourcePaneImportPluginComponentProps extends DataSourcePaneImportPluginCustomProps { + dataSourceTypes: DataSourceType[]; + onImport?: (dataSourceList: DataSourceConfig[]) => void; + onCancel?: () => void; +} diff --git a/packages/plugin-datasource-pane/src/types/index.ts b/packages/plugin-datasource-pane/src/types/index.ts new file mode 100644 index 000000000..f3ea68ac2 --- /dev/null +++ b/packages/plugin-datasource-pane/src/types/index.ts @@ -0,0 +1,2 @@ +export * from './datasource-type'; +export * from './import-plugin'; diff --git a/packages/plugin-datasource-pane/test/foobar.ts b/packages/plugin-datasource-pane/test/foobar.ts new file mode 100644 index 000000000..7a14c4b2d --- /dev/null +++ b/packages/plugin-datasource-pane/test/foobar.ts @@ -0,0 +1,5 @@ +import test from 'ava'; + +test('foobar', t => { + t.pass(); +}); diff --git a/packages/plugin-datasource-pane/tsconfig.json b/packages/plugin-datasource-pane/tsconfig.json new file mode 100644 index 000000000..020e1e82f --- /dev/null +++ b/packages/plugin-datasource-pane/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "lib": ["es6", "dom"], + "compilerOptions": { + "outDir": "lib" + }, + "include": [ + "./src/" + ] +} From 47f55cafce0ea973e7472b8078a6baa2c1008d64 Mon Sep 17 00:00:00 2001 From: "muyun.my" Date: Mon, 21 Sep 2020 08:33:46 +0800 Subject: [PATCH 02/34] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E6=BA=90?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/demo/public/schema.json | 67 ++++++++- packages/plugin-datasource-pane/CHANGELOG.md | 0 packages/plugin-datasource-pane/README.md | 38 +---- packages/plugin-datasource-pane/TODO.md | 18 +++ packages/plugin-datasource-pane/build.json | 5 +- .../src/datasource-form.tsx | 12 +- .../src/form-components/param-value.scss | 7 + .../src/form-components/param-value.tsx | 65 +++++++-- .../src/import-plugins/code.scss | 15 ++ .../src/import-plugins/code.tsx | 12 +- .../plugin-datasource-pane/src/index.scss | 83 ++++++++++- packages/plugin-datasource-pane/src/index.tsx | 2 + packages/plugin-datasource-pane/src/list.tsx | 122 +++++++++------- packages/plugin-datasource-pane/src/pane.tsx | 131 ++++++++++++------ packages/plugin-datasource-pane/tsconfig.json | 2 +- 15 files changed, 424 insertions(+), 155 deletions(-) create mode 100644 packages/plugin-datasource-pane/CHANGELOG.md create mode 100644 packages/plugin-datasource-pane/TODO.md create mode 100644 packages/plugin-datasource-pane/src/form-components/param-value.scss create mode 100644 packages/plugin-datasource-pane/src/import-plugins/code.scss diff --git a/packages/demo/public/schema.json b/packages/demo/public/schema.json index 49f07baba..131b55860 100644 --- a/packages/demo/public/schema.json +++ b/packages/demo/public/schema.json @@ -13,7 +13,72 @@ "list": [ { "type": "http", - "id": "http1", + "id": "请求商家数据,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求", + "isInit": true, + "options": { + "uri": "https://www.taobao.com", + "params": { + "a": 1, + "b": true, + "c": "3" + } + } + }, + { + "type": "http", + "id": "请求商家数据2,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求", + "isInit": true, + "options": { + "uri": "https://www.taobao.com", + "params": { + "a": 1, + "b": true, + "c": "3" + } + } + }, + { + "type": "http", + "id": "请求商家数据3,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求", + "isInit": true, + "options": { + "uri": "https://www.taobao.com", + "params": { + "a": 1, + "b": true, + "c": "3" + } + } + }, + { + "type": "http", + "id": "请求商家数据4,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求", + "isInit": true, + "options": { + "uri": "https://www.taobao.com", + "params": { + "a": 1, + "b": true, + "c": "3" + } + } + }, + { + "type": "http", + "id": "请求商家数据5,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求", + "isInit": false, + "options": { + "uri": "https://www.taobao.com", + "params": { + "a": 1, + "b": true, + "c": "3" + } + } + }, + { + "type": "http", + "id": "请求商家数据6,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求", "isInit": true, "options": { "uri": "https://www.taobao.com", diff --git a/packages/plugin-datasource-pane/CHANGELOG.md b/packages/plugin-datasource-pane/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/packages/plugin-datasource-pane/README.md b/packages/plugin-datasource-pane/README.md index ea5630f97..4e0213a43 100644 --- a/packages/plugin-datasource-pane/README.md +++ b/packages/plugin-datasource-pane/README.md @@ -1,26 +1,10 @@ -TODO ---- +## 低代码引擎 - 数据源面板插件 -* 多语言 -* [later]表达式和其他类型的切换 -* 现有场景代码的兼容 -* class publich method bind issue -* ICON -* 支持变量 - -## 数据源面板 - -数据源管理 - -* 新建 -* 编辑 -* 导入 -* 指定数据源类型 -* 定制数据源导入插件 +对页面的数据源进行管理(新建,编辑,导入)。 ## 数据源类型定义 -内置变量,http 和 mtop 类型,支持传入自定义类型。 +内置 fetch 和 mtop 类型,支持传入自定义类型。 ``` type DataSourceType = { @@ -29,9 +13,7 @@ type DataSourceType = { }; ``` -数据源类型需要在集团规范约束下扩展。 - -目前只允许在 options 下添加扩展字段。 +数据源类型需要在集团规范约束下扩展。目前只允许在 options 下添加扩展字段。 比如 mtop 类型,需要添加 options.v (版本)字段。 @@ -56,16 +38,8 @@ interface DataSourcePaneImportPluginComponentProps extends DataSourcePaneImportP } ``` -## 问题 - -* 变量,上下文放数据源里管理是否合适 -* mockUrl 和 mockData -* 设计器的设计语言无法统一 - ## 插件开发 - +[https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq](插件开发文档)。 -## node 版本 - -v14.4.0 +本地开发需要在 v14.4.0 的 node 环境下进行。 diff --git a/packages/plugin-datasource-pane/TODO.md b/packages/plugin-datasource-pane/TODO.md new file mode 100644 index 000000000..3fbe5ebc5 --- /dev/null +++ b/packages/plugin-datasource-pane/TODO.md @@ -0,0 +1,18 @@ +TODO +--- + +* 多语言 +* ICON +* 支持变量 +* 定制样式 +* 不使用 bind +* 表达式 setter 的联想 +* [later]表达式和其他类型的切换 +* 变量,上下文的提案 +* mock 的提案 + +## 问题 + +* 变量,上下文放数据源里管理是否合适 +* mockUrl 和 mockData +* 设计器的设计语言无法统一 diff --git a/packages/plugin-datasource-pane/build.json b/packages/plugin-datasource-pane/build.json index 49a393b6b..e765b2233 100644 --- a/packages/plugin-datasource-pane/build.json +++ b/packages/plugin-datasource-pane/build.json @@ -1,7 +1,6 @@ { "plugins": [ - [ - "build-plugin-component" - ] + "build-plugin-component", + "build-plugin-fusion" ] } diff --git a/packages/plugin-datasource-pane/src/datasource-form.tsx b/packages/plugin-datasource-pane/src/datasource-form.tsx index 7fc5e9ab6..b4c2170c3 100644 --- a/packages/plugin-datasource-pane/src/datasource-form.tsx +++ b/packages/plugin-datasource-pane/src/datasource-form.tsx @@ -1,5 +1,6 @@ // @todo schema default import React, { PureComponent, ReactElement, FC } from 'react'; +import { Button } from '@alifd/next'; import { SchemaForm, FormButtonGroup, Submit } from '@formily/next'; import { ArrayTable, Input, Switch, NumberPicker } from '@formily/next-components'; import _isPlainObject from 'lodash/isPlainObject'; @@ -164,8 +165,6 @@ export class DataSourceForm extends PureComponent +
    - + 提交 +
    diff --git a/packages/plugin-datasource-pane/src/form-components/param-value.scss b/packages/plugin-datasource-pane/src/form-components/param-value.scss new file mode 100644 index 000000000..97541db8a --- /dev/null +++ b/packages/plugin-datasource-pane/src/form-components/param-value.scss @@ -0,0 +1,7 @@ +.param-value { + display: flex; + flex-direction: row; + .param-value-type { + margin-right: 4px; + } +} diff --git a/packages/plugin-datasource-pane/src/form-components/param-value.tsx b/packages/plugin-datasource-pane/src/form-components/param-value.tsx index 2cb723b37..99d8dee4c 100644 --- a/packages/plugin-datasource-pane/src/form-components/param-value.tsx +++ b/packages/plugin-datasource-pane/src/form-components/param-value.tsx @@ -1,5 +1,5 @@ import React, { PureComponent, ReactElement, FC } from 'react'; -import { Button, Input, Radio, NumberPicker, Switch } from '@alifd/next'; +import { Select, Input, Radio, NumberPicker, Switch } from '@alifd/next'; import { connect } from '@formily/react-schema-renderer'; import _isPlainObject from 'lodash/isPlainObject'; import _isArray from 'lodash/isArray'; @@ -10,21 +10,37 @@ import _get from 'lodash/get'; import _tap from 'lodash/tap'; import { ExpressionSetter } from '@ali/lowcode-editor-setters'; +import './param-value.scss'; + const { Group: RadioGroup } = Radio; +type ParamValueType = 'string' | 'number' | 'boolean' | 'expression'; + export interface ParamValueProps { className: string; value: any; onChange?: () => void; + types: ParamValueType[]; } export interface ParamValueState { type: 'string' | 'number' | 'boolean' | ''; } +const TYPE_LABEL_MAP = { + string: '字符串', + number: '数字', + boolean: '布尔', + expression: '表达式', +}; + class ParamValueComp extends PureComponent { static isFieldComponent = true; + static defaultProps = { + types: ['string', 'boolean', 'number', 'expression'], + }; + state = { type: '', }; @@ -48,7 +64,7 @@ class ParamValueComp extends PureComponent { // @todo 需要再 bind 一次? handleChange = (value) => { this.props?.onChange(value); - } + }; componentDidUpdate(prevProps) { if (this.props.value !== prevProps.value) { @@ -78,19 +94,46 @@ class ParamValueComp extends PureComponent { }); }; + renderTypeSelect = () => { + const { type } = this.state; + const { types } = this.props; + + if (_isArray(types) && types.length > 2) { + return ( + } {type === 'boolean' && } {type === 'number' && } diff --git a/packages/plugin-datasource-pane/src/import-plugins/code.scss b/packages/plugin-datasource-pane/src/import-plugins/code.scss new file mode 100644 index 000000000..a420f7a90 --- /dev/null +++ b/packages/plugin-datasource-pane/src/import-plugins/code.scss @@ -0,0 +1,15 @@ +.lowcode-plugin-datasource-import-plugin-code { + height: unquote("calc(100vh - 48px - 48px - 42px)"); + overflow: auto; + .error-msg { + line-height: 24px; + color: #f60; + font-size: 12px; + } + .btns { + margin-top: 8px; + } + .next-btn { + margin-right: 4px; + } +} diff --git a/packages/plugin-datasource-pane/src/import-plugins/code.tsx b/packages/plugin-datasource-pane/src/import-plugins/code.tsx index a8f1d10ff..4dacccdd6 100644 --- a/packages/plugin-datasource-pane/src/import-plugins/code.tsx +++ b/packages/plugin-datasource-pane/src/import-plugins/code.tsx @@ -14,6 +14,8 @@ import { DataSourceConfig } from '@ali/lowcode-types'; import Ajv from 'ajv'; import { DataSourcePaneImportPluginComponentProps } from '../types'; +import './code.scss'; + export interface DataSourceImportPluginCodeProps extends DataSourcePaneImportPluginComponentProps { defaultValue?: DataSourceConfig[]; } @@ -115,11 +117,11 @@ export class DataSourceImportPluginCode extends PureComponent< const { code, isCodeValid } = this.state; return ( -
    +
    - {!isCodeValid &&

    格式有误

    } -

    + {!isCodeValid &&

    格式有误

    } +

    - +

    ); diff --git a/packages/plugin-datasource-pane/src/index.scss b/packages/plugin-datasource-pane/src/index.scss index 67d1208f6..81a8d5c7b 100644 --- a/packages/plugin-datasource-pane/src/index.scss +++ b/packages/plugin-datasource-pane/src/index.scss @@ -12,7 +12,86 @@ } .lowcode-plugin-datasource-pane-list { - .next-virtual-list-wrapper { - min-height: 400px; + margin: 8px; + .next-search { + width: 100%; + .next-search-left { + height: 28px !important; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + .next-before { + height: 28px !important; + .next-select { + height: 28px !important; + } + } + .next-search-input { + height: 28px !important; + input { + height: 28px !important; + } + } + .next-input { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + .next-after { + // height: 28px !important; + .next-btn { + height: 30px !important; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + .next-icon:before { + font-size: 12px; + } + } + } + } + .datasource-list { + margin-top: 8px; + height: unquote("calc(100vh - 48px - 48px - 42px - 28px - 8px - 8px)"); + overflow: auto; + .next-virtual-list-wrapper > div > ul > li { + border-top: 1px solid #ddd; + &:first-child { + border-top: none; + } + } + } + .datasource-item { + margin: 8px; + .datasource-item-title { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + height: 28px; + .datasource-item-id { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 12px; + } + .next-btn { + margin-left: 4px; + } + } + .datasource-item-desc { + .next-tag { + margin-right: 4px; + } + } + } +} + +.lowcode-plugin-datasource-form { + height: unquote("calc(100vh - 48px - 48px - 42px)"); + overflow: auto; + .next-form-item { + .next-form-item-control { + + } } } diff --git a/packages/plugin-datasource-pane/src/index.tsx b/packages/plugin-datasource-pane/src/index.tsx index ccde8d705..2f0a3650e 100644 --- a/packages/plugin-datasource-pane/src/index.tsx +++ b/packages/plugin-datasource-pane/src/index.tsx @@ -4,6 +4,8 @@ import { DataSourcePane } from './pane'; import { DataSourcePaneImportPlugin, DataSourceType } from './types'; import { DataSourceImportPluginCode } from './import-plugins'; +import './index.scss'; + export { DataSourceImportPluginCode }; const PLUGIN_NAME = 'dataSourcePane'; diff --git a/packages/plugin-datasource-pane/src/list.tsx b/packages/plugin-datasource-pane/src/list.tsx index 4f0ace919..e589ee0df 100644 --- a/packages/plugin-datasource-pane/src/list.tsx +++ b/packages/plugin-datasource-pane/src/list.tsx @@ -64,57 +64,77 @@ export default class DataSourceList extends PureComponent (keyword ? item.id.indexOf(keyword) !== -1 : true)) ?.map((item) => (
  • - - {item.type} - {item.isInit ? '自动' : '手动'} +
    +
    +
    {item.id} - - -
    - } - align="r" - alignEdge - triggerType="hover" - style={{ width: 300 }} - > - ((acc, cur) => { - // @todo 这里的 ts 处理得不好 - if (_isPlainObject(item.options[cur])) { - Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => { - acc.push({ - label: `${cur}.${curInOption}`, - value: (item?.options?.[cur] as any)?.[curInOption], - }); - }); - } else if (!_isNil(item.options[cur])) { - // @todo 排除 null - acc.push({ - label: cur, - value: item.options[cur], - }); - } - return acc; - }, []), console.log)} - > - - ( -
    - - {_isBoolean(val) ? 'bool' : _isNumber(val) ? 'number' : _isPlainObject(val) ? 'obj' : 'string'} - - {val.toString()} -
    - )} - /> -
    - + 详情} + align="b" + alignEdge + triggerType="hover" + style={{ width: 300 }} + > + ((acc, cur) => { + // @todo 这里的 ts 处理得不好 + if (_isPlainObject(item.options[cur])) { + Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => { + acc.push({ + label: `${cur}.${curInOption}`, + value: (item?.options?.[cur] as any)?.[curInOption], + }); + }); + } else if (!_isNil(item.options[cur])) { + // @todo 排除 null + acc.push({ + label: cur, + value: item.options[cur], + }); + } + return acc; + }, []), + console.log, + )} + > + + ( +
    + + {_isBoolean(val) + ? 'bool' + : _isNumber(val) + ? 'number' + : _isPlainObject(val) + ? 'obj' + : 'string'} + + {val.toString()} +
    + )} + /> +
    +
    + + + +
    +
    + {item.type} + {item.isInit ? '自动' : '手动'} +
    +
  • )) || [] ); @@ -136,7 +156,9 @@ export default class DataSourceList extends PureComponent - {this.deriveListDataSource()} +
    + {this.deriveListDataSource()} +
    ); } diff --git a/packages/plugin-datasource-pane/src/pane.tsx b/packages/plugin-datasource-pane/src/pane.tsx index de1b41725..7c71e8508 100644 --- a/packages/plugin-datasource-pane/src/pane.tsx +++ b/packages/plugin-datasource-pane/src/pane.tsx @@ -3,7 +3,7 @@ */ import React, { PureComponent } from 'react'; import { DataSource, DataSourceConfig } from '@ali/lowcode-types'; -import { Tab, Button, MenuButton, Message } from '@alifd/next'; +import { Tab, Button, MenuButton, Message, Dialog } from '@alifd/next'; import _cloneDeep from 'lodash/cloneDeep'; import _uniqueId from 'lodash/uniqueId'; import _startsWith from 'lodash/startsWith'; @@ -63,14 +63,14 @@ export class DataSourcePane extends PureComponent { @@ -83,31 +83,66 @@ export class DataSourcePane extends PureComponent { - this.closeTab(TAB_ITEM_IMPORT); - this.setState( - ({ dataSourceList }) => ({ - dataSourceList: dataSourceList.concat(toImport), - }), - () => { - this.handleDataSourceListChange(); - }, + const importDataSourceList = () => { + this.closeTab(TAB_ITEM_IMPORT); + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.concat(toImport), + }), + () => { + this.handleDataSourceListChange(); + }, + ); + }; + if (!_isArray(toImport) || toImport.length === 0) { + Message.error('没有找到可导入的数据源'); + return; + } + const repeatedDataSourceList = toImport.filter( + item => !!this.state.dataSourceList.find( + dataSource => dataSource.id === item.id + ) ); + if (repeatedDataSourceList.length > 0) { + Dialog.confirm({ + content: `数据源(${repeatedDataSourceList.map(item => item.id).join(',')})已存在,如果导入会替换原数据源,是否继续?`, + onOk: () => { + importDataSourceList(); + } + }); + return; + } + importDataSourceList(); }; handleCreateDataSource = (toCreate: DataSourceConfig) => { - this.closeTab(TAB_ITEM_CREATE); - this.setState( - ({ dataSourceList }) => ({ - dataSourceList: dataSourceList.concat([ - { - ...toCreate, - }, - ]), - }), - () => { - this.handleDataSourceListChange(); - }, - ); + const create = () => { + this.closeTab(TAB_ITEM_CREATE); + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.concat([ + { + ...toCreate, + }, + ]), + }), + () => { + this.handleDataSourceListChange(); + }, + ); + }; + if (this.state.dataSourceList.find( + dataSource => dataSource.id === toCreate.id + )) { + Dialog.confirm({ + content: `数据源(${toCreate.id})已存在,如果导入会替换原数据源,是否继续?`, + onOk: () => { + create(); + } + }); + return; + } + create(); }; handleUpdateDataSource = (toUpdate: DataSourceConfig) => { @@ -130,14 +165,22 @@ export class DataSourcePane extends PureComponent { - this.setState( - ({ dataSourceList }) => ({ - dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId), - }), - () => { - this.handleDataSourceListChange(); - }, - ); + const remove = () => { + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId), + }), + () => { + this.handleDataSourceListChange(); + }, + ); + }; + Dialog.confirm({ + content: `确定要删除吗?`, + onOk: () => { + remove(); + } + }); }; handleDuplicateDataSource = (dataSourceId: string) => { @@ -233,7 +276,7 @@ export class DataSourcePane extends PureComponent 1 ? ( - + {dataSourceTypes.map((type) => ( {type.type} ))} - ) : _isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? ( - + ) : _isArray(dataSourceTypes) && dataSourceTypes.length === 1 ? ( + ) : null, _isArray(importPlugins) && importPlugins.length > 1 ? ( - + {importPlugins.map((plugin) => ( {plugin.name} ))} - ) : _isArray(importPlugins) && importPlugins.length > 1 ? ( + ) : _isArray(importPlugins) && importPlugins.length === 1 ? ( ) : null, ]; diff --git a/packages/plugin-datasource-pane/tsconfig.json b/packages/plugin-datasource-pane/tsconfig.json index 020e1e82f..df5f697e9 100644 --- a/packages/plugin-datasource-pane/tsconfig.json +++ b/packages/plugin-datasource-pane/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "../../tsconfig.json", - "lib": ["es6", "dom"], + "lib": ["esnext", "dom"], "compilerOptions": { "outDir": "lib" }, From 4dd2eefc90ae65b0d1f039e639966bd86782b11a Mon Sep 17 00:00:00 2001 From: "muyun.my" Date: Tue, 22 Sep 2020 11:10:17 +0800 Subject: [PATCH 03/34] fix --- packages/demo/src/editor/config.js | 2 +- packages/plugin-components-pane/package.json | 4 +- packages/plugin-datasource-pane/DEV.md | 5 + packages/plugin-datasource-pane/README.md | 56 +++++- packages/plugin-datasource-pane/TODO.md | 7 +- packages/plugin-datasource-pane/package.json | 10 +- .../src/datasource-form.tsx | 96 +++++----- .../src/form-components/jsfunction.tsx | 44 ++--- .../src/form-components/param-value.tsx | 66 ++++--- .../src/import-plugins/code.tsx | 42 ++--- packages/plugin-datasource-pane/src/index.tsx | 26 ++- packages/plugin-datasource-pane/src/list.tsx | 135 ++++++++------ .../src/locale/index.ts | 8 +- packages/plugin-datasource-pane/src/pane.tsx | 176 ++++++++---------- .../src/types/datasource-type.ts | 4 +- .../src/types/import-plugin.ts | 4 +- 16 files changed, 367 insertions(+), 318 deletions(-) create mode 100644 packages/plugin-datasource-pane/DEV.md diff --git a/packages/demo/src/editor/config.js b/packages/demo/src/editor/config.js index 5965260f8..c929c11fe 100644 --- a/packages/demo/src/editor/config.js +++ b/packages/demo/src/editor/config.js @@ -139,7 +139,7 @@ export default { type: 'PanelIcon', props: { align: 'top', - icon: 'wenjian', + icon: 'shujuyuan', description: '数据源面板', panelProps: { floatable: true, diff --git a/packages/plugin-components-pane/package.json b/packages/plugin-components-pane/package.json index fd27716b6..6da23ef30 100644 --- a/packages/plugin-components-pane/package.json +++ b/packages/plugin-components-pane/package.json @@ -1,7 +1,7 @@ { "name": "@ali/lowcode-plugin-components-pane", - "version": "1.0.7-0", - "description": "alibaba lowcode editor component-list plugin", + "version": "0.1.0-beta.0", + "description": "低代码引擎数据源配置面板", "files": [ "es/", "lib/" diff --git a/packages/plugin-datasource-pane/DEV.md b/packages/plugin-datasource-pane/DEV.md new file mode 100644 index 000000000..7d5e947b5 --- /dev/null +++ b/packages/plugin-datasource-pane/DEV.md @@ -0,0 +1,5 @@ +## 插件开发 + +[https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq](插件开发文档)。 + +本地开发需要在 v14.4.0 的 node 环境下进行。 diff --git a/packages/plugin-datasource-pane/README.md b/packages/plugin-datasource-pane/README.md index 4e0213a43..c8233772b 100644 --- a/packages/plugin-datasource-pane/README.md +++ b/packages/plugin-datasource-pane/README.md @@ -2,9 +2,49 @@ 对页面的数据源进行管理(新建,编辑,导入)。 +一个 pluginProps 的例子 + +``` +{ + importPlugins: [ + { + name: 'code', + title: '源码', + content: DataSourceImportPluginCode, + }, + ], + dataSourceTypes: [ + { + type: 'mopen', + schema: { + type: 'object', + properties: { + options: { + type: 'object', + properties: { + uri: { + title: 'api', + }, + v: { + title: 'v', + type: 'string', + }, + appKey: { + title: 'appKey', + type: 'string', + }, + }, + }, + }, + }, + }, + ], +} +``` + ## 数据源类型定义 -内置 fetch 和 mtop 类型,支持传入自定义类型。 +内置 fetch,mtop,jsonp 类型,支持传入自定义类型。 ``` type DataSourceType = { @@ -29,17 +69,15 @@ interface DataSourcePaneImportPlugin { componentProps?: DataSourcePaneImportPluginCustomProps; } -interface DataSourcePaneImportPluginCustomProps { - [customPropName: string]: any; +interface DataSourcePaneImportPluginComponentProps { + onImport?: (dataSourceList: DataSourceConfig[]) => void; + onCancel?: () => void; + dataSourceTypes?: DataSourceType[]; } -interface DataSourcePaneImportPluginComponentProps extends DataSourcePaneImportPluginCustomProps { - onChange: (dataSourceList: DataSourceConfig[]) => void; +interface DataSourcePaneImportPluginCustomProps extends DataSourcePaneImportPluginComponentProps { + [customPropName: string]: any; } ``` -## 插件开发 -[https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq](插件开发文档)。 - -本地开发需要在 v14.4.0 的 node 环境下进行。 diff --git a/packages/plugin-datasource-pane/TODO.md b/packages/plugin-datasource-pane/TODO.md index 3fbe5ebc5..e5fd18a65 100644 --- a/packages/plugin-datasource-pane/TODO.md +++ b/packages/plugin-datasource-pane/TODO.md @@ -2,14 +2,15 @@ TODO --- * 多语言 -* ICON -* 支持变量 * 定制样式 * 不使用 bind * 表达式 setter 的联想 * [later]表达式和其他类型的切换 + +## 提案 + +* mock * 变量,上下文的提案 -* mock 的提案 ## 问题 diff --git a/packages/plugin-datasource-pane/package.json b/packages/plugin-datasource-pane/package.json index 467a74399..7b27c81d9 100644 --- a/packages/plugin-datasource-pane/package.json +++ b/packages/plugin-datasource-pane/package.json @@ -1,13 +1,14 @@ { "name": "@ali/lowcode-plugin-datasource-pane", - "version": "1.0.7-0", + "version": "0.1.0-beta.3", "description": "低代码引擎数据源面板", "main": "lib/index.js", "files": [ "lib" ], "scripts": { - "build": "tsc", + "build": "build-scripts build", + "cloud-build": "build-scripts build --skip-demo", "test": "ava", "test:snapshot": "ava --update-snapshots" }, @@ -29,6 +30,7 @@ "monaco-editor": "^0.20.0" }, "dependencies": { + "@alib/build-scripts": "^0.1.3", "@ali/lowcode-editor-setters": "^1.0.7-0", "@alifd/next": "^1.20.28", "@formily/next": "^1.3.2", @@ -40,5 +42,9 @@ "react-monaco-editor": "^0.40.0", "styled-components": "^5.2.0", "traverse": "^0.6.6" + }, + "homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-plugin-datasource-pane@0.1.0-beta.1/build/index.html", + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" } } diff --git a/packages/plugin-datasource-pane/src/datasource-form.tsx b/packages/plugin-datasource-pane/src/datasource-form.tsx index b4c2170c3..ecc89632d 100644 --- a/packages/plugin-datasource-pane/src/datasource-form.tsx +++ b/packages/plugin-datasource-pane/src/datasource-form.tsx @@ -1,20 +1,17 @@ // @todo schema default -import React, { PureComponent, ReactElement, FC } from 'react'; +import React, { PureComponent } from 'react'; import { Button } from '@alifd/next'; import { SchemaForm, FormButtonGroup, Submit } from '@formily/next'; import { ArrayTable, Input, Switch, NumberPicker } from '@formily/next-components'; import _isPlainObject from 'lodash/isPlainObject'; import _isArray from 'lodash/isArray'; -import _isNumber from 'lodash/isNumber'; -import _isString from 'lodash/isString'; -import _isBoolean from 'lodash/isBoolean'; import _cloneDeep from 'lodash/cloneDeep'; import _mergeWith from 'lodash/mergeWith'; import _get from 'lodash/get'; -import _tap from 'lodash/tap'; import traverse from 'traverse'; +import { DataSourceConfig } from '@ali/lowcode-types'; import { ParamValue, JSFunction } from './form-components'; -import { DataSourceType, DataSourceConfig } from './types'; +import { DataSourceType } from './types'; // @todo $ref @@ -89,11 +86,11 @@ const SCHEMA = { export interface DataSourceFormProps { dataSourceType: DataSourceType; dataSource?: DataSourceConfig; - omComplete?: (dataSource: DataSourceConfig) => void; + onComplete?: (dataSource: DataSourceConfig) => void; + onCancel?: () => void; } -export interface DataSourceFormState { -} +export type DataSourceFormState = {}; /** * 通过是否存在 ID 来决定读写状态 @@ -101,65 +98,63 @@ export interface DataSourceFormState { export class DataSourceForm extends PureComponent { state = {}; - handleFormSubmit = (formData) => { + handleFormSubmit = (formData: any) => { // @todo mutable? if (_isArray(_get(formData, 'options.params'))) { - formData.options.params = formData.options.params.reduce((acc, cur) => { - if (!cur.name) return; + formData.options.params = formData.options.params.reduce((acc: any, cur: any) => { + if (!cur.name) return acc; acc[cur.name] = cur.value; return acc; }, {}); } if (_isArray(_get(formData, 'options.headers'))) { - formData.options.headers = formData.options.headers.reduce((acc, cur) => { - if (!cur.name) return; + formData.options.headers = formData.options.headers.reduce((acc: any, cur: any) => { + if (!cur.name) return acc; acc[cur.name] = cur.value; return acc; }, {}); } - console.log('submit', formData); - this.props?.onComplete(formData); + // console.log('submit', formData); + this.props.onComplete?.(formData); }; - deriveInitialData = (dataSource = {}) => { + handleCancel = () => { + this.props.onCancel?.(); + }; + + deriveInitialData = (dataSource: object = {}) => { const { dataSourceType } = this.props; - const result = _cloneDeep(dataSource); + const result: any = _cloneDeep(dataSource); if (_isPlainObject(_get(result, 'options.params'))) { - result.options.params = Object.keys(result.options.params).reduce( - (acc, cur) => { - acc.push({ - name: cur, - value: result.options.params[cur] - }); - return acc; - }, - [] - ); + result.options.params = Object.keys(result.options.params).reduce((acc: any, cur: any) => { + acc.push({ + name: cur, + value: result.options.params[cur], + }); + return acc; + }, []); } if (_isPlainObject(_get(result, 'options.headers'))) { - result.options.headers = Object.keys(result.options.headers).reduce( - (acc, cur) => { - acc.push({ - name: cur, - value: result.options.headers[cur] - }); - return acc; - }, - [] - ); + result.options.headers = Object.keys(result.options.headers).reduce((acc: any, cur: any) => { + acc.push({ + name: cur, + value: result.options.headers[cur], + }); + return acc; + }, []); } result.type = dataSourceType.type; return result; - } + }; deriveSchema = () => { const { dataSourceType } = this.props; // @todo 减小覆盖的风险 - const formSchema = _mergeWith({}, SCHEMA, dataSourceType.schema, (objValue, srcValue) => { + const formSchema: any = _mergeWith({}, SCHEMA, dataSourceType.schema, (objValue, srcValue) => { if (_isArray(objValue)) { return srcValue; } @@ -185,16 +180,11 @@ export class DataSourceForm extends PureComponent diff --git a/packages/plugin-datasource-pane/src/form-components/jsfunction.tsx b/packages/plugin-datasource-pane/src/form-components/jsfunction.tsx index 03dbb5cfe..531d8341b 100644 --- a/packages/plugin-datasource-pane/src/form-components/jsfunction.tsx +++ b/packages/plugin-datasource-pane/src/form-components/jsfunction.tsx @@ -1,60 +1,46 @@ -import React, { PureComponent, createRef } from 'react'; -import { Button, Input, Radio, NumberPicker, Switch } from '@alifd/next'; +import React, { PureComponent } from 'react'; import { connect } from '@formily/react-schema-renderer'; -import _isPlainObject from 'lodash/isPlainObject'; -import _isArray from 'lodash/isArray'; -import _isNumber from 'lodash/isNumber'; -import _isString from 'lodash/isString'; -import _isBoolean from 'lodash/isBoolean'; -import _get from 'lodash/get'; -import _tap from 'lodash/tap'; import MonacoEditor, { EditorWillMount } from 'react-monaco-editor'; - -const { Group: RadioGroup } = Radio; +import _noop from 'lodash/noop'; +import { editor } from 'monaco-editor'; export interface JSFunctionProps { className: string; value: any; - onChange?: () => void; + onChange?: (val: any) => void; } -export interface JSFunctionState { -} +export type JSFunctionState = {}; class JSFunctionComp extends PureComponent { static isFieldComponent = true; - private monacoRef = createRef(); + static defaultProps = { + onChange: _noop, + }; - constructor(props) { - super(props); - this.handleEditorChange = this.handleEditorChange.bind(this); - } + private monacoRef: any = null; handleEditorChange = () => { - if (this.monacoRef.current) { - if ( - !(this.monacoRef.current as editor.IStandaloneCodeEditor) - .getModelMarkers() - .find((marker: editor.IMarker) => marker.owner === 'json') - ) { - this.props?.onChange(this.monacoRef.current?.getModels()?.[0]?.getValue()); + if (this.monacoRef) { + if (!(this.monacoRef as any).getModelMarkers().find((marker: editor.IMarker) => marker.owner === 'json')) { + this.props.onChange?.((this.monacoRef as any)?.getModels()?.[0]?.getValue()); } } }; handleEditorWillMount: EditorWillMount = (editor) => { - (this.monacoRef as MutableRefObject).current = editor?.editor; + this.monacoRef = editor?.editor; }; render() { - const { value, onChange } = this.props; + const { value } = this.props; return ( void; + onChange?: (value: any) => void; types: ParamValueType[]; } export interface ParamValueState { - type: 'string' | 'number' | 'boolean' | ''; + type: ParamValueType; } const TYPE_LABEL_MAP = { @@ -41,16 +41,17 @@ class ParamValueComp extends PureComponent { types: ['string', 'boolean', 'number', 'expression'], }; - state = { - type: '', + state: ParamValueState = { + type: 'string', }; - constructor(props) { + constructor(props: ParamValueProps) { super(props); this.state.type = this.getTypeFromValue(this.props.value); } - getTypeFromValue = (value) => { + // @todo + getTypeFromValue = (value: any) => { if (_isBoolean(value)) { return 'boolean'; } else if (_isNumber(value)) { @@ -62,36 +63,38 @@ class ParamValueComp extends PureComponent { }; // @todo 需要再 bind 一次? - handleChange = (value) => { - this.props?.onChange(value); + handleChange = (value: any) => { + this.props?.onChange?.(value); }; - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps: ParamValueProps) { if (this.props.value !== prevProps.value) { this.setState({ - value: this.props.value, type: this.getTypeFromValue(this.props.value), }); } } - handleTypeChange = (type) => { - this.setState(({ value }) => { - let nextValue = value || ''; - if (type === 'string') { - nextValue = nextValue.toString(); - } else if (type === 'number') { - nextValue = nextValue * 1; - } else if (type === 'boolean') { - nextValue = nextValue === 'true' || nextValue; - } else if (type === 'expression') { - nextValue = ''; - } - return { - value: nextValue, - type, - }; - }); + handleTypeChange = (type: string) => { + this.setState( + { + type: type as ParamValueType, + }, + () => { + let nextValue = this.props.value || ''; + const { type } = this.state; + if (type === 'string') { + nextValue = nextValue.toString(); + } else if (type === 'number') { + nextValue = nextValue * 1; + } else if (type === 'boolean') { + nextValue = nextValue === 'true' || nextValue; + } else if (type === 'expression') { + nextValue = ''; + } + this.props.onChange?.(nextValue); + }, + ); }; renderTypeSelect = () => { @@ -107,6 +110,7 @@ class ParamValueComp extends PureComponent { value: item, }))} value={type} + onChange={this.handleTypeChange} /> ); } @@ -134,10 +138,10 @@ class ParamValueComp extends PureComponent { return (
    {this.renderTypeSelect()} - {type === 'string' && } - {type === 'boolean' && } - {type === 'number' && } - {type === 'expression' && } + {type === 'string' && } + {type === 'boolean' && } + {type === 'number' && } + {type === 'expression' && }
    ); } diff --git a/packages/plugin-datasource-pane/src/import-plugins/code.tsx b/packages/plugin-datasource-pane/src/import-plugins/code.tsx index 4dacccdd6..e3141dccb 100644 --- a/packages/plugin-datasource-pane/src/import-plugins/code.tsx +++ b/packages/plugin-datasource-pane/src/import-plugins/code.tsx @@ -1,8 +1,10 @@ +/* eslint-disable @typescript-eslint/indent */ +// @todo 缩进问题 /** * 源码导入插件 * @todo editor 关联 types,并提供详细的出错信息 */ -import React, { PureComponent, createRef, MutableRefObject } from 'react'; +import React, { PureComponent } from 'react'; import { Button } from '@alifd/next'; import _noop from 'lodash/noop'; import _isArray from 'lodash/isArray'; @@ -35,7 +37,7 @@ export class DataSourceImportPluginCode extends PureComponent< type: 'http', id: 'test', }, - ] + ], }; state = { @@ -43,7 +45,7 @@ export class DataSourceImportPluginCode extends PureComponent< isCodeValid: true, }; - private monacoRef = createRef(); + private monacoRef: any; constructor(props: DataSourceImportPluginCodeProps) { super(props); @@ -77,14 +79,12 @@ export class DataSourceImportPluginCode extends PureComponent< }; handleComplete = () => { - if (this.monacoRef.current) { - if ( - !(this.monacoRef.current as editor.IStandaloneCodeEditor) - .getModelMarkers() - .find((marker: editor.IMarker) => marker.owner === 'json') - ) { + if (this.monacoRef) { + if (!this.monacoRef.getModelMarkers().find((marker: editor.IMarker) => marker.owner === 'json')) { this.setState({ isCodeValid: true }); - this.props?.onImport(this.deriveValue(JSON.parse(_last(this.monacoRef.current.getModels()).getValue()))); + const model: any = _last(this.monacoRef.getModels()); + if (!model) return; + this.props.onImport?.(this.deriveValue(JSON.parse(model.getValue()))); return; } } @@ -92,30 +92,28 @@ export class DataSourceImportPluginCode extends PureComponent< }; handleEditorChange = () => { - if (this.monacoRef.current) { - if ( - !(this.monacoRef.current as editor.IStandaloneCodeEditor) - .getModelMarkers() - .find((marker: editor.IMarker) => marker.owner === 'json') - ) { + if (this.monacoRef) { + if (!this.monacoRef.getModelMarkers().find((marker: editor.IMarker) => marker.owner === 'json')) { this.setState({ isCodeValid: true }); } } }; handleEditorWillMount: EditorWillMount = (editor) => { - (this.monacoRef as MutableRefObject).current = editor?.editor; + this.monacoRef = editor?.editor; // @todo 格式化一次 }; - handleCodeChagne = (code) => { + handleCodeChagne = (code: string) => { this.setState({ code }); - } + }; render() { const { onCancel = _noop } = this.props; const { code, isCodeValid } = this.state; + // @todo + // formatOnType formatOnPaste return (
    {!isCodeValid &&

    格式有误

    }

    - +

    ); diff --git a/packages/plugin-datasource-pane/src/index.tsx b/packages/plugin-datasource-pane/src/index.tsx index 2f0a3650e..435e0fad8 100644 --- a/packages/plugin-datasource-pane/src/index.tsx +++ b/packages/plugin-datasource-pane/src/index.tsx @@ -19,9 +19,9 @@ export interface DataSourcePaneState { active: boolean; } -const BUILTIN_DATASOURCE_TYPES = [ +const BUILTIN_DATASOURCE_TYPES: DataSourceType[] = [ { - type: 'http', + type: 'fetch', schema: { type: 'object', properties: { @@ -56,9 +56,25 @@ const BUILTIN_DATASOURCE_TYPES = [ }, }, }, + { + type: 'jsonp', + schema: { + type: 'object', + properties: { + options: { + type: 'object', + properties: { + method: { + enum: ['GET'], + }, + }, + }, + }, + }, + }, ]; -const BUILTIN_IMPORT_PLUGINS = [ +const BUILTIN_IMPORT_PLUGINS: DataSourcePaneImportPlugin[] = [ { name: 'default', title: '源码', @@ -98,7 +114,7 @@ export default class DataSourcePanePlugin extends PureComponent { const { filteredType, keyword } = this.state; - const { dataSource } = this.props; + const { dataSource, dataSourceTypes } = this.props; return ( dataSource @@ -69,63 +76,61 @@ export default class DataSourceList extends PureComponent {item.id} - 详情} - align="b" - alignEdge - triggerType="hover" - style={{ width: 300 }} - > - ((acc, cur) => { - // @todo 这里的 ts 处理得不好 - if (_isPlainObject(item.options[cur])) { - Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => { - acc.push({ - label: `${cur}.${curInOption}`, - value: (item?.options?.[cur] as any)?.[curInOption], - }); - }); - } else if (!_isNil(item.options[cur])) { - // @todo 排除 null - acc.push({ - label: cur, - value: item.options[cur], - }); - } - return acc; - }, []), - console.log, - )} + {!!dataSourceTypes.find((ds) => ds.type === item.type) && ( + 详情} + align="b" + alignEdge + triggerType="hover" + style={{ width: 300 }} > - - ( -
    - - {_isBoolean(val) - ? 'bool' - : _isNumber(val) - ? 'number' - : _isPlainObject(val) - ? 'obj' - : 'string'} - - {val.toString()} -
    +
    ((acc, cur) => { + // @todo 这里的 ts 处理得不好 + if (_isPlainObject(item.options[cur])) { + Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => { + acc.push({ + label: `${cur}.${curInOption}`, + value: (item?.options?.[cur] as any)?.[curInOption], + }); + }); + } else if (!_isNil(item.options[cur])) { + // @todo 排除 null + acc.push({ + label: cur, + value: item.options[cur], + }); + } + return acc; + }, []), + console.log, )} - /> -
    -
    - - + > + + ( +
    + {deriveTypeFromValue(val)} + {val.toString()} +
    + )} + /> + + + )} + {!!dataSourceTypes.find((ds) => ds.type === item.type) && ( + + )} + {!!dataSourceTypes.find((ds) => ds.type === item.type) && ( + + )} @@ -142,6 +147,7 @@ export default class DataSourceList extends PureComponent @@ -149,11 +155,18 @@ export default class DataSourceList extends PureComponent ({ - label: type?.type, - value: type?.type, - }))} + defaultFilterValue={filteredType} + filter={[ + { + label: '全部', + value: '', + }, + ].concat( + dataSourceTypes.map((type) => ({ + label: type?.type, + value: type?.type, + })), + )} onFilterChange={this.handleSearchFilterChange} />
    diff --git a/packages/plugin-datasource-pane/src/locale/index.ts b/packages/plugin-datasource-pane/src/locale/index.ts index 26507f0ef..49de985ed 100644 --- a/packages/plugin-datasource-pane/src/locale/index.ts +++ b/packages/plugin-datasource-pane/src/locale/index.ts @@ -1,10 +1,10 @@ import { createIntl } from '@ali/lowcode-editor-core'; -import en_US from './en-US.json'; -import zh_CN from './zh-CN.json'; +import enUS from './en-US.json'; +import zhCN from './zh-CN.json'; const { intl, intlNode, getLocale, setLocale } = createIntl({ - 'en-US': en_US, - 'zh-CN': zh_CN, + 'en-US': enUS, + 'zh-CN': zhCN, }); export { intl, intlNode, getLocale, setLocale }; diff --git a/packages/plugin-datasource-pane/src/pane.tsx b/packages/plugin-datasource-pane/src/pane.tsx index 7c71e8508..2604c9f9f 100644 --- a/packages/plugin-datasource-pane/src/pane.tsx +++ b/packages/plugin-datasource-pane/src/pane.tsx @@ -6,7 +6,6 @@ import { DataSource, DataSourceConfig } from '@ali/lowcode-types'; import { Tab, Button, MenuButton, Message, Dialog } from '@alifd/next'; import _cloneDeep from 'lodash/cloneDeep'; import _uniqueId from 'lodash/uniqueId'; -import _startsWith from 'lodash/startsWith'; import _isArray from 'lodash/isArray'; import _get from 'lodash/get'; import List from './list'; @@ -29,15 +28,12 @@ export interface DataSourcePaneProps { onSchemaChange?: (schema: DataSource) => void; } -export interface TabItemProps { +export interface TabItem { key: string; title: string; closeable: boolean; - data: any; -} - -export interface TabItem { - tabItemProps: TabItemProps; + data?: any; + content?: any; } export interface DataSourcePaneState { @@ -47,32 +43,18 @@ export interface DataSourcePaneState { } export class DataSourcePane extends PureComponent { - state = { + state: DataSourcePaneState = { dataSourceList: [...(this.props.defaultSchema?.list || [])], tabItems: [ { - tabItemProps: { - key: TAB_ITEM_LIST, - title: '数据源列表', - closeable: false, - }, + key: TAB_ITEM_LIST, + title: '数据源列表', + closeable: false, }, ], activeTabKey: TAB_ITEM_LIST, }; - constructor(props) { - super(props); - // this.handleDataSourceListChange = this.handleDataSourceListChange.bind(this); - // this.handleImportDataSourceList = this.handleImportDataSourceList.bind(this); - // this.handleCreateDataSource = this.handleCreateDataSource.bind(this); - // this.handleUpdateDataSource = this.handleUpdateDataSource.bind(this); - // this.handleRemoveDataSource = this.handleRemoveDataSource.bind(this); - // this.handleDuplicateDataSource = this.handleDuplicateDataSource.bind(this); - // this.handleEditDataSource = this.handleEditDataSource.bind(this); - // this.handleTabChange = this.handleTabChange.bind(this); - } - handleDataSourceListChange = (dataSourceList?: DataSourceConfig[]) => { if (dataSourceList) { this.setState({ dataSourceList }); @@ -99,16 +81,16 @@ export class DataSourcePane extends PureComponent !!this.state.dataSourceList.find( - dataSource => dataSource.id === item.id - ) + (item) => !!this.state.dataSourceList.find((dataSource) => dataSource.id === item.id), ); if (repeatedDataSourceList.length > 0) { Dialog.confirm({ - content: `数据源(${repeatedDataSourceList.map(item => item.id).join(',')})已存在,如果导入会替换原数据源,是否继续?`, + content: `数据源(${repeatedDataSourceList + .map((item) => item.id) + .join(',')})已存在,如果导入会替换原数据源,是否继续?`, onOk: () => { importDataSourceList(); - } + }, }); return; } @@ -131,14 +113,12 @@ export class DataSourcePane extends PureComponent dataSource.id === toCreate.id - )) { + if (this.state.dataSourceList.find((dataSource) => dataSource.id === toCreate.id)) { Dialog.confirm({ content: `数据源(${toCreate.id})已存在,如果导入会替换原数据源,是否继续?`, onOk: () => { create(); - } + }, }); return; } @@ -179,12 +159,13 @@ export class DataSourcePane extends PureComponent { remove(); - } + }, }); }; handleDuplicateDataSource = (dataSourceId: string) => { const target = this.state.dataSourceList.find((item) => item.id === dataSourceId); + if (!target) return; const cloned = _cloneDeep(target); this.openCreateDataSourceTab({ @@ -195,6 +176,7 @@ export class DataSourcePane extends PureComponent { const target = this.state.dataSourceList.find((item) => item.id === dataSourceId); + if (!target) return; const cloned = _cloneDeep(target); this.openEditDataSourceTab({ @@ -207,22 +189,18 @@ export class DataSourcePane extends PureComponent { + openCreateDataSourceTab = (dataSource: DataSourceConfig) => { const { tabItems } = this.state; - const { dataSourceTypes } = this.props; + const { dataSourceTypes = [] } = this.props; - if (!tabItems.find((item) => item.tabItemProps.key === TAB_ITEM_CREATE)) { + if (!tabItems.find((item) => item.key === TAB_ITEM_CREATE)) { this.setState(({ tabItems }) => ({ tabItems: tabItems.concat({ - tabItemProps: { - key: TAB_ITEM_CREATE, - title: `添加数据源`, - closeable: true, - data: { - dataSourceType: dataSourceTypes?.find( - type => type.type === dataSourceTypeName - ), - }, + key: TAB_ITEM_CREATE, + title: `添加数据源`, + closeable: true, + data: { + dataSourceType: dataSourceTypes?.find((type) => type.type === dataSource.type), }, }), })); @@ -232,23 +210,31 @@ export class DataSourcePane extends PureComponent { + this.openCreateDataSourceTab({ + type: dataSourceType, + } as DataSourceConfig); + }; + + handleCreateDataSourceMenuBtnClick = (dataSourceType: string) => { + this.openCreateDataSourceTab({ + type: dataSourceType, + } as DataSourceConfig); + }; + openEditDataSourceTab = (dataSource: DataSourceConfig) => { const { tabItems } = this.state; - const { dataSourceTypes } = this.props; + const { dataSourceTypes = [] } = this.props; - if (!tabItems.find((item) => item.tabItemProps.key === TAB_ITEM_EDIT)) { + if (!tabItems.find((item) => item.key === TAB_ITEM_EDIT)) { this.setState(({ tabItems }) => ({ tabItems: tabItems.concat({ - tabItemProps: { - key: TAB_ITEM_EDIT, - title: '修改数据源', - closeable: true, - data: { - dataSource, - dataSourceType: dataSourceTypes?.find( - type => type.type === dataSource.type - ), - }, + key: TAB_ITEM_EDIT, + title: '修改数据源', + closeable: true, + data: { + dataSource, + dataSourceType: dataSourceTypes?.find((type) => type.type === dataSource.type), }, }), })); @@ -256,22 +242,20 @@ export class DataSourcePane extends PureComponent { + openImportDataSourceTab = (selectedImportPluginName: string) => { const { tabItems } = this.state; const { importPlugins } = this.props; - if (!tabItems.find((item) => item.tabItemProps.key === `${TAB_ITEM_IMPORT}_${selectedImportPluginName}`)) { + if (!tabItems.find((item) => item.key === `${TAB_ITEM_IMPORT}_${selectedImportPluginName}`)) { this.setState(({ tabItems }) => ({ tabItems: tabItems.concat({ - tabItemProps: { - key: TAB_ITEM_IMPORT, - title: `导入数据源-${selectedImportPluginName}`, - closeable: true, - content: _get( - importPlugins?.find((plugin) => selectedImportPluginName === plugin.name), - 'component', - ), - }, + key: TAB_ITEM_IMPORT, + title: `导入数据源-${selectedImportPluginName}`, + closeable: true, + content: _get( + importPlugins?.find((plugin) => selectedImportPluginName === plugin.name), + 'component', + ), }), })); this.setState({ activeTabKey: TAB_ITEM_IMPORT }); @@ -283,11 +267,11 @@ export class DataSourcePane extends PureComponent { this.setState( ({ tabItems }) => ({ - tabItems: tabItems.filter((item) => item.tabItemProps.key !== tabKey), + tabItems: tabItems.filter((item) => item.key !== tabKey), }), () => { this.setState(({ tabItems }) => ({ - activeTabKey: _get(tabItems, '[0].tabItemProps.key') + activeTabKey: _get(tabItems, '[0].key'), })); }, ); @@ -298,14 +282,14 @@ export class DataSourcePane extends PureComponent 1 ? ( - + _isArray(dataSourceTypes) && dataSourceTypes.length > 0 ? ( + {dataSourceTypes.map((type) => ( {type.type} ))} ) : _isArray(dataSourceTypes) && dataSourceTypes.length === 1 ? ( - + ) : null, _isArray(importPlugins) && importPlugins.length > 1 ? ( @@ -322,7 +306,7 @@ export class DataSourcePane extends PureComponent { const { dataSourceList, tabItems } = this.state; - const { dataSourceTypes } = this.props; + const { dataSourceTypes = [] } = this.props; if (tabItemKey === TAB_ITEM_LIST) { return ( @@ -336,16 +320,17 @@ export class DataSourcePane extends PureComponent type.type === data?.dataSource.type); - return ( - - ); + if (dataSourceType) { + return ( + + ); + } } else if (tabItemKey === TAB_ITEM_CREATE) { - const tabItemData = tabItems.find((tabItem) => tabItem.tabItemProps.key === tabItemKey); return ( ); } else if (tabItemKey === TAB_ITEM_IMPORT) { - const tabItemData = tabItems.find((tabItem) => tabItem.tabItemProps.key === tabItemKey); + const tabItemData = tabItems.find((tabItem) => tabItem.key === tabItemKey); if (tabItemData) { - const Content = tabItemData.tabItemProps.content; - return ; + const Content = tabItemData.content; + return ( + + ); } } return null; }; render() { - const { dataSourceList, activeTabKey, tabItems } = this.state; - const { importPlugins, dataSourceTypes } = this.props; + const { activeTabKey, tabItems } = this.state; return (
    @@ -375,10 +365,8 @@ export class DataSourcePane extends PureComponent - {tabItems.map((item) => ( - - {this.renderTabItemContentByKey(item.tabItemProps.key, item.tabItemProps.data)} - + {tabItems.map((item: TabItem) => ( + {this.renderTabItemContentByKey(item.key, item.data)} ))}
    diff --git a/packages/plugin-datasource-pane/src/types/datasource-type.ts b/packages/plugin-datasource-pane/src/types/datasource-type.ts index 88533593f..630f9dc29 100644 --- a/packages/plugin-datasource-pane/src/types/datasource-type.ts +++ b/packages/plugin-datasource-pane/src/types/datasource-type.ts @@ -1,6 +1,6 @@ -import { JSONSchema4 } from '@types/json-schema'; +import { JSONSchema6 } from 'json-schema'; export type DataSourceType = { type: string; - schema: JSONSchema4 + schema: JSONSchema6; }; diff --git a/packages/plugin-datasource-pane/src/types/import-plugin.ts b/packages/plugin-datasource-pane/src/types/import-plugin.ts index f3a999241..074e2f106 100644 --- a/packages/plugin-datasource-pane/src/types/import-plugin.ts +++ b/packages/plugin-datasource-pane/src/types/import-plugin.ts @@ -9,11 +9,11 @@ export interface DataSourcePaneImportPlugin { componentProps?: DataSourcePaneImportPluginCustomProps; } -export interface DataSourcePaneImportPluginCustomProps { +export interface DataSourcePaneImportPluginCustomProps extends DataSourcePaneImportPluginComponentProps { [customPropName: string]: any; } -export interface DataSourcePaneImportPluginComponentProps extends DataSourcePaneImportPluginCustomProps { +export interface DataSourcePaneImportPluginComponentProps { dataSourceTypes: DataSourceType[]; onImport?: (dataSourceList: DataSourceConfig[]) => void; onCancel?: () => void; From a0e5a266d6baee6a6fdf3ac2a00ec8d7704a61c3 Mon Sep 17 00:00:00 2001 From: "muyun.my" Date: Tue, 22 Sep 2020 15:57:04 +0800 Subject: [PATCH 04/34] =?UTF-8?q?fix:=20schema=20=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/plugin-datasource-pane/src/index.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/plugin-datasource-pane/src/index.tsx b/packages/plugin-datasource-pane/src/index.tsx index 435e0fad8..de74cc461 100644 --- a/packages/plugin-datasource-pane/src/index.tsx +++ b/packages/plugin-datasource-pane/src/index.tsx @@ -1,5 +1,7 @@ import React, { PureComponent } from 'react'; -import { PluginProps } from '@ali/lowcode-types'; +import { PluginProps, DataSource } from '@ali/lowcode-types'; +import _get from 'lodash/get'; +import _set from 'lodash/set'; import { DataSourcePane } from './pane'; import { DataSourcePaneImportPlugin, DataSourceType } from './types'; import { DataSourceImportPluginCode } from './import-plugins'; @@ -113,6 +115,18 @@ export default class DataSourcePanePlugin extends PureComponent { + const { editor } = this.props; + + if (editor.get('designer')) { + const docSchema = editor.get('designer').project.currentDocument.schema; + _set(docSchema, 'componentsTree[0].dataSource', schema); + debugger; + editor.get('designer').project.currentDocument.import(docSchema); + console.log('editor schema', editor.get('designer').schema); + } + }; + render() { const { importPlugins, dataSourceTypes = [], editor } = this.props; const { active } = this.state; @@ -126,6 +140,7 @@ export default class DataSourcePanePlugin extends PureComponent ); } From 9a0a44877852f9a6f3fbef7c759f9ca8b18a5285 Mon Sep 17 00:00:00 2001 From: "muyun.my" Date: Tue, 22 Sep 2020 15:57:36 +0800 Subject: [PATCH 05/34] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/plugin-datasource-pane/src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-datasource-pane/src/index.tsx b/packages/plugin-datasource-pane/src/index.tsx index de74cc461..ed77c20ea 100644 --- a/packages/plugin-datasource-pane/src/index.tsx +++ b/packages/plugin-datasource-pane/src/index.tsx @@ -118,10 +118,10 @@ export default class DataSourcePanePlugin extends PureComponent { const { editor } = this.props; + // @TODO 姿势是否最优? if (editor.get('designer')) { const docSchema = editor.get('designer').project.currentDocument.schema; _set(docSchema, 'componentsTree[0].dataSource', schema); - debugger; editor.get('designer').project.currentDocument.import(docSchema); console.log('editor schema', editor.get('designer').schema); } From d115ce0bdc36e6a74ddfac518c3845684a7482b4 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Sat, 10 Oct 2020 09:06:00 +0800 Subject: [PATCH 06/34] feat: add datasource engine & handlers --- packages/datasource-engine/.eslintignore | 1 + packages/datasource-engine/.eslintrc.js | 7 + packages/datasource-engine/.gitignore | 6 + packages/datasource-engine/.prettierrc.js | 4 + packages/datasource-engine/CHANGELOG.md | 30 ++++ packages/datasource-engine/ava.config.js | 8 + packages/datasource-engine/interpret.d.ts | 1 + packages/datasource-engine/interpret.js | 1 + packages/datasource-engine/package.json | 39 +++++ packages/datasource-engine/readme.md | 45 ++++++ packages/datasource-engine/runtime.d.ts | 1 + packages/datasource-engine/runtime.js | 1 + .../src/core/RuntimeDataSourceItem.ts | 144 ++++++++++++++++++ .../datasource-engine/src/core/adapter.ts | 66 ++++++++ packages/datasource-engine/src/core/index.ts | 2 + .../src/core/reloadDataSourceFactory.ts | 64 ++++++++ .../datasource-engine/src/helpers/index.ts | 14 ++ packages/datasource-engine/src/index.ts | 4 + .../src/interpret/DataSourceEngineFactory.ts | 56 +++++++ .../datasource-engine/src/interpret/index.ts | 3 + .../runtime/RuntimeDataSourceEngineFactory.ts | 69 +++++++++ .../datasource-engine/src/runtime/index.ts | 3 + packages/datasource-engine/src/typings.d.ts | 3 + packages/datasource-engine/src/utils.ts | 139 +++++++++++++++++ .../test/_helpers/bind-runtime-context.ts | 25 +++ .../datasource-engine/test/_helpers/delay.ts | 3 + .../datasource-engine/test/_helpers/index.ts | 3 + .../test/_helpers/mock-context.ts | 50 ++++++ .../scenes/p0-0-simplest-defaults/README.md | 3 + .../_datasource-runtime.ts | 15 ++ .../_datasource-schema.ts | 15 ++ .../p0-0-simplest-defaults/_macro-abnormal.ts | 72 +++++++++ .../p0-0-simplest-defaults/_macro-normal.ts | 81 ++++++++++ .../abnormal-interpret.test.ts | 22 +++ .../abnormal-runtime.test.ts | 20 +++ .../normal-interpret.test.ts | 20 +++ .../normal-runtime.test.ts | 20 +++ .../README.md | 3 + .../_datasource-runtime.ts | 33 ++++ .../_datasource-schema.ts | 30 ++++ .../_macro-abnormal.ts | 96 ++++++++++++ .../_macro-normal.ts | 92 +++++++++++ .../abnormal-interpret.test.ts | 22 +++ .../abnormal-runtime.test.ts | 20 +++ .../normal-interpret.test.ts | 20 +++ .../normal-runtime.test.ts | 20 +++ .../test/scenes/p0-0-url-params/README.md | 3 + .../p0-0-url-params/_datasource-runtime.ts | 13 ++ .../p0-0-url-params/_datasource-schema.ts | 13 ++ .../scenes/p0-0-url-params/_macro-normal.ts | 72 +++++++++ .../p0-0-url-params/normal-interpret.test.ts | 20 +++ .../p0-0-url-params/normal-runtime.test.ts | 20 +++ .../p0-1-custom-response-status/README.md | 26 ++++ .../_datasource-runtime.ts | 30 ++++ .../_datasource-schema.ts | 35 +++++ .../_macro-abnormal.ts | 95 ++++++++++++ .../_macro-normal.ts | 96 ++++++++++++ .../abnormal-interpret.test.ts | 21 +++ .../abnormal-runtime.test.ts | 20 +++ .../normal-interpret.test.ts | 20 +++ .../normal-runtime.test.ts | 20 +++ .../snapshots/abnormal-interpret.test.ts.md | 20 +++ .../snapshots/abnormal-interpret.test.ts.snap | Bin 0 -> 274 bytes .../snapshots/abnormal-runtime.test.ts.md | 20 +++ .../snapshots/abnormal-runtime.test.ts.snap | Bin 0 -> 274 bytes .../README.md | 3 + .../_datasource-runtime.ts | 21 +++ .../_datasource-schema.ts | 24 +++ .../_macro-abnormal.ts | 78 ++++++++++ .../_macro-normal.ts | 81 ++++++++++ .../abnormal-interpret.test.ts | 22 +++ .../abnormal-runtime.test.ts | 20 +++ .../normal-interpret.test.ts | 20 +++ .../normal-runtime.test.ts | 20 +++ .../README.md | 3 + .../_datasource-runtime.ts | 30 ++++ .../_datasource-schema.ts | 35 +++++ .../_macro-abnormal.ts | 95 ++++++++++++ .../_macro-normal.ts | 96 ++++++++++++ .../abnormal-interpret.test.ts | 21 +++ .../abnormal-runtime.test.ts | 20 +++ .../normal-interpret.test.ts | 20 +++ .../normal-runtime.test.ts | 20 +++ .../snapshots/abnormal-interpret.test.ts.md | 20 +++ .../snapshots/abnormal-interpret.test.ts.snap | Bin 0 -> 274 bytes .../snapshots/abnormal-runtime.test.ts.md | 20 +++ .../snapshots/abnormal-runtime.test.ts.snap | Bin 0 -> 274 bytes .../README.md | 3 + .../_datasource-runtime.ts | 32 ++++ .../_datasource-schema.ts | 38 +++++ .../_macro-normal.ts | 108 +++++++++++++ .../normal-interpret.test.ts | 20 +++ .../normal-runtime.test.ts | 20 +++ packages/datasource-engine/tsconfig.json | 68 +++++++++ packages/datasource-handlers/.eslintignore | 1 + packages/datasource-handlers/.eslintrc.js | 7 + packages/datasource-handlers/.prettierrc.js | 4 + packages/datasource-handlers/lerna.json | 5 + packages/datasource-handlers/package.json | 9 ++ .../packages/fetch/es/index.d.ts | 2 + .../packages/fetch/es/index.js | 25 +++ .../packages/fetch/package.json | 29 ++++ .../packages/fetch/src/index.ts | 20 +++ .../packages/fetch/tsconfig.json | 10 ++ .../packages/mopen/es/index.d.ts | 5 + .../packages/mopen/es/index.js | 26 ++++ .../packages/mopen/package.json | 29 ++++ .../packages/mopen/src/index.ts | 33 ++++ .../packages/mopen/tsconfig.json | 10 ++ .../packages/mtop/es/index.d.ts | 6 + .../packages/mtop/es/index.js | 35 +++++ .../packages/mtop/package.json | 29 ++++ .../packages/mtop/src/index.ts | 26 ++++ .../packages/mtop/src/typings.d.ts | 11 ++ .../packages/mtop/tsconfig.json | 10 ++ .../packages/universalMtop/es/index.d.ts | 5 + .../packages/universalMtop/es/index.js | 23 +++ .../packages/universalMtop/package.json | 29 ++++ .../packages/universalMtop/src/index.ts | 29 ++++ .../packages/universalMtop/tsconfig.json | 10 ++ .../packages/urlParams/es/index.d.ts | 2 + .../packages/urlParams/es/index.js | 21 +++ .../packages/urlParams/package.json | 29 ++++ .../packages/urlParams/src/index.ts | 15 ++ .../packages/urlParams/tsconfig.json | 10 ++ packages/datasource-handlers/tsconfig.json | 67 ++++++++ 126 files changed, 3470 insertions(+) create mode 100644 packages/datasource-engine/.eslintignore create mode 100644 packages/datasource-engine/.eslintrc.js create mode 100644 packages/datasource-engine/.gitignore create mode 100644 packages/datasource-engine/.prettierrc.js create mode 100644 packages/datasource-engine/CHANGELOG.md create mode 100644 packages/datasource-engine/ava.config.js create mode 100644 packages/datasource-engine/interpret.d.ts create mode 100644 packages/datasource-engine/interpret.js create mode 100644 packages/datasource-engine/package.json create mode 100644 packages/datasource-engine/readme.md create mode 100644 packages/datasource-engine/runtime.d.ts create mode 100644 packages/datasource-engine/runtime.js create mode 100644 packages/datasource-engine/src/core/RuntimeDataSourceItem.ts create mode 100644 packages/datasource-engine/src/core/adapter.ts create mode 100644 packages/datasource-engine/src/core/index.ts create mode 100644 packages/datasource-engine/src/core/reloadDataSourceFactory.ts create mode 100644 packages/datasource-engine/src/helpers/index.ts create mode 100644 packages/datasource-engine/src/index.ts create mode 100644 packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts create mode 100644 packages/datasource-engine/src/interpret/index.ts create mode 100644 packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts create mode 100644 packages/datasource-engine/src/runtime/index.ts create mode 100644 packages/datasource-engine/src/typings.d.ts create mode 100644 packages/datasource-engine/src/utils.ts create mode 100644 packages/datasource-engine/test/_helpers/bind-runtime-context.ts create mode 100644 packages/datasource-engine/test/_helpers/delay.ts create mode 100644 packages/datasource-engine/test/_helpers/index.ts create mode 100644 packages/datasource-engine/test/_helpers/mock-context.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/README.md create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-abnormal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/abnormal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/abnormal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-simplest-defaults/normal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/README.md create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/abnormal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/abnormal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/normal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-url-params/README.md create mode 100644 packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-url-params/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-url-params/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-url-params/normal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/README.md create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-abnormal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/abnormal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/abnormal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/normal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-interpret.test.ts.md create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-interpret.test.ts.snap create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-runtime.test.ts.md create mode 100644 packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-runtime.test.ts.snap create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/README.md create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-abnormal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/abnormal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/abnormal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/normal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/README.md create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-abnormal.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/abnormal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/abnormal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/normal-runtime.test.ts create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-interpret.test.ts.md create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-interpret.test.ts.snap create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-runtime.test.ts.md create mode 100644 packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-runtime.test.ts.snap create mode 100644 packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/README.md create mode 100644 packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/normal-runtime.test.ts create mode 100644 packages/datasource-engine/tsconfig.json create mode 100644 packages/datasource-handlers/.eslintignore create mode 100644 packages/datasource-handlers/.eslintrc.js create mode 100644 packages/datasource-handlers/.prettierrc.js create mode 100644 packages/datasource-handlers/lerna.json create mode 100644 packages/datasource-handlers/package.json create mode 100644 packages/datasource-handlers/packages/fetch/es/index.d.ts create mode 100644 packages/datasource-handlers/packages/fetch/es/index.js create mode 100644 packages/datasource-handlers/packages/fetch/package.json create mode 100644 packages/datasource-handlers/packages/fetch/src/index.ts create mode 100644 packages/datasource-handlers/packages/fetch/tsconfig.json create mode 100644 packages/datasource-handlers/packages/mopen/es/index.d.ts create mode 100644 packages/datasource-handlers/packages/mopen/es/index.js create mode 100644 packages/datasource-handlers/packages/mopen/package.json create mode 100644 packages/datasource-handlers/packages/mopen/src/index.ts create mode 100644 packages/datasource-handlers/packages/mopen/tsconfig.json create mode 100644 packages/datasource-handlers/packages/mtop/es/index.d.ts create mode 100644 packages/datasource-handlers/packages/mtop/es/index.js create mode 100644 packages/datasource-handlers/packages/mtop/package.json create mode 100644 packages/datasource-handlers/packages/mtop/src/index.ts create mode 100644 packages/datasource-handlers/packages/mtop/src/typings.d.ts create mode 100644 packages/datasource-handlers/packages/mtop/tsconfig.json create mode 100644 packages/datasource-handlers/packages/universalMtop/es/index.d.ts create mode 100644 packages/datasource-handlers/packages/universalMtop/es/index.js create mode 100644 packages/datasource-handlers/packages/universalMtop/package.json create mode 100644 packages/datasource-handlers/packages/universalMtop/src/index.ts create mode 100644 packages/datasource-handlers/packages/universalMtop/tsconfig.json create mode 100644 packages/datasource-handlers/packages/urlParams/es/index.d.ts create mode 100644 packages/datasource-handlers/packages/urlParams/es/index.js create mode 100644 packages/datasource-handlers/packages/urlParams/package.json create mode 100644 packages/datasource-handlers/packages/urlParams/src/index.ts create mode 100644 packages/datasource-handlers/packages/urlParams/tsconfig.json create mode 100644 packages/datasource-handlers/tsconfig.json diff --git a/packages/datasource-engine/.eslintignore b/packages/datasource-engine/.eslintignore new file mode 100644 index 000000000..30bc16279 --- /dev/null +++ b/packages/datasource-engine/.eslintignore @@ -0,0 +1 @@ +/node_modules \ No newline at end of file diff --git a/packages/datasource-engine/.eslintrc.js b/packages/datasource-engine/.eslintrc.js new file mode 100644 index 000000000..b33327802 --- /dev/null +++ b/packages/datasource-engine/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: '../../.eslintrc.js', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + 'no-param-reassign': 0 + }, +}; diff --git a/packages/datasource-engine/.gitignore b/packages/datasource-engine/.gitignore new file mode 100644 index 000000000..207b42eba --- /dev/null +++ b/packages/datasource-engine/.gitignore @@ -0,0 +1,6 @@ +/node_modules/ +*.log +.DS_Store +/es/ +/lib/ +/dist \ No newline at end of file diff --git a/packages/datasource-engine/.prettierrc.js b/packages/datasource-engine/.prettierrc.js new file mode 100644 index 000000000..d2db80ead --- /dev/null +++ b/packages/datasource-engine/.prettierrc.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'always', +}; diff --git a/packages/datasource-engine/CHANGELOG.md b/packages/datasource-engine/CHANGELOG.md new file mode 100644 index 000000000..c43546b6a --- /dev/null +++ b/packages/datasource-engine/CHANGELOG.md @@ -0,0 +1,30 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + + +## [0.1.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-datasource-engine@0.1.13...@ali/lowcode-datasource-engine@0.1.14) (2020-09-29) + + + + +**Note:** Version bump only for package @ali/lowcode-datasource-engine + + +## [0.1.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-datasource-engine@0.1.12...@ali/lowcode-datasource-engine@0.1.13) (2020-09-28) + + + + +**Note:** Version bump only for package @ali/lowcode-datasource-engine + + +## 0.1.12 (2020-09-28) + + +### Features + +* 🎸 按 826 对齐结论调整出码和数据源引擎 ([b9a562e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b9a562e)) +* 🎸 添加数据源引擎 ([624e2f8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/624e2f8)) +* 🎸 与国凯的数据源保持一致,将 urlParams 所需的 search 参数直接传入 ([19fabc1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/19fabc1)) diff --git a/packages/datasource-engine/ava.config.js b/packages/datasource-engine/ava.config.js new file mode 100644 index 000000000..987ecb184 --- /dev/null +++ b/packages/datasource-engine/ava.config.js @@ -0,0 +1,8 @@ +export default { + babel: { + compileEnhancements: false, + }, + files: ['./test/core/*.ts', './test/scenes/**/*.test.ts'], + require: ['ts-node/register/transpile-only'], + extensions: ['ts'], +}; diff --git a/packages/datasource-engine/interpret.d.ts b/packages/datasource-engine/interpret.d.ts new file mode 100644 index 000000000..b37fce092 --- /dev/null +++ b/packages/datasource-engine/interpret.d.ts @@ -0,0 +1 @@ +export { create } from './dist/interpret'; diff --git a/packages/datasource-engine/interpret.js b/packages/datasource-engine/interpret.js new file mode 100644 index 000000000..42c42028e --- /dev/null +++ b/packages/datasource-engine/interpret.js @@ -0,0 +1 @@ +module.exports = require('./dist/interpret'); diff --git a/packages/datasource-engine/package.json b/packages/datasource-engine/package.json new file mode 100644 index 000000000..99c775919 --- /dev/null +++ b/packages/datasource-engine/package.json @@ -0,0 +1,39 @@ +{ + "name": "@ali/lowcode-datasource-engine", + "version": "1.0.1", + "main": "dist/index.js", + "files": [ + "dist", + "src", + "interpret*", + "runtime*" + ], + "scripts": { + "build": "rm -rf dist && tsc --outDir ./dist --module esnext", + "test": "ava", + "prepublishOnly": "npm run build" + }, + "typings": "dist/index.d.ts", + "dependencies": { + "@ali/build-success-types": "^0.1.2-alpha.35", + "typescript": "^3.9.7" + }, + "devDependencies": { + "@ali/datasource-engine-universal-mtop-handler": "1.0.0-alpha.2", + "@ali/datasource-engine-url-params-handler": "^1.0.0-alpha.3", + "@ali/lowcode-datasource-http-handler": "^1.0.0-alpha.1", + "@ali/lowcode-datasource-url-params-handler": "^1.0.0-alpha.3", + "@ali/ng-lc-types": "^1.0.0-r2009222d5o6k8r8", + "@ava/babel": "^1.0.1", + "@types/sinon": "^9.0.5", + "ava": "3.11.1", + "get-port": "^5.1.1", + "json5": "^2.1.3", + "sinon": "^9.0.3", + "ts-node": "^8.10.2", + "tslib": "^2.0.1" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + } +} diff --git a/packages/datasource-engine/readme.md b/packages/datasource-engine/readme.md new file mode 100644 index 000000000..d5bcb84d6 --- /dev/null +++ b/packages/datasource-engine/readme.md @@ -0,0 +1,45 @@ +## 关于 @ali/lc-datasource-engine + +低代码引擎数据源核心代码 + +## doc + +[原理介绍](https://yuque.antfin-inc.com/docs/share/6ba9dab7-0712-4302-a5bb-b17d4a5f8505?# 《DataSource Engine》) + + +[fetch流程图](https://yuque.antfin-inc.com/docs/share/e9baef9a-3586-40fc-8708-eaeee0d7937e?# 《fetch 流程》) + + +## 使用 + +```ts +// 面向运行时渲染,直接给 schema +import { create } from '@ali/lowcode-datasource-engine/interpret'; + +// 面向出码,需要给处理过后的内容 +import { create } from '@ali/lowcode-datasource-engine/runtime'; + +// dataSource 可以是 schema 协议内容 或者是运行时的转化后的配置内容 (出码专用) + +// context 上下文(setState 为必选) +const dsf = create(dataSource, context, { + requestHandlersMap: { // 可选参数,以下内容为当前默认的内容 + urlParams: handlersMap.urlParams('?bar=1&test=2'), + mtop: mtophandlers, + }, +}); + + +console.log(dsf.dataSourceMap) // 符合集团协议的 datasourceMap https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#QUSn5 + +dsf.dataSourceMap['id'].load() // 加载 + +dsf.dataSourceMap['id'].status // 获取状态 + +dsf.dataSourceMap['id'].data // 获取数据 + +dsf.dataSourceMap['id'].error // 获取错误信息 + +dsf.reloadDataSource(); // 刷新所有数据源 + +``` diff --git a/packages/datasource-engine/runtime.d.ts b/packages/datasource-engine/runtime.d.ts new file mode 100644 index 000000000..61344f9b4 --- /dev/null +++ b/packages/datasource-engine/runtime.d.ts @@ -0,0 +1 @@ +export { create } from './dist/runtime'; diff --git a/packages/datasource-engine/runtime.js b/packages/datasource-engine/runtime.js new file mode 100644 index 000000000..28f19824a --- /dev/null +++ b/packages/datasource-engine/runtime.js @@ -0,0 +1 @@ +module.exports = require('./dist/runtime/index'); diff --git a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts new file mode 100644 index 000000000..b2dff9bb1 --- /dev/null +++ b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts @@ -0,0 +1,144 @@ +import { + IRuntimeDataSource, + RuntimeDataSourceConfig, + RuntimeDataSourceStatus, + IRuntimeContext, + RequestHandler, + RuntimeOptionsConfig, + UrlParamsHandler, +} from '@ali/build-success-types'; + +class RuntimeDataSourceItem< + TParams extends Record = Record, + TResultData = unknown +> implements IRuntimeDataSource { + private _data?: TResultData; + + private _error?: Error; + + private _status = RuntimeDataSourceStatus.Initial; + + private _dataSourceConfig: RuntimeDataSourceConfig; + + private _request: + | RequestHandler<{ data: TResultData }> + | UrlParamsHandler; + + private _context: IRuntimeContext; + + private _options?: RuntimeOptionsConfig; + + constructor( + dataSourceConfig: RuntimeDataSourceConfig, + request: + | RequestHandler<{ data: TResultData }> + | UrlParamsHandler, + context: IRuntimeContext, + ) { + this._dataSourceConfig = dataSourceConfig; + this._request = request; + this._context = context; + } + + get data() { + return this._data; + } + + get error() { + return this._error; + } + + get status() { + return this._status; + } + + public async load(params?: TParams) { + if (!this._dataSourceConfig) return; + // 考虑没有绑定对应的 handler 的情况 + if (!this._request) { + throw new Error(`no ${this._dataSourceConfig.type} handler provide`); + } + + // TODO: urlParams 有没有更好的处理方式 + if (this._dataSourceConfig.type === 'urlParams') { + const response = await (this._request as UrlParamsHandler)( + this._context, + ); + this._context.setState({ + [this._dataSourceConfig.id]: response, + }); + + this._data = response; + this._status = RuntimeDataSourceStatus.Loaded; + return response; + } + + if (!this._dataSourceConfig.options) { + throw new Error(`${this._dataSourceConfig.id} has no options`); + } + + if (typeof this._dataSourceConfig.options === 'function') { + this._options = this._dataSourceConfig.options(); + } + + // 考虑转换之后是 null 的场景 + if (!this._options) { + throw new Error(`${this._dataSourceConfig.id} options transform error`); + } + + // 临时变量存,每次可能结果不一致,不做缓存 + let shouldFetch = true; + + if (this._dataSourceConfig.shouldFetch) { + if (typeof this._dataSourceConfig.shouldFetch === 'function') { + shouldFetch = this._dataSourceConfig.shouldFetch(); + } else if (typeof this._dataSourceConfig.shouldFetch === 'boolean') { + shouldFetch = this._dataSourceConfig.shouldFetch; + } + } + + if (!shouldFetch) { + this._status = RuntimeDataSourceStatus.Error; + this._error = new Error( + `the ${this._dataSourceConfig.id} request should not fetch, please check the condition`, + ); + return; + } + + // willFetch + this._dataSourceConfig.willFetch!(); + + // 约定如果 params 有内容,直接做替换,如果没有就用默认的 options 的 + if (params && this._options) { + this._options.params = params; + } + + const dataHandler = this._dataSourceConfig.dataHandler!; + const { errorHandler } = this._dataSourceConfig; + + // 调用实际的请求,获取到对应的数据和状态后赋值给当前的 dataSource + try { + this._status = RuntimeDataSourceStatus.Loading; + + // _context 会给传,但是用不用由 handler 说了算 + const result = await (this._request as RequestHandler<{ + data: TResultData; + }>)(this._options, this._context).then(dataHandler, errorHandler); + + // setState + this._context.setState({ + [this._dataSourceConfig.id]: result, + }); + // 结果赋值 + this._data = result; + this._status = RuntimeDataSourceStatus.Loaded; + return this._data; + } catch (error) { + this._error = error; + this._status = RuntimeDataSourceStatus.Error; + throw error; + } + } +} + +export { RuntimeDataSourceItem }; diff --git a/packages/datasource-engine/src/core/adapter.ts b/packages/datasource-engine/src/core/adapter.ts new file mode 100644 index 000000000..b1274b6ae --- /dev/null +++ b/packages/datasource-engine/src/core/adapter.ts @@ -0,0 +1,66 @@ +import { + transformFunction, + getRuntimeValueFromConfig, + getRuntimeJsValue, + buildOptions, + buildShouldFetch, +} from './../utils'; +// 将不同渠道给的 schema 转为 runtime 需要的类型 + +import { + DataSource, + IPageContext, + DataSourceConfig, + RuntimeDataSourceConfig, + DataSourceMap, +} from '@ali/build-success-types'; +import { defaultDataHandler, defaultWillFetch } from '../helpers'; + +const adapt2Runtime = (dataSource: DataSource, context: IPageContext) => { + const { + list: interpretConfigList, + dataHandler: interpretDataHandler, + } = dataSource; + const dataHandler: (dataMap?: DataSourceMap) => void = + interpretDataHandler && + interpretDataHandler.compiled && + transformFunction(interpretDataHandler.compiled, context); + + // 为空判断 + if (!interpretConfigList || !interpretConfigList.length) { + return { + list: [], + dataHandler, + }; + } + const list: RuntimeDataSourceConfig[] = interpretConfigList.map( + (el: DataSourceConfig) => { + return { + id: el.id, + isInit: + getRuntimeValueFromConfig('boolean', el.isInit, context) || true, // 默认 true + isSync: + getRuntimeValueFromConfig('boolean', el.isSync, context) || false, // 默认 false + type: el.type || 'fetch', + willFetch: el.willFetch + ? getRuntimeJsValue(el.willFetch, context) + : defaultWillFetch, + shouldFetch: buildShouldFetch(el, context), + dataHandler: el.dataHandler + ? getRuntimeJsValue(el.dataHandler, context) + : defaultDataHandler, + errorHandler: el.errorHandler + ? getRuntimeJsValue(el.errorHandler, context) + : undefined, + options: buildOptions(el, context), + }; + }, + ); + + return { + list, + dataHandler, + }; +}; + +export { adapt2Runtime }; diff --git a/packages/datasource-engine/src/core/index.ts b/packages/datasource-engine/src/core/index.ts new file mode 100644 index 000000000..846867d09 --- /dev/null +++ b/packages/datasource-engine/src/core/index.ts @@ -0,0 +1,2 @@ +export { RuntimeDataSourceItem } from './RuntimeDataSourceItem'; +export { adapt2Runtime } from './adapter'; diff --git a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts new file mode 100644 index 000000000..ac8776341 --- /dev/null +++ b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts @@ -0,0 +1,64 @@ +import { + RuntimeDataSource, + DataSourceMap, + RuntimeDataSourceConfig, +} from '@ali/build-success-types'; + +export const reloadDataSourceFactory = ( + dataSource: RuntimeDataSource, + dataSourceMap: DataSourceMap, +) => async () => { + const allAsyncLoadings: Array> = []; + + // TODO: 那么,如果有新的类型过来,这个地方怎么处理??? + // 单独处理 urlParams 类型的 + dataSource.list + .filter( + (el: RuntimeDataSourceConfig) => el.type === 'urlParams' && + (typeof el.isInit === 'boolean' ? el.isInit : true), + ) + .forEach((el: RuntimeDataSourceConfig) => { + dataSourceMap[el.id].load(); + }); + + const remainRuntimeDataSourceList = dataSource.list.filter( + (el: RuntimeDataSourceConfig) => el.type !== 'urlParams', + ); + + // 处理并行 + for (const ds of remainRuntimeDataSourceList) { + if (!ds.options) { + continue; + } + if ( + // 需要考虑出码直接不传值的情况 + ds.isInit && + !ds.isSync + ) { + allAsyncLoadings.push(dataSourceMap[ds.id].load()); + } + } + + // 处理串行 + for (const ds of remainRuntimeDataSourceList) { + if (!ds.options) { + continue; + } + + if ( + // 需要考虑出码直接不传值的情况 + ds.isInit && + ds.isSync + ) { + // TODO: 我理解这个异常也应该吃掉的,待确认 + try { + // eslint-disable-next-line no-await-in-loop + await dataSourceMap[ds.id].load(); + } catch (e) { + console.error(e); + } + } + } + + await Promise.allSettled(allAsyncLoadings); +}; diff --git a/packages/datasource-engine/src/helpers/index.ts b/packages/datasource-engine/src/helpers/index.ts new file mode 100644 index 000000000..d13e747f6 --- /dev/null +++ b/packages/datasource-engine/src/helpers/index.ts @@ -0,0 +1,14 @@ +import { DataHandler } from '@ali/build-success-types'; + +function noop() {} + +// 默认的 dataSourceItem 的 dataHandler +export const defaultDataHandler: DataHandler = async (response: { + data: T; +}) => response.data; + +// 默认的 dataSourceItem 的 willFetch +export const defaultWillFetch = noop; + +// 默认的 dataSourceItem 的 shouldFetch +export const defaultShouldFetch = () => true; diff --git a/packages/datasource-engine/src/index.ts b/packages/datasource-engine/src/index.ts new file mode 100644 index 000000000..560958856 --- /dev/null +++ b/packages/datasource-engine/src/index.ts @@ -0,0 +1,4 @@ +import createInterpret from './interpret/DataSourceEngineFactory'; +import createRuntime from './runtime/RuntimeDataSourceEngineFactory'; + +export { createInterpret, createRuntime }; diff --git a/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts b/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts new file mode 100644 index 000000000..a31a5a095 --- /dev/null +++ b/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts @@ -0,0 +1,56 @@ +import { + IRuntimeContext, + IRuntimeDataSource, + DataSource, + RuntimeDataSourceConfig, + RuntimeDataSource, + RequestHandlersMap, +} from '@ali/build-success-types'; + +import { adapt2Runtime } from '../core/adapter'; +import { RuntimeDataSourceItem } from '../core/RuntimeDataSourceItem'; +import { reloadDataSourceFactory } from '../core/reloadDataSourceFactory'; + +// TODO: requestConfig mtop 默认的请求 config 怎么处理? +/** + * @param dataSource + * @param context + */ + +export default ( + dataSource: DataSource, + context: IRuntimeContext, + extraConfig: { + requestHandlersMap: RequestHandlersMap<{ data: unknown }>; + } = { + requestHandlersMap: {}, + }, +) => { + const { requestHandlersMap } = extraConfig; + + const runtimeDataSource: RuntimeDataSource = adapt2Runtime( + dataSource, + context, + ); + + const dataSourceMap = runtimeDataSource.list.reduce( + ( + prev: Record, + current: RuntimeDataSourceConfig, + ) => { + prev[current.id] = new RuntimeDataSourceItem( + current, + // type 协议默认值 fetch + requestHandlersMap[current.type || 'fetch'], + context, + ); + return prev; + }, + {}, + ); + + return { + dataSourceMap, + reloadDataSource: reloadDataSourceFactory(runtimeDataSource, dataSourceMap), + }; +}; diff --git a/packages/datasource-engine/src/interpret/index.ts b/packages/datasource-engine/src/interpret/index.ts new file mode 100644 index 000000000..e139eac42 --- /dev/null +++ b/packages/datasource-engine/src/interpret/index.ts @@ -0,0 +1,3 @@ +import createInterpret from './DataSourceEngineFactory'; + +export const create = createInterpret; diff --git a/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts b/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts new file mode 100644 index 000000000..2a98f1a14 --- /dev/null +++ b/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts @@ -0,0 +1,69 @@ +/* eslint-disable no-nested-ternary */ +import { + IRuntimeContext, + IRuntimeDataSource, + RuntimeDataSourceConfig, + RuntimeDataSource, + RequestHandlersMap, +} from '@ali/build-success-types'; + +import { RuntimeDataSourceItem } from '../core'; +import { reloadDataSourceFactory } from '../core/reloadDataSourceFactory'; +import { + defaultDataHandler, + defaultShouldFetch, + defaultWillFetch, +} from '../helpers'; + +// TODO: requestConfig mtop 默认的请求 config 怎么处理? +/** + * @param dataSource + * @param context + */ +export default ( + dataSource: RuntimeDataSource, + context: IRuntimeContext, + extraConfig: { + requestHandlersMap: RequestHandlersMap<{ data: unknown }>; + } = { + requestHandlersMap: {}, + }, +) => { + const { requestHandlersMap } = extraConfig; + + // TODO: 对于出码类型,需要做一层数据兼容,给一些必要的值设置默认值,先兜底几个必要的 + dataSource.list.forEach((ds) => { + ds.isInit = ds.isInit || true; + ds.isSync = ds.isSync || false; + ds.shouldFetch = !ds.shouldFetch + ? defaultShouldFetch + : typeof ds.shouldFetch === 'function' + ? ds.shouldFetch.bind(context) + : ds.shouldFetch; + ds.willFetch = ds.willFetch ? ds.willFetch.bind(context) : defaultWillFetch; + ds.dataHandler = ds.dataHandler + ? ds.dataHandler.bind(context) + : defaultDataHandler; + }); + + const dataSourceMap = dataSource.list.reduce( + ( + prev: Record, + current: RuntimeDataSourceConfig, + ) => { + prev[current.id] = new RuntimeDataSourceItem( + current, + // type 协议默认值 fetch + requestHandlersMap[current.type || 'fetch'], + context, + ); + return prev; + }, + {}, + ); + + return { + dataSourceMap, + reloadDataSource: reloadDataSourceFactory(dataSource, dataSourceMap), + }; +}; diff --git a/packages/datasource-engine/src/runtime/index.ts b/packages/datasource-engine/src/runtime/index.ts new file mode 100644 index 000000000..8123c7207 --- /dev/null +++ b/packages/datasource-engine/src/runtime/index.ts @@ -0,0 +1,3 @@ +import createRuntime from './RuntimeDataSourceEngineFactory'; + +export const create = createRuntime; diff --git a/packages/datasource-engine/src/typings.d.ts b/packages/datasource-engine/src/typings.d.ts new file mode 100644 index 000000000..d82d18b87 --- /dev/null +++ b/packages/datasource-engine/src/typings.d.ts @@ -0,0 +1,3 @@ +declare module '@ali/mirror-io-client-mopen'; +declare module '@ali/mirror-io-client-mtop'; +declare module '@ali/mirror-io-client-universal-mtop'; diff --git a/packages/datasource-engine/src/utils.ts b/packages/datasource-engine/src/utils.ts new file mode 100644 index 000000000..f39171e96 --- /dev/null +++ b/packages/datasource-engine/src/utils.ts @@ -0,0 +1,139 @@ +/* eslint-disable no-new-func */ +import { + JSExpression, + IRuntimeContext, + CompositeValue, + JSFunction, + JSONObject, + isJSExpression, + DataSourceConfig, + isJSFunction, +} from '@ali/build-success-types'; + +export const transformExpression = (code: string, context: IRuntimeContext) => { + try { + return new Function(`return (${code})`).call(context); + } catch (error) { + console.error( + `transformExpression error, code is ${code}, context is ${context}, error is ${error}`, + ); + } +}; + +export const transformFunction = (code: string, context: IRuntimeContext) => { + try { + return new Function(`return (${code})`).call(context).bind(context); + } catch (error) { + console.error( + `transformFunction error, code is ${code}, context is ${context}, error is ${error}`, + ); + } +}; + +export const transformBoolStr = (str: string) => { + return str !== 'false'; +}; + +export const getRuntimeJsValue = ( + value: JSExpression | JSFunction, + context: IRuntimeContext, +) => { + if (!['JSExpression', 'JSFunction'].includes(value.type)) { + console.error(`translate error, value is ${JSON.stringify(value)}`); + return ''; + } + const code = value.compiled || value.value; + return value.type === 'JSFunction' + ? transformFunction(code, context) + : transformExpression(code, context); +}; + +export const getRuntimeBaseValue = (type: string, value: any) => { + switch (type) { + case 'string': + return `${value}`; + case 'boolean': + return typeof value === 'string' + ? transformBoolStr(value as string) + : value; + case 'number': + return Number(value); + default: + return value; + } +}; + +export const getRuntimeValueFromConfig = ( + type: string, + value: CompositeValue, + context: IRuntimeContext, +) => { + if (!value) return undefined; + if (isJSExpression(value) || isJSFunction(value)) { + return getRuntimeBaseValue(type, getRuntimeJsValue(value, context)); + } + return getRuntimeBaseValue(type, value); +}; + +export const buildJsonObj = ( + params: JSONObject | JSExpression, + context: IRuntimeContext, +) => { + const result: Record = {}; + if (isJSExpression(params)) { + return transformExpression(params.value, context); + } + Object.keys(params).forEach((key: string) => { + const currentParam: any = params[key]; + if (isJSExpression(currentParam)) { + result[key] = transformExpression(currentParam.value, context); + } else { + result[key] = getRuntimeBaseValue(currentParam.type, currentParam.value); + } + }); + + return result; +}; + +export const buildShouldFetch = ( + ds: DataSourceConfig, + context: IRuntimeContext, +) => { + if (!ds.options || !ds.shouldFetch) { + return true; // 默认为 true + } + if (isJSExpression(ds.shouldFetch) || isJSFunction(ds.shouldFetch)) { + return getRuntimeJsValue(ds.shouldFetch, context); + } + + return getRuntimeBaseValue('boolean', ds.shouldFetch); +}; + +export const buildOptions = ( + ds: DataSourceConfig, + context: IRuntimeContext, +) => { + const { options } = ds; + if (!options) return undefined; + return function () { + return { + uri: getRuntimeValueFromConfig('string', options.uri, context), + params: options.params ? buildJsonObj(options.params, context) : {}, + method: options.method + ? getRuntimeValueFromConfig('string', options.method, context) + : 'GET', + isCors: options.isCors + ? getRuntimeValueFromConfig('boolean', options.isCors, context) + : true, + timeout: options.timeout + ? getRuntimeValueFromConfig('number', options.timeout, context) + : 5000, + headers: options.headers + ? buildJsonObj(options.headers, context) + : undefined, + v: options.v + ? getRuntimeValueFromConfig('string', options.v, context) + : '1.0', + }; + }; +}; diff --git a/packages/datasource-engine/test/_helpers/bind-runtime-context.ts b/packages/datasource-engine/test/_helpers/bind-runtime-context.ts new file mode 100644 index 000000000..d8c4d471e --- /dev/null +++ b/packages/datasource-engine/test/_helpers/bind-runtime-context.ts @@ -0,0 +1,25 @@ +export function bindRuntimeContext(x: T, ctx: U): T { + if (typeof x === 'function') { + return x.bind(ctx); + } + + if (typeof x !== 'object') { + return x; + } + + if (x === null) { + return null; + } + + if (Array.isArray(x)) { + return (x.map((item) => bindRuntimeContext(item, ctx)) as unknown) as T; + } + + const res = {} as Record; + + Object.entries(x).forEach(([k, v]) => { + res[k] = bindRuntimeContext(v, ctx); + }); + + return (res as unknown) as T; +} diff --git a/packages/datasource-engine/test/_helpers/delay.ts b/packages/datasource-engine/test/_helpers/delay.ts new file mode 100644 index 000000000..81b6039c3 --- /dev/null +++ b/packages/datasource-engine/test/_helpers/delay.ts @@ -0,0 +1,3 @@ +export async function delay(ms: number = 0) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/packages/datasource-engine/test/_helpers/index.ts b/packages/datasource-engine/test/_helpers/index.ts new file mode 100644 index 000000000..3ef1ff216 --- /dev/null +++ b/packages/datasource-engine/test/_helpers/index.ts @@ -0,0 +1,3 @@ +export * from './mock-context'; +export * from './delay'; +export * from './bind-runtime-context'; diff --git a/packages/datasource-engine/test/_helpers/mock-context.ts b/packages/datasource-engine/test/_helpers/mock-context.ts new file mode 100644 index 000000000..f602489de --- /dev/null +++ b/packages/datasource-engine/test/_helpers/mock-context.ts @@ -0,0 +1,50 @@ +import { IDataSourceEngine, IRuntimeContext } from '@ali/build-success-types'; + +export class MockContext> + implements IRuntimeContext { + private _dataSourceEngine: IDataSourceEngine; + + public constructor( + private _state: TState, + private _createDataSourceEngine: ( + context: IRuntimeContext + ) => IDataSourceEngine, + private _customMethods: Record any> = {} + ) { + this._dataSourceEngine = _createDataSourceEngine(this); + + // 自定义方法 + Object.assign(this, _customMethods); + } + + public get state() { + return this._state; + } + + public setState(state: Partial) { + this._state = { + ...this._state, + ...state, + }; + } + + public get dataSourceMap() { + return this._dataSourceEngine.dataSourceMap; + } + + public async reloadDataSource(): Promise { + this._dataSourceEngine.reloadDataSource(); + } + + public get page(): any { + throw new Error('this.page should not be accessed by datasource-engine'); + } + + public get component(): any { + throw new Error( + 'this.component should not be accessed by datasource-engine' + ); + } + + [customMethod: string]: any; +} diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/README.md b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/README.md new file mode 100644 index 000000000..e7ab03e28 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/README.md @@ -0,0 +1,3 @@ +# 关于此场景 + +这个是一个及其简单的场景 -- 就是直接调用 fetch,没有啥 dataHandler 之类的 diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-runtime.ts new file mode 100644 index 000000000..ccb41e1f0 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-runtime.ts @@ -0,0 +1,15 @@ +import { RuntimeDataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'user', + type: 'fetch', + options: () => ({ + uri: 'https://mocks.alibaba-inc.com/user.json', + }), + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-schema.ts new file mode 100644 index 000000000..7218c7864 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-schema.ts @@ -0,0 +1,15 @@ +import { DataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: DataSource = { + list: [ + { + id: 'user', + type: 'fetch', + options: { + uri: 'https://mocks.alibaba-inc.com/user.json', + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-abnormal.ts new file mode 100644 index 000000000..4a2297aa0 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-abnormal.ts @@ -0,0 +1,72 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { delay, MockContext } from '../../_helpers'; +// import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const abnormalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async () => { + await delay(100); + throw new Error(ERROR_MSG); + }); + + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该失败了,error 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, undefined); + t.not(context.dataSourceMap.user.error, undefined); + t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); + + // 检查状态数据 + t.assert(setState.notCalled); + t.deepEqual(context.state.user, undefined); + + // fetchHandler 不应该被调 + t.assert(fetchHandler.calledOnce); +}; + +abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-normal.ts new file mode 100644 index 000000000..7115ab1eb --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-normal.ts @@ -0,0 +1,81 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { data: USER_DATA }; + }); + + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + // 检查调用参数 + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/abnormal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/abnormal-interpret.test.ts new file mode 100644 index 000000000..816523b10 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/abnormal-interpret.test.ts @@ -0,0 +1,22 @@ +import test, { ExecutionContext } from 'ava'; +import sinon from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { abnormalScene } from './_macro-abnormal'; + +import type { SinonFakeTimers } from 'sinon'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/abnormal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/abnormal-runtime.test.ts new file mode 100644 index 000000000..c338af3b1 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/abnormal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { abnormalScene } from './_macro-abnormal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/README.md b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/README.md new file mode 100644 index 000000000..3aa7d33e4 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/README.md @@ -0,0 +1,3 @@ +# 关于此场景 + +有些场景下,多个数据源之间有依赖关系,这时候可以将其都设置为 `isSync: true`, 这样这些数据源就会按配置面板的顺序进行串行调用。 diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-runtime.ts new file mode 100644 index 000000000..09e244a38 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-runtime.ts @@ -0,0 +1,33 @@ +import { RuntimeDataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + isSync: true, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/user.json', + }; + }, + }, + { + id: 'orders', + isInit: true, + type: 'fetch', + isSync: true, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/orders.json', + params: { + userId: this.state.user.id, + }, + }; + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-schema.ts new file mode 100644 index 000000000..e4e549ece --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-schema.ts @@ -0,0 +1,30 @@ +import { DataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: DataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + isSync: true, + options: { + uri: 'https://mocks.alibaba-inc.com/user.json', + }, + }, + { + id: 'orders', + isInit: true, + type: 'fetch', + isSync: true, + options: { + uri: 'https://mocks.alibaba-inc.com/orders.json', + params: { + type: 'JSExpression', + value: '{ userId: this.state.user.id }', + }, + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts new file mode 100644 index 000000000..fc0aaa0b3 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts @@ -0,0 +1,96 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const abnormalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const USER_DATA = { + id: 9527, + name: 'Alice', + }; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async ({ uri }) => { + await delay(100); + if (/user/.test(uri)) { + return { data: USER_DATA }; + } else { + throw new Error(ERROR_MSG); + } + }); + + const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(50); + + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后 user 应该成功了,loaded + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + // 最后 orders 应该失败了,error 状态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.is(context.dataSourceMap.user.error, undefined); + t.deepEqual(context.dataSourceMap.orders.data, undefined); + t.not(context.dataSourceMap.orders.error, undefined); + t.regex(context.dataSourceMap.orders.error!.message, new RegExp(ERROR_MSG)); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + t.is(context.state.orders, undefined); + + // fetchHandler 应该被调用了2次 + t.assert(fetchHandler.calledTwice); + + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + // 检查调用参数 + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); +}; + +abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-normal.ts new file mode 100644 index 000000000..2587c08b3 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-normal.ts @@ -0,0 +1,92 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const USER_DATA = { + id: 9527, + name: 'Alice', + }; + + const ORDERS_DATA = [{ id: 123 }, { id: 456 }]; + + const fetchHandler = sinon.fake(async ({ uri }) => { + await delay(100); + return { data: /user/.test(uri) ? USER_DATA : ORDERS_DATA }; + }); + + const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(50); + + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + t.deepEqual(context.dataSourceMap.orders.data, ORDERS_DATA); + t.deepEqual(context.dataSourceMap.orders.error, undefined); + + // 检查状态数据 + t.assert(setState.calledTwice); + t.deepEqual(context.state.user, USER_DATA); + t.deepEqual(context.state.orders, ORDERS_DATA); + + // fetchHandler 应该被调用了2次 + t.assert(fetchHandler.calledTwice); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/abnormal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/abnormal-interpret.test.ts new file mode 100644 index 000000000..816523b10 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/abnormal-interpret.test.ts @@ -0,0 +1,22 @@ +import test, { ExecutionContext } from 'ava'; +import sinon from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { abnormalScene } from './_macro-abnormal'; + +import type { SinonFakeTimers } from 'sinon'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/abnormal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/abnormal-runtime.test.ts new file mode 100644 index 000000000..c338af3b1 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/abnormal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { abnormalScene } from './_macro-abnormal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/README.md b/packages/datasource-engine/test/scenes/p0-0-url-params/README.md new file mode 100644 index 000000000..e7ab03e28 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/README.md @@ -0,0 +1,3 @@ +# 关于此场景 + +这个是一个及其简单的场景 -- 就是直接调用 fetch,没有啥 dataHandler 之类的 diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-runtime.ts new file mode 100644 index 000000000..2f58b64e0 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-runtime.ts @@ -0,0 +1,13 @@ +import { RuntimeDataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'urlParams', + isInit: true, + type: 'urlParams', + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-schema.ts new file mode 100644 index 000000000..9b00b9300 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-schema.ts @@ -0,0 +1,13 @@ +import { DataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: DataSource = { + list: [ + { + id: 'urlParams', + isInit: true, + type: 'urlParams', + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-0-url-params/_macro-normal.ts new file mode 100644 index 000000000..4b0b9bc06 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/_macro-normal.ts @@ -0,0 +1,72 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { MockContext } from '../../_helpers'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const URL_PARAMS = { + name: 'Alice', + age: '18', + }; + + const urlParamsHandler = sinon.fake(async () => { + return URL_PARAMS; // TODO: 别的都是返回的套了一层 data 的,但是 urlParams 的为啥不一样? + }); + + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + urlParams: urlParamsHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.urlParams.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.urlParams.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.urlParams.data, URL_PARAMS); + t.deepEqual(context.dataSourceMap.urlParams.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.urlParams, URL_PARAMS); + + // fetchHandler 应该被调用了一次 + t.assert(urlParamsHandler.calledOnce); + + // 检查调用参数 url 没有 options + t.deepEqual(urlParamsHandler.firstCall.args, [context]); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-0-url-params/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-0-url-params/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/README.md b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/README.md new file mode 100644 index 000000000..cccb18844 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/README.md @@ -0,0 +1,26 @@ +# 关于此场景 + +这个是一个很常见的场景 -- 查出来的数据里面套的还有一层数据,可能有异常状态得需要处理下。 + +比如,期望的正常的数据应该是: + +```json +{ + "success": true, + "data": { + // ... + } +} +``` + +而异常场景下,服务端会返回: + +```json +{ + "success": false, + "message": "这是错误原因", + "code": "错误码" +} +``` + +-- 这时候期望有异常监控埋点。 diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-runtime.ts new file mode 100644 index 000000000..756adeb83 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-runtime.ts @@ -0,0 +1,30 @@ +import { RuntimeDataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + options: () => ({ + uri: 'https://mocks.alibaba-inc.com/user.json', + }), + dataHandler: function dataHandler(response: any) { + const { data } = response; + if (!data) { + throw new Error('empty data!'); + } + + if (data.success) { + return data.data; + } + + this.recordError({ type: 'FETCH_ERROR', detail: data }); + + throw new Error(data.message); + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-schema.ts new file mode 100644 index 000000000..111cf641f --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-schema.ts @@ -0,0 +1,35 @@ +import { DataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: DataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + options: { + uri: 'https://mocks.alibaba-inc.com/user.json', + }, + dataHandler: { + type: 'JSFunction', + value: ` +function dataHandler(response){ + const { data } = response; + if (!data) { + throw new Error('empty data!'); + } + + if (data.success){ + return data.data; + } + + this.recordError({ type: 'FETCH_ERROR', detail: data }); + + throw new Error(data.message); +} +`, + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-abnormal.ts new file mode 100644 index 000000000..757aaba6e --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-abnormal.ts @@ -0,0 +1,95 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const abnormalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: { + success: false, + message: ERROR_MSG, + code: 'E_FOO', + }, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() {}, + }, + ); + + const setState = sinon.spy(context, 'setState'); + const recordError = sinon.spy(context, 'recordError'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该失败了,error 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, undefined); + t.not(context.dataSourceMap.user.error, undefined); + + t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); + + // 检查状态数据 + t.assert(setState.notCalled); + t.deepEqual(context.state.user, undefined); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + + // 埋点应该也会被调用 + t.assert(recordError.calledOnce); + t.snapshot(recordError.firstCall.args); +}; + +abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-normal.ts new file mode 100644 index 000000000..d00fa39d9 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-normal.ts @@ -0,0 +1,96 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: { + success: true, + data: USER_DATA, + }, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() {}, + }, + ); + + const setState = sinon.spy(context, 'setState'); + const recordError = sinon.spy(context, 'recordError'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + + // 埋点不应该被调用 + t.assert(recordError.notCalled); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/abnormal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/abnormal-interpret.test.ts new file mode 100644 index 000000000..7f3169a50 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/abnormal-interpret.test.ts @@ -0,0 +1,21 @@ +import test, { ExecutionContext } from 'ava'; +import sinon from 'sinon'; + +import { create } from '../../../src/interpret'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { abnormalScene } from './_macro-abnormal'; + +import type { SinonFakeTimers } from 'sinon'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/abnormal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/abnormal-runtime.test.ts new file mode 100644 index 000000000..c338af3b1 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/abnormal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { abnormalScene } from './_macro-abnormal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-interpret.test.ts.md b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-interpret.test.ts.md new file mode 100644 index 000000000..5baeac319 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-interpret.test.ts.md @@ -0,0 +1,20 @@ +# Snapshot report for `test/scenes/custom-response-status/abnormal-interpret.test.ts` + +The actual snapshot is saved in `abnormal-interpret.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## abnormal scene + +> Snapshot 1 + + [ + { + detail: { + code: 'E_FOO', + message: 'test error', + success: false, + }, + type: 'FETCH_ERROR', + }, + ] diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-interpret.test.ts.snap b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-interpret.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..6a9794bde2dd0e5ca70c5439fb81d97ebf958f80 GIT binary patch literal 274 zcmV+t0qy=lRzVZO*LU;00AE$#mvACW;1dyGU)(mBOn%LWD{g$bu21M ztYl<_vH1D<85p@37#SHDxfvO4V49fIfpjhqx56~C`6p$iCYLZW!I=UA0t}4242(<+ zjC_oYYk>+y7?~LuS%C^tQcDsua~K%;fqI!>qAVqq1*tF&x0`E-vq!vZP>_ER$U>Go zK>d$^m<8y1Jw`N3nK3M7MmIb;KLu_$t82WQzdxD^_T1Fs;>2{gBCe9u;u3|_qN4mF Ybd|-W$;m*)U_O%o0LO-s0c-&P0I>aR-2eap literal 0 HcmV?d00001 diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-runtime.test.ts.md b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-runtime.test.ts.md new file mode 100644 index 000000000..7c65d528f --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-runtime.test.ts.md @@ -0,0 +1,20 @@ +# Snapshot report for `test/scenes/p0-1-custom-response-status/abnormal-runtime.test.ts` + +The actual snapshot is saved in `abnormal-runtime.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## abnormal scene + +> Snapshot 1 + + [ + { + detail: { + code: 'E_FOO', + message: 'test error', + success: false, + }, + type: 'FETCH_ERROR', + }, + ] diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-runtime.test.ts.snap b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/snapshots/abnormal-runtime.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..6a9794bde2dd0e5ca70c5439fb81d97ebf958f80 GIT binary patch literal 274 zcmV+t0qy=lRzVZO*LU;00AE$#mvACW;1dyGU)(mBOn%LWD{g$bu21M ztYl<_vH1D<85p@37#SHDxfvO4V49fIfpjhqx56~C`6p$iCYLZW!I=UA0t}4242(<+ zjC_oYYk>+y7?~LuS%C^tQcDsua~K%;fqI!>qAVqq1*tF&x0`E-vq!vZP>_ER$U>Go zK>d$^m<8y1Jw`N3nK3M7MmIb;KLu_$t82WQzdxD^_T1Fs;>2{gBCe9u;u3|_qN4mF Ybd|-W$;m*)U_O%o0LO-s0c-&P0I>aR-2eap literal 0 HcmV?d00001 diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/README.md b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/README.md new file mode 100644 index 000000000..d2eb4a470 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/README.md @@ -0,0 +1,3 @@ +# 关于此场景 + +有些数据源的错误可以忽略(吃掉)-- 通过 dataHandler 捕获 error,只要其不重新抛出 error 而且不返回 rejected 状态的 Promise. diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-runtime.ts new file mode 100644 index 000000000..2608841e1 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-runtime.ts @@ -0,0 +1,21 @@ +import { RuntimeDataSource } from '@ali/build-success-types'; + +export const DEFAULT_USER_DATA = { id: 0, name: 'guest' }; // 返回一个兜底的数据 + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + options: () => ({ + uri: 'https://mocks.alibaba-inc.com/user.json', + }), + dataHandler: function dataHandler(response: any) { + return response.data; + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-schema.ts new file mode 100644 index 000000000..b9b44cc6a --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-schema.ts @@ -0,0 +1,24 @@ +import { DataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: DataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + options: { + uri: 'https://mocks.alibaba-inc.com/user.json', + }, + dataHandler: { + type: 'JSFunction', + value: ` +function dataHandler(response) { + return response.data; +} +`, + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-abnormal.ts new file mode 100644 index 000000000..1c1e5d800 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-abnormal.ts @@ -0,0 +1,78 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const abnormalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async () => { + await delay(100); + throw new Error(ERROR_MSG); + }); + + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 注意 error 是会被吃掉了,还是 loaded 状态 + // FIXME: 根据协议内容,dataHandler 返回的结果是需要抛出错误的,那么 fetchHandler 的错误难道不需要处理? + // TODO: 提案:request 如果挂了,不应该需要走 dataHandler 了,没有意义 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, undefined); + t.not(context.dataSourceMap.user.error, undefined); + t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); + + // 检查状态数据 + t.assert(setState.notCalled); + + // fetchHandler 应该没调 + t.assert.skip(fetchHandler.notCalled); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); +}; + +abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-normal.ts new file mode 100644 index 000000000..78aa87c61 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-normal.ts @@ -0,0 +1,81 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { data: USER_DATA }; + }); + + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/abnormal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/abnormal-interpret.test.ts new file mode 100644 index 000000000..816523b10 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/abnormal-interpret.test.ts @@ -0,0 +1,22 @@ +import test, { ExecutionContext } from 'ava'; +import sinon from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { abnormalScene } from './_macro-abnormal'; + +import type { SinonFakeTimers } from 'sinon'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/abnormal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/abnormal-runtime.test.ts new file mode 100644 index 000000000..c338af3b1 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/abnormal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { abnormalScene } from './_macro-abnormal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/README.md b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/README.md new file mode 100644 index 000000000..4f8590da4 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/README.md @@ -0,0 +1,3 @@ +# 关于此场景 + +某些场景下 dataHandler 不能同步返回,比如可能需要读取某个特殊的异步的数据源并合并响应数据。 diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-runtime.ts new file mode 100644 index 000000000..5dc07956a --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-runtime.ts @@ -0,0 +1,30 @@ +import { RuntimeDataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + options: () => ({ + uri: 'https://mocks.alibaba-inc.com/user.json', + }), + dataHandler: async function dataHandler(response: any) { + const { data } = response; + if (!data) { + throw new Error('empty data!'); + } + + if (data.success) { + return data.data; + } + + this.recordError({ type: 'FETCH_ERROR', detail: data }); + + throw new Error(data.message); + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-schema.ts new file mode 100644 index 000000000..f35743828 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-schema.ts @@ -0,0 +1,35 @@ +import { DataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: DataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + options: { + uri: 'https://mocks.alibaba-inc.com/user.json', + }, + dataHandler: { + type: 'JSFunction', + value: ` +async function dataHandler(response){ + const { data } = response; + if (!data) { + throw new Error('empty data!'); + } + + if (data.success){ + return data.data; + } + + this.recordError({ type: 'FETCH_ERROR', detail: data }); + + throw new Error(data.message); +} +`, + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-abnormal.ts new file mode 100644 index 000000000..757aaba6e --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-abnormal.ts @@ -0,0 +1,95 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const abnormalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: { + success: false, + message: ERROR_MSG, + code: 'E_FOO', + }, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() {}, + }, + ); + + const setState = sinon.spy(context, 'setState'); + const recordError = sinon.spy(context, 'recordError'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该失败了,error 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, undefined); + t.not(context.dataSourceMap.user.error, undefined); + + t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); + + // 检查状态数据 + t.assert(setState.notCalled); + t.deepEqual(context.state.user, undefined); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + + // 埋点应该也会被调用 + t.assert(recordError.calledOnce); + t.snapshot(recordError.firstCall.args); +}; + +abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-normal.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-normal.ts new file mode 100644 index 000000000..d00fa39d9 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-normal.ts @@ -0,0 +1,96 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: { + success: true, + data: USER_DATA, + }, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() {}, + }, + ); + + const setState = sinon.spy(context, 'setState'); + const recordError = sinon.spy(context, 'recordError'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + + // 埋点不应该被调用 + t.assert(recordError.notCalled); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/abnormal-interpret.test.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/abnormal-interpret.test.ts new file mode 100644 index 000000000..7f3169a50 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/abnormal-interpret.test.ts @@ -0,0 +1,21 @@ +import test, { ExecutionContext } from 'ava'; +import sinon from 'sinon'; + +import { create } from '../../../src/interpret'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { abnormalScene } from './_macro-abnormal'; + +import type { SinonFakeTimers } from 'sinon'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/abnormal-runtime.test.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/abnormal-runtime.test.ts new file mode 100644 index 000000000..c338af3b1 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/abnormal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { abnormalScene } from './_macro-abnormal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(abnormalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-interpret.test.ts.md b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-interpret.test.ts.md new file mode 100644 index 000000000..558b612d6 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-interpret.test.ts.md @@ -0,0 +1,20 @@ +# Snapshot report for `test/scenes/data-handler-returns-promise/abnormal-interpret.test.ts` + +The actual snapshot is saved in `abnormal-interpret.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## abnormal scene + +> Snapshot 1 + + [ + { + detail: { + code: 'E_FOO', + message: 'test error', + success: false, + }, + type: 'FETCH_ERROR', + }, + ] diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-interpret.test.ts.snap b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-interpret.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..6a9794bde2dd0e5ca70c5439fb81d97ebf958f80 GIT binary patch literal 274 zcmV+t0qy=lRzVZO*LU;00AE$#mvACW;1dyGU)(mBOn%LWD{g$bu21M ztYl<_vH1D<85p@37#SHDxfvO4V49fIfpjhqx56~C`6p$iCYLZW!I=UA0t}4242(<+ zjC_oYYk>+y7?~LuS%C^tQcDsua~K%;fqI!>qAVqq1*tF&x0`E-vq!vZP>_ER$U>Go zK>d$^m<8y1Jw`N3nK3M7MmIb;KLu_$t82WQzdxD^_T1Fs;>2{gBCe9u;u3|_qN4mF Ybd|-W$;m*)U_O%o0LO-s0c-&P0I>aR-2eap literal 0 HcmV?d00001 diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-runtime.test.ts.md b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-runtime.test.ts.md new file mode 100644 index 000000000..98deb8904 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-runtime.test.ts.md @@ -0,0 +1,20 @@ +# Snapshot report for `test/scenes/p1-0-data-handler-returns-promise/abnormal-runtime.test.ts` + +The actual snapshot is saved in `abnormal-runtime.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## abnormal scene + +> Snapshot 1 + + [ + { + detail: { + code: 'E_FOO', + message: 'test error', + success: false, + }, + type: 'FETCH_ERROR', + }, + ] diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-runtime.test.ts.snap b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/snapshots/abnormal-runtime.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..6a9794bde2dd0e5ca70c5439fb81d97ebf958f80 GIT binary patch literal 274 zcmV+t0qy=lRzVZO*LU;00AE$#mvACW;1dyGU)(mBOn%LWD{g$bu21M ztYl<_vH1D<85p@37#SHDxfvO4V49fIfpjhqx56~C`6p$iCYLZW!I=UA0t}4242(<+ zjC_oYYk>+y7?~LuS%C^tQcDsua~K%;fqI!>qAVqq1*tF&x0`E-vq!vZP>_ER$U>Go zK>d$^m<8y1Jw`N3nK3M7MmIb;KLu_$t82WQzdxD^_T1Fs;>2{gBCe9u;u3|_qN4mF Ybd|-W$;m*)U_O%o0LO-s0c-&P0I>aR-2eap literal 0 HcmV?d00001 diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/README.md b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/README.md new file mode 100644 index 000000000..efde6173c --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/README.md @@ -0,0 +1,3 @@ +# 关于此场景 + +某些场景下 shouldFetch 的结果可以影响请求是否被发出去。 diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-runtime.ts new file mode 100644 index 000000000..2085535c6 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-runtime.ts @@ -0,0 +1,32 @@ +import { RuntimeDataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + isSync: true, + options: () => ({ + uri: 'https://mocks.alibaba-inc.com/user.json', + }), + }, + { + id: 'orders', + isInit: true, + type: 'fetch', + isSync: true, + shouldFetch: () => false, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/orders.json', + params: { + userId: this.state.user.id, + }, + }; + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-schema.ts new file mode 100644 index 000000000..e333f485a --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-schema.ts @@ -0,0 +1,38 @@ +import { DataSource } from '@ali/build-success-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: DataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'fetch', + isSync: true, + options: { + uri: 'https://mocks.alibaba-inc.com/user.json', + }, + }, + { + id: 'orders', + isInit: true, + type: 'fetch', + isSync: true, + shouldFetch: { + type: 'JSFunction', + value: ` + function (){ + return false; + } + `, + }, + options: { + uri: 'https://mocks.alibaba-inc.com/orders.json', + params: { + type: 'JSExpression', + value: '{ userId: this.state.user.id }', + }, + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_macro-normal.ts b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_macro-normal.ts new file mode 100644 index 000000000..4289a6d89 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_macro-normal.ts @@ -0,0 +1,108 @@ +import { + DataSource, + IDataSourceEngine, + IRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/build-success-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IRuntimeContext, + options: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | DataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + const ORDERS_ERROR_MSG = + 'the orders request should not fetch, please check the condition'; + + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: USER_DATA, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() {}, + }, + ); + + const setState = sinon.spy(context, 'setState'); + // const recordError = sinon.spy(context, 'recordError'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后 user 成功, orders 失败 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.is(context.dataSourceMap.user.error, undefined); + t.regex( + context.dataSourceMap.orders.error!.message, + new RegExp(ORDERS_ERROR_MSG), + ); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了 1 次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + + // // 埋点应该也会被调用 + // t.assert(recordError.calledOnce); + // t.snapshot(recordError.firstCall.args); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/datasource-engine/tsconfig.json b/packages/datasource-engine/tsconfig.json new file mode 100644 index 000000000..4c30ce1c8 --- /dev/null +++ b/packages/datasource-engine/tsconfig.json @@ -0,0 +1,68 @@ +{ + "compilerOptions": { + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + "jsx": "preserve" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */, + "declaration": true /* Generates corresponding '.d.ts' file. */, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "dist" /* Redirect output structure to the directory. */, + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + "importHelpers": true /* Import emit helpers from 'tslib'. */, + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + "skipLibCheck": true + }, + "include": ["src"] +} diff --git a/packages/datasource-handlers/.eslintignore b/packages/datasource-handlers/.eslintignore new file mode 100644 index 000000000..096746c14 --- /dev/null +++ b/packages/datasource-handlers/.eslintignore @@ -0,0 +1 @@ +/node_modules/ \ No newline at end of file diff --git a/packages/datasource-handlers/.eslintrc.js b/packages/datasource-handlers/.eslintrc.js new file mode 100644 index 000000000..e19c549ba --- /dev/null +++ b/packages/datasource-handlers/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: '../../.eslintrc.js', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + 'no-param-reassign': 0, + }, +}; diff --git a/packages/datasource-handlers/.prettierrc.js b/packages/datasource-handlers/.prettierrc.js new file mode 100644 index 000000000..d2db80ead --- /dev/null +++ b/packages/datasource-handlers/.prettierrc.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'always', +}; diff --git a/packages/datasource-handlers/lerna.json b/packages/datasource-handlers/lerna.json new file mode 100644 index 000000000..b9933894c --- /dev/null +++ b/packages/datasource-handlers/lerna.json @@ -0,0 +1,5 @@ +{ + "packages": ["packages/*"], + "version": "independent", + "npmClient": "yarn" +} diff --git a/packages/datasource-handlers/package.json b/packages/datasource-handlers/package.json new file mode 100644 index 000000000..43cea9f9d --- /dev/null +++ b/packages/datasource-handlers/package.json @@ -0,0 +1,9 @@ +{ + "name": "@ali/lowcode-datasource-handlers", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "devDependencies": { + "lerna": "^3.22.0" + } +} diff --git a/packages/datasource-handlers/packages/fetch/es/index.d.ts b/packages/datasource-handlers/packages/fetch/es/index.d.ts new file mode 100644 index 000000000..443ad0dd1 --- /dev/null +++ b/packages/datasource-handlers/packages/fetch/es/index.d.ts @@ -0,0 +1,2 @@ +import { RuntimeOptionsConfig } from '@ali/build-success-types'; +export declare function createFetchHandler(config?: unknown): (options: RuntimeOptionsConfig) => Promise; diff --git a/packages/datasource-handlers/packages/fetch/es/index.js b/packages/datasource-handlers/packages/fetch/es/index.js new file mode 100644 index 000000000..0b4d6e5ba --- /dev/null +++ b/packages/datasource-handlers/packages/fetch/es/index.js @@ -0,0 +1,25 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import request from 'universal-request'; +// config 留着扩展 +export function createFetchHandler(config) { + return function (options) { + return __awaiter(this, void 0, void 0, function* () { + const requestConfig = Object.assign(Object.assign({}, options), { url: options.uri, method: options.method, data: options.params, headers: options.headers }); + try { + const response = yield request(requestConfig); + return response; + } + catch (error) { + throw error; + } + }); + }; +} diff --git a/packages/datasource-handlers/packages/fetch/package.json b/packages/datasource-handlers/packages/fetch/package.json new file mode 100644 index 000000000..ad28decb4 --- /dev/null +++ b/packages/datasource-handlers/packages/fetch/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ali/lowcode-datasource-fetch-handler", + "version": "1.0.2", + "main": "lib/index.js", + "module": "es/index.js", + "typings": "es/index.d.ts", + "files": [ + "src", + "lib", + "es" + ], + "scripts": { + "dev": "tsc --watch", + "clean": "rm -rf es lib", + "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "typescript": "^3.9.7", + "universal-request": "^2.2.0" + }, + "devDependencies": { + "@ali/build-success-types": "^0.1.2-alpha.35" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + }, + "gitHead": "829e504c52a294fc28966ab0e491f4d2de1d4c90" +} diff --git a/packages/datasource-handlers/packages/fetch/src/index.ts b/packages/datasource-handlers/packages/fetch/src/index.ts new file mode 100644 index 000000000..d59fc0a8d --- /dev/null +++ b/packages/datasource-handlers/packages/fetch/src/index.ts @@ -0,0 +1,20 @@ +import { RuntimeOptionsConfig } from '@ali/build-success-types'; + +import request from 'universal-request'; +import { RequestOptions, AsObject } from 'universal-request/lib/types'; + +// config 留着扩展 +export function createFetchHandler(config?: Record) { + return async function (options: RuntimeOptionsConfig) { + const requestConfig: RequestOptions = { + ...options, + url: options.uri, + method: options.method as RequestOptions['method'], + data: options.params as AsObject, + headers: options.headers as AsObject, + ...config, + }; + const response = await request(requestConfig); + return response; + }; +} diff --git a/packages/datasource-handlers/packages/fetch/tsconfig.json b/packages/datasource-handlers/packages/fetch/tsconfig.json new file mode 100644 index 000000000..268731175 --- /dev/null +++ b/packages/datasource-handlers/packages/fetch/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext" + }, + + "include": ["src/**/*"] +} diff --git a/packages/datasource-handlers/packages/mopen/es/index.d.ts b/packages/datasource-handlers/packages/mopen/es/index.d.ts new file mode 100644 index 000000000..17039d9f2 --- /dev/null +++ b/packages/datasource-handlers/packages/mopen/es/index.d.ts @@ -0,0 +1,5 @@ +import { MopenClientConfig } from '@ali/mirror-io-client-mopen'; +import { RuntimeOptionsConfig } from '@ali/build-success-types'; +export declare function createMopenHandler(config?: MopenClientConfig): (options: RuntimeOptionsConfig) => Promise<{ + data: T; +}>; diff --git a/packages/datasource-handlers/packages/mopen/es/index.js b/packages/datasource-handlers/packages/mopen/es/index.js new file mode 100644 index 000000000..967facd1d --- /dev/null +++ b/packages/datasource-handlers/packages/mopen/es/index.js @@ -0,0 +1,26 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { MopenClient, MOPEN_APPKEY_XSPACE_PRE_ONLINE, MOPEN_DOMAIN_TAOBAO_PRE_ONLINE, } from '@ali/mirror-io-client-mopen'; +export function createMopenHandler(config = { + mtopDomain: MOPEN_DOMAIN_TAOBAO_PRE_ONLINE, + appKey: MOPEN_APPKEY_XSPACE_PRE_ONLINE, +}) { + return function (options) { + return __awaiter(this, void 0, void 0, function* () { + try { + const { data, response } = yield MopenClient.request(Object.assign(Object.assign({ config }, options), { api: options.uri, v: options.v, data: options.params, type: options.method || 'get', dataType: options.dataType || 'json', timeout: options.timeout, headers: options.headers })); + return Object.assign(Object.assign({}, response), { data }); + } + catch (error) { + throw error; + } + }); + }; +} diff --git a/packages/datasource-handlers/packages/mopen/package.json b/packages/datasource-handlers/packages/mopen/package.json new file mode 100644 index 000000000..87ff98947 --- /dev/null +++ b/packages/datasource-handlers/packages/mopen/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ali/lowcode-datasource-mopen-handler", + "version": "1.0.2", + "main": "lib/index.js", + "module": "es/index.js", + "typings": "es/index.d.ts", + "files": [ + "src", + "lib", + "es" + ], + "scripts": { + "dev": "tsc --watch", + "clean": "rm -rf es lib", + "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", + "prepublishOnly": "npm run build" + }, + "devDependencies": { + "@ali/build-success-types": "^0.1.2-alpha.35" + }, + "dependencies": { + "@ali/mirror-io-client-mopen": "1.0.0-beta.16", + "typescript": "^3.9.7" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + }, + "gitHead": "829e504c52a294fc28966ab0e491f4d2de1d4c90" +} diff --git a/packages/datasource-handlers/packages/mopen/src/index.ts b/packages/datasource-handlers/packages/mopen/src/index.ts new file mode 100644 index 000000000..9367fbb4f --- /dev/null +++ b/packages/datasource-handlers/packages/mopen/src/index.ts @@ -0,0 +1,33 @@ +import { + MopenClient, + MopenClientConfig, + MOPEN_APPKEY_XSPACE_PRE_ONLINE, + MOPEN_DOMAIN_TAOBAO_PRE_ONLINE, +} from '@ali/mirror-io-client-mopen'; +import { RuntimeOptionsConfig } from '@ali/build-success-types'; + +type Method = 'get' | 'post' | 'GET' | 'POST'; + +type DataType = 'jsonp' | 'json' | 'originaljsonp'; + +export function createMopenHandler( + config: MopenClientConfig = { + mtopDomain: MOPEN_DOMAIN_TAOBAO_PRE_ONLINE, + appKey: MOPEN_APPKEY_XSPACE_PRE_ONLINE, + }, +) { + return async function (options: RuntimeOptionsConfig): Promise<{ data: T }> { + const { data, response } = await MopenClient.request({ + config, + ...options, + api: options.uri, + v: options.v as string, + data: options.params, + type: (options.method as Method) || 'get', + dataType: (options.dataType as DataType) || 'json', + timeout: options.timeout, + headers: options.headers, + }); + return { ...response, data }; + }; +} diff --git a/packages/datasource-handlers/packages/mopen/tsconfig.json b/packages/datasource-handlers/packages/mopen/tsconfig.json new file mode 100644 index 000000000..268731175 --- /dev/null +++ b/packages/datasource-handlers/packages/mopen/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext" + }, + + "include": ["src/**/*"] +} diff --git a/packages/datasource-handlers/packages/mtop/es/index.d.ts b/packages/datasource-handlers/packages/mtop/es/index.d.ts new file mode 100644 index 000000000..c30b6a50a --- /dev/null +++ b/packages/datasource-handlers/packages/mtop/es/index.d.ts @@ -0,0 +1,6 @@ +import { RuntimeOptionsConfig } from '@ali/build-success-types'; +export declare type Method = 'get' | 'post' | 'GET' | 'POST'; +export declare type DataType = 'jsonp' | 'json' | 'originaljsonp'; +export declare function createMtopHandler(config?: MTopConfig): (options: RuntimeOptionsConfig) => Promise<{ + data: T; +}>; diff --git a/packages/datasource-handlers/packages/mtop/es/index.js b/packages/datasource-handlers/packages/mtop/es/index.js new file mode 100644 index 000000000..fed789e22 --- /dev/null +++ b/packages/datasource-handlers/packages/mtop/es/index.js @@ -0,0 +1,35 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import mtopRequest from '@ali/universal-mtop'; +// 考虑一下 mtop 类型的问题,官方没有提供 ts 文件 +export function createMtopHandler(config) { + if (config && Object.keys(config).length > 0) { + Object.keys(config).forEach((key) => mtopRequest.config(key, config[key])); + } + return function (options) { + return __awaiter(this, void 0, void 0, function* () { + try { + const response = yield mtopRequest.request({ + api: options.uri, + v: options.v || '1.0', + data: options.params, + type: options.method || 'get', + dataType: options.dataType || 'json', + timeout: options.timeout, + headers: options.headers, + }); + return response; + } + catch (error) { + throw error; + } + }); + }; +} diff --git a/packages/datasource-handlers/packages/mtop/package.json b/packages/datasource-handlers/packages/mtop/package.json new file mode 100644 index 000000000..d0f0288c7 --- /dev/null +++ b/packages/datasource-handlers/packages/mtop/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ali/lowcode-datasource-mtop-handler", + "version": "1.0.1", + "main": "lib/index.js", + "module": "es/index.js", + "typings": "es/index.d.ts", + "files": [ + "src", + "lib", + "es" + ], + "scripts": { + "dev": "tsc --watch", + "clean": "rm -rf es lib", + "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", + "prepublishOnly": "npm run build" + }, + "devDependencies": { + "@ali/build-success-types": "^0.1.2-alpha.35" + }, + "dependencies": { + "@ali/universal-mtop": "^5.1.9", + "typescript": "^3.9.7" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + }, + "gitHead": "829e504c52a294fc28966ab0e491f4d2de1d4c90" +} diff --git a/packages/datasource-handlers/packages/mtop/src/index.ts b/packages/datasource-handlers/packages/mtop/src/index.ts new file mode 100644 index 000000000..0c01cdd64 --- /dev/null +++ b/packages/datasource-handlers/packages/mtop/src/index.ts @@ -0,0 +1,26 @@ +import mtopRequest from '@ali/universal-mtop'; + +import { RuntimeOptionsConfig } from '@ali/build-success-types'; + +export type Method = 'get' | 'post' | 'GET' | 'POST'; + +export type DataType = 'jsonp' | 'json' | 'originaljsonp'; + +// 考虑一下 mtop 类型的问题,官方没有提供 ts 文件 +export function createMtopHandler(config?: MTopConfig) { + if (config && Object.keys(config).length > 0) { + Object.keys(config).forEach((key: string) => mtopRequest.config(key, config[key])); + } + return async function (options: RuntimeOptionsConfig): Promise<{ data: T }> { + const response = await mtopRequest.request({ + api: options.uri, + v: (options.v as string) || '1.0', + data: options.params, + type: (options.method as Method) || 'get', + dataType: (options.dataType as DataType) || 'json', + timeout: options.timeout, + headers: options.headers, + }); + return response; + }; +} diff --git a/packages/datasource-handlers/packages/mtop/src/typings.d.ts b/packages/datasource-handlers/packages/mtop/src/typings.d.ts new file mode 100644 index 000000000..6a5989f78 --- /dev/null +++ b/packages/datasource-handlers/packages/mtop/src/typings.d.ts @@ -0,0 +1,11 @@ +declare interface MTopConfig { + prefix?: string; + subDomain?: string; + mainDomain?: string; + [index: string]: unknown; +} + +declare module '@ali/universal-mtop' { + const request: (config: any) => Promise<{ data: T }>; + const config: (key: string, value: unknown) => void; +} diff --git a/packages/datasource-handlers/packages/mtop/tsconfig.json b/packages/datasource-handlers/packages/mtop/tsconfig.json new file mode 100644 index 000000000..268731175 --- /dev/null +++ b/packages/datasource-handlers/packages/mtop/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext" + }, + + "include": ["src/**/*"] +} diff --git a/packages/datasource-handlers/packages/universalMtop/es/index.d.ts b/packages/datasource-handlers/packages/universalMtop/es/index.d.ts new file mode 100644 index 000000000..2a16eb3e9 --- /dev/null +++ b/packages/datasource-handlers/packages/universalMtop/es/index.d.ts @@ -0,0 +1,5 @@ +import { UniversalMtopClientConfig } from '@ali/mirror-io-client-universal-mtop'; +import { RuntimeOptionsConfig } from '@ali/build-success-types'; +export declare function createMopenHandler(config?: UniversalMtopClientConfig): (options: RuntimeOptionsConfig) => Promise<{ + data: T; +}>; diff --git a/packages/datasource-handlers/packages/universalMtop/es/index.js b/packages/datasource-handlers/packages/universalMtop/es/index.js new file mode 100644 index 000000000..718adf31b --- /dev/null +++ b/packages/datasource-handlers/packages/universalMtop/es/index.js @@ -0,0 +1,23 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { UniversalMtopClient, } from '@ali/mirror-io-client-universal-mtop'; +export function createMopenHandler(config) { + return function (options) { + return __awaiter(this, void 0, void 0, function* () { + try { + const { data, response } = yield UniversalMtopClient.request(Object.assign(Object.assign({ config }, options), { api: options.uri, v: options.v, data: options.params, type: options.method || 'get', dataType: options.dataType || 'json', timeout: options.timeout, headers: options.headers })); + return Object.assign(Object.assign({}, response), { data }); + } + catch (error) { + throw error; + } + }); + }; +} diff --git a/packages/datasource-handlers/packages/universalMtop/package.json b/packages/datasource-handlers/packages/universalMtop/package.json new file mode 100644 index 000000000..75c9f216f --- /dev/null +++ b/packages/datasource-handlers/packages/universalMtop/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ali/lowcode-datasource-universal-mtop-handler", + "version": "1.0.1", + "main": "lib/index.js", + "module": "es/index.js", + "typings": "es/index.d.ts", + "files": [ + "src", + "lib", + "es" + ], + "scripts": { + "dev": "tsc --watch", + "clean": "rm -rf es lib", + "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", + "prepublishOnly": "npm run build" + }, + "devDependencies": { + "@ali/build-success-types": "^0.1.2-alpha.27" + }, + "dependencies": { + "@ali/mirror-io-client-universal-mtop": "1.0.0-beta.16", + "typescript": "^3.9.7" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + }, + "gitHead": "829e504c52a294fc28966ab0e491f4d2de1d4c90" +} diff --git a/packages/datasource-handlers/packages/universalMtop/src/index.ts b/packages/datasource-handlers/packages/universalMtop/src/index.ts new file mode 100644 index 000000000..f44d9eebd --- /dev/null +++ b/packages/datasource-handlers/packages/universalMtop/src/index.ts @@ -0,0 +1,29 @@ +import { + UniversalMtopClient, + UniversalMtopClientConfig, +} from '@ali/mirror-io-client-universal-mtop'; + +import { RuntimeOptionsConfig } from '@ali/build-success-types'; + +type Method = 'get' | 'post' | 'GET' | 'POST'; + +type DataType = 'jsonp' | 'json' | 'originaljsonp'; + +export function createMopenHandler( + config?: UniversalMtopClientConfig, +) { + return async function (options: RuntimeOptionsConfig): Promise<{ data: T }> { + const { data, response } = await UniversalMtopClient.request({ + config, + ...options, + api: options.uri, + v: options.v as string, + data: options.params, + type: (options.method as Method) || 'get', + dataType: (options.dataType as DataType) || 'json', + timeout: options.timeout, + headers: options.headers, + }); + return { ...response, data }; + }; +} diff --git a/packages/datasource-handlers/packages/universalMtop/tsconfig.json b/packages/datasource-handlers/packages/universalMtop/tsconfig.json new file mode 100644 index 000000000..268731175 --- /dev/null +++ b/packages/datasource-handlers/packages/universalMtop/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext" + }, + + "include": ["src/**/*"] +} diff --git a/packages/datasource-handlers/packages/urlParams/es/index.d.ts b/packages/datasource-handlers/packages/urlParams/es/index.d.ts new file mode 100644 index 000000000..f16cb44c3 --- /dev/null +++ b/packages/datasource-handlers/packages/urlParams/es/index.d.ts @@ -0,0 +1,2 @@ +import { UrlParamsHandler } from '@ali/build-success-types'; +export declare function createUrlParamsHandler(searchString?: string | T): UrlParamsHandler; diff --git a/packages/datasource-handlers/packages/urlParams/es/index.js b/packages/datasource-handlers/packages/urlParams/es/index.js new file mode 100644 index 000000000..84a9451ef --- /dev/null +++ b/packages/datasource-handlers/packages/urlParams/es/index.js @@ -0,0 +1,21 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import qs from 'query-string'; +export function createUrlParamsHandler(searchString = '') { + return function () { + return __awaiter(this, void 0, void 0, function* () { + if (typeof searchString === 'string') { + const params = qs.parse(searchString); + return params; + } + return searchString; + }); + }; +} diff --git a/packages/datasource-handlers/packages/urlParams/package.json b/packages/datasource-handlers/packages/urlParams/package.json new file mode 100644 index 000000000..41ee2e618 --- /dev/null +++ b/packages/datasource-handlers/packages/urlParams/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ali/lowcode-datasource-url-params-handler", + "version": "1.0.1", + "main": "lib/index.js", + "module": "es/index.js", + "typings": "es/index.d.ts", + "files": [ + "src", + "lib", + "es" + ], + "scripts": { + "dev": "tsc --watch", + "clean": "rm -rf es lib", + "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", + "prepublishOnly": "npm run build" + }, + "devDependencies": { + "@ali/build-success-types": "^0.1.2-alpha.31" + }, + "dependencies": { + "query-string": "^6.13.1", + "typescript": "^3.9.7" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + }, + "gitHead": "829e504c52a294fc28966ab0e491f4d2de1d4c90" +} diff --git a/packages/datasource-handlers/packages/urlParams/src/index.ts b/packages/datasource-handlers/packages/urlParams/src/index.ts new file mode 100644 index 000000000..c0c4a8836 --- /dev/null +++ b/packages/datasource-handlers/packages/urlParams/src/index.ts @@ -0,0 +1,15 @@ +import qs from 'query-string'; +import { UrlParamsHandler } from '@ali/build-success-types'; + +export function createUrlParamsHandler( + searchString: string | T = '', +): UrlParamsHandler { + return async function (): Promise { + if (typeof searchString === 'string') { + const params = (qs.parse(searchString) as unknown) as T; + return params; + } + + return searchString; + }; +} diff --git a/packages/datasource-handlers/packages/urlParams/tsconfig.json b/packages/datasource-handlers/packages/urlParams/tsconfig.json new file mode 100644 index 000000000..268731175 --- /dev/null +++ b/packages/datasource-handlers/packages/urlParams/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext" + }, + + "include": ["src/**/*"] +} diff --git a/packages/datasource-handlers/tsconfig.json b/packages/datasource-handlers/tsconfig.json new file mode 100644 index 000000000..68d4e6bb3 --- /dev/null +++ b/packages/datasource-handlers/tsconfig.json @@ -0,0 +1,67 @@ +{ + "compilerOptions": { + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + // "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + // "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": ["ESNext", "DOM"] /* Specify library files to be included in the compilation. */, + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "es" /* Redirect output structure to the directory. */, + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + "skipLibCheck": true + } +} From 2b9bcb5174466371663fa5496ccd93dc2e4dc7c4 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Tue, 13 Oct 2020 17:06:51 +0800 Subject: [PATCH 07/34] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=20datasource-h?= =?UTF-8?q?andlers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/datasource-engine/.eslintignore | 4 +- packages/datasource-engine/.eslintrc.js | 4 +- packages/datasource-engine/.prettierrc.js | 2 +- packages/datasource-engine/package.json | 7 +- .../src/core/RuntimeDataSourceItem.ts | 21 +-- .../datasource-engine/src/core/adapter.ts | 21 ++- .../src/core/reloadDataSourceFactory.ts | 16 +- .../datasource-engine/src/helpers/index.ts | 3 +- .../src/interpret/DataSourceEngineFactory.ts | 25 ++- .../runtime/RuntimeDataSourceEngineFactory.ts | 19 +- packages/datasource-engine/src/utils.ts | 40 +++-- .../test/_helpers/mock-context.ts | 11 +- .../_datasource-runtime.ts | 2 +- .../_datasource-schema.ts | 4 +- .../p0-0-simplest-defaults/_macro-abnormal.ts | 74 ++++---- .../p0-0-simplest-defaults/_macro-normal.ts | 110 ++++++------ .../_datasource-runtime.ts | 2 +- .../_datasource-schema.ts | 4 +- .../_macro-abnormal.ts | 140 +++++++-------- .../_macro-normal.ts | 132 +++++++------- .../p0-0-url-params/_datasource-runtime.ts | 2 +- .../p0-0-url-params/_datasource-schema.ts | 4 +- .../scenes/p0-0-url-params/_macro-normal.ts | 94 +++++----- .../_datasource-runtime.ts | 2 +- .../_datasource-schema.ts | 4 +- .../_macro-abnormal.ts | 114 ++++++------ .../_macro-normal.ts | 140 +++++++-------- .../_datasource-runtime.ts | 2 +- .../_datasource-schema.ts | 4 +- .../_macro-abnormal.ts | 84 ++++----- .../_macro-normal.ts | 110 ++++++------ .../_datasource-runtime.ts | 2 +- .../_datasource-schema.ts | 4 +- .../_macro-abnormal.ts | 114 ++++++------ .../_macro-normal.ts | 140 +++++++-------- .../_datasource-runtime.ts | 2 +- .../_datasource-schema.ts | 4 +- .../_macro-normal.ts | 164 +++++++++--------- .../datasource-fetch-handler/.eslintignore | 3 + .../.eslintrc.js | 2 +- .../.prettierrc.js | 2 +- .../package.json | 4 +- .../src/index.ts | 2 +- .../tsconfig.json | 21 ++- packages/datasource-handlers/.eslintignore | 1 - packages/datasource-handlers/lerna.json | 5 - packages/datasource-handlers/package.json | 9 - .../packages/fetch/es/index.d.ts | 2 - .../packages/fetch/es/index.js | 25 --- .../packages/fetch/tsconfig.json | 10 -- .../packages/mopen/es/index.d.ts | 5 - .../packages/mopen/es/index.js | 26 --- .../packages/mopen/tsconfig.json | 10 -- .../packages/mtop/es/index.d.ts | 6 - .../packages/mtop/es/index.js | 35 ---- .../packages/mtop/tsconfig.json | 10 -- .../packages/universalMtop/es/index.d.ts | 5 - .../packages/universalMtop/es/index.js | 23 --- .../packages/universalMtop/tsconfig.json | 10 -- .../packages/urlParams/es/index.d.ts | 2 - .../packages/urlParams/es/index.js | 21 --- .../packages/urlParams/tsconfig.json | 10 -- .../datasource-mopen-handler/.eslintignore | 3 + .../datasource-mopen-handler/.eslintrc.js | 7 + .../datasource-mopen-handler/.prettierrc.js | 4 + .../package.json | 4 +- .../src/index.ts | 2 +- .../datasource-mopen-handler/tsconfig.json | 70 ++++++++ .../datasource-mtop-handler/.eslintignore | 3 + packages/datasource-mtop-handler/.eslintrc.js | 7 + .../datasource-mtop-handler/.prettierrc.js | 4 + .../package.json | 4 +- .../src/index.ts | 2 +- .../src/typings.d.ts | 0 .../datasource-mtop-handler/tsconfig.json | 70 ++++++++ .../.eslintignore | 3 + .../.eslintrc.js | 7 + .../.prettierrc.js | 4 + .../package.json | 4 +- .../src/index.ts | 2 +- .../tsconfig.json | 70 ++++++++ .../.eslintignore | 3 + .../.eslintrc.js | 7 + .../.prettierrc.js | 0 .../package.json | 4 +- .../src/index.ts | 2 +- .../tsconfig.json | 70 ++++++++ packages/types/.eslintignore | 3 + packages/types/.eslintrc.js | 9 + packages/types/.prettierrc.js | 6 + packages/types/src/data-source-handlers.ts | 15 ++ packages/types/src/data-source-interpret.ts | 41 +++++ packages/types/src/data-source-runtime.ts | 53 ++++++ packages/types/src/data-source.ts | 73 ++++++-- packages/types/src/index.ts | 3 + packages/types/src/value-type.ts | 63 ++++++- 96 files changed, 1426 insertions(+), 1076 deletions(-) create mode 100644 packages/datasource-fetch-handler/.eslintignore rename packages/{datasource-handlers => datasource-fetch-handler}/.eslintrc.js (78%) rename packages/{datasource-handlers => datasource-fetch-handler}/.prettierrc.js (61%) rename packages/{datasource-handlers/packages/fetch => datasource-fetch-handler}/package.json (88%) rename packages/{datasource-handlers/packages/fetch => datasource-fetch-handler}/src/index.ts (90%) rename packages/{datasource-handlers => datasource-fetch-handler}/tsconfig.json (95%) delete mode 100644 packages/datasource-handlers/.eslintignore delete mode 100644 packages/datasource-handlers/lerna.json delete mode 100644 packages/datasource-handlers/package.json delete mode 100644 packages/datasource-handlers/packages/fetch/es/index.d.ts delete mode 100644 packages/datasource-handlers/packages/fetch/es/index.js delete mode 100644 packages/datasource-handlers/packages/fetch/tsconfig.json delete mode 100644 packages/datasource-handlers/packages/mopen/es/index.d.ts delete mode 100644 packages/datasource-handlers/packages/mopen/es/index.js delete mode 100644 packages/datasource-handlers/packages/mopen/tsconfig.json delete mode 100644 packages/datasource-handlers/packages/mtop/es/index.d.ts delete mode 100644 packages/datasource-handlers/packages/mtop/es/index.js delete mode 100644 packages/datasource-handlers/packages/mtop/tsconfig.json delete mode 100644 packages/datasource-handlers/packages/universalMtop/es/index.d.ts delete mode 100644 packages/datasource-handlers/packages/universalMtop/es/index.js delete mode 100644 packages/datasource-handlers/packages/universalMtop/tsconfig.json delete mode 100644 packages/datasource-handlers/packages/urlParams/es/index.d.ts delete mode 100644 packages/datasource-handlers/packages/urlParams/es/index.js delete mode 100644 packages/datasource-handlers/packages/urlParams/tsconfig.json create mode 100644 packages/datasource-mopen-handler/.eslintignore create mode 100644 packages/datasource-mopen-handler/.eslintrc.js create mode 100644 packages/datasource-mopen-handler/.prettierrc.js rename packages/{datasource-handlers/packages/mopen => datasource-mopen-handler}/package.json (89%) rename packages/{datasource-handlers/packages/mopen => datasource-mopen-handler}/src/index.ts (93%) create mode 100644 packages/datasource-mopen-handler/tsconfig.json create mode 100644 packages/datasource-mtop-handler/.eslintignore create mode 100644 packages/datasource-mtop-handler/.eslintrc.js create mode 100644 packages/datasource-mtop-handler/.prettierrc.js rename packages/{datasource-handlers/packages/mtop => datasource-mtop-handler}/package.json (88%) rename packages/{datasource-handlers/packages/mtop => datasource-mtop-handler}/src/index.ts (93%) rename packages/{datasource-handlers/packages/mtop => datasource-mtop-handler}/src/typings.d.ts (100%) create mode 100644 packages/datasource-mtop-handler/tsconfig.json create mode 100644 packages/datasource-universal-mtop-handler/.eslintignore create mode 100644 packages/datasource-universal-mtop-handler/.eslintrc.js create mode 100644 packages/datasource-universal-mtop-handler/.prettierrc.js rename packages/{datasource-handlers/packages/universalMtop => datasource-universal-mtop-handler}/package.json (89%) rename packages/{datasource-handlers/packages/universalMtop => datasource-universal-mtop-handler}/src/index.ts (92%) create mode 100644 packages/datasource-universal-mtop-handler/tsconfig.json create mode 100644 packages/datasource-url-params-handler/.eslintignore create mode 100644 packages/datasource-url-params-handler/.eslintrc.js create mode 100644 packages/datasource-url-params-handler/.prettierrc.js rename packages/{datasource-handlers/packages/urlParams => datasource-url-params-handler}/package.json (88%) rename packages/{datasource-handlers/packages/urlParams => datasource-url-params-handler}/src/index.ts (85%) create mode 100644 packages/datasource-url-params-handler/tsconfig.json create mode 100644 packages/types/.eslintignore create mode 100644 packages/types/.eslintrc.js create mode 100644 packages/types/.prettierrc.js create mode 100644 packages/types/src/data-source-handlers.ts create mode 100644 packages/types/src/data-source-interpret.ts create mode 100644 packages/types/src/data-source-runtime.ts diff --git a/packages/datasource-engine/.eslintignore b/packages/datasource-engine/.eslintignore index 30bc16279..fecb7c26d 100644 --- a/packages/datasource-engine/.eslintignore +++ b/packages/datasource-engine/.eslintignore @@ -1 +1,3 @@ -/node_modules \ No newline at end of file +/node_modules +/es +/lib \ No newline at end of file diff --git a/packages/datasource-engine/.eslintrc.js b/packages/datasource-engine/.eslintrc.js index b33327802..8c13fcaf4 100644 --- a/packages/datasource-engine/.eslintrc.js +++ b/packages/datasource-engine/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { - extends: '../../.eslintrc.js', + extends: '../../.eslintrc', rules: { '@typescript-eslint/no-parameter-properties': 1, - 'no-param-reassign': 0 + 'no-param-reassign': 0, }, }; diff --git a/packages/datasource-engine/.prettierrc.js b/packages/datasource-engine/.prettierrc.js index d2db80ead..de2f53cdf 100644 --- a/packages/datasource-engine/.prettierrc.js +++ b/packages/datasource-engine/.prettierrc.js @@ -1,4 +1,4 @@ module.exports = { singleQuote: true, - trailingComma: 'always', + trailingComma: 'all', }; diff --git a/packages/datasource-engine/package.json b/packages/datasource-engine/package.json index 99c775919..6479c7c0b 100644 --- a/packages/datasource-engine/package.json +++ b/packages/datasource-engine/package.json @@ -15,15 +15,10 @@ }, "typings": "dist/index.d.ts", "dependencies": { - "@ali/build-success-types": "^0.1.2-alpha.35", + "@ali/lowcode-types": "^0.8.13", "typescript": "^3.9.7" }, "devDependencies": { - "@ali/datasource-engine-universal-mtop-handler": "1.0.0-alpha.2", - "@ali/datasource-engine-url-params-handler": "^1.0.0-alpha.3", - "@ali/lowcode-datasource-http-handler": "^1.0.0-alpha.1", - "@ali/lowcode-datasource-url-params-handler": "^1.0.0-alpha.3", - "@ali/ng-lc-types": "^1.0.0-r2009222d5o6k8r8", "@ava/babel": "^1.0.1", "@types/sinon": "^9.0.5", "ava": "3.11.1", diff --git a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts index b2dff9bb1..d4184707a 100644 --- a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts +++ b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts @@ -1,12 +1,13 @@ +/* eslint-disable @typescript-eslint/indent */ import { + IDataSourceRuntimeContext, IRuntimeDataSource, + RequestHandler, RuntimeDataSourceConfig, RuntimeDataSourceStatus, - IRuntimeContext, - RequestHandler, RuntimeOptionsConfig, UrlParamsHandler, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; class RuntimeDataSourceItem< TParams extends Record = Record, @@ -21,19 +22,19 @@ class RuntimeDataSourceItem< private _dataSourceConfig: RuntimeDataSourceConfig; private _request: - | RequestHandler<{ data: TResultData }> - | UrlParamsHandler; + | RequestHandler<{ data: TResultData }> + | UrlParamsHandler; - private _context: IRuntimeContext; + private _context: IDataSourceRuntimeContext; private _options?: RuntimeOptionsConfig; constructor( dataSourceConfig: RuntimeDataSourceConfig, request: - | RequestHandler<{ data: TResultData }> - | UrlParamsHandler, - context: IRuntimeContext, + | RequestHandler<{ data: TResultData }> + | UrlParamsHandler, + context: IDataSourceRuntimeContext, ) { this._dataSourceConfig = dataSourceConfig; this._request = request; @@ -52,7 +53,7 @@ class RuntimeDataSourceItem< return this._status; } - public async load(params?: TParams) { + async load(params?: TParams) { if (!this._dataSourceConfig) return; // 考虑没有绑定对应的 handler 的情况 if (!this._request) { diff --git a/packages/datasource-engine/src/core/adapter.ts b/packages/datasource-engine/src/core/adapter.ts index b1274b6ae..41a476bc7 100644 --- a/packages/datasource-engine/src/core/adapter.ts +++ b/packages/datasource-engine/src/core/adapter.ts @@ -7,16 +7,19 @@ import { } from './../utils'; // 将不同渠道给的 schema 转为 runtime 需要的类型 -import { - DataSource, - IPageContext, - DataSourceConfig, - RuntimeDataSourceConfig, - DataSourceMap, -} from '@ali/build-success-types'; import { defaultDataHandler, defaultWillFetch } from '../helpers'; +import { + DataSourceMap, + IDataSourceRuntimeContext, + InterpretDataSource, + InterpretDataSourceConfig, + RuntimeDataSourceConfig, +} from '@ali/lowcode-types'; -const adapt2Runtime = (dataSource: DataSource, context: IPageContext) => { +const adapt2Runtime = ( + dataSource: InterpretDataSource, + context: IDataSourceRuntimeContext, +) => { const { list: interpretConfigList, dataHandler: interpretDataHandler, @@ -34,7 +37,7 @@ const adapt2Runtime = (dataSource: DataSource, context: IPageContext) => { }; } const list: RuntimeDataSourceConfig[] = interpretConfigList.map( - (el: DataSourceConfig) => { + (el: InterpretDataSourceConfig) => { return { id: el.id, isInit: diff --git a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts index ac8776341..8433d0d0a 100644 --- a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts +++ b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts @@ -1,8 +1,8 @@ import { - RuntimeDataSource, DataSourceMap, + RuntimeDataSource, RuntimeDataSourceConfig, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; export const reloadDataSourceFactory = ( dataSource: RuntimeDataSource, @@ -14,7 +14,8 @@ export const reloadDataSourceFactory = ( // 单独处理 urlParams 类型的 dataSource.list .filter( - (el: RuntimeDataSourceConfig) => el.type === 'urlParams' && + (el: RuntimeDataSourceConfig) => + el.type === 'urlParams' && (typeof el.isInit === 'boolean' ? el.isInit : true), ) .forEach((el: RuntimeDataSourceConfig) => { @@ -50,13 +51,8 @@ export const reloadDataSourceFactory = ( ds.isInit && ds.isSync ) { - // TODO: 我理解这个异常也应该吃掉的,待确认 - try { - // eslint-disable-next-line no-await-in-loop - await dataSourceMap[ds.id].load(); - } catch (e) { - console.error(e); - } + // eslint-disable-next-line no-await-in-loop + await dataSourceMap[ds.id].load(); } } diff --git a/packages/datasource-engine/src/helpers/index.ts b/packages/datasource-engine/src/helpers/index.ts index d13e747f6..71565b434 100644 --- a/packages/datasource-engine/src/helpers/index.ts +++ b/packages/datasource-engine/src/helpers/index.ts @@ -1,5 +1,6 @@ -import { DataHandler } from '@ali/build-success-types'; +import { DataHandler } from '@ali/lowcode-types'; +// eslint-disable-next-line @typescript-eslint/no-empty-function function noop() {} // 默认的 dataSourceItem 的 dataHandler diff --git a/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts b/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts index a31a5a095..4adcf1f82 100644 --- a/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts +++ b/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts @@ -1,15 +1,14 @@ -import { - IRuntimeContext, - IRuntimeDataSource, - DataSource, - RuntimeDataSourceConfig, - RuntimeDataSource, - RequestHandlersMap, -} from '@ali/build-success-types'; - import { adapt2Runtime } from '../core/adapter'; import { RuntimeDataSourceItem } from '../core/RuntimeDataSourceItem'; import { reloadDataSourceFactory } from '../core/reloadDataSourceFactory'; +import { + IDataSourceRuntimeContext, + InterpretDataSource, + IRuntimeDataSource, + RequestHandlersMap, + RuntimeDataSource, + RuntimeDataSourceConfig, +} from '@ali/lowcode-types'; // TODO: requestConfig mtop 默认的请求 config 怎么处理? /** @@ -18,13 +17,11 @@ import { reloadDataSourceFactory } from '../core/reloadDataSourceFactory'; */ export default ( - dataSource: DataSource, - context: IRuntimeContext, + dataSource: InterpretDataSource, + context: IDataSourceRuntimeContext, extraConfig: { requestHandlersMap: RequestHandlersMap<{ data: unknown }>; - } = { - requestHandlersMap: {}, - }, + } = { requestHandlersMap: {} }, ) => { const { requestHandlersMap } = extraConfig; diff --git a/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts b/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts index 2a98f1a14..d504054c3 100644 --- a/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts +++ b/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts @@ -1,11 +1,12 @@ +/* eslint-disable @typescript-eslint/indent */ /* eslint-disable no-nested-ternary */ import { - IRuntimeContext, IRuntimeDataSource, + IDataSourceRuntimeContext, + RequestHandlersMap, RuntimeDataSourceConfig, RuntimeDataSource, - RequestHandlersMap, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import { RuntimeDataSourceItem } from '../core'; import { reloadDataSourceFactory } from '../core/reloadDataSourceFactory'; @@ -22,24 +23,22 @@ import { */ export default ( dataSource: RuntimeDataSource, - context: IRuntimeContext, + context: IDataSourceRuntimeContext, extraConfig: { requestHandlersMap: RequestHandlersMap<{ data: unknown }>; - } = { - requestHandlersMap: {}, - }, + } = { requestHandlersMap: {} }, ) => { const { requestHandlersMap } = extraConfig; // TODO: 对于出码类型,需要做一层数据兼容,给一些必要的值设置默认值,先兜底几个必要的 - dataSource.list.forEach((ds) => { + dataSource.list.forEach(ds => { ds.isInit = ds.isInit || true; ds.isSync = ds.isSync || false; ds.shouldFetch = !ds.shouldFetch ? defaultShouldFetch : typeof ds.shouldFetch === 'function' - ? ds.shouldFetch.bind(context) - : ds.shouldFetch; + ? ds.shouldFetch.bind(context) + : ds.shouldFetch; ds.willFetch = ds.willFetch ? ds.willFetch.bind(context) : defaultWillFetch; ds.dataHandler = ds.dataHandler ? ds.dataHandler.bind(context) diff --git a/packages/datasource-engine/src/utils.ts b/packages/datasource-engine/src/utils.ts index f39171e96..b31076f28 100644 --- a/packages/datasource-engine/src/utils.ts +++ b/packages/datasource-engine/src/utils.ts @@ -1,16 +1,20 @@ /* eslint-disable no-new-func */ + import { - JSExpression, - IRuntimeContext, CompositeValue, + IDataSourceRuntimeContext, + InterpretDataSourceConfig, + isJSExpression, + isJSFunction, + JSExpression, JSFunction, JSONObject, - isJSExpression, - DataSourceConfig, - isJSFunction, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; -export const transformExpression = (code: string, context: IRuntimeContext) => { +export const transformExpression = ( + code: string, + context: IDataSourceRuntimeContext, +) => { try { return new Function(`return (${code})`).call(context); } catch (error) { @@ -20,7 +24,10 @@ export const transformExpression = (code: string, context: IRuntimeContext) => { } }; -export const transformFunction = (code: string, context: IRuntimeContext) => { +export const transformFunction = ( + code: string, + context: IDataSourceRuntimeContext, +) => { try { return new Function(`return (${code})`).call(context).bind(context); } catch (error) { @@ -36,12 +43,13 @@ export const transformBoolStr = (str: string) => { export const getRuntimeJsValue = ( value: JSExpression | JSFunction, - context: IRuntimeContext, + context: IDataSourceRuntimeContext, ) => { if (!['JSExpression', 'JSFunction'].includes(value.type)) { console.error(`translate error, value is ${JSON.stringify(value)}`); return ''; } + // TODO: 类型修复 const code = value.compiled || value.value; return value.type === 'JSFunction' ? transformFunction(code, context) @@ -66,7 +74,7 @@ export const getRuntimeBaseValue = (type: string, value: any) => { export const getRuntimeValueFromConfig = ( type: string, value: CompositeValue, - context: IRuntimeContext, + context: IDataSourceRuntimeContext, ) => { if (!value) return undefined; if (isJSExpression(value) || isJSFunction(value)) { @@ -77,7 +85,7 @@ export const getRuntimeValueFromConfig = ( export const buildJsonObj = ( params: JSONObject | JSExpression, - context: IRuntimeContext, + context: IDataSourceRuntimeContext, ) => { const result: Record = {}; if (isJSExpression(params)) { @@ -96,8 +104,8 @@ export const buildJsonObj = ( }; export const buildShouldFetch = ( - ds: DataSourceConfig, - context: IRuntimeContext, + ds: InterpretDataSourceConfig, + context: IDataSourceRuntimeContext, ) => { if (!ds.options || !ds.shouldFetch) { return true; // 默认为 true @@ -110,12 +118,12 @@ export const buildShouldFetch = ( }; export const buildOptions = ( - ds: DataSourceConfig, - context: IRuntimeContext, + ds: InterpretDataSourceConfig, + context: IDataSourceRuntimeContext, ) => { const { options } = ds; if (!options) return undefined; - return function () { + return function() { return { uri: getRuntimeValueFromConfig('string', options.uri, context), params: options.params ? buildJsonObj(options.params, context) : {}, diff --git a/packages/datasource-engine/test/_helpers/mock-context.ts b/packages/datasource-engine/test/_helpers/mock-context.ts index f602489de..7b62f29b7 100644 --- a/packages/datasource-engine/test/_helpers/mock-context.ts +++ b/packages/datasource-engine/test/_helpers/mock-context.ts @@ -1,13 +1,16 @@ -import { IDataSourceEngine, IRuntimeContext } from '@ali/build-success-types'; +import { + IDataSourceRuntimeContext, + IDataSourceEngine +} from '@ali/lowcode-types'; -export class MockContext> - implements IRuntimeContext { +export class MockContext = Record> + implements IDataSourceRuntimeContext { private _dataSourceEngine: IDataSourceEngine; public constructor( private _state: TState, private _createDataSourceEngine: ( - context: IRuntimeContext + context: IDataSourceRuntimeContext ) => IDataSourceEngine, private _customMethods: Record any> = {} ) { diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-runtime.ts index ccb41e1f0..58002ead2 100644 --- a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-runtime.ts +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-runtime.ts @@ -1,4 +1,4 @@ -import { RuntimeDataSource } from '@ali/build-success-types'; +import { RuntimeDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-schema.ts index 7218c7864..848a85687 100644 --- a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-schema.ts +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_datasource-schema.ts @@ -1,8 +1,8 @@ -import { DataSource } from '@ali/build-success-types'; +import { InterpretDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的 schema: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 -export const DATA_SOURCE_SCHEMA: DataSource = { +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { list: [ { id: 'user', diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-abnormal.ts index 4a2297aa0..78c0f5cb2 100644 --- a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-abnormal.ts +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-abnormal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { delay, MockContext } from '../../_helpers'; @@ -17,56 +17,56 @@ export const abnormalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; - const ERROR_MSG = 'test error'; - const fetchHandler = sinon.fake(async () => { - await delay(100); - throw new Error(ERROR_MSG); - }); + ) => { + const { clock } = t.context; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async () => { + await delay(100); + throw new Error(ERROR_MSG); + }); - const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - })); + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); - const setState = sinon.spy(context, 'setState'); + const setState = sinon.spy(context, 'setState'); - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - const loading = context.reloadDataSource(); + const loading = context.reloadDataSource(); - await clock.tickAsync(50); + await clock.tickAsync(50); - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - await Promise.all([clock.runAllAsync(), loading]); + await Promise.all([clock.runAllAsync(), loading]); - // 最后应该失败了,error 状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); + // 最后应该失败了,error 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, undefined); - t.not(context.dataSourceMap.user.error, undefined); - t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, undefined); + t.not(context.dataSourceMap.user.error, undefined); + t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); - // 检查状态数据 - t.assert(setState.notCalled); - t.deepEqual(context.state.user, undefined); + // 检查状态数据 + t.assert(setState.notCalled); + t.deepEqual(context.state.user, undefined); - // fetchHandler 不应该被调 - t.assert(fetchHandler.calledOnce); -}; + // fetchHandler 不应该被调 + t.assert(fetchHandler.calledOnce); + }; abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-normal.ts index 7115ab1eb..9d2a7e353 100644 --- a/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-normal.ts +++ b/packages/datasource-engine/test/scenes/p0-0-simplest-defaults/_macro-normal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { delay, MockContext } from '../../_helpers'; @@ -17,65 +17,65 @@ export const normalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; + ) => { + const { clock } = t.context; - const USER_DATA = { - name: 'Alice', - age: 18, + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { data: USER_DATA }; + }); + + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + // 检查调用参数 + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); }; - const fetchHandler = sinon.fake(async () => { - await delay(100); - return { data: USER_DATA }; - }); - - const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - })); - - const setState = sinon.spy(context, 'setState'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后应该成功了,loaded 状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, USER_DATA); - t.deepEqual(context.dataSourceMap.user.error, undefined); - - // 检查状态数据 - t.assert(setState.calledOnce); - t.deepEqual(context.state.user, USER_DATA); - - // fetchHandler 应该被调用了一次 - t.assert(fetchHandler.calledOnce); - - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - // 检查调用参数 - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); -}; - normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-runtime.ts index 09e244a38..c5fe1194c 100644 --- a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-runtime.ts +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-runtime.ts @@ -1,4 +1,4 @@ -import { RuntimeDataSource } from '@ali/build-success-types'; +import { RuntimeDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-schema.ts index e4e549ece..2c75c180a 100644 --- a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-schema.ts +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_datasource-schema.ts @@ -1,8 +1,8 @@ -import { DataSource } from '@ali/build-success-types'; +import { InterpretDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的 schema: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 -export const DATA_SOURCE_SCHEMA: DataSource = { +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { list: [ { id: 'user', diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts index fc0aaa0b3..f81db6b49 100644 --- a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; @@ -17,80 +17,80 @@ export const abnormalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; + ) => { + const { clock } = t.context; - const USER_DATA = { - id: 9527, - name: 'Alice', + const USER_DATA = { + id: 9527, + name: 'Alice', + }; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async ({ uri }) => { + await delay(100); + if (/user/.test(uri)) { + return { data: USER_DATA }; + } else { + throw new Error(ERROR_MSG); + } + }); + + const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(50); + + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后 user 应该成功了,loaded + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + // 最后 orders 应该失败了,error 状态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.is(context.dataSourceMap.user.error, undefined); + t.deepEqual(context.dataSourceMap.orders.data, undefined); + t.not(context.dataSourceMap.orders.error, undefined); + t.regex(context.dataSourceMap.orders.error!.message, new RegExp(ERROR_MSG)); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + t.is(context.state.orders, undefined); + + // fetchHandler 应该被调用了2次 + t.assert(fetchHandler.calledTwice); + + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + // 检查调用参数 + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); }; - const ERROR_MSG = 'test error'; - const fetchHandler = sinon.fake(async ({ uri }) => { - await delay(100); - if (/user/.test(uri)) { - return { data: USER_DATA }; - } else { - throw new Error(ERROR_MSG); - } - }); - - const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - })); - - const setState = sinon.spy(context, 'setState'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - - await clock.tickAsync(50); - - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后 user 应该成功了,loaded - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); - // 最后 orders 应该失败了,error 状态 - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, USER_DATA); - t.is(context.dataSourceMap.user.error, undefined); - t.deepEqual(context.dataSourceMap.orders.data, undefined); - t.not(context.dataSourceMap.orders.error, undefined); - t.regex(context.dataSourceMap.orders.error!.message, new RegExp(ERROR_MSG)); - - // 检查状态数据 - t.assert(setState.calledOnce); - t.deepEqual(context.state.user, USER_DATA); - t.is(context.state.orders, undefined); - - // fetchHandler 应该被调用了2次 - t.assert(fetchHandler.calledTwice); - - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - // 检查调用参数 - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); -}; abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-normal.ts index 2587c08b3..c6a95c672 100644 --- a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-normal.ts +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-normal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; @@ -17,76 +17,76 @@ export const normalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; + ) => { + const { clock } = t.context; - const USER_DATA = { - id: 9527, - name: 'Alice', + const USER_DATA = { + id: 9527, + name: 'Alice', + }; + + const ORDERS_DATA = [{ id: 123 }, { id: 456 }]; + + const fetchHandler = sinon.fake(async ({ uri }) => { + await delay(100); + return { data: /user/.test(uri) ? USER_DATA : ORDERS_DATA }; + }); + + const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(50); + + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + t.deepEqual(context.dataSourceMap.orders.data, ORDERS_DATA); + t.deepEqual(context.dataSourceMap.orders.error, undefined); + + // 检查状态数据 + t.assert(setState.calledTwice); + t.deepEqual(context.state.user, USER_DATA); + t.deepEqual(context.state.orders, ORDERS_DATA); + + // fetchHandler 应该被调用了2次 + t.assert(fetchHandler.calledTwice); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); }; - const ORDERS_DATA = [{ id: 123 }, { id: 456 }]; - - const fetchHandler = sinon.fake(async ({ uri }) => { - await delay(100); - return { data: /user/.test(uri) ? USER_DATA : ORDERS_DATA }; - }); - - const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - })); - - const setState = sinon.spy(context, 'setState'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - - await clock.tickAsync(50); - - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后应该成功了,loaded 状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loaded); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, USER_DATA); - t.deepEqual(context.dataSourceMap.user.error, undefined); - t.deepEqual(context.dataSourceMap.orders.data, ORDERS_DATA); - t.deepEqual(context.dataSourceMap.orders.error, undefined); - - // 检查状态数据 - t.assert(setState.calledTwice); - t.deepEqual(context.state.user, USER_DATA); - t.deepEqual(context.state.orders, ORDERS_DATA); - - // fetchHandler 应该被调用了2次 - t.assert(fetchHandler.calledTwice); - - // 检查调用参数 - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); -}; - normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-runtime.ts index 2f58b64e0..09b060b49 100644 --- a/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-runtime.ts +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-runtime.ts @@ -1,4 +1,4 @@ -import { RuntimeDataSource } from '@ali/build-success-types'; +import { RuntimeDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-schema.ts index 9b00b9300..20fcb2154 100644 --- a/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-schema.ts +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/_datasource-schema.ts @@ -1,8 +1,8 @@ -import { DataSource } from '@ali/build-success-types'; +import { InterpretDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的 schema: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 -export const DATA_SOURCE_SCHEMA: DataSource = { +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { list: [ { id: 'urlParams', diff --git a/packages/datasource-engine/test/scenes/p0-0-url-params/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-0-url-params/_macro-normal.ts index 4b0b9bc06..0156af315 100644 --- a/packages/datasource-engine/test/scenes/p0-0-url-params/_macro-normal.ts +++ b/packages/datasource-engine/test/scenes/p0-0-url-params/_macro-normal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { MockContext } from '../../_helpers'; @@ -16,57 +16,57 @@ export const normalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; + ) => { + const { clock } = t.context; - const URL_PARAMS = { - name: 'Alice', - age: '18', + const URL_PARAMS = { + name: 'Alice', + age: '18', + }; + + const urlParamsHandler = sinon.fake(async () => { + return URL_PARAMS; // TODO: 别的都是返回的套了一层 data 的,但是 urlParams 的为啥不一样? + }); + + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + urlParams: urlParamsHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.urlParams.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.urlParams.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.urlParams.data, URL_PARAMS); + t.deepEqual(context.dataSourceMap.urlParams.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.urlParams, URL_PARAMS); + + // fetchHandler 应该被调用了一次 + t.assert(urlParamsHandler.calledOnce); + + // 检查调用参数 url 没有 options + t.deepEqual(urlParamsHandler.firstCall.args, [context]); }; - const urlParamsHandler = sinon.fake(async () => { - return URL_PARAMS; // TODO: 别的都是返回的套了一层 data 的,但是 urlParams 的为啥不一样? - }); - - const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { - requestHandlersMap: { - urlParams: urlParamsHandler, - }, - })); - - const setState = sinon.spy(context, 'setState'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.urlParams.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后应该成功了,loaded 状态 - t.is(context.dataSourceMap.urlParams.status, RuntimeDataSourceStatus.Loaded); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.urlParams.data, URL_PARAMS); - t.deepEqual(context.dataSourceMap.urlParams.error, undefined); - - // 检查状态数据 - t.assert(setState.calledOnce); - t.deepEqual(context.state.urlParams, URL_PARAMS); - - // fetchHandler 应该被调用了一次 - t.assert(urlParamsHandler.calledOnce); - - // 检查调用参数 url 没有 options - t.deepEqual(urlParamsHandler.firstCall.args, [context]); -}; - normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-runtime.ts index 756adeb83..4b06ca7b8 100644 --- a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-runtime.ts +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-runtime.ts @@ -1,4 +1,4 @@ -import { RuntimeDataSource } from '@ali/build-success-types'; +import { RuntimeDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-schema.ts index 111cf641f..2352df683 100644 --- a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-schema.ts +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_datasource-schema.ts @@ -1,8 +1,8 @@ -import { DataSource } from '@ali/build-success-types'; +import { InterpretDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的 schema: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 -export const DATA_SOURCE_SCHEMA: DataSource = { +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { list: [ { id: 'user', diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-abnormal.ts index 757aaba6e..a07619bd4 100644 --- a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-abnormal.ts +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-abnormal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; @@ -17,79 +17,79 @@ export const abnormalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; - const ERROR_MSG = 'test error'; - const fetchHandler = sinon.fake(async () => { - await delay(100); - return { - data: { - success: false, - message: ERROR_MSG, - code: 'E_FOO', + ) => { + const { clock } = t.context; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: { + success: false, + message: ERROR_MSG, + code: 'E_FOO', + }, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() { }, }, - }; - }); + ); - const context = new MockContext>( - {}, - (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - }), - { - recordError() {}, - }, - ); + const setState = sinon.spy(context, 'setState'); + const recordError = sinon.spy(context, 'recordError'); - const setState = sinon.spy(context, 'setState'); - const recordError = sinon.spy(context, 'recordError'); + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + const loading = context.reloadDataSource(); - const loading = context.reloadDataSource(); + await clock.tickAsync(50); - await clock.tickAsync(50); + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + await Promise.all([clock.runAllAsync(), loading]); - await Promise.all([clock.runAllAsync(), loading]); + // 最后应该失败了,error 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); - // 最后应该失败了,error 状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, undefined); + t.not(context.dataSourceMap.user.error, undefined); - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, undefined); - t.not(context.dataSourceMap.user.error, undefined); + t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); - t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); + // 检查状态数据 + t.assert(setState.notCalled); + t.deepEqual(context.state.user, undefined); - // 检查状态数据 - t.assert(setState.notCalled); - t.deepEqual(context.state.user, undefined); + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); - // fetchHandler 应该被调用了一次 - t.assert(fetchHandler.calledOnce); + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); - // 检查调用参数 - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); - - // 埋点应该也会被调用 - t.assert(recordError.calledOnce); - t.snapshot(recordError.firstCall.args); -}; + // 埋点应该也会被调用 + t.assert(recordError.calledOnce); + t.snapshot(recordError.firstCall.args); + }; abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-normal.ts index d00fa39d9..8774ef200 100644 --- a/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-normal.ts +++ b/packages/datasource-engine/test/scenes/p0-1-custom-response-status/_macro-normal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; @@ -17,80 +17,80 @@ export const normalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; + ) => { + const { clock } = t.context; - const USER_DATA = { - name: 'Alice', - age: 18, + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: { + success: true, + data: USER_DATA, + }, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() { }, + }, + ); + + const setState = sinon.spy(context, 'setState'); + const recordError = sinon.spy(context, 'recordError'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + + // 埋点不应该被调用 + t.assert(recordError.notCalled); }; - const fetchHandler = sinon.fake(async () => { - await delay(100); - return { - data: { - success: true, - data: USER_DATA, - }, - }; - }); - - const context = new MockContext>( - {}, - (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - }), - { - recordError() {}, - }, - ); - - const setState = sinon.spy(context, 'setState'); - const recordError = sinon.spy(context, 'recordError'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后应该成功了,loaded 状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, USER_DATA); - t.deepEqual(context.dataSourceMap.user.error, undefined); - - // 检查状态数据 - t.assert(setState.calledOnce); - t.deepEqual(context.state.user, USER_DATA); - - // fetchHandler 应该被调用了一次 - t.assert(fetchHandler.calledOnce); - - // 检查调用参数 - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); - - // 埋点不应该被调用 - t.assert(recordError.notCalled); -}; - normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-runtime.ts index 2608841e1..d9ac8d6d0 100644 --- a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-runtime.ts +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-runtime.ts @@ -1,4 +1,4 @@ -import { RuntimeDataSource } from '@ali/build-success-types'; +import { RuntimeDataSource } from '@ali/lowcode-types'; export const DEFAULT_USER_DATA = { id: 0, name: 'guest' }; // 返回一个兜底的数据 diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-schema.ts index b9b44cc6a..1b33622a9 100644 --- a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-schema.ts +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_datasource-schema.ts @@ -1,8 +1,8 @@ -import { DataSource } from '@ali/build-success-types'; +import { InterpretDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的 schema: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 -export const DATA_SOURCE_SCHEMA: DataSource = { +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { list: [ { id: 'user', diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-abnormal.ts index 1c1e5d800..4b5a2237e 100644 --- a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-abnormal.ts +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-abnormal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { delay, MockContext } from '../../_helpers'; @@ -17,62 +17,62 @@ export const abnormalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; - const ERROR_MSG = 'test error'; - const fetchHandler = sinon.fake(async () => { - await delay(100); - throw new Error(ERROR_MSG); - }); + ) => { + const { clock } = t.context; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async () => { + await delay(100); + throw new Error(ERROR_MSG); + }); - const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - })); + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); - const setState = sinon.spy(context, 'setState'); + const setState = sinon.spy(context, 'setState'); - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - const loading = context.reloadDataSource(); + const loading = context.reloadDataSource(); - await clock.tickAsync(50); + await clock.tickAsync(50); - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - await Promise.all([clock.runAllAsync(), loading]); + await Promise.all([clock.runAllAsync(), loading]); - // 注意 error 是会被吃掉了,还是 loaded 状态 - // FIXME: 根据协议内容,dataHandler 返回的结果是需要抛出错误的,那么 fetchHandler 的错误难道不需要处理? - // TODO: 提案:request 如果挂了,不应该需要走 dataHandler 了,没有意义 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); + // 注意 error 是会被吃掉了,还是 loaded 状态 + // FIXME: 根据协议内容,dataHandler 返回的结果是需要抛出错误的,那么 fetchHandler 的错误难道不需要处理? + // TODO: 提案:request 如果挂了,不应该需要走 dataHandler 了,没有意义 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, undefined); - t.not(context.dataSourceMap.user.error, undefined); - t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, undefined); + t.not(context.dataSourceMap.user.error, undefined); + t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); - // 检查状态数据 - t.assert(setState.notCalled); + // 检查状态数据 + t.assert(setState.notCalled); - // fetchHandler 应该没调 - t.assert.skip(fetchHandler.notCalled); + // fetchHandler 应该没调 + t.assert.skip(fetchHandler.notCalled); - // 检查调用参数 - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); -}; + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + }; abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-normal.ts index 78aa87c61..c8484c434 100644 --- a/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-normal.ts +++ b/packages/datasource-engine/test/scenes/p0-1-data-handler-can-eat-errors/_macro-normal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { delay, MockContext } from '../../_helpers'; @@ -17,65 +17,65 @@ export const normalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; + ) => { + const { clock } = t.context; - const USER_DATA = { - name: 'Alice', - age: 18, + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { data: USER_DATA }; + }); + + const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); }; - const fetchHandler = sinon.fake(async () => { - await delay(100); - return { data: USER_DATA }; - }); - - const context = new MockContext>({}, (ctx) => create(dataSource, ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - })); - - const setState = sinon.spy(context, 'setState'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后应该成功了,loaded 状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, USER_DATA); - t.deepEqual(context.dataSourceMap.user.error, undefined); - - // 检查状态数据 - t.assert(setState.calledOnce); - t.deepEqual(context.state.user, USER_DATA); - - // fetchHandler 应该被调用了一次 - t.assert(fetchHandler.calledOnce); - - // 检查调用参数 - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); -}; - normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-runtime.ts index 5dc07956a..19d35f910 100644 --- a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-runtime.ts +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-runtime.ts @@ -1,4 +1,4 @@ -import { RuntimeDataSource } from '@ali/build-success-types'; +import { RuntimeDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-schema.ts index f35743828..f163ea6c2 100644 --- a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-schema.ts +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_datasource-schema.ts @@ -1,8 +1,8 @@ -import { DataSource } from '@ali/build-success-types'; +import { InterpretDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的 schema: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 -export const DATA_SOURCE_SCHEMA: DataSource = { +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { list: [ { id: 'user', diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-abnormal.ts index 757aaba6e..a07619bd4 100644 --- a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-abnormal.ts +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-abnormal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; @@ -17,79 +17,79 @@ export const abnormalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; - const ERROR_MSG = 'test error'; - const fetchHandler = sinon.fake(async () => { - await delay(100); - return { - data: { - success: false, - message: ERROR_MSG, - code: 'E_FOO', + ) => { + const { clock } = t.context; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: { + success: false, + message: ERROR_MSG, + code: 'E_FOO', + }, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() { }, }, - }; - }); + ); - const context = new MockContext>( - {}, - (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - }), - { - recordError() {}, - }, - ); + const setState = sinon.spy(context, 'setState'); + const recordError = sinon.spy(context, 'recordError'); - const setState = sinon.spy(context, 'setState'); - const recordError = sinon.spy(context, 'recordError'); + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + const loading = context.reloadDataSource(); - const loading = context.reloadDataSource(); + await clock.tickAsync(50); - await clock.tickAsync(50); + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + await Promise.all([clock.runAllAsync(), loading]); - await Promise.all([clock.runAllAsync(), loading]); + // 最后应该失败了,error 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); - // 最后应该失败了,error 状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Error); + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, undefined); + t.not(context.dataSourceMap.user.error, undefined); - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, undefined); - t.not(context.dataSourceMap.user.error, undefined); + t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); - t.regex(context.dataSourceMap.user.error!.message, new RegExp(ERROR_MSG)); + // 检查状态数据 + t.assert(setState.notCalled); + t.deepEqual(context.state.user, undefined); - // 检查状态数据 - t.assert(setState.notCalled); - t.deepEqual(context.state.user, undefined); + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); - // fetchHandler 应该被调用了一次 - t.assert(fetchHandler.calledOnce); + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); - // 检查调用参数 - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); - - // 埋点应该也会被调用 - t.assert(recordError.calledOnce); - t.snapshot(recordError.firstCall.args); -}; + // 埋点应该也会被调用 + t.assert(recordError.calledOnce); + t.snapshot(recordError.firstCall.args); + }; abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; diff --git a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-normal.ts b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-normal.ts index d00fa39d9..8774ef200 100644 --- a/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-normal.ts +++ b/packages/datasource-engine/test/scenes/p1-0-data-handler-returns-promise/_macro-normal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; @@ -17,80 +17,80 @@ export const normalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; + ) => { + const { clock } = t.context; - const USER_DATA = { - name: 'Alice', - age: 18, + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: { + success: true, + data: USER_DATA, + }, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() { }, + }, + ); + + const setState = sinon.spy(context, 'setState'); + const recordError = sinon.spy(context, 'recordError'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后应该成功了,loaded 状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.deepEqual(context.dataSourceMap.user.error, undefined); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了一次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + + // 埋点不应该被调用 + t.assert(recordError.notCalled); }; - const fetchHandler = sinon.fake(async () => { - await delay(100); - return { - data: { - success: true, - data: USER_DATA, - }, - }; - }); - - const context = new MockContext>( - {}, - (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - }), - { - recordError() {}, - }, - ); - - const setState = sinon.spy(context, 'setState'); - const recordError = sinon.spy(context, 'recordError'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后应该成功了,loaded 状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, USER_DATA); - t.deepEqual(context.dataSourceMap.user.error, undefined); - - // 检查状态数据 - t.assert(setState.calledOnce); - t.deepEqual(context.state.user, USER_DATA); - - // fetchHandler 应该被调用了一次 - t.assert(fetchHandler.calledOnce); - - // 检查调用参数 - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); - - // 埋点不应该被调用 - t.assert(recordError.notCalled); -}; - normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-runtime.ts index 2085535c6..49d30425e 100644 --- a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-runtime.ts +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-runtime.ts @@ -1,4 +1,4 @@ -import { RuntimeDataSource } from '@ali/build-success-types'; +import { RuntimeDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-schema.ts index e333f485a..4032c9a35 100644 --- a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-schema.ts +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_datasource-schema.ts @@ -1,8 +1,8 @@ -import { DataSource } from '@ali/build-success-types'; +import { InterpretDataSource } from '@ali/lowcode-types'; // 这里仅仅是数据源部分的 schema: // @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 -export const DATA_SOURCE_SCHEMA: DataSource = { +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { list: [ { id: 'user', diff --git a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_macro-normal.ts b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_macro-normal.ts index 4289a6d89..a12e0a48c 100644 --- a/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_macro-normal.ts +++ b/packages/datasource-engine/test/scenes/p1-1-shouldfetch-control-request/_macro-normal.ts @@ -1,10 +1,10 @@ import { - DataSource, + InterpretDataSource, IDataSourceEngine, - IRuntimeContext, + IDataSourceRuntimeContext, RuntimeDataSource, RuntimeDataSourceStatus, -} from '@ali/build-success-types'; +} from '@ali/lowcode-types'; import sinon from 'sinon'; import { bindRuntimeContext, delay, MockContext } from '../../_helpers'; @@ -17,92 +17,92 @@ export const normalScene: Macro<[ { create: ( dataSource: any, - ctx: IRuntimeContext, + ctx: IDataSourceRuntimeContext, options: any ) => IDataSourceEngine; - dataSource: RuntimeDataSource | DataSource; + dataSource: RuntimeDataSource | InterpretDataSource; } ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, -) => { - const { clock } = t.context; - const ORDERS_ERROR_MSG = - 'the orders request should not fetch, please check the condition'; + ) => { + const { clock } = t.context; + const ORDERS_ERROR_MSG = + 'the orders request should not fetch, please check the condition'; - const USER_DATA = { - name: 'Alice', - age: 18, + const USER_DATA = { + name: 'Alice', + age: 18, + }; + + const fetchHandler = sinon.fake(async () => { + await delay(100); + return { + data: USER_DATA, + }; + }); + + const context = new MockContext>( + {}, + (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + }), + { + recordError() { }, + }, + ); + + const setState = sinon.spy(context, 'setState'); + // const recordError = sinon.spy(context, 'recordError'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后 user 成功, orders 失败 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.is(context.dataSourceMap.user.error, undefined); + t.regex( + context.dataSourceMap.orders.error!.message, + new RegExp(ORDERS_ERROR_MSG), + ); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + + // fetchHandler 应该被调用了 1 次 + t.assert(fetchHandler.calledOnce); + + // 检查调用参数 + + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + + // // 埋点应该也会被调用 + // t.assert(recordError.calledOnce); + // t.snapshot(recordError.firstCall.args); }; - const fetchHandler = sinon.fake(async () => { - await delay(100); - return { - data: USER_DATA, - }; - }); - - const context = new MockContext>( - {}, - (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - }), - { - recordError() {}, - }, - ); - - const setState = sinon.spy(context, 'setState'); - // const recordError = sinon.spy(context, 'recordError'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后 user 成功, orders 失败 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, USER_DATA); - t.is(context.dataSourceMap.user.error, undefined); - t.regex( - context.dataSourceMap.orders.error!.message, - new RegExp(ORDERS_ERROR_MSG), - ); - - // 检查状态数据 - t.assert(setState.calledOnce); - t.deepEqual(context.state.user, USER_DATA); - - // fetchHandler 应该被调用了 1 次 - t.assert(fetchHandler.calledOnce); - - // 检查调用参数 - - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); - - // // 埋点应该也会被调用 - // t.assert(recordError.calledOnce); - // t.snapshot(recordError.firstCall.args); -}; - normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-fetch-handler/.eslintignore b/packages/datasource-fetch-handler/.eslintignore new file mode 100644 index 000000000..fecb7c26d --- /dev/null +++ b/packages/datasource-fetch-handler/.eslintignore @@ -0,0 +1,3 @@ +/node_modules +/es +/lib \ No newline at end of file diff --git a/packages/datasource-handlers/.eslintrc.js b/packages/datasource-fetch-handler/.eslintrc.js similarity index 78% rename from packages/datasource-handlers/.eslintrc.js rename to packages/datasource-fetch-handler/.eslintrc.js index e19c549ba..8c13fcaf4 100644 --- a/packages/datasource-handlers/.eslintrc.js +++ b/packages/datasource-fetch-handler/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = { - extends: '../../.eslintrc.js', + extends: '../../.eslintrc', rules: { '@typescript-eslint/no-parameter-properties': 1, 'no-param-reassign': 0, diff --git a/packages/datasource-handlers/.prettierrc.js b/packages/datasource-fetch-handler/.prettierrc.js similarity index 61% rename from packages/datasource-handlers/.prettierrc.js rename to packages/datasource-fetch-handler/.prettierrc.js index d2db80ead..de2f53cdf 100644 --- a/packages/datasource-handlers/.prettierrc.js +++ b/packages/datasource-fetch-handler/.prettierrc.js @@ -1,4 +1,4 @@ module.exports = { singleQuote: true, - trailingComma: 'always', + trailingComma: 'all', }; diff --git a/packages/datasource-handlers/packages/fetch/package.json b/packages/datasource-fetch-handler/package.json similarity index 88% rename from packages/datasource-handlers/packages/fetch/package.json rename to packages/datasource-fetch-handler/package.json index ad28decb4..8dbc63a6f 100644 --- a/packages/datasource-handlers/packages/fetch/package.json +++ b/packages/datasource-fetch-handler/package.json @@ -16,12 +16,10 @@ "prepublishOnly": "npm run build" }, "dependencies": { + "@ali/lowcode-types": "^1.0.10", "typescript": "^3.9.7", "universal-request": "^2.2.0" }, - "devDependencies": { - "@ali/build-success-types": "^0.1.2-alpha.35" - }, "publishConfig": { "registry": "https://registry.npm.alibaba-inc.com" }, diff --git a/packages/datasource-handlers/packages/fetch/src/index.ts b/packages/datasource-fetch-handler/src/index.ts similarity index 90% rename from packages/datasource-handlers/packages/fetch/src/index.ts rename to packages/datasource-fetch-handler/src/index.ts index d59fc0a8d..2bb5df893 100644 --- a/packages/datasource-handlers/packages/fetch/src/index.ts +++ b/packages/datasource-fetch-handler/src/index.ts @@ -1,4 +1,4 @@ -import { RuntimeOptionsConfig } from '@ali/build-success-types'; +import { RuntimeOptionsConfig } from '@ali/lowcode-types'; import request from 'universal-request'; import { RequestOptions, AsObject } from 'universal-request/lib/types'; diff --git a/packages/datasource-handlers/tsconfig.json b/packages/datasource-fetch-handler/tsconfig.json similarity index 95% rename from packages/datasource-handlers/tsconfig.json rename to packages/datasource-fetch-handler/tsconfig.json index 68d4e6bb3..ecd74d9e2 100644 --- a/packages/datasource-handlers/tsconfig.json +++ b/packages/datasource-fetch-handler/tsconfig.json @@ -1,10 +1,16 @@ { "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext", /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ // "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, // "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "lib": ["ESNext", "DOM"] /* Specify library files to be included in the compilation. */, + "lib": [ + "ESNext", + "DOM" + ] /* Specify library files to be included in the compilation. */, // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ @@ -21,7 +27,6 @@ // "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ @@ -31,13 +36,11 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - /* Module Resolution Options */ "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ @@ -49,19 +52,19 @@ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - /* Source Map Options */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - /* Advanced Options */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "skipLibCheck": true + "skipLibCheck": true, + "include": [ + "src/**/*" + ] } -} +} \ No newline at end of file diff --git a/packages/datasource-handlers/.eslintignore b/packages/datasource-handlers/.eslintignore deleted file mode 100644 index 096746c14..000000000 --- a/packages/datasource-handlers/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -/node_modules/ \ No newline at end of file diff --git a/packages/datasource-handlers/lerna.json b/packages/datasource-handlers/lerna.json deleted file mode 100644 index b9933894c..000000000 --- a/packages/datasource-handlers/lerna.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "packages": ["packages/*"], - "version": "independent", - "npmClient": "yarn" -} diff --git a/packages/datasource-handlers/package.json b/packages/datasource-handlers/package.json deleted file mode 100644 index 43cea9f9d..000000000 --- a/packages/datasource-handlers/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "@ali/lowcode-datasource-handlers", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "devDependencies": { - "lerna": "^3.22.0" - } -} diff --git a/packages/datasource-handlers/packages/fetch/es/index.d.ts b/packages/datasource-handlers/packages/fetch/es/index.d.ts deleted file mode 100644 index 443ad0dd1..000000000 --- a/packages/datasource-handlers/packages/fetch/es/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { RuntimeOptionsConfig } from '@ali/build-success-types'; -export declare function createFetchHandler(config?: unknown): (options: RuntimeOptionsConfig) => Promise; diff --git a/packages/datasource-handlers/packages/fetch/es/index.js b/packages/datasource-handlers/packages/fetch/es/index.js deleted file mode 100644 index 0b4d6e5ba..000000000 --- a/packages/datasource-handlers/packages/fetch/es/index.js +++ /dev/null @@ -1,25 +0,0 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import request from 'universal-request'; -// config 留着扩展 -export function createFetchHandler(config) { - return function (options) { - return __awaiter(this, void 0, void 0, function* () { - const requestConfig = Object.assign(Object.assign({}, options), { url: options.uri, method: options.method, data: options.params, headers: options.headers }); - try { - const response = yield request(requestConfig); - return response; - } - catch (error) { - throw error; - } - }); - }; -} diff --git a/packages/datasource-handlers/packages/fetch/tsconfig.json b/packages/datasource-handlers/packages/fetch/tsconfig.json deleted file mode 100644 index 268731175..000000000 --- a/packages/datasource-handlers/packages/fetch/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "es", - "target": "es6", - "module": "esnext" - }, - - "include": ["src/**/*"] -} diff --git a/packages/datasource-handlers/packages/mopen/es/index.d.ts b/packages/datasource-handlers/packages/mopen/es/index.d.ts deleted file mode 100644 index 17039d9f2..000000000 --- a/packages/datasource-handlers/packages/mopen/es/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { MopenClientConfig } from '@ali/mirror-io-client-mopen'; -import { RuntimeOptionsConfig } from '@ali/build-success-types'; -export declare function createMopenHandler(config?: MopenClientConfig): (options: RuntimeOptionsConfig) => Promise<{ - data: T; -}>; diff --git a/packages/datasource-handlers/packages/mopen/es/index.js b/packages/datasource-handlers/packages/mopen/es/index.js deleted file mode 100644 index 967facd1d..000000000 --- a/packages/datasource-handlers/packages/mopen/es/index.js +++ /dev/null @@ -1,26 +0,0 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import { MopenClient, MOPEN_APPKEY_XSPACE_PRE_ONLINE, MOPEN_DOMAIN_TAOBAO_PRE_ONLINE, } from '@ali/mirror-io-client-mopen'; -export function createMopenHandler(config = { - mtopDomain: MOPEN_DOMAIN_TAOBAO_PRE_ONLINE, - appKey: MOPEN_APPKEY_XSPACE_PRE_ONLINE, -}) { - return function (options) { - return __awaiter(this, void 0, void 0, function* () { - try { - const { data, response } = yield MopenClient.request(Object.assign(Object.assign({ config }, options), { api: options.uri, v: options.v, data: options.params, type: options.method || 'get', dataType: options.dataType || 'json', timeout: options.timeout, headers: options.headers })); - return Object.assign(Object.assign({}, response), { data }); - } - catch (error) { - throw error; - } - }); - }; -} diff --git a/packages/datasource-handlers/packages/mopen/tsconfig.json b/packages/datasource-handlers/packages/mopen/tsconfig.json deleted file mode 100644 index 268731175..000000000 --- a/packages/datasource-handlers/packages/mopen/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "es", - "target": "es6", - "module": "esnext" - }, - - "include": ["src/**/*"] -} diff --git a/packages/datasource-handlers/packages/mtop/es/index.d.ts b/packages/datasource-handlers/packages/mtop/es/index.d.ts deleted file mode 100644 index c30b6a50a..000000000 --- a/packages/datasource-handlers/packages/mtop/es/index.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { RuntimeOptionsConfig } from '@ali/build-success-types'; -export declare type Method = 'get' | 'post' | 'GET' | 'POST'; -export declare type DataType = 'jsonp' | 'json' | 'originaljsonp'; -export declare function createMtopHandler(config?: MTopConfig): (options: RuntimeOptionsConfig) => Promise<{ - data: T; -}>; diff --git a/packages/datasource-handlers/packages/mtop/es/index.js b/packages/datasource-handlers/packages/mtop/es/index.js deleted file mode 100644 index fed789e22..000000000 --- a/packages/datasource-handlers/packages/mtop/es/index.js +++ /dev/null @@ -1,35 +0,0 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import mtopRequest from '@ali/universal-mtop'; -// 考虑一下 mtop 类型的问题,官方没有提供 ts 文件 -export function createMtopHandler(config) { - if (config && Object.keys(config).length > 0) { - Object.keys(config).forEach((key) => mtopRequest.config(key, config[key])); - } - return function (options) { - return __awaiter(this, void 0, void 0, function* () { - try { - const response = yield mtopRequest.request({ - api: options.uri, - v: options.v || '1.0', - data: options.params, - type: options.method || 'get', - dataType: options.dataType || 'json', - timeout: options.timeout, - headers: options.headers, - }); - return response; - } - catch (error) { - throw error; - } - }); - }; -} diff --git a/packages/datasource-handlers/packages/mtop/tsconfig.json b/packages/datasource-handlers/packages/mtop/tsconfig.json deleted file mode 100644 index 268731175..000000000 --- a/packages/datasource-handlers/packages/mtop/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "es", - "target": "es6", - "module": "esnext" - }, - - "include": ["src/**/*"] -} diff --git a/packages/datasource-handlers/packages/universalMtop/es/index.d.ts b/packages/datasource-handlers/packages/universalMtop/es/index.d.ts deleted file mode 100644 index 2a16eb3e9..000000000 --- a/packages/datasource-handlers/packages/universalMtop/es/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { UniversalMtopClientConfig } from '@ali/mirror-io-client-universal-mtop'; -import { RuntimeOptionsConfig } from '@ali/build-success-types'; -export declare function createMopenHandler(config?: UniversalMtopClientConfig): (options: RuntimeOptionsConfig) => Promise<{ - data: T; -}>; diff --git a/packages/datasource-handlers/packages/universalMtop/es/index.js b/packages/datasource-handlers/packages/universalMtop/es/index.js deleted file mode 100644 index 718adf31b..000000000 --- a/packages/datasource-handlers/packages/universalMtop/es/index.js +++ /dev/null @@ -1,23 +0,0 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import { UniversalMtopClient, } from '@ali/mirror-io-client-universal-mtop'; -export function createMopenHandler(config) { - return function (options) { - return __awaiter(this, void 0, void 0, function* () { - try { - const { data, response } = yield UniversalMtopClient.request(Object.assign(Object.assign({ config }, options), { api: options.uri, v: options.v, data: options.params, type: options.method || 'get', dataType: options.dataType || 'json', timeout: options.timeout, headers: options.headers })); - return Object.assign(Object.assign({}, response), { data }); - } - catch (error) { - throw error; - } - }); - }; -} diff --git a/packages/datasource-handlers/packages/universalMtop/tsconfig.json b/packages/datasource-handlers/packages/universalMtop/tsconfig.json deleted file mode 100644 index 268731175..000000000 --- a/packages/datasource-handlers/packages/universalMtop/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "es", - "target": "es6", - "module": "esnext" - }, - - "include": ["src/**/*"] -} diff --git a/packages/datasource-handlers/packages/urlParams/es/index.d.ts b/packages/datasource-handlers/packages/urlParams/es/index.d.ts deleted file mode 100644 index f16cb44c3..000000000 --- a/packages/datasource-handlers/packages/urlParams/es/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { UrlParamsHandler } from '@ali/build-success-types'; -export declare function createUrlParamsHandler(searchString?: string | T): UrlParamsHandler; diff --git a/packages/datasource-handlers/packages/urlParams/es/index.js b/packages/datasource-handlers/packages/urlParams/es/index.js deleted file mode 100644 index 84a9451ef..000000000 --- a/packages/datasource-handlers/packages/urlParams/es/index.js +++ /dev/null @@ -1,21 +0,0 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import qs from 'query-string'; -export function createUrlParamsHandler(searchString = '') { - return function () { - return __awaiter(this, void 0, void 0, function* () { - if (typeof searchString === 'string') { - const params = qs.parse(searchString); - return params; - } - return searchString; - }); - }; -} diff --git a/packages/datasource-handlers/packages/urlParams/tsconfig.json b/packages/datasource-handlers/packages/urlParams/tsconfig.json deleted file mode 100644 index 268731175..000000000 --- a/packages/datasource-handlers/packages/urlParams/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "es", - "target": "es6", - "module": "esnext" - }, - - "include": ["src/**/*"] -} diff --git a/packages/datasource-mopen-handler/.eslintignore b/packages/datasource-mopen-handler/.eslintignore new file mode 100644 index 000000000..fecb7c26d --- /dev/null +++ b/packages/datasource-mopen-handler/.eslintignore @@ -0,0 +1,3 @@ +/node_modules +/es +/lib \ No newline at end of file diff --git a/packages/datasource-mopen-handler/.eslintrc.js b/packages/datasource-mopen-handler/.eslintrc.js new file mode 100644 index 000000000..8c13fcaf4 --- /dev/null +++ b/packages/datasource-mopen-handler/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: '../../.eslintrc', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + 'no-param-reassign': 0, + }, +}; diff --git a/packages/datasource-mopen-handler/.prettierrc.js b/packages/datasource-mopen-handler/.prettierrc.js new file mode 100644 index 000000000..de2f53cdf --- /dev/null +++ b/packages/datasource-mopen-handler/.prettierrc.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'all', +}; diff --git a/packages/datasource-handlers/packages/mopen/package.json b/packages/datasource-mopen-handler/package.json similarity index 89% rename from packages/datasource-handlers/packages/mopen/package.json rename to packages/datasource-mopen-handler/package.json index 87ff98947..7c60a774a 100644 --- a/packages/datasource-handlers/packages/mopen/package.json +++ b/packages/datasource-mopen-handler/package.json @@ -15,10 +15,8 @@ "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", "prepublishOnly": "npm run build" }, - "devDependencies": { - "@ali/build-success-types": "^0.1.2-alpha.35" - }, "dependencies": { + "@ali/lowcode-types": "^1.0.10", "@ali/mirror-io-client-mopen": "1.0.0-beta.16", "typescript": "^3.9.7" }, diff --git a/packages/datasource-handlers/packages/mopen/src/index.ts b/packages/datasource-mopen-handler/src/index.ts similarity index 93% rename from packages/datasource-handlers/packages/mopen/src/index.ts rename to packages/datasource-mopen-handler/src/index.ts index 9367fbb4f..6fc4fb287 100644 --- a/packages/datasource-handlers/packages/mopen/src/index.ts +++ b/packages/datasource-mopen-handler/src/index.ts @@ -4,7 +4,7 @@ import { MOPEN_APPKEY_XSPACE_PRE_ONLINE, MOPEN_DOMAIN_TAOBAO_PRE_ONLINE, } from '@ali/mirror-io-client-mopen'; -import { RuntimeOptionsConfig } from '@ali/build-success-types'; +import { RuntimeOptionsConfig } from '@ali/lowcode-types'; type Method = 'get' | 'post' | 'GET' | 'POST'; diff --git a/packages/datasource-mopen-handler/tsconfig.json b/packages/datasource-mopen-handler/tsconfig.json new file mode 100644 index 000000000..ecd74d9e2 --- /dev/null +++ b/packages/datasource-mopen-handler/tsconfig.json @@ -0,0 +1,70 @@ +{ + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext", + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + // "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + // "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": [ + "ESNext", + "DOM" + ] /* Specify library files to be included in the compilation. */, + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "es" /* Redirect output structure to the directory. */, + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + "skipLibCheck": true, + "include": [ + "src/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/datasource-mtop-handler/.eslintignore b/packages/datasource-mtop-handler/.eslintignore new file mode 100644 index 000000000..fecb7c26d --- /dev/null +++ b/packages/datasource-mtop-handler/.eslintignore @@ -0,0 +1,3 @@ +/node_modules +/es +/lib \ No newline at end of file diff --git a/packages/datasource-mtop-handler/.eslintrc.js b/packages/datasource-mtop-handler/.eslintrc.js new file mode 100644 index 000000000..8c13fcaf4 --- /dev/null +++ b/packages/datasource-mtop-handler/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: '../../.eslintrc', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + 'no-param-reassign': 0, + }, +}; diff --git a/packages/datasource-mtop-handler/.prettierrc.js b/packages/datasource-mtop-handler/.prettierrc.js new file mode 100644 index 000000000..de2f53cdf --- /dev/null +++ b/packages/datasource-mtop-handler/.prettierrc.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'all', +}; diff --git a/packages/datasource-handlers/packages/mtop/package.json b/packages/datasource-mtop-handler/package.json similarity index 88% rename from packages/datasource-handlers/packages/mtop/package.json rename to packages/datasource-mtop-handler/package.json index d0f0288c7..2143f71eb 100644 --- a/packages/datasource-handlers/packages/mtop/package.json +++ b/packages/datasource-mtop-handler/package.json @@ -15,10 +15,8 @@ "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", "prepublishOnly": "npm run build" }, - "devDependencies": { - "@ali/build-success-types": "^0.1.2-alpha.35" - }, "dependencies": { + "@ali/lowcode-types": "^1.0.10", "@ali/universal-mtop": "^5.1.9", "typescript": "^3.9.7" }, diff --git a/packages/datasource-handlers/packages/mtop/src/index.ts b/packages/datasource-mtop-handler/src/index.ts similarity index 93% rename from packages/datasource-handlers/packages/mtop/src/index.ts rename to packages/datasource-mtop-handler/src/index.ts index 0c01cdd64..2527dda5c 100644 --- a/packages/datasource-handlers/packages/mtop/src/index.ts +++ b/packages/datasource-mtop-handler/src/index.ts @@ -1,6 +1,6 @@ import mtopRequest from '@ali/universal-mtop'; -import { RuntimeOptionsConfig } from '@ali/build-success-types'; +import { RuntimeOptionsConfig } from '@ali/lowcode-types'; export type Method = 'get' | 'post' | 'GET' | 'POST'; diff --git a/packages/datasource-handlers/packages/mtop/src/typings.d.ts b/packages/datasource-mtop-handler/src/typings.d.ts similarity index 100% rename from packages/datasource-handlers/packages/mtop/src/typings.d.ts rename to packages/datasource-mtop-handler/src/typings.d.ts diff --git a/packages/datasource-mtop-handler/tsconfig.json b/packages/datasource-mtop-handler/tsconfig.json new file mode 100644 index 000000000..ecd74d9e2 --- /dev/null +++ b/packages/datasource-mtop-handler/tsconfig.json @@ -0,0 +1,70 @@ +{ + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext", + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + // "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + // "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": [ + "ESNext", + "DOM" + ] /* Specify library files to be included in the compilation. */, + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "es" /* Redirect output structure to the directory. */, + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + "skipLibCheck": true, + "include": [ + "src/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/datasource-universal-mtop-handler/.eslintignore b/packages/datasource-universal-mtop-handler/.eslintignore new file mode 100644 index 000000000..fecb7c26d --- /dev/null +++ b/packages/datasource-universal-mtop-handler/.eslintignore @@ -0,0 +1,3 @@ +/node_modules +/es +/lib \ No newline at end of file diff --git a/packages/datasource-universal-mtop-handler/.eslintrc.js b/packages/datasource-universal-mtop-handler/.eslintrc.js new file mode 100644 index 000000000..8c13fcaf4 --- /dev/null +++ b/packages/datasource-universal-mtop-handler/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: '../../.eslintrc', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + 'no-param-reassign': 0, + }, +}; diff --git a/packages/datasource-universal-mtop-handler/.prettierrc.js b/packages/datasource-universal-mtop-handler/.prettierrc.js new file mode 100644 index 000000000..de2f53cdf --- /dev/null +++ b/packages/datasource-universal-mtop-handler/.prettierrc.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'all', +}; diff --git a/packages/datasource-handlers/packages/universalMtop/package.json b/packages/datasource-universal-mtop-handler/package.json similarity index 89% rename from packages/datasource-handlers/packages/universalMtop/package.json rename to packages/datasource-universal-mtop-handler/package.json index 75c9f216f..bcb45d028 100644 --- a/packages/datasource-handlers/packages/universalMtop/package.json +++ b/packages/datasource-universal-mtop-handler/package.json @@ -15,10 +15,8 @@ "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", "prepublishOnly": "npm run build" }, - "devDependencies": { - "@ali/build-success-types": "^0.1.2-alpha.27" - }, "dependencies": { + "@ali/lowcode-types": "^1.0.10", "@ali/mirror-io-client-universal-mtop": "1.0.0-beta.16", "typescript": "^3.9.7" }, diff --git a/packages/datasource-handlers/packages/universalMtop/src/index.ts b/packages/datasource-universal-mtop-handler/src/index.ts similarity index 92% rename from packages/datasource-handlers/packages/universalMtop/src/index.ts rename to packages/datasource-universal-mtop-handler/src/index.ts index f44d9eebd..81cad731d 100644 --- a/packages/datasource-handlers/packages/universalMtop/src/index.ts +++ b/packages/datasource-universal-mtop-handler/src/index.ts @@ -3,7 +3,7 @@ import { UniversalMtopClientConfig, } from '@ali/mirror-io-client-universal-mtop'; -import { RuntimeOptionsConfig } from '@ali/build-success-types'; +import { RuntimeOptionsConfig } from '@ali/lowcode-types'; type Method = 'get' | 'post' | 'GET' | 'POST'; diff --git a/packages/datasource-universal-mtop-handler/tsconfig.json b/packages/datasource-universal-mtop-handler/tsconfig.json new file mode 100644 index 000000000..ecd74d9e2 --- /dev/null +++ b/packages/datasource-universal-mtop-handler/tsconfig.json @@ -0,0 +1,70 @@ +{ + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext", + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + // "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + // "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": [ + "ESNext", + "DOM" + ] /* Specify library files to be included in the compilation. */, + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "es" /* Redirect output structure to the directory. */, + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + "skipLibCheck": true, + "include": [ + "src/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/datasource-url-params-handler/.eslintignore b/packages/datasource-url-params-handler/.eslintignore new file mode 100644 index 000000000..fecb7c26d --- /dev/null +++ b/packages/datasource-url-params-handler/.eslintignore @@ -0,0 +1,3 @@ +/node_modules +/es +/lib \ No newline at end of file diff --git a/packages/datasource-url-params-handler/.eslintrc.js b/packages/datasource-url-params-handler/.eslintrc.js new file mode 100644 index 000000000..8c13fcaf4 --- /dev/null +++ b/packages/datasource-url-params-handler/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: '../../.eslintrc', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + 'no-param-reassign': 0, + }, +}; diff --git a/packages/datasource-url-params-handler/.prettierrc.js b/packages/datasource-url-params-handler/.prettierrc.js new file mode 100644 index 000000000..e69de29bb diff --git a/packages/datasource-handlers/packages/urlParams/package.json b/packages/datasource-url-params-handler/package.json similarity index 88% rename from packages/datasource-handlers/packages/urlParams/package.json rename to packages/datasource-url-params-handler/package.json index 41ee2e618..869648b15 100644 --- a/packages/datasource-handlers/packages/urlParams/package.json +++ b/packages/datasource-url-params-handler/package.json @@ -15,10 +15,8 @@ "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", "prepublishOnly": "npm run build" }, - "devDependencies": { - "@ali/build-success-types": "^0.1.2-alpha.31" - }, "dependencies": { + "@ali/lowcode-types": "^1.0.10", "query-string": "^6.13.1", "typescript": "^3.9.7" }, diff --git a/packages/datasource-handlers/packages/urlParams/src/index.ts b/packages/datasource-url-params-handler/src/index.ts similarity index 85% rename from packages/datasource-handlers/packages/urlParams/src/index.ts rename to packages/datasource-url-params-handler/src/index.ts index c0c4a8836..db4761fc0 100644 --- a/packages/datasource-handlers/packages/urlParams/src/index.ts +++ b/packages/datasource-url-params-handler/src/index.ts @@ -1,5 +1,5 @@ import qs from 'query-string'; -import { UrlParamsHandler } from '@ali/build-success-types'; +import { UrlParamsHandler } from '@ali/lowcode-types'; export function createUrlParamsHandler( searchString: string | T = '', diff --git a/packages/datasource-url-params-handler/tsconfig.json b/packages/datasource-url-params-handler/tsconfig.json new file mode 100644 index 000000000..ecd74d9e2 --- /dev/null +++ b/packages/datasource-url-params-handler/tsconfig.json @@ -0,0 +1,70 @@ +{ + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext", + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + // "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + // "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": [ + "ESNext", + "DOM" + ] /* Specify library files to be included in the compilation. */, + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "es" /* Redirect output structure to the directory. */, + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + "skipLibCheck": true, + "include": [ + "src/**/*" + ] + } +} \ No newline at end of file diff --git a/packages/types/.eslintignore b/packages/types/.eslintignore new file mode 100644 index 000000000..a218a6cce --- /dev/null +++ b/packages/types/.eslintignore @@ -0,0 +1,3 @@ +lib +es +node_modules \ No newline at end of file diff --git a/packages/types/.eslintrc.js b/packages/types/.eslintrc.js new file mode 100644 index 000000000..3c65aade8 --- /dev/null +++ b/packages/types/.eslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + extends: '../../.eslintrc', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + 'no-param-reassign': 0, + '@typescript-eslint/member-ordering': 0, + indent: 0, + }, +}; diff --git a/packages/types/.prettierrc.js b/packages/types/.prettierrc.js new file mode 100644 index 000000000..092b67059 --- /dev/null +++ b/packages/types/.prettierrc.js @@ -0,0 +1,6 @@ +module.exports = { + printWidth: 80, + singleQuote: true, + trailingComma: 'all', + tabSize: 2, +}; diff --git a/packages/types/src/data-source-handlers.ts b/packages/types/src/data-source-handlers.ts new file mode 100644 index 000000000..2e054b4e8 --- /dev/null +++ b/packages/types/src/data-source-handlers.ts @@ -0,0 +1,15 @@ +import { + IDataSourceRuntimeContext, + RuntimeOptionsConfig, +} from './data-source-runtime'; + +export type RequestHandler = ( + options: RuntimeOptionsConfig, + context: IDataSourceRuntimeContext +) => Promise; + +export type UrlParamsHandler = ( + context?: IDataSourceRuntimeContext +) => Promise; + +export type RequestHandlersMap = Record>; diff --git a/packages/types/src/data-source-interpret.ts b/packages/types/src/data-source-interpret.ts new file mode 100644 index 000000000..be28117f7 --- /dev/null +++ b/packages/types/src/data-source-interpret.ts @@ -0,0 +1,41 @@ +import { + CompositeValue, + JSExpression, + JSFunction, + JSONObject, +} from './value-type'; + +/** + * 数据源对象 + * @see https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 + */ +export interface InterpretDataSource { + list: InterpretDataSourceConfig[]; + dataHandler?: JSFunction; +} + +/** + * 数据源对象 + * @see https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 + */ +export interface InterpretDataSourceConfig { + id: string; + isInit?: boolean | JSExpression; + isSync?: boolean | JSExpression; + type?: string; + requestHandler?: JSFunction; + dataHandler?: JSFunction; + errorHandler?: JSFunction; + willFetch?: JSFunction; + shouldFetch?: JSFunction; + options?: { + uri: string | JSExpression; + params?: JSONObject | JSExpression; + method?: string | JSExpression; + isCors?: boolean | JSExpression; + timeout?: number | JSExpression; + headers?: JSONObject | JSExpression; + [option: string]: CompositeValue; + }; + [otherKey: string]: CompositeValue; +} diff --git a/packages/types/src/data-source-runtime.ts b/packages/types/src/data-source-runtime.ts new file mode 100644 index 000000000..eb27dab61 --- /dev/null +++ b/packages/types/src/data-source-runtime.ts @@ -0,0 +1,53 @@ +import { IRuntimeDataSource } from './data-source'; + +// 先定义运行模式的类型 +export interface RuntimeDataSource { + list: RuntimeDataSourceConfig[]; + // TODO: dataMap 格式不对要处理 + dataHandler?: (dataMap: DataSourceMap) => void; +} + +export type DataSourceMap = Record; + +export interface RuntimeDataSourceConfig { + id: string; + isInit?: boolean; + isSync?: boolean; + type?: string; + willFetch?: () => void; + shouldFetch?: () => boolean; + requestHandler?: () => void; // TODO: 待定 + dataHandler?: DataHandler; + errorHandler?: ErrorHandler; + options?: RuntimeOptions; + [otherKey: string]: unknown; +} + +export type DataHandler = (response: { + data: T; + [index: string]: unknown; +}) => Promise; + +export type ErrorHandler = (err: unknown) => Promise; + +export type RuntimeOptions = () => RuntimeOptionsConfig; + +export interface RuntimeOptionsConfig { + uri: string; + params?: Record; + method?: string; + isCors?: boolean; + timeout?: number; + headers?: Record; + [option: string]: unknown; +} + +// 可以采用 react 的 state,但是需要注意必须提供同步的 setState 功能 +export interface IDataSourceRuntimeContext< + TState extends Record = Record + > { + /** 当前数据源的内容 */ + state: TState; + /** 设置状态(浅合并) */ + setState(state: Partial): void; +} diff --git a/packages/types/src/data-source.ts b/packages/types/src/data-source.ts index 79bca2e91..77d8c6d56 100644 --- a/packages/types/src/data-source.ts +++ b/packages/types/src/data-source.ts @@ -1,16 +1,65 @@ -import { CompositeValue } from './value-type'; +import { RequestHandlersMap } from './data-source-handlers'; +import { + IDataSourceRuntimeContext, + RuntimeDataSource, +} from './data-source-runtime'; -export interface DataSourceConfig { - id: string; - isInit: boolean; - type: string; - options: { - uri: string; - [option: string]: CompositeValue; - }; - [otherKey: string]: CompositeValue; +/** 数据源的状态 */ +export enum RuntimeDataSourceStatus { + /** 初始状态,尚未加载 */ + Initial = 'init', + + /** 正在加载 */ + Loading = 'loading', + + /** 已加载(无错误) */ + Loaded = 'loaded', + + /** 加载出错了 */ + Error = 'error', } -export interface DataSource { - items: DataSourceConfig[]; +/** + * 运行时的数据源(对外暴露的接口) + * @see https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#Jwgj5 + */ +export interface IRuntimeDataSource { + /** 当前状态(initial/loading/loaded/error) */ + readonly status: RuntimeDataSourceStatus; + + /** 加载成功时的数据 */ + readonly data?: TResultData; + + /** 加载出错的时候的错误信息 */ + readonly error?: Error; + + /** + * 加载数据 (无论是否曾经加载过) + * 注意:若提供 params,则会和默认配置的参数做浅合并;否则会使用默认配置的参数。 + */ + load(params?: TParams): Promise; +} + +/** + * DataSourceEngineFactory + * 用来定义 engine 的工厂函数类型 + */ +export interface IRuntimeDataSourceEngineFactory { + create( + dataSource: RuntimeDataSource, + context: IDataSourceRuntimeContext, + extraConfig?: { + requestHandlersMap: RequestHandlersMap; + [key: string]: any; + } + ): IDataSourceEngine; +} + +// create 返回的 DataSourceEngine 定义 +export interface IDataSourceEngine { + /** 数据源, key 是数据源的 ID */ + dataSourceMap: Record; + + /** 重新加载所有的数据源 */ + reloadDataSource(): Promise; } diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index d8f66a46c..4889f5e8f 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,4 +1,7 @@ export * from './data-source'; +export * from './data-source-handlers'; +export * from './data-source-interpret'; +export * from './data-source-runtime'; export * from './editor'; export * from './field-config'; export * from './i18n'; diff --git a/packages/types/src/value-type.ts b/packages/types/src/value-type.ts index 6e5083c0a..353033605 100644 --- a/packages/types/src/value-type.ts +++ b/packages/types/src/value-type.ts @@ -11,6 +11,44 @@ export interface JSExpression { * 模拟值 */ mock?: any; +} + +// 函数 +export interface JSFunction { + type: 'JSFunction'; + /** + * 表达式字符串 + */ + value: string; +} + +/** + * 事件函数类型 + * @see https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#feHTW + */ +export interface JSFunction { + type: 'JSFunction'; + + /** + * 函数定义,或直接函数表达式 + */ + value: string; + + /** 源码 */ + compiled?: string; +} + +// 函数 +export interface JSFunction { + type: 'JSFunction'; + /** + * 函数字符串 + */ + value: string; + /** + * 模拟值 + */ + mock?: any; /** * 额外扩展属性,如 extType、events */ @@ -18,7 +56,6 @@ export interface JSExpression { } export interface JSSlot { - name?: string; type: 'JSSlot'; title?: string; // 函数的入参 @@ -32,28 +69,44 @@ export interface JSBlock { } // JSON 基本类型 -export type JSONValue = boolean | string | number | null | undefined | JSONArray | JSONObject; +export type JSONValue = + | boolean + | string + | number + | null + | undefined + | JSONArray + | JSONObject; export type JSONArray = JSONValue[]; export interface JSONObject { [key: string]: JSONValue; } // 复合类型 -export type CompositeValue = JSONValue | JSExpression | JSSlot | CompositeArray | CompositeObject; +export type CompositeValue = + | JSONValue + | JSExpression + | JSFunction + | JSSlot + | CompositeArray + | CompositeObject; export type CompositeArray = CompositeValue[]; export interface CompositeObject { [key: string]: CompositeValue; } - export function isJSExpression(data: any): data is JSExpression { return data && data.type === 'JSExpression'; } +export function isJSFunction(x: any): x is JSFunction { + return typeof x === 'object' && x && x.type === 'JSFunction'; +} + export function isJSSlot(data: any): data is JSSlot { return data && data.type === 'JSSlot'; } export function isJSBlock(data: any): data is JSBlock { - return data && data.type === 'JSBlock' + return data && data.type === 'JSBlock'; } From 64a477cf3573729a55c031103e621954f08e5b73 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Tue, 13 Oct 2020 17:17:04 +0800 Subject: [PATCH 08/34] =?UTF-8?q?fix:=20tsconfig=20=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/datasource-fetch-handler/tsconfig.json | 10 ++++------ packages/datasource-mopen-handler/tsconfig.json | 10 ++++------ packages/datasource-mtop-handler/tsconfig.json | 10 ++++------ .../tsconfig.json | 10 ++++------ .../datasource-url-params-handler/tsconfig.json | 15 +++++---------- 5 files changed, 21 insertions(+), 34 deletions(-) diff --git a/packages/datasource-fetch-handler/tsconfig.json b/packages/datasource-fetch-handler/tsconfig.json index ecd74d9e2..4f788e5ed 100644 --- a/packages/datasource-fetch-handler/tsconfig.json +++ b/packages/datasource-fetch-handler/tsconfig.json @@ -62,9 +62,7 @@ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "skipLibCheck": true, - "include": [ - "src/**/*" - ] - } -} \ No newline at end of file + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/packages/datasource-mopen-handler/tsconfig.json b/packages/datasource-mopen-handler/tsconfig.json index ecd74d9e2..4f788e5ed 100644 --- a/packages/datasource-mopen-handler/tsconfig.json +++ b/packages/datasource-mopen-handler/tsconfig.json @@ -62,9 +62,7 @@ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "skipLibCheck": true, - "include": [ - "src/**/*" - ] - } -} \ No newline at end of file + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/packages/datasource-mtop-handler/tsconfig.json b/packages/datasource-mtop-handler/tsconfig.json index ecd74d9e2..4f788e5ed 100644 --- a/packages/datasource-mtop-handler/tsconfig.json +++ b/packages/datasource-mtop-handler/tsconfig.json @@ -62,9 +62,7 @@ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "skipLibCheck": true, - "include": [ - "src/**/*" - ] - } -} \ No newline at end of file + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/packages/datasource-universal-mtop-handler/tsconfig.json b/packages/datasource-universal-mtop-handler/tsconfig.json index ecd74d9e2..4f788e5ed 100644 --- a/packages/datasource-universal-mtop-handler/tsconfig.json +++ b/packages/datasource-universal-mtop-handler/tsconfig.json @@ -62,9 +62,7 @@ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "skipLibCheck": true, - "include": [ - "src/**/*" - ] - } -} \ No newline at end of file + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/packages/datasource-url-params-handler/tsconfig.json b/packages/datasource-url-params-handler/tsconfig.json index ecd74d9e2..eeea7a79b 100644 --- a/packages/datasource-url-params-handler/tsconfig.json +++ b/packages/datasource-url-params-handler/tsconfig.json @@ -7,10 +7,7 @@ // "incremental": true, /* Enable incremental compilation */ // "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, // "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "lib": [ - "ESNext", - "DOM" - ] /* Specify library files to be included in the compilation. */, + "lib": ["ESNext", "DOM"] /* Specify library files to be included in the compilation. */, // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ @@ -62,9 +59,7 @@ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "skipLibCheck": true, - "include": [ - "src/**/*" - ] - } -} \ No newline at end of file + "skipLibCheck": true + }, + "include": ["src/**/*"] +} From af4bc83cc39f69448a1280e9e9ee8da59638d7c4 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Tue, 13 Oct 2020 17:29:40 +0800 Subject: [PATCH 09/34] =?UTF-8?q?fix:=20=E4=BB=A3=E7=A0=81=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/datasource-mopen-handler/src/index.ts | 2 +- packages/datasource-mtop-handler/src/index.ts | 6 ++++-- packages/datasource-url-params-handler/package.json | 2 +- packages/datasource-url-params-handler/src/index.ts | 6 ++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/datasource-mopen-handler/src/index.ts b/packages/datasource-mopen-handler/src/index.ts index 6fc4fb287..20fa4d2cc 100644 --- a/packages/datasource-mopen-handler/src/index.ts +++ b/packages/datasource-mopen-handler/src/index.ts @@ -16,7 +16,7 @@ export function createMopenHandler( appKey: MOPEN_APPKEY_XSPACE_PRE_ONLINE, }, ) { - return async function (options: RuntimeOptionsConfig): Promise<{ data: T }> { + return async function(options: RuntimeOptionsConfig): Promise<{ data: T }> { const { data, response } = await MopenClient.request({ config, ...options, diff --git a/packages/datasource-mtop-handler/src/index.ts b/packages/datasource-mtop-handler/src/index.ts index 2527dda5c..1a6007be6 100644 --- a/packages/datasource-mtop-handler/src/index.ts +++ b/packages/datasource-mtop-handler/src/index.ts @@ -9,9 +9,11 @@ export type DataType = 'jsonp' | 'json' | 'originaljsonp'; // 考虑一下 mtop 类型的问题,官方没有提供 ts 文件 export function createMtopHandler(config?: MTopConfig) { if (config && Object.keys(config).length > 0) { - Object.keys(config).forEach((key: string) => mtopRequest.config(key, config[key])); + Object.keys(config).forEach((key: string) => + mtopRequest.config(key, config[key]), + ); } - return async function (options: RuntimeOptionsConfig): Promise<{ data: T }> { + return async function(options: RuntimeOptionsConfig): Promise<{ data: T }> { const response = await mtopRequest.request({ api: options.uri, v: (options.v as string) || '1.0', diff --git a/packages/datasource-url-params-handler/package.json b/packages/datasource-url-params-handler/package.json index 869648b15..39f45f729 100644 --- a/packages/datasource-url-params-handler/package.json +++ b/packages/datasource-url-params-handler/package.json @@ -16,7 +16,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@ali/lowcode-types": "^1.0.10", + "@ali/lowcode-types": "^0.8.13", "query-string": "^6.13.1", "typescript": "^3.9.7" }, diff --git a/packages/datasource-url-params-handler/src/index.ts b/packages/datasource-url-params-handler/src/index.ts index db4761fc0..350234854 100644 --- a/packages/datasource-url-params-handler/src/index.ts +++ b/packages/datasource-url-params-handler/src/index.ts @@ -1,10 +1,8 @@ import qs from 'query-string'; import { UrlParamsHandler } from '@ali/lowcode-types'; -export function createUrlParamsHandler( - searchString: string | T = '', -): UrlParamsHandler { - return async function (): Promise { +export function createUrlParamsHandler(searchString: string | T = ''): UrlParamsHandler { + return async function(): Promise { if (typeof searchString === 'string') { const params = (qs.parse(searchString) as unknown) as T; return params; From 2d64a839ac38a6297607cb61755446674260f577 Mon Sep 17 00:00:00 2001 From: "muyun.my" Date: Thu, 22 Oct 2020 20:34:41 +0800 Subject: [PATCH 10/34] fix --- packages/plugin-datasource-pane/DEV.md | 6 +++++- packages/plugin-datasource-pane/package.json | 6 +++--- packages/plugin-datasource-pane/src/index.tsx | 10 +++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/plugin-datasource-pane/DEV.md b/packages/plugin-datasource-pane/DEV.md index 7d5e947b5..8abcbe74c 100644 --- a/packages/plugin-datasource-pane/DEV.md +++ b/packages/plugin-datasource-pane/DEV.md @@ -2,4 +2,8 @@ [https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq](插件开发文档)。 -本地开发需要在 v14.4.0 的 node 环境下进行。 +[lowcode 组件库文档](https://fusion.alibaba-inc.com/22117/design/style/icon?themeid=4579)。 + +[搭建协议](https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema)。 + +本地开发需要在 v14.4.0 的 node 环境下能完成 setup diff --git a/packages/plugin-datasource-pane/package.json b/packages/plugin-datasource-pane/package.json index 7b27c81d9..9484de9af 100644 --- a/packages/plugin-datasource-pane/package.json +++ b/packages/plugin-datasource-pane/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-plugin-datasource-pane", - "version": "0.1.0-beta.3", + "version": "0.1.0-beta.6", "description": "低代码引擎数据源面板", "main": "lib/index.js", "files": [ @@ -31,7 +31,7 @@ }, "dependencies": { "@alib/build-scripts": "^0.1.3", - "@ali/lowcode-editor-setters": "^1.0.7-0", + "@ali/lowcode-editor-setters": "^1.0.8-0", "@alifd/next": "^1.20.28", "@formily/next": "^1.3.2", "@formily/next-components": "^1.3.2", @@ -43,7 +43,7 @@ "styled-components": "^5.2.0", "traverse": "^0.6.6" }, - "homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-plugin-datasource-pane@0.1.0-beta.1/build/index.html", + "homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-plugin-datasource-pane@0.1.0-beta.6/build/index.html", "publishConfig": { "registry": "https://registry.npm.alibaba-inc.com" } diff --git a/packages/plugin-datasource-pane/src/index.tsx b/packages/plugin-datasource-pane/src/index.tsx index ed77c20ea..4ee4dc71d 100644 --- a/packages/plugin-datasource-pane/src/index.tsx +++ b/packages/plugin-datasource-pane/src/index.tsx @@ -120,10 +120,10 @@ export default class DataSourcePanePlugin extends PureComponent ); From b9bf8002dce78212f542c854f7bb0075ce2596dc Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Fri, 23 Oct 2020 11:30:38 +0800 Subject: [PATCH 11/34] =?UTF-8?q?fix:=20will=20fetch=20=E6=8C=89=E7=85=A7?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/core/RuntimeDataSourceItem.ts | 14 ++++++++++---- packages/datasource-engine/src/helpers/index.ts | 12 +++++++----- packages/types/src/data-source-runtime.ts | 8 ++++++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts index d4184707a..0abfe5a18 100644 --- a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts +++ b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts @@ -106,12 +106,18 @@ class RuntimeDataSourceItem< return; } + let fetchOptions = this._options; + // willFetch - this._dataSourceConfig.willFetch!(); + try { + fetchOptions = await this._dataSourceConfig.willFetch!(this._options); + } catch (error) { + console.error(error); + } // 约定如果 params 有内容,直接做替换,如果没有就用默认的 options 的 - if (params && this._options) { - this._options.params = params; + if (params && fetchOptions) { + fetchOptions.params = params; } const dataHandler = this._dataSourceConfig.dataHandler!; @@ -124,7 +130,7 @@ class RuntimeDataSourceItem< // _context 会给传,但是用不用由 handler 说了算 const result = await (this._request as RequestHandler<{ data: TResultData; - }>)(this._options, this._context).then(dataHandler, errorHandler); + }>)(fetchOptions, this._context).then(dataHandler, errorHandler); // setState this._context.setState({ diff --git a/packages/datasource-engine/src/helpers/index.ts b/packages/datasource-engine/src/helpers/index.ts index 71565b434..1b2726566 100644 --- a/packages/datasource-engine/src/helpers/index.ts +++ b/packages/datasource-engine/src/helpers/index.ts @@ -1,7 +1,8 @@ -import { DataHandler } from '@ali/lowcode-types'; - -// eslint-disable-next-line @typescript-eslint/no-empty-function -function noop() {} +import { + DataHandler, + RuntimeOptionsConfig, + WillFetch, +} from '@ali/lowcode-types'; // 默认的 dataSourceItem 的 dataHandler export const defaultDataHandler: DataHandler = async (response: { @@ -9,7 +10,8 @@ export const defaultDataHandler: DataHandler = async (response: { }) => response.data; // 默认的 dataSourceItem 的 willFetch -export const defaultWillFetch = noop; +export const defaultWillFetch: WillFetch = (options: RuntimeOptionsConfig) => + options; // 默认的 dataSourceItem 的 shouldFetch export const defaultShouldFetch = () => true; diff --git a/packages/types/src/data-source-runtime.ts b/packages/types/src/data-source-runtime.ts index eb27dab61..9a89e39aa 100644 --- a/packages/types/src/data-source-runtime.ts +++ b/packages/types/src/data-source-runtime.ts @@ -14,7 +14,7 @@ export interface RuntimeDataSourceConfig { isInit?: boolean; isSync?: boolean; type?: string; - willFetch?: () => void; + willFetch?: WillFetch; shouldFetch?: () => boolean; requestHandler?: () => void; // TODO: 待定 dataHandler?: DataHandler; @@ -23,6 +23,10 @@ export interface RuntimeDataSourceConfig { [otherKey: string]: unknown; } +export type WillFetch = ( + options: RuntimeOptionsConfig, +) => Promise | RuntimeOptionsConfig; + export type DataHandler = (response: { data: T; [index: string]: unknown; @@ -45,7 +49,7 @@ export interface RuntimeOptionsConfig { // 可以采用 react 的 state,但是需要注意必须提供同步的 setState 功能 export interface IDataSourceRuntimeContext< TState extends Record = Record - > { +> { /** 当前数据源的内容 */ state: TState; /** 设置状态(浅合并) */ From a2a7ee7fcc80969ab81a8acea80ed058e5b1a378 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Fri, 23 Oct 2020 12:32:06 +0800 Subject: [PATCH 12/34] v0.8.14-alpha.1 --- packages/types/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/package.json b/packages/types/package.json index 010ae5cd1..afe7de92c 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-types", - "version": "0.8.13", + "version": "0.8.14-alpha.1", "description": "Types for Ali lowCode engine", "files": [ "es", From 9f51e39264f55cae94ad4a594145aa297c679c8f Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Fri, 23 Oct 2020 14:05:54 +0800 Subject: [PATCH 13/34] =?UTF-8?q?fix:=20JSExpression=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=20compiled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/types/src/value-type.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/types/src/value-type.ts b/packages/types/src/value-type.ts index 353033605..47904a6b7 100644 --- a/packages/types/src/value-type.ts +++ b/packages/types/src/value-type.ts @@ -11,6 +11,8 @@ export interface JSExpression { * 模拟值 */ mock?: any; + /** 源码 */ + compiled?: string; } // 函数 From 7785e69a54c9febfb4c29e74f6ac6e09a520a2c2 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Fri, 23 Oct 2020 18:37:13 +0800 Subject: [PATCH 14/34] v1.0.13-alpha.1 --- packages/types/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/package.json b/packages/types/package.json index 9dba9b103..54e781abc 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-types", - "version": "1.0.12", + "version": "1.0.13-alpha.1", "description": "Types for Ali lowCode engine", "files": [ "es", From 732c35b1ef6afca269cdd65216736b8e626bfc0a Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Fri, 23 Oct 2020 18:49:24 +0800 Subject: [PATCH 15/34] v1.0.2-alpha.1 --- packages/datasource-engine/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/datasource-engine/package.json b/packages/datasource-engine/package.json index 6479c7c0b..c19924a9d 100644 --- a/packages/datasource-engine/package.json +++ b/packages/datasource-engine/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-datasource-engine", - "version": "1.0.1", + "version": "1.0.2-alpha.1", "main": "dist/index.js", "files": [ "dist", @@ -15,7 +15,7 @@ }, "typings": "dist/index.d.ts", "dependencies": { - "@ali/lowcode-types": "^0.8.13", + "@ali/lowcode-types": "1.0.13-alpha.1", "typescript": "^3.9.7" }, "devDependencies": { From 9d97e569b146a3023d509def4a9b234c02512763 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Fri, 23 Oct 2020 18:51:30 +0800 Subject: [PATCH 16/34] v1.0.2-alpha.1 --- packages/datasource-mtop-handler/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/datasource-mtop-handler/package.json b/packages/datasource-mtop-handler/package.json index 2143f71eb..ed15f9813 100644 --- a/packages/datasource-mtop-handler/package.json +++ b/packages/datasource-mtop-handler/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-datasource-mtop-handler", - "version": "1.0.1", + "version": "1.0.2-alpha.1", "main": "lib/index.js", "module": "es/index.js", "typings": "es/index.d.ts", @@ -16,7 +16,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@ali/lowcode-types": "^1.0.10", + "@ali/lowcode-types": "1.0.13-alpha.1", "@ali/universal-mtop": "^5.1.9", "typescript": "^3.9.7" }, From c346137092e20689cc9f67dd27652e37113075f7 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Mon, 26 Oct 2020 15:32:55 +0800 Subject: [PATCH 17/34] fix: eslint --- packages/datasource-engine/package.json | 2 +- .../src/core/reloadDataSourceFactory.ts | 10 +- packages/datasource-engine/src/utils.ts | 82 ++++++++--- .../_macro-abnormal.ts | 130 +++++++++--------- 4 files changed, 138 insertions(+), 86 deletions(-) diff --git a/packages/datasource-engine/package.json b/packages/datasource-engine/package.json index c19924a9d..efa301ff7 100644 --- a/packages/datasource-engine/package.json +++ b/packages/datasource-engine/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-datasource-engine", - "version": "1.0.2-alpha.1", + "version": "1.0.2-alpha.2", "main": "dist/index.js", "files": [ "dist", diff --git a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts index 8433d0d0a..b871c2f37 100644 --- a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts +++ b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts @@ -15,6 +15,7 @@ export const reloadDataSourceFactory = ( dataSource.list .filter( (el: RuntimeDataSourceConfig) => + // eslint-disable-next-line implicit-arrow-linebreak el.type === 'urlParams' && (typeof el.isInit === 'boolean' ? el.isInit : true), ) @@ -51,8 +52,13 @@ export const reloadDataSourceFactory = ( ds.isInit && ds.isSync ) { - // eslint-disable-next-line no-await-in-loop - await dataSourceMap[ds.id].load(); + try { + // eslint-disable-next-line no-await-in-loop + await dataSourceMap[ds.id].load(); + } catch (e) { + // TODO: 这个错误直接吃掉? + console.error(e); + } } } diff --git a/packages/datasource-engine/src/utils.ts b/packages/datasource-engine/src/utils.ts index b31076f28..19b277615 100644 --- a/packages/datasource-engine/src/utils.ts +++ b/packages/datasource-engine/src/utils.ts @@ -9,6 +9,7 @@ import { JSExpression, JSFunction, JSONObject, + RuntimeOptionsConfig, } from '@ali/lowcode-types'; export const transformExpression = ( @@ -123,25 +124,70 @@ export const buildOptions = ( ) => { const { options } = ds; if (!options) return undefined; + // eslint-disable-next-line space-before-function-paren return function() { - return { - uri: getRuntimeValueFromConfig('string', options.uri, context), - params: options.params ? buildJsonObj(options.params, context) : {}, - method: options.method - ? getRuntimeValueFromConfig('string', options.method, context) - : 'GET', - isCors: options.isCors - ? getRuntimeValueFromConfig('boolean', options.isCors, context) - : true, - timeout: options.timeout - ? getRuntimeValueFromConfig('number', options.timeout, context) - : 5000, - headers: options.headers - ? buildJsonObj(options.headers, context) - : undefined, - v: options.v - ? getRuntimeValueFromConfig('string', options.v, context) - : '1.0', + // 默认值 + const fetchOptions: RuntimeOptionsConfig = { + uri: '', + params: {}, + method: 'GET', + isCors: true, + timeout: 5000, + headers: undefined, + v: '1.0', }; + Object.keys(options).forEach((key: string) => { + switch (key) { + case 'uri': + fetchOptions.uri = getRuntimeValueFromConfig( + 'string', + options.uri, + context, + ); + break; + case 'params': + fetchOptions.params = buildJsonObj(options.params!, context); + break; + case 'method': + fetchOptions.method = getRuntimeValueFromConfig( + 'string', + options.method, + context, + ); + break; + case 'isCors': + fetchOptions.isCors = getRuntimeValueFromConfig( + 'boolean', + options.isCors, + context, + ); + break; + case 'timeout': + fetchOptions.timeout = getRuntimeValueFromConfig( + 'number', + options.timeout, + context, + ); + break; + case 'headers': + fetchOptions.headers = buildJsonObj(options.headers!, context); + break; + case 'v': + fetchOptions.v = getRuntimeValueFromConfig( + 'string', + options.v, + context, + ); + break; + default: + // 其余的除了做表达式或者 function 的转换,直接透传 + fetchOptions[key] = getRuntimeValueFromConfig( + 'unknown', + options[key], + context, + ); + } + }); + return fetchOptions; }; }; diff --git a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts index f81db6b49..f0fa43060 100644 --- a/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts +++ b/packages/datasource-engine/test/scenes/p0-0-sync-datasources-dealt-in-serial/_macro-abnormal.ts @@ -25,72 +25,72 @@ export const abnormalScene: Macro<[ ]> = async ( t: ExecutionContext<{ clock: SinonFakeTimers }>, { create, dataSource }, - ) => { - const { clock } = t.context; +) => { + const { clock } = t.context; - const USER_DATA = { - id: 9527, - name: 'Alice', - }; - const ERROR_MSG = 'test error'; - const fetchHandler = sinon.fake(async ({ uri }) => { - await delay(100); - if (/user/.test(uri)) { - return { data: USER_DATA }; - } else { - throw new Error(ERROR_MSG); - } - }); - - const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { - requestHandlersMap: { - fetch: fetchHandler, - }, - })); - - const setState = sinon.spy(context, 'setState'); - - // 一开始应该是初始状态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); - - const loading = context.reloadDataSource(); - - await clock.tickAsync(50); - - // 中间应该有 loading 态 - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); - - await clock.tickAsync(50); - - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); - - await Promise.all([clock.runAllAsync(), loading]); - - // 最后 user 应该成功了,loaded - t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); - // 最后 orders 应该失败了,error 状态 - t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); - - // 检查数据源的数据 - t.deepEqual(context.dataSourceMap.user.data, USER_DATA); - t.is(context.dataSourceMap.user.error, undefined); - t.deepEqual(context.dataSourceMap.orders.data, undefined); - t.not(context.dataSourceMap.orders.error, undefined); - t.regex(context.dataSourceMap.orders.error!.message, new RegExp(ERROR_MSG)); - - // 检查状态数据 - t.assert(setState.calledOnce); - t.deepEqual(context.state.user, USER_DATA); - t.is(context.state.orders, undefined); - - // fetchHandler 应该被调用了2次 - t.assert(fetchHandler.calledTwice); - - const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; - const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; - // 检查调用参数 - t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); + const USER_DATA = { + id: 9527, + name: 'Alice', }; + const ERROR_MSG = 'test error'; + const fetchHandler = sinon.fake(async ({ uri }) => { + await delay(100); + if (/user/.test(uri)) { + return { data: USER_DATA }; + } else { + throw new Error(ERROR_MSG); + } + }); + + const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx, { + requestHandlersMap: { + fetch: fetchHandler, + }, + })); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(50); + + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后 user 应该成功了,loaded + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + // 最后 orders 应该失败了,error 状态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.is(context.dataSourceMap.user.error, undefined); + t.deepEqual(context.dataSourceMap.orders.data, undefined); + t.not(context.dataSourceMap.orders.error, undefined); + t.regex(context.dataSourceMap.orders.error!.message, new RegExp(ERROR_MSG)); + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + t.is(context.state.orders, undefined); + + // fetchHandler 应该被调用了2次 + t.assert(fetchHandler.calledTwice); + + const firstListItemOptions = DATA_SOURCE_SCHEMA.list[0].options; + const fetchHandlerCallArgs = fetchHandler.firstCall.args[0]; + // 检查调用参数 + t.is(firstListItemOptions.uri, fetchHandlerCallArgs.uri); +}; abnormalScene.title = (providedTitle) => providedTitle || 'abnormal scene'; From 17289d466a2e01f14fe996e0e11446ee14c15504 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Tue, 27 Oct 2020 12:21:41 +0800 Subject: [PATCH 18/34] v1.0.2-alpha.2 --- packages/datasource-mtop-handler/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/datasource-mtop-handler/package.json b/packages/datasource-mtop-handler/package.json index ed15f9813..1c841db3a 100644 --- a/packages/datasource-mtop-handler/package.json +++ b/packages/datasource-mtop-handler/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-datasource-mtop-handler", - "version": "1.0.2-alpha.1", + "version": "1.0.2-alpha.2", "main": "lib/index.js", "module": "es/index.js", "typings": "es/index.d.ts", From 98f3a17c3c3fd048dde588286fde940854dfcccc Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Tue, 27 Oct 2020 12:24:18 +0800 Subject: [PATCH 19/34] fix: eslint --- packages/datasource-engine/.eslintrc.js | 2 +- .../src/core/DataSourceEngine.ts | 124 ------------------ .../src/core/RuntimeDataSource.ts | 94 ------------- .../datasource-fetch-handler/package.json | 2 +- .../datasource-mtop-handler/.prettierrc.js | 2 +- packages/datasource-mtop-handler/src/index.ts | 18 ++- .../datasource-mtop-handler/src/typings.d.ts | 2 +- 7 files changed, 18 insertions(+), 226 deletions(-) delete mode 100644 packages/datasource-engine/src/core/DataSourceEngine.ts delete mode 100644 packages/datasource-engine/src/core/RuntimeDataSource.ts diff --git a/packages/datasource-engine/.eslintrc.js b/packages/datasource-engine/.eslintrc.js index 8c13fcaf4..258d60040 100644 --- a/packages/datasource-engine/.eslintrc.js +++ b/packages/datasource-engine/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { extends: '../../.eslintrc', rules: { - '@typescript-eslint/no-parameter-properties': 1, + '@typescript-eslint/no-parameter-properties': 0, 'no-param-reassign': 0, }, }; diff --git a/packages/datasource-engine/src/core/DataSourceEngine.ts b/packages/datasource-engine/src/core/DataSourceEngine.ts deleted file mode 100644 index d24ef2420..000000000 --- a/packages/datasource-engine/src/core/DataSourceEngine.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { - DataSourceConfig, - DataSourceEngineOptions, - IDataSourceEngine, - IDataSourceEngineFactory, - IRuntimeContext, -} from '../types'; -import { RuntimeDataSource } from './RuntimeDataSource'; - -export class DataSourceEngine implements IDataSourceEngine { - private _dataSourceMap: Record = {}; - - constructor( - private _dataSourceConfig: DataSourceConfig, - private _runtimeContext: IRuntimeContext, - private _options?: DataSourceEngineOptions, - ) { - // eslint-disable-next-line no-unused-expressions - _dataSourceConfig.list?.forEach((ds) => { - // 确保数据源都有处理器 - const requestHandler = ds.requestHandler || _options?.requestHandlersMap?.[ds.type]; - if (!requestHandler) { - throw new Error(`No request handler for "${ds.type}" data source`); - } - - this._dataSourceMap[ds.id] = new RuntimeDataSource( - ds.id, - ds.type, - getValue(ds.options) || {}, - requestHandler.bind(_runtimeContext), - ds.dataHandler ? ds.dataHandler.bind(_runtimeContext) : undefined, - (data) => { - _runtimeContext.setState({ [ds.id]: data }); - }, - ); - }); - } - - public get dataSourceMap() { - return this._dataSourceMap; - } - - public async reloadDataSource() { - try { - const allDataSourceConfigList = this._dataSourceConfig.list || []; - - // urlParams 类型的优先加载 - for (const ds of allDataSourceConfigList) { - if (ds.type === 'urlParams' && (getValue(ds.isInit) ?? true)) { - await this._dataSourceMap[ds.id].load(); - } - } - - // 然后是所有其他的 - const remainDataSourceConfigList = allDataSourceConfigList.filter((x) => x.type !== 'urlParams'); - - // 先发起异步的 - const asyncLoadings: Array> = []; - for (const ds of remainDataSourceConfigList) { - if (getValue(ds.isInit) ?? true) { - const options = getValue(ds.options); - if (options && !options.isSync) { - this._dataSourceMap[ds.id].setOptions(options); - asyncLoadings.push(this._dataSourceMap[ds.id].load(options?.params).catch(() => {})); - } - } - } - - try { - // 再按先后顺序发起同步请求 - for (const ds of remainDataSourceConfigList) { - if (getValue(ds.isInit) ?? true) { - const options = getValue(ds.options); - if (options && options.isSync) { - this._dataSourceMap[ds.id].setOptions(options); - await this._dataSourceMap[ds.id].load(options?.params); - await sleep(0); // TODO: 如何优雅地解决 setState 的异步问题? - } - } - } - } catch (e) { - // ignore error - } - - await Promise.all(asyncLoadings); - } finally { - const allDataHandler = this._dataSourceConfig.dataHandler; - if (allDataHandler) { - await allDataHandler(this._getDataMapOfAll()); - } - } - } - - private _getDataMapOfAll(): Record { - const dataMap: Record = {}; - - Object.entries(this._dataSourceMap).forEach(([dsId, ds]) => { - dataMap[dsId] = ds.data; - }); - - return dataMap; - } -} - -export const create: IDataSourceEngineFactory['create'] = (dataSourceConfig, runtimeContext, options) => { - return new DataSourceEngine(dataSourceConfig, runtimeContext, options); -}; - -function getValue(valueOrValueGetter: T | (() => T)): T; -function getValue(valueOrValueGetter: T | (() => T)): T | undefined { - if (typeof valueOrValueGetter === 'function') { - try { - return valueOrValueGetter(); - } catch (e) { - return undefined; - } - } else { - return valueOrValueGetter; - } -} - -function sleep(ms = 0) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} diff --git a/packages/datasource-engine/src/core/RuntimeDataSource.ts b/packages/datasource-engine/src/core/RuntimeDataSource.ts deleted file mode 100644 index 89ec2d930..000000000 --- a/packages/datasource-engine/src/core/RuntimeDataSource.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { DataSourceOptions, IRuntimeDataSource, RequestHandler, RuntimeDataSourceStatus } from '../types'; -import { DataSourceResponse } from '../types/DataSourceResponse'; - -export class RuntimeDataSource< - TParams extends Record = Record, - TRequestResult = unknown, - TResultData = unknown -> implements IRuntimeDataSource { - private _status: RuntimeDataSourceStatus = RuntimeDataSourceStatus.Initial; - - private _data?: TResultData; - - private _error?: Error; - - private _latestOptions: DataSourceOptions; - - constructor( - private _id: string, - private _type: string, - private _initialOptions: DataSourceOptions, - private _requestHandler: RequestHandler, DataSourceResponse>, - private _dataHandler: - | (( - data: DataSourceResponse | undefined, - error: unknown | undefined, - ) => TResultData | Promise) - | undefined, - private _onLoaded: (data: TResultData) => void, - ) { - this._latestOptions = _initialOptions; - } - - public get status() { - return this._status; - } - - public get data() { - return this._data; - } - - public get error() { - return this._error; - } - - public async load(params?: TParams): Promise { - try { - this._latestOptions = { - ...this._latestOptions, - params: { - ...this._latestOptions.params, - ...params, - } as TParams, - }; - - this._status = RuntimeDataSourceStatus.Loading; - - const data = await this._request(this._latestOptions); - - this._status = RuntimeDataSourceStatus.Loaded; - - this._onLoaded(data); - - this._data = data; - return data; - } catch (err) { - this._error = err; - this._status = RuntimeDataSourceStatus.Error; - throw err; - } - } - - public setOptions(options: DataSourceOptions) { - this._latestOptions = options; - } - - private async _request(options: DataSourceOptions) { - try { - const response = await this._requestHandler(options); - - const data = this._dataHandler - ? await this._dataHandler(response, undefined) - : ((response.data as unknown) as TResultData); - - return data; - } catch (err) { - if (this._dataHandler) { - const data = await this._dataHandler(undefined, err); - return data; - } - - throw err; - } - } -} diff --git a/packages/datasource-fetch-handler/package.json b/packages/datasource-fetch-handler/package.json index 8dbc63a6f..720a8f770 100644 --- a/packages/datasource-fetch-handler/package.json +++ b/packages/datasource-fetch-handler/package.json @@ -16,7 +16,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@ali/lowcode-types": "^1.0.10", + "@ali/lowcode-types": "1.0.13-alpha.1", "typescript": "^3.9.7", "universal-request": "^2.2.0" }, diff --git a/packages/datasource-mtop-handler/.prettierrc.js b/packages/datasource-mtop-handler/.prettierrc.js index de2f53cdf..a425d3f76 100644 --- a/packages/datasource-mtop-handler/.prettierrc.js +++ b/packages/datasource-mtop-handler/.prettierrc.js @@ -1,4 +1,4 @@ module.exports = { singleQuote: true, - trailingComma: 'all', + trailingComma: 'es5', }; diff --git a/packages/datasource-mtop-handler/src/index.ts b/packages/datasource-mtop-handler/src/index.ts index 1a6007be6..a582076da 100644 --- a/packages/datasource-mtop-handler/src/index.ts +++ b/packages/datasource-mtop-handler/src/index.ts @@ -9,10 +9,11 @@ export type DataType = 'jsonp' | 'json' | 'originaljsonp'; // 考虑一下 mtop 类型的问题,官方没有提供 ts 文件 export function createMtopHandler(config?: MTopConfig) { if (config && Object.keys(config).length > 0) { - Object.keys(config).forEach((key: string) => - mtopRequest.config(key, config[key]), - ); + Object.keys(config).forEach((key: string) => { + mtopRequest.config(key, config[key]); + }); } + // eslint-disable-next-line space-before-function-paren return async function(options: RuntimeOptionsConfig): Promise<{ data: T }> { const response = await mtopRequest.request({ api: options.uri, @@ -23,6 +24,15 @@ export function createMtopHandler(config?: MTopConfig) { timeout: options.timeout, headers: options.headers, }); - return response; + if (response.ret && response.ret[0].indexOf('SUCCESS::') > -1) { + // 校验成功 + return response; + } + // 默认异常 + let errorMsg = '未知异常'; + if (response.ret && response.ret[0]) { + errorMsg = response.ret[0]; + } + throw new Error(errorMsg); }; } diff --git a/packages/datasource-mtop-handler/src/typings.d.ts b/packages/datasource-mtop-handler/src/typings.d.ts index 6a5989f78..11f4d02cd 100644 --- a/packages/datasource-mtop-handler/src/typings.d.ts +++ b/packages/datasource-mtop-handler/src/typings.d.ts @@ -6,6 +6,6 @@ declare interface MTopConfig { } declare module '@ali/universal-mtop' { - const request: (config: any) => Promise<{ data: T }>; + const request: (config: any) => Promise<{ data: T; ret: string[] }>; const config: (key: string, value: unknown) => void; } From 9c8a011160803f20afab954d110860c2135bb589 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Thu, 29 Oct 2020 17:44:54 +0800 Subject: [PATCH 20/34] v1.0.13-alpha.2 --- packages/types/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/package.json b/packages/types/package.json index 54e781abc..200cc6eb7 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-types", - "version": "1.0.13-alpha.1", + "version": "1.0.13-alpha.2", "description": "Types for Ali lowCode engine", "files": [ "es", From 4ef1097638c4ce959781770d5cff4e8111f93659 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Thu, 29 Oct 2020 17:47:17 +0800 Subject: [PATCH 21/34] v1.0.2-alpha.3 --- packages/datasource-engine/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/datasource-engine/package.json b/packages/datasource-engine/package.json index efa301ff7..ba99aee17 100644 --- a/packages/datasource-engine/package.json +++ b/packages/datasource-engine/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-datasource-engine", - "version": "1.0.2-alpha.2", + "version": "1.0.2-alpha.3", "main": "dist/index.js", "files": [ "dist", @@ -15,7 +15,7 @@ }, "typings": "dist/index.d.ts", "dependencies": { - "@ali/lowcode-types": "1.0.13-alpha.1", + "@ali/lowcode-types": "1.0.13-alpha.2", "typescript": "^3.9.7" }, "devDependencies": { From cf3c7dbd35f90b8aa5efba81ff26ca10daf8c9bc Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Thu, 29 Oct 2020 17:54:53 +0800 Subject: [PATCH 22/34] feat: update datasource engine --- packages/datasource-engine/.eslintrc.js | 1 + packages/datasource-engine/.prettierrc.js | 1 + .../src/core/RuntimeDataSourceItem.ts | 28 +++--- .../datasource-engine/src/core/adapter.ts | 62 +++++-------- .../src/core/reloadDataSourceFactory.ts | 20 ++--- .../datasource-engine/src/helpers/index.ts | 26 ++++-- .../src/interpret/DataSourceEngineFactory.ts | 22 ++--- .../runtime/RuntimeDataSourceEngineFactory.ts | 29 ++---- .../p0-0-custom-request-handlers/README.md | 3 + .../_datasource-runtime.ts | 67 ++++++++++++++ .../_datasource-schema.ts | 67 ++++++++++++++ .../_macro-normal.ts | 90 +++++++++++++++++++ .../normal-interpret.test.ts | 20 +++++ .../normal-runtime.test.ts | 20 +++++ packages/types/src/data-source-handlers.ts | 10 ++- packages/types/src/data-source-runtime.ts | 6 +- 16 files changed, 355 insertions(+), 117 deletions(-) create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/README.md create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-runtime.test.ts diff --git a/packages/datasource-engine/.eslintrc.js b/packages/datasource-engine/.eslintrc.js index 258d60040..6cbc6c8e9 100644 --- a/packages/datasource-engine/.eslintrc.js +++ b/packages/datasource-engine/.eslintrc.js @@ -3,5 +3,6 @@ module.exports = { rules: { '@typescript-eslint/no-parameter-properties': 0, 'no-param-reassign': 0, + 'max-len': 0, }, }; diff --git a/packages/datasource-engine/.prettierrc.js b/packages/datasource-engine/.prettierrc.js index de2f53cdf..21ec86215 100644 --- a/packages/datasource-engine/.prettierrc.js +++ b/packages/datasource-engine/.prettierrc.js @@ -1,4 +1,5 @@ module.exports = { singleQuote: true, trailingComma: 'all', + printWidth: 120, }; diff --git a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts index 0abfe5a18..5d71e2e1b 100644 --- a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts +++ b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts @@ -9,10 +9,8 @@ import { UrlParamsHandler, } from '@ali/lowcode-types'; -class RuntimeDataSourceItem< - TParams extends Record = Record, - TResultData = unknown -> implements IRuntimeDataSource { +class RuntimeDataSourceItem = Record, TResultData = unknown> + implements IRuntimeDataSource { private _data?: TResultData; private _error?: Error; @@ -21,9 +19,7 @@ class RuntimeDataSourceItem< private _dataSourceConfig: RuntimeDataSourceConfig; - private _request: - | RequestHandler<{ data: TResultData }> - | UrlParamsHandler; + private _request: RequestHandler<{ data: TResultData }> | UrlParamsHandler; private _context: IDataSourceRuntimeContext; @@ -31,9 +27,7 @@ class RuntimeDataSourceItem< constructor( dataSourceConfig: RuntimeDataSourceConfig, - request: - | RequestHandler<{ data: TResultData }> - | UrlParamsHandler, + request: RequestHandler<{ data: TResultData }> | UrlParamsHandler, context: IDataSourceRuntimeContext, ) { this._dataSourceConfig = dataSourceConfig; @@ -57,14 +51,14 @@ class RuntimeDataSourceItem< if (!this._dataSourceConfig) return; // 考虑没有绑定对应的 handler 的情况 if (!this._request) { - throw new Error(`no ${this._dataSourceConfig.type} handler provide`); + this._error = new Error(`no ${this._dataSourceConfig.type} handler provide`); + this._status = RuntimeDataSourceStatus.Error; + throw this._error; } // TODO: urlParams 有没有更好的处理方式 if (this._dataSourceConfig.type === 'urlParams') { - const response = await (this._request as UrlParamsHandler)( - this._context, - ); + const response = await (this._request as UrlParamsHandler)(this._context); this._context.setState({ [this._dataSourceConfig.id]: response, }); @@ -100,10 +94,8 @@ class RuntimeDataSourceItem< if (!shouldFetch) { this._status = RuntimeDataSourceStatus.Error; - this._error = new Error( - `the ${this._dataSourceConfig.id} request should not fetch, please check the condition`, - ); - return; + this._error = new Error(`the ${this._dataSourceConfig.id} request should not fetch, please check the condition`); + throw this._error; } let fetchOptions = this._options; diff --git a/packages/datasource-engine/src/core/adapter.ts b/packages/datasource-engine/src/core/adapter.ts index 41a476bc7..71f930bea 100644 --- a/packages/datasource-engine/src/core/adapter.ts +++ b/packages/datasource-engine/src/core/adapter.ts @@ -1,10 +1,4 @@ -import { - transformFunction, - getRuntimeValueFromConfig, - getRuntimeJsValue, - buildOptions, - buildShouldFetch, -} from './../utils'; +import { getRuntimeValueFromConfig, getRuntimeJsValue, buildOptions, buildShouldFetch } from './../utils'; // 将不同渠道给的 schema 转为 runtime 需要的类型 import { defaultDataHandler, defaultWillFetch } from '../helpers'; @@ -16,18 +10,11 @@ import { RuntimeDataSourceConfig, } from '@ali/lowcode-types'; -const adapt2Runtime = ( - dataSource: InterpretDataSource, - context: IDataSourceRuntimeContext, -) => { - const { - list: interpretConfigList, - dataHandler: interpretDataHandler, - } = dataSource; - const dataHandler: (dataMap?: DataSourceMap) => void = - interpretDataHandler && - interpretDataHandler.compiled && - transformFunction(interpretDataHandler.compiled, context); +const adapt2Runtime = (dataSource: InterpretDataSource, context: IDataSourceRuntimeContext) => { + const { list: interpretConfigList, dataHandler: interpretDataHandler } = dataSource; + const dataHandler: (dataMap?: DataSourceMap) => void = interpretDataHandler + ? getRuntimeJsValue(interpretDataHandler, context) + : undefined; // 为空判断 if (!interpretConfigList || !interpretConfigList.length) { @@ -36,29 +23,20 @@ const adapt2Runtime = ( dataHandler, }; } - const list: RuntimeDataSourceConfig[] = interpretConfigList.map( - (el: InterpretDataSourceConfig) => { - return { - id: el.id, - isInit: - getRuntimeValueFromConfig('boolean', el.isInit, context) || true, // 默认 true - isSync: - getRuntimeValueFromConfig('boolean', el.isSync, context) || false, // 默认 false - type: el.type || 'fetch', - willFetch: el.willFetch - ? getRuntimeJsValue(el.willFetch, context) - : defaultWillFetch, - shouldFetch: buildShouldFetch(el, context), - dataHandler: el.dataHandler - ? getRuntimeJsValue(el.dataHandler, context) - : defaultDataHandler, - errorHandler: el.errorHandler - ? getRuntimeJsValue(el.errorHandler, context) - : undefined, - options: buildOptions(el, context), - }; - }, - ); + const list: RuntimeDataSourceConfig[] = interpretConfigList.map((el: InterpretDataSourceConfig) => { + return { + id: el.id, + isInit: getRuntimeValueFromConfig('boolean', el.isInit, context) || true, // 默认 true + isSync: getRuntimeValueFromConfig('boolean', el.isSync, context) || false, // 默认 false + type: el.type || 'fetch', + willFetch: el.willFetch ? getRuntimeJsValue(el.willFetch, context) : defaultWillFetch, + shouldFetch: buildShouldFetch(el, context), + dataHandler: el.dataHandler ? getRuntimeJsValue(el.dataHandler, context) : defaultDataHandler, + errorHandler: el.errorHandler ? getRuntimeJsValue(el.errorHandler, context) : undefined, + requestHandler: el.requestHandler ? getRuntimeJsValue(el.requestHandler, context) : undefined, + options: buildOptions(el, context), + }; + }); return { list, diff --git a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts index b871c2f37..87a111ca0 100644 --- a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts +++ b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts @@ -1,12 +1,9 @@ -import { - DataSourceMap, - RuntimeDataSource, - RuntimeDataSourceConfig, -} from '@ali/lowcode-types'; +import { DataSourceMap, RuntimeDataSource, RuntimeDataSourceConfig } from '@ali/lowcode-types'; export const reloadDataSourceFactory = ( dataSource: RuntimeDataSource, dataSourceMap: DataSourceMap, + dataHandler?: (dataSourceMap: DataSourceMap) => void, ) => async () => { const allAsyncLoadings: Array> = []; @@ -16,16 +13,13 @@ export const reloadDataSourceFactory = ( .filter( (el: RuntimeDataSourceConfig) => // eslint-disable-next-line implicit-arrow-linebreak - el.type === 'urlParams' && - (typeof el.isInit === 'boolean' ? el.isInit : true), + el.type === 'urlParams' && (typeof el.isInit === 'boolean' ? el.isInit : true), ) .forEach((el: RuntimeDataSourceConfig) => { dataSourceMap[el.id].load(); }); - const remainRuntimeDataSourceList = dataSource.list.filter( - (el: RuntimeDataSourceConfig) => el.type !== 'urlParams', - ); + const remainRuntimeDataSourceList = dataSource.list.filter((el: RuntimeDataSourceConfig) => el.type !== 'urlParams'); // 处理并行 for (const ds of remainRuntimeDataSourceList) { @@ -63,4 +57,10 @@ export const reloadDataSourceFactory = ( } await Promise.allSettled(allAsyncLoadings); + + // 所有的初始化请求都结束之后,调用钩子函数 + + if (dataHandler) { + dataHandler(dataSourceMap); + } }; diff --git a/packages/datasource-engine/src/helpers/index.ts b/packages/datasource-engine/src/helpers/index.ts index 1b2726566..6202e61b2 100644 --- a/packages/datasource-engine/src/helpers/index.ts +++ b/packages/datasource-engine/src/helpers/index.ts @@ -1,17 +1,33 @@ import { DataHandler, + RequestHandler, + RequestHandlersMap, + RuntimeDataSourceConfig, RuntimeOptionsConfig, + UrlParamsHandler, WillFetch, } from '@ali/lowcode-types'; // 默认的 dataSourceItem 的 dataHandler -export const defaultDataHandler: DataHandler = async (response: { - data: T; -}) => response.data; +export const defaultDataHandler: DataHandler = async (response: { data: T }) => response.data; // 默认的 dataSourceItem 的 willFetch -export const defaultWillFetch: WillFetch = (options: RuntimeOptionsConfig) => - options; +export const defaultWillFetch: WillFetch = (options: RuntimeOptionsConfig) => options; // 默认的 dataSourceItem 的 shouldFetch export const defaultShouldFetch = () => true; + +type GetRequestHandler = ( + ds: RuntimeDataSourceConfig, + requestHandlersMap: RequestHandlersMap<{ data: T }>, +) => RequestHandler<{ data: T }> | UrlParamsHandler; + +// 从当前 dataSourceItem 中获取 requestHandler +export const getRequestHandler: GetRequestHandler = (ds, requestHandlersMap) => { + if (ds.type === 'custom') { + // 自定义类型处理 + return (ds.requestHandler as unknown) as RequestHandler<{ data: unknown }>; // 理论上这里应该是能强转的,就算为空,应该在 request 请求的时候触发失败 + } + // type 协议默认值 fetch + return requestHandlersMap[ds.type || 'fetch']; +}; diff --git a/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts b/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts index 4adcf1f82..15d4dc5d8 100644 --- a/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts +++ b/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts @@ -9,11 +9,12 @@ import { RuntimeDataSource, RuntimeDataSourceConfig, } from '@ali/lowcode-types'; +import { getRequestHandler } from '../helpers'; -// TODO: requestConfig mtop 默认的请求 config 怎么处理? /** * @param dataSource * @param context + * @param extraConfig: { requestHandlersMap } */ export default ( @@ -25,22 +26,11 @@ export default ( ) => { const { requestHandlersMap } = extraConfig; - const runtimeDataSource: RuntimeDataSource = adapt2Runtime( - dataSource, - context, - ); + const runtimeDataSource: RuntimeDataSource = adapt2Runtime(dataSource, context); const dataSourceMap = runtimeDataSource.list.reduce( - ( - prev: Record, - current: RuntimeDataSourceConfig, - ) => { - prev[current.id] = new RuntimeDataSourceItem( - current, - // type 协议默认值 fetch - requestHandlersMap[current.type || 'fetch'], - context, - ); + (prev: Record, current: RuntimeDataSourceConfig) => { + prev[current.id] = new RuntimeDataSourceItem(current, getRequestHandler(current, requestHandlersMap), context); return prev; }, {}, @@ -48,6 +38,6 @@ export default ( return { dataSourceMap, - reloadDataSource: reloadDataSourceFactory(runtimeDataSource, dataSourceMap), + reloadDataSource: reloadDataSourceFactory(runtimeDataSource, dataSourceMap, runtimeDataSource.dataHandler), }; }; diff --git a/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts b/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts index d504054c3..e1cdead62 100644 --- a/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts +++ b/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/indent */ -/* eslint-disable no-nested-ternary */ import { IRuntimeDataSource, IDataSourceRuntimeContext, @@ -10,17 +9,14 @@ import { import { RuntimeDataSourceItem } from '../core'; import { reloadDataSourceFactory } from '../core/reloadDataSourceFactory'; -import { - defaultDataHandler, - defaultShouldFetch, - defaultWillFetch, -} from '../helpers'; +import { defaultDataHandler, defaultShouldFetch, defaultWillFetch, getRequestHandler } from '../helpers'; -// TODO: requestConfig mtop 默认的请求 config 怎么处理? /** * @param dataSource * @param context + * @param extraConfig: { requestHandlersMap } */ + export default ( dataSource: RuntimeDataSource, context: IDataSourceRuntimeContext, @@ -34,28 +30,19 @@ export default ( dataSource.list.forEach(ds => { ds.isInit = ds.isInit || true; ds.isSync = ds.isSync || false; + // eslint-disable-next-line no-nested-ternary ds.shouldFetch = !ds.shouldFetch ? defaultShouldFetch : typeof ds.shouldFetch === 'function' ? ds.shouldFetch.bind(context) : ds.shouldFetch; ds.willFetch = ds.willFetch ? ds.willFetch.bind(context) : defaultWillFetch; - ds.dataHandler = ds.dataHandler - ? ds.dataHandler.bind(context) - : defaultDataHandler; + ds.dataHandler = ds.dataHandler ? ds.dataHandler.bind(context) : defaultDataHandler; }); const dataSourceMap = dataSource.list.reduce( - ( - prev: Record, - current: RuntimeDataSourceConfig, - ) => { - prev[current.id] = new RuntimeDataSourceItem( - current, - // type 协议默认值 fetch - requestHandlersMap[current.type || 'fetch'], - context, - ); + (prev: Record, current: RuntimeDataSourceConfig) => { + prev[current.id] = new RuntimeDataSourceItem(current, getRequestHandler(current, requestHandlersMap), context); return prev; }, {}, @@ -63,6 +50,6 @@ export default ( return { dataSourceMap, - reloadDataSource: reloadDataSourceFactory(dataSource, dataSourceMap), + reloadDataSource: reloadDataSourceFactory(dataSource, dataSourceMap, dataSource.dataHandler), }; }; diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/README.md b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/README.md new file mode 100644 index 000000000..355853ddd --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/README.md @@ -0,0 +1,3 @@ +# 关于此场景 + +数据源的 type 可以是 `custom` 类型的, 此时需要提供 `requestHandler` 给数据源 diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-runtime.ts new file mode 100644 index 000000000..fc46c3459 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-runtime.ts @@ -0,0 +1,67 @@ +import { RuntimeDataSource } from '@ali/lowcode-types'; + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'custom', + isSync: true, + requestHandler: options => { + return new Promise(res => { + setTimeout(() => { + // test return data + res({ + data: { + id: 9527, + name: 'Alice', + uri: options.uri, + }, + }); + }, 1000); + }); + }, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/user.json', + }; + }, + }, + { + id: 'orders', + isInit: true, + type: 'custom', + isSync: true, + requestHandler: () => { + return new Promise((res, rej) => { + setTimeout(() => { + // test return data + rej(new Error('test error')); + }, 1000); + }); + }, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/orders.json', + params: { + userId: this.state.user.id, + }, + }; + }, + }, + { + // 这个 api 是假的,调不通的,当前场景是故意需要报错的 + id: 'members', + isInit: true, + type: 'custom', + isSync: true, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/members.json', + }; + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-schema.ts new file mode 100644 index 000000000..0a71914ca --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-schema.ts @@ -0,0 +1,67 @@ +import { InterpretDataSource } from '@ali/lowcode-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'custom', + isSync: true, + requestHandler: { + type: 'JSFunction', + value: `function(options){ + return new Promise(res => { + setTimeout(() => { + // test return data + res({ + data: { + id: 9527, + name: 'Alice', + uri: options.uri, + } + }); + }, 1000); + }); + }`, + }, + options: { + uri: 'https://mocks.alibaba-inc.com/user.json', + }, + }, + { + id: 'orders', + isInit: true, + type: 'custom', + isSync: true, + requestHandler: { + type: 'JSFunction', + value: `function(options){ + return new Promise((res, rej) => { + setTimeout(() => { + // test return data + return rej(new Error('test error')); + }, 1000); + }); + }`, + }, + options: { + uri: 'https://mocks.alibaba-inc.com/orders.json', + params: { + type: 'JSExpression', + value: '{ userId: this.state.user.id }', + }, + }, + }, + { + id: 'members', + isInit: true, + type: 'custom', + isSync: true, + options: { + uri: 'https://mocks.alibaba-inc.com/members.json', + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_macro-normal.ts new file mode 100644 index 000000000..1fe39c61e --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_macro-normal.ts @@ -0,0 +1,90 @@ +import { + InterpretDataSource, + IDataSourceEngine, + IDataSourceRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/lowcode-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, MockContext } from '../../_helpers'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IDataSourceRuntimeContext, + options?: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | InterpretDataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const USER_DATA = { + id: 9527, + name: 'Alice', + uri: 'https://mocks.alibaba-inc.com/user.json' + }; + const ERROR_MSG = 'test error'; + + + const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx)); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.members.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(1050); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(1050); + + // members 因为没有 requestHandler 直接就挂了 + t.is(context.dataSourceMap.members.status, RuntimeDataSourceStatus.Error) + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后 user 应该成功了,loaded + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + // 最后 orders 应该失败了,error 状态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.is(context.dataSourceMap.user.error, undefined); + t.deepEqual(context.dataSourceMap.orders.data, undefined); + t.not(context.dataSourceMap.orders.error, undefined); + t.deepEqual(context.dataSourceMap.members.data, undefined); + t.not(context.dataSourceMap.members.error, undefined); + t.regex(context.dataSourceMap.orders.error!.message, new RegExp(ERROR_MSG)); + t.regex(context.dataSourceMap.members.error!.message, new RegExp('no custom handler provide')); + + + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + t.is(context.state.orders, undefined); + t.is(context.state.members, undefined); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/types/src/data-source-handlers.ts b/packages/types/src/data-source-handlers.ts index 2e054b4e8..4ee7f6a0b 100644 --- a/packages/types/src/data-source-handlers.ts +++ b/packages/types/src/data-source-handlers.ts @@ -5,11 +5,17 @@ import { export type RequestHandler = ( options: RuntimeOptionsConfig, - context: IDataSourceRuntimeContext + context?: IDataSourceRuntimeContext, ) => Promise; export type UrlParamsHandler = ( - context?: IDataSourceRuntimeContext + context?: IDataSourceRuntimeContext, ) => Promise; export type RequestHandlersMap = Record>; + +// 仅在 type=custom 的时候生效的 handler +export type CustomRequestHandler = ( + options: RuntimeOptionsConfig, + context?: IDataSourceRuntimeContext, +) => Promise; diff --git a/packages/types/src/data-source-runtime.ts b/packages/types/src/data-source-runtime.ts index 9a89e39aa..878039340 100644 --- a/packages/types/src/data-source-runtime.ts +++ b/packages/types/src/data-source-runtime.ts @@ -1,10 +1,10 @@ import { IRuntimeDataSource } from './data-source'; +import { CustomRequestHandler } from './data-source-handlers'; // 先定义运行模式的类型 export interface RuntimeDataSource { list: RuntimeDataSourceConfig[]; - // TODO: dataMap 格式不对要处理 - dataHandler?: (dataMap: DataSourceMap) => void; + dataHandler?: (dataSourceMap: DataSourceMap) => void; } export type DataSourceMap = Record; @@ -16,7 +16,7 @@ export interface RuntimeDataSourceConfig { type?: string; willFetch?: WillFetch; shouldFetch?: () => boolean; - requestHandler?: () => void; // TODO: 待定 + requestHandler?: CustomRequestHandler; dataHandler?: DataHandler; errorHandler?: ErrorHandler; options?: RuntimeOptions; From 2a491ae0df8ed81e9970992178e0da753e60baf7 Mon Sep 17 00:00:00 2001 From: "zude.hzd" Date: Thu, 29 Oct 2020 21:38:36 +0800 Subject: [PATCH 23/34] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=BC=82=E6=AD=A5=E7=B1=BB=E5=9E=8Blibrary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designer/src/builtin-simulator/host.ts | 12 +++++++++++- .../react-simulator-renderer/src/renderer.ts | 11 ++++++++--- packages/utils/src/asset.ts | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 4679b3338..6f17c201d 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -209,11 +209,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost { this.libraryMap[item.package] = item.library; + if (item.async) { + this.asycnLibraryMap[item.package] = item; + } if (item.urls) { libraryAsset.push(item.urls); } @@ -254,7 +260,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost { // sync layout config - // sync schema this._schema = host.document.export(1); - // todo: split with others, not all should recompute if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) { this._libraryMap = host.libraryMap || {}; this._componentsMap = host.designer.componentsMap; - this.buildComponents(); + // this.buildComponents(); } // sync designMode @@ -57,6 +55,7 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer { // sync device this._device = host.device; }); + host.componentsConsumer.consume(async (componentsAsset) => { if (componentsAsset) { await this.load(componentsAsset); @@ -142,6 +141,12 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer { return loader.load(asset); } + async loadAsyncLibrary(asycnLibraryMap) { + const promise = await loader.loadAsyncLibrary(asycnLibraryMap); + this.buildComponents(); + return promise; + } + private instancesMap = new Map(); private unmountIntance(id: string, instance: ReactInstance) { diff --git a/packages/utils/src/asset.ts b/packages/utils/src/asset.ts index 6534372cd..85328952b 100644 --- a/packages/utils/src/asset.ts +++ b/packages/utils/src/asset.ts @@ -271,4 +271,23 @@ export class AssetLoader { } return isUrl ? load(content) : evaluate(content); } + + private async loadAsyncLibrary(asyncLibraryMap) { + const promiseList = []; const libraryKeyList = []; + for (const key in asyncLibraryMap) { + // 需要异步加载 + if (asyncLibraryMap[key].async) { + promiseList.push(window[asyncLibraryMap[key].library]); + libraryKeyList.push(asyncLibraryMap[key].library); + } + } + await Promise.all(promiseList).then((mods) => { + if (mods.length > 0) { + mods.map((item, index) => { + window[libraryKeyList[index]] = item; + return item; + }); + } + }); + } } From dcdcf287af97db63c217c6c430a771eae6ccf43d Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Sat, 31 Oct 2020 21:04:06 +0800 Subject: [PATCH 24/34] feat: add jsonp datahandler --- .../datasource-engine/src/handlers/fetch.ts | 24 ------- .../datasource-engine/src/handlers/mtop.ts | 18 ----- .../src/handlers/url-params.ts | 12 ---- .../datasource-jsonp-handler/.eslintignore | 3 + .../datasource-jsonp-handler/.eslintrc.js | 7 ++ .../datasource-jsonp-handler/.prettierrc.js | 4 ++ .../datasource-jsonp-handler/package.json | 29 +++++++++ .../datasource-jsonp-handler/src/index.ts | 31 +++++++++ .../datasource-jsonp-handler/tsconfig.json | 65 +++++++++++++++++++ 9 files changed, 139 insertions(+), 54 deletions(-) delete mode 100644 packages/datasource-engine/src/handlers/fetch.ts delete mode 100644 packages/datasource-engine/src/handlers/mtop.ts delete mode 100644 packages/datasource-engine/src/handlers/url-params.ts create mode 100644 packages/datasource-jsonp-handler/.eslintignore create mode 100644 packages/datasource-jsonp-handler/.eslintrc.js create mode 100644 packages/datasource-jsonp-handler/.prettierrc.js create mode 100644 packages/datasource-jsonp-handler/package.json create mode 100644 packages/datasource-jsonp-handler/src/index.ts create mode 100644 packages/datasource-jsonp-handler/tsconfig.json diff --git a/packages/datasource-engine/src/handlers/fetch.ts b/packages/datasource-engine/src/handlers/fetch.ts deleted file mode 100644 index d0f6d344b..000000000 --- a/packages/datasource-engine/src/handlers/fetch.ts +++ /dev/null @@ -1,24 +0,0 @@ -import request from 'universal-request'; -import type { AsObject, RequestOptions } from 'universal-request/lib/types'; - -import { DataSourceOptions, RequestHandler } from '../types'; - -const fetchHandler: RequestHandler = async ({ - url, - uri, - data, - params, - ...otherOptions -}: DataSourceOptions) => { - const reqOptions = { - url: ((url || uri) as unknown) as string, - data: ((data || params) as unknown) as AsObject, - ...otherOptions, - }; - - const res = await request(reqOptions as RequestOptions); - - return res; -}; - -export default fetchHandler; diff --git a/packages/datasource-engine/src/handlers/mtop.ts b/packages/datasource-engine/src/handlers/mtop.ts deleted file mode 100644 index 4894b9ad9..000000000 --- a/packages/datasource-engine/src/handlers/mtop.ts +++ /dev/null @@ -1,18 +0,0 @@ -import mtop from '@ali/universal-mtop'; -import { RequestHandler } from '../types'; - -const mtopHandler: RequestHandler = async (options) => { - const { api, uri, data, params, type, method, ...otherOptions } = options; - const reqOptions = { - ...otherOptions, - api: api || uri, - data: data || params, - type: type || method, - }; - - const res = await mtop(reqOptions); - - return res; -}; - -export default mtopHandler; diff --git a/packages/datasource-engine/src/handlers/url-params.ts b/packages/datasource-engine/src/handlers/url-params.ts deleted file mode 100644 index 67540c9f2..000000000 --- a/packages/datasource-engine/src/handlers/url-params.ts +++ /dev/null @@ -1,12 +0,0 @@ -import qs from 'query-string'; -import { RequestHandler } from '../types'; - -export default function urlParamsHandler(search: string | Record): RequestHandler { - const urlParams = typeof search === 'string' ? qs.parse(search) : search; - - return async () => { - return { - data: urlParams, - }; - }; -} diff --git a/packages/datasource-jsonp-handler/.eslintignore b/packages/datasource-jsonp-handler/.eslintignore new file mode 100644 index 000000000..fecb7c26d --- /dev/null +++ b/packages/datasource-jsonp-handler/.eslintignore @@ -0,0 +1,3 @@ +/node_modules +/es +/lib \ No newline at end of file diff --git a/packages/datasource-jsonp-handler/.eslintrc.js b/packages/datasource-jsonp-handler/.eslintrc.js new file mode 100644 index 000000000..8c13fcaf4 --- /dev/null +++ b/packages/datasource-jsonp-handler/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: '../../.eslintrc', + rules: { + '@typescript-eslint/no-parameter-properties': 1, + 'no-param-reassign': 0, + }, +}; diff --git a/packages/datasource-jsonp-handler/.prettierrc.js b/packages/datasource-jsonp-handler/.prettierrc.js new file mode 100644 index 000000000..de2f53cdf --- /dev/null +++ b/packages/datasource-jsonp-handler/.prettierrc.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'all', +}; diff --git a/packages/datasource-jsonp-handler/package.json b/packages/datasource-jsonp-handler/package.json new file mode 100644 index 000000000..e2f1d5c1f --- /dev/null +++ b/packages/datasource-jsonp-handler/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ali/datasource-jsonp-handler", + "version": "1.0.0-alpha.1", + "main": "lib/index.js", + "module": "es/index.js", + "typings": "es/index.d.ts", + "files": [ + "src", + "lib", + "es" + ], + "scripts": { + "dev": "tsc --watch", + "clean": "rm -rf es lib", + "build": "npm run clean && tsc && tsc --outDir ./lib --module commonjs ", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "@ali/lowcode-types": "1.0.13-alpha.1", + "jsonp": "^0.2.1", + "typescript": "^3.9.7" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + }, + "devDependencies": { + "@types/jsonp": "^0.2.0" + } +} diff --git a/packages/datasource-jsonp-handler/src/index.ts b/packages/datasource-jsonp-handler/src/index.ts new file mode 100644 index 000000000..ca2d58bf8 --- /dev/null +++ b/packages/datasource-jsonp-handler/src/index.ts @@ -0,0 +1,31 @@ +import { RuntimeOptionsConfig } from '@ali/lowcode-types'; +import jsonp from 'jsonp'; + +const handleJsonpFetch = (url: string, param: string, name: string) => { + return new Promise((res, rej) => { + jsonp(url, { param, name }, (error: Error | null, data: any) => { + if (error) { + return rej(error); + } + res({ data }); + }); + }); +}; + +// config 留着扩展 +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function createJsonpHandler(config?: Record) { + // eslint-disable-next-line space-before-function-paren + return async function(options: RuntimeOptionsConfig) { + const params = + typeof options.params === 'object' + ? JSON.stringify(options.params) + : options.params; + const response = await handleJsonpFetch( + options.uri, + params || '', + options.name as string | '', + ); + return response; + }; +} diff --git a/packages/datasource-jsonp-handler/tsconfig.json b/packages/datasource-jsonp-handler/tsconfig.json new file mode 100644 index 000000000..eeea7a79b --- /dev/null +++ b/packages/datasource-jsonp-handler/tsconfig.json @@ -0,0 +1,65 @@ +{ + "compilerOptions": { + "outDir": "es", + "target": "es6", + "module": "esnext", + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + // "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + // "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": ["ESNext", "DOM"] /* Specify library files to be included in the compilation. */, + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "es" /* Redirect output structure to the directory. */, + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + "skipLibCheck": true + }, + "include": ["src/**/*"] +} From 2f28a1ddcad64c73b77bc3870ff26b23b723c734 Mon Sep 17 00:00:00 2001 From: "zude.hzd" Date: Mon, 2 Nov 2020 17:00:26 +0800 Subject: [PATCH 25/34] fix: update --- .../src/function-setter/index.tsx | 41 ++++++++++++------- .../plugin-event-bind-dialog/src/index.tsx | 30 +++++++------- packages/plugin-source-editor/src/index.tsx | 4 -- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/packages/editor-setters/src/function-setter/index.tsx b/packages/editor-setters/src/function-setter/index.tsx index e4c0971cc..20a6deb04 100644 --- a/packages/editor-setters/src/function-setter/index.tsx +++ b/packages/editor-setters/src/function-setter/index.tsx @@ -1,3 +1,4 @@ + import React, { PureComponent } from 'react'; // import PropTypes from 'prop-types'; import { Button, Icon, Dialog } from '@alifd/next'; @@ -64,8 +65,8 @@ export default class FunctionSetter extends PureComponent { editor.on(`${this.emitEventName}.bindEvent`, this.bindEvent); } - bindEvent = (eventName) => { - this.bindEventCallback(eventName); + bindEvent = (eventName, paramStr) => { + this.bindEventCallback(eventName, paramStr); }; @@ -75,9 +76,17 @@ export default class FunctionSetter extends PureComponent { } - bindFunction = () => { - const { field } = this.props; - field.editor.emit('eventBindDialog.openDialog', field.name, this.emitEventName); + bindFunction = (isEdit) => { + const { field, value } = this.props; + + let paramStr; + + if (value) { + paramStr = this.parseFunctionParam(value.value); + } + + + field.editor.emit('eventBindDialog.openDialog', field.name, this.emitEventName, paramStr, isEdit); }; openDialog = () => { @@ -102,14 +111,16 @@ export default class FunctionSetter extends PureComponent { parseFunctionName = (functionString: string) => { // 因为函数格式是固定的,所以可以按照字符换去匹配获取函数名 - const funNameStr = functionString.split('this.')[1]; + const funNameStr = functionString.split('this.')[1].split('.')[0]; + return funNameStr; + }; - if (funNameStr) { - const endIndex = funNameStr.indexOf('('); - return funNameStr.substr(0, endIndex); - } else { - return ''; + parseFunctionParam = (functionString:string) => { + // eslint-disable-next-line no-useless-escape + const matchList = functionString.match(/\[(\w|\s|\,|")*\]/); + if (matchList?.length) { + return matchList[0].substring(1, matchList[0].length - 1); } }; @@ -158,7 +169,7 @@ export default class FunctionSetter extends PureComponent {
    this.focusFunctionName(functionName)}>{functionName} - + this.bindFunction(true)} />
    ); @@ -177,14 +188,16 @@ export default class FunctionSetter extends PureComponent { }; - bindEventCallback = (eventName: string) => { + bindEventCallback = (eventName: string, paramStr:string) => { const { onChange } = this.props; + onChange({ type: 'JSFunction', - value: `function(){ return this.${eventName}() }`, + value: `function(){ return this.${eventName}.apply(this,Array.prototype.slice.call(arguments).concat([${paramStr || ''}])) }`, }); }; + render() { const { value } = this.props; const { isShowDialog } = this.state; diff --git a/packages/plugin-event-bind-dialog/src/index.tsx b/packages/plugin-event-bind-dialog/src/index.tsx index 978f074e5..7af71729a 100644 --- a/packages/plugin-event-bind-dialog/src/index.tsx +++ b/packages/plugin-event-bind-dialog/src/index.tsx @@ -58,15 +58,11 @@ export default class EventBindDialog extends Component { paramStr: '', }; - openDialog = (bindEventName: string) => { + openDialog = (bindEventName: string, isEdit:boolean) => { this.bindEventName = bindEventName; - this.initEventName(); + this.initEventName(isEdit); - this.setState({ - visiable: true, - selectedEventName: '', - }); }; closeDialog = () => { @@ -77,7 +73,7 @@ export default class EventBindDialog extends Component { componentDidMount() { const { editor, config } = this.props; - editor.on(`${config.pluginKey}.openDialog`, (bindEventName: string, setterName:string, paramStr:string) => { + editor.on(`${config.pluginKey}.openDialog`, (bindEventName: string, setterName:string, paramStr:string, isEdit:boolean) => { console.log(`paramStr:${ paramStr}`); this.setState({ setterName, @@ -95,20 +91,25 @@ export default class EventBindDialog extends Component { } } - this.openDialog(bindEventName); + this.openDialog(bindEventName, isEdit); }); } - initEventName = () => { + initEventName = (isEdit:boolean) => { let eventName = this.bindEventName; - this.eventList.forEach((item) => { - if (item.name === eventName) { - eventName = `${eventName}_new`; - } - }); + + if (!isEdit) { + this.eventList.forEach((item) => { + if (item.name === eventName) { + eventName = `${eventName}_new`; + } + }); + } this.setState({ eventName, + selectedEventName: (isEdit ? eventName : ''), + visiable: true, }); }; @@ -168,6 +169,7 @@ export default class EventBindDialog extends Component { render() { const { selectedEventName, eventName, visiable, paramStr } = this.state; + console.log('selectedEventName:' + selectedEventName); return ( Date: Tue, 3 Nov 2020 00:10:21 +0800 Subject: [PATCH 26/34] =?UTF-8?q?feat:=20createApp=E6=97=B6=E6=8B=BF?= =?UTF-8?q?=E5=8F=96onReady=E7=9A=84=E5=85=A5=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runtime/src/core/provider.ts | 3 ++- packages/runtime/src/core/runApp.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/runtime/src/core/provider.ts b/packages/runtime/src/core/provider.ts index 3c24dd7e5..33b2f4df8 100644 --- a/packages/runtime/src/core/provider.ts +++ b/packages/runtime/src/core/provider.ts @@ -250,7 +250,8 @@ export default class Provider { } // 定制构造根组件的逻辑,如切换路由机制 - createApp() { + // eslint-disable-next-line + createApp(params?: any) { throw new Error('Method called "createApp" not implemented.'); } diff --git a/packages/runtime/src/core/runApp.ts b/packages/runtime/src/core/runApp.ts index 0241334fd..604a4b0f6 100644 --- a/packages/runtime/src/core/runApp.ts +++ b/packages/runtime/src/core/runApp.ts @@ -28,13 +28,13 @@ export default function runApp() { if (!provider) { throw new Error('Please register class Provider'); } - provider.onReady(() => { + provider.onReady((params) => { const promise = provider.async(); promise.then((config: IAppConfig) => { if (!config) { return; } - const App = provider.createApp(); + const App = provider.createApp(params); provider.runApp(App, config); }).catch((err: Error) => { console.error(err.message); From aaec68377b149587e437d1e19517be2798510c74 Mon Sep 17 00:00:00 2001 From: "zude.hzd" Date: Tue, 3 Nov 2020 18:55:21 +0800 Subject: [PATCH 27/34] =?UTF-8?q?fix:=20loadAsyncLibrary=E4=B9=8B=E5=90=8E?= =?UTF-8?q?buildComponents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/builtin-simulator/host.ts | 6 ++++-- packages/editor-setters/src/function-setter/index.tsx | 4 +--- packages/react-simulator-renderer/src/renderer.ts | 7 +++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 6f17c201d..5b95b05d9 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -260,8 +260,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost { parseFunctionName = (functionString: string) => { // 因为函数格式是固定的,所以可以按照字符换去匹配获取函数名 - const funNameStr = functionString.split('this.')[1].split('.')[0]; - - return funNameStr; + return functionString.split('this.')[1]?.split('.')[0]; }; parseFunctionParam = (functionString:string) => { diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index 936a010cb..35d53b161 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -42,7 +42,7 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer { if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) { this._libraryMap = host.libraryMap || {}; this._componentsMap = host.designer.componentsMap; - // this.buildComponents(); + this.buildComponents(); } // sync designMode @@ -141,10 +141,9 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer { return loader.load(asset); } - async loadAsyncLibrary(asycnLibraryMap) { - const promise = await loader.loadAsyncLibrary(asycnLibraryMap); + async loadAsyncLibrary(asyncLibraryMap) { + await loader.loadAsyncLibrary(asyncLibraryMap); this.buildComponents(); - return promise; } private instancesMap = new Map(); From a155920705f235bb2df68f7e869fbbdd58a18f04 Mon Sep 17 00:00:00 2001 From: "muyun.my" Date: Tue, 3 Nov 2020 18:57:02 +0800 Subject: [PATCH 28/34] =?UTF-8?q?feat:=20renderer=20=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=E5=BC=95=E6=93=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/rax-render/package.json | 1 + packages/rax-render/src/engine/base.jsx | 79 +++++++++++-------- packages/react-renderer/package.json | 1 + packages/react-renderer/src/renderer/base.jsx | 76 +++++++++++------- 4 files changed, 98 insertions(+), 59 deletions(-) diff --git a/packages/rax-render/package.json b/packages/rax-render/package.json index 5ab65c43e..365d34de6 100644 --- a/packages/rax-render/package.json +++ b/packages/rax-render/package.json @@ -36,6 +36,7 @@ "@ali/b3-one": "^0.0.17", "@ali/bzb-request": "2.6.1", "@ali/lib-mtop": "^2.5.1", + "@ali/lowcode-datasource-engine": "1.0.7-0", "classnames": "^2.2.6", "debug": "^4.1.1", "events": "^3.0.0", diff --git a/packages/rax-render/src/engine/base.jsx b/packages/rax-render/src/engine/base.jsx index 850804129..8d0c3ca6b 100644 --- a/packages/rax-render/src/engine/base.jsx +++ b/packages/rax-render/src/engine/base.jsx @@ -2,6 +2,7 @@ import { Component, createElement } from 'rax'; import PropTypes from 'prop-types'; import Debug from 'debug'; import classnames from 'classnames'; +import { createInterpret } from '@ali/lowcode-datasource-engine'; import DataHelper from '../utils/dataHelper'; import { forEach, @@ -84,31 +85,6 @@ export default class BaseEngine extends Component { console.warn(e); } - reloadDataSource = () => new Promise((resolve, reject) => { - debug('reload data source'); - if (!this.__dataHelper) { - this.__showPlaceholder = false; - return resolve(); - } - this.__dataHelper - .getInitData() - .then((res) => { - this.__showPlaceholder = false; - if (isEmpty(res)) { - this.forceUpdate(); - return resolve(); - } - this.setState(res, resolve); - }) - .catch((err) => { - if (this.__showPlaceholder) { - this.__showPlaceholder = false; - this.forceUpdate(); - } - reject(err); - }); - }); - __setLifeCycleMethods = (method, args) => { const lifeCycleMethods = getValue(this.props.__schema, 'lifeCycles', {}); if (lifeCycleMethods[method]) { @@ -154,17 +130,58 @@ export default class BaseEngine extends Component { __initDataSource = (props = this.props) => { const schema = props.__schema || {}; - const appHelper = props.__appHelper; const dataSource = (schema && schema.dataSource) || {}; - this.__dataHelper = new DataHelper(this, dataSource, appHelper, (config) => this.__parseData(config)); - this.dataSourceMap = this.__dataHelper.dataSourceMap; + // requestHandlersMap 存在才走数据源引擎方案 + if (props.requestHandlersMap) { + const { dataSourceMap, reloadDataSource } = createInterpret(dataSource, this, { + requestHandlersMap: { + mtop: createMtopHandler(), + fetch: createFetchHandler(), + } + }); + this.dataSourceMap = dataSourceMap; + this.reloadDataSource = () => new Promise((resolve, reject) => { + debug('reload data source'); + this.__showPlaceholder = true; + reloadDataSource().then(() => { + this.__showPlaceholder = false; + // @TODO 是否需要 forceUpate + resolve(); + }) + }); + } else { + const appHelper = props.__appHelper; + this.__dataHelper = new DataHelper(this, dataSource, appHelper, (config) => this.__parseData(config)); + this.dataSourceMap = this.__dataHelper.dataSourceMap; + this.reloadDataSource = () => new Promise((resolve, reject) => { + debug('reload data source'); + if (!this.__dataHelper) { + this.__showPlaceholder = false; + return resolve(); + } + this.__dataHelper + .getInitData() + .then((res) => { + this.__showPlaceholder = false; + if (isEmpty(res)) { + this.forceUpdate(); + return resolve(); + } + this.setState(res, resolve); + }) + .catch((err) => { + if (this.__showPlaceholder) { + this.__showPlaceholder = false; + this.forceUpdate(); + } + reject(err); + }); + }); + } // 设置容器组件占位,若设置占位则在初始异步请求完成之前用loading占位且不渲染容器组件内部内容 if (this.__parseData(schema.props && schema.props.autoLoading)) { this.__showPlaceholder = (dataSource.list || []).some((item) => !!this.__parseData(item.isInit)); } - // this.__showPlaceholder = this.__parseData(schema.props && schema.props.autoLoading) && (dataSource.list || []).some( - // (item) => !!this.__parseData(item.isInit), - // ); }; __render = () => { diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index df949554a..922b6e4e4 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -28,6 +28,7 @@ "@ali/bzb-request": "^2.6.0-beta.13", "@ali/lib-mtop": "^2.5.1", "@alifd/next": "^1.19.17", + "@ali/lowcode-datasource-engine": "1.0.7-0", "debug": "^4.1.1", "events": "^3.0.0", "fetch-jsonp": "^1.1.3", diff --git a/packages/react-renderer/src/renderer/base.jsx b/packages/react-renderer/src/renderer/base.jsx index 2e17720ac..d2dea761b 100644 --- a/packages/react-renderer/src/renderer/base.jsx +++ b/packages/react-renderer/src/renderer/base.jsx @@ -1,6 +1,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import Debug from 'debug'; +import { createInterpret } from '@ali/lowcode-datasource-engine'; import Div from '../components/Div'; import VisualDom from '../components/VisualDom'; import AppContext from '../context/appContext'; @@ -81,31 +82,6 @@ export default class BaseRender extends PureComponent { console.warn(e); } - reloadDataSource = () => new Promise((resolve, reject) => { - debug('reload data source'); - if (!this.__dataHelper) { - this.__showPlaceholder = false; - return resolve(); - } - this.__dataHelper - .getInitData() - .then((res) => { - this.__showPlaceholder = false; - if (isEmpty(res)) { - this.forceUpdate(); - return resolve(); - } - this.setState(res, resolve); - }) - .catch((err) => { - if (this.__showPlaceholder) { - this.__showPlaceholder = false; - this.forceUpdate(); - } - reject(err); - }); - }); - __setLifeCycleMethods = (method, args) => { const lifeCycleMethods = getValue(this.props.__schema, 'lifeCycles', {}); let fn = lifeCycleMethods[method]; @@ -167,10 +143,54 @@ export default class BaseRender extends PureComponent { __initDataSource = (props = this.props) => { const schema = props.__schema || {}; - const appHelper = props.__appHelper; const dataSource = (schema && schema.dataSource) || {}; - this.__dataHelper = new DataHelper(this, dataSource, appHelper, (config) => this.__parseData(config)); - this.dataSourceMap = this.__dataHelper.dataSourceMap; + // requestHandlersMap 存在才走数据源引擎方案 + if (props.requestHandlersMap) { + const { dataSourceMap, reloadDataSource } = createInterpret(dataSource, this, { + requestHandlersMap: { + mtop: createMtopHandler(), + fetch: createFetchHandler(), + } + }); + this.dataSourceMap = dataSourceMap; + this.reloadDataSource = () => new Promise((resolve, reject) => { + debug('reload data source'); + this.__showPlaceholder = true; + reloadDataSource().then(() => { + this.__showPlaceholder = false; + // @TODO 是否需要 forceUpate + resolve(); + }) + }); + } else { + const appHelper = props.__appHelper; + this.__dataHelper = new DataHelper(this, dataSource, appHelper, (config) => this.__parseData(config)); + this.dataSourceMap = this.__dataHelper.dataSourceMap; + this.reloadDataSource = () => new Promise((resolve, reject) => { + debug('reload data source'); + if (!this.__dataHelper) { + this.__showPlaceholder = false; + return resolve(); + } + this.__dataHelper + .getInitData() + .then((res) => { + this.__showPlaceholder = false; + if (isEmpty(res)) { + this.forceUpdate(); + return resolve(); + } + this.setState(res, resolve); + }) + .catch((err) => { + if (this.__showPlaceholder) { + this.__showPlaceholder = false; + this.forceUpdate(); + } + reject(err); + }); + }); + } // 设置容器组件占位,若设置占位则在初始异步请求完成之前用loading占位且不渲染容器组件内部内容 this.__showPlaceholder = this.__parseData(schema.props && schema.props.autoLoading) && (dataSource.list || []).some( (item) => !!this.__parseData(item.isInit), From 8b2f0454135e7a19b86e5d45ca74e9521f42e7c2 Mon Sep 17 00:00:00 2001 From: "zude.hzd" Date: Tue, 3 Nov 2020 20:34:39 +0800 Subject: [PATCH 29/34] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=20asyncLibraryM?= =?UTF-8?q?ap=20=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/builtin-simulator/host.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 5b95b05d9..a61ca0dc4 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -209,7 +209,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost { this.libraryMap[item.package] = item.library; if (item.async) { - this.asycnLibraryMap[item.package] = item; + this.asyncLibraryMap[item.package] = item; } if (item.urls) { libraryAsset.push(item.urls); @@ -270,7 +270,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost Date: Tue, 3 Nov 2020 20:55:46 +0800 Subject: [PATCH 30/34] =?UTF-8?q?feat:=20renderer=20=E5=B1=82=E9=80=8F?= =?UTF-8?q?=E4=BC=A0=20requestHandlersMap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/demo/src/editor/config.js | 12 ++++++++++-- packages/designer/src/builtin-simulator/host.ts | 3 +++ packages/rax-render/src/engine/index.jsx | 4 ++++ .../rax-simulator-renderer/src/renderer-view.tsx | 1 + .../react-simulator-renderer/src/renderer-view.tsx | 1 + 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/demo/src/editor/config.js b/packages/demo/src/editor/config.js index c929c11fe..489d22d6f 100644 --- a/packages/demo/src/editor/config.js +++ b/packages/demo/src/editor/config.js @@ -1,4 +1,7 @@ import { DataSourceImportPluginCode } from '@ali/lowcode-plugin-datasource-pane'; +import { createMtopHandler } from '@ali/lowcode-datasource-mtop-handler'; +import { createFetchHandler } from '@ali/lowcode-datasource-fetch-handler'; +import { createJsonpHandler } from '@ali/lowcode-datasource-jsonp-handler'; export default { plugins: { @@ -177,10 +180,15 @@ export default { const assets = await editor.utils.get('./assets.json'); editor.set('assets', assets); const simulatorUrl = [ - 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/0.9.50/react-simulator-renderer.css', - 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/0.9.50/react-simulator-renderer.js', + 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/1.0.0/react-simulator-renderer.css', + 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/1.0.0/react-simulator-renderer.js', ]; editor.set('simulatorUrl', simulatorUrl); + editor.set('requestHandlersMap', { + mtop: createMtopHandler(), + fetch: createFetchHandler(), + jsonp: createJsonpHandler() + }); // editor.set('renderEnv', 'rax'); const schema = await editor.utils.get('./schema.json'); diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 20e417675..a92073a06 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -49,6 +49,9 @@ export interface BuiltinSimulatorProps { device?: 'mobile' | 'iphone' | string; deviceClassName?: string; environment?: Asset; + // @TODO 补充类型 + /** @property 请求处理器配置 */ + requestHandlersMap?: any; extraEnvironment?: Asset; library?: LibraryItem[]; simulatorUrl?: Asset; diff --git a/packages/rax-render/src/engine/index.jsx b/packages/rax-render/src/engine/index.jsx index 2a4af143f..2aeec553a 100644 --- a/packages/rax-render/src/engine/index.jsx +++ b/packages/rax-render/src/engine/index.jsx @@ -45,6 +45,8 @@ export default class Engine extends Component { appHelper: PropTypes.object, components: PropTypes.object, componentsMap: PropTypes.object, + // 数据源请求处理 + requestHandlersMap: PropTypes.object, designMode: PropTypes.string, suspended: PropTypes.bool, schema: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), @@ -59,6 +61,8 @@ export default class Engine extends Component { appHelper: null, components: {}, componentsMap: {}, + // 数据源请求处理 + requestHandlersMap: null, designMode: '', suspended: false, schema: {}, diff --git a/packages/rax-simulator-renderer/src/renderer-view.tsx b/packages/rax-simulator-renderer/src/renderer-view.tsx index 37658532e..c58bb1dfa 100644 --- a/packages/rax-simulator-renderer/src/renderer-view.tsx +++ b/packages/rax-simulator-renderer/src/renderer-view.tsx @@ -106,6 +106,7 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> { schema={renderer.schema} components={renderer.components} context={renderer.context} + requestHandlersMap={host.requestHandlersMap} device={device} designMode={renderer.designMode} suspended={renderer.suspended} diff --git a/packages/react-simulator-renderer/src/renderer-view.tsx b/packages/react-simulator-renderer/src/renderer-view.tsx index c5931929f..f4e81187d 100644 --- a/packages/react-simulator-renderer/src/renderer-view.tsx +++ b/packages/react-simulator-renderer/src/renderer-view.tsx @@ -99,6 +99,7 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> { components={renderer.components} appHelper={renderer.context} // context={renderer.context} + requestHandlersMap={host.requestHandlersMap} designMode={designMode} device={device} suspended={renderer.suspended} From 6e416d28c80525d8374028d73a10ce20dabb67d4 Mon Sep 17 00:00:00 2001 From: "muyun.my" Date: Tue, 3 Nov 2020 22:03:47 +0800 Subject: [PATCH 31/34] chore: resolve conflicts from release/1.0.0 --- packages/demo/src/editor/components.ts | 4 --- packages/demo/src/editor/config.ts | 7 +---- packages/plugin-components-pane/package.json | 5 ---- packages/plugin-datasource-pane/package.json | 2 +- packages/rax-render/package.json | 5 +--- packages/rax-render/src/engine/base.tsx | 28 ------------------- packages/react-renderer/src/renderer/base.tsx | 28 ------------------- 7 files changed, 3 insertions(+), 76 deletions(-) diff --git a/packages/demo/src/editor/components.ts b/packages/demo/src/editor/components.ts index 003923a84..caa52a36f 100644 --- a/packages/demo/src/editor/components.ts +++ b/packages/demo/src/editor/components.ts @@ -2,12 +2,8 @@ import logo from '@ali/lowcode-plugin-sample-logo'; import samplePreview from '@ali/lowcode-plugin-sample-preview'; import undoRedo from '@ali/lowcode-plugin-undo-redo'; import componentsPane from '@ali/lowcode-plugin-components-pane'; -<<<<<<< HEAD import outline, { OutlinePane } from '@ali/lowcode-plugin-outline-pane'; import dataSourcePane from '@ali/lowcode-plugin-datasource-pane'; -======= -import outline from '@ali/lowcode-plugin-outline-pane'; ->>>>>>> origin/release/1.0.0 import zhEn from '@ali/lowcode-plugin-zh-en'; import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog'; import variableBindDialog from '@ali/lowcode-plugin-variable-bind-dialog'; diff --git a/packages/demo/src/editor/config.ts b/packages/demo/src/editor/config.ts index 7736c5e5a..bda055b0b 100644 --- a/packages/demo/src/editor/config.ts +++ b/packages/demo/src/editor/config.ts @@ -180,16 +180,11 @@ export default { const assets = await editor.utils.get('./assets.json'); editor.set('assets', assets); const simulatorUrl = [ -<<<<<<< HEAD:packages/demo/src/editor/config.js 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/1.0.0/react-simulator-renderer.css', - 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/1.0.0/react-simulator-renderer.js', -======= - 'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/0.9.50/react-simulator-renderer.css', - //'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/0.9.50/react-simulator-renderer.js', + //'https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/1.0.0/react-simulator-renderer.js', // for debug 'http://localhost:3333/js/react-simulator-renderer.js', // 'http://localhost:3333/js/react-simulator-renderer.css', ->>>>>>> origin/release/1.0.0:packages/demo/src/editor/config.ts ]; editor.set('simulatorUrl', simulatorUrl); editor.set('requestHandlersMap', { diff --git a/packages/plugin-components-pane/package.json b/packages/plugin-components-pane/package.json index 7213923f8..2049b9fd0 100644 --- a/packages/plugin-components-pane/package.json +++ b/packages/plugin-components-pane/package.json @@ -1,12 +1,7 @@ { "name": "@ali/lowcode-plugin-components-pane", -<<<<<<< HEAD - "version": "0.1.0-beta.0", - "description": "低代码引擎数据源配置面板", -======= "version": "1.0.12", "description": "alibaba lowcode editor component-list plugin", ->>>>>>> origin/release/1.0.0 "files": [ "es/", "lib/" diff --git a/packages/plugin-datasource-pane/package.json b/packages/plugin-datasource-pane/package.json index 9484de9af..cbfc02d11 100644 --- a/packages/plugin-datasource-pane/package.json +++ b/packages/plugin-datasource-pane/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-plugin-datasource-pane", - "version": "0.1.0-beta.6", + "version": "1.0.12", "description": "低代码引擎数据源面板", "main": "lib/index.js", "files": [ diff --git a/packages/rax-render/package.json b/packages/rax-render/package.json index 3968ba88b..702742d2d 100644 --- a/packages/rax-render/package.json +++ b/packages/rax-render/package.json @@ -36,11 +36,8 @@ "@ali/b3-one": "^0.0.17", "@ali/bzb-request": "2.6.1", "@ali/lib-mtop": "^2.5.1", -<<<<<<< HEAD - "@ali/lowcode-datasource-engine": "1.0.7-0", -======= + "@ali/lowcode-datasource-engine": "^1.0.12", "@ali/lowcode-utils": "^1.0.12", ->>>>>>> origin/release/1.0.0 "classnames": "^2.2.6", "debug": "^4.1.1", "events": "^3.0.0", diff --git a/packages/rax-render/src/engine/base.tsx b/packages/rax-render/src/engine/base.tsx index 428185525..bf9436a6e 100644 --- a/packages/rax-render/src/engine/base.tsx +++ b/packages/rax-render/src/engine/base.tsx @@ -87,34 +87,6 @@ export default class BaseEngine extends Component { console.warn(e); } -<<<<<<< HEAD:packages/rax-render/src/engine/base.jsx -======= - reloadDataSource = () => new Promise((resolve, reject) => { - debug('reload data source'); - if (!this.__dataHelper) { - this.__showPlaceholder = false; - return resolve(); - } - this.__dataHelper - .getInitData() - .then((res) => { - this.__showPlaceholder = false; - if (isEmpty(res)) { - this.forceUpdate(); - return resolve(); - } - this.setState(res, resolve); - }) - .catch((err) => { - if (this.__showPlaceholder) { - this.__showPlaceholder = false; - this.forceUpdate(); - } - reject(err); - }); - }); - ->>>>>>> origin/release/1.0.0:packages/rax-render/src/engine/base.tsx __setLifeCycleMethods = (method, args) => { const lifeCycleMethods = getValue(this.props.__schema, 'lifeCycles', {}); if (lifeCycleMethods[method]) { diff --git a/packages/react-renderer/src/renderer/base.tsx b/packages/react-renderer/src/renderer/base.tsx index cbee1107f..a67ccf3fd 100644 --- a/packages/react-renderer/src/renderer/base.tsx +++ b/packages/react-renderer/src/renderer/base.tsx @@ -83,34 +83,6 @@ export default class BaseRender extends PureComponent { console.warn(e); } -<<<<<<< HEAD:packages/react-renderer/src/renderer/base.jsx -======= - reloadDataSource = () => new Promise((resolve, reject) => { - debug('reload data source'); - if (!this.__dataHelper) { - this.__showPlaceholder = false; - return resolve(); - } - this.__dataHelper - .getInitData() - .then((res) => { - this.__showPlaceholder = false; - if (isEmpty(res)) { - this.forceUpdate(); - return resolve(); - } - this.setState(res, resolve); - }) - .catch((err) => { - if (this.__showPlaceholder) { - this.__showPlaceholder = false; - this.forceUpdate(); - } - reject(err); - }); - }); - ->>>>>>> origin/release/1.0.0:packages/react-renderer/src/renderer/base.tsx __setLifeCycleMethods = (method, args) => { const lifeCycleMethods = getValue(this.props.__schema, 'lifeCycles', {}); let fn = lifeCycleMethods[method]; From cf3a61a8e8d662718b4c82914c056eed0bbb9f6a Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Tue, 3 Nov 2020 23:05:55 +0800 Subject: [PATCH 32/34] fix: jsonp handler rename --- packages/datasource-engine/handlers/fetch/index.d.ts | 1 - packages/datasource-engine/handlers/fetch/index.js | 1 - packages/datasource-engine/handlers/mtop/index.d.ts | 1 - packages/datasource-engine/handlers/mtop/index.js | 1 - .../datasource-engine/handlers/url-params/index.d.ts | 1 - .../datasource-engine/handlers/url-params/index.js | 1 - packages/datasource-engine/readme.md | 10 ++++++++-- packages/datasource-jsonp-handler/package.json | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 packages/datasource-engine/handlers/fetch/index.d.ts delete mode 100644 packages/datasource-engine/handlers/fetch/index.js delete mode 100644 packages/datasource-engine/handlers/mtop/index.d.ts delete mode 100644 packages/datasource-engine/handlers/mtop/index.js delete mode 100644 packages/datasource-engine/handlers/url-params/index.d.ts delete mode 100644 packages/datasource-engine/handlers/url-params/index.js diff --git a/packages/datasource-engine/handlers/fetch/index.d.ts b/packages/datasource-engine/handlers/fetch/index.d.ts deleted file mode 100644 index 86829236a..000000000 --- a/packages/datasource-engine/handlers/fetch/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export type * from '../../es/handlers/fetch'; diff --git a/packages/datasource-engine/handlers/fetch/index.js b/packages/datasource-engine/handlers/fetch/index.js deleted file mode 100644 index 5abed6279..000000000 --- a/packages/datasource-engine/handlers/fetch/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../lib/handlers/fetch').default; diff --git a/packages/datasource-engine/handlers/mtop/index.d.ts b/packages/datasource-engine/handlers/mtop/index.d.ts deleted file mode 100644 index 1d11c303b..000000000 --- a/packages/datasource-engine/handlers/mtop/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export type * from '../../es/handlers/mtop'; diff --git a/packages/datasource-engine/handlers/mtop/index.js b/packages/datasource-engine/handlers/mtop/index.js deleted file mode 100644 index 89f131c78..000000000 --- a/packages/datasource-engine/handlers/mtop/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../lib/handlers/mtop').default; diff --git a/packages/datasource-engine/handlers/url-params/index.d.ts b/packages/datasource-engine/handlers/url-params/index.d.ts deleted file mode 100644 index 58e059ec8..000000000 --- a/packages/datasource-engine/handlers/url-params/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export type * from '../../es/handlers/url-params'; diff --git a/packages/datasource-engine/handlers/url-params/index.js b/packages/datasource-engine/handlers/url-params/index.js deleted file mode 100644 index f9b01c61e..000000000 --- a/packages/datasource-engine/handlers/url-params/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../lib/handlers/url-params').default; diff --git a/packages/datasource-engine/readme.md b/packages/datasource-engine/readme.md index d5bcb84d6..d5be75f84 100644 --- a/packages/datasource-engine/readme.md +++ b/packages/datasource-engine/readme.md @@ -19,13 +19,19 @@ import { create } from '@ali/lowcode-datasource-engine/interpret'; // 面向出码,需要给处理过后的内容 import { create } from '@ali/lowcode-datasource-engine/runtime'; +import { createFetchHandler } from '@ali/lowcode-datasource-fetch-handler'; + +import { createMtopHandler } from '@ali/lowcode-datasource-mtop-handler'; + // dataSource 可以是 schema 协议内容 或者是运行时的转化后的配置内容 (出码专用) + // context 上下文(setState 为必选) -const dsf = create(dataSource, context, { +const dataSourceEngine = create(dataSource, context, { requestHandlersMap: { // 可选参数,以下内容为当前默认的内容 urlParams: handlersMap.urlParams('?bar=1&test=2'), - mtop: mtophandlers, + fetch: createFetchHandler, + mtop: createMtopHandler }, }); diff --git a/packages/datasource-jsonp-handler/package.json b/packages/datasource-jsonp-handler/package.json index e2f1d5c1f..58698ebae 100644 --- a/packages/datasource-jsonp-handler/package.json +++ b/packages/datasource-jsonp-handler/package.json @@ -1,5 +1,5 @@ { - "name": "@ali/datasource-jsonp-handler", + "name": "@ali/lowcode-datasource-jsonp-handler", "version": "1.0.0-alpha.1", "main": "lib/index.js", "module": "es/index.js", From af5ef187aa1b2cdfd3b028952c6c907cdfef7a23 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Wed, 4 Nov 2020 00:10:50 +0800 Subject: [PATCH 33/34] fix: lowcode types update --- packages/datasource-url-params-handler/package.json | 2 +- packages/datasource-url-params-handler/src/index.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/datasource-url-params-handler/package.json b/packages/datasource-url-params-handler/package.json index 39f45f729..9c51d26fc 100644 --- a/packages/datasource-url-params-handler/package.json +++ b/packages/datasource-url-params-handler/package.json @@ -16,7 +16,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@ali/lowcode-types": "^0.8.13", + "@ali/lowcode-types": "^1.0.13-alpha.2", "query-string": "^6.13.1", "typescript": "^3.9.7" }, diff --git a/packages/datasource-url-params-handler/src/index.ts b/packages/datasource-url-params-handler/src/index.ts index 350234854..589f2d2c8 100644 --- a/packages/datasource-url-params-handler/src/index.ts +++ b/packages/datasource-url-params-handler/src/index.ts @@ -1,7 +1,10 @@ import qs from 'query-string'; import { UrlParamsHandler } from '@ali/lowcode-types'; -export function createUrlParamsHandler(searchString: string | T = ''): UrlParamsHandler { +export function createUrlParamsHandler( + searchString: string | T = '', +): UrlParamsHandler { + // eslint-disable-next-line space-before-function-paren return async function(): Promise { if (typeof searchString === 'string') { const params = (qs.parse(searchString) as unknown) as T; From 79e51a926d76b9c816de4ff9da7b3260567b1591 Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Wed, 4 Nov 2020 00:15:13 +0800 Subject: [PATCH 34/34] fix: lowcode types update --- packages/datasource-mopen-handler/package.json | 2 +- packages/datasource-universal-mtop-handler/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/datasource-mopen-handler/package.json b/packages/datasource-mopen-handler/package.json index 7c60a774a..e0f460757 100644 --- a/packages/datasource-mopen-handler/package.json +++ b/packages/datasource-mopen-handler/package.json @@ -16,7 +16,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@ali/lowcode-types": "^1.0.10", + "@ali/lowcode-types": "^1.0.13-alpha.2", "@ali/mirror-io-client-mopen": "1.0.0-beta.16", "typescript": "^3.9.7" }, diff --git a/packages/datasource-universal-mtop-handler/package.json b/packages/datasource-universal-mtop-handler/package.json index bcb45d028..a98764103 100644 --- a/packages/datasource-universal-mtop-handler/package.json +++ b/packages/datasource-universal-mtop-handler/package.json @@ -16,7 +16,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@ali/lowcode-types": "^1.0.10", + "@ali/lowcode-types": "^1.0.13-alpha.2", "@ali/mirror-io-client-universal-mtop": "1.0.0-beta.16", "typescript": "^3.9.7" },