`);
+ expect(generatedPageFileContent).not.toContain(`import Page from "undefined";`);
+});
+
+function exportProject(inputPath: string, outputPath: string) {
+ const schemaJson = fs.readFileSync(inputPath, { encoding: 'utf8' });
+ const newSchema = schemaJson;
+ const builder = CodeGenerator.solutions.icejs();
+
+ return builder.generateProject(newSchema).then(async (result) => {
+ // displayResultInConsole(result);
+ const publisher = CodeGenerator.publishers.disk();
+ await publisher.publish({
+ project: result,
+ outputPath,
+ projectSlug: 'demo-project',
+ createProjectFolder: true,
+ });
+ return result;
+ });
+}
diff --git a/modules/code-generator/tests/bugfix/page-element1.schema.json b/modules/code-generator/tests/bugfix/page-element1.schema.json
new file mode 100644
index 0000000000..72640a246b
--- /dev/null
+++ b/modules/code-generator/tests/bugfix/page-element1.schema.json
@@ -0,0 +1,844 @@
+{
+ "version": "1.0.0",
+ "componentsMap": [
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Page",
+ "main": "",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "Page"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Image",
+ "main": "",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "Image"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Container",
+ "main": "",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "Container"
+ },
+ {
+ "devMode": "lowcode",
+ "componentName": "Slot"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Text",
+ "main": "",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "Text"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Link",
+ "main": "",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "Link"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Share",
+ "main": "",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "Share"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "DruidList",
+ "main": "",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "DruidList"
+ }
+ ],
+ "componentsTree": [
+ {
+ "componentName": "Page",
+ "id": "node_dockcviv8fo1",
+ "props": {
+ "ref": "outerView",
+ "style": {
+ "height": "100%"
+ },
+ "isTransparentTitle": true,
+ "spmA": "a691",
+ "spmB": "b34649",
+ "spmBizType": "BAOXIAN"
+ },
+ "fileName": "/",
+ "dataSource": {
+ "list": []
+ },
+ "lifeCycles": {
+ "componentDidMount": {
+ "type": "JSFunction",
+ "value": "function() {\n this.utils.rpc('com.alipay.inslifeweb.channel.pilotpension.render', {\n showType: 4,\n })\n .then((result) => {\n this.setState({\n policyCount: result.policyCount,\n hasAuthorized: result.hasAuthorized\n });\n });\n }"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "_insiopConfig": {
+ "sceneCode": "PILOT_PENSION_LANDING_PAGE"
+ },
+ "css": "body {\n background: #f5f5f9;\n}",
+ "methods": {
+ "handleAuth": {
+ "type": "JSFunction",
+ "value": "function() {\n this.setState({\n hasAuthorized: true,\n });\n \n this.utils.rpc('com.alipay.inslifeweb.agreement.index.authorize', {\n bizScene: 'PILOT_ENDOWMENT_CHANNEL_POLICY_AGREEMENT',\n agreementScene: '20',\n });\n\n Tracert.click('c88773.d183217');\n }"
+ }
+ },
+ "state": {
+ "policyCount": 0,
+ "hasAuthorized": false
+ },
+ "children": [
+ {
+ "componentName": "DruidList",
+ "id": "node_ockwcyxpypb",
+ "props": {
+ "slotList": [
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwnbkrje1e",
+ "props": {
+ "style": {
+ "marginBottom": "16px"
+ },
+ "spmC": "c88756"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Image",
+ "id": "node_ockwd01xqzc",
+ "props": {
+ "src": {
+ "type": "JSExpression",
+ "value": "this.module.imgList[0].imgUrl",
+ "mock": "https://img.alicdn.com/imgextra/i3/O1CN01eqyMv71N2XZXffFkv_!!6000000001512-2-tps-750-642.png"
+ },
+ "width": "100%",
+ "style": {
+ "display": "block"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ }
+ ],
+ "title": "图片区块"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_PICTURE"
+ },
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwdmjns334",
+ "props": {
+ "style": {
+ "marginLeft": "24px",
+ "marginRight": "24px",
+ "marginTop": "0px",
+ "borderRadius": "16px",
+ "backgroundColor": "#ffffff",
+ "marginBottom": "16px",
+ "paddingLeft": "20px",
+ "paddingTop": "20px",
+ "paddingRight": "20px",
+ "paddingBottom": "20px"
+ },
+ "spmC": "c88773"
+ },
+ "hidden": false,
+ "title": "已授权状态",
+ "isLocked": false,
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.policyCount > 0 && this.state.hasAuthorized",
+ "mock": true
+ },
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwkbudw48",
+ "props": {
+ "style": {
+ "backgroundColor": "#fff",
+ "marginRight": "0px",
+ "display": "flex",
+ "flexDirection": "row",
+ "justifyContent": "space-between",
+ "alignItems": "center",
+ "borderBottomStyle": "solid",
+ "borderBottomWidth": "0px",
+ "borderBottomColor": "#9b9b9b",
+ "marginBottom": "0px",
+ "marginLeft": "0px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "condition": true,
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwkbudw49",
+ "props": {},
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwkbudw4a",
+ "props": {
+ "context": "我的保单",
+ "style": {
+ "marginRight": "16px",
+ "fontSize": "30px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ },
+ {
+ "componentName": "Text",
+ "id": "node_ockwkbudw4b",
+ "props": {
+ "context": "专属商业养老保险",
+ "style": {
+ "color": "#999999",
+ "fontSize": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ },
+ {
+ "componentName": "Link",
+ "id": "node_ockx02i8r07",
+ "props": {
+ "link": "./pilot-pension_policy-list.html",
+ "spmD": "c88773.d183218"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwkbudw4s",
+ "props": {
+ "style": {
+ "boxSizing": "border-box",
+ "display": "flex",
+ "position": "relative",
+ "alignItems": "center",
+ "flexDirection": "row",
+ "marginLeft": "24px",
+ "borderWidth": "1px",
+ "borderStyle": "solid",
+ "borderRadius": "8px",
+ "borderColor": "#1677ff",
+ "paddingRight": "24px",
+ "paddingLeft": "24px",
+ "height": "58px",
+ "lineHeight": "30px",
+ "whiteSpace": "nowrap"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwkbudw4t",
+ "props": {
+ "context": "点击查看",
+ "style": {
+ "color": "#1677ff",
+ "fontSize": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "Container",
+ "id": "node_ockwptkenn17",
+ "props": {
+ "style": {
+ "marginLeft": "24px",
+ "marginRight": "24px",
+ "marginTop": "0px",
+ "borderRadius": "16px",
+ "backgroundColor": "#ffffff",
+ "marginBottom": "16px",
+ "paddingLeft": "20px",
+ "paddingTop": "20px",
+ "paddingRight": "20px",
+ "paddingBottom": "20px"
+ },
+ "spmC": "c88773"
+ },
+ "hidden": false,
+ "title": "未授权状态",
+ "isLocked": false,
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.policyCount > 0 && !this.state.hasAuthorized",
+ "mock": true
+ },
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwptkenn19",
+ "props": {
+ "style": {
+ "marginBottom": "0px",
+ "borderStyle": "none",
+ "display": "flex",
+ "alignItems": "center",
+ "paddingBottom": "16px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwptkenn1a",
+ "props": {
+ "context": "我的保单",
+ "style": {
+ "marginRight": "16px",
+ "fontSize": "30px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ },
+ {
+ "componentName": "Text",
+ "id": "node_ockwptkenn1b",
+ "props": {
+ "context": "专属商业养老保险",
+ "style": {
+ "color": "#999999",
+ "fontSize": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ },
+ {
+ "componentName": "Container",
+ "id": "node_ockwvvdp9p7",
+ "props": {
+ "style": {
+ "paddingTop": "16px",
+ "borderTopWidth": "1px",
+ "borderTopColor": "#eeeeee"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwptkenn1c",
+ "props": {
+ "context": "同意在蚂蚁保查看、管理专属商业养老保险保单",
+ "style": {
+ "height": "37px",
+ "lineHeight": "37px",
+ "color": "#999",
+ "fontSize": "26px",
+ "fontWeight": "400",
+ "marginLeft": "0px",
+ "display": "block",
+ "borderTopWidth": "1px",
+ "borderTopStyle": "solid",
+ "borderTopColor": "#eeeeee",
+ "paddingTop": "0px",
+ "borderStyle": "none"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ },
+ {
+ "componentName": "Container",
+ "id": "node_ockwptkenn1d",
+ "props": {
+ "style": {
+ "display": "block",
+ "flexDirection": "row"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwptkenn1e",
+ "props": {
+ "style": {
+ "boxSizing": "border-box",
+ "display": "inline-block",
+ "position": "relative",
+ "alignItems": "center",
+ "flexDirection": "row",
+ "marginTop": "16px",
+ "marginLeft": "0px",
+ "borderWidth": "1px",
+ "borderStyle": "solid",
+ "borderRadius": "8px",
+ "borderColor": "#1677ff",
+ "paddingRight": "24px",
+ "paddingLeft": "24px",
+ "whiteSpace": "nowrap",
+ "paddingTop": "0px",
+ "paddingBottom": "0px",
+ "height": "58px",
+ "lineHeight": "58px"
+ },
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "handleAuth"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.handleAuth.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwptkenn1f",
+ "props": {
+ "context": "同意并查看",
+ "style": {
+ "color": "#1677ff",
+ "fontSize": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "title": "我的保单"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_MYPOLICY"
+ },
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwdbwgg7o",
+ "props": {
+ "style": {
+ "paddingTop": "20px",
+ "paddingLeft": "20px",
+ "paddingRight": "20px",
+ "backgroundColor": "#ffffff",
+ "marginLeft": "24px",
+ "marginRight": "24px",
+ "paddingBottom": "20px",
+ "borderRadius": "16px",
+ "marginBottom": "16px"
+ },
+ "spmC": "c88758"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwdb9utbc",
+ "props": {
+ "style": {
+ "paddingBottom": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.module.productImg"
+ },
+ "children": [
+ {
+ "componentName": "Link",
+ "id": "node_ockx03llkjw",
+ "props": {
+ "link": {
+ "type": "JSExpression",
+ "value": "this.item.link"
+ },
+ "spmD": "c88758.d183221"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Image",
+ "id": "node_ockwdb9utbd",
+ "props": {
+ "src": {
+ "type": "JSExpression",
+ "value": "this.item.imgSrc",
+ "mock": "https://img.alicdn.com/imgextra/i1/O1CN01c35RIk1e3Ji8oUPXQ_!!6000000003815-2-tps-654-376.png"
+ },
+ "width": "100%",
+ "style": {
+ "display": "block"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "Text",
+ "id": "node_ockwnbkrje1l",
+ "props": {
+ "context": "更多指定保司产品将逐渐开放,敬请期待",
+ "style": {
+ "color": "#999999",
+ "fontSize": "26px",
+ "textAlign": "center",
+ "display": "block"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ]
+ }
+ ],
+ "title": "产品列表"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_ARTICLE_LIST"
+ },
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Container",
+ "id": "node_ockx4gcrxg1c",
+ "props": {
+ "style": {
+ "paddingTop": "0px",
+ "paddingLeft": "0px",
+ "paddingRight": "0px",
+ "backgroundColor": "#ffffff",
+ "marginLeft": "24px",
+ "marginRight": "24px",
+ "paddingBottom": "0px",
+ "borderRadius": "16px",
+ "marginBottom": "16px"
+ },
+ "spmC": "c88757"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Image",
+ "id": "node_ockx4h25ygq",
+ "props": {
+ "src": {
+ "type": "JSExpression",
+ "value": "this.module.header",
+ "mock": "https://gw.alicdn.com/imgextra/i2/O1CN01nQxtcb1ail4yyw2kZ_!!6000000003364-2-tps-702-78.png"
+ },
+ "width": "100%"
+ },
+ "hidden": false,
+ "title": "标题",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ },
+ {
+ "componentName": "Container",
+ "id": "node_ockx4gcrxg1d",
+ "props": {
+ "style": {
+ "paddingBottom": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "文章列表循环",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.module.productIntroduce"
+ },
+ "children": [
+ {
+ "componentName": "Link",
+ "id": "node_ockx4gcrxg1e",
+ "props": {
+ "link": {
+ "type": "JSExpression",
+ "value": "this.item.link"
+ },
+ "spmD": {
+ "type": "JSExpression",
+ "value": "'c88757.d183219_' + this.index"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Image",
+ "id": "node_ockx4gcrxg1f",
+ "props": {
+ "src": "https://img.alicdn.com/imgextra/i4/O1CN015NY1E21XIhhWNXs3J_!!6000000002901-2-tps-700-230.png",
+ "width": "100%",
+ "style": {
+ "display": "block"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "title": "文章列表"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_PRODUCT_LIST"
+ },
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Share",
+ "id": "node_ockx0429phm",
+ "props": {
+ "bizType": "ztokenV0_PaWxRUaO",
+ "title": {
+ "type": "JSExpression",
+ "value": "this.module.share.shareTitle",
+ "mock": "我是分享标题"
+ },
+ "desc": {
+ "type": "JSExpression",
+ "value": "this.module.share.shareDesc",
+ "mock": "我是分享描述"
+ },
+ "iconUrl": {
+ "type": "JSExpression",
+ "value": "this.module.share.iconUrl",
+ "mock": "我是分享图标链接"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ],
+ "title": "分享设置"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_SHARE"
+ }
+ ],
+ "moduleList": {
+ "type": "JSExpression",
+ "value": "this.state._insiopData.modules || []"
+ }
+ },
+ "hidden": false,
+ "title": "德鲁伊容器",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ }
+ ],
+ "i18n": {}
+}
diff --git a/modules/code-generator/tests/bugfix/page-element1.test.ts b/modules/code-generator/tests/bugfix/page-element1.test.ts
new file mode 100644
index 0000000000..71b4bfc605
--- /dev/null
+++ b/modules/code-generator/tests/bugfix/page-element1.test.ts
@@ -0,0 +1,79 @@
+import CodeGenerator from '../../src';
+import * as fs from 'fs';
+import * as path from 'path';
+
+test('page-element1', async () => {
+ const inputSchemaJsonFile = path.join(__dirname, 'page-element1.schema.json');
+ const outputDir = path.join(__dirname, 'page-element1.generated');
+ await exportProject(inputSchemaJsonFile, outputDir);
+
+ const generatedPageFileContent = fs.readFileSync(
+ path.join(outputDir, 'demo-project/src/pages/$/index.jsx'),
+ 'utf-8',
+ );
+ expect(generatedPageFileContent).toContain('
{
+ // displayResultInConsole(result);
+ const publisher = CodeGenerator.publishers.disk();
+ await publisher.publish({
+ project: result,
+ outputPath,
+ projectSlug: 'demo-project',
+ createProjectFolder: true,
+ });
+ return result;
+ });
+}
diff --git a/modules/code-generator/tests/bugfix/page-element2.schema.json b/modules/code-generator/tests/bugfix/page-element2.schema.json
new file mode 100644
index 0000000000..5317582c98
--- /dev/null
+++ b/modules/code-generator/tests/bugfix/page-element2.schema.json
@@ -0,0 +1,844 @@
+{
+ "version": "1.0.0",
+ "componentsMap": [
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Page",
+ "destructuring": false,
+ "main": "/es/components/page",
+ "subName": "",
+ "componentName": "Page"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Image",
+ "main": "/es/components/image",
+ "destructuring": false,
+ "subName": "",
+ "componentName": "Image"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Container",
+ "main": "/es/components/container",
+ "destructuring": false,
+ "subName": "",
+ "componentName": "Container"
+ },
+ {
+ "devMode": "lowcode",
+ "componentName": "Slot"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Text",
+ "main": "/es/components/text",
+ "destructuring": false,
+ "subName": "",
+ "componentName": "Text"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Link",
+ "main": "/es/components/link",
+ "destructuring": false,
+ "subName": "",
+ "componentName": "Link"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "Share",
+ "main": "/es/components/share",
+ "destructuring": false,
+ "subName": "",
+ "componentName": "Share"
+ },
+ {
+ "package": "@alipay/insragdoll-common-components",
+ "version": "1.0.x",
+ "exportName": "DruidList",
+ "main": "/es/components/druid-list",
+ "destructuring": false,
+ "subName": "",
+ "componentName": "DruidList"
+ }
+ ],
+ "componentsTree": [
+ {
+ "componentName": "Page",
+ "id": "node_dockcviv8fo1",
+ "props": {
+ "ref": "outerView",
+ "style": {
+ "height": "100%"
+ },
+ "isTransparentTitle": true,
+ "spmA": "a691",
+ "spmB": "b34649",
+ "spmBizType": "BAOXIAN"
+ },
+ "fileName": "/",
+ "dataSource": {
+ "list": []
+ },
+ "lifeCycles": {
+ "componentDidMount": {
+ "type": "JSFunction",
+ "value": "function() {\n this.utils.rpc('com.alipay.inslifeweb.channel.pilotpension.render', {\n showType: 4,\n })\n .then((result) => {\n this.setState({\n policyCount: result.policyCount,\n hasAuthorized: result.hasAuthorized\n });\n });\n }"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "_insiopConfig": {
+ "sceneCode": "PILOT_PENSION_LANDING_PAGE"
+ },
+ "css": "body {\n background: #f5f5f9;\n}",
+ "methods": {
+ "handleAuth": {
+ "type": "JSFunction",
+ "value": "function() {\n this.setState({\n hasAuthorized: true,\n });\n \n this.utils.rpc('com.alipay.inslifeweb.agreement.index.authorize', {\n bizScene: 'PILOT_ENDOWMENT_CHANNEL_POLICY_AGREEMENT',\n agreementScene: '20',\n });\n\n Tracert.click('c88773.d183217');\n }"
+ }
+ },
+ "state": {
+ "policyCount": 0,
+ "hasAuthorized": false
+ },
+ "children": [
+ {
+ "componentName": "DruidList",
+ "id": "node_ockwcyxpypb",
+ "props": {
+ "slotList": [
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwnbkrje1e",
+ "props": {
+ "style": {
+ "marginBottom": "16px"
+ },
+ "spmC": "c88756"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Image",
+ "id": "node_ockwd01xqzc",
+ "props": {
+ "src": {
+ "type": "JSExpression",
+ "value": "this.module.imgList[0].imgUrl",
+ "mock": "https://img.alicdn.com/imgextra/i3/O1CN01eqyMv71N2XZXffFkv_!!6000000001512-2-tps-750-642.png"
+ },
+ "width": "100%",
+ "style": {
+ "display": "block"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ }
+ ],
+ "title": "图片区块"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_PICTURE"
+ },
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwdmjns334",
+ "props": {
+ "style": {
+ "marginLeft": "24px",
+ "marginRight": "24px",
+ "marginTop": "0px",
+ "borderRadius": "16px",
+ "backgroundColor": "#ffffff",
+ "marginBottom": "16px",
+ "paddingLeft": "20px",
+ "paddingTop": "20px",
+ "paddingRight": "20px",
+ "paddingBottom": "20px"
+ },
+ "spmC": "c88773"
+ },
+ "hidden": false,
+ "title": "已授权状态",
+ "isLocked": false,
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.policyCount > 0 && this.state.hasAuthorized",
+ "mock": true
+ },
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwkbudw48",
+ "props": {
+ "style": {
+ "backgroundColor": "#fff",
+ "marginRight": "0px",
+ "display": "flex",
+ "flexDirection": "row",
+ "justifyContent": "space-between",
+ "alignItems": "center",
+ "borderBottomStyle": "solid",
+ "borderBottomWidth": "0px",
+ "borderBottomColor": "#9b9b9b",
+ "marginBottom": "0px",
+ "marginLeft": "0px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "condition": true,
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwkbudw49",
+ "props": {},
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwkbudw4a",
+ "props": {
+ "context": "我的保单",
+ "style": {
+ "marginRight": "16px",
+ "fontSize": "30px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ },
+ {
+ "componentName": "Text",
+ "id": "node_ockwkbudw4b",
+ "props": {
+ "context": "专属商业养老保险",
+ "style": {
+ "color": "#999999",
+ "fontSize": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ },
+ {
+ "componentName": "Link",
+ "id": "node_ockx02i8r07",
+ "props": {
+ "link": "./pilot-pension_policy-list.html",
+ "spmD": "c88773.d183218"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwkbudw4s",
+ "props": {
+ "style": {
+ "boxSizing": "border-box",
+ "display": "flex",
+ "position": "relative",
+ "alignItems": "center",
+ "flexDirection": "row",
+ "marginLeft": "24px",
+ "borderWidth": "1px",
+ "borderStyle": "solid",
+ "borderRadius": "8px",
+ "borderColor": "#1677ff",
+ "paddingRight": "24px",
+ "paddingLeft": "24px",
+ "height": "58px",
+ "lineHeight": "30px",
+ "whiteSpace": "nowrap"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwkbudw4t",
+ "props": {
+ "context": "点击查看",
+ "style": {
+ "color": "#1677ff",
+ "fontSize": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "Container",
+ "id": "node_ockwptkenn17",
+ "props": {
+ "style": {
+ "marginLeft": "24px",
+ "marginRight": "24px",
+ "marginTop": "0px",
+ "borderRadius": "16px",
+ "backgroundColor": "#ffffff",
+ "marginBottom": "16px",
+ "paddingLeft": "20px",
+ "paddingTop": "20px",
+ "paddingRight": "20px",
+ "paddingBottom": "20px"
+ },
+ "spmC": "c88773"
+ },
+ "hidden": false,
+ "title": "未授权状态",
+ "isLocked": false,
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.policyCount > 0 && !this.state.hasAuthorized",
+ "mock": true
+ },
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwptkenn19",
+ "props": {
+ "style": {
+ "marginBottom": "0px",
+ "borderStyle": "none",
+ "display": "flex",
+ "alignItems": "center",
+ "paddingBottom": "16px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwptkenn1a",
+ "props": {
+ "context": "我的保单",
+ "style": {
+ "marginRight": "16px",
+ "fontSize": "30px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ },
+ {
+ "componentName": "Text",
+ "id": "node_ockwptkenn1b",
+ "props": {
+ "context": "专属商业养老保险",
+ "style": {
+ "color": "#999999",
+ "fontSize": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ },
+ {
+ "componentName": "Container",
+ "id": "node_ockwvvdp9p7",
+ "props": {
+ "style": {
+ "paddingTop": "16px",
+ "borderTopWidth": "1px",
+ "borderTopColor": "#eeeeee"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwptkenn1c",
+ "props": {
+ "context": "同意在蚂蚁保查看、管理专属商业养老保险保单",
+ "style": {
+ "height": "37px",
+ "lineHeight": "37px",
+ "color": "#999",
+ "fontSize": "26px",
+ "fontWeight": "400",
+ "marginLeft": "0px",
+ "display": "block",
+ "borderTopWidth": "1px",
+ "borderTopStyle": "solid",
+ "borderTopColor": "#eeeeee",
+ "paddingTop": "0px",
+ "borderStyle": "none"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ },
+ {
+ "componentName": "Container",
+ "id": "node_ockwptkenn1d",
+ "props": {
+ "style": {
+ "display": "block",
+ "flexDirection": "row"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwptkenn1e",
+ "props": {
+ "style": {
+ "boxSizing": "border-box",
+ "display": "inline-block",
+ "position": "relative",
+ "alignItems": "center",
+ "flexDirection": "row",
+ "marginTop": "16px",
+ "marginLeft": "0px",
+ "borderWidth": "1px",
+ "borderStyle": "solid",
+ "borderRadius": "8px",
+ "borderColor": "#1677ff",
+ "paddingRight": "24px",
+ "paddingLeft": "24px",
+ "whiteSpace": "nowrap",
+ "paddingTop": "0px",
+ "paddingBottom": "0px",
+ "height": "58px",
+ "lineHeight": "58px"
+ },
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "handleAuth"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.handleAuth.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Text",
+ "id": "node_ockwptkenn1f",
+ "props": {
+ "context": "同意并查看",
+ "style": {
+ "color": "#1677ff",
+ "fontSize": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "title": "我的保单"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_MYPOLICY"
+ },
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwdbwgg7o",
+ "props": {
+ "style": {
+ "paddingTop": "20px",
+ "paddingLeft": "20px",
+ "paddingRight": "20px",
+ "backgroundColor": "#ffffff",
+ "marginLeft": "24px",
+ "marginRight": "24px",
+ "paddingBottom": "20px",
+ "borderRadius": "16px",
+ "marginBottom": "16px"
+ },
+ "spmC": "c88758"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Container",
+ "id": "node_ockwdb9utbc",
+ "props": {
+ "style": {
+ "paddingBottom": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.module.productImg"
+ },
+ "children": [
+ {
+ "componentName": "Link",
+ "id": "node_ockx03llkjw",
+ "props": {
+ "link": {
+ "type": "JSExpression",
+ "value": "this.item.link"
+ },
+ "spmD": "c88758.d183221"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Image",
+ "id": "node_ockwdb9utbd",
+ "props": {
+ "src": {
+ "type": "JSExpression",
+ "value": "this.item.imgSrc",
+ "mock": "https://img.alicdn.com/imgextra/i1/O1CN01c35RIk1e3Ji8oUPXQ_!!6000000003815-2-tps-654-376.png"
+ },
+ "width": "100%",
+ "style": {
+ "display": "block"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "Text",
+ "id": "node_ockwnbkrje1l",
+ "props": {
+ "context": "更多指定保司产品将逐渐开放,敬请期待",
+ "style": {
+ "color": "#999999",
+ "fontSize": "26px",
+ "textAlign": "center",
+ "display": "block"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ]
+ }
+ ],
+ "title": "产品列表"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_ARTICLE_LIST"
+ },
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Container",
+ "id": "node_ockx4gcrxg1c",
+ "props": {
+ "style": {
+ "paddingTop": "0px",
+ "paddingLeft": "0px",
+ "paddingRight": "0px",
+ "backgroundColor": "#ffffff",
+ "marginLeft": "24px",
+ "marginRight": "24px",
+ "paddingBottom": "0px",
+ "borderRadius": "16px",
+ "marginBottom": "16px"
+ },
+ "spmC": "c88757"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "Image",
+ "id": "node_ockx4h25ygq",
+ "props": {
+ "src": {
+ "type": "JSExpression",
+ "value": "this.module.header",
+ "mock": "https://gw.alicdn.com/imgextra/i2/O1CN01nQxtcb1ail4yyw2kZ_!!6000000003364-2-tps-702-78.png"
+ },
+ "width": "100%"
+ },
+ "hidden": false,
+ "title": "标题",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ },
+ {
+ "componentName": "Container",
+ "id": "node_ockx4gcrxg1d",
+ "props": {
+ "style": {
+ "paddingBottom": "24px"
+ }
+ },
+ "hidden": false,
+ "title": "文章列表循环",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.module.productIntroduce"
+ },
+ "children": [
+ {
+ "componentName": "Link",
+ "id": "node_ockx4gcrxg1e",
+ "props": {
+ "link": {
+ "type": "JSExpression",
+ "value": "this.item.link"
+ },
+ "spmD": {
+ "type": "JSExpression",
+ "value": "'c88757.d183219_' + this.index"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""],
+ "children": [
+ {
+ "componentName": "Image",
+ "id": "node_ockx4gcrxg1f",
+ "props": {
+ "src": "https://img.alicdn.com/imgextra/i4/O1CN015NY1E21XIhhWNXs3J_!!6000000002901-2-tps-700-230.png",
+ "width": "100%",
+ "style": {
+ "display": "block"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "title": "文章列表"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_PRODUCT_LIST"
+ },
+ {
+ "childRender": {
+ "type": "JSSlot",
+ "params": ["module"],
+ "value": [
+ {
+ "componentName": "Share",
+ "id": "node_ockx0429phm",
+ "props": {
+ "bizType": "ztokenV0_PaWxRUaO",
+ "title": {
+ "type": "JSExpression",
+ "value": "this.module.share.shareTitle",
+ "mock": "我是分享标题"
+ },
+ "desc": {
+ "type": "JSExpression",
+ "value": "this.module.share.shareDesc",
+ "mock": "我是分享描述"
+ },
+ "iconUrl": {
+ "type": "JSExpression",
+ "value": "this.module.share.iconUrl",
+ "mock": "我是分享图标链接"
+ }
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ],
+ "title": "分享设置"
+ },
+ "templateCode": "PILOT_PENSION_LANDING_PAGE_SHARE"
+ }
+ ],
+ "moduleList": {
+ "type": "JSExpression",
+ "value": "this.state._insiopData.modules || []"
+ }
+ },
+ "hidden": false,
+ "title": "德鲁伊容器",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "loopArgs": ["", ""]
+ }
+ ]
+ }
+ ],
+ "i18n": {}
+}
diff --git a/modules/code-generator/tests/bugfix/page-element2.test.ts b/modules/code-generator/tests/bugfix/page-element2.test.ts
new file mode 100644
index 0000000000..cb739b0df9
--- /dev/null
+++ b/modules/code-generator/tests/bugfix/page-element2.test.ts
@@ -0,0 +1,79 @@
+import CodeGenerator from '../../src';
+import * as fs from 'fs';
+import * as path from 'path';
+
+test('page-element2', async () => {
+ const inputSchemaJsonFile = path.join(__dirname, 'page-element2.schema.json');
+ const outputDir = path.join(__dirname, 'page-element2.generated');
+ await exportProject(inputSchemaJsonFile, outputDir);
+
+ const generatedPageFileContent = fs.readFileSync(
+ path.join(outputDir, 'demo-project/src/pages/$/index.jsx'),
+ 'utf-8',
+ );
+ expect(generatedPageFileContent).toContain(' {
+ // displayResultInConsole(result);
+ const publisher = CodeGenerator.publishers.disk();
+ await publisher.publish({
+ project: result,
+ outputPath,
+ projectSlug: 'demo-project',
+ createProjectFolder: true,
+ });
+ return result;
+ });
+}
diff --git a/modules/code-generator/tests/cli.test.ts b/modules/code-generator/tests/cli.test.ts
new file mode 100644
index 0000000000..2a785c293e
--- /dev/null
+++ b/modules/code-generator/tests/cli.test.ts
@@ -0,0 +1,35 @@
+import { run } from '../src/cli';
+
+describe('cli', () => {
+ it('should works for the default example-schema.json', async () => {
+ const res = await run(['example-schema.json'], {
+ solution: 'icejs',
+ output: './demo',
+ });
+ expect(res).toBe(0);
+ });
+
+ it('should works for the default example-schema.json5', async () => {
+ const res = await run(['example-schema.json5'], {
+ solution: 'icejs',
+ output: './demo',
+ });
+ expect(res).toBe(0);
+ });
+
+ it('should returns error for no schema file', async () => {
+ const res = await run([], {
+ solution: 'icejs',
+ output: './demo',
+ });
+
+ expect(res).not.toBe(0);
+ });
+
+ it('should returns error for to many schema files', async () => {
+ const res = await run(['example-schema.json', 'example-schema.json5'], {
+ solution: 'icejs',
+ });
+ expect(res).not.toBe(0);
+ });
+});
diff --git a/modules/code-generator/tests/helpers/solutionHelper.ts b/modules/code-generator/tests/helpers/solutionHelper.ts
new file mode 100644
index 0000000000..b3070bd59a
--- /dev/null
+++ b/modules/code-generator/tests/helpers/solutionHelper.ts
@@ -0,0 +1,106 @@
+import { spawnSync } from 'child_process';
+import fs from 'fs';
+import path from 'path';
+import chalk from 'chalk';
+
+export { createDiskPublisher } from '../../src/publisher/disk';
+
+export function removeActualDirRecursiveSync(actualDir: string, caseFullDir: string) {
+ ensureShellExec('rm', ['-rf', actualDir], { cwd: caseFullDir });
+}
+
+export function runPrettierSync(files: string[], cwd: string) {
+ ensureShellExec('npx', ['prettier', '--write', ...files], { cwd });
+}
+
+export function diffActualAndExpectedSync(caseFullDir: string): string {
+ const res = spawnSync(
+ 'diff',
+ ['-wBur', '-x', '.eslintrc.js', '-x', 'abc.json', 'expected', 'actual'],
+ {
+ cwd: caseFullDir,
+ stdio: 'pipe',
+ shell: true,
+ encoding: 'utf-8',
+ },
+ );
+
+ return colorizeDiffOutput(res.stdout);
+}
+
+export function ensureShellExec(
+ shellCmd: string,
+ args: string[],
+ { cwd = process.cwd() }: { cwd?: string } = {},
+): { stdout: string; stderr: string } {
+ const res = spawnSync(shellCmd, args, {
+ stdio: 'pipe',
+ shell: true,
+ cwd,
+ encoding: 'utf-8',
+ });
+
+ if (res.status !== 0) {
+ throw new Error(
+ `Shell command "${shellCmd} ${args.slice(0, 2).join(' ')}..." failed with status: ${
+ res.status
+ } (Full command: "${shellCmd} ${args.join(' ')}" ) (stderr: ${res.stderr})`,
+ );
+ }
+
+ return res;
+}
+
+export function colorizeDiffOutput(output: string): string {
+ if (!output) {
+ return output;
+ }
+
+ return output
+ .split('\n')
+ .map((line) => {
+ if (/^Only/i.test(line)) {
+ return chalk.red(line);
+ } else if (line[0] === '+') {
+ return chalk.yellow(line);
+ } else if (line[0] === '-') {
+ return chalk.red(line);
+ } else {
+ return line;
+ }
+ })
+ .join('\n');
+}
+
+export function getSubDirectoriesSync(baseDir: string) {
+ return fs
+ .readdirSync(baseDir)
+ .filter((dirOrFileName: string) =>
+ fs.statSync(path.join(baseDir, dirOrFileName)).isDirectory(),
+ );
+}
+
+expect.extend({
+ toBeSameFileContents(caseFullDir: string) {
+ const differences = diffActualAndExpectedSync(caseFullDir);
+ if (differences) {
+ return {
+ message: () => differences,
+ pass: false,
+ };
+ } else {
+ return {
+ message: () => `expected case [${caseFullDir}] not to be same`,
+ pass: true,
+ };
+ }
+ },
+});
+
+declare global {
+ namespace jest {
+ interface Matchers {
+ toBeSameFileContents(): R;
+ }
+ }
+}
diff --git a/modules/code-generator/tests/plugins/common/__snapshots__/requireUtils.test.ts.snap b/modules/code-generator/tests/plugins/common/__snapshots__/requireUtils.test.ts.snap
new file mode 100644
index 0000000000..f64ee47f64
--- /dev/null
+++ b/modules/code-generator/tests/plugins/common/__snapshots__/requireUtils.test.ts.snap
@@ -0,0 +1,18 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`tests/plugins/common/requireUtils should works 1`] = `
+Object {
+ "chunks": Array [
+ Object {
+ "content": "import * from 'react';",
+ "fileType": "jsx",
+ "linkAfter": Array [],
+ "name": "CommonInternalDependencyImport",
+ "type": "string",
+ },
+ ],
+ "contextData": Object {},
+ "depNames": Array [],
+ "ir": Object {},
+}
+`;
diff --git a/modules/code-generator/tests/plugins/common/requireUtils.test.ts b/modules/code-generator/tests/plugins/common/requireUtils.test.ts
new file mode 100644
index 0000000000..9d09d81195
--- /dev/null
+++ b/modules/code-generator/tests/plugins/common/requireUtils.test.ts
@@ -0,0 +1,17 @@
+import requireUtils from '../../../src/plugins/common/requireUtils';
+import { ICodeStruct } from '../../../src/types';
+
+describe('tests/plugins/common/requireUtils', () => {
+ it('should works', async () => {
+ const plugin = requireUtils();
+ const ctx: ICodeStruct = {
+ chunks: [],
+ depNames: [],
+ ir: {},
+ contextData: {},
+ };
+
+ const newCtx = await plugin.apply(ctx, [ctx]);
+ expect(newCtx).toMatchSnapshot();
+ });
+});
diff --git a/modules/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap b/modules/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap
new file mode 100644
index 0000000000..534b19495d
--- /dev/null
+++ b/modules/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap
@@ -0,0 +1,227 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`condition at root condition and loop should be both works 1`] = `
+Object {
+ "chunks": Array [
+ Object {
+ "content": "
+ const __$$context = this;
+ const { state } = this;
+ return (this.state.otherThings).map((item, index) => ((__$$context) => (!!(__$$context.state.something) && (Hello world!)))(__$$createChildContext(__$$context, { item, index })));
+ ",
+ "fileType": "jsx",
+ "linkAfter": Array [
+ "ReactComponentClassRenderStart",
+ "ReactComponentClassRenderPre",
+ ],
+ "name": "ReactComponentClassRenderJSX",
+ "type": "string",
+ },
+ Object {
+ "content": "
+ function __$$createChildContext(oldContext, ext) {
+ const childContext = {
+ ...oldContext,
+ ...ext,
+ };
+ childContext.__proto__ = oldContext;
+ return childContext;
+ }
+ ",
+ "fileType": "jsx",
+ "linkAfter": Array [
+ "CommonFileExport",
+ ],
+ "name": "CommonCustomContent",
+ "type": "string",
+ },
+ ],
+ "contextData": Object {},
+ "depNames": Array [],
+ "ir": Object {
+ "children": Array [
+ Object {
+ "children": "Hello world!",
+ "componentName": "Text",
+ },
+ ],
+ "componentName": "Page",
+ "condition": Object {
+ "type": "JSExpression",
+ "value": "this.state.something",
+ },
+ "containerType": "Page",
+ "fileName": "test",
+ "loop": Object {
+ "type": "JSExpression",
+ "value": "this.state.otherThings",
+ },
+ "moduleName": "test",
+ },
+}
+`;
+
+exports[`condition at root condition=JSExpression should be ignored 1`] = `
+Object {
+ "chunks": Array [
+ Object {
+ "content": "
+ const __$$context = this;
+ const { state } = this;
+ return !!(this.state.something) && (Hello world!);
+ ",
+ "fileType": "jsx",
+ "linkAfter": Array [
+ "ReactComponentClassRenderStart",
+ "ReactComponentClassRenderPre",
+ ],
+ "name": "ReactComponentClassRenderJSX",
+ "type": "string",
+ },
+ Object {
+ "content": "
+ function __$$createChildContext(oldContext, ext) {
+ const childContext = {
+ ...oldContext,
+ ...ext,
+ };
+ childContext.__proto__ = oldContext;
+ return childContext;
+ }
+ ",
+ "fileType": "jsx",
+ "linkAfter": Array [
+ "CommonFileExport",
+ ],
+ "name": "CommonCustomContent",
+ "type": "string",
+ },
+ ],
+ "contextData": Object {},
+ "depNames": Array [],
+ "ir": Object {
+ "children": Array [
+ Object {
+ "children": "Hello world!",
+ "componentName": "Text",
+ },
+ ],
+ "componentName": "Page",
+ "condition": Object {
+ "type": "JSExpression",
+ "value": "this.state.something",
+ },
+ "containerType": "Page",
+ "fileName": "test",
+ "moduleName": "test",
+ },
+}
+`;
+
+exports[`condition at root condition=null should be ignored 1`] = `
+Object {
+ "chunks": Array [
+ Object {
+ "content": "
+ const __$$context = this;
+ const { state } = this;
+ return Hello world!;
+ ",
+ "fileType": "jsx",
+ "linkAfter": Array [
+ "ReactComponentClassRenderStart",
+ "ReactComponentClassRenderPre",
+ ],
+ "name": "ReactComponentClassRenderJSX",
+ "type": "string",
+ },
+ Object {
+ "content": "
+ function __$$createChildContext(oldContext, ext) {
+ const childContext = {
+ ...oldContext,
+ ...ext,
+ };
+ childContext.__proto__ = oldContext;
+ return childContext;
+ }
+ ",
+ "fileType": "jsx",
+ "linkAfter": Array [
+ "CommonFileExport",
+ ],
+ "name": "CommonCustomContent",
+ "type": "string",
+ },
+ ],
+ "contextData": Object {},
+ "depNames": Array [],
+ "ir": Object {
+ "children": Array [
+ Object {
+ "children": "Hello world!",
+ "componentName": "Text",
+ },
+ ],
+ "componentName": "Page",
+ "condition": null,
+ "containerType": "Page",
+ "fileName": "test",
+ "moduleName": "test",
+ },
+}
+`;
+
+exports[`condition at root condition=true should be ignored 1`] = `
+Object {
+ "chunks": Array [
+ Object {
+ "content": "
+ const __$$context = this;
+ const { state } = this;
+ return Hello world!;
+ ",
+ "fileType": "jsx",
+ "linkAfter": Array [
+ "ReactComponentClassRenderStart",
+ "ReactComponentClassRenderPre",
+ ],
+ "name": "ReactComponentClassRenderJSX",
+ "type": "string",
+ },
+ Object {
+ "content": "
+ function __$$createChildContext(oldContext, ext) {
+ const childContext = {
+ ...oldContext,
+ ...ext,
+ };
+ childContext.__proto__ = oldContext;
+ return childContext;
+ }
+ ",
+ "fileType": "jsx",
+ "linkAfter": Array [
+ "CommonFileExport",
+ ],
+ "name": "CommonCustomContent",
+ "type": "string",
+ },
+ ],
+ "contextData": Object {},
+ "depNames": Array [],
+ "ir": Object {
+ "children": Array [
+ Object {
+ "children": "Hello world!",
+ "componentName": "Text",
+ },
+ ],
+ "componentName": "Page",
+ "condition": true,
+ "containerType": "Page",
+ "fileName": "test",
+ "moduleName": "test",
+ },
+}
+`;
diff --git a/modules/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts b/modules/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts
new file mode 100644
index 0000000000..984c848303
--- /dev/null
+++ b/modules/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts
@@ -0,0 +1,86 @@
+import jsx from '../../../src/plugins/component/react/jsx';
+import { IContainerInfo } from '../../../src/types';
+
+describe('condition at root', () => {
+ test('condition=true should be ignored', async () => {
+ const containerIr: IContainerInfo = {
+ containerType: 'Page',
+ moduleName: 'test',
+ componentName: 'Page',
+ fileName: 'test',
+ condition: true,
+ children: [{ componentName: 'Text', children: 'Hello world!' }],
+ };
+ const result = await jsx()({
+ ir: containerIr,
+ contextData: {},
+ chunks: [],
+ depNames: [],
+ });
+ expect(result).toMatchSnapshot();
+ });
+
+ test('condition=null should be ignored', async () => {
+ const containerIr: IContainerInfo = {
+ containerType: 'Page',
+ moduleName: 'test',
+ componentName: 'Page',
+ fileName: 'test',
+ condition: null,
+ children: [{ componentName: 'Text', children: 'Hello world!' }],
+ };
+ const result = await jsx()({
+ ir: containerIr,
+ contextData: {},
+ chunks: [],
+ depNames: [],
+ });
+ expect(result).toMatchSnapshot();
+ });
+
+ test('condition=JSExpression should be ignored', async () => {
+ const containerIr: IContainerInfo = {
+ containerType: 'Page',
+ moduleName: 'test',
+ componentName: 'Page',
+ fileName: 'test',
+ condition: {
+ type: 'JSExpression',
+ value: 'this.state.something',
+ },
+ children: [{ componentName: 'Text', children: 'Hello world!' }],
+ };
+ const result = await jsx()({
+ ir: containerIr,
+ contextData: {},
+ chunks: [],
+ depNames: [],
+ });
+ expect(result).toMatchSnapshot();
+ });
+
+ test('condition and loop should be both works', async () => {
+ const containerIr: IContainerInfo = {
+ containerType: 'Page',
+ moduleName: 'test',
+ componentName: 'Page',
+ fileName: 'test',
+ condition: {
+ type: 'JSExpression',
+ value: 'this.state.something',
+ },
+ loop: {
+ type: 'JSExpression',
+ value: 'this.state.otherThings',
+ },
+ children: [{ componentName: 'Text', children: 'Hello world!' }],
+ };
+ const result = await jsx()({
+ ir: containerIr,
+ contextData: {},
+ chunks: [],
+ depNames: [],
+ });
+ expect(result).toMatchSnapshot();
+ });
+});
diff --git a/modules/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap b/modules/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap
new file mode 100644
index 0000000000..18b0a2aa21
--- /dev/null
+++ b/modules/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap
@@ -0,0 +1,39 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`postprocessor/prettier should works for custom files 1`] = `
+"
+ Hello
+
+
+"
+`;
+
+exports[`postprocessor/prettier should works for js file 1`] = `
+"import { Button } from \\"@alifd/next\\";
+export function App() {
+ return ;
+}
+"
+`;
+
+exports[`postprocessor/prettier should works for json file 1`] = `
+"{ \\"components\\": [\\"Button\\", \\"Block\\"] }
+"
+`;
+
+exports[`postprocessor/prettier should works for jsx file 1`] = `
+"import { Button } from \\"@alifd/next\\";
+export function App() {
+ return ;
+}
+"
+`;
+
+exports[`postprocessor/prettier should works for other files 1`] = `
+".foo {
+ font-size: 12px;
+}
+"
+`;
diff --git a/modules/code-generator/tests/postprocessor/prettier.test.ts b/modules/code-generator/tests/postprocessor/prettier.test.ts
new file mode 100644
index 0000000000..8a5649950a
--- /dev/null
+++ b/modules/code-generator/tests/postprocessor/prettier.test.ts
@@ -0,0 +1,39 @@
+import { prettier } from '../../src/postprocessor';
+
+describe('postprocessor/prettier', () => {
+ it('should works for js file', () => {
+ const fileType = 'js';
+ const content = `import { Button } from '@alifd/next'; export function App(){return }`;
+ expect(prettier()(content, fileType)).toMatchSnapshot();
+ });
+
+ it('should works for jsx file', () => {
+ const fileType = 'jsx';
+ const content = `import { Button } from '@alifd/next'; export function App(){return }`;
+ expect(prettier()(content, fileType)).toMatchSnapshot();
+ });
+
+ it('should works for json file', () => {
+ const fileType = 'json';
+ const content = `{"components": ["Button","Block"]}`;
+ expect(prettier()(content, fileType)).toMatchSnapshot();
+ });
+
+ it('should works for custom files', () => {
+ const fileType = 'vue';
+ const content = `Hello
`;
+ expect(
+ prettier({
+ customFileTypeParser: {
+ vue: 'html',
+ },
+ })(content, fileType),
+ ).toMatchSnapshot();
+ });
+
+ it('should works for other files', () => {
+ const fileType = 'less';
+ const content = `.foo{font-size: 12px;}`;
+ expect(prettier()(content, fileType)).toMatchSnapshot();
+ });
+});
diff --git a/modules/code-generator/tests/public/README.md b/modules/code-generator/tests/public/README.md
new file mode 100644
index 0000000000..7f9483343e
--- /dev/null
+++ b/modules/code-generator/tests/public/README.md
@@ -0,0 +1 @@
+# 这里测试的都是对外公开的 API,必须要保持稳定性
diff --git a/modules/code-generator/tests/public/SchemaParser/__snapshots__/p0-basic.test.ts.snap b/modules/code-generator/tests/public/SchemaParser/__snapshots__/p0-basic.test.ts.snap
new file mode 100644
index 0000000000..cc3770d07b
--- /dev/null
+++ b/modules/code-generator/tests/public/SchemaParser/__snapshots__/p0-basic.test.ts.snap
@@ -0,0 +1,178 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`tests/public/SchemaParser/p0-basics should be able to get dependencies in slots 1`] = `
+Array [
+ Array [
+ Object {
+ "componentName": "Page",
+ "dependencyType": "External",
+ "destructuring": false,
+ "devMode": "lowcode",
+ "exportName": "Page",
+ "version": "*",
+ },
+ Object {
+ "componentName": "Modal",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Modal",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "AliAutoDivDefault",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "AliAutoDiv",
+ "main": "build/lowcode/index.js",
+ "package": "@alife/mc-assets-1935",
+ "subName": "default",
+ "version": "0.1.43",
+ },
+ Object {
+ "componentName": "Button",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Button",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "Typography.Text",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Typography",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "subName": "Text",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "Typography.Link",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Typography",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "subName": "Link",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "NextPage",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Page",
+ "main": "lib/index.js",
+ "package": "@alife/container",
+ "subName": "",
+ "version": "0.3.7",
+ },
+ Object {
+ "componentName": "NextBlock",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Block",
+ "main": "lib/index.js",
+ "package": "@alife/container",
+ "subName": "",
+ "version": "0.3.7",
+ },
+ Object {
+ "componentName": "NextBlockCell",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Block",
+ "main": "lib/index.js",
+ "package": "@alife/container",
+ "subName": "Cell",
+ "version": "0.3.7",
+ },
+ Object {
+ "componentName": "NextP",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "P",
+ "main": "lib/index.js",
+ "package": "@alife/container",
+ "subName": "",
+ "version": "0.3.7",
+ },
+ Object {
+ "componentName": "Form",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Form",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "Form.Item",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Form",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "subName": "Item",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "Select",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Select",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "Input",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Input",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "AliAutoSearchTableDefault",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "AliAutoSearchTable",
+ "main": "build/lowcode/index.js",
+ "package": "@alife/mc-assets-1935",
+ "subName": "default",
+ "version": "0.1.43",
+ },
+ Object {
+ "componentName": "Tooltip",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Tooltip",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "Icon",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Icon",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ },
+ Object {
+ "componentName": "Empty",
+ "dependencyType": "External",
+ "destructuring": true,
+ "exportName": "Empty",
+ "main": "dist/antd-lowcode.esm.js",
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ },
+ ],
+]
+`;
diff --git a/modules/code-generator/tests/public/SchemaParser/data/schema-with-slot.json b/modules/code-generator/tests/public/SchemaParser/data/schema-with-slot.json
new file mode 100644
index 0000000000..07bd0db699
--- /dev/null
+++ b/modules/code-generator/tests/public/SchemaParser/data/schema-with-slot.json
@@ -0,0 +1,1457 @@
+{
+ "version": "1.0.0",
+ "componentsMap": [
+ {
+ "devMode": "lowcode",
+ "componentName": "Slot"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Button",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Button"
+ },
+ {
+ "package": "@alife/mc-assets-1935",
+ "version": "0.1.43",
+ "exportName": "AliAutoDiv",
+ "main": "build/lowcode/index.js",
+ "destructuring": true,
+ "subName": "default",
+ "componentName": "AliAutoDivDefault"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Typography",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "subName": "Text",
+ "componentName": "Typography.Text"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Typography",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "subName": "Link",
+ "componentName": "Typography.Link"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Modal",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Modal"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Select",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Select"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Form",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "subName": "Item",
+ "componentName": "Form.Item"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Input",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Input"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Form",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Form"
+ },
+ {
+ "package": "@alife/container",
+ "version": "0.3.7",
+ "exportName": "P",
+ "main": "lib/index.js",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "NextP"
+ },
+ {
+ "package": "@alife/container",
+ "version": "0.3.7",
+ "exportName": "Block",
+ "main": "lib/index.js",
+ "destructuring": true,
+ "subName": "Cell",
+ "componentName": "NextBlockCell"
+ },
+ {
+ "package": "@alife/container",
+ "version": "0.3.7",
+ "exportName": "Block",
+ "main": "lib/index.js",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "NextBlock"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Tooltip",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Tooltip"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Icon",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Icon"
+ },
+ {
+ "package": "@alife/mc-assets-1935",
+ "version": "0.1.43",
+ "exportName": "AliAutoSearchTable",
+ "main": "build/lowcode/index.js",
+ "destructuring": true,
+ "subName": "default",
+ "componentName": "AliAutoSearchTableDefault"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Empty",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Empty"
+ },
+ {
+ "package": "@alife/container",
+ "version": "0.3.7",
+ "exportName": "Page",
+ "main": "lib/index.js",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "NextPage"
+ },
+ {
+ "devMode": "lowcode",
+ "componentName": "Page"
+ }
+ ],
+ "componentsTree": [
+ {
+ "componentName": "Page",
+ "id": "node_dockcviv8fo1",
+ "props": {
+ "ref": "outterView",
+ "style": {
+ "height": "100%"
+ }
+ },
+ "fileName": "test",
+ "dataSource": {
+ "list": []
+ },
+ "css": "body {\n font-size: 12px;\n}\n\n.botton {\n width: 100px;\n color: #ff00ff\n}",
+ "lifeCycles": {
+ "constructor": {
+ "type": "JSFunction",
+ "value": "function() {\n this.__jp__init();\n this.statusDesc = {\n 0: '失败',\n 1: '成功',\n 2: '构建中',\n 3: '构建超时',\n };\n this.pageParams = {};\n this.searchParams = {};\n this.userTimeout = null;\n this.currentUser = null;\n this.notFoundContent = null;\n this.projectTimeout = null;\n this.currentProject = null;\n }"
+ },
+ "componentDidMount": {
+ "type": "JSFunction",
+ "value": "function() {\n this.$ds.resolve('PROJECTS');\n if (this.userTimeout) {\n clearTimeout(this.userTimeout);\n this.userTimeout = null;\n }\n if (this.projectTimeout) {\n clearTimeout(this.projectTimeout);\n this.projectTimeout = null;\n }\n }"
+ },
+ "componentDidUpdate": {
+ "type": "JSFunction",
+ "value": "function(prevProps, prevState, snapshot) {}"
+ },
+ "componentWillUnmount": {
+ "type": "JSFunction",
+ "value": "function() {}"
+ }
+ },
+ "methods": {
+ "__jp__init": {
+ "type": "JSFunction",
+ "value": "function() {\n this.__jp__initEnv && this.__jp__initEnv();\n this.__jp__initConfig && this.__jp__initConfig();\n this.__jp__initDataSource && this.__jp__initDataSource();\n this.__jp__initRouter && this.__jp__initRouter();\n this.__jp__initUtils && this.__jp__initUtils();\n}"
+ },
+ "__jp__initRouter": {
+ "type": "JSFunction",
+ "value": "function() {\n if (window.arsenal) {\n this.$router = new window.jianpin.ArsenalRouter({\n app: this.props.microApp,\n });\n } else {\n this.$router = new window.jianpin.ArsenalRouter();\n }\n}"
+ },
+ "__jp__initDataSource": {
+ "type": "JSFunction",
+ "value": "function() {\n this.$apis = {\n PKG_LIST: {\n name: '打包列表',\n code: 'PKG_LIST',\n url: 'https://auto-nvwa.amap.com/ws/nvwa/cpp5x/packages/',\n method: 'GET',\n dataHandler: res => res.data,\n },\n PROJECTS: {\n name: '项目名称/渠道号',\n code: 'PROJECTS',\n url:\n 'http://auto-nvwa-staging.alibaba.com/ws/nvwa/cpp/select_projects/',\n method: 'GET',\n state: 'projects',\n params: {\n size: 5000,\n },\n dataHandler: res => {\n return res.data.data.result.map(d => {\n const { id, channelId, project_name } = d;\n return {\n label: `${project_name} / ${channelId}`,\n value: id,\n };\n });\n },\n },\n RELOAD: {\n name: '重新执行',\n code: 'RELOAD',\n url: 'https://auto-nvwa.amap.com/cpp/configbuild/rebuild/',\n method: 'GET',\n },\n BUILD_RESULT: {\n name: '打包结果',\n code: 'BUILD_RESULT',\n url:\n 'https://auto-nvwa.amap.com/cpp/api/configbuild/get_build_result/',\n method: 'GET',\n state: 'results',\n dataHandler: res => {\n return res.data.result;\n },\n },\n BUC_USER: {\n name: '搜索用户',\n code: 'BUC_USER',\n url: 'https://auto-nvwa.amap.com/ws/nvwa/sso_users/',\n method: 'GET',\n dataHandler: res => res.data.items,\n },\n};\n this.$ds = new window.jianpin.DataSource(this, {});\n}"
+ },
+ "__jp__initEnv": {
+ "type": "JSFunction",
+ "value": "function() {\n const hostname = window.location.hostname;\n let env = 'prod';\n\n if (window.jianpin && window.jianpin.env === 'dev') {\n env = 'dev';\n } else if (window.arsenalConfig) {\n env = window.arsenalConfig.env;\n }\n\n const urlSearchParams = new URLSearchParams(window.location.search);\n const searchParams = {};\n for (const [key, value] of urlSearchParams) {\n searchParams[key] = value;\n }\n this.$env = env;\n this.$searchParams = searchParams;\n\n if (window.arsenal && window.arsenal.store) {\n this.$user = window.arsenal.store.getState('user');\n this.$store = window.arsenal.store;\n window.arsenal.store.subscribe('user', () => {\n this.$user = window.arsenal.store.getState('user');\n });\n } else {\n this.$store = {\n subscribe: () => {},\n getState: () => {},\n };\n this.$user = this.__jp__mockUser || {};\n }\n}"
+ },
+ "__jp__initConfig": {
+ "type": "JSFunction",
+ "value": "function() {\n const __config = {\n \"default\": {},\n \"dev\": {},\n \"daily\": {},\n \"pre\": {},\n \"prod\": {}\n};\n\n this.$config = window.jianpin.utils.extend(true, {}, __config.default, __config[this.$env]);\n}"
+ },
+ "__jp__initUtils": {
+ "type": "JSFunction",
+ "value": "function() {\n this.$utils = {\n message: window.jianpin.utils.message,\n axios: window.jianpin.utils.axios,\n moment: window.jianpin.utils.moment,\n };\n}"
+ },
+ "setSearchItem": {
+ "type": "JSFunction",
+ "value": "function(item) {\n const searchState = this.state.searchValues;\n const reducer = (pre, key) => {\n let value = searchState[key];\n if (item.hasOwnProperty(key)) {\n value = item[key];\n }\n return {\n ...pre,\n [key]: value || null,\n };\n };\n const searchValues = Object.keys(searchState).reduce(reducer, {});\n this.setState({\n searchValues,\n });\n }"
+ },
+ "fetchProject": {
+ "type": "JSFunction",
+ "value": "function(value, callback) {\n if (this.projectTimeout) {\n clearTimeout(this.projectTimeout);\n this.projectTimeout = null;\n }\n this.currentProject = value;\n\n const fake = () => {\n this.$ds\n .resolve('PROJECTS', {\n params: { search_param: value },\n })\n .then(res => {\n if (this.currentProject !== value) {\n return;\n }\n callback(res || []);\n });\n };\n this.projectTimeout = setTimeout(fake, 300);\n }"
+ },
+ "handleProjectSearch": {
+ "type": "JSFunction",
+ "value": "function(value) {\n if (value) {\n this.fetchProject(value, projects => {\n this.setState({ projects });\n });\n } else {\n this.setState({ projects: [] });\n }\n }"
+ },
+ "handleProjectChange": {
+ "type": "JSFunction",
+ "value": "function(id) {\n this.setSearchItem({\n channel_id: id,\n });\n }"
+ },
+ "fetchUser": {
+ "type": "JSFunction",
+ "value": "function(value, callback) {\n if (this.userTimeout) {\n clearTimeout(this.userTimeout);\n this.userTimeout = null;\n }\n this.currentUser = value;\n\n const fake = () => {\n this.$ds\n .resolve('BUC_USER', {\n params: { q: value },\n })\n .then(res => {\n if (this.currentUser !== value) {\n return;\n }\n const data = res.slice(0, 8).map(r => ({\n label: `${r.id} / ${r.label}`,\n value: r.id,\n }));\n callback(data);\n });\n };\n this.userTimeout = setTimeout(fake, 300);\n }"
+ },
+ "handleUserSearch": {
+ "type": "JSFunction",
+ "value": "function(value) {\n if (value) {\n this.fetchUser(value, userOptions => {\n this.setState({ userOptions });\n });\n } else {\n this.setState({ userOptions: [] });\n }\n }"
+ },
+ "handleUserChange": {
+ "type": "JSFunction",
+ "value": "function(user) {\n console.log('debug user', user);\n this.setSearchItem({\n user_id: user,\n });\n }"
+ },
+ "fetchPkgs": {
+ "type": "JSFunction",
+ "value": "function() {\n const { pageIndex, pageSize } = this.pageParams;\n this.$ds\n .resolve('PKG_LIST', {\n params: {\n ...this.searchParams,\n page: pageIndex,\n size: pageSize,\n },\n })\n .then(res => {\n const { result, page } = res.data;\n const { count } = page;\n this.setState({\n isSearch: true,\n pkgs: result,\n total: count,\n });\n });\n }"
+ },
+ "onPageChange": {
+ "type": "JSFunction",
+ "value": "function(pageIndex, pageSize) {\n this.pageParams = {\n pageIndex,\n pageSize,\n };\n this.fetchPkgs();\n }"
+ },
+ "renderTime": {
+ "type": "JSFunction",
+ "value": "function(time) {\n return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\n }"
+ },
+ "renderUserName": {
+ "type": "JSFunction",
+ "value": "function(user) {\n return user.user_name;\n }"
+ },
+ "reload": {
+ "type": "JSFunction",
+ "value": "function(id) {\n if (!confirm('确实要重新执行?')) {\n return;\n }\n this.$ds\n .resolve('RELOAD', {\n params: {\n build_id: id,\n },\n })\n .then(res => {\n const { code, message } = res.data.status;\n if (code == 0) {\n this.$utils.message.error(message);\n } else {\n const { pageIndex, pageSize } = this.pageParams;\n this.onPageChange(pageIndex, pageSize);\n }\n })\n .catch(err => {\n this.$utils.message.error(err.message);\n });\n }"
+ },
+ "handleResult": {
+ "type": "JSFunction",
+ "value": "function(e) {\n // e.persist();\n e.preventDefault();\n e.stopPropagation();\n let href;\n let tagName;\n let target = e.target;\n do {\n tagName = target.tagName.toUpperCase();\n href = target.getAttribute('href');\n target = target.parentNode;\n } while (!href && tagName !== 'TD');\n if (!href) {\n return;\n }\n\n this.$ds\n .resolve('BUILD_RESULT', {\n params: {\n build_id: href,\n },\n })\n .then(res => {\n this.setState({\n resultVisible: true,\n });\n })\n .catch(err => {\n this.$utils.message.error(`打包结果获取失败: ${err.message}`);\n });\n }"
+ },
+ "handleDetail": {
+ "type": "JSFunction",
+ "value": "function() {\n // 跳转详情页面 TODO\n }"
+ },
+ "onResultCancel": {
+ "type": "JSFunction",
+ "value": "function() {\n this.setState({\n resultVisible: false,\n });\n }"
+ },
+ "formatResult": {
+ "type": "JSFunction",
+ "value": "function(item) {\n if (!item) {\n return '暂无结果';\n }\n const { channel, plat, version, status } = item;\n return [channel, plat, version, status].join('-');\n }"
+ },
+ "handleDownload": {
+ "type": "JSFunction",
+ "value": "function() {\n const { results } = this.state;\n if (!results || results.length < 1) {\n return;\n }\n let link = document.createElement('a');\n link.style.display = 'none';\n document.body.appendChild(link);\n results.forEach(r => {\n link.href = r.download_link;\n link.click();\n });\n document.body.removeChild(link);\n link = null;\n }"
+ },
+ "onFinish": {
+ "type": "JSFunction",
+ "value": "function(f) {\n const params = Object.keys(f).reduce((pre, key) => {\n const value = f[key];\n if (value === undefined) {\n return pre;\n }\n return {\n ...pre,\n [key]: value,\n };\n }, {});\n this.searchParams = params;\n this.fetchPkgs();\n }"
+ }
+ },
+ "state": {
+ "pkgs": [],
+ "total": 0,
+ "isSearch": false,
+ "projects": [],
+ "results": [],
+ "resultVisible": false,
+ "userOptions": [],
+ "searchValues": {
+ "user_id": "",
+ "channel_id": ""
+ }
+ },
+ "children": [
+ {
+ "componentName": "Modal",
+ "id": "node_ocksh9yppxb",
+ "props": {
+ "title": "查看结果",
+ "visible": {
+ "type": "JSExpression",
+ "value": "this.state.resultVisible"
+ },
+ "footer": {
+ "type": "JSSlot",
+ "value": [
+ {
+ "componentName": "Button",
+ "id": "node_ocksh9yppxf",
+ "props": {
+ "type": "primary",
+ "children": "确定",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "onResultCancel"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onCancel",
+ "relatedEventName": "onResultCancel"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onCancel",
+ "disabled": true
+ },
+ {
+ "name": "onOk",
+ "disabled": false
+ }
+ ]
+ },
+ "onCancel": {
+ "type": "JSFunction",
+ "value": "function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "width": "720px",
+ "centered": true,
+ "closable": true,
+ "keyboard": true,
+ "mask": true,
+ "maskClosable": true
+ },
+ "hidden": true,
+ "children": [
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockshazuxa4",
+ "props": {
+ "style": {
+ "width": "100%"
+ }
+ },
+ "children": [
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockshazuxai",
+ "props": {
+ "style": {
+ "width": "100%",
+ "textAlign": "left",
+ "marginBottom": "16px"
+ }
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.results && this.state.results.length > 0"
+ },
+ "children": [
+ {
+ "componentName": "Button",
+ "id": "node_ockshazuxah",
+ "props": {
+ "type": "primary",
+ "children": "下载全部",
+ "size": "small",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "handleDownload"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockt2muyfi4",
+ "props": {
+ "style": {
+ "width": "100%",
+ "marginTop": "10px"
+ }
+ },
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.state.results"
+ },
+ "children": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ockshazuxa5",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.formatResult(this.item)"
+ }
+ }
+ },
+ {
+ "componentName": "Typography.Link",
+ "id": "node_ockshazuxa6",
+ "props": {
+ "href": {
+ "type": "JSExpression",
+ "value": "this.item.download_link"
+ },
+ "target": "_blank",
+ "children": " - 点击下载"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.item.download_link"
+ }
+ },
+ {
+ "componentName": "Typography.Link",
+ "id": "node_ockshazuxa7",
+ "props": {
+ "href": {
+ "type": "JSExpression",
+ "value": "this.item.release_notes"
+ },
+ "target": "_blank",
+ "children": " - 跳转发布节点"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.item.release_notes"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "NextPage",
+ "id": "node_ocko19zplh1",
+ "props": {
+ "columns": 12,
+ "headerDivider": true,
+ "placeholderStyle": {
+ "gridRowEnd": "span 1",
+ "gridColumnEnd": "span 12"
+ },
+ "placeholder": "页面主体内容:拖拽Block布局组件到这里",
+ "header": {
+ "type": "JSSlot",
+ "title": "header"
+ },
+ "headerProps": {
+ "background": "surface",
+ "style": {
+ "padding": ""
+ }
+ },
+ "footer": {
+ "type": "JSSlot",
+ "title": "footer"
+ },
+ "minHeight": "100vh",
+ "contentProps": {
+ "noPadding": false,
+ "background": "transparent"
+ }
+ },
+ "title": "页面",
+ "children": [
+ {
+ "componentName": "NextBlock",
+ "id": "node_ockt3t4q8565",
+ "props": {
+ "childTotalColumns": 12
+ },
+ "title": "区块",
+ "children": [
+ {
+ "componentName": "NextBlockCell",
+ "id": "node_ockt3t4q8566",
+ "props": {
+ "isAutoContainer": true,
+ "colSpan": 12,
+ "rowSpan": 1
+ },
+ "title": "子区块",
+ "children": [
+ {
+ "componentName": "NextP",
+ "id": "node_ockt3t4q8567",
+ "props": {
+ "wrap": false,
+ "type": "body2",
+ "verAlign": "middle",
+ "textSpacing": true,
+ "align": "left",
+ "flex": true
+ },
+ "title": "段落",
+ "children": [
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockt3t4q8568",
+ "props": {
+ "style": {
+ "width": "100%",
+ "display": "flex"
+ }
+ },
+ "children": [
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockt3t4q857a",
+ "props": {
+ "style": {
+ "flex": "1"
+ }
+ },
+ "children": [
+ {
+ "componentName": "Form",
+ "id": "node_ocks8dtt1mt",
+ "props": {
+ "labelCol": {
+ "span": 10
+ },
+ "wrapperCol": {
+ "span": 14
+ },
+ "onFinish": {
+ "type": "JSFunction",
+ "value": "function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "name": "basic",
+ "layout": "inline",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onFinish",
+ "relatedEventName": "onFinish"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onFinish",
+ "disabled": true
+ },
+ {
+ "name": "onFinishFailed",
+ "disabled": false
+ },
+ {
+ "name": "onFieldsChange",
+ "disabled": false
+ },
+ {
+ "name": "onValuesChange",
+ "disabled": false
+ }
+ ]
+ },
+ "colon": true,
+ "labelAlign": "right",
+ "preserve": true,
+ "scrollToFirstError": true,
+ "size": "middle",
+ "values": {
+ "type": "JSExpression",
+ "value": "this.state.searchValues"
+ }
+ },
+ "children": [
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1mz",
+ "props": {
+ "label": "项目名称/渠道号",
+ "name": "channel_id",
+ "labelAlign": "right",
+ "colon": true
+ },
+ "children": [
+ {
+ "componentName": "Select",
+ "id": "node_ocksfuhwhsd",
+ "props": {
+ "style": {
+ "width": "320px"
+ },
+ "options": {
+ "type": "JSExpression",
+ "value": "this.state.projects"
+ },
+ "showArrow": false,
+ "tokenSeparators": [],
+ "showSearch": true,
+ "defaultActiveFirstOption": true,
+ "size": "middle",
+ "bordered": true,
+ "filterOption": true,
+ "optionFilterProp": "label",
+ "allowClear": true,
+ "placeholder": "请输入项目名称/渠道号",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onChange",
+ "relatedEventName": "handleProjectChange"
+ },
+ {
+ "type": "componentEvent",
+ "name": "onSearch",
+ "relatedEventName": "handleProjectSearch"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onBlur",
+ "disabled": false
+ },
+ {
+ "name": "onChange",
+ "disabled": true
+ },
+ {
+ "name": "onDeselect",
+ "disabled": false
+ },
+ {
+ "name": "onFocus",
+ "disabled": false
+ },
+ {
+ "name": "onInputKeyDown",
+ "disabled": false
+ },
+ {
+ "name": "onMouseEnter",
+ "disabled": false
+ },
+ {
+ "name": "onMouseLeave",
+ "disabled": false
+ },
+ {
+ "name": "onPopupScroll",
+ "disabled": false
+ },
+ {
+ "name": "onSearch",
+ "disabled": true
+ },
+ {
+ "name": "onSelect",
+ "disabled": false
+ },
+ {
+ "name": "onDropdownVisibleChange",
+ "disabled": false
+ }
+ ]
+ },
+ "onChange": {
+ "type": "JSFunction",
+ "value": "function(){this.handleProjectChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "onSearch": {
+ "type": "JSFunction",
+ "value": "function(){this.handleProjectSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1m12",
+ "props": {
+ "label": "版本号",
+ "name": "buildId"
+ },
+ "children": [
+ {
+ "componentName": "Input",
+ "id": "node_ocksfuhwhs3",
+ "props": {
+ "placeholder": "请输入版本号",
+ "style": {
+ "width": "180px"
+ },
+ "size": "middle",
+ "bordered": true
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1m18",
+ "props": {
+ "label": "构建人",
+ "name": "user_id"
+ },
+ "children": [
+ {
+ "componentName": "Select",
+ "id": "node_ocksfuhwhsi",
+ "props": {
+ "style": {
+ "width": "210px"
+ },
+ "options": {
+ "type": "JSExpression",
+ "value": "this.state.userOptions"
+ },
+ "showSearch": true,
+ "defaultActiveFirstOption": false,
+ "size": "middle",
+ "bordered": true,
+ "filterOption": true,
+ "optionFilterProp": "label",
+ "notFoundContent": {
+ "type": "JSExpression",
+ "value": "this.userNotFoundContent"
+ },
+ "showArrow": false,
+ "placeholder": "请输入构建人",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onChange",
+ "relatedEventName": "handleUserChange"
+ },
+ {
+ "type": "componentEvent",
+ "name": "onSearch",
+ "relatedEventName": "handleUserSearch"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onBlur",
+ "disabled": false
+ },
+ {
+ "name": "onChange",
+ "disabled": true
+ },
+ {
+ "name": "onDeselect",
+ "disabled": false
+ },
+ {
+ "name": "onFocus",
+ "disabled": false
+ },
+ {
+ "name": "onInputKeyDown",
+ "disabled": false
+ },
+ {
+ "name": "onMouseEnter",
+ "disabled": false
+ },
+ {
+ "name": "onMouseLeave",
+ "disabled": false
+ },
+ {
+ "name": "onPopupScroll",
+ "disabled": false
+ },
+ {
+ "name": "onSearch",
+ "disabled": true
+ },
+ {
+ "name": "onSelect",
+ "disabled": false
+ },
+ {
+ "name": "onDropdownVisibleChange",
+ "disabled": false
+ }
+ ]
+ },
+ "onChange": {
+ "type": "JSFunction",
+ "value": "function(){this.handleUserChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "onSearch": {
+ "type": "JSFunction",
+ "value": "function(){this.handleUserSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "allowClear": true
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1m19",
+ "props": {
+ "label": "ID",
+ "name": "id",
+ "labelAlign": "right",
+ "colon": true
+ },
+ "children": [
+ {
+ "componentName": "Input",
+ "id": "node_ocksfuhwhs8",
+ "props": {
+ "placeholder": "请输入ID",
+ "style": {
+ "width": "180px"
+ },
+ "bordered": true,
+ "size": "middle"
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1mw",
+ "props": {
+ "wrapperCol": {
+ "offset": 6
+ },
+ "labelAlign": "right",
+ "colon": true,
+ "style": {
+ "flex": "1",
+ "textAlign": "right"
+ }
+ },
+ "children": [
+ {
+ "componentName": "Button",
+ "id": "node_ocks8dtt1mx",
+ "props": {
+ "type": "primary",
+ "children": "查询",
+ "htmlType": "submit",
+ "shape": "default",
+ "size": "middle"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockt3t4q856b",
+ "props": {
+ "style": {}
+ },
+ "children": [
+ {
+ "componentName": "Button",
+ "id": "node_ockt3t4q85y",
+ "props": {
+ "type": "link",
+ "children": "新增打包",
+ "htmlType": "button",
+ "shape": "default",
+ "size": "middle"
+ },
+ "condition": true
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "NextBlock",
+ "id": "node_ockshc4ifn1b",
+ "props": {
+ "childTotalColumns": 12,
+ "mode": "inset",
+ "layoutmode": "O",
+ "autolayout": "(12|1)"
+ },
+ "title": "区块",
+ "children": [
+ {
+ "componentName": "NextBlockCell",
+ "id": "node_ockshc4ifn1c",
+ "props": {
+ "isAutoContainer": true,
+ "colSpan": 12,
+ "rowSpan": 1
+ },
+ "title": "子区块",
+ "children": [
+ {
+ "componentName": "NextP",
+ "id": "node_ockshc4ifn1d",
+ "props": {
+ "wrap": false,
+ "type": "body2",
+ "verAlign": "middle",
+ "textSpacing": true,
+ "align": "left",
+ "flex": true
+ },
+ "title": "段落",
+ "children": [
+ {
+ "componentName": "AliAutoSearchTableDefault",
+ "id": "node_ocksfuhwhsx",
+ "props": {
+ "rowKey": "key",
+ "dataSource": {
+ "type": "JSExpression",
+ "value": "this.state.pkgs"
+ },
+ "columns": [
+ {
+ "title": "ID",
+ "dataIndex": "id",
+ "key": "name",
+ "width": 80
+ },
+ {
+ "title": "渠道号",
+ "dataIndex": "channels",
+ "key": "age",
+ "width": 142,
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksh2bq0428",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.item"
+ },
+ "style": {
+ "display": "block"
+ }
+ },
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.text.split(',')"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "title": "版本号",
+ "dataIndex": "dic_version",
+ "key": "address",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Tooltip",
+ "id": "node_ocksts0jqgj",
+ "props": {
+ "title": {
+ "type": "JSSlot",
+ "value": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksts0jqgn",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.item. channelId + ' / ' + this.item.version"
+ },
+ "style": {
+ "display": "block",
+ "color": "#FFFFFF"
+ }
+ },
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.text || []"
+ }
+ }
+ ]
+ }
+ },
+ "children": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksts0jqgm",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.text[0].version"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "width": 120
+ },
+ {
+ "title": "构建Job",
+ "dataIndex": "job_name",
+ "width": 180
+ },
+ {
+ "title": "构建类型",
+ "dataIndex": "packaging_type",
+ "width": 94
+ },
+ {
+ "title": "构建状态",
+ "dataIndex": "status",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksh3jkxzw",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.statusDesc[this.text]"
+ }
+ }
+ },
+ {
+ "componentName": "Icon",
+ "id": "node_ocksh3jkxzx",
+ "props": {
+ "type": "SyncOutlined",
+ "size": 16,
+ "spin": true,
+ "style": {
+ "marginLeft": "10px"
+ }
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.text === 2"
+ }
+ }
+ ]
+ },
+ "width": 100
+ },
+ {
+ "title": "构建时间",
+ "dataIndex": "start_time",
+ "render": {
+ "type": "JSFunction",
+ "value": "function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "width": 148
+ },
+ {
+ "title": "构建人",
+ "dataIndex": "user",
+ "render": {
+ "type": "JSFunction",
+ "value": "function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "width": 80
+ },
+ {
+ "title": "Jenkins 链接",
+ "dataIndex": "jenkins_link",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Typography.Link",
+ "id": "node_ocksh64kbx21",
+ "props": {
+ "href": {
+ "type": "JSExpression",
+ "value": "this.text"
+ },
+ "target": "_blank",
+ "children": "查看"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.text"
+ }
+ },
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksh64kbx22",
+ "props": {
+ "children": "暂无"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "!this.text"
+ }
+ }
+ ]
+ },
+ "width": 120
+ },
+ {
+ "title": "测试平台链接",
+ "dataIndex": "is_run_testing",
+ "width": 120,
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Typography.Link",
+ "id": "node_ocksh3jkxz3e",
+ "props": {
+ "href": "http://rivermap.alibaba.net/dashboard/testExecute",
+ "target": "_blank",
+ "children": "查看"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.text"
+ }
+ },
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksh3jkxz3f",
+ "props": {
+ "children": "暂无"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "!this.text"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "title": "触发源",
+ "dataIndex": "source",
+ "width": 120
+ },
+ {
+ "title": "详情",
+ "dataIndex": "id",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Button",
+ "id": "node_ocksh8yryw7",
+ "props": {
+ "type": "link",
+ "children": "查看",
+ "size": "small",
+ "style": {
+ "padding": "0px"
+ },
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "handleDetail"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ "width": 80,
+ "fixed": "right"
+ },
+ {
+ "title": "结果",
+ "dataIndex": "id",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Button",
+ "id": "node_ocksh9v6jw7",
+ "props": {
+ "type": "link",
+ "children": "查看",
+ "size": "small",
+ "style": {
+ "padding": "0px"
+ },
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "handleResult",
+ "paramStr": "this.text"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "ghost": false,
+ "href": {
+ "type": "JSExpression",
+ "value": "this.text"
+ }
+ }
+ }
+ ]
+ },
+ "width": 80,
+ "fixed": "right"
+ },
+ {
+ "title": "重新执行",
+ "dataIndex": "id",
+ "width": 92,
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Button",
+ "id": "node_ocksh96rad1g",
+ "props": {
+ "type": "text",
+ "children": "",
+ "icon": {
+ "type": "JSSlot",
+ "value": [
+ {
+ "componentName": "Icon",
+ "id": "node_ocksh96rad1j",
+ "props": {
+ "type": "ReloadOutlined",
+ "size": 14,
+ "color": "#0593d3",
+ "style": {
+ "padding": "3px",
+ "border": "1px solid #0593d3",
+ "borderRadius": "14px",
+ "cursor": "pointer",
+ "height": "22px"
+ },
+ "spin": false
+ }
+ }
+ ]
+ },
+ "shape": "circle",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "reload"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ "fixed": "right"
+ }
+ ],
+ "actions": [],
+ "pagination": {
+ "total": {
+ "type": "JSExpression",
+ "value": "this.state.total"
+ },
+ "defaultPageSize": 10,
+ "onPageChange": {
+ "type": "JSFunction",
+ "value": "function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "defaultPageIndex": 1
+ },
+ "scrollX": 1200,
+ "isPagination": true
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "NextBlock",
+ "id": "node_ocksk6f8fa3b",
+ "props": {
+ "childTotalColumns": 12,
+ "mode": "inset",
+ "layoutmode": "O",
+ "autolayout": "(12|1)"
+ },
+ "title": "区块",
+ "children": [
+ {
+ "componentName": "NextBlockCell",
+ "id": "node_ocksk6f8fa3c",
+ "props": {
+ "isAutoContainer": true,
+ "colSpan": 12,
+ "rowSpan": 1
+ },
+ "title": "子区块",
+ "children": [
+ {
+ "componentName": "NextP",
+ "id": "node_ocksk6f8fa3d",
+ "props": {
+ "wrap": false,
+ "type": "body2",
+ "verAlign": "middle",
+ "textSpacing": true,
+ "align": "left",
+ "flex": true
+ },
+ "title": "段落",
+ "children": [
+ {
+ "componentName": "Empty",
+ "id": "node_ocksk6f8fa3e",
+ "props": {
+ "description": "暂无数据"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.pkgs.length < 1 && this.state.isSearch"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "i18n": {}
+}
diff --git a/modules/code-generator/tests/public/SchemaParser/p0-basic.test.ts b/modules/code-generator/tests/public/SchemaParser/p0-basic.test.ts
new file mode 100644
index 0000000000..4743e77583
--- /dev/null
+++ b/modules/code-generator/tests/public/SchemaParser/p0-basic.test.ts
@@ -0,0 +1,13 @@
+import { ProjectSchema } from '@alilc/lowcode-types';
+import { SchemaParser } from '../../../src';
+import SCHEMA_WITH_SLOT from './data/schema-with-slot.json';
+
+describe('tests/public/SchemaParser/p0-basics', () => {
+ it('should be able to get dependencies in slots', () => {
+ const schemaParser = new SchemaParser();
+ const result = schemaParser.parse(SCHEMA_WITH_SLOT as ProjectSchema);
+ expect(result.containers.map((c) => c.deps)).toMatchSnapshot();
+ expect(result.containers[0].deps?.some((dep) => dep.componentName === 'Tooltip')).toBeTruthy();
+ expect(result.containers[0].deps?.some((dep) => dep.componentName === 'Icon')).toBeTruthy();
+ });
+});
diff --git a/modules/code-generator/tests/public/cli.test.ts b/modules/code-generator/tests/public/cli.test.ts
new file mode 100644
index 0000000000..d0c1e613f7
--- /dev/null
+++ b/modules/code-generator/tests/public/cli.test.ts
@@ -0,0 +1,32 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import { spawnSync } from 'child_process';
+
+const PROJECT_ROOT = path.resolve(__dirname, '../..');
+
+describe('cli - lowcode-code-generator', () => {
+ it('should works', () => {
+ const res = spawnSync('node bin/lowcode-code-generator --solution icejs example-schema.json', {
+ shell: true,
+ stdio: 'pipe',
+ encoding: 'utf8',
+ cwd: PROJECT_ROOT,
+ });
+
+ expect({
+ status: res.status,
+ stdout: res.stdout,
+ stderr: res.stderr,
+ }).toMatchInlineSnapshot(`
+ Object {
+ "status": 0,
+ "stderr": "",
+ "stdout": "",
+ }
+ `);
+
+ expect(
+ fs.existsSync(path.join(PROJECT_ROOT, 'generated/src/pages/Test/index.jsx')),
+ ).toBeTruthy();
+ });
+});
diff --git a/modules/code-generator/tests/public/publisher/disk/disk.test.ts b/modules/code-generator/tests/public/publisher/disk/disk.test.ts
new file mode 100644
index 0000000000..a654a8a63b
--- /dev/null
+++ b/modules/code-generator/tests/public/publisher/disk/disk.test.ts
@@ -0,0 +1,56 @@
+import CodeGen from '../../../../src';
+import { ResultDir } from '@alilc/lowcode-types';
+
+describe('public/publisher/disk/disk', () => {
+ // standalone 模式下没有 disk publisher
+ if (process.env.TEST_TARGET === 'standalone') {
+ it('should ignore', () => {
+ expect(true).toBe(true);
+ });
+ return;
+ }
+
+ it('should works', async () => {
+ const disk = CodeGen.publishers.disk({
+ outputPath: 'demo-output',
+ projectSlug: 'example-project',
+ });
+
+ const demoProject: ResultDir = {
+ name: 'demo',
+ dirs: [],
+ files: [
+ {
+ name: 'package',
+ ext: 'json',
+ content: '{ "name": "demo", "version": "1.0.0" }',
+ },
+ ],
+ };
+
+ expect(disk.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
+
+ disk.setProject(demoProject);
+ expect(disk.getProject()).toBeTruthy();
+
+ expect(disk.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
+ expect(disk.setOutputPath('output')).toBe(undefined);
+ expect(disk.getOutputPath()).toMatchInlineSnapshot(`"output"`);
+
+ const publishRes = await disk.publish({
+ project: demoProject,
+ });
+
+ expect(publishRes.success).toBeTruthy();
+ expect(publishRes.payload).toBeTruthy();
+ });
+
+ it('should throws Error when project is missing', async () => {
+ const disk = CodeGen.publishers.disk({});
+ expect(disk.publish()).rejects.toBeTruthy();
+
+ expect(() => {
+ return disk.getProject();
+ }).toThrowError(/MissingProject/);
+ });
+});
diff --git a/modules/code-generator/tests/public/publisher/zip/zip.test.ts b/modules/code-generator/tests/public/publisher/zip/zip.test.ts
new file mode 100644
index 0000000000..ed37980d03
--- /dev/null
+++ b/modules/code-generator/tests/public/publisher/zip/zip.test.ts
@@ -0,0 +1,44 @@
+import CodeGen from '../../../../src';
+
+describe('public/publisher/zip/zip', () => {
+ it('should works', async () => {
+ const zip = CodeGen.publishers.zip({
+ outputPath: 'demo-output',
+ projectSlug: 'example-project',
+ });
+
+ const demoProject = {
+ name: 'demo',
+ dirs: [],
+ files: [
+ {
+ name: 'package',
+ ext: 'json',
+ content: '{ "name": "demo", "version": "1.0.0" }',
+ },
+ ],
+ };
+
+ expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
+
+ expect(zip.getProject()).toMatchInlineSnapshot(`undefined`);
+ zip.setProject(demoProject);
+ expect(zip.getProject()).toBeTruthy();
+
+ expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
+ expect(zip.setOutputPath('output')).toBe(undefined);
+ expect(zip.getOutputPath()).toMatchInlineSnapshot(`"output"`);
+
+ const publishRes = await zip.publish({
+ project: demoProject,
+ });
+
+ expect(publishRes.success).toBeTruthy();
+ expect(publishRes.payload).toBeTruthy();
+ });
+
+ it('should throws Error when project is missing', async () => {
+ const zip = CodeGen.publishers.zip({});
+ expect(zip.publish()).rejects.toBeTruthy();
+ });
+});
diff --git a/modules/code-generator/tests/public/solutions/rax-app.test.ts b/modules/code-generator/tests/public/solutions/rax-app.test.ts
new file mode 100644
index 0000000000..1912b7b5d4
--- /dev/null
+++ b/modules/code-generator/tests/public/solutions/rax-app.test.ts
@@ -0,0 +1,64 @@
+import 'jest';
+import fs from 'fs';
+import glob from 'glob';
+import JSON from 'json5';
+import path from 'path';
+
+import {
+ getSubDirectoriesSync,
+ removeActualDirRecursiveSync,
+ runPrettierSync,
+ createDiskPublisher,
+} from '../../helpers/solutionHelper';
+
+import CodeGenerator from '../../../src';
+
+import type { ProjectSchema } from '@alilc/lowcode-types';
+
+jest.setTimeout(15 * 1000);
+
+const TEST_CASES_DIR = path.join(__dirname, '../../../test-cases/rax-app');
+const SHOULD_UPDATE_EXPECTED = process.env.UPDATE_EXPECTED === 'true';
+
+getSubDirectoriesSync(TEST_CASES_DIR).forEach(defineTest);
+
+function defineTest(caseDirName: string) {
+ test(`rax-app/${caseDirName} should works`, async () => {
+ try {
+ const caseFullDir = path.join(TEST_CASES_DIR, caseDirName);
+ const schema = JSON.parse(fs.readFileSync(path.join(caseFullDir, 'schema.json5'), 'utf-8'));
+ const actualDir = path.join(caseFullDir, SHOULD_UPDATE_EXPECTED ? 'expected' : 'actual');
+
+ removeActualDirRecursiveSync(actualDir, caseFullDir);
+
+ await exportProject(schema, actualDir, 'demo-project');
+
+ const actualFiles = glob.sync('**/*.{js,jsx,json,ts,tsx,less,css,scss,sass}', {
+ cwd: actualDir,
+ });
+
+ expect(actualFiles.length > 0).toBeTruthy();
+
+ runPrettierSync(actualFiles, actualDir);
+
+ if (!SHOULD_UPDATE_EXPECTED) {
+ expect(caseFullDir).toBeSameFileContents();
+ }
+ } catch (e) {
+ throw e; // just for debugger
+ }
+ });
+}
+
+async function exportProject(schemaJson: ProjectSchema, targetPath: string, projectName: string) {
+ const raxAppBuilder = CodeGenerator.solutions.rax();
+ const result = await raxAppBuilder.generateProject(schemaJson);
+
+ const publisher = createDiskPublisher();
+ await publisher.publish({
+ project: result,
+ outputPath: targetPath,
+ projectSlug: projectName,
+ createProjectFolder: true,
+ });
+}
diff --git a/modules/code-generator/tests/public/solutions/react-app.test.ts b/modules/code-generator/tests/public/solutions/react-app.test.ts
new file mode 100644
index 0000000000..bb9dc0ae5e
--- /dev/null
+++ b/modules/code-generator/tests/public/solutions/react-app.test.ts
@@ -0,0 +1,63 @@
+import 'jest';
+import fs from 'fs';
+import glob from 'glob';
+import JSON from 'json5';
+import path from 'path';
+
+import {
+ getSubDirectoriesSync,
+ removeActualDirRecursiveSync,
+ createDiskPublisher,
+} from '../../helpers/solutionHelper';
+
+import CodeGenerator from '../../../src';
+
+import type { ProjectSchema } from '@alilc/lowcode-types';
+
+jest.setTimeout(15 * 1000);
+
+const TEST_CASES_DIR = path.join(__dirname, '../../../test-cases/react-app');
+const SHOULD_UPDATE_EXPECTED = process.env.UPDATE_EXPECTED === 'true';
+
+getSubDirectoriesSync(TEST_CASES_DIR).forEach(defineTest);
+
+function defineTest(caseDirName: string) {
+ test(`react-app/${caseDirName} should works`, async () => {
+ try {
+ const caseFullDir = path.join(TEST_CASES_DIR, caseDirName);
+ const schema = JSON.parse(fs.readFileSync(path.join(caseFullDir, 'schema.json5'), 'utf-8'));
+ const actualDir = path.join(caseFullDir, SHOULD_UPDATE_EXPECTED ? 'expected' : 'actual');
+
+ removeActualDirRecursiveSync(actualDir, caseFullDir);
+
+ await exportProject(schema, actualDir, 'demo-project');
+
+ const actualFiles = glob.sync('**/*.{js,jsx,json,ts,tsx,less,css,scss,sass}', {
+ cwd: actualDir,
+ });
+
+ expect(actualFiles.length > 0).toBeTruthy();
+
+ // runPrettierSync(actualFiles, actualDir);
+
+ if (!SHOULD_UPDATE_EXPECTED) {
+ expect(caseFullDir).toBeSameFileContents();
+ }
+ } catch (e) {
+ throw e; // just for debugger
+ }
+ });
+}
+
+async function exportProject(schemaJson: ProjectSchema, targetPath: string, projectName: string) {
+ const reactAppBuilder = CodeGenerator.solutions.icejs();
+ const result = await reactAppBuilder.generateProject(schemaJson);
+
+ const publisher = createDiskPublisher();
+ await publisher.publish({
+ project: result,
+ outputPath: targetPath,
+ projectSlug: projectName,
+ createProjectFolder: true,
+ });
+}
diff --git a/modules/code-generator/tests/utils/compositeType.test.ts b/modules/code-generator/tests/utils/compositeType.test.ts
new file mode 100644
index 0000000000..64ecfab9d3
--- /dev/null
+++ b/modules/code-generator/tests/utils/compositeType.test.ts
@@ -0,0 +1,18 @@
+import { generateCompositeType } from '../../src/utils/compositeType';
+import { Scope } from '../../src/utils/Scope';
+
+test('single line string', () => {
+ expect(generateCompositeType('ab c', Scope.createRootScope())).toEqual('"ab c"');
+});
+
+test('multi line string', () => {
+ expect(generateCompositeType('a\nb\nc', Scope.createRootScope())).toEqual('"a\\nb\\nc"');
+});
+
+test('string with single quote', () => {
+ expect(generateCompositeType("a'bc", Scope.createRootScope())).toEqual('"a\'bc"');
+});
+
+test('string with double quote', () => {
+ expect(generateCompositeType('a"bc', Scope.createRootScope())).toEqual('"a\\"bc"');
+});
diff --git a/modules/code-generator/tests/utils/errors.test.ts b/modules/code-generator/tests/utils/errors.test.ts
new file mode 100644
index 0000000000..c66fb58eb0
--- /dev/null
+++ b/modules/code-generator/tests/utils/errors.test.ts
@@ -0,0 +1,27 @@
+import { getErrorMessage } from '../../src/utils/errors';
+
+describe('getErrorMessage', () => {
+ it('can deal normal error', () => {
+ expect(getErrorMessage(new Error('test'))).toBe('test');
+ });
+
+ it('can deal error object with message field', () => {
+ expect(getErrorMessage({ message: 'test' })).toBe('test');
+ });
+
+ it('can deal null', () => {
+ expect(getErrorMessage(null)).toBe(null);
+ });
+
+ it('can deal string', () => {
+ expect(getErrorMessage('test')).toBe('test');
+ });
+
+ it('can deal error object with detail', () => {
+ expect(getErrorMessage({ detail: 'test' })).toBe('test');
+ });
+
+ it('can deal error object with errorMessage', () => {
+ expect(getErrorMessage({ errorMessage: 'test' })).toBe('test');
+ });
+});
diff --git a/modules/code-generator/tests/utils/expressionParser/parseExpressionConvertThis2Context.test.ts b/modules/code-generator/tests/utils/expressionParser/parseExpressionConvertThis2Context.test.ts
new file mode 100644
index 0000000000..7422eb645e
--- /dev/null
+++ b/modules/code-generator/tests/utils/expressionParser/parseExpressionConvertThis2Context.test.ts
@@ -0,0 +1,95 @@
+import { parseExpressionConvertThis2Context } from '../../../src/utils/expressionParser';
+
+// return providedTitle || `after convert this to context "${input[0]}" should be "${expected}"`.replace(/\n|\s+/g, ' ');
+
+const marcoFactory = () => {
+ const cases: any[] = [];
+
+ const marco = (input: any[], expected: string) => {
+ const tmpInput = [...input];
+ while (tmpInput.length < 3) {
+ tmpInput.push(undefined);
+ }
+ cases.push([...tmpInput, expected]);
+ };
+
+ const start = () => {
+ test.each(cases)(
+ `after convert this to context "${1}" should be "${4}"`,
+ (a, b, c, expected) => {
+ expect(parseExpressionConvertThis2Context(a, b, c)).toEqual(expected);
+ },
+ );
+ };
+
+ return { marco, start };
+};
+
+const { marco: testMarco, start: startMarco } = marcoFactory();
+
+testMarco(['this.hello', '__$$context', []], '__$$context.hello');
+testMarco(['this.utils.recordEvent', '__$$context', []], '__$$context.utils.recordEvent');
+
+testMarco(
+ ['this.utils.recordEvent.bind(this)', '__$$context', []],
+ '__$$context.utils.recordEvent.bind(__$$context)',
+);
+
+testMarco(['this.item', '__$$context', ['item']], 'item');
+
+testMarco(['this.user.name', '__$$context', ['user']], 'user.name');
+
+testMarco(['function (){}', '__$$context', []], 'function () {}');
+
+testMarco(
+ ['function (){ this.utils.Toast.show("Hello world!") }', '__$$context'],
+ 'function () {\n __$$context.utils.Toast.show("Hello world!");\n}',
+);
+
+// 变量能被替换掉
+testMarco(
+ ['function (){ this.utils.recordEvent("click", this.item) }', '__$$context', ['item']],
+ 'function () {\n __$$context.utils.recordEvent("click", item);\n}',
+);
+
+// 只替换顶层的,不替换内层
+testMarco(
+ [
+ 'function (){ return function (){ this.utils.recordEvent("click", this.item) } }',
+ '__$$context',
+ ['item'],
+ ],
+ 'function () {\n return function () {\n this.utils.recordEvent("click", item);\n };\n}',
+);
+
+// 只替换顶层的,不替换内层
+testMarco(
+ [
+ 'function onClick(){ return function (){ this.utils.recordEvent("click", this.item) } }',
+ '__$$context',
+ ['item'],
+ ],
+ 'function onClick() {\n return function () {\n this.utils.recordEvent("click", item);\n };\n}',
+);
+
+// 只替换顶层的,不替换内层
+testMarco(
+ [
+ '() => { return function (){ this.utils.recordEvent("click", this.item) } }',
+ '__$$context',
+ ['item'],
+ ],
+ '() => {\n return function () {\n this.utils.recordEvent("click", item);\n };\n}',
+);
+
+// 但是若内层有用箭头函数定义的则还是要替换下
+testMarco(
+ [
+ '() => { return () => { this.utils.recordEvent("click", this.item) } }',
+ '__$$context',
+ ['item'],
+ ],
+ '() => {\n return () => {\n __$$context.utils.recordEvent("click", item);\n };\n}',
+);
+
+startMarco();
diff --git a/modules/code-generator/tests/utils/expressionParser/parseExpressionGetGlobalVariables.test.ts b/modules/code-generator/tests/utils/expressionParser/parseExpressionGetGlobalVariables.test.ts
new file mode 100644
index 0000000000..1c98054b81
--- /dev/null
+++ b/modules/code-generator/tests/utils/expressionParser/parseExpressionGetGlobalVariables.test.ts
@@ -0,0 +1,134 @@
+import {
+ parseExpressionGetGlobalVariables,
+ // ParseExpressionGetGlobalVariablesOptions,
+} from '../../../src/utils/expressionParser';
+
+const marcoFactory = () => {
+ const cases: any[] = [];
+
+ const marco = (input: any[], expected: string[]) => {
+ const tmpInput = [...input];
+ while (tmpInput.length < 2) {
+ tmpInput.push(undefined);
+ }
+ cases.push([...tmpInput, expected]);
+ };
+
+ const start = () => {
+ test.each(cases)(`global variables of "${1}" should be "${3}"`, (a, b, expected) => {
+ expect(parseExpressionGetGlobalVariables(a, b)).toEqual(expected);
+ });
+ };
+
+ return { marco, start };
+};
+
+const { marco: testMarco, start: startMarco } = marcoFactory();
+
+testMarco(['function (){ }', {}], []);
+testMarco(['function (){ __$$context.utils.Toast.show("Hello world!") }', {}], ['__$$context']);
+
+testMarco(
+ ['function (){ __$$context.utils.formatPrice(item.price1, "元") }', {}],
+ ['__$$context', 'item'],
+);
+
+testMarco(
+ [
+ 'function (){ __$$context.utils.formatPrice(item2, "元"); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['item2'],
+);
+
+testMarco(
+ [
+ 'function (){ __$$context.utils.log(item3, [item4, item5]); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['item3', 'item4', 'item5'],
+);
+
+testMarco(
+ [
+ 'function (){ item3[item4]("Hello"); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['item3', 'item4'],
+);
+
+testMarco(
+ ['function (){ item3("Hello"); }', { filter: (varName: string) => !/^__\$\$/.test(varName) }],
+ ['item3'],
+);
+
+testMarco(
+ [
+ 'function foo(){ foo[item3]("Hello"); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['item3'],
+);
+
+// isAssignmentExpression/right
+testMarco(
+ [
+ 'function (){ let foo; foo = item3; foo(); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['item3'],
+);
+
+// isAssignmentExpression/left
+testMarco(
+ ['function (){ foo = item3; foo(); }', { filter: (varName: string) => !/^__\$\$/.test(varName) }],
+ ['foo', 'item3'],
+);
+
+// isVariableDeclarator
+testMarco(
+ [
+ 'function (){ const foo = item3; foo(); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['item3'],
+);
+
+// isVariableDeclarator
+testMarco(
+ [
+ 'function (){ let foo = item3; foo(); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['item3'],
+);
+
+// isVariableDeclarator
+testMarco(
+ [
+ 'function (){ var foo = item3; foo(); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['item3'],
+);
+
+// isTemplateLiteral
+testMarco(
+ [
+ 'function (){ console.log(`Hello ${item3};`); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['console', 'item3'],
+);
+
+// isBinaryExpression
+testMarco(
+ [
+ 'function (){ console.log(item2 | item3); }',
+ { filter: (varName: string) => !/^__\$\$/.test(varName) },
+ ],
+ ['console', 'item2', 'item3'],
+);
+
+// TODO: 补充更多类型的测试用例
+startMarco();
diff --git a/modules/code-generator/tests/utils/flattenResult.test.ts b/modules/code-generator/tests/utils/flattenResult.test.ts
new file mode 100644
index 0000000000..0b4357476b
--- /dev/null
+++ b/modules/code-generator/tests/utils/flattenResult.test.ts
@@ -0,0 +1,60 @@
+import { flattenResult } from '../../src/utils/resultHelper';
+
+test('utils/flattenResult', () => {
+ expect(
+ flattenResult({
+ name: 'demo',
+ dirs: [
+ {
+ name: 'src',
+ dirs: [
+ {
+ name: 'components',
+ dirs: [
+ {
+ name: 'Hello',
+ dirs: [],
+ files: [
+ {
+ name: 'index',
+ ext: 'js',
+ content: 'export default () => Hello
',
+ },
+ ],
+ },
+ ],
+ files: [
+ {
+ name: 'index',
+ ext: 'js',
+ content: 'export * from "./Hello";',
+ },
+ ],
+ },
+ ],
+ files: [{ name: 'index', ext: 'js', content: 'console.log("Hello")' }],
+ },
+ ],
+ files: [{ name: '.eslintrc', ext: '', content: '{}' }],
+ }),
+ ).toMatchInlineSnapshot(`
+ Array [
+ Object {
+ "content": "{}",
+ "pathName": ".eslintrc",
+ },
+ Object {
+ "content": "console.log(\\"Hello\\")",
+ "pathName": "src/index.js",
+ },
+ Object {
+ "content": "export * from \\"./Hello\\";",
+ "pathName": "src/components/index.js",
+ },
+ Object {
+ "content": "export default () => Hello
",
+ "pathName": "src/components/Hello/index.js",
+ },
+ ]
+ `);
+});
diff --git a/modules/code-generator/tests/utils/schema/data/schema-with-slot.json b/modules/code-generator/tests/utils/schema/data/schema-with-slot.json
new file mode 100644
index 0000000000..07bd0db699
--- /dev/null
+++ b/modules/code-generator/tests/utils/schema/data/schema-with-slot.json
@@ -0,0 +1,1457 @@
+{
+ "version": "1.0.0",
+ "componentsMap": [
+ {
+ "devMode": "lowcode",
+ "componentName": "Slot"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Button",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Button"
+ },
+ {
+ "package": "@alife/mc-assets-1935",
+ "version": "0.1.43",
+ "exportName": "AliAutoDiv",
+ "main": "build/lowcode/index.js",
+ "destructuring": true,
+ "subName": "default",
+ "componentName": "AliAutoDivDefault"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Typography",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "subName": "Text",
+ "componentName": "Typography.Text"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Typography",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "subName": "Link",
+ "componentName": "Typography.Link"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Modal",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Modal"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Select",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Select"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Form",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "subName": "Item",
+ "componentName": "Form.Item"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Input",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Input"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Form",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Form"
+ },
+ {
+ "package": "@alife/container",
+ "version": "0.3.7",
+ "exportName": "P",
+ "main": "lib/index.js",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "NextP"
+ },
+ {
+ "package": "@alife/container",
+ "version": "0.3.7",
+ "exportName": "Block",
+ "main": "lib/index.js",
+ "destructuring": true,
+ "subName": "Cell",
+ "componentName": "NextBlockCell"
+ },
+ {
+ "package": "@alife/container",
+ "version": "0.3.7",
+ "exportName": "Block",
+ "main": "lib/index.js",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "NextBlock"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Tooltip",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Tooltip"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Icon",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Icon"
+ },
+ {
+ "package": "@alife/mc-assets-1935",
+ "version": "0.1.43",
+ "exportName": "AliAutoSearchTable",
+ "main": "build/lowcode/index.js",
+ "destructuring": true,
+ "subName": "default",
+ "componentName": "AliAutoSearchTableDefault"
+ },
+ {
+ "package": "@alilc/antd-lowcode-materials",
+ "version": "0.11.0",
+ "exportName": "Empty",
+ "main": "dist/antd-lowcode.esm.js",
+ "destructuring": true,
+ "componentName": "Empty"
+ },
+ {
+ "package": "@alife/container",
+ "version": "0.3.7",
+ "exportName": "Page",
+ "main": "lib/index.js",
+ "destructuring": true,
+ "subName": "",
+ "componentName": "NextPage"
+ },
+ {
+ "devMode": "lowcode",
+ "componentName": "Page"
+ }
+ ],
+ "componentsTree": [
+ {
+ "componentName": "Page",
+ "id": "node_dockcviv8fo1",
+ "props": {
+ "ref": "outterView",
+ "style": {
+ "height": "100%"
+ }
+ },
+ "fileName": "test",
+ "dataSource": {
+ "list": []
+ },
+ "css": "body {\n font-size: 12px;\n}\n\n.botton {\n width: 100px;\n color: #ff00ff\n}",
+ "lifeCycles": {
+ "constructor": {
+ "type": "JSFunction",
+ "value": "function() {\n this.__jp__init();\n this.statusDesc = {\n 0: '失败',\n 1: '成功',\n 2: '构建中',\n 3: '构建超时',\n };\n this.pageParams = {};\n this.searchParams = {};\n this.userTimeout = null;\n this.currentUser = null;\n this.notFoundContent = null;\n this.projectTimeout = null;\n this.currentProject = null;\n }"
+ },
+ "componentDidMount": {
+ "type": "JSFunction",
+ "value": "function() {\n this.$ds.resolve('PROJECTS');\n if (this.userTimeout) {\n clearTimeout(this.userTimeout);\n this.userTimeout = null;\n }\n if (this.projectTimeout) {\n clearTimeout(this.projectTimeout);\n this.projectTimeout = null;\n }\n }"
+ },
+ "componentDidUpdate": {
+ "type": "JSFunction",
+ "value": "function(prevProps, prevState, snapshot) {}"
+ },
+ "componentWillUnmount": {
+ "type": "JSFunction",
+ "value": "function() {}"
+ }
+ },
+ "methods": {
+ "__jp__init": {
+ "type": "JSFunction",
+ "value": "function() {\n this.__jp__initEnv && this.__jp__initEnv();\n this.__jp__initConfig && this.__jp__initConfig();\n this.__jp__initDataSource && this.__jp__initDataSource();\n this.__jp__initRouter && this.__jp__initRouter();\n this.__jp__initUtils && this.__jp__initUtils();\n}"
+ },
+ "__jp__initRouter": {
+ "type": "JSFunction",
+ "value": "function() {\n if (window.arsenal) {\n this.$router = new window.jianpin.ArsenalRouter({\n app: this.props.microApp,\n });\n } else {\n this.$router = new window.jianpin.ArsenalRouter();\n }\n}"
+ },
+ "__jp__initDataSource": {
+ "type": "JSFunction",
+ "value": "function() {\n this.$apis = {\n PKG_LIST: {\n name: '打包列表',\n code: 'PKG_LIST',\n url: 'https://auto-nvwa.amap.com/ws/nvwa/cpp5x/packages/',\n method: 'GET',\n dataHandler: res => res.data,\n },\n PROJECTS: {\n name: '项目名称/渠道号',\n code: 'PROJECTS',\n url:\n 'http://auto-nvwa-staging.alibaba.com/ws/nvwa/cpp/select_projects/',\n method: 'GET',\n state: 'projects',\n params: {\n size: 5000,\n },\n dataHandler: res => {\n return res.data.data.result.map(d => {\n const { id, channelId, project_name } = d;\n return {\n label: `${project_name} / ${channelId}`,\n value: id,\n };\n });\n },\n },\n RELOAD: {\n name: '重新执行',\n code: 'RELOAD',\n url: 'https://auto-nvwa.amap.com/cpp/configbuild/rebuild/',\n method: 'GET',\n },\n BUILD_RESULT: {\n name: '打包结果',\n code: 'BUILD_RESULT',\n url:\n 'https://auto-nvwa.amap.com/cpp/api/configbuild/get_build_result/',\n method: 'GET',\n state: 'results',\n dataHandler: res => {\n return res.data.result;\n },\n },\n BUC_USER: {\n name: '搜索用户',\n code: 'BUC_USER',\n url: 'https://auto-nvwa.amap.com/ws/nvwa/sso_users/',\n method: 'GET',\n dataHandler: res => res.data.items,\n },\n};\n this.$ds = new window.jianpin.DataSource(this, {});\n}"
+ },
+ "__jp__initEnv": {
+ "type": "JSFunction",
+ "value": "function() {\n const hostname = window.location.hostname;\n let env = 'prod';\n\n if (window.jianpin && window.jianpin.env === 'dev') {\n env = 'dev';\n } else if (window.arsenalConfig) {\n env = window.arsenalConfig.env;\n }\n\n const urlSearchParams = new URLSearchParams(window.location.search);\n const searchParams = {};\n for (const [key, value] of urlSearchParams) {\n searchParams[key] = value;\n }\n this.$env = env;\n this.$searchParams = searchParams;\n\n if (window.arsenal && window.arsenal.store) {\n this.$user = window.arsenal.store.getState('user');\n this.$store = window.arsenal.store;\n window.arsenal.store.subscribe('user', () => {\n this.$user = window.arsenal.store.getState('user');\n });\n } else {\n this.$store = {\n subscribe: () => {},\n getState: () => {},\n };\n this.$user = this.__jp__mockUser || {};\n }\n}"
+ },
+ "__jp__initConfig": {
+ "type": "JSFunction",
+ "value": "function() {\n const __config = {\n \"default\": {},\n \"dev\": {},\n \"daily\": {},\n \"pre\": {},\n \"prod\": {}\n};\n\n this.$config = window.jianpin.utils.extend(true, {}, __config.default, __config[this.$env]);\n}"
+ },
+ "__jp__initUtils": {
+ "type": "JSFunction",
+ "value": "function() {\n this.$utils = {\n message: window.jianpin.utils.message,\n axios: window.jianpin.utils.axios,\n moment: window.jianpin.utils.moment,\n };\n}"
+ },
+ "setSearchItem": {
+ "type": "JSFunction",
+ "value": "function(item) {\n const searchState = this.state.searchValues;\n const reducer = (pre, key) => {\n let value = searchState[key];\n if (item.hasOwnProperty(key)) {\n value = item[key];\n }\n return {\n ...pre,\n [key]: value || null,\n };\n };\n const searchValues = Object.keys(searchState).reduce(reducer, {});\n this.setState({\n searchValues,\n });\n }"
+ },
+ "fetchProject": {
+ "type": "JSFunction",
+ "value": "function(value, callback) {\n if (this.projectTimeout) {\n clearTimeout(this.projectTimeout);\n this.projectTimeout = null;\n }\n this.currentProject = value;\n\n const fake = () => {\n this.$ds\n .resolve('PROJECTS', {\n params: { search_param: value },\n })\n .then(res => {\n if (this.currentProject !== value) {\n return;\n }\n callback(res || []);\n });\n };\n this.projectTimeout = setTimeout(fake, 300);\n }"
+ },
+ "handleProjectSearch": {
+ "type": "JSFunction",
+ "value": "function(value) {\n if (value) {\n this.fetchProject(value, projects => {\n this.setState({ projects });\n });\n } else {\n this.setState({ projects: [] });\n }\n }"
+ },
+ "handleProjectChange": {
+ "type": "JSFunction",
+ "value": "function(id) {\n this.setSearchItem({\n channel_id: id,\n });\n }"
+ },
+ "fetchUser": {
+ "type": "JSFunction",
+ "value": "function(value, callback) {\n if (this.userTimeout) {\n clearTimeout(this.userTimeout);\n this.userTimeout = null;\n }\n this.currentUser = value;\n\n const fake = () => {\n this.$ds\n .resolve('BUC_USER', {\n params: { q: value },\n })\n .then(res => {\n if (this.currentUser !== value) {\n return;\n }\n const data = res.slice(0, 8).map(r => ({\n label: `${r.id} / ${r.label}`,\n value: r.id,\n }));\n callback(data);\n });\n };\n this.userTimeout = setTimeout(fake, 300);\n }"
+ },
+ "handleUserSearch": {
+ "type": "JSFunction",
+ "value": "function(value) {\n if (value) {\n this.fetchUser(value, userOptions => {\n this.setState({ userOptions });\n });\n } else {\n this.setState({ userOptions: [] });\n }\n }"
+ },
+ "handleUserChange": {
+ "type": "JSFunction",
+ "value": "function(user) {\n console.log('debug user', user);\n this.setSearchItem({\n user_id: user,\n });\n }"
+ },
+ "fetchPkgs": {
+ "type": "JSFunction",
+ "value": "function() {\n const { pageIndex, pageSize } = this.pageParams;\n this.$ds\n .resolve('PKG_LIST', {\n params: {\n ...this.searchParams,\n page: pageIndex,\n size: pageSize,\n },\n })\n .then(res => {\n const { result, page } = res.data;\n const { count } = page;\n this.setState({\n isSearch: true,\n pkgs: result,\n total: count,\n });\n });\n }"
+ },
+ "onPageChange": {
+ "type": "JSFunction",
+ "value": "function(pageIndex, pageSize) {\n this.pageParams = {\n pageIndex,\n pageSize,\n };\n this.fetchPkgs();\n }"
+ },
+ "renderTime": {
+ "type": "JSFunction",
+ "value": "function(time) {\n return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\n }"
+ },
+ "renderUserName": {
+ "type": "JSFunction",
+ "value": "function(user) {\n return user.user_name;\n }"
+ },
+ "reload": {
+ "type": "JSFunction",
+ "value": "function(id) {\n if (!confirm('确实要重新执行?')) {\n return;\n }\n this.$ds\n .resolve('RELOAD', {\n params: {\n build_id: id,\n },\n })\n .then(res => {\n const { code, message } = res.data.status;\n if (code == 0) {\n this.$utils.message.error(message);\n } else {\n const { pageIndex, pageSize } = this.pageParams;\n this.onPageChange(pageIndex, pageSize);\n }\n })\n .catch(err => {\n this.$utils.message.error(err.message);\n });\n }"
+ },
+ "handleResult": {
+ "type": "JSFunction",
+ "value": "function(e) {\n // e.persist();\n e.preventDefault();\n e.stopPropagation();\n let href;\n let tagName;\n let target = e.target;\n do {\n tagName = target.tagName.toUpperCase();\n href = target.getAttribute('href');\n target = target.parentNode;\n } while (!href && tagName !== 'TD');\n if (!href) {\n return;\n }\n\n this.$ds\n .resolve('BUILD_RESULT', {\n params: {\n build_id: href,\n },\n })\n .then(res => {\n this.setState({\n resultVisible: true,\n });\n })\n .catch(err => {\n this.$utils.message.error(`打包结果获取失败: ${err.message}`);\n });\n }"
+ },
+ "handleDetail": {
+ "type": "JSFunction",
+ "value": "function() {\n // 跳转详情页面 TODO\n }"
+ },
+ "onResultCancel": {
+ "type": "JSFunction",
+ "value": "function() {\n this.setState({\n resultVisible: false,\n });\n }"
+ },
+ "formatResult": {
+ "type": "JSFunction",
+ "value": "function(item) {\n if (!item) {\n return '暂无结果';\n }\n const { channel, plat, version, status } = item;\n return [channel, plat, version, status].join('-');\n }"
+ },
+ "handleDownload": {
+ "type": "JSFunction",
+ "value": "function() {\n const { results } = this.state;\n if (!results || results.length < 1) {\n return;\n }\n let link = document.createElement('a');\n link.style.display = 'none';\n document.body.appendChild(link);\n results.forEach(r => {\n link.href = r.download_link;\n link.click();\n });\n document.body.removeChild(link);\n link = null;\n }"
+ },
+ "onFinish": {
+ "type": "JSFunction",
+ "value": "function(f) {\n const params = Object.keys(f).reduce((pre, key) => {\n const value = f[key];\n if (value === undefined) {\n return pre;\n }\n return {\n ...pre,\n [key]: value,\n };\n }, {});\n this.searchParams = params;\n this.fetchPkgs();\n }"
+ }
+ },
+ "state": {
+ "pkgs": [],
+ "total": 0,
+ "isSearch": false,
+ "projects": [],
+ "results": [],
+ "resultVisible": false,
+ "userOptions": [],
+ "searchValues": {
+ "user_id": "",
+ "channel_id": ""
+ }
+ },
+ "children": [
+ {
+ "componentName": "Modal",
+ "id": "node_ocksh9yppxb",
+ "props": {
+ "title": "查看结果",
+ "visible": {
+ "type": "JSExpression",
+ "value": "this.state.resultVisible"
+ },
+ "footer": {
+ "type": "JSSlot",
+ "value": [
+ {
+ "componentName": "Button",
+ "id": "node_ocksh9yppxf",
+ "props": {
+ "type": "primary",
+ "children": "确定",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "onResultCancel"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onCancel",
+ "relatedEventName": "onResultCancel"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onCancel",
+ "disabled": true
+ },
+ {
+ "name": "onOk",
+ "disabled": false
+ }
+ ]
+ },
+ "onCancel": {
+ "type": "JSFunction",
+ "value": "function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "width": "720px",
+ "centered": true,
+ "closable": true,
+ "keyboard": true,
+ "mask": true,
+ "maskClosable": true
+ },
+ "hidden": true,
+ "children": [
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockshazuxa4",
+ "props": {
+ "style": {
+ "width": "100%"
+ }
+ },
+ "children": [
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockshazuxai",
+ "props": {
+ "style": {
+ "width": "100%",
+ "textAlign": "left",
+ "marginBottom": "16px"
+ }
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.results && this.state.results.length > 0"
+ },
+ "children": [
+ {
+ "componentName": "Button",
+ "id": "node_ockshazuxah",
+ "props": {
+ "type": "primary",
+ "children": "下载全部",
+ "size": "small",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "handleDownload"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockt2muyfi4",
+ "props": {
+ "style": {
+ "width": "100%",
+ "marginTop": "10px"
+ }
+ },
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.state.results"
+ },
+ "children": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ockshazuxa5",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.formatResult(this.item)"
+ }
+ }
+ },
+ {
+ "componentName": "Typography.Link",
+ "id": "node_ockshazuxa6",
+ "props": {
+ "href": {
+ "type": "JSExpression",
+ "value": "this.item.download_link"
+ },
+ "target": "_blank",
+ "children": " - 点击下载"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.item.download_link"
+ }
+ },
+ {
+ "componentName": "Typography.Link",
+ "id": "node_ockshazuxa7",
+ "props": {
+ "href": {
+ "type": "JSExpression",
+ "value": "this.item.release_notes"
+ },
+ "target": "_blank",
+ "children": " - 跳转发布节点"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.item.release_notes"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "NextPage",
+ "id": "node_ocko19zplh1",
+ "props": {
+ "columns": 12,
+ "headerDivider": true,
+ "placeholderStyle": {
+ "gridRowEnd": "span 1",
+ "gridColumnEnd": "span 12"
+ },
+ "placeholder": "页面主体内容:拖拽Block布局组件到这里",
+ "header": {
+ "type": "JSSlot",
+ "title": "header"
+ },
+ "headerProps": {
+ "background": "surface",
+ "style": {
+ "padding": ""
+ }
+ },
+ "footer": {
+ "type": "JSSlot",
+ "title": "footer"
+ },
+ "minHeight": "100vh",
+ "contentProps": {
+ "noPadding": false,
+ "background": "transparent"
+ }
+ },
+ "title": "页面",
+ "children": [
+ {
+ "componentName": "NextBlock",
+ "id": "node_ockt3t4q8565",
+ "props": {
+ "childTotalColumns": 12
+ },
+ "title": "区块",
+ "children": [
+ {
+ "componentName": "NextBlockCell",
+ "id": "node_ockt3t4q8566",
+ "props": {
+ "isAutoContainer": true,
+ "colSpan": 12,
+ "rowSpan": 1
+ },
+ "title": "子区块",
+ "children": [
+ {
+ "componentName": "NextP",
+ "id": "node_ockt3t4q8567",
+ "props": {
+ "wrap": false,
+ "type": "body2",
+ "verAlign": "middle",
+ "textSpacing": true,
+ "align": "left",
+ "flex": true
+ },
+ "title": "段落",
+ "children": [
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockt3t4q8568",
+ "props": {
+ "style": {
+ "width": "100%",
+ "display": "flex"
+ }
+ },
+ "children": [
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockt3t4q857a",
+ "props": {
+ "style": {
+ "flex": "1"
+ }
+ },
+ "children": [
+ {
+ "componentName": "Form",
+ "id": "node_ocks8dtt1mt",
+ "props": {
+ "labelCol": {
+ "span": 10
+ },
+ "wrapperCol": {
+ "span": 14
+ },
+ "onFinish": {
+ "type": "JSFunction",
+ "value": "function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "name": "basic",
+ "layout": "inline",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onFinish",
+ "relatedEventName": "onFinish"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onFinish",
+ "disabled": true
+ },
+ {
+ "name": "onFinishFailed",
+ "disabled": false
+ },
+ {
+ "name": "onFieldsChange",
+ "disabled": false
+ },
+ {
+ "name": "onValuesChange",
+ "disabled": false
+ }
+ ]
+ },
+ "colon": true,
+ "labelAlign": "right",
+ "preserve": true,
+ "scrollToFirstError": true,
+ "size": "middle",
+ "values": {
+ "type": "JSExpression",
+ "value": "this.state.searchValues"
+ }
+ },
+ "children": [
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1mz",
+ "props": {
+ "label": "项目名称/渠道号",
+ "name": "channel_id",
+ "labelAlign": "right",
+ "colon": true
+ },
+ "children": [
+ {
+ "componentName": "Select",
+ "id": "node_ocksfuhwhsd",
+ "props": {
+ "style": {
+ "width": "320px"
+ },
+ "options": {
+ "type": "JSExpression",
+ "value": "this.state.projects"
+ },
+ "showArrow": false,
+ "tokenSeparators": [],
+ "showSearch": true,
+ "defaultActiveFirstOption": true,
+ "size": "middle",
+ "bordered": true,
+ "filterOption": true,
+ "optionFilterProp": "label",
+ "allowClear": true,
+ "placeholder": "请输入项目名称/渠道号",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onChange",
+ "relatedEventName": "handleProjectChange"
+ },
+ {
+ "type": "componentEvent",
+ "name": "onSearch",
+ "relatedEventName": "handleProjectSearch"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onBlur",
+ "disabled": false
+ },
+ {
+ "name": "onChange",
+ "disabled": true
+ },
+ {
+ "name": "onDeselect",
+ "disabled": false
+ },
+ {
+ "name": "onFocus",
+ "disabled": false
+ },
+ {
+ "name": "onInputKeyDown",
+ "disabled": false
+ },
+ {
+ "name": "onMouseEnter",
+ "disabled": false
+ },
+ {
+ "name": "onMouseLeave",
+ "disabled": false
+ },
+ {
+ "name": "onPopupScroll",
+ "disabled": false
+ },
+ {
+ "name": "onSearch",
+ "disabled": true
+ },
+ {
+ "name": "onSelect",
+ "disabled": false
+ },
+ {
+ "name": "onDropdownVisibleChange",
+ "disabled": false
+ }
+ ]
+ },
+ "onChange": {
+ "type": "JSFunction",
+ "value": "function(){this.handleProjectChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "onSearch": {
+ "type": "JSFunction",
+ "value": "function(){this.handleProjectSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1m12",
+ "props": {
+ "label": "版本号",
+ "name": "buildId"
+ },
+ "children": [
+ {
+ "componentName": "Input",
+ "id": "node_ocksfuhwhs3",
+ "props": {
+ "placeholder": "请输入版本号",
+ "style": {
+ "width": "180px"
+ },
+ "size": "middle",
+ "bordered": true
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1m18",
+ "props": {
+ "label": "构建人",
+ "name": "user_id"
+ },
+ "children": [
+ {
+ "componentName": "Select",
+ "id": "node_ocksfuhwhsi",
+ "props": {
+ "style": {
+ "width": "210px"
+ },
+ "options": {
+ "type": "JSExpression",
+ "value": "this.state.userOptions"
+ },
+ "showSearch": true,
+ "defaultActiveFirstOption": false,
+ "size": "middle",
+ "bordered": true,
+ "filterOption": true,
+ "optionFilterProp": "label",
+ "notFoundContent": {
+ "type": "JSExpression",
+ "value": "this.userNotFoundContent"
+ },
+ "showArrow": false,
+ "placeholder": "请输入构建人",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onChange",
+ "relatedEventName": "handleUserChange"
+ },
+ {
+ "type": "componentEvent",
+ "name": "onSearch",
+ "relatedEventName": "handleUserSearch"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onBlur",
+ "disabled": false
+ },
+ {
+ "name": "onChange",
+ "disabled": true
+ },
+ {
+ "name": "onDeselect",
+ "disabled": false
+ },
+ {
+ "name": "onFocus",
+ "disabled": false
+ },
+ {
+ "name": "onInputKeyDown",
+ "disabled": false
+ },
+ {
+ "name": "onMouseEnter",
+ "disabled": false
+ },
+ {
+ "name": "onMouseLeave",
+ "disabled": false
+ },
+ {
+ "name": "onPopupScroll",
+ "disabled": false
+ },
+ {
+ "name": "onSearch",
+ "disabled": true
+ },
+ {
+ "name": "onSelect",
+ "disabled": false
+ },
+ {
+ "name": "onDropdownVisibleChange",
+ "disabled": false
+ }
+ ]
+ },
+ "onChange": {
+ "type": "JSFunction",
+ "value": "function(){this.handleUserChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "onSearch": {
+ "type": "JSFunction",
+ "value": "function(){this.handleUserSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "allowClear": true
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1m19",
+ "props": {
+ "label": "ID",
+ "name": "id",
+ "labelAlign": "right",
+ "colon": true
+ },
+ "children": [
+ {
+ "componentName": "Input",
+ "id": "node_ocksfuhwhs8",
+ "props": {
+ "placeholder": "请输入ID",
+ "style": {
+ "width": "180px"
+ },
+ "bordered": true,
+ "size": "middle"
+ }
+ }
+ ]
+ },
+ {
+ "componentName": "Form.Item",
+ "id": "node_ocks8dtt1mw",
+ "props": {
+ "wrapperCol": {
+ "offset": 6
+ },
+ "labelAlign": "right",
+ "colon": true,
+ "style": {
+ "flex": "1",
+ "textAlign": "right"
+ }
+ },
+ "children": [
+ {
+ "componentName": "Button",
+ "id": "node_ocks8dtt1mx",
+ "props": {
+ "type": "primary",
+ "children": "查询",
+ "htmlType": "submit",
+ "shape": "default",
+ "size": "middle"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "AliAutoDivDefault",
+ "id": "node_ockt3t4q856b",
+ "props": {
+ "style": {}
+ },
+ "children": [
+ {
+ "componentName": "Button",
+ "id": "node_ockt3t4q85y",
+ "props": {
+ "type": "link",
+ "children": "新增打包",
+ "htmlType": "button",
+ "shape": "default",
+ "size": "middle"
+ },
+ "condition": true
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "NextBlock",
+ "id": "node_ockshc4ifn1b",
+ "props": {
+ "childTotalColumns": 12,
+ "mode": "inset",
+ "layoutmode": "O",
+ "autolayout": "(12|1)"
+ },
+ "title": "区块",
+ "children": [
+ {
+ "componentName": "NextBlockCell",
+ "id": "node_ockshc4ifn1c",
+ "props": {
+ "isAutoContainer": true,
+ "colSpan": 12,
+ "rowSpan": 1
+ },
+ "title": "子区块",
+ "children": [
+ {
+ "componentName": "NextP",
+ "id": "node_ockshc4ifn1d",
+ "props": {
+ "wrap": false,
+ "type": "body2",
+ "verAlign": "middle",
+ "textSpacing": true,
+ "align": "left",
+ "flex": true
+ },
+ "title": "段落",
+ "children": [
+ {
+ "componentName": "AliAutoSearchTableDefault",
+ "id": "node_ocksfuhwhsx",
+ "props": {
+ "rowKey": "key",
+ "dataSource": {
+ "type": "JSExpression",
+ "value": "this.state.pkgs"
+ },
+ "columns": [
+ {
+ "title": "ID",
+ "dataIndex": "id",
+ "key": "name",
+ "width": 80
+ },
+ {
+ "title": "渠道号",
+ "dataIndex": "channels",
+ "key": "age",
+ "width": 142,
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksh2bq0428",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.item"
+ },
+ "style": {
+ "display": "block"
+ }
+ },
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.text.split(',')"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "title": "版本号",
+ "dataIndex": "dic_version",
+ "key": "address",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Tooltip",
+ "id": "node_ocksts0jqgj",
+ "props": {
+ "title": {
+ "type": "JSSlot",
+ "value": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksts0jqgn",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.item. channelId + ' / ' + this.item.version"
+ },
+ "style": {
+ "display": "block",
+ "color": "#FFFFFF"
+ }
+ },
+ "loop": {
+ "type": "JSExpression",
+ "value": "this.text || []"
+ }
+ }
+ ]
+ }
+ },
+ "children": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksts0jqgm",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.text[0].version"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "width": 120
+ },
+ {
+ "title": "构建Job",
+ "dataIndex": "job_name",
+ "width": 180
+ },
+ {
+ "title": "构建类型",
+ "dataIndex": "packaging_type",
+ "width": 94
+ },
+ {
+ "title": "构建状态",
+ "dataIndex": "status",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksh3jkxzw",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.statusDesc[this.text]"
+ }
+ }
+ },
+ {
+ "componentName": "Icon",
+ "id": "node_ocksh3jkxzx",
+ "props": {
+ "type": "SyncOutlined",
+ "size": 16,
+ "spin": true,
+ "style": {
+ "marginLeft": "10px"
+ }
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.text === 2"
+ }
+ }
+ ]
+ },
+ "width": 100
+ },
+ {
+ "title": "构建时间",
+ "dataIndex": "start_time",
+ "render": {
+ "type": "JSFunction",
+ "value": "function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "width": 148
+ },
+ {
+ "title": "构建人",
+ "dataIndex": "user",
+ "render": {
+ "type": "JSFunction",
+ "value": "function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "width": 80
+ },
+ {
+ "title": "Jenkins 链接",
+ "dataIndex": "jenkins_link",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Typography.Link",
+ "id": "node_ocksh64kbx21",
+ "props": {
+ "href": {
+ "type": "JSExpression",
+ "value": "this.text"
+ },
+ "target": "_blank",
+ "children": "查看"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.text"
+ }
+ },
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksh64kbx22",
+ "props": {
+ "children": "暂无"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "!this.text"
+ }
+ }
+ ]
+ },
+ "width": 120
+ },
+ {
+ "title": "测试平台链接",
+ "dataIndex": "is_run_testing",
+ "width": 120,
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Typography.Link",
+ "id": "node_ocksh3jkxz3e",
+ "props": {
+ "href": "http://rivermap.alibaba.net/dashboard/testExecute",
+ "target": "_blank",
+ "children": "查看"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.text"
+ }
+ },
+ {
+ "componentName": "Typography.Text",
+ "id": "node_ocksh3jkxz3f",
+ "props": {
+ "children": "暂无"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "!this.text"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "title": "触发源",
+ "dataIndex": "source",
+ "width": 120
+ },
+ {
+ "title": "详情",
+ "dataIndex": "id",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Button",
+ "id": "node_ocksh8yryw7",
+ "props": {
+ "type": "link",
+ "children": "查看",
+ "size": "small",
+ "style": {
+ "padding": "0px"
+ },
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "handleDetail"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ "width": 80,
+ "fixed": "right"
+ },
+ {
+ "title": "结果",
+ "dataIndex": "id",
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Button",
+ "id": "node_ocksh9v6jw7",
+ "props": {
+ "type": "link",
+ "children": "查看",
+ "size": "small",
+ "style": {
+ "padding": "0px"
+ },
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "handleResult",
+ "paramStr": "this.text"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "ghost": false,
+ "href": {
+ "type": "JSExpression",
+ "value": "this.text"
+ }
+ }
+ }
+ ]
+ },
+ "width": 80,
+ "fixed": "right"
+ },
+ {
+ "title": "重新执行",
+ "dataIndex": "id",
+ "width": 92,
+ "render": {
+ "type": "JSSlot",
+ "params": ["text", "record", "index"],
+ "value": [
+ {
+ "componentName": "Button",
+ "id": "node_ocksh96rad1g",
+ "props": {
+ "type": "text",
+ "children": "",
+ "icon": {
+ "type": "JSSlot",
+ "value": [
+ {
+ "componentName": "Icon",
+ "id": "node_ocksh96rad1j",
+ "props": {
+ "type": "ReloadOutlined",
+ "size": 14,
+ "color": "#0593d3",
+ "style": {
+ "padding": "3px",
+ "border": "1px solid #0593d3",
+ "borderRadius": "14px",
+ "cursor": "pointer",
+ "height": "22px"
+ },
+ "spin": false
+ }
+ }
+ ]
+ },
+ "shape": "circle",
+ "__events": {
+ "eventDataList": [
+ {
+ "type": "componentEvent",
+ "name": "onClick",
+ "relatedEventName": "reload"
+ }
+ ],
+ "eventList": [
+ {
+ "name": "onClick",
+ "disabled": true
+ }
+ ]
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ }
+ }
+ }
+ ]
+ },
+ "fixed": "right"
+ }
+ ],
+ "actions": [],
+ "pagination": {
+ "total": {
+ "type": "JSExpression",
+ "value": "this.state.total"
+ },
+ "defaultPageSize": 10,
+ "onPageChange": {
+ "type": "JSFunction",
+ "value": "function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
+ },
+ "defaultPageIndex": 1
+ },
+ "scrollX": 1200,
+ "isPagination": true
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "componentName": "NextBlock",
+ "id": "node_ocksk6f8fa3b",
+ "props": {
+ "childTotalColumns": 12,
+ "mode": "inset",
+ "layoutmode": "O",
+ "autolayout": "(12|1)"
+ },
+ "title": "区块",
+ "children": [
+ {
+ "componentName": "NextBlockCell",
+ "id": "node_ocksk6f8fa3c",
+ "props": {
+ "isAutoContainer": true,
+ "colSpan": 12,
+ "rowSpan": 1
+ },
+ "title": "子区块",
+ "children": [
+ {
+ "componentName": "NextP",
+ "id": "node_ocksk6f8fa3d",
+ "props": {
+ "wrap": false,
+ "type": "body2",
+ "verAlign": "middle",
+ "textSpacing": true,
+ "align": "left",
+ "flex": true
+ },
+ "title": "段落",
+ "children": [
+ {
+ "componentName": "Empty",
+ "id": "node_ocksk6f8fa3e",
+ "props": {
+ "description": "暂无数据"
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.pkgs.length < 1 && this.state.isSearch"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "i18n": {}
+}
diff --git a/modules/code-generator/tests/utils/schema/handleSubNodes.test.ts b/modules/code-generator/tests/utils/schema/handleSubNodes.test.ts
new file mode 100644
index 0000000000..be88e3e305
--- /dev/null
+++ b/modules/code-generator/tests/utils/schema/handleSubNodes.test.ts
@@ -0,0 +1,92 @@
+import { NodeData } from '@alilc/lowcode-types';
+import { handleSubNodes } from '../../../src/utils/schema';
+import SCHEMA_WITH_SLOT from './data/schema-with-slot.json';
+
+describe('utils/schema/handleSubNodes', () => {
+ it('should be able to visit nodes in JSSlot(1)', () => {
+ const nodes: NodeData[] = [
+ {
+ componentName: 'Foo',
+ props: {
+ renderBar: {
+ type: 'JSSlot',
+ value: [
+ {
+ componentName: 'Bar',
+ },
+ ],
+ },
+ },
+ },
+ ];
+
+ const result = handleSubNodes(nodes, {
+ node: (node) => node.componentName,
+ });
+
+ expect(result).toEqual(['Foo', 'Bar']);
+ });
+
+ it('should be able to visit nodes in JSSlot(2)', () => {
+ const nodes: NodeData[] = (SCHEMA_WITH_SLOT as any).componentsTree[0].children;
+
+ const result = handleSubNodes(nodes, {
+ node: (node) => node.componentName,
+ });
+
+ expect(result).toMatchInlineSnapshot(`
+ Array [
+ "Modal",
+ "AliAutoDivDefault",
+ "AliAutoDivDefault",
+ "Button",
+ "AliAutoDivDefault",
+ "Typography.Text",
+ "Typography.Link",
+ "Typography.Link",
+ "Button",
+ "NextPage",
+ "NextBlock",
+ "NextBlockCell",
+ "NextP",
+ "AliAutoDivDefault",
+ "AliAutoDivDefault",
+ "Form",
+ "Form.Item",
+ "Select",
+ "Form.Item",
+ "Input",
+ "Form.Item",
+ "Select",
+ "Form.Item",
+ "Input",
+ "Form.Item",
+ "Button",
+ "AliAutoDivDefault",
+ "Button",
+ "NextBlock",
+ "NextBlockCell",
+ "NextP",
+ "AliAutoSearchTableDefault",
+ "Typography.Text",
+ "Tooltip",
+ "Typography.Text",
+ "Typography.Text",
+ "Typography.Text",
+ "Icon",
+ "Typography.Link",
+ "Typography.Text",
+ "Typography.Link",
+ "Typography.Text",
+ "Button",
+ "Button",
+ "Button",
+ "Icon",
+ "NextBlock",
+ "NextBlockCell",
+ "NextP",
+ "Empty",
+ ]
+ `);
+ });
+});
diff --git a/modules/code-generator/tests/utils/validate.test.ts b/modules/code-generator/tests/utils/validate.test.ts
new file mode 100644
index 0000000000..5d83c67a95
--- /dev/null
+++ b/modules/code-generator/tests/utils/validate.test.ts
@@ -0,0 +1,20 @@
+import { isValidIdentifier } from '../../src/utils/validate';
+describe('utils/validate', () => {
+ it('isValidIdentifier should works for normal identifiers', () => {
+ expect(isValidIdentifier('foo')).toBeTruthy();
+ expect(isValidIdentifier('bar')).toBeTruthy();
+ expect(isValidIdentifier('hello123')).toBeTruthy();
+ expect(isValidIdentifier('helloWorld123')).toBeTruthy();
+ expect(isValidIdentifier('hello_world123')).toBeTruthy();
+ expect(isValidIdentifier('$hello_world123')).toBeTruthy();
+ expect(isValidIdentifier('姓名')).toBeTruthy();
+ expect(isValidIdentifier('电话号码')).toBeTruthy();
+ });
+
+ it('isValidIdentifier should works for invalid identifiers', () => {
+ expect(isValidIdentifier('ak dak')).toBeFalsy();
+ expect(isValidIdentifier('姓名 电话')).toBeFalsy();
+ expect(isValidIdentifier('123akk')).toBeFalsy();
+ expect(isValidIdentifier('a,b')).toBeFalsy();
+ });
+});
diff --git a/modules/code-generator/tests/utils/version.test.ts b/modules/code-generator/tests/utils/version.test.ts
new file mode 100644
index 0000000000..edcda41ede
--- /dev/null
+++ b/modules/code-generator/tests/utils/version.test.ts
@@ -0,0 +1,33 @@
+import { calcCompatibleVersion } from '../../src/utils/version';
+
+const NO_COMPATIBLE_VERSIONS = /no compatible versions/;
+
+test.each([
+ ['*', '*', '*'],
+ ['1.0.0', '1.0.0', '1.0.0'],
+ ['^1.0.0', '^1.0.0', '^1.0.0'],
+ ['*', undefined, '*'],
+ [undefined, undefined, '*'],
+ ['^1.0.0', undefined, '^1.0.0'],
+ ['*', '^1.0.0', '^1.0.0'],
+ ['^1.0.0', '^1.0.2', '^1.0.2'],
+ ['^1.2.0', '^1.1.2', '^1.2.0'],
+ ['^1.0.0', '1.0.2', '1.0.2'],
+])('calc compatible versions "%i" & "%i" should be "%i"', (a, b, expected) => {
+ expect(calcCompatibleVersion(a, b)).toBe(expected);
+ expect(calcCompatibleVersion(b, a)).toBe(expected); // 应该满足交换律
+});
+
+test.each([
+ ['^0.2.0', '^0.1.2', NO_COMPATIBLE_VERSIONS],
+ ['>0.2.0', '^0.1.2', NO_COMPATIBLE_VERSIONS],
+ ['1.0.1', '1.0.2', NO_COMPATIBLE_VERSIONS],
+])('calc compatible versions "%i" & "%i" should be no compatible versions', (a, b, expected) => {
+ expect(() => {
+ calcCompatibleVersion(a, b);
+ }).toThrow(expected);
+
+ expect(() => {
+ calcCompatibleVersion(b, a); // 应该满足交换律
+ }).toThrow(expected);
+});
diff --git a/modules/code-generator/tsconfig.json b/modules/code-generator/tsconfig.json
new file mode 100644
index 0000000000..d9a27b0f22
--- /dev/null
+++ b/modules/code-generator/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "lib"
+ },
+ "include": ["src/**/*.ts"],
+ "exclude": ["./tests", "./test-cases", "../types", "node_modules"]
+}
diff --git a/modules/material-parser/README.md b/modules/material-parser/README.md
new file mode 100644
index 0000000000..99786b2e41
--- /dev/null
+++ b/modules/material-parser/README.md
@@ -0,0 +1,16 @@
+# @ali/lowcode-material-parser
+
+> 入料模块
+
+本模块负责物料接入,能自动扫描、解析源码组件,并最终产出一份符合 **[《中后台搭建组件描述协议》](https://yuque.antfin-inc.com/rt656r/spec/pbeaqx)** 的 **JSON Schema**。
+
+详见[文档](https://yuque.antfin-inc.com/ali-lowcode/docs/tyktrt)。
+
+## demo
+
+```shell
+cd demo
+node index.js
+```
+
+## API
diff --git a/modules/material-parser/build.test.json b/modules/material-parser/build.test.json
new file mode 100644
index 0000000000..2b9fe85e6a
--- /dev/null
+++ b/modules/material-parser/build.test.json
@@ -0,0 +1,5 @@
+{
+ "plugins": [
+ "@alilc/lowcode-test-mate/plugin/index.ts"
+ ]
+}
\ No newline at end of file
diff --git a/modules/material-parser/demo/component.jsx b/modules/material-parser/demo/component.jsx
new file mode 100644
index 0000000000..0a6e805fb0
--- /dev/null
+++ b/modules/material-parser/demo/component.jsx
@@ -0,0 +1,81 @@
+/* eslint-disable react/forbid-prop-types,react/no-unused-prop-types */
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import './main.scss';
+
+class Demo extends React.Component {
+ render() {
+ return Test
;
+ }
+}
+
+Demo.propTypes = {
+ optionalArray: PropTypes.array,
+ optionalBool: PropTypes.bool,
+ optionalFunc: PropTypes.func,
+ optionalNumber: PropTypes.number,
+ optionalObject: PropTypes.object,
+ optionalString: PropTypes.string,
+ optionalSymbol: PropTypes.symbol,
+
+ // Anything that can be rendered: numbers, strings, elements or an array
+ // (or fragment) containing these types.
+ optionalNode: PropTypes.node,
+
+ // A React element (ie. ).
+ optionalElement: PropTypes.element,
+
+ // A React element type (ie. MyComponent).
+ optionalElementType: PropTypes.elementType,
+
+ // You can also declare that a prop is an instance of a class. This uses
+ // JS's instanceof operator.
+ optionalMessage: PropTypes.instanceOf(Demo),
+
+ // You can ensure that your prop is limited to specific values by treating
+ // it as an enum.
+ optionalEnum: PropTypes.oneOf(['News', 'Photos']),
+
+ // An object that could be one of many types
+ optionalUnion: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number,
+ PropTypes.instanceOf(Demo),
+ ]),
+
+ // An array of a certain type
+ optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
+
+ // An object with property values of a certain type
+ optionalObjectOf: PropTypes.objectOf(PropTypes.number),
+
+ // You can chain any of the above with `isRequired` to make sure a warning
+ // is shown if the prop isn't provided.
+
+ // An object taking on a particular shape
+ optionalObjectWithShape: PropTypes.shape({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }),
+
+ optionalObjectWithShape2: PropTypes.shape({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }).isRequired,
+
+ // An object with warnings on extra properties
+ optionalObjectWithStrictShape: PropTypes.exact({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }),
+
+ requiredFunc: PropTypes.func.isRequired,
+
+ // A value of any data type
+ requiredAny: PropTypes.any.isRequired,
+};
+
+Demo.defaultProps = {};
+
+export default Demo;
diff --git a/modules/material-parser/demo/index.js b/modules/material-parser/demo/index.js
new file mode 100644
index 0000000000..5c079efe30
--- /dev/null
+++ b/modules/material-parser/demo/index.js
@@ -0,0 +1,11 @@
+const parse = require('../lib').default;
+
+(async () => {
+ const options = {
+ entry: './component.jsx',
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+ console.log(JSON.stringify(actual, null, 2));
+})();
diff --git a/modules/material-parser/jest.config.js b/modules/material-parser/jest.config.js
new file mode 100644
index 0000000000..5686a4647c
--- /dev/null
+++ b/modules/material-parser/jest.config.js
@@ -0,0 +1,20 @@
+
+module.exports = {
+ transform: {
+ '^.+\\.(ts|tsx|js|jsx)$': 'ts-jest',
+ },
+ testEnvironment: 'node',
+ // testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
+ testTimeout: 1000000,
+ testPathIgnorePatterns: [
+ '/node_modules/',
+ 'test/fixtures',
+ ],
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
+ collectCoverage: true,
+ collectCoverageFrom: [
+ 'src/**/*.{ts,tsx}',
+ '!**/node_modules/**',
+ '!**/vendor/**',
+ ],
+};
\ No newline at end of file
diff --git a/modules/material-parser/package.json b/modules/material-parser/package.json
new file mode 100644
index 0000000000..dbdfd676bf
--- /dev/null
+++ b/modules/material-parser/package.json
@@ -0,0 +1,67 @@
+{
+ "name": "@alilc/lowcode-material-parser",
+ "version": "1.0.0-beta.15",
+ "description": "material parser for Ali lowCode engine",
+ "main": "lib/index.js",
+ "module": "es/index.js",
+ "files": [
+ "lib",
+ "schemas"
+ ],
+ "private": true,
+ "devDependencies": {
+ "@babel/runtime": "^7.11.2",
+ "@types/debug": "^4.1.5",
+ "@types/fs-extra": "^8.0.1",
+ "@types/jest": "^26.0.18",
+ "@types/js-yaml": "^3.12.2",
+ "@types/lodash": "^4.14.149",
+ "@types/node": "^14.6.0",
+ "@types/prop-types": "^15.7.3",
+ "copy-webpack-plugin": "^9.1.0",
+ "copyfiles": "^2.4.1",
+ "jest": "^26.6.3",
+ "js-yaml": "^3.13.1",
+ "json-schema-to-typescript": "^8.2.0",
+ "ts-jest": "^26.0.0",
+ "ts-loader": "^9.2.6",
+ "ts-node": "^8.10.2",
+ "tslib": "^1.11.1",
+ "webpack": "^5.64.1",
+ "webpack-cli": "^4.9.1",
+ "webpack-node-externals": "^3.0.0"
+ },
+ "scripts": {
+ "build": "tsc",
+ "prebuild": "npm run schema && npm run bundle",
+ "postbuild": "copyfiles -u 1 \"src/**/*.json\" lib/",
+ "prepublishOnly": "npm run build",
+ "test": "jest --verbose",
+ "test:snapshot": "jest --updateSnapshot --verbose",
+ "schema": "node ./scripts/transform.js",
+ "bundle": "webpack"
+ },
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.0",
+ "ast-types": "^0.13.3",
+ "cross-spawn-promise": "^0.10.2",
+ "debug": "^4.1.1",
+ "find-config": "^1.0.0",
+ "fs-extra": "^8.1.0",
+ "lodash": "^4.17.15",
+ "parse-prop-types": "^0.3.0",
+ "prop-types": "^15.7.2",
+ "react-docgen": "5.3.0",
+ "react-docgen-typescript": "^1.16.5",
+ "safe-eval": "^0.4.1",
+ "short-uuid": "^3.1.1",
+ "ts-polyfill": "^3.8.1-rc",
+ "typescript": "3.9.4",
+ "vm2": "^3.9.2"
+ },
+ "publishConfig": {
+ "access": "public",
+ "registry": "https://registry.npmjs.org/"
+ }
+}
diff --git a/modules/material-parser/schemas/schema.json b/modules/material-parser/schemas/schema.json
new file mode 100644
index 0000000000..7a5469a106
--- /dev/null
+++ b/modules/material-parser/schemas/schema.json
@@ -0,0 +1,537 @@
+{
+ "$id": "@ali/low-code-component-protocol-schema",
+ "description": "json schema for low code component protocol",
+ "allOf": [
+ {
+ "$ref": "#/definitions/BasicSection"
+ },
+ {
+ "$ref": "#/definitions/PropsSection"
+ },
+ {
+ "$ref": "#/definitions/ConfigureSection"
+ }
+ ],
+ "definitions": {
+ "BasicSection": {
+ "type": "object",
+ "properties": {
+ "componentName": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "docUrl": {
+ "type": "string"
+ },
+ "screenshot": {
+ "type": "string"
+ },
+ "icon": {
+ "type": "string"
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "devMode": {
+ "enum": [
+ "proCode",
+ "lowCode"
+ ]
+ },
+ "npm": {
+ "$ref": "#/definitions/Npm"
+ }
+ },
+ "required": [
+ "componentName",
+ "title",
+ "npm",
+ "docUrl",
+ "screenshot"
+ ]
+ },
+ "PropsSection": {
+ "type": "object",
+ "properties": {
+ "props": {
+ "type": "array",
+ "items": {
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "propType": {
+ "$ref": "#/definitions/PropType"
+ },
+ "description": {
+ "type": "string"
+ },
+ "defaultValue": {}
+ },
+ "required": [
+ "name",
+ "propType"
+ ]
+ }
+ }
+ }
+ },
+ "ConfigureSection": {
+ "type": "object",
+ "properties": {
+ "configure": {
+ "type": "object",
+ "properties": {
+ "props": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ConfigureProp"
+ }
+ },
+ "styles": {
+ "type": "object",
+ "properties": {}
+ },
+ "events": {
+ "type": "object",
+ "properties": {}
+ },
+ "component": {
+ "$ref": "#/definitions/ConfigureComponent"
+ }
+ }
+ }
+ }
+ },
+ "Npm": {
+ "type": "object",
+ "properties": {
+ "package": {
+ "type": "string"
+ },
+ "exportName": {
+ "type": "string"
+ },
+ "subName": {
+ "type": "string"
+ },
+ "main": {
+ "type": "string"
+ },
+ "destructuring": {
+ "type": "boolean"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "package",
+ "exportName",
+ "subName",
+ "main",
+ "destructuring",
+ "version"
+ ]
+ },
+ "PropType": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/BasicType"
+ },
+ {
+ "$ref": "#/definitions/RequiredType"
+ },
+ {
+ "$ref": "#/definitions/ComplexType"
+ }
+ ]
+ },
+ "BasicType": {
+ "type": "string",
+ "enum": [
+ "array",
+ "bool",
+ "func",
+ "number",
+ "object",
+ "string",
+ "node",
+ "element",
+ "any"
+ ]
+ },
+ "RequiredType": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/definitions/BasicType"
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type"
+ ]
+ },
+ "ComplexType": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/OneOf"
+ },
+ {
+ "$ref": "#/definitions/OneOfType"
+ },
+ {
+ "$ref": "#/definitions/ArrayOf"
+ },
+ {
+ "$ref": "#/definitions/ObjectOf"
+ },
+ {
+ "$ref": "#/definitions/Shape"
+ },
+ {
+ "$ref": "#/definitions/Exact"
+ }
+ ]
+ },
+ "OneOf": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "oneOf"
+ ]
+ },
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "OneOfType": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "oneOfType"
+ ]
+ },
+ "value": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PropType"
+ }
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "ArrayOf": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "arrayOf"
+ ]
+ },
+ "value": {
+ "$ref": "#/definitions/PropType"
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "ObjectOf": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "objectOf"
+ ]
+ },
+ "value": {
+ "$ref": "#/definitions/PropType"
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "Shape": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "shape"
+ ]
+ },
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "propType": {
+ "$ref": "#/definitions/PropType"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "ShapeItem": {
+ "type": "object",
+ "required": [
+ "name",
+ "propType"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "propType": {
+ "$ref": "#/definitions/PropType"
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Exact": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "exact"
+ ]
+ },
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "propType": {
+ "$ref": "#/definitions/PropType"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "ConfigureProp": {
+ "type": "object",
+ "allOf": [
+ {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "extraProps": {
+ "type": "object",
+ "properties": {}
+ }
+ }
+ },
+ {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/ConfigureFieldProp"
+ },
+ {
+ "$ref": "#/definitions/ConfigureGroupProp"
+ }
+ ]
+ }
+ ]
+ },
+ "ConfigureFieldProp": {
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "field"
+ ]
+ },
+ "name": {
+ "type": "string"
+ },
+ "setter": {
+ "$ref": "#/definitions/ConfigureFieldSetter"
+ }
+ }
+ },
+ "ConfigureFieldSetter": {
+ "type": "object",
+ "required": [
+ "componentName"
+ ],
+ "properties": {
+ "componentName": {
+ "type": "string",
+ "enum": [
+ "List",
+ "Object",
+ "Function",
+ "Node",
+ "Mixin",
+ "Expression",
+ "Switch",
+ "Number",
+ "Input",
+ "TextArea",
+ "Date",
+ "DateYear",
+ "DateMonth",
+ "DateRange",
+ "ColorPicker",
+ "CodeEditor",
+ "Select",
+ "RadioGroup"
+ ]
+ },
+ "props": {
+ "type": "object",
+ "properties": {}
+ }
+ }
+ },
+ "ConfigureGroupProp": {
+ "type": "object",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "group"
+ ]
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ConfigureProp"
+ }
+ }
+ }
+ },
+ "ConfigureComponent": {
+ "type": "object",
+ "properties": {
+ "isContainer": {
+ "type": "boolean"
+ },
+ "isModal": {
+ "type": "boolean"
+ },
+ "descriptor": {
+ "type": "string"
+ },
+ "nestingRule": {
+ "type": "object",
+ "properties": {
+ "childWhitelist": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "parentWhitelist": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "descendantBlacklist": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "ancestorWhitelist": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "isNullNode": {
+ "type": "boolean"
+ },
+ "isLayout": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/material-parser/schemas/schema.yml b/modules/material-parser/schemas/schema.yml
new file mode 100644
index 0000000000..71d2f8ec01
--- /dev/null
+++ b/modules/material-parser/schemas/schema.yml
@@ -0,0 +1,351 @@
+$id: "@ali/low-code-component-protocol-schema"
+description: json schema for low code component protocol
+allOf:
+ - $ref: "#/definitions/BasicSection"
+ - $ref: "#/definitions/PropsSection"
+ - $ref: "#/definitions/ConfigureSection"
+definitions:
+ BasicSection:
+ type: object
+ properties:
+ componentName:
+ type: string
+ title:
+ type: string
+ description:
+ type: string
+ docUrl:
+ type: string
+ screenshot:
+ type: string
+ icon:
+ type: string
+ tags:
+ type: array
+ items:
+ type: string
+ devMode:
+ enum:
+ - proCode
+ - lowCode
+ npm:
+ $ref: "#/definitions/Npm"
+ required:
+ - componentName
+ - title
+ - npm
+ PropsSection:
+ type: object
+ required:
+ - props
+ properties:
+ props:
+ type: array
+ items:
+ properties:
+ name:
+ type: string
+ propType:
+ $ref: "#/definitions/PropType"
+ description:
+ type: string
+ defaultValue: {}
+ required:
+ - name
+ - propType
+ ConfigureSection:
+ type: object
+ properties:
+ configure:
+ type: object
+ properties:
+ props:
+ type: array
+ items:
+ $ref: "#/definitions/ConfigureProp"
+ styles:
+ type: object
+ properties: {}
+ events:
+ type: object
+ properties: {}
+ component:
+ $ref: "#/definitions/ConfigureComponent"
+ Npm:
+ type: object
+ properties:
+ package:
+ type: string
+ exportName:
+ type: string
+ subName:
+ type: string
+ main:
+ type: string
+ destructuring:
+ type: boolean
+ version:
+ type: string
+ required:
+ - package
+ - exportName
+ - subName
+ - main
+ - destructuring
+ - version
+ PropType:
+ oneOf:
+ - $ref: "#/definitions/BasicType"
+ - $ref: "#/definitions/RequiredType"
+ - $ref: "#/definitions/ComplexType"
+ BasicType:
+ type: string
+ enum:
+ - array
+ - bool
+ - func
+ - number
+ - object
+ - string
+ - node
+ - element
+ - any
+ RequiredType:
+ type: object
+ properties:
+ type:
+ $ref: "#/definitions/BasicType"
+ isRequired:
+ type: boolean
+ additionalProperties: false
+ required:
+ - type
+ ComplexType:
+ oneOf:
+ - $ref: "#/definitions/OneOf"
+ - $ref: "#/definitions/OneOfType"
+ - $ref: "#/definitions/ArrayOf"
+ - $ref: "#/definitions/ObjectOf"
+ - $ref: "#/definitions/Shape"
+ - $ref: "#/definitions/Exact"
+ OneOf:
+ type: object
+ required:
+ - type
+ - value
+ properties:
+ type:
+ type: string
+ enum:
+ - oneOf
+ value:
+ type: array
+ items:
+ oneOf:
+ - type: string
+ - type: number
+ - type: boolean
+ isRequired:
+ type: boolean
+ OneOfType:
+ type: object
+ required:
+ - type
+ - value
+ properties:
+ type:
+ type: string
+ enum:
+ - oneOfType
+ value:
+ type: array
+ items:
+ $ref: "#/definitions/PropType"
+ isRequired:
+ type: boolean
+ ArrayOf:
+ type: object
+ required:
+ - type
+ - value
+ properties:
+ type:
+ type: string
+ enum:
+ - arrayOf
+ value:
+ $ref: "#/definitions/PropType"
+ isRequired:
+ type: boolean
+ ObjectOf:
+ type: object
+ required:
+ - type
+ - value
+ properties:
+ type:
+ type: string
+ enum:
+ - objectOf
+ value:
+ $ref: "#/definitions/PropType"
+ isRequired:
+ type: boolean
+ Shape:
+ type: object
+ required:
+ - type
+ - value
+ properties:
+ type:
+ type: string
+ enum:
+ - shape
+ value:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ propType:
+ $ref: "#/definitions/PropType"
+ additionalProperties: false
+ isRequired:
+ type: boolean
+ ShapeItem:
+ type: object
+ required:
+ - name
+ - propType
+ properties:
+ name:
+ type: string
+ propType:
+ $ref: "#/definitions/PropType"
+ isRequired:
+ type: boolean
+ additionalProperties: false
+ Exact:
+ type: object
+ required:
+ - type
+ - value
+ properties:
+ type:
+ type: string
+ enum:
+ - exact
+ value:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ propType:
+ $ref: "#/definitions/PropType"
+ additionalProperties: false
+ isRequired:
+ type: boolean
+ ConfigureProp:
+ type: object
+ allOf:
+ - type: object
+ properties:
+ title:
+ type: string
+ extraProps:
+ type: object
+ properties: {}
+ - oneOf:
+ - $ref: "#/definitions/ConfigureFieldProp"
+ - $ref: "#/definitions/ConfigureGroupProp"
+ ConfigureFieldProp:
+ type: object
+ required:
+ - type
+ properties:
+ type:
+ type: string
+ enum:
+ - field
+ name:
+ type: string
+ setter:
+ $ref: "#/definitions/ConfigureFieldSetter"
+ ConfigureFieldSetter:
+ type: object
+ required:
+ - componentName
+ properties:
+ componentName:
+ type: string
+ enum:
+ - List
+ - Object
+ - Function
+ - Node
+ - Mixin
+ - Expression
+ - Switch
+ - Number
+ - Input
+ - TextArea
+ - Date
+ - DateYear
+ - DateMonth
+ - DateRange
+ - ColorPicker
+ - CodeEditor
+ - Select
+ - RadioGroup
+ props:
+ type: object
+ properties: {} # 暂未校验每个控件的props,待控件入料后获取真实属性
+ ConfigureGroupProp:
+ type: object
+ required:
+ - type
+ - items
+ properties:
+ type:
+ type: string
+ enum:
+ - group
+ items:
+ type: array
+ items:
+ $ref: "#/definitions/ConfigureProp"
+ ConfigureComponent:
+ type: object
+ properties:
+ isContainer:
+ type: boolean
+ isModal:
+ type: boolean
+ descriptor:
+ type: string
+ nestingRule:
+ type: object
+ properties:
+ childWhitelist:
+ type: array
+ items:
+ type: string
+ parentWhitelist:
+ type: array
+ items:
+ type: string
+ descendantBlacklist:
+ type: array
+ items:
+ type: string
+ ancestorWhitelist:
+ type: array
+ items:
+ type: string
+ isNullNode:
+ type: boolean
+ isLayout:
+ type: boolean
diff --git a/modules/material-parser/scripts/transform.js b/modules/material-parser/scripts/transform.js
new file mode 100644
index 0000000000..4e9c127f1b
--- /dev/null
+++ b/modules/material-parser/scripts/transform.js
@@ -0,0 +1,27 @@
+const yaml = require('js-yaml');
+const fs = require('fs');
+const path = require('path');
+const Ajv = require('ajv');
+const { compile } = require('json-schema-to-typescript');
+
+const ajv = new Ajv();
+
+const YamlPath = path.resolve(__dirname, '../schemas/schema.yml');
+const JsonPath = path.resolve(__dirname, '../src/validate/schema.json');
+const tsPath = path.resolve(__dirname, '../src/core/schema/types.ts');
+// Get document, or throw exception on error
+
+(async function () {
+ try {
+ const schema = yaml.load(fs.readFileSync(YamlPath, 'utf8'));
+ ajv.compile(schema);
+ fs.writeFileSync(JsonPath, JSON.stringify(schema, null, 2), 'utf-8');
+ console.log('yaml file is successfully transformed into json');
+ const ts = await compile(schema, 'ComponentMeta');
+ fs.writeFileSync(tsPath, ts);
+ console.log('schema.d.ts is successfully generated');
+ } catch (e) {
+ console.log(e);
+ process.exit(1);
+ }
+})();
diff --git a/modules/material-parser/src/core/index.ts b/modules/material-parser/src/core/index.ts
new file mode 100644
index 0000000000..2b46db64b2
--- /dev/null
+++ b/modules/material-parser/src/core/index.ts
@@ -0,0 +1,10 @@
+import _debug from 'debug';
+
+export * from './schema/types';
+
+/**
+ * Dev helper
+ */
+export const debug = _debug('lowcode:mat');
+export const enableDebug = () => _debug.enable('lowcode:*');
+export const disableDebug = () => _debug.disable();
diff --git a/modules/material-parser/src/core/schema/types.ts b/modules/material-parser/src/core/schema/types.ts
new file mode 100644
index 0000000000..196032d2cf
--- /dev/null
+++ b/modules/material-parser/src/core/schema/types.ts
@@ -0,0 +1,163 @@
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+/**
+ * json schema for low code component protocol
+ */
+export type ComponentMeta = BasicSection & PropsSection & ConfigureSection;
+export type PropType = BasicType | RequiredType | ComplexType;
+export type BasicType = 'array' | 'bool' | 'func' | 'number' | 'object' | 'string' | 'node' | 'element' | 'any';
+export type ComplexType = OneOf | OneOfType | ArrayOf | ObjectOf | Shape | Exact;
+export type ConfigureProp = {
+ title?: string;
+ extraProps?: {
+ [k: string]: any;
+ };
+ [k: string]: any;
+} & (ConfigureFieldProp | ConfigureGroupProp);
+
+export interface BasicSection {
+ componentName: string;
+ title: string;
+ description?: string;
+ docUrl?: string;
+ screenshot?: string;
+ icon?: string;
+ tags?: string[];
+ devMode?: 'proCode' | 'lowCode';
+ npm: Npm;
+ [k: string]: any;
+}
+export interface Npm {
+ package: string;
+ exportName: string;
+ subName: string;
+ main: string;
+ destructuring: boolean;
+ version: string;
+ [k: string]: any;
+}
+export interface PropsSection {
+ props: {
+ name: string;
+ propType: PropType;
+ description?: string;
+ defaultValue?: any;
+ [k: string]: any;
+ }[];
+ [k: string]: any;
+}
+export interface RequiredType {
+ type: BasicType;
+ isRequired?: boolean;
+}
+export interface OneOf {
+ type: 'oneOf';
+ value: (string | number | boolean)[];
+ isRequired?: boolean;
+ [k: string]: any;
+}
+export interface OneOfType {
+ type: 'oneOfType';
+ value: PropType[];
+ isRequired?: boolean;
+ [k: string]: any;
+}
+export interface ArrayOf {
+ type: 'arrayOf';
+ value: PropType;
+ isRequired?: boolean;
+ [k: string]: any;
+}
+export interface ObjectOf {
+ type: 'objectOf';
+ value: PropType;
+ isRequired?: boolean;
+ [k: string]: any;
+}
+export interface Shape {
+ type: 'shape';
+ value: {
+ name?: string;
+ propType?: PropType;
+ }[];
+ isRequired?: boolean;
+ [k: string]: any;
+}
+export interface Exact {
+ type: 'exact';
+ value: {
+ name?: string;
+ propType?: PropType;
+ }[];
+ isRequired?: boolean;
+ [k: string]: any;
+}
+export interface ConfigureSection {
+ configure?: {
+ props?: ConfigureProp[];
+ styles?: {
+ [k: string]: any;
+ };
+ events?: {
+ [k: string]: any;
+ };
+ component?: ConfigureComponent;
+ [k: string]: any;
+ };
+ [k: string]: any;
+}
+export interface ConfigureFieldProp {
+ type: 'field';
+ name?: string;
+ setter?: ConfigureFieldSetter;
+ [k: string]: any;
+}
+export interface ConfigureFieldSetter {
+ componentName:
+ | 'List'
+ | 'Object'
+ | 'Function'
+ | 'Node'
+ | 'Mixin'
+ | 'Expression'
+ | 'Switch'
+ | 'Number'
+ | 'Input'
+ | 'TextArea'
+ | 'Date'
+ | 'DateYear'
+ | 'DateMonth'
+ | 'DateRange'
+ | 'ColorPicker'
+ | 'CodeEditor'
+ | 'Select'
+ | 'RadioGroup';
+ props?: {
+ [k: string]: any;
+ };
+ [k: string]: any;
+}
+export interface ConfigureGroupProp {
+ type: 'group';
+ items: ConfigureProp[];
+ [k: string]: any;
+}
+export interface ConfigureComponent {
+ isContainer?: boolean;
+ isModal?: boolean;
+ descriptor?: string;
+ nestingRule?: {
+ childWhitelist?: string[];
+ parentWhitelist?: string[];
+ descendantBlacklist?: string[];
+ ancestorWhitelist?: string[];
+ [k: string]: any;
+ };
+ isNullNode?: boolean;
+ isLayout?: boolean;
+ [k: string]: any;
+}
diff --git a/modules/material-parser/src/generate.ts b/modules/material-parser/src/generate.ts
new file mode 100644
index 0000000000..ec057a8c6a
--- /dev/null
+++ b/modules/material-parser/src/generate.ts
@@ -0,0 +1,65 @@
+import * as path from 'path';
+import { debug, ComponentMeta } from './core';
+import { IMaterialParsedModel, IMaterialScanModel, IInternalMaterializeOptions } from './types';
+
+const log = debug.extend('gen');
+
+export default async function (
+ matScanModel: IMaterialScanModel,
+ matParsedModels: IMaterialParsedModel[],
+ options: IInternalMaterializeOptions,
+): Promise {
+ const containerList = [];
+ for (const matParsedModel of matParsedModels) {
+ // 默认排除掉 defaultExportName 为空的组件
+ if (!matParsedModel.componentName) {
+ log('skip');
+ continue;
+ }
+ // 组装 manifest
+ const manifest: any = await genManifest(matScanModel, matParsedModel, options);
+
+ containerList.push(manifest);
+ }
+
+ return containerList;
+}
+
+/**
+ * 生成 manifest
+ *
+ * @param {IMaterialParsedModel} matParsedModel
+ * @returns {Promise<
+ * manifestObj: ComponentMeta, // 组件描述
+ * >}
+ * @memberof LocalGenerator
+ */
+export async function genManifest(
+ matScanModel: IMaterialScanModel,
+ matParsedModel: IMaterialParsedModel,
+ options: IInternalMaterializeOptions,
+): Promise {
+ const manifestObj: Partial = {
+ componentName: matParsedModel.componentName,
+ title: matScanModel.pkgName,
+ docUrl: '',
+ screenshot: '',
+ devMode: 'proCode', // 需要入料的组件都是源码模式,低代码组件在平台上即可直接生成描述
+ npm: {
+ package: matScanModel.pkgName,
+ version: matScanModel.pkgVersion,
+ exportName: matParsedModel.meta?.exportName || matParsedModel.componentName,
+ main:
+ options.root && path.isAbsolute(matScanModel.mainFilePath)
+ ? path.relative(options.root, matScanModel.mainFilePath)
+ : matScanModel.mainFilePath,
+ destructuring: matParsedModel.meta?.exportName !== 'default',
+ subName: matParsedModel.meta?.subName || '',
+ },
+ };
+
+ // 填充 props
+ manifestObj.props = matParsedModel.props;
+ // 执行扩展点
+ return manifestObj as ComponentMeta;
+}
diff --git a/modules/material-parser/src/index.ts b/modules/material-parser/src/index.ts
new file mode 100644
index 0000000000..f5df4e1d03
--- /dev/null
+++ b/modules/material-parser/src/index.ts
@@ -0,0 +1,70 @@
+import 'ts-polyfill';
+import { remove, lstatSync } from 'fs-extra';
+import { join, isAbsolute } from 'path';
+import {
+ IMaterializeOptions,
+ IMaterializeLocalOptions,
+ IMaterializeOnlineOptions,
+ IInternalMaterializeOptions,
+} from './types';
+import { ComponentMeta } from './core';
+import scan from './scan';
+import generate from './generate';
+import parse from './parse';
+import localize from './localize';
+
+export { default as validate } from './validate';
+export { default as schema } from './validate/schema.json';
+
+export * from './types';
+
+export default async function (options: IMaterializeOptions): Promise {
+ const { accesser = 'local', dslType } = options;
+
+ let { entry = '' } = options;
+ const internalOptions: IInternalMaterializeOptions = {
+ ...options,
+ accesser,
+ entry: options.entry || '',
+ root: (options as IMaterializeLocalOptions)?.root || '',
+ } as IInternalMaterializeOptions;
+
+ if (accesser === 'local') {
+ const { root } = options as IMaterializeLocalOptions;
+ internalOptions.root = root;
+ if (!root) {
+ const stats = lstatSync(entry);
+ if (stats.isDirectory()) {
+ internalOptions.root = entry;
+ } else {
+ internalOptions.root = process.cwd();
+ }
+ } else if (!isAbsolute(entry)) {
+ internalOptions.entry = join(root, entry);
+ }
+ }
+
+ let workDir = internalOptions.root || '';
+ let moduleDir = '';
+ if (accesser === 'online') {
+ const result = await localize(internalOptions as IMaterializeOnlineOptions);
+ workDir = result.workDir;
+ moduleDir = result.moduleDir;
+ internalOptions.entry = result.entry ? join(moduleDir, result.entry) : moduleDir;
+ internalOptions.root = moduleDir;
+ }
+ const scanedModel = await scan(internalOptions);
+ const parsedModel = await parse({
+ ...scanedModel,
+ dslType,
+ accesser,
+ npmClient: internalOptions.npmClient,
+ workDir,
+ moduleDir,
+ });
+ const result = await generate(scanedModel, parsedModel, internalOptions);
+ if (workDir && accesser === 'online') {
+ await remove(workDir);
+ }
+ return result;
+}
diff --git a/modules/material-parser/src/localize.ts b/modules/material-parser/src/localize.ts
new file mode 100644
index 0000000000..a152fc0de3
--- /dev/null
+++ b/modules/material-parser/src/localize.ts
@@ -0,0 +1,126 @@
+import spawn from 'cross-spawn-promise';
+import { ensureDir, ensureFile, writeFile } from 'fs-extra';
+import { join, resolve } from 'path';
+import uuid from 'short-uuid';
+import { debug } from './core';
+import { IMaterializeOnlineOptions, IMaterializeOnlinePackageAndVersionOptions } from './types';
+
+const log = debug.extend('localize');
+
+/**
+ * 创建组件包
+ *
+ * @private
+ * @param {{
+ * pkgName: string;
+ * pkgVersion: string;
+ * }} params
+ * @returns {Promise}
+ * @memberof OnlineAccesser
+ */
+export async function createFakePackage(params: {
+ workDir: string;
+ pkgName: string;
+ pkgVersion: string;
+ npmClient?: string;
+}): Promise {
+ // 创建临时组件包
+ const { workDir } = params;
+ const pkgJsonFilePath = join(workDir, 'package.json');
+ await ensureFile(pkgJsonFilePath);
+ await writeFile(
+ pkgJsonFilePath,
+ JSON.stringify(
+ {
+ name: params.pkgName,
+ version: params.pkgVersion || '0.0.0',
+ dependencies: {
+ [params.pkgName]: params.pkgVersion || 'latest',
+ react: 'latest',
+ 'react-dom': 'latest',
+ 'parse-prop-types': '^0.3.0',
+ typesync: 'latest',
+ },
+ },
+ null,
+ 2,
+ ),
+ );
+
+ // 安装依赖
+ const npmClient = params.npmClient || 'tnpm';
+ await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);
+}
+
+/**
+ * 创建临时目录
+ *
+ * @private
+ * @returns {Promise} 返回临时文件夹路径
+ * @memberof LocalGenerator
+ */
+export async function createworkDir(tempDir?: string): Promise {
+ const workDirName = uuid.generate();
+ const workDir = resolve(tempDir || '../../node_modules/.temp/', workDirName);
+ await ensureDir(workDir);
+ log('create temp dir successfully', workDir);
+ return workDir;
+}
+
+/**
+ * 分离物料组件名称和版本号
+ *
+ * @private
+ * @param {string} pkgNameWithVersion
+ * @returns {{ [key: string]: any }}
+ * @memberof OnlineAccesser
+ */
+export function getPkgNameAndVersion(pkgNameWithVersion: string): { [key: string]: any } {
+ const matches = pkgNameWithVersion.match(/(@[^/]+)$/);
+ if (!matches) {
+ return {
+ name: pkgNameWithVersion,
+ };
+ }
+ const name = pkgNameWithVersion.replace(matches[0], '');
+ return {
+ version: matches[0].slice(1),
+ name,
+ };
+}
+
+// 将问题转化为本地物料化场景
+export default async function localize(options: IMaterializeOnlineOptions): Promise<{
+ workDir: string;
+ moduleDir: string;
+ entry?: string;
+}> {
+ // 创建临时目录
+ const workDir = await createworkDir(options.tempDir);
+ await ensureDir(workDir);
+ let { name, version = 'latest' } = options as IMaterializeOnlinePackageAndVersionOptions;
+ if (!name) {
+ const pkgNameAndVersion = getPkgNameAndVersion(options.entry);
+ name = pkgNameAndVersion.name;
+ version = pkgNameAndVersion.version;
+ }
+ // 创建组件包
+ await createFakePackage({
+ pkgName: name,
+ pkgVersion: version,
+ workDir,
+ npmClient: options.npmClient,
+ });
+
+ const result = {
+ workDir,
+ moduleDir: join(workDir, 'node_modules', name),
+ entry: undefined,
+ };
+
+ if ((options as IMaterializeOnlinePackageAndVersionOptions)?.name) {
+ result.entry = options.entry;
+ }
+
+ return result;
+}
diff --git a/modules/material-parser/src/parse/dynamic/index.ts b/modules/material-parser/src/parse/dynamic/index.ts
new file mode 100644
index 0000000000..0a7e968f9f
--- /dev/null
+++ b/modules/material-parser/src/parse/dynamic/index.ts
@@ -0,0 +1,121 @@
+import { isEmpty } from 'lodash';
+// import * as path from 'path';
+// @ts-ignore
+import parsePropTypes from 'parse-prop-types';
+import PropTypes from 'prop-types';
+import { transformItem } from '../transform';
+import requireInSandbox from './requireInSandbox';
+
+export interface IComponentInfo {
+ component: any;
+ meta: {
+ exportName: string;
+ subName?: string;
+ };
+}
+
+const reservedKeys = [
+ 'propTypes',
+ 'defaultProps',
+ 'name',
+ 'arguments',
+ 'caller',
+ 'length',
+ 'contextTypes',
+ 'displayName',
+ '__esModule',
+ 'version',
+];
+
+function getKeys(com: any) {
+ const keys = Object.keys(com).filter(x => {
+ return !reservedKeys.includes(x) && !x.startsWith('_');
+ });
+
+ return keys;
+}
+
+function isComponent(obj: any) {
+ return (
+ typeof obj === 'function' &&
+ (Object.prototype.hasOwnProperty.call(obj, 'propTypes') ||
+ Object.prototype.hasOwnProperty.call(obj, 'defaultProps'))
+ );
+}
+
+export default function (filePath: string) {
+ // const { filePath } = arg;
+ // const modulePath = path.resolve(workDir, 'node_modules', 'parse-prop-types');
+ // const parsePropTypes = require(modulePath).default;
+ if (!filePath) return [];
+ const Com = requireInSandbox(filePath, PropTypes);
+ const components: IComponentInfo[] = [];
+ let index = 0;
+
+ if (Com.__esModule) {
+ const keys = getKeys(Com);
+ keys.forEach(k => {
+ if (isComponent(Com[k])) {
+ components.push({
+ component: Com[k],
+ meta: {
+ exportName: k,
+ },
+ });
+ }
+ });
+ } else if (isComponent(Com)) {
+ components.push({
+ component: Com,
+ meta: {
+ exportName: 'default',
+ },
+ });
+ }
+
+ // dps
+ while (index < components.length) {
+ const item = components[index++];
+
+ const keys = getKeys(item.component);
+ const subs = keys
+ .filter(k => isComponent(item.component[k]))
+ .map(k => ({
+ component: item.component[k],
+ meta: {
+ ...item.meta,
+ subName: k,
+ },
+ }));
+ if (subs.length) {
+ components.splice(index, 0, ...subs);
+ }
+ }
+
+ const result = components.reduce((acc: any, { meta, component }) => {
+ const componentInfo = parsePropTypes(component);
+ if (!isEmpty(componentInfo)) {
+ const props = Object.keys(componentInfo).reduce((acc2: any[], name) => {
+ try {
+ const item: any = transformItem(name, componentInfo[name]);
+ acc2.push(item);
+ } catch (e) {
+ // TODO
+ }
+ return acc2;
+ }, []);
+
+ return [
+ ...acc,
+ {
+ meta,
+ props,
+ componentName: meta.subName || meta.exportName || component.displayName,
+ },
+ ];
+ }
+ return acc;
+ }, []);
+
+ return result;
+}
diff --git a/modules/material-parser/src/parse/dynamic/requireInSandbox.ts b/modules/material-parser/src/parse/dynamic/requireInSandbox.ts
new file mode 100644
index 0000000000..511b300388
--- /dev/null
+++ b/modules/material-parser/src/parse/dynamic/requireInSandbox.ts
@@ -0,0 +1,37 @@
+import { readFileSync } from 'fs-extra';
+import { NodeVM } from 'vm2';
+// import PropTypes from 'prop-types';
+
+const cssPattern = /\.(css|scss|sass|less)$/;
+function requireInSandbox(filePath: string, PropTypes: any) {
+ const vm = new NodeVM({
+ sandbox: {},
+ sourceExtensions: ['js', 'css', 'scss', 'sass', 'less'],
+ compiler: (code, filename) => {
+ if (filename.match(cssPattern)) {
+ return `
+ const handler = {
+ get() {
+ return new Proxy({}, handler);
+ },
+ };
+ const proxiedObject = new Proxy({}, handler);
+ module.exports = proxiedObject;
+ `;
+ } else {
+ return code;
+ }
+ },
+ require: {
+ external: true,
+ context: 'sandbox',
+ mock: {
+ 'prop-types': PropTypes,
+ },
+ },
+ });
+ const fileContent = readFileSync(filePath, { encoding: 'utf8' });
+ return vm.run(fileContent, filePath);
+}
+
+export default requireInSandbox;
diff --git a/modules/material-parser/src/parse/index.ts b/modules/material-parser/src/parse/index.ts
new file mode 100644
index 0000000000..f38fab199d
--- /dev/null
+++ b/modules/material-parser/src/parse/index.ts
@@ -0,0 +1,80 @@
+import parseDynamic from './dynamic';
+import parseJS from './js';
+import parseTS from './ts';
+import { install, installPeerAndDevDeps, syncTypeModules, installTypeDTS } from '../utils';
+import { IMaterialScanModel, DSLType } from '../types';
+import { debug } from '../core';
+
+const log = debug.extend('parse');
+
+export interface IParseArgs extends IMaterialScanModel {
+ accesser?: 'online' | 'local';
+ dslType?: DSLType;
+ npmClient?: string;
+ workDir: string;
+ moduleDir: string;
+ typingsFileAbsolutePath?: string;
+ mainFileAbsolutePath: string;
+ moduleFileAbsolutePath?: string;
+}
+
+export function isTSLike(str) {
+ return str.endsWith('ts') || str.endsWith('tsx');
+}
+
+export default async (args: IParseArgs) => {
+ const {
+ typingsFileAbsolutePath,
+ mainFileAbsolutePath,
+ moduleFileAbsolutePath = mainFileAbsolutePath,
+ useEntry = false,
+ } = args;
+ if (args.accesser === 'local') {
+ if (isTSLike(mainFileAbsolutePath)) {
+ await install(args);
+ // in case the developer forgets to install types
+ await installTypeDTS(args);
+ return parseTS(mainFileAbsolutePath, args);
+ } else if (typingsFileAbsolutePath) {
+ await installTypeDTS(args);
+ return parseTS(typingsFileAbsolutePath, args);
+ } else {
+ try {
+ return parseJS(moduleFileAbsolutePath || mainFileAbsolutePath);
+ } catch (e) {
+ log(e);
+ await install(args);
+ const info = parseDynamic(mainFileAbsolutePath);
+ if (!info || !info.length) {
+ throw Error();
+ }
+ return info;
+ }
+ }
+ } else if (args.accesser === 'online') {
+ // ts
+ const entryPath = useEntry ? mainFileAbsolutePath : typingsFileAbsolutePath;
+ if (entryPath && isTSLike(entryPath)) {
+ await syncTypeModules(args);
+ await install(args);
+ await installTypeDTS(args);
+ await installPeerAndDevDeps(args);
+ return parseTS(entryPath, args);
+ }
+ // js
+ try {
+ // try dynamic parsing first
+ await installPeerAndDevDeps(args);
+ const info = parseDynamic(mainFileAbsolutePath);
+ if (!info || !info.length) {
+ throw Error();
+ }
+ return info;
+ } catch (e) {
+ log(e);
+ // if error, use static js parsing instead
+ return parseJS(moduleFileAbsolutePath || mainFileAbsolutePath);
+ }
+ }
+ return parseJS(moduleFileAbsolutePath || mainFileAbsolutePath);
+};
diff --git a/modules/material-parser/src/parse/js/handlers/defaultPropsHandler.ts b/modules/material-parser/src/parse/js/handlers/defaultPropsHandler.ts
new file mode 100644
index 0000000000..078db5f18b
--- /dev/null
+++ b/modules/material-parser/src/parse/js/handlers/defaultPropsHandler.ts
@@ -0,0 +1,138 @@
+import getComposedPath from '../utils/getComposedPath';
+import evaluate from '../utils/evaluate';
+
+const { namedTypes: t, NodePath, visit } = require('ast-types');
+type NodePathType = typeof NodePath;
+const {
+ getPropertyName,
+ isReactComponentClass,
+ getMemberValuePath,
+ isReactForwardRefCall,
+ printValue,
+ resolveToValue,
+} = require('react-docgen').utils;
+const resolveFunctionDefinitionToReturnValue = require('react-docgen/dist/utils/resolveFunctionDefinitionToReturnValue');
+
+function getDefaultValue(path: NodePathType) {
+ let { node } = path;
+ let defaultValue;
+ if (t.Literal.check(node)) {
+ defaultValue = node.raw;
+ } else {
+ if (t.AssignmentPattern.check(path.node)) {
+ path = resolveToValue(path.get('right'));
+ } else {
+ path = resolveToValue(path);
+ }
+ if (t.ImportDeclaration.check(path.node)) {
+ defaultValue = node.name;
+ } else {
+ node = path.node;
+ try {
+ const result = evaluate(path);
+ if (result.confident) {
+ defaultValue = result.value;
+ }
+ } catch (e) {
+ // log(e);
+ // TODO
+ }
+ }
+ }
+ if (typeof defaultValue !== 'undefined') {
+ return {
+ value: defaultValue,
+ computed:
+ t.CallExpression.check(node) || t.MemberExpression.check(node) || t.Identifier.check(node),
+ };
+ }
+
+ return null;
+}
+
+function getStatelessPropsPath(componentDefinition: any) {
+ const value = resolveToValue(componentDefinition);
+ if (isReactForwardRefCall(value)) {
+ const inner = resolveToValue(value.get('arguments', 0));
+ return inner.get('params', 0);
+ }
+ return value.get('params', 0);
+}
+
+function getDefaultPropsPath(componentDefinition: any) {
+ let defaultPropsPath = getMemberValuePath(componentDefinition, 'defaultProps');
+ if (!defaultPropsPath) {
+ return null;
+ }
+
+ defaultPropsPath = resolveToValue(defaultPropsPath);
+ if (!defaultPropsPath) {
+ return null;
+ }
+
+ if (t.FunctionExpression.check(defaultPropsPath.node)) {
+ // Find the value that is returned from the function and process it if it is
+ // an object literal.
+ const returnValue = resolveFunctionDefinitionToReturnValue(defaultPropsPath);
+ if (returnValue && t.ObjectExpression.check(returnValue.node)) {
+ defaultPropsPath = returnValue;
+ }
+ }
+ return defaultPropsPath;
+}
+
+function getDefaultValuesFromProps(properties: any[], documentation: any, isStateless: boolean) {
+ properties
+ // Don't evaluate property if component is functional and the node is not an AssignmentPattern
+ .filter(
+ (propertyPath) => !isStateless || t.AssignmentPattern.check(propertyPath.get('value').node),
+ )
+ .forEach((propertyPath) => {
+ if (t.Property.check(propertyPath.node)) {
+ const propName = getPropertyName(propertyPath);
+ if (!propName) return;
+
+ const propDescriptor = documentation.getPropDescriptor(propName);
+ const defaultValue = getDefaultValue(
+ isStateless ? propertyPath.get('value', 'right') : propertyPath.get('value'),
+ );
+ if (defaultValue) {
+ propDescriptor.defaultValue = defaultValue;
+ }
+ } else if (t.SpreadElement.check(propertyPath.node)) {
+ const resolvedValuePath = resolveToValue(propertyPath.get('argument'));
+ if (t.ObjectExpression.check(resolvedValuePath.node)) {
+ getDefaultValuesFromProps(
+ resolvedValuePath.get('properties'),
+ documentation,
+ isStateless,
+ );
+ }
+ }
+ });
+}
+
+export default function defaultPropsHandler(documentation: any, componentDefinition: any) {
+ let statelessProps = null;
+ let defaultPropsPath = getDefaultPropsPath(componentDefinition);
+ /**
+ * function, lazy, memo, forwardRef etc components can resolve default props as well
+ */
+ if (!isReactComponentClass(componentDefinition)) {
+ statelessProps = getStatelessPropsPath(componentDefinition);
+ }
+
+ // Do both statelessProps and defaultProps if both are available so defaultProps can override
+ if (statelessProps && t.ObjectPattern.check(statelessProps.node)) {
+ getDefaultValuesFromProps(statelessProps.get('properties'), documentation, true);
+ }
+ if (defaultPropsPath && !t.ObjectExpression.check(defaultPropsPath.node)) {
+ const composedPath = getComposedPath(documentation, 'defaultProps', defaultPropsPath);
+ if (composedPath) {
+ defaultPropsPath = composedPath;
+ }
+ }
+ if (defaultPropsPath && t.ObjectExpression.check(defaultPropsPath.node)) {
+ getDefaultValuesFromProps(defaultPropsPath.get('properties'), documentation, false);
+ }
+}
diff --git a/modules/material-parser/src/parse/js/handlers/index.ts b/modules/material-parser/src/parse/js/handlers/index.ts
new file mode 100644
index 0000000000..46f6abd4ec
--- /dev/null
+++ b/modules/material-parser/src/parse/js/handlers/index.ts
@@ -0,0 +1,22 @@
+import { propTypeHandler, contextTypeHandler, childContextTypeHandler } from './propTypeHandler';
+import defaultPropsHandler from './defaultPropsHandler';
+import preProcessHandler from './preProcessHandler';
+import propTypeJsDocHandler from './propTypeJsDocHandler';
+
+const { handlers } = require('react-docgen');
+
+const defaultHandlers = [
+ preProcessHandler,
+ handlers.propTypeCompositionHandler,
+ propTypeHandler,
+ contextTypeHandler,
+ childContextTypeHandler,
+ handlers.propDocBlockHandler,
+ propTypeJsDocHandler,
+ defaultPropsHandler,
+ handlers.componentDocblockHandler,
+ handlers.displayNameHandler,
+ handlers.componentMethodsJsDocHandler,
+];
+
+export default defaultHandlers;
diff --git a/modules/material-parser/src/parse/js/handlers/preProcessHandler.ts b/modules/material-parser/src/parse/js/handlers/preProcessHandler.ts
new file mode 100644
index 0000000000..48541c55bb
--- /dev/null
+++ b/modules/material-parser/src/parse/js/handlers/preProcessHandler.ts
@@ -0,0 +1,3 @@
+export default function preProcessHandler(documentation: any, path: any) {
+ documentation.set('meta', path.__meta);
+}
diff --git a/modules/material-parser/src/parse/js/handlers/propTypeHandler.ts b/modules/material-parser/src/parse/js/handlers/propTypeHandler.ts
new file mode 100644
index 0000000000..85930ee10b
--- /dev/null
+++ b/modules/material-parser/src/parse/js/handlers/propTypeHandler.ts
@@ -0,0 +1,139 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ */
+
+import { namedTypes as t, visit } from 'ast-types';
+import fs from 'fs';
+import path from 'path';
+import getRoot from '../utils/getRoot';
+import findJSFilePath from '../utils/findJSFilePath';
+import getComposedPath from '../utils/getComposedPath';
+const buildParser = require('react-docgen/dist/babelParser').default;
+
+const {
+ resolveToValue,
+ isExportsOrModuleAssignment,
+ getPropType,
+ getPropertyName,
+ getMemberValuePath,
+ isReactModuleName,
+ printValue,
+ resolveToModule,
+} = require('react-docgen').utils;
+
+const expressionTo = require('react-docgen/dist/utils/expressionTo');
+const isRequiredPropType = require('react-docgen/dist/utils/isRequiredPropType')
+ .default;
+
+function isPropTypesExpression(path: any) {
+ const moduleName = resolveToModule(path);
+ if (moduleName) {
+ return isReactModuleName(moduleName) || moduleName === 'ReactPropTypes';
+ }
+ return false;
+}
+
+function amendPropTypes(getDescriptor: any, path: any, documentation, propName: string) {
+ if (!t.ObjectExpression.check(path.node)) {
+ const propTypesPath = getComposedPath(documentation, propName, path);
+ if (!propTypesPath) {
+ return;
+ } else {
+ path.replace(propTypesPath.node);
+ }
+ }
+
+ path.get('properties').each((propertyPath: any) => {
+ switch (propertyPath.node.type) {
+ // @ts-ignore
+ case t.Property.name: {
+ const propName = getPropertyName(propertyPath);
+ if (!propName) return;
+
+ const propDescriptor = getDescriptor(propName);
+ const valuePath = propertyPath.get('value');
+ const type = getPropType(valuePath);
+
+ if (type) {
+ propDescriptor.type = type;
+ propDescriptor.required =
+ type.name !== 'custom' && isRequiredPropType(valuePath);
+ }
+ break;
+ }
+ // @ts-ignore
+ case t.SpreadElement.name: {
+ const resolvedValuePath = resolveToValue(propertyPath.get('argument'));
+ switch (resolvedValuePath.node.type) {
+ // @ts-ignore
+ case t.ObjectExpression.name: // normal object literal
+ amendPropTypes(getDescriptor, resolvedValuePath, documentation, propName);
+ break;
+ }
+ break;
+ }
+ }
+ });
+}
+
+function getDefinePropertyValuePath(nodePath: any, propName: string) {
+ const program = getRoot(nodePath);
+ let resultPath = nodePath;
+ if (!nodePath.node.id) return;
+ const componentName = nodePath.node.id.name;
+
+ visit(program, {
+ visitCallExpression(path) {
+ const args = path.get('arguments');
+ const argsNodeList = args.value;
+ if (
+ argsNodeList.length === 3 &&
+ t.Identifier.check(argsNodeList[0]) &&
+ argsNodeList[0].name === componentName &&
+ t.Literal.check(argsNodeList[1]) &&
+ argsNodeList[1].value === propName
+ ) {
+ resultPath = args.get(2);
+ }
+ return false;
+ },
+ });
+ return resultPath;
+}
+
+function getPropTypeHandler(propName: string) {
+ return function (documentation: any, path: any) {
+ let propTypesPath = getMemberValuePath(path, propName);
+ if (!propTypesPath) {
+ propTypesPath = getDefinePropertyValuePath(path, propName);
+ if (!propTypesPath) {
+ return;
+ }
+ }
+ propTypesPath = resolveToValue(propTypesPath);
+ if (!propTypesPath) {
+ return;
+ }
+ let getDescriptor;
+ switch (propName) {
+ case 'childContextTypes':
+ getDescriptor = documentation.getChildContextDescriptor;
+ break;
+ case 'contextTypes':
+ getDescriptor = documentation.getContextDescriptor;
+ break;
+ default:
+ getDescriptor = documentation.getPropDescriptor;
+ }
+ amendPropTypes(getDescriptor.bind(documentation), propTypesPath, documentation, propName);
+ };
+}
+
+export const propTypeHandler = getPropTypeHandler('propTypes');
+export const contextTypeHandler = getPropTypeHandler('contextTypes');
+export const childContextTypeHandler = getPropTypeHandler('childContextTypes');
diff --git a/modules/material-parser/src/parse/js/handlers/propTypeJsDocHandler.ts b/modules/material-parser/src/parse/js/handlers/propTypeJsDocHandler.ts
new file mode 100644
index 0000000000..7fd160c8bd
--- /dev/null
+++ b/modules/material-parser/src/parse/js/handlers/propTypeJsDocHandler.ts
@@ -0,0 +1,64 @@
+/* eslint-disable no-param-reassign */
+import { set, get } from 'lodash';
+import { debug } from '../../../core';
+
+const log = debug.extend('parse:js');
+
+const parseJsDoc = require('react-docgen/dist/utils/parseJsDoc').default;
+const { getMemberValuePath, resolveToValue } = require('react-docgen').utils;
+
+function getType(type = 'void') {
+ const typeOfType = typeof type;
+ if (typeOfType === 'string') {
+ return typeOfType;
+ } else if (typeOfType === 'object') {
+ return get(type, 'name', 'void');
+ }
+ return 'void';
+}
+
+function generateRaw(params = [], returns = { type: 'void' }): string {
+ const raw = `(${params.filter(x => !!x).map(x => `${x.name}: ${getType(x.type)}`).join(', ')}) => ${returns ? getType(returns.type) : 'void'}`;
+ return raw;
+}
+
+function resolveDocumentation(documentation) {
+ documentation._props.forEach(propDescriptor => {
+ const { description } = propDescriptor;
+ if (description.includes('@') && propDescriptor?.type?.name === 'func') {
+ const jsDoc = parseJsDoc(description);
+ propDescriptor.description = jsDoc.description;
+ if (jsDoc.params) {
+ set(propDescriptor, ['type', 'params'], jsDoc.params);
+ }
+ if (jsDoc.returns) {
+ set(propDescriptor, ['type', 'returns'], jsDoc.returns);
+ }
+ try {
+ const raw = generateRaw(jsDoc.params, jsDoc.returns);
+ if (raw) {
+ set(propDescriptor, ['type', 'raw'], raw);
+ }
+ } catch (e) {
+ log(e);
+ }
+ }
+ });
+}
+
+/**
+ * Extract info from the propType jsdoc blocks. Must be run after
+ * propDocBlockHandler.
+ */
+export default function propTypeJsDocHandler(documentation, path) {
+ let propTypesPath = getMemberValuePath(path, 'propTypes');
+ if (!propTypesPath) {
+ return;
+ }
+ propTypesPath = resolveToValue(propTypesPath);
+ if (!propTypesPath) {
+ return;
+ }
+
+ resolveDocumentation(documentation);
+}
diff --git a/modules/material-parser/src/parse/js/index.ts b/modules/material-parser/src/parse/js/index.ts
new file mode 100644
index 0000000000..283b6bf988
--- /dev/null
+++ b/modules/material-parser/src/parse/js/index.ts
@@ -0,0 +1,42 @@
+import { transformItem } from '../transform';
+import { IMaterialParsedModel } from '../../types';
+import { loadFile } from '../../utils';
+import resolver from './resolver';
+import handlers from './handlers';
+
+const reactDocs = require('react-docgen');
+
+export default function parse(filePath: string): IMaterialParsedModel[] {
+ if (!filePath) return [];
+ const fileContent = loadFile(filePath);
+ const result = reactDocs.parse(
+ fileContent,
+ (ast: any) => {
+ ast.__path = filePath;
+ return resolver(ast);
+ },
+ handlers,
+ {
+ filename: filePath,
+ },
+ );
+ const coms = result.reduce((res: any[], info: any) => {
+ if (!info || !info.props) return res;
+ const props = Object.keys(info.props).reduce((acc: any[], name) => {
+ try {
+ const item: any = transformItem(name, info.props[name]);
+ acc.push(item);
+ } catch (e) {
+ // TODO
+ }
+ return acc;
+ }, []);
+ res.push({
+ componentName: info.displayName,
+ props,
+ meta: info.meta || {},
+ });
+ return res;
+ }, []);
+ return coms;
+}
diff --git a/modules/material-parser/src/parse/js/resolver/checkIsIIFE.ts b/modules/material-parser/src/parse/js/resolver/checkIsIIFE.ts
new file mode 100644
index 0000000000..4e56be8914
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/checkIsIIFE.ts
@@ -0,0 +1,8 @@
+export default function checkIsIIFE(path: any) {
+ return (
+ path.value &&
+ path.value.callee &&
+ path.value.callee.type === 'FunctionExpression' &&
+ path.node.type === 'CallExpression'
+ );
+}
diff --git a/modules/material-parser/src/parse/js/resolver/findAssignedMethods.ts b/modules/material-parser/src/parse/js/resolver/findAssignedMethods.ts
new file mode 100644
index 0000000000..e14a40ac12
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/findAssignedMethods.ts
@@ -0,0 +1,37 @@
+import { namedTypes as t } from 'ast-types';
+import isReactComponentStaticMember from './isReactComponentStaticMember';
+
+const { match } = require('react-docgen').utils;
+const { traverseShallow } = require('react-docgen/dist/utils/traverse');
+
+function findAssignedMethods(scope: any, idPath: any) {
+ const results: any[] = [];
+
+ if (!t.Identifier.check(idPath.node)) {
+ return results;
+ }
+
+ const { name } = idPath.node;
+ // const idScope = idPath.scope.lookup(idPath.node.name);
+
+ traverseShallow(scope.path, {
+ visitAssignmentExpression(path: any) {
+ const { node } = path;
+ if (
+ match(node.left, {
+ type: 'MemberExpression',
+ object: { type: 'Identifier', name },
+ })
+ // && path.scope.lookup(name) === idScope
+ ) {
+ results.push(path);
+ return false;
+ }
+ return this.traverse(path);
+ },
+ });
+
+ return results.filter((x) => !isReactComponentStaticMember(x.get('left')));
+}
+
+export default findAssignedMethods;
diff --git a/modules/material-parser/src/parse/js/resolver/index.ts b/modules/material-parser/src/parse/js/resolver/index.ts
new file mode 100644
index 0000000000..ba91757153
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/index.ts
@@ -0,0 +1,393 @@
+import { namedTypes as t, visit } from 'ast-types';
+import { uniqBy } from 'lodash';
+import checkIsIIFE from './checkIsIIFE';
+import resolveHOC from './resolveHOC';
+import resolveIIFE from './resolveIIFE';
+import resolveImport from './resolveImport';
+import resolveTranspiledClass from './resolveTranspiledClass';
+import isStaticMethod from './isStaticMethod';
+import findAssignedMethods from './findAssignedMethods';
+import resolveExportDeclaration from './resolveExportDeclaration';
+import makeProxy from '../utils/makeProxy';
+import { get, set, has, ICache } from '../utils/cache';
+import getName from '../utils/getName';
+import getRoot from '../utils/getRoot';
+
+const expressionTo = require('react-docgen/dist/utils/expressionTo');
+
+const {
+ isExportsOrModuleAssignment,
+ isReactComponentClass,
+ isReactCreateClassCall,
+ isReactForwardRefCall,
+ isStatelessComponent,
+ normalizeClassDefinition,
+ resolveToValue,
+ getMemberValuePath,
+} = require('react-docgen').utils;
+
+function ignore() {
+ return false;
+}
+
+function isComponentDefinition(path: any) {
+ return (
+ isReactCreateClassCall(path) ||
+ isReactComponentClass(path) ||
+ isStatelessComponent(path) ||
+ isReactForwardRefCall(path)
+ );
+}
+
+function resolveDefinition(definition: any) {
+ if (isReactCreateClassCall(definition)) {
+ // return argument
+ const resolvedPath = resolveToValue(definition.get('arguments', 0));
+ if (t.ObjectExpression.check(resolvedPath.node)) {
+ return resolvedPath;
+ }
+ } else if (isReactComponentClass(definition)) {
+ normalizeClassDefinition(definition);
+ return definition;
+ } else if (isStatelessComponent(definition) || isReactForwardRefCall(definition)) {
+ return definition;
+ }
+ return null;
+}
+
+function getDefinition(definition: any, cache: ICache = {}): any {
+ const { __meta: exportMeta = {} } = definition;
+ if (checkIsIIFE(definition)) {
+ definition = resolveToValue(resolveIIFE(definition));
+ if (!isComponentDefinition(definition)) {
+ definition = resolveTranspiledClass(definition);
+ }
+ } else {
+ definition = resolveToValue(resolveHOC(definition));
+ if (isComponentDefinition(definition)) {
+ definition = makeProxy(definition, {
+ __meta: exportMeta,
+ });
+ return definition;
+ }
+ if (checkIsIIFE(definition)) {
+ definition = resolveToValue(resolveIIFE(definition));
+ if (!isComponentDefinition(definition)) {
+ definition = resolveTranspiledClass(definition);
+ }
+ } else if (t.SequenceExpression.check(definition.node)) {
+ const classNameNode = definition.parent.get('id').node;
+ const localNames: string[] = [];
+ let { node } = definition.get('expressions', 0);
+ while (t.AssignmentExpression.check(node)) {
+ // @ts-ignore
+ const { name } = node.left;
+ if (name) {
+ localNames.push(name);
+ }
+ node = node.right;
+ }
+ definition.get('expressions').each((x: any) => {
+ if (!x.name) return;
+ if (t.AssignmentExpression.check(x.node) && t.MemberExpression.check(x.node.left)) {
+ const objectName = x.node.left.object.name;
+ if (localNames.includes(objectName)) {
+ x.get('left', 'object').replace(classNameNode);
+ }
+ }
+ });
+ definition = getDefinition(resolveToValue(definition.get('expressions').get(0)), cache);
+ } else {
+ return resolveImport(definition, (ast: any, sourcePath: string, importMeta, mode) => {
+ let result;
+ if (has('ast-export', ast.__path)) {
+ result = get('ast-export', ast.__path);
+ } else {
+ result = findAllExportedComponentDefinition(ast);
+ set('ast-export', ast.__path, result);
+ }
+
+ const exportList: any[] = [];
+ const importList: any[] = [];
+ result.forEach((def: any) => {
+ const { __meta: meta = {} } = def;
+ let { exportName } = meta;
+ for (const item of importMeta) {
+ if (exportName === item.importedName) {
+ exportName = item.localName;
+ break;
+ }
+ }
+
+ if (exportName) {
+ importList.push(makeProxy(def, { __meta: { exportName } }));
+ }
+
+ const nextMeta: any = {
+ exportName,
+ };
+
+ if (exportName === exportMeta.localName) {
+ nextMeta.exportName = exportMeta.exportName;
+ } else if (mode === 'import') {
+ // } else {
+ return;
+ }
+
+ if (exportMeta.subName) {
+ nextMeta.subName = exportMeta.subName;
+ } else if (meta.subName) {
+ nextMeta.subName = meta.subName;
+ }
+ exportList.push(makeProxy(def, { __meta: nextMeta }));
+ });
+ cache[sourcePath] = importList;
+
+ // result = result.filter((x) => !x.__shouldDelete);
+ return exportList;
+ });
+ }
+ }
+ if (definition && (!definition.__meta || Object.keys(definition.__meta).length === 0)) {
+ definition.__meta = exportMeta;
+ }
+ return definition;
+}
+
+export interface IMethodsPath {
+ subName: string;
+ localName: string;
+ value: any;
+}
+
+/**
+ * Extract all flow types for the methods of a react component. Doesn't
+ * return any react specific lifecycle methods.
+ */
+function getSubComponents(path: any, scope: any, cache: ICache) {
+ // Extract all methods from the class or object.
+ let methodPaths = [];
+ if (isReactComponentClass(path)) {
+ methodPaths = path.get('body', 'body').filter(isStaticMethod);
+ methodPaths = [...methodPaths, ...findAssignedMethods(scope || path.scope, path.get('id'))];
+ } else if (t.ObjectExpression.check(path.node)) {
+ methodPaths = path.get('properties').filter(isStaticMethod);
+ methodPaths = [...methodPaths, ...findAssignedMethods(scope || path.scope, path.get('id'))];
+ // Add the statics object properties.
+ const statics = getMemberValuePath(path, 'statics');
+ if (statics) {
+ statics.get('properties').each((p: any) => {
+ if (isStaticMethod(p)) {
+ p.node.static = true;
+ methodPaths.push(p);
+ }
+ });
+ }
+ } else if (
+ t.VariableDeclarator.check(path.parent.node) &&
+ path.parent.node.init === path.node &&
+ t.Identifier.check(path.parent.node.id)
+ ) {
+ methodPaths = findAssignedMethods(scope || path.parent.scope, path.parent.get('id'));
+ } else if (
+ t.AssignmentExpression.check(path.parent.node) &&
+ path.parent.node.right === path.node &&
+ t.Identifier.check(path.parent.node.left)
+ ) {
+ methodPaths = findAssignedMethods(scope || path.parent.scope, path.parent.get('left'));
+ } else if (t.FunctionDeclaration.check(path.node)) {
+ methodPaths = findAssignedMethods(scope || path.parent.scope, path.get('id'));
+ } else if (t.ArrowFunctionExpression.check(path.node)) {
+ methodPaths = findAssignedMethods(scope || path.parent.scope, path.parent.get('id'));
+ }
+
+ return (
+ methodPaths
+ .map((x: any) => {
+ if (t.ClassProperty.check(x.node)) {
+ return {
+ value: x.get('value'),
+ subName: x.node.key.name,
+ localName: getName(x.get('value')),
+ };
+ }
+ return {
+ value: x,
+ subName: x.node.left.property.name,
+ localName: getName(x.get('right')),
+ };
+ })
+ .map(({ subName, localName, value }: IMethodsPath) => ({
+ subName,
+ localName,
+ value: resolveToValue(value),
+ }))
+ .map(({ subName, localName, value }: IMethodsPath) => {
+ let def = getDefinition(
+ makeProxy(value, {
+ __meta: {
+ localName,
+ subName,
+ exportName: path.__meta && path.__meta.exportName,
+ },
+ }),
+ cache,
+ );
+ if (!Array.isArray(def)) {
+ def = [def];
+ }
+ return {
+ subName,
+ localName,
+ value: def.flatMap((x: any) => x).filter((x: any) => isComponentDefinition(x)),
+ };
+ })
+ .map(({ subName, localName, value }: IMethodsPath) => {
+ return value.map((x: any) => ({
+ subName,
+ localName,
+ value: x,
+ }));
+ })
+ // @ts-ignore
+ .flatMap((x: any) => x)
+ .map(({ subName, value }: IMethodsPath) => {
+ const __meta = {
+ subName,
+ exportName: path.__meta && path.__meta.exportName,
+ };
+ return makeProxy(value, { __meta });
+ })
+ );
+}
+
+/**
+ * Given an AST, this function tries to find the exported component definition.
+ *
+ * The component definition is either the ObjectExpression passed to
+ * `React.createClass` or a `class` definition extending `React.Component` or
+ * having a `render()` method.
+ *
+ * If a definition is part of the following statements, it is considered to be
+ * exported:
+ *
+ * modules.exports = Definition;
+ * exports.foo = Definition;
+ * export default Definition;
+ * export var Definition = ...;
+ */
+export default function findAllExportedComponentDefinition(ast: any) {
+ const components: any[] = [];
+ const cache: ICache = {};
+ let programScope: any;
+
+ function exportDeclaration(path: any) {
+ const definitions = resolveExportDeclaration(path)
+ .reduce((acc: any[], definition: any) => {
+ if (isComponentDefinition(definition)) {
+ acc.push(definition);
+ } else {
+ definition = getDefinition(definition, cache);
+ if (!Array.isArray(definition)) {
+ definition = [definition];
+ }
+ definition.forEach((def: any) => {
+ if (isComponentDefinition(def)) {
+ acc.push(def);
+ }
+ });
+ }
+ return acc;
+ }, [])
+ .map((definition: any) => {
+ const { __meta: meta } = definition;
+ const def = resolveDefinition(definition);
+ return makeProxy(def, { __meta: meta });
+ });
+
+ if (definitions.length === 0) {
+ return false;
+ }
+ definitions.forEach((definition: any) => {
+ if (definition && components.indexOf(definition) === -1) {
+ components.push(definition);
+ }
+ });
+ return false;
+ }
+
+ visit(ast, {
+ visitProgram(path) {
+ programScope = path.scope;
+ return this.traverse(path);
+ },
+ visitFunctionDeclaration: ignore,
+ visitFunctionExpression: ignore,
+ visitClassDeclaration: ignore,
+ visitClassExpression: ignore,
+ visitIfStatement: ignore,
+ visitWithStatement: ignore,
+ visitSwitchStatement: ignore,
+ visitWhileStatement: ignore,
+ visitDoWhileStatement: ignore,
+ visitForStatement: ignore,
+ visitForInStatement: ignore,
+ visitForOfStatement: ignore,
+ visitImportDeclaration: ignore,
+
+ visitExportNamedDeclaration: exportDeclaration,
+ visitExportDefaultDeclaration: exportDeclaration,
+ visitExportAllDeclaration(path) {
+ components.push(...resolveImport(path, findAllExportedComponentDefinition));
+ return false;
+ },
+
+ visitAssignmentExpression(path: any) {
+ // Ignore anything that is not `exports.X = ...;` or
+ // `module.exports = ...;`
+ if (!isExportsOrModuleAssignment(path)) {
+ return false;
+ }
+ const arr = expressionTo.Array(path.get('left'));
+ const meta: any = {
+ exportName: arr[1] === 'exports' ? 'default' : arr[1],
+ };
+ // Resolve the value of the right hand side. It should resolve to a call
+ // expression, something like React.createClass
+ path = resolveToValue(path.get('right'));
+ if (!isComponentDefinition(path)) {
+ path = getDefinition(path, cache);
+ }
+
+ if (!Array.isArray(path)) {
+ path = [path];
+ }
+
+ const definitions = path.map(resolveDefinition);
+
+ definitions.forEach((definition: any) => {
+ if (definition && components.indexOf(definition) === -1) {
+ // if (definition.__meta) {
+ definition = makeProxy(definition, {
+ __meta: meta,
+ });
+ // }
+ components.push(definition);
+ }
+ });
+ return false;
+ },
+ });
+
+ const result = components.reduce((acc, item) => {
+ let subModuleDefinitions = [];
+ subModuleDefinitions = getSubComponents(item, programScope, cache);
+ return [...acc, item, ...subModuleDefinitions];
+ }, []);
+
+ const res = uniqBy(result, (x: any) => {
+ return `${getRoot(x)?.node?.__path}/${x.__meta.exportName}/${x.__meta.subName}`;
+ });
+
+ return res;
+}
diff --git a/modules/material-parser/src/parse/js/resolver/isReactComponentStaticMember.ts b/modules/material-parser/src/parse/js/resolver/isReactComponentStaticMember.ts
new file mode 100644
index 0000000000..8249dfac30
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/isReactComponentStaticMember.ts
@@ -0,0 +1,14 @@
+import { namedTypes as t } from 'ast-types';
+
+const { getPropertyName } = require('react-docgen').utils;
+
+const reactStaticMembers = ['propTypes', 'defaultProps', 'contextTypes'];
+export default function isReactComponentStaticMember(methodPath: any) {
+ let name;
+ if (t.MemberExpression.check(methodPath.node)) {
+ name = methodPath.node.property.name;
+ } else {
+ name = getPropertyName(methodPath);
+ }
+ return !!name && reactStaticMembers.indexOf(name) !== -1;
+}
diff --git a/modules/material-parser/src/parse/js/resolver/isStaticMethod.ts b/modules/material-parser/src/parse/js/resolver/isStaticMethod.ts
new file mode 100644
index 0000000000..f8168fa8e7
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/isStaticMethod.ts
@@ -0,0 +1,15 @@
+import { namedTypes as t } from 'ast-types';
+import isReactComponentStaticMember from './isReactComponentStaticMember';
+
+const { isReactComponentMethod } = require('react-docgen').utils;
+
+/**
+ * judge if static method
+ */
+function isStaticMethod(path: any) {
+ const isProbablyStaticMethod = t.ClassProperty.check(path.node) && path.node.static === true;
+
+ return isProbablyStaticMethod && !isReactComponentStaticMember(path) && !isReactComponentMethod(path);
+}
+
+export default isStaticMethod;
diff --git a/modules/material-parser/src/parse/js/resolver/resolveExportDeclaration.ts b/modules/material-parser/src/parse/js/resolver/resolveExportDeclaration.ts
new file mode 100644
index 0000000000..5e8875975c
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/resolveExportDeclaration.ts
@@ -0,0 +1,53 @@
+import { namedTypes as t } from 'ast-types';
+import makeProxy from '../utils/makeProxy';
+import getName from '../utils/getName';
+
+export default function resolveExportDeclaration(path: any) {
+ const definitions = [];
+ if (path.node.default || t.ExportDefaultDeclaration.check(path.node)) {
+ const def = path.get('declaration');
+ const meta: { [name: string]: string } = {
+ exportName: 'default',
+ localName: getName(def),
+ };
+
+ definitions.push(makeProxy(def, { __meta: meta }));
+ } else if (path.node.declaration) {
+ if (t.VariableDeclaration.check(path.node.declaration)) {
+ path.get('declaration', 'declarations').each((declarator: any) => {
+ definitions.push(
+ makeProxy(declarator, {
+ __meta: {
+ exportName: declarator.get('id').node.name,
+ },
+ }),
+ );
+ });
+ } else {
+ const def = path.get('declaration');
+ definitions.push(
+ makeProxy(def, {
+ __meta: {
+ exportName: 'default',
+ },
+ }),
+ );
+ }
+ } else if (path.node.specifiers) {
+ path.get('specifiers').each((specifier: any) => {
+ const def = specifier.node.id ? specifier.get('id') : specifier.get('local');
+ const exportName = specifier.get('exported').node.name;
+ const localName = def.get('local').node.name;
+
+ definitions.push(
+ makeProxy(def, {
+ __meta: {
+ exportName,
+ localName,
+ },
+ }),
+ );
+ });
+ }
+ return definitions;
+}
diff --git a/modules/material-parser/src/parse/js/resolver/resolveHOC.ts b/modules/material-parser/src/parse/js/resolver/resolveHOC.ts
new file mode 100644
index 0000000000..ab62f895ff
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/resolveHOC.ts
@@ -0,0 +1,42 @@
+import { namedTypes as t } from 'ast-types';
+
+const { isReactCreateClassCall, isReactForwardRefCall } = require('react-docgen').utils;
+
+/**
+ * If the path is a call expression, it recursively resolves to the
+ * rightmost argument, stopping if it finds a React.createClass call expression
+ *
+ * Else the path itself is returned.
+ */
+export default function resolveHOC(path: any): any {
+ const { node } = path;
+ if (
+ t.CallExpression.check(node) &&
+ !isReactCreateClassCall(path) &&
+ !isReactForwardRefCall(path)
+ ) {
+ if (node.arguments.length) {
+ const inner = path.get('arguments', 0);
+
+ // If the first argument is one of these types then the component might be the last argument
+ // If there are all identifiers then we cannot figure out exactly and have to assume it is the first
+ if (
+ node.arguments.length > 1 &&
+ (t.Literal.check(inner.node) ||
+ t.ObjectExpression.check(inner.node) ||
+ t.ArrayExpression.check(inner.node) ||
+ t.SpreadElement.check(inner.node))
+ ) {
+ return resolveHOC(
+ // resolveToValue(path.get('arguments', node.arguments.length - 1)),
+ path.get('arguments', node.arguments.length - 1),
+ );
+ }
+
+ // return resolveHOC(resolveToValue(inner));
+ return resolveHOC(inner);
+ }
+ }
+
+ return path;
+}
diff --git a/modules/material-parser/src/parse/js/resolver/resolveIIFE.ts b/modules/material-parser/src/parse/js/resolver/resolveIIFE.ts
new file mode 100644
index 0000000000..371cde5fb9
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/resolveIIFE.ts
@@ -0,0 +1,20 @@
+import checkIsIIFE from './checkIsIIFE';
+
+const resolveFunctionDefinitionToReturnValue = require('react-docgen/dist/utils/resolveFunctionDefinitionToReturnValue')
+ .default;
+/**
+ * If the path is a call expression, it recursively resolves to the
+ * rightmost argument, stopping if it finds a React.createClass call expression
+ *
+ * Else the path itself is returned.
+ */
+export default function resolveIIFE(path: any) {
+ if (!checkIsIIFE(path)) {
+ return path;
+ }
+ const returnValue = resolveFunctionDefinitionToReturnValue(
+ path.get('callee'),
+ );
+
+ return returnValue;
+}
diff --git a/modules/material-parser/src/parse/js/resolver/resolveImport.ts b/modules/material-parser/src/parse/js/resolver/resolveImport.ts
new file mode 100644
index 0000000000..2acefff6fc
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/resolveImport.ts
@@ -0,0 +1,178 @@
+import { namedTypes as t } from 'ast-types';
+import fs from 'fs';
+import p from 'path';
+import getRoot from '../utils/getRoot';
+
+const { resolveToModule, resolveToValue, match } = require('react-docgen').utils;
+
+export function isImportLike(path) {
+ const { node } = path;
+ return (
+ t.ImportDeclaration.check(node) ||
+ t.ExportAllDeclaration.check(node) ||
+ t.ExportNamedDeclaration.check(node)
+ );
+}
+
+export function isRequireLike(path: any) {
+ if (
+ t.CallExpression.check(path.node) &&
+ t.Identifier.check(path.get('callee').node) &&
+ path.get('callee').node.name === 'require' &&
+ t.Literal.check(path.get('arguments', 0)?.node)
+ ) {
+ return true;
+ }
+
+ return false;
+}
+
+export function resolveToImport(initialPath) {
+ const pathBuffer = [initialPath];
+
+ while (pathBuffer.length) {
+ let path = pathBuffer.shift();
+ const node = path.node;
+ switch (node.type) {
+ case 'VariableDeclarator':
+ if (node.init) {
+ pathBuffer.unshift(path.get('init'));
+ }
+ break;
+ case 'CallExpression': {
+ if (match(node.callee, { type: 'Identifier', name: 'require' })) {
+ return path;
+ }
+ const paths = [path.get('callee')];
+ const argumentsPath = path.get('arguments');
+ for (let index = 0; index < argumentsPath.value.length; index++) {
+ paths.push(argumentsPath.get(index));
+ }
+ pathBuffer.unshift(...paths);
+ }
+ case 'Identifier':
+ case 'JSXIdentifier': {
+ const valuePath = resolveToValue(path);
+ if (valuePath !== path) {
+ pathBuffer.unshift(valuePath);
+ }
+ break;
+ }
+ case 'ImportDeclaration':
+ return path;
+ case 'MemberExpression':
+ while (path && t.MemberExpression.check(path.node)) {
+ path = path.get('object');
+ }
+ if (path) {
+ pathBuffer.unshift(path);
+ }
+ }
+ }
+
+ return null;
+}
+
+function getPath(path: any, name: any) {
+ const root = getRoot(path).node;
+ if (!root) return;
+ let { __path } = root;
+ __path = p.dirname(__path);
+ // is directory
+ if (fs.existsSync(p.resolve(__path, name))) {
+ name += '/index';
+ }
+ const suffix = suffixes.find((suf) => {
+ return fs.existsSync(p.resolve(__path, name + suf));
+ });
+ if (!suffix) return;
+ return p.resolve(__path, name + suffix);
+}
+
+const buildParser = require('react-docgen/dist/babelParser').default;
+
+const suffixes = ['.js', '.jsx', '.ts', '.tsx'];
+
+const cache: {
+ [name: string]: any;
+} = {};
+
+export default function resolveImport(path: any, callback: any) {
+ let name;
+ let mode: 'import' | 'require' = 'import';
+
+ let importPath;
+ if (path.name === 'local') {
+ name = path.parentPath.parentPath.parentPath.node.source.value;
+ importPath = path;
+ } else {
+ importPath = resolveToImport(path);
+ if (!importPath) {
+ return path;
+ }
+ if (isImportLike(importPath)) {
+ name = importPath.node.source.value;
+ } else if (isRequireLike(importPath)) {
+ const moduleName = resolveToModule(importPath);
+ if (typeof moduleName === 'string') {
+ mode = 'require';
+ name = moduleName;
+ }
+ } else {
+ return path;
+ }
+ }
+
+ if (name) {
+ const __path = getPath(path, name);
+ if (!__path) return path;
+ let ast;
+ if (!cache[__path]) {
+ const fileContent = fs.readFileSync(__path, 'utf8');
+ const parser = buildParser({ filename: __path });
+ ast = parser.parse(fileContent);
+ ast.__src = fileContent;
+ ast.__path = __path;
+ cache[__path] = ast;
+ } else {
+ ast = cache[__path];
+ }
+
+ const importMeta: any[] = [];
+ if (mode === 'import') {
+ if (t.ImportDeclaration.check(importPath.node)) {
+ // @ts-ignore
+ const specifiers = importPath.get('specifiers');
+ specifiers.each((spec: any) => {
+ const { node } = spec;
+ importMeta.push({
+ localName: node.local.name,
+ importedName: node.imported ? node.imported.name : 'default',
+ });
+ });
+ }
+ } else {
+ const idPath = importPath.parentPath.get('id');
+ if (t.Identifier.check(idPath.node)) {
+ importMeta.push({
+ localName: 'default',
+ importedName: idPath.node.name,
+ });
+ } else if (t.ObjectPattern.check(path.node)) {
+ path.get('properties').each((propertyPath) => {
+ const keyPath = propertyPath.get('key');
+ const valuePath = propertyPath.get('value');
+ if (t.Identifier.check(keyPath.node) && t.Identifier.check(valuePath.node)) {
+ importMeta.push({
+ localName: keyPath.node.name,
+ importedName: valuePath.node.name,
+ });
+ }
+ });
+ }
+ }
+
+ return callback(ast, __path, importMeta, mode);
+ }
+ return path;
+}
diff --git a/modules/material-parser/src/parse/js/resolver/resolveTranspiledClass.ts b/modules/material-parser/src/parse/js/resolver/resolveTranspiledClass.ts
new file mode 100644
index 0000000000..992d0321b1
--- /dev/null
+++ b/modules/material-parser/src/parse/js/resolver/resolveTranspiledClass.ts
@@ -0,0 +1,31 @@
+import { builders, NodePath, visit } from 'ast-types';
+/**
+ * If the path is a call expression, it recursively resolves to the
+ * rightmost argument, stopping if it finds a React.createClass call expression
+ *
+ * Else the path itself is returned.
+ */
+export default function resolveTranspiledClass(path: any) {
+ let classPath = path;
+ visit(path, {
+ visitFunctionDeclaration(arg) {
+ classPath = new NodePath(
+ builders.functionDeclaration(
+ // @ts-ignore
+ arg.node.id || 'Default',
+ [],
+ builders.blockStatement([
+ builders.returnStatement(
+ builders.jsxElement(
+ builders.jsxOpeningElement(builders.jsxIdentifier('div'), [], true),
+ ),
+ ),
+ ]),
+ ),
+ path.parent,
+ );
+ return false;
+ },
+ });
+ return classPath;
+}
diff --git a/modules/material-parser/src/parse/js/utils/cache.ts b/modules/material-parser/src/parse/js/utils/cache.ts
new file mode 100644
index 0000000000..c8bcabb8d0
--- /dev/null
+++ b/modules/material-parser/src/parse/js/utils/cache.ts
@@ -0,0 +1,18 @@
+export interface ICache {
+ [name: string]: any;
+}
+
+const cache: ICache = {};
+
+export function set(scope: string, name: string, value: any) {
+ cache[scope] = cache[scope] || {};
+ cache[scope][name] = value;
+}
+
+export function get(scope: string, name: string) {
+ return (cache[scope] || {})[name];
+}
+
+export function has(scope: string, name: string) {
+ return cache[scope] && Object.prototype.hasOwnProperty.call(cache[scope], name);
+}
diff --git a/modules/material-parser/src/parse/js/utils/evaluate.ts b/modules/material-parser/src/parse/js/utils/evaluate.ts
new file mode 100644
index 0000000000..91388d2ba8
--- /dev/null
+++ b/modules/material-parser/src/parse/js/utils/evaluate.ts
@@ -0,0 +1,103 @@
+const { namedTypes: t } = require('ast-types');
+
+const { resolveToValue } = require('react-docgen').utils;
+
+function isInfinity(path) {
+ return t.Identifier.check(path.node) && path.node.name === 'Infinity';
+}
+
+function wrapValue(value, confident = true) {
+ return {
+ value,
+ confident,
+ };
+}
+
+export default function evaluate(path: any) {
+ if (t.UnaryExpression.check(path.node)) {
+ if (path.node.operator === 'void') {
+ return wrapValue(undefined);
+ }
+
+ const argument = path.get('argument');
+
+ const result = evaluate(argument);
+ if (!result.confident) {
+ return wrapValue(undefined, false);
+ }
+
+ const arg = result.value;
+ if (arg === undefined) {
+ return wrapValue(undefined);
+ }
+
+ switch (path.node.operator) {
+ case '!':
+ return wrapValue(!arg);
+ case '+':
+ return wrapValue(+arg);
+ case '-':
+ return wrapValue(-arg);
+ case '~':
+ return wrapValue(~arg);
+ case 'typeof':
+ return wrapValue(typeof arg);
+ }
+ }
+
+ if (t.Identifier.check(path.node)) {
+ const valuePath = resolveToValue(path);
+ if (isInfinity(valuePath)) {
+ return wrapValue(undefined);
+ }
+ return evaluate(valuePath);
+ }
+
+ if (t.Literal.check(path.node)) {
+ return wrapValue(path.node.value);
+ }
+
+ if (t.ObjectExpression.check(path.node)) {
+ const returnValue = {};
+ path.get('properties').each((propertyPath) => {
+ const { confident, value } = evaluate(propertyPath.get('value'));
+ if (!confident) {
+ return;
+ }
+ const keyPath = propertyPath.get('key');
+ let key;
+ if (keyPath.node.computed) {
+ const result = evaluate(keyPath);
+ if (!result.confident) {
+ return;
+ }
+ key = result.value;
+ } else {
+ key = keyPath.node.name;
+ }
+ returnValue[key] = value;
+ });
+
+ return wrapValue(returnValue);
+ }
+
+ if (t.ArrayExpression.check(path.node)) {
+ const value = [];
+ let isValid = true;
+ path.get('elements').each((x) => {
+ if (!isValid) return;
+ const result = evaluate(x);
+ if (!result.confident) {
+ isValid = false;
+ } else {
+ value.push(result.value);
+ }
+ });
+
+ if (isValid) {
+ return wrapValue(value);
+ }
+ }
+
+ return wrapValue(undefined, false);
+}
diff --git a/modules/material-parser/src/parse/js/utils/findJSFilePath.ts b/modules/material-parser/src/parse/js/utils/findJSFilePath.ts
new file mode 100644
index 0000000000..d5ec20518f
--- /dev/null
+++ b/modules/material-parser/src/parse/js/utils/findJSFilePath.ts
@@ -0,0 +1,15 @@
+import fs from 'fs';
+
+const suffixes = ['js', 'jsx'];
+export default function findJSFilePath(fileBasePath: string): string {
+ let filePath;
+ for (const suffix of suffixes) {
+ const fp = `${fileBasePath}.${suffix}`;
+ if (fs.existsSync(fp)) {
+ filePath = fp;
+ break;
+ }
+ }
+
+ return filePath;
+}
\ No newline at end of file
diff --git a/modules/material-parser/src/parse/js/utils/getComposedPath.ts b/modules/material-parser/src/parse/js/utils/getComposedPath.ts
new file mode 100644
index 0000000000..471af46a48
--- /dev/null
+++ b/modules/material-parser/src/parse/js/utils/getComposedPath.ts
@@ -0,0 +1,51 @@
+import { namedTypes as t, visit } from 'ast-types';
+import fs from 'fs';
+import path from 'path';
+import getRoot from './getRoot';
+import findJSFilePath from './findJSFilePath';
+
+const buildParser = require('react-docgen/dist/babelParser').default;
+const expressionTo = require('react-docgen/dist/utils/expressionTo');
+
+const {
+ resolveToValue,
+ isExportsOrModuleAssignment,
+} = require('react-docgen').utils;
+
+export default function getComposedPropTypesPath(documentation, propName, p) {
+ const composes: string[] = Array.from(documentation._composes);
+ let _path = null;
+ const root = getRoot(p).node;
+ for (const compose of composes) {
+ const composePath = findJSFilePath(path.resolve(path.dirname(root.__path), compose));
+ if (!composePath) continue;
+
+ const fileContent = fs.readFileSync(composePath, 'utf8');
+ const parser = buildParser({ filename: composePath });
+ const ast = parser.parse(fileContent);
+
+ visit(ast, {
+ visitAssignmentExpression(path: any) {
+ // Ignore anything that is not `exports.X = ...;` or
+ // `module.exports = ...;`
+ if (!isExportsOrModuleAssignment(path)) {
+ return false;
+ }
+ const arr = expressionTo.Array(path.get('left'));
+ if (!(arr[0] === 'exports' && arr[1] === propName)) return false;
+
+ // Resolve the value of the right hand side. It should resolve to a call
+ // expression, something like React.createClass
+ path = resolveToValue(path.get('right'));
+ _path = path;
+ return false;
+ },
+ });
+
+ if (_path) {
+ break;
+ }
+ }
+
+ return _path;
+}
\ No newline at end of file
diff --git a/modules/material-parser/src/parse/js/utils/getName.ts b/modules/material-parser/src/parse/js/utils/getName.ts
new file mode 100644
index 0000000000..81f48cc715
--- /dev/null
+++ b/modules/material-parser/src/parse/js/utils/getName.ts
@@ -0,0 +1,13 @@
+import { namedTypes as t } from 'ast-types';
+
+export default function (def: any) {
+ let name = '';
+ if (def.node.name) {
+ name = def.node.name;
+ // hoc
+ } else if (t.CallExpression.check(def.node)) {
+ if (def.node.arguments && def.node.arguments.length && t.Identifier.check(def.get('arguments', 0).node)) name = def.get('arguments', 0).node.name;
+ }
+
+ return name;
+}
diff --git a/modules/material-parser/src/parse/js/utils/getRoot.ts b/modules/material-parser/src/parse/js/utils/getRoot.ts
new file mode 100644
index 0000000000..3a20579d31
--- /dev/null
+++ b/modules/material-parser/src/parse/js/utils/getRoot.ts
@@ -0,0 +1,7 @@
+export default function getRoot(path: any) {
+ let root = path.parent;
+ while (root.parent) {
+ root = root.parent;
+ }
+ return root;
+}
diff --git a/modules/material-parser/src/parse/js/utils/makeProxy.ts b/modules/material-parser/src/parse/js/utils/makeProxy.ts
new file mode 100644
index 0000000000..4f6c7ace15
--- /dev/null
+++ b/modules/material-parser/src/parse/js/utils/makeProxy.ts
@@ -0,0 +1,23 @@
+function makeProxy(target: { [name: string]: any }, meta: any = {}): any {
+ if (target.__isProxy) {
+ const value = target.__getRaw();
+ const rawMeta = target.__getMeta();
+ return makeProxy(value, Object.assign({}, rawMeta, meta));
+ }
+ return new Proxy(target, {
+ get: (obj, prop: string | number) => {
+ if (prop === '__isProxy') return true;
+ if (prop === '__getRaw') return () => target;
+ if (prop === '__getMeta') return () => meta;
+ return Object.prototype.hasOwnProperty.call(meta, prop) ? meta[prop] : obj[prop];
+ },
+ has: (obj, prop) => {
+ return (
+ Object.prototype.hasOwnProperty.call(obj, prop) ||
+ Object.prototype.hasOwnProperty.call(meta, prop)
+ );
+ },
+ });
+}
+
+export default makeProxy;
diff --git a/modules/material-parser/src/parse/transform.ts b/modules/material-parser/src/parse/transform.ts
new file mode 100644
index 0000000000..6325be8b49
--- /dev/null
+++ b/modules/material-parser/src/parse/transform.ts
@@ -0,0 +1,306 @@
+import { omit, pick, isNil, uniq } from 'lodash';
+import { safeEval, isEvaluable } from '../utils';
+import { debug } from '../core';
+
+const log = debug.extend('parse:transform');
+
+export function transformType(itemType: any) {
+ if (typeof itemType === 'string') return itemType;
+ const {
+ name,
+ elements,
+ value = elements,
+ computed,
+ required,
+ type,
+ raw,
+ params,
+ returns,
+ } = itemType;
+ if (computed !== undefined && value) {
+ return safeEval(value);
+ }
+ const result: any = {
+ type: name,
+ };
+ if (required) {
+ result.isRequired = required;
+ }
+ switch (name) {
+ case 'number':
+ case 'string':
+ case 'bool':
+ case 'any':
+ case 'symbol':
+ case 'object':
+ case 'null':
+ case 'array':
+ case 'element':
+ case 'node':
+ case 'void':
+ break;
+ case 'func':
+ if (params) {
+ result.params = params.map((x) => {
+ const res: any = {
+ name: x.name,
+ propType: transformType(x.type || x.propType),
+ };
+ if (x.description) {
+ res.description = x.description;
+ }
+ return res;
+ });
+ }
+ if (returns) {
+ result.returns = {
+ propType: transformType(returns.type || returns.propType),
+ };
+ }
+ if (raw) {
+ result.raw = raw;
+ }
+ break;
+ case 'literal': {
+ result.type = 'oneOf';
+ try {
+ const literalValue = safeEval(value);
+ result.value = [literalValue];
+ } catch (e) {
+ result.value = [raw];
+ }
+ break;
+ }
+ case 'enum':
+ case 'oneOf':
+ result.type = 'oneOf';
+ result.value = value.map(transformType);
+ break;
+ case 'tuple':
+ result.type = 'tuple';
+ result.value = value.map(transformType);
+ break;
+ case 'union': {
+ if (itemType.raw) {
+ if (itemType.raw.match(/ReactNode$/)) {
+ result.type = 'node';
+ break;
+ } else if (itemType.raw.match(/Element$/)) {
+ result.type = 'element';
+ break;
+ }
+ }
+ }
+ // eslint-disable-next-line no-fallthrough
+ case 'oneOfType':
+ result.type = 'oneOfType';
+ result.value = value.map(transformType);
+ break;
+ case 'boolean':
+ result.type = 'bool';
+ break;
+ case 'Function':
+ result.type = 'func';
+ break;
+ case 'unknown':
+ result.type = 'any';
+ break;
+ case 'Array':
+ case 'arrayOf': {
+ result.type = 'arrayOf';
+ let _itemType = transformType(value[0]);
+ if (typeof _itemType === 'object') {
+ _itemType = omit(_itemType, ['isRequired']);
+ }
+
+ result.value = _itemType;
+ break;
+ }
+ case 'signature': {
+ if (typeof type === 'string') {
+ result.type = type;
+ break;
+ }
+ result.type = 'shape';
+ const properties = type?.signature?.properties || itemType?.signature?.properties || [];
+ if (properties.length === 0) {
+ if (raw?.includes('=>')) {
+ result.type = 'func';
+ result.raw = raw;
+ } else {
+ result.type = 'object';
+ }
+ } else if (properties.length === 1 && typeof properties[0].key === 'object') {
+ const v = transformType(properties[0].value);
+ if (v === 'any') {
+ result.type = 'object';
+ } else if (typeof v === 'string') {
+ result.value = v;
+ result.type = 'objectOf';
+ } else if (typeof v?.type === 'string') {
+ result.value = v.type;
+ result.type = 'objectOf';
+ } else {
+ result.type = 'object';
+ }
+ } else if (properties.length === 1 && properties[0].key === '__call') {
+ result.type = 'func';
+ } else {
+ result.value = properties
+ .filter((item: any) => typeof item.key !== 'object')
+ .map((prop: any) => {
+ const { key } = prop;
+ const typeItem = {
+ ...omit(prop.value, 'name'),
+ type: prop.value.type || {},
+ };
+ typeItem.type = {
+ ...typeItem.type,
+ ...pick(prop.value, ['name', 'value']),
+ };
+ return transformItem(key, typeItem);
+ });
+ }
+ break;
+ }
+ case 'objectOf':
+ case 'instanceOf':
+ result.value = transformType(value);
+ break;
+ case 'exact':
+ case 'shape':
+ result.value = Object.keys(value).map((n) => {
+ const { name: _name, ...others } = value[n];
+ return transformItem(n, {
+ ...others,
+ type: {
+ name: _name,
+ },
+ });
+ });
+ break;
+ case (name.match(/ReactNode$/) || {}).input:
+ result.type = 'node';
+ break;
+ case (name.match(/JSX\.Element$/) || {}).input:
+ result.type = 'element';
+ break;
+ default:
+ result.type = 'object';
+ break;
+ }
+ if (Object.keys(result).length === 1) {
+ return result.type;
+ }
+ if (result?.type === 'oneOfType') {
+ return combineOneOfValues(result);
+ }
+ return result;
+}
+
+function combineOneOfValues(propType) {
+ if (propType.type !== 'oneOfType') {
+ return propType;
+ }
+ const newValue = [];
+ let oneOfItem = null;
+ let firstBooleanIndex = -1;
+ propType.value.forEach((item) => {
+ if (item?.type === 'oneOf') {
+ if (!oneOfItem) {
+ oneOfItem = {
+ type: 'oneOf',
+ value: [],
+ };
+ }
+ if (item.value.includes(true) || item.value.includes(false)) {
+ if (firstBooleanIndex !== -1) {
+ oneOfItem.value.splice(firstBooleanIndex, 1);
+ newValue.push('bool');
+ } else {
+ firstBooleanIndex = oneOfItem.value.length;
+ oneOfItem.value = oneOfItem.value.concat(item.value);
+ }
+ } else {
+ oneOfItem.value = oneOfItem.value.concat(item.value);
+ }
+ } else {
+ newValue.push(item);
+ }
+ });
+ let result = propType;
+ const oneOfItemLength = oneOfItem?.value?.length;
+ if (oneOfItemLength) {
+ newValue.push(oneOfItem);
+ }
+ if (firstBooleanIndex !== -1 || oneOfItemLength) {
+ result = {
+ ...propType,
+ value: newValue,
+ };
+ }
+ if (result.value.length === 1 && result.value[0]?.type === 'oneOf') {
+ result = {
+ ...result,
+ type: 'oneOf',
+ value: result.value[0].value,
+ };
+ }
+ result.value = uniq(result.value);
+ return result;
+}
+
+export function transformItem(name: string, item: any) {
+ const {
+ description,
+ flowType,
+ tsType,
+ type = tsType || flowType,
+ optional,
+ required = optional,
+ defaultValue,
+ ...others
+ } = item;
+ const result: any = {
+ name,
+ };
+
+ if (type) {
+ result.propType = transformType({
+ ...type,
+ ...omit(others, ['name']),
+ required: !!required,
+ });
+ }
+ if (description) {
+ if (description.includes('\n')) {
+ result.description = description.split('\n')[0];
+ } else {
+ result.description = description;
+ }
+ }
+ if (!isNil(defaultValue) && typeof defaultValue === 'object' && isEvaluable(defaultValue)) {
+ if (defaultValue === null) {
+ result.defaultValue = defaultValue;
+ } else {
+ // if ('computed' in defaultValue) {
+ // val = val.value;
+ try {
+ const value = safeEval(defaultValue.value);
+ if (isEvaluable(value)) {
+ result.defaultValue = value;
+ }
+ } catch (e) {
+ log(e);
+ }
+ }
+ // else {
+ // result.defaultValue = defaultValue.value;
+ // }
+ }
+ if (result.propType === undefined) {
+ delete result.propType;
+ }
+
+ return result;
+}
diff --git a/modules/material-parser/src/parse/ts/generateDTS.ts b/modules/material-parser/src/parse/ts/generateDTS.ts
new file mode 100644
index 0000000000..79ccf853cc
--- /dev/null
+++ b/modules/material-parser/src/parse/ts/generateDTS.ts
@@ -0,0 +1,56 @@
+import * as path from 'path';
+import { writeFileSync, pathExistsSync, ensureDirSync, copySync } from 'fs-extra';
+import { loadFile } from '../../utils';
+
+import { debug } from '../../core';
+
+const log = debug.extend('parse:ts:generate_dts');
+
+/**
+ * Generate alias dts file by removing some needless interfaces.
+ * Replace original file at present, which will cause type pollution, looking for better solution
+ * @param {string} workDir - the dir containing the module to be parsed
+ * @returns {string} - the path of generated xxx.d.ts
+ */
+export default function generateDTS({
+ workDir,
+ dslType = 'react',
+}: {
+ workDir: string;
+ dslType?: string;
+}): {
+ originalTypePath: string;
+ newTypePath: string;
+} {
+ const typeDir = path.join(workDir, 'node_modules', `@types/${dslType}`);
+ const typePath = path.join(typeDir, 'index.d.ts');
+ const fileContent = loadFile(typePath);
+ // const materialParserTypeDir = path.join(workDir, `node_modules/material-parser-types/${type}`);
+ // ensureDirSync(materialParserTypeDir);
+ const materialParserTypeDir = typeDir;
+ const newTypePath = path.join(materialParserTypeDir, 'index.d.ts');
+ // if (!pathExistsSync(newTypePath)) {
+ // copySync(
+ // path.join(typeDir, 'global.d.ts'),
+ // path.join(materialParserTypeDir, 'global.d.ts'),
+ // );
+ let newContent = fileContent.replace(
+ /(?<=interface HTMLAttributes[^e]+)(extends[^}]+)/,
+ `{
+ style?: CSSProperties;
+ className?: string;
+ `,
+ );
+ newContent = newContent.replace(/(?<=interface IntrinsicElements {)([^}]+)/, '');
+ newContent = newContent.replace(/type LibraryManagedAttributes[^;]+;/, '');
+ writeFileSync(newTypePath, newContent);
+ log('generate dts', newTypePath);
+ // } else {
+ // log('found dts', newTypePath);
+ // }
+
+ return {
+ originalTypePath: typePath,
+ newTypePath,
+ };
+}
diff --git a/modules/material-parser/src/parse/ts/index.ts b/modules/material-parser/src/parse/ts/index.ts
new file mode 100644
index 0000000000..059d9fb90a
--- /dev/null
+++ b/modules/material-parser/src/parse/ts/index.ts
@@ -0,0 +1,611 @@
+import * as path from 'path';
+import { Parser, ComponentDoc } from 'react-docgen-typescript';
+import ts, { SymbolFlags, TypeFlags, SyntaxKind } from 'typescript';
+import { isEmpty, isEqual } from 'lodash';
+import { existsSync, readFileSync } from 'fs-extra';
+import findConfig from 'find-config';
+import { debug } from '../../core';
+import { Json } from '../../types';
+import { transformItem } from '../transform';
+import generateDTS from './generateDTS';
+import { IParseArgs } from '../index';
+
+const log = debug.extend('parse:ts');
+
+type ExtendedType = ts.Type & {
+ id: string;
+ typeArguments: any[];
+};
+
+function getNextParentIds(parentIds: number[], type: ts.Type) {
+ // @ts-ignore
+ const id = type?.symbol?.id;
+ if (id) {
+ return [...parentIds, id];
+ }
+ return parentIds;
+}
+
+function getSymbolName(symbol: ts.Symbol) {
+ // @ts-ignore
+ const prefix: string = symbol?.parent && getSymbolName(symbol.parent);
+ const name = symbol.getName();
+ if (prefix && prefix.length <= 20) {
+ return `${prefix}.${name}`;
+ }
+ return name;
+}
+
+function getFunctionParams(parameters: any[] = [], checker, parentIds, type) {
+ return parameters.map((node) => {
+ const typeObject = checker.getTypeOfSymbolAtLocation(node.symbol, node.symbol.valueDeclaration);
+ const v = getDocgenTypeHelper(checker, typeObject, false, getNextParentIds(parentIds, type));
+ const name = node.symbol.escapedName;
+ return {
+ name,
+ propType: v,
+ };
+ });
+}
+
+function getFunctionReturns(node: any, checker, parentIds, type) {
+ if (!node) return {};
+ const propType = getDocgenTypeHelper(
+ checker,
+ node.type,
+ false,
+ getNextParentIds(parentIds, type),
+ );
+ return {
+ propType,
+ };
+}
+
+const blacklistNames = [
+ 'prototype',
+ 'getDerivedStateFromProps',
+ 'propTypes',
+ 'defaultProps',
+ 'contextTypes',
+ 'displayName',
+ 'contextType',
+ 'Provider',
+ 'Consumer',
+];
+
+const blacklistPatterns = [
+ /^HTML/,
+ /^React\./,
+ /^Object$/,
+ /^Date$/,
+ /^Promise$/,
+ /^XML/,
+ /^Function$/,
+];
+
+// function hasTooManyTypes(type) {
+// return type?.types?.length >= 20;
+// }
+
+function isComplexType(type) {
+ let isAliasSymbol = false;
+ let symbol = type?.symbol;
+ if (!symbol) {
+ symbol = type?.aliasSymbol;
+ isAliasSymbol = true;
+ }
+ if (!symbol) return false;
+ if (isAliasSymbol) {
+ return false;
+ }
+ const name = getSymbolName(symbol);
+ if (blacklistPatterns.some((patt) => patt.test(name))) {
+ return true;
+ }
+ return false;
+}
+
+function getDocgenTypeHelper(
+ checker: ts.TypeChecker,
+ type: ts.Type,
+ skipRequired = false,
+ parentIds: number[] = [],
+ isRequired = false,
+): any {
+ function isTuple(_type: ts.Type) {
+ // @ts-ignore use internal methods
+ return checker.isArrayLikeType(_type) && !checker.isArrayType(_type);
+ }
+ let required: boolean;
+ if (isRequired !== undefined) {
+ required = isRequired;
+ } else {
+ required = !(type.flags & SymbolFlags.Optional) || isRequired;
+ }
+
+ function makeResult(typeInfo: Json) {
+ if (skipRequired) {
+ return {
+ raw: checker.typeToString(type),
+ ...typeInfo,
+ };
+ } else {
+ return {
+ required,
+ raw: checker.typeToString(type),
+ ...typeInfo,
+ };
+ }
+ }
+
+ function getShapeFromArray(symbolArr: ts.Symbol[], _type: ts.Type) {
+ const shape: Array<{
+ key:
+ | {
+ name: string;
+ }
+ | string;
+ value: any;
+ }> = symbolArr.map((prop) => {
+ const propType = checker.getTypeOfSymbolAtLocation(
+ prop,
+ // @ts-ignore
+ prop.valueDeclaration || (prop.declarations && prop.declarations[0]) || {},
+ );
+ return {
+ key: prop.getName(),
+
+ value: getDocgenTypeHelper(
+ checker,
+ propType,
+ false,
+ // @ts-ignore
+ getNextParentIds(parentIds, _type),
+ // @ts-ignore
+ !prop?.valueDeclaration?.questionToken,
+ ),
+ };
+ });
+ // @ts-ignore use internal methods
+ if (checker.isArrayLikeType(_type)) {
+ return shape;
+ }
+ if (_type.getStringIndexType()) {
+ // @ts-ignore use internal methods
+ if (!_type.stringIndexInfo) {
+ return shape;
+ }
+ shape.push({
+ key: {
+ name: 'string',
+ },
+ value: getDocgenTypeHelper(
+ checker,
+ // @ts-ignore use internal methods
+ _type.stringIndexInfo.type,
+ false,
+ getNextParentIds(parentIds, _type),
+ ),
+ });
+ } else if (_type.getNumberIndexType()) {
+ // @ts-ignore use internal methods
+ if (!_type.numberIndexInfo) {
+ return shape;
+ }
+ shape.push({
+ key: {
+ name: 'number',
+ },
+
+ value: getDocgenTypeHelper(
+ checker,
+ // @ts-ignore use internal methods
+ _type.numberIndexInfo.type,
+ false,
+ getNextParentIds(parentIds, _type),
+ ),
+ });
+ }
+ return shape;
+ }
+
+ function getShape(_type: ts.Type) {
+ const { symbol } = _type;
+ if (symbol && symbol.members) {
+ // @ts-ignore
+ const props: ts.Symbol[] = Array.from(symbol.members.values());
+ // if (props.length >= 20) {
+ // throw new Error('too many props');
+ // }
+ return getShapeFromArray(
+ props.filter((prop) => prop.getName() !== '__index'),
+ _type,
+ );
+ } else {
+ // @ts-ignore
+ const args = _type.resolvedTypeArguments || [];
+ const props = checker.getPropertiesOfType(_type);
+ // if (props.length >= 20) {
+ // throw new Error('too many props');
+ // }
+ const shape = getShapeFromArray(props.slice(0, args.length), _type);
+ return shape;
+ }
+ }
+
+ // @ts-ignore
+ if (type?.kind === SyntaxKind.VoidExpression) {
+ return makeResult({
+ name: 'void',
+ raw: 'void',
+ });
+ }
+
+ const pattern = /^__global\.(.+)$/;
+ // @ts-ignore
+ if (parentIds.includes(type?.symbol?.id)) {
+ return makeResult({
+ name: 'object', // checker.typeToString(type),
+ });
+ }
+ if (type.symbol) {
+ const symbolName = getSymbolName(type.symbol);
+ if (symbolName) {
+ const matches = pattern.exec(symbolName);
+ if (matches) {
+ return makeResult({
+ name: matches[1],
+ });
+ }
+ }
+ }
+
+ if (type.flags & TypeFlags.Number) {
+ return makeResult({
+ name: 'number',
+ });
+ } else if (type.flags & TypeFlags.String) {
+ return makeResult({
+ name: 'string',
+ });
+ } else if (type.flags & TypeFlags.NumberLiteral) {
+ return makeResult({
+ name: 'literal',
+ // @ts-ignore
+ value: type.value,
+ });
+ } else if (type.flags & TypeFlags.Literal) {
+ return makeResult({
+ name: 'literal',
+ value: checker.typeToString(type),
+ });
+ } else if (type.symbol?.flags & SymbolFlags.Enum) {
+ return makeResult({
+ name: 'union',
+ // @ts-ignore
+ value: type.types.map((t) => t.value),
+ });
+ // @ts-ignore
+ } else if (type.flags & TypeFlags.DisjointDomains) {
+ return makeResult({
+ name: checker.typeToString(type),
+ });
+ } else if (type.flags & TypeFlags.Any) {
+ return makeResult({
+ name: 'any',
+ });
+ } else if (type.flags & TypeFlags.Union && !isComplexType(type)) {
+ return makeResult({
+ name: 'union',
+ // @ts-ignore
+ value: type.types.map((t) =>
+ getDocgenTypeHelper(checker, t, true, getNextParentIds(parentIds, type)),
+ ),
+ });
+ } else if (isComplexType(type)) {
+ return makeResult({
+ name: getSymbolName(type?.symbol || type?.aliasSymbol),
+ });
+ } else if (type.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
+ if (isTuple(type)) {
+ try {
+ const props = getShape(type);
+ return makeResult({
+ name: 'tuple',
+ value: props.map((p) => p.value),
+ });
+ } catch (e) {
+ return makeResult({
+ name: 'object',
+ });
+ }
+
+ // @ts-ignore
+ } else if (checker.isArrayType(type)) {
+ return makeResult({
+ name: 'Array',
+ // @ts-ignore
+ elements: [
+ getDocgenTypeHelper(
+ checker,
+ (type as ExtendedType).typeArguments[0],
+ false,
+ getNextParentIds(parentIds, type),
+ ),
+ ],
+ });
+ // @ts-ignore
+ } else if (type?.symbol?.valueDeclaration?.parameters?.length) {
+ return makeResult({
+ name: 'func',
+ params: getFunctionParams(
+ // @ts-ignore
+ type?.symbol?.valueDeclaration?.parameters,
+ checker,
+ parentIds,
+ type,
+ ),
+ returns: getFunctionReturns(
+ checker.typeToTypeNode(type, type?.symbol?.valueDeclaration),
+ checker,
+ parentIds,
+ type,
+ ),
+ });
+ } else if (
+ // @ts-ignore
+ type?.members?.get('__call')?.declarations[0]?.symbol?.declarations[0]?.parameters?.length
+ ) {
+ return makeResult({
+ name: 'func',
+ params: getFunctionParams(
+ // @ts-ignore
+ type?.members?.get('__call')?.declarations[0]?.symbol?.declarations[0]?.parameters,
+ checker,
+ parentIds,
+ type,
+ ),
+ });
+ } else {
+ try {
+ const props = getShape(type);
+ return makeResult({
+ name: 'signature',
+ type: {
+ signature: {
+ properties: props,
+ },
+ },
+ });
+ } catch (e) {
+ return makeResult({
+ name: 'object',
+ });
+ }
+ }
+ } else {
+ return makeResult({
+ name: 'object',
+ });
+ }
+}
+class MyParser extends Parser {
+ getDocgenType(propType: ts.Type): any {
+ const parentIds = [];
+ // @ts-ignore
+ const parentId = propType?.symbol?.parent?.id;
+ if (parentId) {
+ parentIds.push(parentId);
+ }
+ // @ts-ignore
+ const result = getDocgenTypeHelper(this.checker, propType, true, parentIds);
+ return result;
+ }
+
+ // override the builtin method, to avoid the false positive
+ public extractPropsFromTypeIfStatelessComponent(type: ts.Type): ts.Symbol | null {
+ const callSignatures = type.getCallSignatures();
+
+ if (callSignatures.length) {
+ // Could be a stateless component. Is a function, so the props object we're interested
+ // in is the (only) parameter.
+
+ for (const sig of callSignatures) {
+ const params = sig.getParameters();
+ if (params.length === 0) {
+ continue;
+ }
+
+ // @ts-ignore
+ const returnSymbol = this.checker.getReturnTypeOfSignature(sig);
+ if (!returnSymbol) continue;
+ const symbol = returnSymbol?.symbol;
+ if (!symbol) continue;
+ // @ts-ignore
+ const typeString = this.checker.symbolToString(symbol);
+ if (
+ typeString.startsWith('ReactElement') ||
+ typeString.startsWith('Element') ||
+ typeString.startsWith('RaxElement')
+ ) {
+ const propsParam = params[0];
+ if (propsParam) {
+ return propsParam;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}
+
+const getCompilerOptions = (reactTypePath, originalReactTypePath) => {
+ const options: any = {
+ jsx: ts.JsxEmit.React,
+ module: ts.ModuleKind.CommonJS,
+ target: ts.ScriptTarget.Latest,
+ allowSyntheticDefaultImports: true,
+ };
+ // if (reactTypePath) {
+ // options.paths = {
+ // react: [reactTypePath],
+ // };
+ // options.exclude = [path.dirname(originalReactTypePath)];
+ // options.types = [];
+ // options.skipLibCheck = true;
+ // }
+ return options;
+};
+
+interface SymbolWithMeta extends ts.Symbol {
+ meta?: {
+ exportName: string;
+ subName?: string;
+ };
+}
+
+function getComponentName(exportName, displayName) {
+ if (displayName) {
+ const firstCharCode = displayName.charCodeAt(0);
+ if (firstCharCode >= 65 && firstCharCode <= 90) {
+ return displayName || exportName;
+ }
+ }
+ return exportName;
+}
+
+const defaultTsConfigPath = path.resolve(__dirname, './tsconfig.json');
+
+export default function parseTS(filePath: string, args: IParseArgs): ComponentDoc[] {
+ if (!filePath) return [];
+
+ let basePath = args.moduleDir || args.workDir || path.dirname(filePath);
+ let tsConfigPath = findConfig('tsconfig.json', { cwd: basePath }); // path.resolve(basePath, 'tsconfig.json')
+ if (
+ !tsConfigPath ||
+ !existsSync(tsConfigPath) ||
+ (args.accesser === 'online' && tsConfigPath === 'tsconfig.json')
+ ) {
+ tsConfigPath = defaultTsConfigPath;
+ } else {
+ basePath = path.dirname(tsConfigPath);
+ }
+
+ log('ts config path is', tsConfigPath);
+ const { config, error } = ts.readConfigFile(tsConfigPath, (filename) =>
+ readFileSync(filename, 'utf8'),
+ );
+
+ if (error !== undefined) {
+ const errorText = `Cannot load custom tsconfig.json from provided path: ${tsConfigPath}, with error code: ${error.code}, message: ${error.messageText}`;
+ throw new Error(errorText);
+ }
+
+ const { options, errors } = ts.parseJsonConfigFileContent(
+ config,
+ ts.sys,
+ basePath,
+ {},
+ tsConfigPath,
+ );
+
+ if (errors && errors.length) {
+ throw errors[0];
+ }
+ log('ts config is', options);
+ // const filePaths = Array.isArray(filePathOrPaths) ? filePathOrPaths : [filePathOrPaths];
+ generateDTS(args);
+ const program = ts.createProgram([filePath], options);
+
+ const parser = new MyParser(program, {});
+
+ const checker = program.getTypeChecker();
+
+ const result = [filePath]
+ .map((fPath) => program.getSourceFile(fPath))
+ .filter((sourceFile) => typeof sourceFile !== 'undefined')
+ .reduce((docs: any[], sourceFile) => {
+ const moduleSymbol = checker.getSymbolAtLocation(sourceFile as ts.Node);
+
+ if (!moduleSymbol) {
+ return docs;
+ }
+
+ const exportSymbols = checker.getExportsOfModule(moduleSymbol);
+
+ for (let index = 0; index < exportSymbols.length; index++) {
+ const sym: SymbolWithMeta = exportSymbols[index];
+ const name = sym.getName();
+ if (blacklistNames.includes(name)) {
+ continue;
+ }
+
+ // polyfill valueDeclaration
+ sym.valueDeclaration =
+ sym.valueDeclaration || (Array.isArray(sym.declarations) && sym.declarations[0]);
+
+ if (!sym.valueDeclaration) {
+ continue;
+ }
+ const info = parser.getComponentInfo(sym, sourceFile);
+ if (info === null) {
+ continue;
+ }
+ const exportName = sym.meta && sym.meta.exportName;
+ const meta = {
+ subName: exportName ? name : '',
+ exportName: exportName || name,
+ };
+ if (docs.find((x) => isEqual(x.meta, meta))) {
+ continue;
+ }
+ docs.push({
+ ...info,
+ meta,
+ });
+ // find sub components
+ if (!!sym.declarations && sym.declarations.length === 0) {
+ continue;
+ }
+
+ const type = checker.getTypeOfSymbolAtLocation(
+ sym,
+ sym.valueDeclaration || sym.declarations[0],
+ );
+ Array.prototype.push.apply(
+ exportSymbols,
+ type.getProperties().map((x: SymbolWithMeta) => {
+ x.meta = { exportName: name };
+ return x;
+ }),
+ );
+ }
+
+ return docs;
+ }, []);
+ const coms = result.reduce((res: any[], info: any) => {
+ if (!info || !info.props || isEmpty(info.props)) return res;
+ const props = Object.keys(info.props).reduce((acc: any[], name) => {
+ // omit aria related properties temporarily
+ if (name.startsWith('aria-')) {
+ return acc;
+ }
+ try {
+ const item: any = transformItem(name, info.props[name]);
+ acc.push(item);
+ } catch (e) {
+ log(e);
+ }
+ return acc;
+ }, []);
+ const exportName = info?.meta?.exportName;
+ res.push({
+ componentName: getComponentName(exportName, info.displayName),
+ props,
+ meta: info.meta || {},
+ });
+ return res;
+ }, []);
+ return coms;
+}
diff --git a/modules/material-parser/src/parse/ts/tsconfig.json b/modules/material-parser/src/parse/ts/tsconfig.json
new file mode 100644
index 0000000000..533839dce3
--- /dev/null
+++ b/modules/material-parser/src/parse/ts/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "jsx": "react",
+ "target": "es6",
+ "module": "commonjs",
+ "allowSyntheticDefaultImports": true,
+ "allowJs": true
+ },
+ "include": ["**/*"],
+ "exclude": [""]
+}
diff --git a/modules/material-parser/src/scan.ts b/modules/material-parser/src/scan.ts
new file mode 100644
index 0000000000..f6bb09e769
--- /dev/null
+++ b/modules/material-parser/src/scan.ts
@@ -0,0 +1,78 @@
+import {
+ IInternalMaterializeOptions,
+ IMaterializeOnlinePackageAndVersionOptions,
+ IMaterialScanModel,
+} from './types';
+import { pathExists, lstatSync } from 'fs-extra';
+import { join, isAbsolute, resolve } from 'path';
+import { debug } from './core';
+import { resolvePkgJson } from './utils';
+
+const log = debug.extend('mat');
+
+export default async function scan(
+ options: IInternalMaterializeOptions,
+): Promise {
+ const model: IMaterialScanModel = {
+ pkgName: '',
+ pkgVersion: '',
+ mainFileAbsolutePath: '',
+ mainFilePath: '',
+ };
+ log('options', options);
+ // 入口文件路径
+ const entryFilePath = options.entry;
+ const stats = lstatSync(entryFilePath);
+ if (
+ (options.accesser === 'local' ||
+ (options.accesser === 'online' &&
+ (options as IMaterializeOnlinePackageAndVersionOptions).name &&
+ options.entry)) &&
+ stats.isFile()
+ ) {
+ if (options.accesser === 'online') {
+ model.useEntry = true;
+ }
+ if (isAbsolute(entryFilePath)) {
+ model.mainFilePath = entryFilePath;
+ model.mainFileAbsolutePath = entryFilePath;
+ } else {
+ model.mainFilePath = entryFilePath;
+ model.mainFileAbsolutePath = resolve(entryFilePath);
+ }
+ }
+ const pkgJsonPath = join(options.root, 'package.json');
+ if (await pathExists(pkgJsonPath)) {
+ const pkgJson = await resolvePkgJson(pkgJsonPath);
+ model.pkgName = pkgJson.name;
+ model.pkgVersion = pkgJson.version;
+ if (pkgJson.module) {
+ const moduleFileAbsolutePath = join(options.root, pkgJson.module);
+ if (await pathExists(moduleFileAbsolutePath)) {
+ model.moduleFilePath = pkgJson.module;
+ model.moduleFileAbsolutePath = moduleFileAbsolutePath;
+ }
+ }
+ model.mainFilePath = model.mainFilePath || pkgJson.main || './index.js';
+ model.mainFileAbsolutePath = model.mainFileAbsolutePath || join(entryFilePath, pkgJson.main);
+ const typingsPathCandidates = [
+ pkgJson.typings,
+ pkgJson.types,
+ './index.d.ts',
+ './lib/index.d.ts',
+ ];
+ for (let i = 0; i < typingsPathCandidates.length; i++) {
+ const typingsFilePath = typingsPathCandidates[i];
+ if (!typingsFilePath) continue;
+ const typingsFileAbsolutePath = join(options.root, typingsFilePath);
+ if (await pathExists(typingsFileAbsolutePath)) {
+ model.typingsFileAbsolutePath = typingsFileAbsolutePath;
+ model.typingsFilePath = typingsFilePath;
+ break;
+ }
+ }
+ }
+
+ log('model', model);
+ return model;
+}
diff --git a/modules/material-parser/src/types/Basic.ts b/modules/material-parser/src/types/Basic.ts
new file mode 100644
index 0000000000..18752003b4
--- /dev/null
+++ b/modules/material-parser/src/types/Basic.ts
@@ -0,0 +1,5 @@
+export interface Json {
+ [x: string]: string | number | boolean | Date | Json | JsonArray;
+}
+export type JsonArray = Array;
+export type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never;
diff --git a/modules/material-parser/src/types/ChannelType.ts b/modules/material-parser/src/types/ChannelType.ts
new file mode 100644
index 0000000000..1f9953480f
--- /dev/null
+++ b/modules/material-parser/src/types/ChannelType.ts
@@ -0,0 +1,9 @@
+/**
+ * 物料接入渠道
+ */
+export enum ChannelType {
+ /** 本地 */
+ LOCAL = 'local',
+ /** 在线 */
+ ONLINE = 'online',
+}
diff --git a/modules/material-parser/src/types/DSLType.ts b/modules/material-parser/src/types/DSLType.ts
new file mode 100644
index 0000000000..dc9133554e
--- /dev/null
+++ b/modules/material-parser/src/types/DSLType.ts
@@ -0,0 +1,4 @@
+/**
+ * DSL类型
+ */
+export type DSLType = 'react' | 'rax';
diff --git a/modules/material-parser/src/types/IAccesser.ts b/modules/material-parser/src/types/IAccesser.ts
new file mode 100644
index 0000000000..3495817d70
--- /dev/null
+++ b/modules/material-parser/src/types/IAccesser.ts
@@ -0,0 +1,14 @@
+import { ComponentMeta } from '../core';
+
+/**
+ * 接入器接口(用于定义物料化组件的接入渠道)
+ * @interface IAccesser
+ */
+export interface IAccesser {
+ /**
+ * 接入
+ * @returns {Promise}
+ * @memberof IAccesser
+ */
+ access(): Promise;
+}
diff --git a/modules/material-parser/src/types/IExtensionConfigManifest.ts b/modules/material-parser/src/types/IExtensionConfigManifest.ts
new file mode 100644
index 0000000000..a1f711033a
--- /dev/null
+++ b/modules/material-parser/src/types/IExtensionConfigManifest.ts
@@ -0,0 +1,13 @@
+import { ComponentMeta } from '../core';
+/**
+ * 扩展点:配置 manifest
+ * (物料化场景)
+ */
+export type IExtensionConfigManifest = (params: {
+ manifestObj: ComponentMeta; // manifest 配置对象
+ manifestFilePath: string; // manifest 文件默认路径
+}) => Promise<{
+ manifestJSON: string; // manifest 文件内容
+ manifestFilePath: string; // manifest 文件路径
+ manifestObj: ComponentMeta; // manifest 文件对象
+}>;
diff --git a/modules/material-parser/src/types/IMaterialParsedModel.ts b/modules/material-parser/src/types/IMaterialParsedModel.ts
new file mode 100644
index 0000000000..c263d46519
--- /dev/null
+++ b/modules/material-parser/src/types/IMaterialParsedModel.ts
@@ -0,0 +1,22 @@
+import { PropsSection } from '../core';
+/**
+ * 对应解析器分析出的一些关键信息
+ */
+export interface IPropType {
+ name: string;
+ type: string;
+ value?: IPropTypes;
+ required: boolean;
+}
+
+export type IPropTypes = IPropType[];
+
+export interface IMaterialParsedModel {
+ // filePath: string;
+ componentName: string;
+ props?: PropsSection['props'];
+ meta?: {
+ exportName?: string;
+ subName?: string;
+ };
+}
diff --git a/modules/material-parser/src/types/IMaterialScanModel.ts b/modules/material-parser/src/types/IMaterialScanModel.ts
new file mode 100644
index 0000000000..f2da73b35a
--- /dev/null
+++ b/modules/material-parser/src/types/IMaterialScanModel.ts
@@ -0,0 +1,23 @@
+/**
+ * 对应扫描阶段的产物
+ */
+export interface IMaterialScanModel {
+ /** 当前包名 */
+ pkgName: string;
+ /** 当前包版本 */
+ pkgVersion: string;
+ /** 在ts场景下,使用entry */
+ useEntry?: boolean;
+ /** main文件相对路径 */
+ mainFilePath: string;
+ /** module文件相对路径 */
+ moduleFilePath?: string;
+ /** typings文件相对路径 */
+ typingsFilePath?: string;
+ /** main文件绝对路径 */
+ mainFileAbsolutePath: string;
+ /** module文件绝对路径 */
+ moduleFileAbsolutePath?: string;
+ /** typings文件绝对路径 */
+ typingsFileAbsolutePath?: string;
+}
diff --git a/modules/material-parser/src/types/IMaterializeOptions.ts b/modules/material-parser/src/types/IMaterializeOptions.ts
new file mode 100644
index 0000000000..72e37689ef
--- /dev/null
+++ b/modules/material-parser/src/types/IMaterializeOptions.ts
@@ -0,0 +1,117 @@
+import { Expand } from './Basic';
+import { DSLType } from './DSLType';
+/**
+ * 通用入料配置项
+ * @interface IMaterializeCommonOptions
+ */
+export interface IMaterializeCommonOptions {
+ /**
+ * 当 accesser=online 时,配置要使用的 npm client,如:tnpm、cnpm、yarn、npm
+ */
+ npmClient?: string;
+ /**
+ * 当前dsl类型,可选值包括'react' | 'rax'
+ */
+ dslType?: DSLType;
+}
+
+/**
+ * 本地入料配置项
+ * @interface IMaterializeOnlineOptions
+ */
+export interface IMaterializeLocalOptions extends IMaterializeCommonOptions {
+ /**
+ * 接入渠道
+ * (local:表示本地物料工作台方式接入,online:表示在线 npm 包接入)
+ * @type {('local' | 'online')}
+ * @memberof IMaterializeOptions
+ */
+ accesser: 'local';
+
+ /**
+ * 组件文件(夹)路径或包名
+ * 形如:
+ * 本地路径:/usr/project/src/container/DemoMaterial
+ * 包名:@ali/demo-material@0.0.1
+ */
+ entry: string;
+
+ /**
+ * 组件根目录,当entry为文件路径的时候,可以用root来指定根目录,当entry为文件夹时,root默认为entry
+ * 形如:
+ * 相对路径:./
+ * 绝对路径:/usr/project/src/container/DemoMaterial
+ */
+ root?: string;
+}
+
+/**
+ * 在线入料配置项
+ * @interface IMaterializeOnlineOptions
+ */
+export interface IMaterializeOnlineCommonOptions {
+ /**
+ * 接入渠道
+ * (local:表示本地物料工作台方式接入,online:表示在线 npm 包接入)
+ * @type {('local' | 'online')}
+ * @memberof IMaterializeOptions
+ */
+ accesser: 'online';
+ /**
+ * 临时工作目录,用来存放下载的npm包,可为绝对路径或相对路径
+ */
+ tempDir?: string;
+}
+
+/**
+ * 只通过entry指定包名&版本号,无需内部路径
+ */
+export interface IMaterializeOnlineEntryOptions {
+ /**
+ * npm包名&版本号,此时无需指定内部路径,会从package.json自动解析
+ * 形如:
+ * 包名&版本号:@ali/demo-material@0.0.1
+ */
+ entry: string;
+}
+
+export interface IMaterializeOnlinePackageAndVersionOptions {
+ /**
+ * npm包内部相对路径
+ * 形如:
+ * 相对路径:lib/index.js
+ */
+ entry?: string;
+
+ /**
+ * npm包名
+ * 形如:
+ * react-color
+ */
+ name: string;
+
+ /**
+ * npm包版本号
+ * 形如:
+ * latest/1.0.0/1.x.0
+ * @default latest
+ */
+ version?: string;
+}
+
+export type IMaterializeOnlineOptions = Expand<
+ IMaterializeCommonOptions &
+ IMaterializeOnlineCommonOptions &
+ (IMaterializeOnlineEntryOptions | IMaterializeOnlinePackageAndVersionOptions)
+>;
+/**
+ * 入料配置项
+ * @interface IMaterializeOptions
+ */
+export type IMaterializeOptions = Expand;
+
+export type IInternalMaterializeOptions = Expand<
+ IMaterializeOptions & {
+ root: string;
+ }
+>;
diff --git a/modules/material-parser/src/types/Meta.ts b/modules/material-parser/src/types/Meta.ts
new file mode 100644
index 0000000000..2cf810ce45
--- /dev/null
+++ b/modules/material-parser/src/types/Meta.ts
@@ -0,0 +1,14 @@
+import { Path } from 'ast-types';
+
+export interface IFileMeta {
+ src: string;
+ path: string;
+ exports: IDefinitionMeta[];
+}
+
+export interface IDefinitionMeta {
+ subDefinitions: IDefinitionMeta[];
+ nodePath: typeof Path;
+ exportName: string;
+ id: string;
+}
diff --git a/modules/material-parser/src/types/index.ts b/modules/material-parser/src/types/index.ts
new file mode 100644
index 0000000000..be700f7b6f
--- /dev/null
+++ b/modules/material-parser/src/types/index.ts
@@ -0,0 +1,8 @@
+export * from './ChannelType';
+export * from './DSLType';
+export * from './IAccesser';
+export * from './IExtensionConfigManifest';
+export * from './IMaterializeOptions';
+export * from './IMaterialScanModel';
+export * from './IMaterialParsedModel';
+export * from './Basic';
diff --git a/modules/material-parser/src/utils.ts b/modules/material-parser/src/utils.ts
new file mode 100644
index 0000000000..dfd36d8801
--- /dev/null
+++ b/modules/material-parser/src/utils.ts
@@ -0,0 +1,129 @@
+import { pathExists, readFileSync, writeFile } from 'fs-extra';
+import { isPlainObject } from 'lodash';
+import originalSafeEval from 'safe-eval';
+import * as path from 'path';
+import spawn from 'cross-spawn-promise';
+import { DSLType } from './types';
+
+export async function isNPMInstalled(args: {
+ workDir: string;
+ moduleDir: string;
+ npmClient?: string;
+}) {
+ return pathExists(path.join(args.workDir, 'node_modules'));
+}
+
+export async function install(args: { workDir: string; moduleDir: string; npmClient?: string }) {
+ if (await isNPMInstalled(args)) return;
+ const { workDir, npmClient = 'tnpm' } = args;
+ try {
+ await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);
+ } catch (e) {
+ // TODO
+ }
+}
+
+export async function installModule(
+ args: { workDir: string; moduleDir: string; npmClient?: string },
+ name: string,
+) {
+ const { workDir, npmClient = 'tnpm' } = args;
+ try {
+ await spawn(npmClient, ['i', name], { stdio: 'inherit', cwd: workDir } as any);
+ } catch (e) {
+ // TODO
+ }
+}
+
+export function installTypeDTS(args: {
+ workDir: string;
+ moduleDir: string;
+ npmClient?: string;
+ dslType?: DSLType;
+}) {
+ return installModule(args, `@types/${args.dslType || 'react'}`);
+}
+
+export async function installTypeScript(args: {
+ workDir: string;
+ moduleDir: string;
+ npmClient?: string;
+}) {
+ if (await pathExists(path.join(args.workDir, 'node_modules', '.bin', 'tsc'))) return;
+ const { workDir, npmClient = 'tnpm' } = args;
+ await spawn(npmClient, ['i', 'typescript'], { stdio: 'inherit', cwd: workDir } as any);
+}
+
+export async function installPeerAndDevDeps(args: {
+ workDir: string;
+ moduleDir: string;
+ npmClient?: string;
+}) {
+ const { workDir, moduleDir, npmClient = 'tnpm' } = args;
+ const modulePkgJsonPath = path.resolve(moduleDir, 'package.json');
+ if (!(await pathExists(modulePkgJsonPath))) {
+ return;
+ }
+ const pkgJsonPath = path.resolve(workDir, 'package.json');
+ if (!(await pathExists(pkgJsonPath))) {
+ return;
+ }
+ const modulePkgJson = await resolvePkgJson(modulePkgJsonPath);
+ const pkgJson = await resolvePkgJson(pkgJsonPath);
+ const { peerDependencies = {}, devDependencies = {} } = modulePkgJson;
+ pkgJson.dependencies = pkgJson.dependencies || {};
+ pkgJson.dependencies = {
+ ...pkgJson.dependencies,
+ ...peerDependencies,
+ ...devDependencies,
+ };
+ await writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
+ await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);
+}
+
+export async function syncTypeModules(args: {
+ workDir: string;
+ moduleDir: string;
+ npmClient?: string;
+}) {
+ const { workDir, moduleDir, npmClient = 'tnpm' } = args;
+ const pkgJsonPath = path.resolve(moduleDir, 'package.json');
+ if (!(await pathExists(pkgJsonPath))) {
+ return;
+ }
+ await installModule(args, 'typesync');
+ await spawn(npmClient.replace('m', 'x'), ['typesync'], { stdio: 'inherit', cwd: workDir } as any);
+}
+
+export async function resolvePkgJson(pkgJsonPath: string): Promise<{ [k: string]: any }> {
+ const content = await loadFile(pkgJsonPath);
+ const json = JSON.parse(content);
+ return json;
+}
+
+export function loadFile(filePath: string): string {
+ const content: string | Buffer = readFileSync(filePath);
+ if (typeof content === 'string') {
+ return content;
+ }
+ return content.toString();
+}
+
+export function isPrimitive(val) {
+ return !['object', 'function'].includes(typeof val) || val === null;
+}
+
+export function isEvaluable(value) {
+ if (isPrimitive(value)) return true;
+ if (Array.isArray(value)) {
+ return value.every(isEvaluable);
+ } else if (isPlainObject(value)) {
+ return Object.keys(value).every((key) => isEvaluable(value[key]));
+ }
+ return false;
+}
+
+export function safeEval(value: any) {
+ if (typeof value === 'string') return originalSafeEval(value);
+ return value;
+}
diff --git a/modules/material-parser/src/validate/index.ts b/modules/material-parser/src/validate/index.ts
new file mode 100644
index 0000000000..3028b85c58
--- /dev/null
+++ b/modules/material-parser/src/validate/index.ts
@@ -0,0 +1,14 @@
+import Ajv from 'ajv';
+import { Json } from '../types/Basic';
+import schema from './schema.json';
+
+const ajv = new Ajv({ jsonPointers: true });
+const validate = ajv.compile(schema);
+
+export default function validateSchema(json: Json) {
+ if (validate(json) === false) {
+ throw new Error(JSON.stringify(validate.errors, null, 2));
+ }
+
+ return true;
+}
diff --git a/modules/material-parser/src/validate/schema.json b/modules/material-parser/src/validate/schema.json
new file mode 100644
index 0000000000..5a0364f762
--- /dev/null
+++ b/modules/material-parser/src/validate/schema.json
@@ -0,0 +1,548 @@
+{
+ "$id": "@ali/low-code-component-protocol-schema",
+ "description": "json schema for low code component protocol",
+ "allOf": [
+ {
+ "$ref": "#/definitions/BasicSection"
+ },
+ {
+ "$ref": "#/definitions/PropsSection"
+ },
+ {
+ "$ref": "#/definitions/ConfigureSection"
+ }
+ ],
+ "definitions": {
+ "BasicSection": {
+ "type": "object",
+ "properties": {
+ "componentName": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "docUrl": {
+ "type": "string"
+ },
+ "screenshot": {
+ "type": "string"
+ },
+ "icon": {
+ "type": "string"
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "devMode": {
+ "enum": [
+ "proCode",
+ "lowCode"
+ ]
+ },
+ "npm": {
+ "$ref": "#/definitions/Npm"
+ }
+ },
+ "required": [
+ "componentName",
+ "title",
+ "npm"
+ ]
+ },
+ "PropsSection": {
+ "type": "object",
+ "required": [
+ "props"
+ ],
+ "properties": {
+ "props": {
+ "type": "array",
+ "items": {
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "propType": {
+ "$ref": "#/definitions/PropType"
+ },
+ "description": {
+ "type": "string"
+ },
+ "defaultValue": {}
+ },
+ "required": [
+ "name",
+ "propType"
+ ]
+ }
+ }
+ }
+ },
+ "ConfigureSection": {
+ "type": "object",
+ "properties": {
+ "configure": {
+ "type": "object",
+ "properties": {
+ "props": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ConfigureProp"
+ }
+ },
+ "styles": {
+ "type": "object",
+ "properties": {}
+ },
+ "events": {
+ "type": "object",
+ "properties": {}
+ },
+ "component": {
+ "$ref": "#/definitions/ConfigureComponent"
+ }
+ }
+ }
+ }
+ },
+ "Npm": {
+ "type": "object",
+ "properties": {
+ "package": {
+ "type": "string"
+ },
+ "exportName": {
+ "type": "string"
+ },
+ "subName": {
+ "type": "string"
+ },
+ "main": {
+ "type": "string"
+ },
+ "destructuring": {
+ "type": "boolean"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "package",
+ "exportName",
+ "subName",
+ "main",
+ "destructuring",
+ "version"
+ ]
+ },
+ "PropType": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/BasicType"
+ },
+ {
+ "$ref": "#/definitions/RequiredType"
+ },
+ {
+ "$ref": "#/definitions/ComplexType"
+ }
+ ]
+ },
+ "BasicType": {
+ "type": "string",
+ "enum": [
+ "array",
+ "bool",
+ "func",
+ "number",
+ "object",
+ "string",
+ "node",
+ "element",
+ "any"
+ ]
+ },
+ "RequiredType": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/definitions/BasicType"
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type"
+ ]
+ },
+ "ComplexType": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/OneOf"
+ },
+ {
+ "$ref": "#/definitions/OneOfType"
+ },
+ {
+ "$ref": "#/definitions/ArrayOf"
+ },
+ {
+ "$ref": "#/definitions/ObjectOf"
+ },
+ {
+ "$ref": "#/definitions/Shape"
+ },
+ {
+ "$ref": "#/definitions/Exact"
+ }
+ ]
+ },
+ "OneOf": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "oneOf"
+ ]
+ },
+ "value": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ }
+ ]
+ }
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "OneOfType": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "oneOfType"
+ ]
+ },
+ "value": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PropType"
+ }
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "ArrayOf": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "arrayOf"
+ ]
+ },
+ "value": {
+ "$ref": "#/definitions/PropType"
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "ObjectOf": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "objectOf"
+ ]
+ },
+ "value": {
+ "$ref": "#/definitions/PropType"
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "Shape": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "shape"
+ ]
+ },
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "propType": {
+ "$ref": "#/definitions/PropType"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "ShapeItem": {
+ "type": "object",
+ "required": [
+ "name",
+ "propType"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "propType": {
+ "$ref": "#/definitions/PropType"
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Exact": {
+ "type": "object",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "exact"
+ ]
+ },
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "propType": {
+ "$ref": "#/definitions/PropType"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "isRequired": {
+ "type": "boolean"
+ }
+ }
+ },
+ "ConfigureProp": {
+ "type": "object",
+ "allOf": [
+ {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "extraProps": {
+ "type": "object",
+ "properties": {}
+ }
+ }
+ },
+ {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/ConfigureFieldProp"
+ },
+ {
+ "$ref": "#/definitions/ConfigureGroupProp"
+ }
+ ]
+ }
+ ]
+ },
+ "ConfigureFieldProp": {
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "field"
+ ]
+ },
+ "name": {
+ "type": "string"
+ },
+ "setter": {
+ "$ref": "#/definitions/ConfigureFieldSetter"
+ }
+ }
+ },
+ "ConfigureFieldSetter": {
+ "type": "object",
+ "required": [
+ "componentName"
+ ],
+ "properties": {
+ "componentName": {
+ "type": "string",
+ "enum": [
+ "List",
+ "Object",
+ "Function",
+ "Node",
+ "Mixin",
+ "Expression",
+ "Switch",
+ "Number",
+ "Input",
+ "TextArea",
+ "Date",
+ "DateYear",
+ "DateMonth",
+ "DateRange",
+ "ColorPicker",
+ "CodeEditor",
+ "Select",
+ "RadioGroup"
+ ]
+ },
+ "props": {
+ "type": "object",
+ "properties": {}
+ }
+ }
+ },
+ "ConfigureGroupProp": {
+ "type": "object",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "group"
+ ]
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ConfigureProp"
+ }
+ }
+ }
+ },
+ "ConfigureComponent": {
+ "type": "object",
+ "properties": {
+ "isContainer": {
+ "type": "boolean"
+ },
+ "isModal": {
+ "type": "boolean"
+ },
+ "descriptor": {
+ "type": "string"
+ },
+ "nestingRule": {
+ "type": "object",
+ "properties": {
+ "childWhitelist": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "parentWhitelist": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "descendantBlacklist": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "ancestorWhitelist": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "isNullNode": {
+ "type": "boolean"
+ },
+ "isLayout": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/__snapshots__/dynamic.test.ts.snap b/modules/material-parser/test/__snapshots__/dynamic.test.ts.snap
new file mode 100644
index 0000000000..86aa94aedc
--- /dev/null
+++ b/modules/material-parser/test/__snapshots__/dynamic.test.ts.snap
@@ -0,0 +1,27 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`materialize dynamic component by online 1`] = `
+Array [
+ Object {
+ "componentName": "BizAnchor",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "lib/index.js",
+ "package": "@alifd/biz-anchor",
+ "subName": "",
+ "version": "1.1.7",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": false,
+ "name": "noHash",
+ },
+ ],
+ "screenshot": "",
+ "title": "@alifd/biz-anchor",
+ },
+]
+`;
diff --git a/modules/material-parser/test/__snapshots__/index.test.ts.snap b/modules/material-parser/test/__snapshots__/index.test.ts.snap
new file mode 100644
index 0000000000..561efc7f8b
--- /dev/null
+++ b/modules/material-parser/test/__snapshots__/index.test.ts.snap
@@ -0,0 +1,1753 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`d.ts component by local 1`] = `
+Array [
+ Object {
+ "componentName": "default",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "src/index.jsx",
+ "package": "dts-component",
+ "subName": "",
+ "version": "1.2.3",
+ },
+ "props": Array [
+ Object {
+ "description": "是否是财鲸主站,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "isMainSite",
+ "propType": "bool",
+ },
+ Object {
+ "description": "财鲸主站的 app 名称,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "mainSiteAppName",
+ "propType": "string",
+ },
+ Object {
+ "description": "主站中文名,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "mainSiteName",
+ "propType": "string",
+ },
+ Object {
+ "description": "主站英文名,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "mainSiteNameEn",
+ "propType": "string",
+ },
+ Object {
+ "description": "主站链接,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "mainSiteLink",
+ "propType": "string",
+ },
+ Object {
+ "description": "子站点的应用名,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "subSiteAppName",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "description": "子站点的名称,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "subSiteName",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "description": "子站点的英文名称,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "subSiteNameEn",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "description": "子站点的链接,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "subSiteLink",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "description": "子站访问相关接口时,属于buc 跨域请求,需要把 ssoTicket 带上,该字段由后端 vm 中吐出在 window.appConfig 中",
+ "name": "ssoTicket",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "description": "是否使用 ak/sk 方案(用于登录)",
+ "name": "aksk",
+ "propType": "bool",
+ },
+ Object {
+ "description": "是否显示左侧导航",
+ "name": "sidebarVisible",
+ "propType": "bool",
+ },
+ Object {
+ "description": "是否显示顶部菜单栏",
+ "name": "topbarVisible",
+ "propType": "bool",
+ },
+ Object {
+ "description": "是否开启全屏",
+ "name": "isFullScreen",
+ "propType": "bool",
+ },
+ Object {
+ "description": "当前选中的导航 key",
+ "name": "navSelectedKeys",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ Object {
+ "description": "history 对象",
+ "name": "history",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "object",
+ ],
+ },
+ },
+ Object {
+ "description": "左侧子导航数组",
+ "name": "nav",
+ "propType": Object {
+ "type": "arrayOf",
+ "value": "object",
+ },
+ },
+ Object {
+ "description": "Next Nav 组件本身的配置",
+ "name": "nextNavConfig",
+ "propType": "object",
+ },
+ Object {
+ "description": "切换语言的 Url",
+ "name": "setLanguageUrl",
+ "propType": "string",
+ },
+ Object {
+ "description": "顶部控件的扩展区渲染内容",
+ "name": "extra",
+ "propType": "node",
+ },
+ Object {
+ "description": "顶部导航站点名称后面的快速入口区域自定义渲染",
+ "name": "quickEntry",
+ "propType": "node",
+ },
+ Object {
+ "description": "水印配置项",
+ "name": "waterMarkOptions",
+ "propType": "object",
+ },
+ Object {
+ "description": "是否需要默认的登出行为",
+ "name": "needDefaultLogout",
+ "propType": "bool",
+ },
+ Object {
+ "description": "点击登出按钮后的回调函数",
+ "name": "onLogoutClick",
+ "propType": "func",
+ },
+ Object {
+ "description": "侧边栏收起展开回调函数",
+ "name": "onToggleMenu",
+ "propType": "func",
+ },
+ Object {
+ "description": "logo 的 style 覆盖",
+ "name": "logoStyle",
+ "propType": "object",
+ },
+ Object {
+ "description": "logo 点击事件,传入覆盖",
+ "name": "onLogoClick",
+ "propType": "func",
+ },
+ Object {
+ "description": "切换语言自定义事件",
+ "name": "onToggleLang",
+ "propType": Object {
+ "params": Array [
+ Object {
+ "name": "nextConfig",
+ "propType": "object",
+ },
+ Object {
+ "name": "appName",
+ "propType": "any",
+ },
+ ],
+ "raw": "(nextConfig: Record, appName: any) => void",
+ "type": "func",
+ },
+ },
+ Object {
+ "description": "语言切换器显示切换",
+ "name": "langVisible",
+ "propType": "bool",
+ },
+ Object {
+ "description": "打开启用浏览器缩放警告",
+ "name": "scaleWarning",
+ "propType": "bool",
+ },
+ Object {
+ "description": "This event is fired whenever the application navigates to a new page.",
+ "name": "test",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "dts-component",
+ },
+]
+`;
+
+exports[`materialize multiple exported component by local 1`] = `
+Array [
+ Object {
+ "componentName": "AIMakeBlank",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "AIMakeBlank",
+ "main": "es/index.js",
+ "package": "multiple-exported-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "styleBoxModel",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleLayout",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleBackground",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleFlexLayout",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ Object {
+ "name": "id",
+ "propType": "string",
+ },
+ ],
+ "screenshot": "",
+ "title": "multiple-exported-component",
+ },
+ Object {
+ "componentName": "AIMakeIcon",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "AIMakeIcon",
+ "main": "es/index.js",
+ "package": "multiple-exported-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "className",
+ "propType": "string",
+ },
+ Object {
+ "name": "iconClassName",
+ "propType": "string",
+ },
+ Object {
+ "name": "styleBoxModel",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleText",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleBackground",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "multiple-exported-component",
+ },
+ Object {
+ "componentName": "AIMakeImage",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "AIMakeImage",
+ "main": "es/index.js",
+ "package": "multiple-exported-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "styleBoxModel",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "multiple-exported-component",
+ },
+ Object {
+ "componentName": "AIMakeLink",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "AIMakeLink",
+ "main": "es/index.js",
+ "package": "multiple-exported-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "styleBoxModel",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleText",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleLayout",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleBackground",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "multiple-exported-component",
+ },
+ Object {
+ "componentName": "AIMakePlaceholder",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "AIMakePlaceholder",
+ "main": "es/index.js",
+ "package": "multiple-exported-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "styleBoxModel",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleLayout",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "multiple-exported-component",
+ },
+ Object {
+ "componentName": "AIMakeText",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "AIMakeText",
+ "main": "es/index.js",
+ "package": "multiple-exported-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "type",
+ "propType": "string",
+ },
+ Object {
+ "name": "styleBoxModel",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleText",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleLayout",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "styleBackground",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "multiple-exported-component",
+ },
+ Object {
+ "componentName": "Root",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "Root",
+ "main": "es/index.js",
+ "package": "multiple-exported-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "multiple-exported-component",
+ },
+]
+`;
+
+exports[`materialize single exported component by local 1`] = `
+Array [
+ Object {
+ "componentName": "Demo",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "src/index.js",
+ "package": "single-exported-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "optionalArray",
+ "propType": "array",
+ },
+ Object {
+ "name": "optionalBool",
+ "propType": "bool",
+ },
+ Object {
+ "description": "desc",
+ "name": "optionalFunc",
+ "propType": Object {
+ "params": Array [
+ Object {
+ "description": "The title of the book.",
+ "name": "title",
+ "propType": "string",
+ },
+ Object {
+ "description": "The author of the book.",
+ "name": "author",
+ "propType": "string",
+ },
+ ],
+ "raw": "(title: string, author: string) => any",
+ "returns": Object {
+ "propType": "any",
+ },
+ "type": "func",
+ },
+ },
+ Object {
+ "defaultValue": 123,
+ "name": "optionalNumber",
+ "propType": "number",
+ },
+ Object {
+ "name": "optionalObject",
+ "propType": "object",
+ },
+ Object {
+ "name": "optionalString",
+ "propType": "string",
+ },
+ Object {
+ "name": "optionalSymbol",
+ "propType": "symbol",
+ },
+ Object {
+ "name": "optionalNode",
+ "propType": "node",
+ },
+ Object {
+ "name": "optionalElement",
+ "propType": "element",
+ },
+ Object {
+ "name": "optionalElementType",
+ "propType": "object",
+ },
+ Object {
+ "name": "optionalMessage",
+ "propType": Object {
+ "type": "instanceOf",
+ "value": "Demo",
+ },
+ },
+ Object {
+ "name": "optionalEnum",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "News",
+ "Photos",
+ ],
+ },
+ },
+ Object {
+ "name": "optionalUnion",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ Object {
+ "type": "instanceOf",
+ "value": "Demo",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "optionalObjectOf",
+ "propType": Object {
+ "type": "objectOf",
+ "value": "number",
+ },
+ },
+ Object {
+ "name": "optionalObjectWithShape",
+ "propType": Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "optionalProperty",
+ "propType": "string",
+ },
+ Object {
+ "name": "requiredProperty",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "optionalObjectWithShape2",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "optionalProperty",
+ "propType": "string",
+ },
+ Object {
+ "name": "requiredProperty",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "optionalObjectWithStrictShape",
+ "propType": Object {
+ "type": "exact",
+ "value": Array [
+ Object {
+ "name": "optionalProperty",
+ "propType": "string",
+ },
+ Object {
+ "name": "requiredProperty",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "requiredFunc",
+ "propType": Object {
+ "isRequired": true,
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "requiredAny",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "single-exported-component",
+ },
+]
+`;
+
+exports[`rax component by local 1`] = `
+Array [
+ Object {
+ "componentName": "default",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "src/index.tsx",
+ "package": "@ali/chaoshi-meta-example",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "a",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "ref",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ Object {
+ "params": Array [
+ Object {
+ "name": "instance",
+ "propType": "object",
+ },
+ ],
+ "raw": "(instance: unknown) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "T",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "current",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "key",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "@ali/chaoshi-meta-example",
+ },
+ Object {
+ "componentName": "Price",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "Price",
+ "main": "src/index.tsx",
+ "package": "@ali/chaoshi-meta-example",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "color",
+ "propType": "string",
+ },
+ Object {
+ "name": "fontSize",
+ "propType": "number",
+ },
+ Object {
+ "name": "symbolSize",
+ "propType": "number",
+ },
+ Object {
+ "name": "decimalSize",
+ "propType": "number",
+ },
+ Object {
+ "name": "value",
+ "propType": "string",
+ },
+ Object {
+ "name": "autoScale",
+ "propType": "bool",
+ },
+ Object {
+ "name": "className",
+ "propType": "string",
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ Object {
+ "name": "rest",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "@ali/chaoshi-meta-example",
+ },
+ Object {
+ "componentName": "Title",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "Title",
+ "main": "src/index.tsx",
+ "package": "@ali/chaoshi-meta-example",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "type",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "small",
+ "medium",
+ "large",
+ ],
+ },
+ },
+ Object {
+ "name": "doubleLine",
+ "propType": "bool",
+ },
+ Object {
+ "name": "className",
+ "propType": "string",
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ Object {
+ "name": "rest",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "@ali/chaoshi-meta-example",
+ },
+]
+`;
+
+exports[`transpiled component by local 1`] = `
+Array [
+ Object {
+ "componentName": "MyComponent",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "\\"default\\"",
+ "main": "lib/index.js",
+ "package": "transpiled-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "description": "Description of prop \\"foo\\".",
+ "name": "foo",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ Object {
+ "defaultValue": 21,
+ "description": "Description of prop \\"bar\\" (a custom validation function).",
+ "name": "bar",
+ "propType": "object",
+ },
+ Object {
+ "name": "baz",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "number",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "optionalObjectWithShape2",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "optionalProperty",
+ "propType": "string",
+ },
+ Object {
+ "name": "requiredProperty",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "transpiled-component",
+ },
+]
+`;
+
+exports[`ts component 2 by local 1`] = `
+Array [
+ Object {
+ "componentName": "default",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "src/index.tsx",
+ "package": "@alife/empty",
+ "subName": "",
+ "version": "1.0.1",
+ },
+ "props": Array [
+ Object {
+ "name": "className",
+ "propType": "string",
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ Object {
+ "name": "imageStyle",
+ "propType": "object",
+ },
+ Object {
+ "name": "image",
+ "propType": "node",
+ },
+ Object {
+ "name": "description",
+ "propType": "node",
+ },
+ Object {
+ "name": "type",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "default",
+ "custom",
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "@alife/empty",
+ },
+]
+`;
+
+exports[`ts component by local 1`] = `
+Array [
+ Object {
+ "componentName": "default",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "src/index.tsx",
+ "package": "ts-component",
+ "subName": "",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "error",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "a",
+ "propType": "string",
+ },
+ ],
+ "raw": "(a: string) => number",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "void",
+ "propType": Object {
+ "isRequired": true,
+ "type": "void",
+ },
+ },
+ Object {
+ "name": "object",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "trigger",
+ "propType": Object {
+ "type": "arrayOf",
+ "value": Object {
+ "type": "oneOf",
+ "value": Array [
+ "click",
+ "hover",
+ "contextMenu",
+ ],
+ },
+ },
+ },
+ Object {
+ "name": "str",
+ "propType": "string",
+ },
+ Object {
+ "name": "num",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ Object {
+ "name": "any",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "bool",
+ "propType": Object {
+ "isRequired": true,
+ "type": "bool",
+ },
+ },
+ Object {
+ "name": "tuple",
+ "propType": Object {
+ "isRequired": true,
+ "type": "tuple",
+ "value": Array [
+ Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ Object {
+ "isRequired": true,
+ "type": "oneOf",
+ "value": Array [
+ true,
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "enum",
+ "propType": Object {
+ "isRequired": true,
+ "type": "oneOf",
+ "value": Array [
+ "red",
+ "yellow",
+ "green",
+ ],
+ },
+ },
+ Object {
+ "name": "arr",
+ "propType": Object {
+ "isRequired": true,
+ "type": "arrayOf",
+ "value": "number",
+ },
+ },
+ Object {
+ "name": "halfEmptyObj",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "fun",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "a",
+ "propType": Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ },
+ ],
+ "raw": "(a: string[]) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "emptyObj",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "func",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "arg",
+ "propType": "string",
+ },
+ ],
+ "raw": "(arg: string) => number",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "funcs",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "n",
+ "propType": Object {
+ "isRequired": true,
+ "raw": "() => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "a",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "arg",
+ "propType": "string",
+ },
+ Object {
+ "name": "num",
+ "propType": "number",
+ },
+ ],
+ "raw": "(arg: string, num: number) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "fuzzy",
+ "propType": Object {
+ "isRequired": true,
+ "type": "oneOfType",
+ "value": Array [
+ "number",
+ "bool",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "a",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "sa",
+ "propType": Object {
+ "isRequired": true,
+ "type": "arrayOf",
+ "value": "string",
+ },
+ },
+ ],
+ },
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "number",
+ "object",
+ "test",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "oneOf",
+ "propType": Object {
+ "isRequired": true,
+ "type": "oneOfType",
+ "value": Array [
+ "bool",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "s",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "n",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ ],
+ },
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "test",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "refFunc",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "p",
+ "propType": "object",
+ },
+ ],
+ "raw": "(p: Props) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "elementOrOther",
+ "propType": Object {
+ "isRequired": true,
+ "type": "oneOfType",
+ "value": Array [
+ "element",
+ Object {
+ "params": Array [
+ Object {
+ "name": "a",
+ "propType": "string",
+ },
+ ],
+ "raw": "Func",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "obj",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "a",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ Object {
+ "name": "arrOfStr",
+ "propType": Object {
+ "isRequired": true,
+ "type": "arrayOf",
+ "value": "string",
+ },
+ },
+ Object {
+ "name": "arrOfObj",
+ "propType": Object {
+ "isRequired": true,
+ "type": "arrayOf",
+ "value": Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "s",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "n",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ ],
+ },
+ },
+ },
+ Object {
+ "name": "func",
+ "propType": Object {
+ "isRequired": true,
+ "type": "func",
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "objOf",
+ "propType": Object {
+ "isRequired": true,
+ "type": "objectOf",
+ "value": "number",
+ },
+ },
+ Object {
+ "name": "exact",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "a",
+ "propType": Object {
+ "isRequired": true,
+ "type": "number",
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "node",
+ "propType": "node",
+ },
+ Object {
+ "name": "element",
+ "propType": "element",
+ },
+ Object {
+ "name": "elementType",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "symbol",
+ "object",
+ "html",
+ "loading",
+ "a",
+ "abbr",
+ "address",
+ "area",
+ "article",
+ "aside",
+ "audio",
+ "b",
+ "base",
+ "bdi",
+ "bdo",
+ "big",
+ "blockquote",
+ "body",
+ "br",
+ "button",
+ "canvas",
+ "caption",
+ "cite",
+ "code",
+ "col",
+ "colgroup",
+ "data",
+ "datalist",
+ "dd",
+ "del",
+ "details",
+ "dfn",
+ "dialog",
+ "div",
+ "dl",
+ "dt",
+ "em",
+ "embed",
+ "fieldset",
+ "figcaption",
+ "figure",
+ "footer",
+ "form",
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+ "head",
+ "header",
+ "hgroup",
+ "hr",
+ "i",
+ "iframe",
+ "img",
+ "input",
+ "ins",
+ "kbd",
+ "keygen",
+ "label",
+ "legend",
+ "li",
+ "link",
+ "main",
+ "map",
+ "mark",
+ "menu",
+ "menuitem",
+ "meta",
+ "meter",
+ "nav",
+ "noindex",
+ "noscript",
+ "ol",
+ "optgroup",
+ "option",
+ "output",
+ "p",
+ "param",
+ "picture",
+ "pre",
+ "progress",
+ "q",
+ "rp",
+ "rt",
+ "ruby",
+ "s",
+ "samp",
+ "script",
+ "section",
+ "select",
+ "small",
+ "source",
+ "span",
+ "strong",
+ "style",
+ "sub",
+ "summary",
+ "sup",
+ "table",
+ "tbody",
+ "td",
+ "textarea",
+ "tfoot",
+ "th",
+ "thead",
+ "time",
+ "title",
+ "tr",
+ "track",
+ "u",
+ "ul",
+ "var",
+ "video",
+ "wbr",
+ "webview",
+ "svg",
+ "animate",
+ "animateMotion",
+ "animateTransform",
+ "circle",
+ "clipPath",
+ "defs",
+ "desc",
+ "ellipse",
+ "feBlend",
+ "feColorMatrix",
+ "feComponentTransfer",
+ "feComposite",
+ "feConvolveMatrix",
+ "feDiffuseLighting",
+ "feDisplacementMap",
+ "feDistantLight",
+ "feDropShadow",
+ "feFlood",
+ "feFuncA",
+ "feFuncB",
+ "feFuncG",
+ "feFuncR",
+ "feGaussianBlur",
+ "feImage",
+ "feMerge",
+ "feMergeNode",
+ "feMorphology",
+ "feOffset",
+ "fePointLight",
+ "feSpecularLighting",
+ "feSpotLight",
+ "feTile",
+ "feTurbulence",
+ "filter",
+ "foreignObject",
+ "g",
+ "image",
+ "line",
+ "linearGradient",
+ "marker",
+ "mask",
+ "metadata",
+ "mpath",
+ "path",
+ "pattern",
+ "polygon",
+ "polyline",
+ "radialGradient",
+ "rect",
+ "stop",
+ "switch",
+ "text",
+ "textPath",
+ "tspan",
+ "use",
+ "view",
+ "list",
+ "cell",
+ "refresh",
+ "recycle-list",
+ "scroller",
+ "slider",
+ "indicator",
+ "waterfall",
+ "web",
+ "richtext",
+ "slot",
+ "swiper",
+ "swiper-item",
+ "scroll-view",
+ "cover-view",
+ "cover-image",
+ "camera",
+ "movable-view",
+ "movable-area",
+ "match-media",
+ "icon",
+ "rich-text",
+ "radio",
+ "radio-group",
+ "picker-view",
+ "picker",
+ "navigator",
+ "web-view",
+ "lifestyle",
+ "contact-button",
+ "aria-component",
+ "functional-page-navigator",
+ "live-player",
+ "live-pusher",
+ "ad",
+ "ad-custom",
+ "open-data",
+ "voip-room",
+ "page-meta",
+ "picker-view-column",
+ "official-account",
+ "navigation-bar",
+ "template",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "union",
+ "propType": Object {
+ "isRequired": true,
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "a",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "func2",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "a",
+ "propType": "string",
+ },
+ ],
+ "raw": "Func",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "html",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ Object {
+ "name": "loading",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "bool",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "delay",
+ "propType": "number",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "ts-component",
+ },
+ Object {
+ "componentName": "SubModule",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "src/index.tsx",
+ "package": "ts-component",
+ "subName": "SubModule",
+ "version": "1.0.0",
+ },
+ "props": Array [
+ Object {
+ "name": "name",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "ts-component",
+ },
+]
+`;
+
+exports[`without display name by local 1`] = `Array []`;
diff --git a/modules/material-parser/test/__snapshots__/online.test.ts.snap b/modules/material-parser/test/__snapshots__/online.test.ts.snap
new file mode 100644
index 0000000000..4591246ffa
--- /dev/null
+++ b/modules/material-parser/test/__snapshots__/online.test.ts.snap
@@ -0,0 +1,5780 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`materialize mc-hello by online 1`] = `
+Array [
+ Object {
+ "componentName": "default",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "lib/index.js",
+ "package": "mc-hello",
+ "subName": "",
+ "version": "1.0.1",
+ },
+ "props": Array [
+ Object {
+ "name": "color",
+ "propType": "string",
+ },
+ Object {
+ "name": "background",
+ "propType": "string",
+ },
+ Object {
+ "defaultValue": false,
+ "name": "round",
+ "propType": "bool",
+ },
+ Object {
+ "defaultValue": 200,
+ "name": "width",
+ "propType": "number",
+ },
+ Object {
+ "defaultValue": 40,
+ "name": "height",
+ "propType": "number",
+ },
+ Object {
+ "name": "children",
+ "propType": "node",
+ },
+ ],
+ "screenshot": "",
+ "title": "mc-hello",
+ },
+]
+`;
+
+exports[`materialize online rax module by path & specify workDir 1`] = `
+Array [
+ Object {
+ "componentName": "default",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "es/common/index.d.ts",
+ "package": "rax-view",
+ "subName": "",
+ "version": "2.2.1",
+ },
+ "props": Array [
+ Object {
+ "name": "ref",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ Object {
+ "params": Array [
+ Object {
+ "name": "instance",
+ "propType": "object",
+ },
+ ],
+ "raw": "(instance: HTMLDivElement) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "T",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "current",
+ "propType": Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "key",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": "object",
+ },
+ Object {
+ "name": "className",
+ "propType": "string",
+ },
+ ],
+ "screenshot": "",
+ "title": "rax-view",
+ },
+]
+`;
+
+exports[`materialize rc-picker by online 1`] = `
+Array [
+ Object {
+ "componentName": "PickerPanel",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "PickerPanel",
+ "main": "./lib/index",
+ "package": "rc-picker",
+ "subName": "",
+ "version": "2.4.3",
+ },
+ "props": Array [
+ Object {
+ "name": "picker",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "prefixCls",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "className",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "description": "@deprecated Will be removed in next big version. Please use \`mode\` instead",
+ "name": "mode",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ "decade",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "tabIndex",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthBeforeYear",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "yearFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthFormat",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "quarterFormat",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "today",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "now",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "backToToday",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "ok",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "timeSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "weekSelect",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "clear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "month",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "year",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousMonth",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextMonth",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "yearSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "decadeSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dayFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateTimeFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousYear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextYear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousDecade",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextDecade",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousCentury",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextCentury",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "shortWeekDays",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "shortMonths",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "generateConfig",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "DateType",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "getWeekDay",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getSecond",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getMinute",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getHour",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getNow",
+ "propType": Object {
+ "isRequired": true,
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getFixedDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "fixed",
+ "propType": "string",
+ },
+ ],
+ "raw": "(fixed: string) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getEndDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "year",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, year: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "month",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, month: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "date",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, date: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setHour",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, hour: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setMinute",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "minute",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, minute: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setSecond",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "second",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, second: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "isAfter",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "date1",
+ "propType": "object",
+ },
+ Object {
+ "name": "date2",
+ "propType": "object",
+ },
+ ],
+ "raw": "(date1: DateType, date2: DateType) => boolean",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "isValidate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "date",
+ "propType": "object",
+ },
+ ],
+ "raw": "(date: DateType) => boolean",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "getWeekFirstDay",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getWeekFirstDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(locale: string, value: DateType) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getWeek",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(locale: string, value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "format",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "date",
+ "propType": "object",
+ },
+ Object {
+ "name": "format",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string, date: DateType, format: string) => string",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "parse",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "text",
+ "propType": "string",
+ },
+ Object {
+ "name": "formats",
+ "propType": Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ },
+ ],
+ "raw": "(locale: string, text: string, formats: string[]) => DateType | null",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getShortWeekDays",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => string[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "getShortMonths",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => string[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "value",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "null",
+ ],
+ },
+ },
+ Object {
+ "name": "defaultValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "description": "[Legacy] Set default display picker view date",
+ "name": "pickerValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "description": "[Legacy] Set default display picker view date",
+ "name": "defaultPickerValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "name": "disabledDate",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "dateRender",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "monthCellRender",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "renderExtraFooter",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "mode",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ "decade",
+ ],
+ },
+ },
+ ],
+ "raw": "(mode: PanelMode) => ReactNode",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onSelect",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onPanelChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseDown",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onOk",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "direction",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "ltr",
+ "rtl",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "description": "@private This is internal usage. Do not use in your production env",
+ "name": "hideHeader",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "description": "@private This is internal usage. Do not use in your production env",
+ "name": "onPickerValueChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "description": "@private Internal usage. Do not use in your production env",
+ "name": "components",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "button",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "rangeItem",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "showToday",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showNow",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showTime",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "DateType",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "format",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "showNow",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showHour",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showMinute",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showSecond",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "use12Hours",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "hourStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "minuteStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "secondStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "hideDisabledOptions",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "defaultValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabledTime",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "format",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "showHour",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showMinute",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showSecond",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "use12Hours",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "hourStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "minuteStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "secondStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "hideDisabledOptions",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "disabledHours",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "disabledMinutes",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ ],
+ "raw": "(hour: number) => number[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabledSeconds",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ Object {
+ "name": "minute",
+ "propType": "number",
+ },
+ ],
+ "raw": "(hour: number, minute: number) => number[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "rc-picker",
+ },
+ Object {
+ "componentName": "RangePicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "RangePicker",
+ "main": "./lib/index",
+ "package": "rc-picker",
+ "subName": "",
+ "version": "2.4.3",
+ },
+ "props": Array [
+ Object {
+ "name": "id",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "value",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "null",
+ Object {
+ "type": "tuple",
+ "value": Array [
+ Object {
+ "isRequired": true,
+ "type": "oneOfType",
+ "value": Array [
+ "null",
+ "object",
+ ],
+ },
+ Object {
+ "isRequired": true,
+ "type": "oneOfType",
+ "value": Array [
+ "null",
+ "object",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "defaultValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "null",
+ Object {
+ "type": "tuple",
+ "value": Array [
+ Object {
+ "isRequired": true,
+ "type": "oneOfType",
+ "value": Array [
+ "null",
+ "object",
+ ],
+ },
+ Object {
+ "isRequired": true,
+ "type": "oneOfType",
+ "value": Array [
+ "null",
+ "object",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "defaultPickerValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "tuple",
+ "value": Array [
+ Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ Object {
+ "isRequired": true,
+ "type": "object",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "placeholder",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "tuple",
+ "value": Array [
+ Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabled",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ Object {
+ "type": "tuple",
+ "value": Array [
+ Object {
+ "isRequired": true,
+ "type": "bool",
+ },
+ Object {
+ "isRequired": true,
+ "type": "bool",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabledTime",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "ranges",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "objectOf",
+ "value": "oneOfType",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "separator",
+ "propType": "node",
+ },
+ Object {
+ "name": "allowEmpty",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "tuple",
+ "value": Array [
+ Object {
+ "isRequired": true,
+ "type": "bool",
+ },
+ Object {
+ "isRequired": true,
+ "type": "bool",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "mode",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "tuple",
+ "value": Array [
+ Object {
+ "isRequired": true,
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ "decade",
+ ],
+ },
+ Object {
+ "isRequired": true,
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ "decade",
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onCalendarChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onPanelChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onFocus",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: FocusEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onBlur",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: FocusEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onOk",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "direction",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "ltr",
+ "rtl",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "autoComplete",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "description": "@private Internal control of active picker. Do not use since it's private usage",
+ "name": "activePickerIndex",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ 0,
+ 1,
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "dateRender",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "panelRender",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "originPanel",
+ "propType": "node",
+ },
+ ],
+ "raw": "(originPanel: ReactNode) => ReactNode",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "picker",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "prefixCls",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "className",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "name": "tabIndex",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthBeforeYear",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "yearFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthFormat",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "quarterFormat",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "today",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "now",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "backToToday",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "ok",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "timeSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "weekSelect",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "clear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "month",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "year",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousMonth",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextMonth",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "yearSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "decadeSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dayFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateTimeFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousYear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextYear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousDecade",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextDecade",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousCentury",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextCentury",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "shortWeekDays",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "shortMonths",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "generateConfig",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "DateType",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "getWeekDay",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getSecond",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getMinute",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getHour",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getNow",
+ "propType": Object {
+ "isRequired": true,
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getFixedDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "fixed",
+ "propType": "string",
+ },
+ ],
+ "raw": "(fixed: string) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getEndDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "year",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, year: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "month",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, month: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "date",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, date: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setHour",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, hour: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setMinute",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "minute",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, minute: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setSecond",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "second",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, second: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "isAfter",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "date1",
+ "propType": "object",
+ },
+ Object {
+ "name": "date2",
+ "propType": "object",
+ },
+ ],
+ "raw": "(date1: DateType, date2: DateType) => boolean",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "isValidate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "date",
+ "propType": "object",
+ },
+ ],
+ "raw": "(date: DateType) => boolean",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "getWeekFirstDay",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getWeekFirstDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(locale: string, value: DateType) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getWeek",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(locale: string, value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "format",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "date",
+ "propType": "object",
+ },
+ Object {
+ "name": "format",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string, date: DateType, format: string) => string",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "parse",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "text",
+ "propType": "string",
+ },
+ Object {
+ "name": "formats",
+ "propType": Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ },
+ ],
+ "raw": "(locale: string, text: string, formats: string[]) => DateType | null",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getShortWeekDays",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => string[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "getShortMonths",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => string[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabledDate",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "monthCellRender",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "renderExtraFooter",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "mode",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ "decade",
+ ],
+ },
+ },
+ ],
+ "raw": "(mode: PanelMode) => ReactNode",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseDown",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "description": "@private Internal usage. Do not use in your production env",
+ "name": "components",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "button",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "rangeItem",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "dropdownClassName",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "dropdownAlign",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "points",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "offset",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "number",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "targetOffset",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "number",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "overflow",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "adjustX",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "adjustY",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ "bool",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "useCssRight",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "useCssBottom",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "useCssTransform",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "ignoreShake",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "popupStyle",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "name": "transitionName",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "allowClear",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "autoFocus",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "open",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "defaultOpen",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "description": "Make input readOnly to avoid popup keyboard in mobile",
+ "name": "inputReadOnly",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "format",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ "func",
+ Object {
+ "type": "arrayOf",
+ "value": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "func",
+ ],
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "suffixIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "clearIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "prevIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "nextIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "superPrevIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "superNextIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "getPopupContainer",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "node",
+ "propType": "object",
+ },
+ ],
+ "raw": "(node: HTMLElement) => HTMLElement",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onOpenChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "open",
+ "propType": "bool",
+ },
+ ],
+ "raw": "(open: boolean) => void",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseUp",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseEnter",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseLeave",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onClick",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onContextMenu",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "description": "@private Internal usage, do not use in production mode!!!",
+ "name": "pickerRef",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "name": "role",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "name",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "showTime",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showNow",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "order",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showHour",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showMinute",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showSecond",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "use12Hours",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "hourStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "minuteStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "secondStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "hideDisabledOptions",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "disabledHours",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "disabledMinutes",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ ],
+ "raw": "(hour: number) => number[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabledSeconds",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ Object {
+ "name": "minute",
+ "propType": "number",
+ },
+ ],
+ "raw": "(hour: number, minute: number) => number[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "description": "@deprecated Please use \`defaultValue\` directly instead",
+ "name": "defaultOpenValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "rc-picker",
+ },
+ Object {
+ "componentName": "default",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "./lib/index",
+ "package": "rc-picker",
+ "subName": "",
+ "version": "2.4.3",
+ },
+ "props": Array [
+ Object {
+ "name": "dropdownClassName",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "dropdownAlign",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "points",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "offset",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "number",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "targetOffset",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "number",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "overflow",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "adjustX",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "adjustY",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ "bool",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "useCssRight",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "useCssBottom",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "useCssTransform",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "ignoreShake",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "popupStyle",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "name": "transitionName",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "placeholder",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "allowClear",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "autoFocus",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "disabled",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "tabIndex",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "open",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "defaultOpen",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "description": "Make input readOnly to avoid popup keyboard in mobile",
+ "name": "inputReadOnly",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "id",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "format",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ "func",
+ Object {
+ "type": "arrayOf",
+ "value": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "func",
+ ],
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "suffixIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "clearIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "prevIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "nextIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "superPrevIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "superNextIcon",
+ "propType": "node",
+ },
+ Object {
+ "name": "getPopupContainer",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "node",
+ "propType": "object",
+ },
+ ],
+ "raw": "(node: HTMLElement) => HTMLElement",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "panelRender",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "originPanel",
+ "propType": "node",
+ },
+ ],
+ "raw": "(originPanel: ReactNode) => ReactNode",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onOpenChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "open",
+ "propType": "bool",
+ },
+ ],
+ "raw": "(open: boolean) => void",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onFocus",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: FocusEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onBlur",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: FocusEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseDown",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseUp",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseEnter",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onMouseLeave",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onClick",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onContextMenu",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "event",
+ "propType": "object",
+ },
+ ],
+ "raw": "(event: MouseEvent) => void",
+ "returns": Object {
+ "propType": "number",
+ },
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "description": "@private Internal usage, do not use in production mode!!!",
+ "name": "pickerRef",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "name": "role",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "name",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "autoComplete",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "direction",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "ltr",
+ "rtl",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "value",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "null",
+ ],
+ },
+ },
+ Object {
+ "name": "defaultValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "description": "[Legacy] Set default display picker view date",
+ "name": "defaultPickerValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "description": "@deprecated Will be removed in next big version. Please use \`mode\` instead",
+ "name": "mode",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ "decade",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "onSelect",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onPanelChange",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "onOk",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "dateRender",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "picker",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "prefixCls",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "className",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "style",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthBeforeYear",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "yearFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthFormat",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "quarterFormat",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "today",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "now",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "backToToday",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "ok",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "timeSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "weekSelect",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "clear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "month",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "year",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousMonth",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextMonth",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "monthSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "yearSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "decadeSelect",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dayFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "dateTimeFormat",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousYear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextYear",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousDecade",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextDecade",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "previousCentury",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "nextCentury",
+ "propType": Object {
+ "isRequired": true,
+ "type": "string",
+ },
+ },
+ Object {
+ "name": "shortWeekDays",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "shortMonths",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "generateConfig",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "DateType",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "getWeekDay",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getSecond",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getMinute",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getHour",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getNow",
+ "propType": Object {
+ "isRequired": true,
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getFixedDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "fixed",
+ "propType": "string",
+ },
+ ],
+ "raw": "(fixed: string) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getEndDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(value: DateType) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "addDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "diff",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, diff: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setYear",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "year",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, year: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setMonth",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "month",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, month: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "date",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, date: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setHour",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, hour: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setMinute",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "minute",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, minute: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "setSecond",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ Object {
+ "name": "second",
+ "propType": "number",
+ },
+ ],
+ "raw": "(value: DateType, second: number) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "isAfter",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "date1",
+ "propType": "object",
+ },
+ Object {
+ "name": "date2",
+ "propType": "object",
+ },
+ ],
+ "raw": "(date1: DateType, date2: DateType) => boolean",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "isValidate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "date",
+ "propType": "object",
+ },
+ ],
+ "raw": "(date: DateType) => boolean",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "locale",
+ "propType": Object {
+ "isRequired": true,
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "getWeekFirstDay",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getWeekFirstDate",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(locale: string, value: DateType) => DateType",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getWeek",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "value",
+ "propType": "object",
+ },
+ ],
+ "raw": "(locale: string, value: DateType) => number",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "format",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "date",
+ "propType": "object",
+ },
+ Object {
+ "name": "format",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string, date: DateType, format: string) => string",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "parse",
+ "propType": Object {
+ "isRequired": true,
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ Object {
+ "name": "text",
+ "propType": "string",
+ },
+ Object {
+ "name": "formats",
+ "propType": Object {
+ "type": "arrayOf",
+ "value": "string",
+ },
+ },
+ ],
+ "raw": "(locale: string, text: string, formats: string[]) => DateType | null",
+ "type": "func",
+ },
+ },
+ Object {
+ "name": "getShortWeekDays",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => string[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "getShortMonths",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "locale",
+ "propType": "string",
+ },
+ ],
+ "raw": "(locale: string) => string[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabledDate",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "monthCellRender",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "renderExtraFooter",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "mode",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "time",
+ "date",
+ "week",
+ "month",
+ "quarter",
+ "year",
+ "decade",
+ ],
+ },
+ },
+ ],
+ "raw": "(mode: PanelMode) => ReactNode",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "description": "@private Internal usage. Do not use in your production env",
+ "name": "components",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "button",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "rangeItem",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabledTime",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "showToday",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showTime",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ Object {
+ "type": "shape",
+ "value": Array [
+ Object {
+ "name": "DateType",
+ "propType": Object {
+ "isRequired": true,
+ "type": "any",
+ },
+ },
+ Object {
+ "name": "format",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "string",
+ ],
+ },
+ },
+ Object {
+ "name": "showNow",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showHour",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showMinute",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showSecond",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "use12Hours",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "hourStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "minuteStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "secondStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "hideDisabledOptions",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "defaultValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "showNow",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "description": "@deprecated Please use \`defaultValue\` directly instead",
+ "name": "defaultOpenValue",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ ],
+ },
+ },
+ Object {
+ "name": "showHour",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showMinute",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "showSecond",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "use12Hours",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "hourStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "minuteStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "secondStep",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "hideDisabledOptions",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "bool",
+ ],
+ },
+ },
+ Object {
+ "name": "disabledHours",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ "func",
+ ],
+ },
+ },
+ Object {
+ "name": "disabledMinutes",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ ],
+ "raw": "(hour: number) => number[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ Object {
+ "name": "disabledSeconds",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "object",
+ Object {
+ "params": Array [
+ Object {
+ "name": "hour",
+ "propType": "number",
+ },
+ Object {
+ "name": "minute",
+ "propType": "number",
+ },
+ ],
+ "raw": "(hour: number, minute: number) => number[]",
+ "type": "func",
+ },
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "rc-picker",
+ },
+]
+`;
+
+exports[`materialize react-color by online 1`] = `
+Array [
+ Object {
+ "componentName": "BlockPicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "BlockPicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": 170,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "triangle",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "top",
+ "hide",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "CirclePicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "CirclePicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": 252,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": 28,
+ "name": "circleSize",
+ "propType": "number",
+ },
+ Object {
+ "defaultValue": 14,
+ "name": "circleSpacing",
+ "propType": "number",
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "default",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": false,
+ "exportName": "default",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": 225,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": false,
+ "name": "disableAlpha",
+ "propType": "bool",
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ Object {
+ "name": "defaultView",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "hex",
+ "rgb",
+ "hsl",
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "ChromePicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "ChromePicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": 225,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": false,
+ "name": "disableAlpha",
+ "propType": "bool",
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ Object {
+ "name": "defaultView",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "hex",
+ "rgb",
+ "hsl",
+ ],
+ },
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "CompactPicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "CompactPicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "GithubPicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "GithubPicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": 200,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "triangle",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "hide",
+ "top-left",
+ "top-right",
+ "bottom-left",
+ "bottom-right",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "HuePicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "HuePicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "PhotoshopPicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "PhotoshopPicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "name": "header",
+ "propType": "string",
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "SketchPicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "SketchPicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": false,
+ "name": "disableAlpha",
+ "propType": "bool",
+ },
+ Object {
+ "defaultValue": 200,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "SliderPicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "SliderPicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "SwatchesPicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "SwatchesPicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": 320,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": 240,
+ "name": "height",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "TwitterPicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "TwitterPicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": 276,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "name": "triangle",
+ "propType": Object {
+ "type": "oneOf",
+ "value": Array [
+ "hide",
+ "top-left",
+ "top-right",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+ Object {
+ "componentName": "GooglePicker",
+ "devMode": "proCode",
+ "docUrl": "",
+ "npm": Object {
+ "destructuring": true,
+ "exportName": "GooglePicker",
+ "main": "lib/index.js",
+ "package": "react-color",
+ "subName": "",
+ "version": "2.19.3",
+ },
+ "props": Array [
+ Object {
+ "defaultValue": 652,
+ "name": "width",
+ "propType": Object {
+ "type": "oneOfType",
+ "value": Array [
+ "string",
+ "number",
+ ],
+ },
+ },
+ Object {
+ "defaultValue": Object {},
+ "name": "styles",
+ "propType": "object",
+ },
+ Object {
+ "name": "header",
+ "propType": "string",
+ },
+ ],
+ "screenshot": "",
+ "title": "react-color",
+ },
+]
+`;
diff --git a/modules/material-parser/test/dynamic.test.ts b/modules/material-parser/test/dynamic.test.ts
new file mode 100644
index 0000000000..f2731f0c91
--- /dev/null
+++ b/modules/material-parser/test/dynamic.test.ts
@@ -0,0 +1,14 @@
+import parse from '../src';
+import { IMaterializeOptions } from '../src/types';
+
+const dynamicComponent = '@alifd/biz-anchor@1.1.7';
+
+test('materialize dynamic component by online', async () => {
+ const options: IMaterializeOptions = {
+ entry: dynamicComponent,
+ accesser: 'online',
+ };
+
+ const actual = await parse(options);
+ expect(actual).toMatchSnapshot();
+});
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/dts-component/index.d.ts b/modules/material-parser/test/fixtures/dts-component/index.d.ts
new file mode 100644
index 0000000000..a9e95203f3
--- /dev/null
+++ b/modules/material-parser/test/fixtures/dts-component/index.d.ts
@@ -0,0 +1,168 @@
+import * as React from 'react';
+
+/**
+ * 财鲸Layout属性配置
+ */
+export interface WhaleLayoutProps {
+ /**
+ * 是否是财鲸主站,该字段由后端 vm 中吐出在 window.appConfig 中
+ * @defaultValue false
+ */
+ isMainSite?: boolean;
+ /**
+ * 财鲸主站的 app 名称,该字段由后端 vm 中吐出在 window.appConfig 中
+ * @defaultValue 'caijing'
+ */
+ mainSiteAppName?: string;
+ /**
+ * 主站中文名,该字段由后端 vm 中吐出在 window.appConfig 中
+ * @defaultValue '财鲸'
+ */
+ mainSiteName?: string;
+ /**
+ * 主站英文名,该字段由后端 vm 中吐出在 window.appConfig 中
+ * @defaultValue 'Caijing'
+ */
+ mainSiteNameEn?: string;
+ /**
+ * 主站链接,该字段由后端 vm 中吐出在 window.appConfig 中
+ * @defaultValue '//caijing.alibaba-inc.com'
+ */
+ mainSiteLink?: string;
+ /**
+ * 子站点的应用名,该字段由后端 vm 中吐出在 window.appConfig 中
+ */
+ subSiteAppName: string;
+ /**
+ * 子站点的名称,该字段由后端 vm 中吐出在 window.appConfig 中
+ */
+ subSiteName: string;
+ /**
+ * 子站点的英文名称,该字段由后端 vm 中吐出在 window.appConfig 中
+ */
+ subSiteNameEn: string;
+ /**
+ * 子站点的链接,该字段由后端 vm 中吐出在 window.appConfig 中
+ */
+ subSiteLink: string;
+ /**
+ * 子站访问相关接口时,属于buc 跨域请求,需要把 ssoTicket 带上,该字段由后端 vm 中吐出在 window.appConfig 中
+ */
+ ssoTicket: string;
+ /**
+ * 是否使用 ak/sk 方案(用于登录)
+ * @defaultValue false
+ */
+ aksk?: boolean;
+ /**
+ * 是否显示左侧导航
+ * @defaultValue true
+ */
+ sidebarVisible?: boolean;
+ /**
+ * 是否显示顶部菜单栏
+ * @defaultValue true
+ */
+ topbarVisible?: boolean;
+ /**
+ * 是否开启全屏
+ * @defaultValue false
+ */
+ isFullScreen?: boolean;
+ /**
+ * 当前选中的导航 key
+ * @defaultValue 'home'
+ */
+ navSelectedKeys?: string | string[];
+ /**
+ * history 对象
+ * @defaultValue {}
+ */
+ history?: string | {};
+ /**
+ * 左侧子导航数组
+ * 参考:https://whale.fusion.alibaba-inc.com/73015/component/basic/nav#demo-api
+ * @defaultValue []
+ */
+ nav?: Array<{}>;
+ /**
+ * Next Nav 组件本身的配置
+ * @defaultValue {}
+ */
+ nextNavConfig?: {};
+ /**
+ * 切换语言的 Url
+ * @defaultValue null
+ */
+ setLanguageUrl?: string;
+ /**
+ * 顶部控件的扩展区渲染内容
+ * @defaultValue null
+ */
+ extra?: React.ReactNode;
+ /**
+ * 顶部导航站点名称后面的快速入口区域自定义渲染
+ * @defaultValue null
+ */
+ quickEntry?: React.ReactNode;
+ /**
+ * 水印配置项
+ * 配置文档参考:{@link https://npm.alibaba-inc.com/package/@alife/waterMark}
+ * @defaultValue null
+ */
+ waterMarkOptions?: {};
+ /**
+ * 是否需要默认的登出行为
+ * @defaultValue true
+ */
+ needDefaultLogout?: boolean;
+ /**
+ * 点击登出按钮后的回调函数
+ * @defaultValue null
+ */
+ onLogoutClick?: () => void;
+ /**
+ * 侧边栏收起展开回调函数
+ * @defaultValue null
+ */
+ onToggleMenu?: () => void;
+ /**
+ * logo 的 style 覆盖
+ * @defaultValue null
+ */
+ logoStyle?: React.CSSProperties;
+ /**
+ * logo 点击事件,传入覆盖
+ * @defaultValue null
+ */
+ onLogoClick?: () => void;
+ /**
+ * 切换语言自定义事件
+ *
+ */
+ onToggleLang?: (nextConfig: Record, appName: any) => void;
+ /**
+ * 语言切换器显示切换
+ * @defaultValueValue true
+ */
+ langVisible?: boolean;
+ /**
+ * 打开启用浏览器缩放警告
+ * @defaultValue `true`
+ */
+ scaleWarning?: boolean;
+ /**
+ * This event is fired whenever the application navigates to a new page.
+ * @eventProperty
+ */
+ test: string;
+}
+
+/**
+ * 财鲸Layout owner: 昔夜
+ *
+ * 查看组件文档: https://whale.fusion.alibaba-inc.com/73015/component/bizcomps/692
+ */
+declare class WhaleLayout extends React.Component { }
+
+export default WhaleLayout;
diff --git a/modules/material-parser/test/fixtures/dts-component/package.json b/modules/material-parser/test/fixtures/dts-component/package.json
new file mode 100644
index 0000000000..09eb1bbc87
--- /dev/null
+++ b/modules/material-parser/test/fixtures/dts-component/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "dts-component",
+ "version": "1.2.3",
+ "main": "./src/index.jsx"
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/dts-component/src/data.js b/modules/material-parser/test/fixtures/dts-component/src/data.js
new file mode 100644
index 0000000000..aeee9f4662
--- /dev/null
+++ b/modules/material-parser/test/fixtures/dts-component/src/data.js
@@ -0,0 +1,1264 @@
+export default [
+ {
+ countryKey: 'CN',
+ value: '+86',
+ countryName_zh: '中国',
+ countryName: 'China',
+ flag: 'C',
+ },
+ {
+ countryKey: 'US',
+ value: '+1',
+ countryName_zh: '美国',
+ countryName: 'United States',
+ flag: 'U',
+ }, {
+ countryKey: 'JP',
+ value: '+81',
+ countryName_zh: '日本',
+ countryName: 'Japan',
+ flag: 'J',
+ }, {
+ countryKey: 'TW',
+ value: '+886',
+ countryName_zh: '中国台湾',
+ countryName: 'Taiwan',
+ flag: 'T',
+ }, {
+ countryKey: 'HK',
+ value: '+852',
+ countryName_zh: '中国香港',
+ countryName: 'Hong Kong',
+ flag: 'H',
+ }, {
+ countryKey: 'IN',
+ value: '+91',
+ countryName_zh: '印度',
+ countryName: 'India',
+ flag: 'I',
+ }, {
+ countryKey: 'AF',
+ value: '+93',
+ countryName_zh: '阿富汗',
+ countryName: 'Afghanistan',
+ flag: 'A',
+ }, {
+ countryKey: 'AL',
+ value: '+355',
+ countryName_zh: '阿尔巴尼亚',
+ countryName: 'Albania',
+ flag: 'A',
+ }, {
+ countryKey: 'DZ',
+ value: '+213',
+ countryName_zh: '阿尔及利亚',
+ countryName: 'Algeria',
+ flag: 'A',
+ }, {
+ countryKey: 'AD',
+ value: '+376',
+ countryName_zh: '安道尔',
+ countryName: 'Andorra',
+ flag: 'A',
+ }, {
+ countryKey: 'AO',
+ value: '+244',
+ countryName_zh: '安哥拉',
+ countryName: 'Angola',
+ flag: 'A',
+ }, {
+ countryKey: 'AI',
+ value: '+1264',
+ countryName_zh: '安圭拉岛',
+ countryName: 'Anguilla',
+ flag: 'A',
+ }, {
+ countryKey: 'AG',
+ value: '+1268',
+ countryName_zh: '安提瓜岛和巴布达',
+ countryName: 'Antigua and Barbuda',
+ flag: 'A',
+ }, {
+ countryKey: 'AR',
+ value: '+54',
+ countryName_zh: '阿根廷',
+ countryName: 'Argentina',
+ flag: 'A',
+ }, {
+ countryKey: 'AM',
+ value: '+374',
+ countryName_zh: '亚美尼亚',
+ countryName: 'Armenia',
+ flag: 'A',
+ }, {
+ countryKey: 'AW',
+ value: '+297',
+ countryName_zh: '阿鲁巴',
+ countryName: 'Aruba',
+ flag: 'A',
+ }, {
+ countryKey: 'AU',
+ value: '+61',
+ countryName_zh: '澳大利亚',
+ countryName: 'Australia',
+ flag: 'A',
+ }, {
+ countryKey: 'AT',
+ value: '+43',
+ countryName_zh: '奥地利',
+ countryName: 'Austria',
+ flag: 'A',
+ }, {
+ countryKey: 'AZ',
+ value: '+994',
+ countryName_zh: '阿塞拜疆',
+ countryName: 'Azerbaijan',
+ flag: 'A',
+ }, {
+ countryKey: 'BS',
+ value: '+1242',
+ countryName_zh: '巴哈马',
+ countryName: 'Bahamas',
+ flag: 'B',
+ }, {
+ countryKey: 'BH',
+ value: '+973',
+ countryName_zh: '巴林',
+ countryName: 'Bahrain',
+ flag: 'B',
+ }, {
+ countryKey: 'BD',
+ value: '+880',
+ countryName_zh: '孟加拉',
+ countryName: 'Bangladesh',
+ flag: 'B',
+ }, {
+ countryKey: 'BB',
+ value: '+1246',
+ countryName_zh: '巴巴多斯岛',
+ countryName: 'Barbados',
+ flag: 'B',
+ }, {
+ countryKey: 'BY',
+ value: '+375',
+ countryName_zh: '白俄罗斯',
+ countryName: 'Belarus',
+ flag: 'B',
+ }, {
+ countryKey: 'BE',
+ value: '+32',
+ countryName_zh: '比利时',
+ countryName: 'Belgium',
+ flag: 'B',
+ }, {
+ countryKey: 'BZ',
+ value: '+501',
+ countryName_zh: '伯利兹',
+ countryName: 'Belize',
+ flag: 'B',
+ }, {
+ countryKey: 'BJ',
+ value: '+229',
+ countryName_zh: '贝宁',
+ countryName: 'Benin',
+ flag: 'B',
+ }, {
+ countryKey: 'BM',
+ value: '+1441',
+ countryName_zh: '百慕大',
+ countryName: 'Bermuda',
+ flag: 'B',
+ }, {
+ countryKey: 'BT',
+ value: '+975',
+ countryName_zh: '不丹',
+ countryName: 'Bhutan',
+ flag: 'B',
+ }, {
+ countryKey: 'BO',
+ value: '+591',
+ countryName_zh: '玻利维亚',
+ countryName: 'Bolivia',
+ flag: 'B',
+ }, {
+ countryKey: 'BA',
+ value: '+387',
+ countryName_zh: '波斯尼亚和黑塞哥维那',
+ countryName: 'Bosnia And Herzegovina',
+ flag: 'B',
+ }, {
+ countryKey: 'BW',
+ value: '+267',
+ countryName_zh: '博茨瓦纳',
+ countryName: 'Botswana',
+ flag: 'B',
+ }, {
+ countryKey: 'BR',
+ value: '+55',
+ countryName_zh: '巴西',
+ countryName: 'Brazil',
+ flag: 'B',
+ }, {
+ countryKey: 'VG',
+ value: '+1284',
+ countryName_zh: '英属维尔京群岛',
+ countryName: 'British Virgin Islands',
+ flag: 'B',
+ }, {
+ countryKey: 'BN',
+ value: '+673',
+ countryName_zh: '文莱',
+ countryName: 'Brunei',
+ flag: 'B',
+ }, {
+ countryKey: 'BG',
+ value: '+359',
+ countryName_zh: '保加利亚',
+ countryName: 'Bulgaria',
+ flag: 'B',
+ }, {
+ countryKey: 'BF',
+ value: '+226',
+ countryName_zh: '布基纳法索',
+ countryName: 'Burkina Faso',
+ flag: 'B',
+ }, {
+ countryKey: 'BI',
+ value: '+257',
+ countryName_zh: '布隆迪',
+ countryName: 'Burundi',
+ flag: 'B',
+ }, {
+ countryKey: 'KH',
+ value: '+855',
+ countryName_zh: '柬埔寨',
+ countryName: 'Cambodia',
+ flag: 'C',
+ }, {
+ countryKey: 'CM',
+ value: '+237',
+ countryName_zh: '喀麦隆',
+ countryName: 'Cameroon',
+ flag: 'C',
+ }, {
+ countryKey: 'CA',
+ value: '+1',
+ countryName_zh: '加拿大',
+ countryName: 'Canada',
+ flag: 'C',
+ }, {
+ countryKey: 'CV',
+ value: '+238',
+ countryName_zh: '佛得角',
+ countryName: 'Cape verde',
+ flag: 'C',
+ }, {
+ countryKey: 'KY',
+ value: '+1345',
+ countryName_zh: '开曼群岛',
+ countryName: 'Cayman Islands',
+ flag: 'C',
+ }, {
+ countryKey: 'CF',
+ value: '+236',
+ countryName_zh: '中非共和国',
+ countryName: 'Central African Republic',
+ flag: 'C',
+ }, {
+ countryKey: 'TD',
+ value: '+235',
+ countryName_zh: '乍得',
+ countryName: 'Chad',
+ flag: 'C',
+ }, {
+ countryKey: 'CL',
+ value: '+56',
+ countryName_zh: '智利',
+ countryName: 'Chile',
+ flag: 'C',
+ }, {
+ countryKey: 'CN',
+ value: '+86',
+ countryName_zh: '中国',
+ countryName: 'China',
+ flag: 'C',
+ }, {
+ countryKey: 'CO',
+ value: '+57',
+ countryName_zh: '哥伦比亚',
+ countryName: 'Columbia',
+ flag: 'C',
+ }, {
+ countryKey: 'KM',
+ value: '+269',
+ countryName_zh: '科摩罗',
+ countryName: 'Comoros',
+ flag: 'C',
+ }, {
+ countryKey: 'CG',
+ value: '+242',
+ countryName_zh: '刚果民主共和国',
+ countryName: 'Congo-Kinshasa',
+ flag: 'C',
+ }, {
+ countryKey: 'CD',
+ value: '+243',
+ countryName_zh: '刚果共和国',
+ countryName: 'Congo-Brazzaville',
+ flag: 'C',
+ }, {
+ countryKey: 'CK',
+ value: '+682',
+ countryName_zh: '库克群岛',
+ countryName: 'Cook Islands',
+ flag: 'C',
+ }, {
+ countryKey: 'CR',
+ value: '+506',
+ countryName_zh: '哥斯达黎加',
+ countryName: 'Costa Rica',
+ flag: 'C',
+ }, {
+ countryKey: 'CI',
+ value: '+225',
+ countryName_zh: '科特迪瓦',
+ countryName: "Cote d'lvoire",
+ flag: 'C',
+ }, {
+ countryKey: 'HR',
+ value: '+385',
+ countryName_zh: '克罗地亚',
+ countryName: 'Croatia',
+ flag: 'C',
+ }, {
+ countryKey: 'CU',
+ value: '+53',
+ countryName_zh: '古巴',
+ countryName: 'Cuba',
+ flag: 'C',
+ }, {
+ countryKey: 'CY',
+ value: '+357',
+ countryName_zh: '塞浦路斯',
+ countryName: 'Cyprus',
+ flag: 'C',
+ }, {
+ countryKey: 'CZ',
+ value: '+420',
+ countryName_zh: '捷克共和国',
+ countryName: 'Czech Republic',
+ flag: 'C',
+ }, {
+ countryKey: 'DK',
+ value: '+45',
+ countryName_zh: '丹麦',
+ countryName: 'Denmark',
+ flag: 'D',
+ }, {
+ countryKey: 'DJ',
+ value: '+253',
+ countryName_zh: '吉布提',
+ countryName: 'Djibouti',
+ flag: 'D',
+ }, {
+ countryKey: 'DM',
+ value: '+1767',
+ countryName_zh: '多米尼加',
+ countryName: 'Domilica',
+ flag: 'D',
+ }, {
+ countryKey: 'DO',
+ value: '+1809',
+ countryName_zh: '多米尼加共和国',
+ countryName: 'Dominican Republic',
+ flag: 'D',
+ }, {
+ countryKey: 'EC',
+ value: '+593',
+ countryName_zh: '厄瓜多尔',
+ countryName: 'Ecuador',
+ flag: 'E',
+ }, {
+ countryKey: 'EG',
+ value: '+20',
+ countryName_zh: '埃及',
+ countryName: 'Egypt',
+ flag: 'E',
+ }, {
+ countryKey: 'SV',
+ value: '+503',
+ countryName_zh: '萨尔瓦多',
+ countryName: 'EI Salvador',
+ flag: 'E',
+ }, {
+ countryKey: 'GQ',
+ value: '+240',
+ countryName_zh: '赤道几内亚',
+ countryName: 'Equatorial Guinea',
+ flag: 'E',
+ }, {
+ countryKey: 'ER',
+ value: '+291',
+ countryName_zh: '厄立特里亚',
+ countryName: 'Eritrea',
+ flag: 'E',
+ }, {
+ countryKey: 'EE',
+ value: '+372',
+ countryName_zh: '爱沙尼亚',
+ countryName: 'Estonia',
+ flag: 'E',
+ }, {
+ countryKey: 'ET',
+ value: '+251',
+ countryName_zh: '埃塞俄比亚',
+ countryName: 'Ethiopia',
+ flag: 'E',
+ }, {
+ countryKey: 'FO',
+ value: '+298',
+ countryName_zh: '法罗群岛',
+ countryName: 'Faroe Islands',
+ flag: 'F',
+ }, {
+ countryKey: 'FJ',
+ value: '+679',
+ countryName_zh: '斐济',
+ countryName: 'Fiji Islands',
+ flag: 'F',
+ }, {
+ countryKey: 'FI',
+ value: '+358',
+ countryName_zh: '芬兰',
+ countryName: 'Finland',
+ flag: 'F',
+ }, {
+ countryKey: 'FR',
+ value: '+33',
+ countryName_zh: '法国',
+ countryName: 'France',
+ flag: 'F',
+ }, {
+ countryKey: 'PF',
+ value: '+689',
+ countryName_zh: '法属波利尼西亚',
+ countryName: 'French Polynesia',
+ flag: 'F',
+ }, {
+ countryKey: 'GA',
+ value: '+241',
+ countryName_zh: '加蓬',
+ countryName: 'Gabon',
+ flag: 'G',
+ }, {
+ countryKey: 'GM',
+ value: '+220',
+ countryName_zh: '冈比亚',
+ countryName: 'Gambia',
+ flag: 'G',
+ }, {
+ countryKey: 'GE',
+ value: '+995',
+ countryName_zh: '乔治亚',
+ countryName: 'Georgia',
+ flag: 'G',
+ }, {
+ countryKey: 'DE',
+ value: '+49',
+ countryName_zh: '德国',
+ countryName: 'Germany',
+ flag: 'G',
+ }, {
+ countryKey: 'GH',
+ value: '+233',
+ countryName_zh: '加纳',
+ countryName: 'Ghana',
+ flag: 'G',
+ }, {
+ countryKey: 'GI',
+ value: '+350',
+ countryName_zh: '直布罗陀',
+ countryName: 'Gibraltar',
+ flag: 'G',
+ }, {
+ countryKey: 'GR',
+ value: '+30',
+ countryName_zh: '希腊',
+ countryName: 'Greece',
+ flag: 'G',
+ }, {
+ countryKey: 'GL',
+ value: '+299',
+ countryName_zh: '格陵兰',
+ countryName: 'Greenland',
+ flag: 'G',
+ }, {
+ countryKey: 'GD',
+ value: '+1473',
+ countryName_zh: '格林纳达',
+ countryName: 'Grenada',
+ flag: 'G',
+ }, {
+ countryKey: 'GU',
+ value: '+1671',
+ countryName_zh: '关岛',
+ countryName: 'Guam',
+ flag: 'G',
+ }, {
+ countryKey: 'GT',
+ value: '+502',
+ countryName_zh: '危地马拉',
+ countryName: 'Guatemala',
+ flag: 'G',
+ }, {
+ countryKey: 'GN',
+ value: '+224',
+ countryName_zh: '几内亚',
+ countryName: 'Guinea',
+ flag: 'G',
+ }, {
+ countryKey: 'GW',
+ value: '+245',
+ countryName_zh: '几内亚比绍',
+ countryName: 'Guinea-Bissau',
+ flag: 'G',
+ }, {
+ countryKey: 'GY',
+ value: '+592',
+ countryName_zh: '圭亚那',
+ countryName: 'Guyana',
+ flag: 'G',
+ }, {
+ countryKey: 'HT',
+ value: '+509',
+ countryName_zh: '海地',
+ countryName: 'Haiti',
+ flag: 'H',
+ }, {
+ countryKey: 'HN',
+ value: '+504',
+ countryName_zh: '洪都拉斯',
+ countryName: 'Honduras',
+ flag: 'H',
+ }, {
+ countryKey: 'HK',
+ value: '+852',
+ countryName_zh: '中国香港',
+ countryName: 'Hong Kong',
+ flag: 'H',
+ }, {
+ countryKey: 'HU',
+ value: '+36',
+ countryName_zh: '匈牙利',
+ countryName: 'Hungary',
+ flag: 'H',
+ }, {
+ countryKey: 'IS',
+ value: '+354',
+ countryName_zh: '冰岛',
+ countryName: 'Iceland',
+ flag: 'I',
+ }, {
+ countryKey: 'IN',
+ value: '+91',
+ countryName_zh: '印度',
+ countryName: 'India',
+ flag: 'I',
+ }, {
+ countryKey: 'ID',
+ value: '+62',
+ countryName_zh: '印度尼西亚',
+ countryName: 'Indonesia',
+ flag: 'I',
+ }, {
+ countryKey: 'IR',
+ value: '+98',
+ countryName_zh: '伊朗',
+ countryName: 'Iran',
+ flag: 'I',
+ }, {
+ countryKey: 'IQ',
+ value: '+964',
+ countryName_zh: '伊拉克',
+ countryName: 'Iraq',
+ flag: 'I',
+ }, {
+ countryKey: 'IE',
+ value: '+353',
+ countryName_zh: '爱尔兰',
+ countryName: 'Ireland',
+ flag: 'I',
+ }, {
+ countryKey: 'IL',
+ value: '+972',
+ countryName_zh: '以色列',
+ countryName: 'Israel',
+ flag: 'I',
+ }, {
+ countryKey: 'IT',
+ value: '+39',
+ countryName_zh: '意大利',
+ countryName: 'Italy',
+ flag: 'I',
+ }, {
+ countryKey: 'JM',
+ value: '+1876',
+ countryName_zh: '牙买加',
+ countryName: 'Jamaica',
+ flag: 'J',
+ }, {
+ countryKey: 'JP',
+ value: '+81',
+ countryName_zh: '日本',
+ countryName: 'Japan',
+ flag: 'J',
+ }, {
+ countryKey: 'JE',
+ value: '+44',
+ countryName_zh: '泽西岛',
+ countryName: 'Jersey',
+ flag: 'J',
+ }, {
+ countryKey: 'JO',
+ value: '+962',
+ countryName_zh: '约旦',
+ countryName: 'Jordan',
+ flag: 'J',
+ }, {
+ countryKey: 'KZ',
+ value: '+7',
+ countryName_zh: '哈萨克斯坦',
+ countryName: 'Kazakhstan',
+ flag: 'K',
+ }, {
+ countryKey: 'KE',
+ value: '+254',
+ countryName_zh: '肯尼亚',
+ countryName: 'Kenya',
+ flag: 'K',
+ }, {
+ countryKey: 'KR',
+ value: '+82',
+ countryName_zh: '韩国',
+ countryName: 'Korea',
+ flag: 'K',
+ }, {
+ countryKey: 'KW',
+ value: '+965',
+ countryName_zh: '科威特',
+ countryName: 'Kuwait',
+ flag: 'K',
+ }, {
+ countryKey: 'KG',
+ value: '+996',
+ countryName_zh: '吉尔吉斯斯坦',
+ countryName: 'Kyrgyzstan',
+ flag: 'K',
+ }, {
+ countryKey: 'LA',
+ value: '+856',
+ countryName_zh: '老挝',
+ countryName: 'Laos',
+ flag: 'L',
+ }, {
+ countryKey: 'LV',
+ value: '+371',
+ countryName_zh: '拉脱维亚',
+ countryName: 'Latvia',
+ flag: 'L',
+ }, {
+ countryKey: 'LB',
+ value: '+961',
+ countryName_zh: '黎巴嫩',
+ countryName: 'Lebanon',
+ flag: 'L',
+ }, {
+ countryKey: 'LS',
+ value: '+266',
+ countryName_zh: '莱索托',
+ countryName: 'Lesotho',
+ flag: 'L',
+ }, {
+ countryKey: 'LR',
+ value: '+231',
+ countryName_zh: '利比里亚',
+ countryName: 'Liberia',
+ flag: 'L',
+ }, {
+ countryKey: 'LY',
+ value: '+218',
+ countryName_zh: '利比亚',
+ countryName: 'Libya',
+ flag: 'L',
+ }, {
+ countryKey: 'LI',
+ value: '+423',
+ countryName_zh: '列支敦士登',
+ countryName: 'Liechtenstein',
+ flag: 'L',
+ }, {
+ countryKey: 'LT',
+ value: '+370',
+ countryName_zh: '立陶宛',
+ countryName: 'Lithuania',
+ flag: 'L',
+ }, {
+ countryKey: 'LU',
+ value: '+352',
+ countryName_zh: '卢森堡',
+ countryName: 'Luxembourg',
+ flag: 'L',
+ }, {
+ countryKey: 'MO',
+ value: '+853',
+ countryName_zh: '中国澳门',
+ countryName: 'Macao',
+ flag: 'M',
+ }, {
+ countryKey: 'MK',
+ value: '+389',
+ countryName_zh: '马其顿',
+ countryName: 'Macedonia,Former Yugoslav Republic of',
+ flag: 'M',
+ }, {
+ countryKey: 'MG',
+ value: '+261',
+ countryName_zh: '马达加斯加',
+ countryName: 'Madagascar',
+ flag: 'M',
+ }, {
+ countryKey: 'MW',
+ value: '+265',
+ countryName_zh: '马拉维',
+ countryName: 'Malawi',
+ flag: 'M',
+ }, {
+ countryKey: 'MY',
+ value: '+60',
+ countryName_zh: '马来西亚',
+ countryName: 'Malaysia',
+ flag: 'M',
+ }, {
+ countryKey: 'MV',
+ value: '+960',
+ countryName_zh: '马尔代夫',
+ countryName: 'Maldives',
+ flag: 'M',
+ }, {
+ countryKey: 'ML',
+ value: '+223',
+ countryName_zh: '马里',
+ countryName: 'Mali',
+ flag: 'M',
+ }, {
+ countryKey: 'MT',
+ value: '+356',
+ countryName_zh: '马耳他',
+ countryName: 'Malta',
+ flag: 'M',
+ }, {
+ countryKey: 'MR',
+ value: '+222',
+ countryName_zh: '毛里塔尼亚',
+ countryName: 'Mauritania',
+ flag: 'M',
+ }, {
+ countryKey: 'MX',
+ value: '+52',
+ countryName_zh: '墨西哥',
+ countryName: 'Mexico',
+ flag: 'M',
+ }, {
+ countryKey: 'MD',
+ value: '+373',
+ countryName_zh: '摩尔多瓦',
+ countryName: 'Moldova',
+ flag: 'M',
+ }, {
+ countryKey: 'MC',
+ value: '+377',
+ countryName_zh: '摩纳哥',
+ countryName: 'Monaco',
+ flag: 'M',
+ }, {
+ countryKey: 'MN',
+ value: '+976',
+ countryName_zh: '蒙古',
+ countryName: 'Mongolia',
+ flag: 'M',
+ }, {
+ countryKey: 'ME',
+ value: '+382',
+ countryName_zh: '黑山共和国',
+ countryName: 'Montenegro',
+ flag: 'M',
+ }, {
+ countryKey: 'MA',
+ value: '+212',
+ countryName_zh: '摩洛哥',
+ countryName: 'Morocco',
+ flag: 'M',
+ }, {
+ countryKey: 'MZ',
+ value: '+258',
+ countryName_zh: '莫桑比克',
+ countryName: 'Mozambique',
+ flag: 'M',
+ }, {
+ countryKey: 'MM',
+ value: '+95',
+ countryName_zh: '缅甸',
+ countryName: 'Myanmar',
+ flag: 'M',
+ }, {
+ countryKey: 'NA',
+ value: '+264',
+ countryName_zh: '纳米比亚',
+ countryName: 'Namibia',
+ flag: 'N',
+ }, {
+ countryKey: 'NP',
+ value: '+977',
+ countryName_zh: '尼泊尔',
+ countryName: 'Nepal',
+ flag: 'N',
+ }, {
+ countryKey: 'NL',
+ value: '+31',
+ countryName_zh: '荷兰',
+ countryName: 'Netherlands',
+ flag: 'N',
+ }, {
+ countryKey: 'AN',
+ value: '+599',
+ countryName_zh: '荷属安的列斯群岛',
+ countryName: 'Netherlands Antilles',
+ flag: 'N',
+ }, {
+ countryKey: 'NC',
+ value: '+687',
+ countryName_zh: '新喀里多尼亚',
+ countryName: 'New Caledonia',
+ flag: 'N',
+ }, {
+ countryKey: 'NZ',
+ value: '+64',
+ countryName_zh: '新西兰',
+ countryName: 'New Zealand',
+ flag: 'N',
+ }, {
+ countryKey: 'NI',
+ value: '+505',
+ countryName_zh: '尼加拉瓜',
+ countryName: 'Nicaragua',
+ flag: 'N',
+ }, {
+ countryKey: 'NE',
+ value: '+227',
+ countryName_zh: '尼日尔',
+ countryName: 'Niger',
+ flag: 'N',
+ }, {
+ countryKey: 'NG',
+ value: '+234',
+ countryName_zh: '尼日利亚',
+ countryName: 'Nigeria',
+ flag: 'N',
+ }, {
+ countryKey: 'KP',
+ value: '+850',
+ countryName_zh: '朝鲜',
+ countryName: 'North Korea',
+ flag: 'N',
+ }, {
+ countryKey: 'NO',
+ value: '+47',
+ countryName_zh: '挪威',
+ countryName: 'Norway',
+ flag: 'N',
+ }, {
+ countryKey: 'OM',
+ value: '+968',
+ countryName_zh: '阿曼',
+ countryName: 'Oman',
+ flag: 'O',
+ }, {
+ countryKey: 'PK',
+ value: '+92',
+ countryName_zh: '巴基斯坦',
+ countryName: 'Pakistan',
+ flag: 'P',
+ }, {
+ countryKey: 'PA',
+ value: '+507',
+ countryName_zh: '巴拿马',
+ countryName: 'Panama',
+ flag: 'P',
+ }, {
+ countryKey: 'PG',
+ value: '+675',
+ countryName_zh: '巴布亚新几内亚',
+ countryName: 'Papua New Guinea',
+ flag: 'P',
+ }, {
+ countryKey: 'PY',
+ value: '+595',
+ countryName_zh: '巴拉圭',
+ countryName: 'Paraguay',
+ flag: 'P',
+ }, {
+ countryKey: 'PE',
+ value: '+51',
+ countryName_zh: '秘鲁',
+ countryName: 'Peru',
+ flag: 'P',
+ }, {
+ countryKey: 'PH',
+ value: '+63',
+ countryName_zh: '菲律宾',
+ countryName: 'Philippines',
+ flag: 'P',
+ }, {
+ countryKey: 'PL',
+ value: '+48',
+ countryName_zh: '波兰',
+ countryName: 'Poland',
+ flag: 'P',
+ }, {
+ countryKey: 'PT',
+ value: '+351',
+ countryName_zh: '葡萄牙',
+ countryName: 'Portugal',
+ flag: 'P',
+ }, {
+ countryKey: 'PR',
+ value: '+1',
+ countryName_zh: '波多黎各',
+ countryName: 'Puerto Rico',
+ flag: 'P',
+ }, {
+ countryKey: 'QA',
+ value: '+974',
+ countryName_zh: '卡塔尔',
+ countryName: 'Qatar',
+ flag: 'Q',
+ }, {
+ countryKey: 'RO',
+ value: '+40',
+ countryName_zh: '罗马尼亚',
+ countryName: 'Romania',
+ flag: 'R',
+ }, {
+ countryKey: 'RU',
+ value: '+7',
+ countryName_zh: '俄罗斯',
+ countryName: 'Russia',
+ flag: 'R',
+ }, {
+ countryKey: 'RW',
+ value: '+250',
+ countryName_zh: '卢旺达',
+ countryName: 'Rwanda',
+ flag: 'R',
+ }, {
+ countryKey: 'LC',
+ value: '+1758',
+ countryName_zh: '圣卢西亚',
+ countryName: 'Saint Lucia',
+ flag: 'S',
+ }, {
+ countryKey: 'PM',
+ value: '+508',
+ countryName_zh: '圣皮埃尔和密克隆',
+ countryName: 'Saint Pierre and Miquelon',
+ flag: 'S',
+ }, {
+ countryKey: 'VC',
+ value: '+1784',
+ countryName_zh: '圣文森特河格林纳丁斯',
+ countryName: 'Saint Vincent And the Grenadines',
+ flag: 'S',
+ }, {
+ countryKey: 'WS',
+ value: '+685',
+ countryName_zh: '萨摩亚',
+ countryName: 'Samoa',
+ flag: 'S',
+ }, {
+ countryKey: 'SM',
+ value: '+378',
+ countryName_zh: '圣马力诺',
+ countryName: 'San Marino',
+ flag: 'S',
+ }, {
+ countryKey: 'ST',
+ value: '+239',
+ countryName_zh: '圣多美和普林西比',
+ countryName: 'Sao Tome and Principe',
+ flag: 'S',
+ }, {
+ countryKey: 'SA',
+ value: '+966',
+ countryName_zh: '沙特阿拉伯',
+ countryName: 'Saudi Arabia',
+ flag: 'S',
+ }, {
+ countryKey: 'SN',
+ value: '+221',
+ countryName_zh: '塞内加尔',
+ countryName: 'Senegal',
+ flag: 'S',
+ }, {
+ countryKey: 'RS',
+ value: '+381',
+ countryName_zh: '塞尔维亚',
+ countryName: 'Serbia',
+ flag: 'S',
+ }, {
+ countryKey: 'SC',
+ value: '+248',
+ countryName_zh: '塞舌尔',
+ countryName: 'Seychelles',
+ flag: 'S',
+ }, {
+ countryKey: 'SL',
+ value: '+232',
+ countryName_zh: '塞拉利昂',
+ countryName: 'Sierra Leone',
+ flag: 'S',
+ }, {
+ countryKey: 'SG',
+ value: '+65',
+ countryName_zh: '新加坡',
+ countryName: 'Singapore',
+ flag: 'S',
+ }, {
+ countryKey: 'SK',
+ value: '+421',
+ countryName_zh: '斯洛伐克',
+ countryName: 'Slovakia',
+ flag: 'S',
+ }, {
+ countryKey: 'SI',
+ value: '+386',
+ countryName_zh: '斯洛文尼亚',
+ countryName: 'Slovenia',
+ flag: 'S',
+ }, {
+ countryKey: 'SO',
+ value: '+252',
+ countryName_zh: '索马里',
+ countryName: 'Somalia',
+ flag: 'S',
+ }, {
+ countryKey: 'ZA',
+ value: '+27',
+ countryName_zh: '南非',
+ countryName: 'South Africa',
+ flag: 'S',
+ }, {
+ countryKey: 'ES',
+ value: '+34',
+ countryName_zh: '西班牙',
+ countryName: 'Spain',
+ flag: 'S',
+ }, {
+ countryKey: 'LK',
+ value: '+94',
+ countryName_zh: '斯里兰卡',
+ countryName: 'Sri Lanka',
+ flag: 'S',
+ }, {
+ countryKey: 'KN',
+ value: '+1869',
+ countryName_zh: '圣基茨和尼维斯',
+ countryName: 'St.Kitts and Nevis',
+ flag: 'S',
+ }, {
+ countryKey: 'SD',
+ value: '+249',
+ countryName_zh: '苏丹',
+ countryName: 'Sudan',
+ flag: 'S',
+ }, {
+ countryKey: 'SR',
+ value: '+597',
+ countryName_zh: '苏里南',
+ countryName: 'Surinam',
+ flag: 'S',
+ }, {
+ countryKey: 'SZ',
+ value: '+268',
+ countryName_zh: '斯威士兰',
+ countryName: 'Swaziland',
+ flag: 'S',
+ }, {
+ countryKey: 'SE',
+ value: '+46',
+ countryName_zh: '瑞典',
+ countryName: 'Sweden',
+ flag: 'S',
+ }, {
+ countryKey: 'CH',
+ value: '+41',
+ countryName_zh: '瑞士',
+ countryName: 'Switzerland',
+ flag: 'S',
+ }, {
+ countryKey: 'SY',
+ value: '+963',
+ countryName_zh: '叙利亚',
+ countryName: 'Syria',
+ flag: 'S',
+ }, {
+ countryKey: 'TW',
+ value: '+886',
+ countryName_zh: '中国台湾',
+ countryName: 'Taiwan',
+ flag: 'T',
+ }, {
+ countryKey: 'TJ',
+ value: '+992',
+ countryName_zh: '塔吉克斯坦',
+ countryName: 'Tajikistan',
+ flag: 'T',
+ }, {
+ countryKey: 'TZ',
+ value: '+255',
+ countryName_zh: '坦桑尼亚',
+ countryName: 'Tanzania',
+ flag: 'T',
+ }, {
+ countryKey: 'TH',
+ value: '+66',
+ countryName_zh: '泰国',
+ countryName: 'Thailand',
+ flag: 'T',
+ }, {
+ countryKey: 'TL',
+ value: '+670',
+ countryName_zh: '东帝汶',
+ countryName: 'Timor-Leste',
+ flag: 'T',
+ }, {
+ countryKey: 'TG',
+ value: '+228',
+ countryName_zh: '多哥',
+ countryName: 'Togo',
+ flag: 'T',
+ }, {
+ countryKey: 'TO',
+ value: '+676',
+ countryName_zh: '汤加',
+ countryName: 'Tonga',
+ flag: 'T',
+ }, {
+ countryKey: 'TT',
+ value: '+1868',
+ countryName_zh: '特立尼达和多巴哥',
+ countryName: 'Trinidad and Tobago',
+ flag: 'T',
+ }, {
+ countryKey: 'TN',
+ value: '+216',
+ countryName_zh: '突尼斯',
+ countryName: 'Tunisia',
+ flag: 'T',
+ }, {
+ countryKey: 'TR',
+ value: '+90',
+ countryName_zh: '土耳其',
+ countryName: 'Turkey',
+ flag: 'T',
+ }, {
+ countryKey: 'TM',
+ value: '+993',
+ countryName_zh: '土库曼斯坦',
+ countryName: 'Turkmenistan',
+ flag: 'T',
+ }, {
+ countryKey: 'TC',
+ value: '+1649',
+ countryName_zh: '特克斯和凯科斯群岛',
+ countryName: 'Turks and Caicos Islands',
+ flag: 'T',
+ }, {
+ countryKey: 'UG',
+ value: '+256',
+ countryName_zh: '乌干达',
+ countryName: 'Uganda',
+ flag: 'U',
+ }, {
+ countryKey: 'UA',
+ value: '+380',
+ countryName_zh: '乌克兰',
+ countryName: 'Ukraine',
+ flag: 'U',
+ }, {
+ countryKey: 'AE',
+ value: '+971',
+ countryName_zh: '阿拉伯联合酋长国',
+ countryName: 'United Arab Emirates',
+ flag: 'U',
+ }, {
+ countryKey: 'GB',
+ value: '+44',
+ countryName_zh: '英国',
+ countryName: 'United Kingdom',
+ flag: 'U',
+ }, {
+ countryKey: 'US',
+ value: '+1',
+ countryName_zh: '美国',
+ countryName: 'United States',
+ flag: 'U',
+ }, {
+ countryKey: 'UY',
+ value: '+598',
+ countryName_zh: '乌拉圭',
+ countryName: 'Uruguay',
+ flag: 'U',
+ }, {
+ countryKey: 'UZ',
+ value: '+998',
+ countryName_zh: '乌兹别克斯坦',
+ countryName: 'Uzbekistan',
+ flag: 'U',
+ }, {
+ countryKey: 'VU',
+ value: '+678',
+ countryName_zh: '瓦努阿图',
+ countryName: 'Vanuatu',
+ flag: 'V',
+ }, {
+ countryKey: 'VE',
+ value: '+58',
+ countryName_zh: '委内瑞拉',
+ countryName: 'Venezuela',
+ flag: 'V',
+ }, {
+ countryKey: 'VN',
+ value: '+84',
+ countryName_zh: '越南',
+ countryName: 'Vietnam',
+ flag: 'V',
+ }, {
+ countryKey: 'YE',
+ value: '+967',
+ countryName_zh: '也门',
+ countryName: 'Yemen',
+ flag: 'Y',
+ }, {
+ countryKey: 'ZM',
+ value: '+260',
+ countryName_zh: '赞比亚',
+ countryName: 'Zambia',
+ flag: 'Z',
+ }, {
+ countryKey: 'ZW',
+ value: '+263',
+ countryName_zh: '津巴布韦',
+ countryName: 'Zimbabwe',
+ flag: 'Z',
+ },
+];
diff --git a/modules/material-parser/test/fixtures/dts-component/src/i18n.js b/modules/material-parser/test/fixtures/dts-component/src/i18n.js
new file mode 100644
index 0000000000..0b4c2e79f6
--- /dev/null
+++ b/modules/material-parser/test/fixtures/dts-component/src/i18n.js
@@ -0,0 +1,27 @@
+/**
+ * 组件内置的多语言文案
+ */
+
+const bundles = {
+ 'zh-CN': {
+ dataSource: [
+ {
+ label: '+86',
+ value: '86',
+ country: '中国',
+ rule: /(?=(\d{4})+$)/g,
+ },
+ ],
+ },
+ 'en-US': {
+ dataSource: [
+ {
+ label: '+86',
+ value: '86',
+ country: 'china',
+ rule: /(?=(\d{4})+$)/g,
+ },
+ ],
+ },
+};
+export default bundles;
diff --git a/modules/material-parser/test/fixtures/dts-component/src/index.jsx b/modules/material-parser/test/fixtures/dts-component/src/index.jsx
new file mode 100644
index 0000000000..eb76866dbd
--- /dev/null
+++ b/modules/material-parser/test/fixtures/dts-component/src/index.jsx
@@ -0,0 +1,142 @@
+import React from 'react';
+import { Select, Input } from '@alifd/next';
+import i18n from '@alife/whale-i18n';
+import classnames from 'classnames';
+import PropTypes from 'prop-types';
+import { getLanguage } from '@alife/whale-util';
+
+import i18nBundles from './i18n';
+import countryDataSource from './data';
+
+const lang = getLanguage();
+const isCN = ['ZH_CN', 'ZH-CN'].includes(lang && lang.toUpperCase());
+
+class WhaleTelephone extends React.Component {
+ static displayName = 'WhaleTelephone';
+
+ static propTypes = {
+ style: PropTypes.object,
+ className: PropTypes.string,
+ disabled: PropTypes.bool,
+ value: PropTypes.object,
+ onChange: PropTypes.func,
+ };
+
+ static defaultProps = {
+ style: {},
+ className: '',
+ disabled: false,
+ onChange: undefined,
+ value: {
+ countryCode: '+86',
+ phoneNumber: '',
+ },
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ popupStyle: {},
+ tmpSelectedItem: {},
+ };
+ }
+
+ componentDidMount() {
+ if (!this.props.readOnly) {
+ this.handleStyle();
+ window.addEventListener('resize', this.resizeEventFunction);
+ }
+ }
+
+ componentWillUnmount() {
+ if (!this.props.readOnly) {
+ window.removeEventListener('resize', this.resizeEventFunction);
+ }
+ }
+
+ resizeEventFunction = () => this.handleStyle();
+
+ handleStyle = () => {
+ const { el } = this;
+ const elWidth = el.offsetWidth;
+ this.setState({
+ popupStyle: {
+ width: elWidth,
+ },
+ });
+ };
+
+ selectChange=(val, actionType, tmpSelectedItem) => {
+ const { value, onChange } = this.props;
+ this.setState({ tmpSelectedItem });
+ onChange && onChange(Object.assign({}, value, { countryCode: val }), tmpSelectedItem, 'select');
+ };
+
+ inputChange = (val) => {
+ const { value, onChange } = this.props;
+ const { tmpSelectedItem } = this.state;
+ onChange && onChange(Object.assign({}, value, { phoneNumber: val }), tmpSelectedItem, 'input');
+ };
+
+ renderItem = (item) => {
+ const { countryName, countryName_zh: countryNameZh, value } = item;
+ return (
+
+ {!isCN ? countryName : countryNameZh}
+ {value}
+
+ );
+ };
+
+ render() {
+ // i18nBundle 是 i18n 包装后额外提供的 prop,表示组件当前实际使用的文案
+ const {
+ style,
+ className,
+ disabled,
+ value: { countryCode, phoneNumber },
+ readOnly,
+ } = this.props;
+ // 排除掉不需要透传下去的参数,特别地适用于直接把大部分特殊控制外的参数透传给 Fusion 等组件的用法
+ const cls = classnames({
+ 'whale-telephone': true,
+ 'whale-telephone-readonly': !!readOnly,
+ [className]: className,
+ });
+ const { popupStyle } = this.state;
+
+ if (readOnly) {
+ return (
+
+ {countryCode} {phoneNumber}
+
+ );
+ }
+
+ return (
+ { this.el = ref; }} data-name="WhaleTelephone">
+
+
+
+ );
+ }
+}
+
+// 默认 export 提供了内置多语言文案的组件
+export default i18n(WhaleTelephone, i18nBundles);
+// 万一需有对组件进行扩展,为了避免 HOC 后无法直接继承,提供了导出组件内置多语言文案及未经 HOC 的组件
+export { i18nBundles, WhaleTelephone as Pure };
diff --git a/modules/material-parser/test/fixtures/dts-component/src/main.scss b/modules/material-parser/test/fixtures/dts-component/src/main.scss
new file mode 100644
index 0000000000..0f25676742
--- /dev/null
+++ b/modules/material-parser/test/fixtures/dts-component/src/main.scss
@@ -0,0 +1,40 @@
+
+@import 'scss/variable';
+
+// put your code here
+
+.whale-telephone {
+ display: flex;
+ .whale-telephone-select {
+ min-width: 72px;
+ width: 72px;
+ .next-select-inner {
+ min-width: 72px;
+ }
+ .next-input.next-medium {
+ border-radius: 0;
+ border-right: none;
+ }
+ }
+ .whale-telephone-number-input {
+ flex-grow: 2;
+ border-radius: 0;
+ &.next-input.next-medium {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+ }
+
+ &.whale-telephone-readonly {
+ font-family: Roboto;
+ color: #262626;
+ font-size: 14px;
+ line-height: 1.7;
+ }
+}
+
+.whale-telephone-select-popup {
+ .code-span {
+ float: right;
+ }
+}
diff --git a/modules/material-parser/test/fixtures/dts-component/src/scss/variable.scss b/modules/material-parser/test/fixtures/dts-component/src/scss/variable.scss
new file mode 100644
index 0000000000..46edcf7194
--- /dev/null
+++ b/modules/material-parser/test/fixtures/dts-component/src/scss/variable.scss
@@ -0,0 +1,12 @@
+////
+/// @module @alife/whale-telephone: 组件中文名
+/// @tag WhaleTelephone
+/// @category custom
+/// @family whale-telephone
+/// @varPrefix $whale-telephone
+/// @classPrefix whale-telephone
+////
+
+/// backgroud
+/// @namespace statement/normal
+$whale-telephone-color: $color-brand1-1 !default;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/amContainer.js
new file mode 100644
index 0000000000..45df1897e6
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/amContainer.js
@@ -0,0 +1,11 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = function () {
+ return Promise.resolve(component);
+};
+
+export default {
+ getComponent,
+ manifest: amManifest,
+};
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/amManifest.js
new file mode 100644
index 0000000000..c9c2b1b059
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/amManifest.js
@@ -0,0 +1,144 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+function _update(Nygma, node) {
+ const attributes = node.get();
+ const display = attributes.display;
+ const flexDirection = attributes.flexDirection;
+ const alignItems = attributes.alignItems;
+ const justifyContent = attributes.justifyContent;
+ const flexWrap = attributes.flexWrap;
+ const isFlex = display === 'flex';
+ node.set({
+ display,
+ flexDirection: isFlex ? flexDirection : undefined,
+ alignItems: isFlex ? alignItems : undefined,
+ justifyContent: isFlex ? justifyContent : undefined,
+ flexWrap: isFlex ? flexWrap : undefined,
+ });
+}
+
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeBlank',
+ // The description of current component.
+ description: '空白卡片',
+ // The coverimage's url of current component.
+ coverImage: 'https://img.alicdn.com/tfs/TB1un9tqntYBeNjy1XdXXXXyVXa-366-124.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '布局',
+ // card.blank
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [{
+ alias: '空白卡片',
+ thumbnail: 'https://img.alicdn.com/tfs/TB1ucPNVsbpK1RjSZFyXXX_qFXa-198-120.png',
+ colSpan: 12,
+ customProps: {
+ id: '',
+ textAlign: 'left',
+ padding: '12px',
+ width: '100%',
+ backgroundColor: '#FFF',
+ },
+ }],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'container',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'tbrlv',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ lifeCycle: {
+ didMount (props) {
+ const Nygma = props.Nygma;
+ const dragInstance = props.dragInstance;
+ const Drager = dragInstance.NygmaNode;
+
+ _update(Nygma, Drager);
+ },
+ didUpdate (Nygma, node, args) {
+ const newvalue = args[1];
+ const oldvalue = args[2];
+
+ if (JSON.stringify(newvalue) !== JSON.stringify(oldvalue)) {
+ _update(Nygma, node);
+ }
+ },
+ },
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [{
+ name: 'id',
+ label: 'id',
+ defaultValue: '',
+ renderer: 'Input',
+ }, {
+ name: 'textAlign',
+ label: '水平对齐',
+ defaultValue: 'left',
+ renderer: 'TextAlign',
+ }, {
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ }, {
+ name: 'padding',
+ label: '内边距',
+ renderer: 'Quadrant',
+ defaultValue: '12px',
+ }, {
+ name: 'width',
+ label: '宽度',
+ defaultValue: '100%',
+ renderer: 'Width',
+ }, {
+ name: 'height',
+ label: '高度',
+ renderer: 'Height',
+ defaultValue: undefined,
+ }, {
+ name: 'backgroundColor',
+ label: '背景颜色',
+ renderer: 'Color',
+ defaultValue: '#FFF',
+ }, {
+ name: 'border',
+ label: '边框',
+ renderer: 'BarBorder',
+ }, {
+ name: 'display',
+ label: '布局设置',
+ renderer: 'FlexLayout',
+ }],
+ },
+};
+export default manifest;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/container.js
new file mode 100644
index 0000000000..30e1f2996f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/container.js
@@ -0,0 +1,6 @@
+
+ import AIMakeBlank from './index.js';
+ import manifest from './manifest.js';
+
+ export default { origin: AIMakeBlank, manifest };
+
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/index.js
new file mode 100644
index 0000000000..429bfc0dff
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/index.js
@@ -0,0 +1,74 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+import HOCLayoutProps from '../utils/HOCLayoutProps';
+import HOCBackgroundProps from '../utils/HOCBackgroundProps';
+import HOCFlexLayoutProps from '../utils/HOCFlexLayoutProps';
+
+const AIMakeBlank =
+/* #__PURE__ */
+function (_Component) {
+ _inherits(AIMakeBlank, _Component);
+
+ function AIMakeBlank() {
+ _classCallCheck(this, AIMakeBlank);
+
+ return _possibleConstructorReturn(this, _getPrototypeOf(AIMakeBlank).apply(this, arguments));
+ }
+
+ _createClass(AIMakeBlank, [{
+ key: "render",
+ value: function render() {
+ const merged = {};
+ const _this$props = this.props;
+ const children = _this$props.children;
+ const styleBoxModel = _this$props.styleBoxModel;
+ const styleLayout = _this$props.styleLayout;
+ const styleBackground = _this$props.styleBackground;
+ const styleFlexLayout = _this$props.styleFlexLayout;
+ const style = _this$props.style;
+ const id = _this$props.id;
+ const styles = { ...styleBoxModel,
+ ...styleLayout,
+ ...styleBackground,
+ ...styleFlexLayout,
+ ...style,
+ };
+
+ if (id) {
+ merged.id = id;
+ }
+
+ return React.createElement("div", _extends({
+ style: styles,
+ }, merged), children);
+ },
+ }]);
+
+ return AIMakeBlank;
+}(Component);
+
+_defineProperty(AIMakeBlank, "propTypes", {
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
+ styleBoxModel: PropTypes.object.isRequired,
+ styleLayout: PropTypes.object.isRequired,
+ styleBackground: PropTypes.object.isRequired,
+ styleFlexLayout: PropTypes.object.isRequired,
+ style: PropTypes.object,
+ id: PropTypes.string,
+});
+
+_defineProperty(AIMakeBlank, "defaultProps", {
+ children: [],
+ style: {},
+ id: '',
+});
+
+export default HOCBoxModelProps(HOCLayoutProps(HOCBackgroundProps(HOCFlexLayoutProps(AIMakeBlank))));
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.js
new file mode 100644
index 0000000000..6ef1078e0e
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeBlank","title":"","docUrl":"","screenshot":"","npm":{"package":"@ali/lowcode-engine-material-parser","version":"0.1.0","exportName":"AIMakeBlank","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"children","propType":"oneOfType","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleLayout","propType":"object","description":""},{"name":"styleBackground","propType":"object","description":""},{"name":"styleFlexLayout","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"},{"name":"id","propType":"string","description":""}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeBlank/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/IconFont.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/IconFont.js
new file mode 100644
index 0000000000..fa86f316da
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/IconFont.js
@@ -0,0 +1,67 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _inherits from "@babel/runtime/helpers/inherits";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types'; // 缓存已加载的字体文件
+
+const customCache = new Set(); // 动态加载字体文件
+
+export default function createFromIconfont(options) {
+ const scriptUrl = options.scriptUrl;
+
+ if (typeof document !== 'undefined' && typeof window !== 'undefined' && typeof document.createElement === 'function' && typeof scriptUrl === 'string' && scriptUrl.length && !customCache.has(scriptUrl)) {
+ const script = document.createElement('script');
+ script.setAttribute('src', scriptUrl);
+ script.setAttribute('data-namespace', scriptUrl);
+ customCache.add(scriptUrl);
+ document.body.appendChild(script);
+ }
+
+ const IconFont =
+ /* #__PURE__ */
+ function (_Component) {
+ _inherits(IconFont, _Component);
+
+ function IconFont() {
+ _classCallCheck(this, IconFont);
+
+ return _possibleConstructorReturn(this, _getPrototypeOf(IconFont).apply(this, arguments));
+ }
+
+ _createClass(IconFont, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const type = _this$props.type;
+ const restProps = _objectWithoutProperties(_this$props, ["type"]);
+
+ const innerSvgProps = {
+ width: '1em',
+ height: '1em',
+ fill: 'currentColor',
+ 'aria-hidden': 'true',
+ focusable: 'false',
+ }; // 引用指定svg
+
+ const content = React.createElement("use", {
+ xlinkHref: `#${type}`,
+ });
+ return React.createElement("i", _extends({}, restProps, {
+ className: `iconfont ${type}`,
+ }), React.createElement("svg", innerSvgProps, content));
+ },
+ }]);
+
+ return IconFont;
+ }(Component);
+
+ IconFont.propTypes = {
+ type: PropTypes.string.isRequired, // icon
+
+ };
+ return IconFont;
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/amContainer.js
new file mode 100644
index 0000000000..35715351d7
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/amContainer.js
@@ -0,0 +1,13 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+import createFromIconfont from './IconFont';
+
+const getComponent = function () {
+ return Promise.resolve(component);
+};
+
+export default {
+ getComponent,
+ manifest: amManifest,
+ createFromIconfont,
+};
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/amManifest.js
new file mode 100644
index 0000000000..3af2f5c8c5
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/amManifest.js
@@ -0,0 +1,82 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeIcon',
+ // The description of current component.
+ description: '图标',
+ // The coverimage's url of current component.
+ coverImage: '',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: 'AIMakeIcon',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'rl',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [{
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ }, {
+ name: 'color',
+ label: '图标颜色',
+ renderer: 'Color',
+ defaultValue: '#333',
+ }, {
+ name: 'fontSize',
+ label: '图标大小',
+ renderer: 'FontSize',
+ defaultValue: '16px',
+ }, {
+ name: 'display',
+ label: '显示',
+ defaultValue: 'inline-block',
+ }, {
+ name: 'className',
+ label: '图标类型',
+ defaultValue: 'iconfont',
+ renderer: false,
+ params: {
+ placeholder: '请输入Iconfont名',
+ },
+ }],
+ },
+};
+export default manifest;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/container.js
new file mode 100644
index 0000000000..e272233de1
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/container.js
@@ -0,0 +1,6 @@
+
+ import AIMakeIcon from './index.js';
+ import manifest from './manifest.js';
+
+ export default { origin: AIMakeIcon, manifest };
+
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/index.js
new file mode 100644
index 0000000000..4007756a79
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/index.js
@@ -0,0 +1,71 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+import createFromIconfont from './IconFont';
+
+const AIMakeIcon =
+/* #__PURE__ */
+function (_Component) {
+ _inherits(AIMakeIcon, _Component);
+
+ function AIMakeIcon() {
+ _classCallCheck(this, AIMakeIcon);
+
+ return _possibleConstructorReturn(this, _getPrototypeOf(AIMakeIcon).apply(this, arguments));
+ }
+
+ _createClass(AIMakeIcon, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const className = _this$props.className;
+ const iconClassName = _this$props.iconClassName;
+ const children = _this$props.children;
+ const styleBoxModel = _this$props.styleBoxModel;
+ const styleText = _this$props.styleText;
+ const styleBackground = _this$props.styleBackground;
+ const style = _this$props.style;
+ const otherProps = _objectWithoutProperties(_this$props, ["className", "iconClassName", "children", "styleBoxModel", "styleText", "styleBackground", "style"]);
+
+ const styles = { ...styleBoxModel,
+ ...styleText,
+ ...styleBackground,
+ ...style,
+ };
+ return React.createElement("i", _extends({}, otherProps, {
+ className: classNames(className, iconClassName),
+ style: styles,
+ }), children);
+ },
+ }]);
+
+ return AIMakeIcon;
+}(Component);
+
+_defineProperty(AIMakeIcon, "propTypes", {
+ className: PropTypes.string,
+ iconClassName: PropTypes.string,
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
+ styleBoxModel: PropTypes.object.isRequired,
+ styleText: PropTypes.object.isRequired,
+ styleBackground: PropTypes.object.isRequired,
+ style: PropTypes.object,
+});
+
+_defineProperty(AIMakeIcon, "defaultProps", {
+ className: '',
+ iconClassName: 'iconfont',
+ children: '',
+ style: {},
+});
+
+AIMakeIcon.createFromIconfont = createFromIconfont;
+export default AIMakeIcon;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.js
new file mode 100644
index 0000000000..cb0b26eab8
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeIcon","title":"","docUrl":"","screenshot":"","npm":{"package":"@ali/lowcode-engine-material-parser","version":"0.1.0","exportName":"AIMakeIcon","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"className","propType":"string","description":""},{"name":"iconClassName","propType":"string","description":""},{"name":"children","propType":"oneOfType","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleText","propType":"object","description":""},{"name":"styleBackground","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeIcon/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/amContainer.js
new file mode 100644
index 0000000000..45df1897e6
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/amContainer.js
@@ -0,0 +1,11 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = function () {
+ return Promise.resolve(component);
+};
+
+export default {
+ getComponent,
+ manifest: amManifest,
+};
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/amManifest.js
new file mode 100644
index 0000000000..b5687bcf42
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/amManifest.js
@@ -0,0 +1,86 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeImage',
+ // The description of current component.
+ description: '图片',
+ // The coverimage's url of current component.
+ coverImage: 'https://img.alicdn.com/tfs/TB17gMFp1uSBuNjy1XcXXcYjFXa-172-120.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '线条图像',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [{
+ alias: '图片',
+ thumbnail: 'https://img.alicdn.com/tfs/TB17gMFp1uSBuNjy1XcXXcYjFXa-172-120.png',
+ colSpan: 12,
+ customProps: {
+ width: '224px',
+ height: '126px',
+ src: 'https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',
+ },
+ }],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'rl',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [{
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ }, {
+ name: 'width',
+ label: '宽度',
+ defaultValue: '224px',
+ renderer: 'Width',
+ }, {
+ name: 'height',
+ label: '高度',
+ defaultValue: '126px',
+ renderer: 'Height',
+ }, {
+ name: 'src',
+ label: '图片URL',
+ renderer: 'Uploader',
+ placeholder: 'eg: https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',
+ hint: '请填入图片的URL',
+ defaultValue: 'https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',
+ }],
+ },
+};
+export default manifest;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/container.js
new file mode 100644
index 0000000000..2c667964a9
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/container.js
@@ -0,0 +1,6 @@
+
+ import AIMakeImage from './index.js';
+ import manifest from './manifest.js';
+
+ export default { origin: AIMakeImage, manifest };
+
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/index.js
new file mode 100644
index 0000000000..8bf5ce2a85
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/index.js
@@ -0,0 +1,54 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+
+const AIMakeImage =
+/* #__PURE__ */
+function (_Component) {
+ _inherits(AIMakeImage, _Component);
+
+ function AIMakeImage() {
+ _classCallCheck(this, AIMakeImage);
+
+ return _possibleConstructorReturn(this, _getPrototypeOf(AIMakeImage).apply(this, arguments));
+ }
+
+ _createClass(AIMakeImage, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const styleBoxModel = _this$props.styleBoxModel;
+ const style = _this$props.style;
+ const otherProps = _objectWithoutProperties(_this$props, ["styleBoxModel", "style"]);
+
+ const styles = { ...styleBoxModel,
+ ...style,
+ };
+ return React.createElement("img", _extends({}, otherProps, {
+ style: styles,
+ alt: "AIMakeImage",
+ }));
+ },
+ }]);
+
+ return AIMakeImage;
+}(Component);
+
+_defineProperty(AIMakeImage, "propTypes", {
+ styleBoxModel: PropTypes.object.isRequired,
+ style: PropTypes.object,
+});
+
+_defineProperty(AIMakeImage, "defaultProps", {
+ style: {},
+});
+
+export default HOCBoxModelProps(AIMakeImage);
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.js
new file mode 100644
index 0000000000..ea27808dcb
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeImage","title":"","docUrl":"","screenshot":"","npm":{"package":"@ali/lowcode-engine-material-parser","version":"0.1.0","exportName":"AIMakeImage","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"styleBoxModel","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeImage/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/amContainer.js
new file mode 100644
index 0000000000..45df1897e6
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/amContainer.js
@@ -0,0 +1,11 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = function () {
+ return Promise.resolve(component);
+};
+
+export default {
+ getComponent,
+ manifest: amManifest,
+};
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/amManifest.js
new file mode 100644
index 0000000000..c254b2cc43
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/amManifest.js
@@ -0,0 +1,102 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeLink',
+ // The description of current component.
+ description: '链接',
+ // The coverimage's url of current component.
+ coverImage: 'https://img.alicdn.com/tfs/TB1otbyVwTqK1RjSZPhXXXfOFXa-192-48.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '文本',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [{
+ alias: '链接',
+ thumbnail: 'https://img.alicdn.com/tfs/TB1otbyVwTqK1RjSZPhXXXfOFXa-192-48.png',
+ colSpan: 12,
+ customProps: {
+ color: '#3788FF',
+ fontSize: '12px',
+ fontWeight: 'normal',
+ href: '#',
+ children: '链接',
+ },
+ }],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'lrv',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [{
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ }, {
+ name: 'color',
+ label: '文字颜色',
+ renderer: 'Color',
+ defaultValue: '#3788FF',
+ }, {
+ name: 'fontSize',
+ label: '字号',
+ renderer: 'FontSize',
+ defaultValue: '12px',
+ }, {
+ name: 'fontWeight',
+ label: '字重',
+ renderer: 'FontWeight',
+ defaultValue: 'normal',
+ }, {
+ name: 'lineHeight',
+ label: '行高',
+ defaultValue: undefined,
+ renderer: 'LineHeight',
+ }, {
+ name: 'href',
+ label: '链接URL',
+ renderer: 'Input',
+ placeholder: '请输入链接URL',
+ defaultValue: '#',
+ }, {
+ name: 'children',
+ label: '内容',
+ defaultValue: '链接',
+ renderer: 'TextArea',
+ }],
+ },
+};
+export default manifest;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/container.js
new file mode 100644
index 0000000000..472ec7f51c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/container.js
@@ -0,0 +1,6 @@
+
+ import AIMakeLink from './index.js';
+ import manifest from './manifest.js';
+
+ export default { origin: AIMakeLink, manifest };
+
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/index.js
new file mode 100644
index 0000000000..ace8d9e94c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/index.js
@@ -0,0 +1,73 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+import HOCTextProps from '../utils/HOCTextProps';
+import HOCLayoutProps from '../utils/HOCLayoutProps';
+import HOCBackgroundProps from '../utils/HOCBackgroundProps';
+
+const AIMakeLink =
+/* #__PURE__ */
+function (_Component) {
+ _inherits(AIMakeLink, _Component);
+
+ function AIMakeLink() {
+ _classCallCheck(this, AIMakeLink);
+
+ return _possibleConstructorReturn(this, _getPrototypeOf(AIMakeLink).apply(this, arguments));
+ }
+
+ _createClass(AIMakeLink, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const children = _this$props.children;
+ const styleBoxModel = _this$props.styleBoxModel;
+ const styleText = _this$props.styleText;
+ const styleLayout = _this$props.styleLayout;
+ const styleBackground = _this$props.styleBackground;
+ const style = _this$props.style;
+ const otherProps = _objectWithoutProperties(_this$props, ["children", "styleBoxModel", "styleText", "styleLayout", "styleBackground", "style"]);
+
+ const styles = { ...styleBoxModel,
+ ...styleText,
+ ...styleLayout,
+ ...styleBackground,
+ ...style,
+ };
+
+ if (typeof children !== 'string') {
+ styles.display = 'inline-block';
+ }
+
+ return React.createElement("a", _extends({}, otherProps, {
+ style: styles,
+ }), [children]);
+ },
+ }]);
+
+ return AIMakeLink;
+}(Component);
+
+_defineProperty(AIMakeLink, "propTypes", {
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
+ styleBoxModel: PropTypes.object.isRequired,
+ styleText: PropTypes.object.isRequired,
+ styleLayout: PropTypes.object.isRequired,
+ styleBackground: PropTypes.object.isRequired,
+ style: PropTypes.object,
+});
+
+_defineProperty(AIMakeLink, "defaultProps", {
+ children: '',
+ style: {},
+});
+
+export default HOCBoxModelProps(HOCTextProps(HOCLayoutProps(HOCBackgroundProps(AIMakeLink))));
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.js
new file mode 100644
index 0000000000..f5f08c322a
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeLink","title":"","docUrl":"","screenshot":"","npm":{"package":"@ali/lowcode-engine-material-parser","version":"0.1.0","exportName":"AIMakeLink","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"children","propType":"oneOfType","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleText","propType":"object","description":""},{"name":"styleLayout","propType":"object","description":""},{"name":"styleBackground","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeLink/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/amContainer.js
new file mode 100644
index 0000000000..45df1897e6
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/amContainer.js
@@ -0,0 +1,11 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = function () {
+ return Promise.resolve(component);
+};
+
+export default {
+ getComponent,
+ manifest: amManifest,
+};
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/amManifest.js
new file mode 100644
index 0000000000..bea679c5e6
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/amManifest.js
@@ -0,0 +1,102 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakePlaceholder',
+ // The description of current component.
+ description: '占位图',
+ // The coverimage's url of current component.
+ coverImage: 'https://img.alicdn.com/tfs/TB1RxDup3mTBuNjy1XbXXaMrVXa-362-120.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '占位图',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [{
+ alias: '占位图',
+ thumbnail: 'https://img.alicdn.com/tfs/TB1RxDup3mTBuNjy1XbXXaMrVXa-362-120.png',
+ colSpan: 24,
+ customProps: {
+ width: '224px',
+ height: '126px',
+ backgroundColor: '#FFF6E0',
+ textAlign: 'center',
+ border: '1px dashed rgb(170, 170, 170)',
+ children: '暂不支持此组件',
+ },
+ }],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'lr',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [{
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ }, {
+ name: 'width',
+ label: '宽度',
+ defaultValue: '224px',
+ renderer: 'Width',
+ }, {
+ name: 'height',
+ label: '高度',
+ defaultValue: '126px',
+ renderer: 'Height',
+ }, {
+ name: 'backgroundColor',
+ label: '背景色',
+ defaultValue: '#FFF6E0',
+ renderer: false,
+ }, {
+ name: 'textAlign',
+ label: '对齐',
+ defaultValue: 'center',
+ renderer: false,
+ }, {
+ name: 'border',
+ label: '边框',
+ defaultValue: '1px dashed rgb(170, 170, 170)',
+ renderer: false,
+ }, {
+ name: 'children',
+ label: '内容',
+ defaultValue: '暂不支持此组件',
+ renderer: false,
+ }],
+ },
+};
+export default manifest;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/container.js
new file mode 100644
index 0000000000..58dfb2fc9f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/container.js
@@ -0,0 +1,6 @@
+
+ import AIMakePlaceholder from './index.js';
+ import manifest from './manifest.js';
+
+ export default { origin: AIMakePlaceholder, manifest };
+
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/index.js
new file mode 100644
index 0000000000..5098988741
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/index.js
@@ -0,0 +1,65 @@
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+import HOCLayoutProps from '../utils/HOCLayoutProps';
+
+const AIMakePlaceholder =
+/* #__PURE__ */
+function (_Component) {
+ _inherits(AIMakePlaceholder, _Component);
+
+ function AIMakePlaceholder() {
+ _classCallCheck(this, AIMakePlaceholder);
+
+ return _possibleConstructorReturn(this, _getPrototypeOf(AIMakePlaceholder).apply(this, arguments));
+ }
+
+ _createClass(AIMakePlaceholder, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const children = _this$props.children;
+ const styleBoxModel = _this$props.styleBoxModel;
+ const styleLayout = _this$props.styleLayout;
+ const style = _this$props.style;
+ const styles = { ...styleBoxModel,
+ ...styleLayout,
+ ...style,
+ };
+ const placeholderStyle = {
+ display: 'inline-block',
+ border: '1px dashed #aaa',
+ lineHeight: styles.height,
+ backgroundColor: '#F5E075',
+ overflow: 'hidden',
+ textAlign: 'center',
+ ...styles,
+ };
+ return React.createElement("div", {
+ style: placeholderStyle,
+ }, children);
+ },
+ }]);
+
+ return AIMakePlaceholder;
+}(Component);
+
+_defineProperty(AIMakePlaceholder, "propTypes", {
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
+ styleBoxModel: PropTypes.object.isRequired,
+ styleLayout: PropTypes.object.isRequired,
+ style: PropTypes.object,
+});
+
+_defineProperty(AIMakePlaceholder, "defaultProps", {
+ children: '',
+ style: {},
+});
+
+export default HOCBoxModelProps(HOCLayoutProps(AIMakePlaceholder));
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.js
new file mode 100644
index 0000000000..022906cdd4
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakePlaceholder","title":"","docUrl":"","screenshot":"","npm":{"package":"@ali/lowcode-engine-material-parser","version":"0.1.0","exportName":"AIMakePlaceholder","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"children","propType":"oneOfType","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleLayout","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakePlaceholder/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/amContainer.js
new file mode 100644
index 0000000000..45df1897e6
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/amContainer.js
@@ -0,0 +1,11 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = function () {
+ return Promise.resolve(component);
+};
+
+export default {
+ getComponent,
+ manifest: amManifest,
+};
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/amManifest.js
new file mode 100644
index 0000000000..96fb34d28f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/amManifest.js
@@ -0,0 +1,115 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeText',
+ // The description of current component.
+ description: '富文本',
+ // The coverimage's url of current component.
+ coverImage: 'https://img.alicdn.com/tfs/TB15R_xVzDpK1RjSZFrXXa78VXa-192-48.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '文本',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [{
+ alias: '富文本',
+ thumbnail: 'https://img.alicdn.com/tfs/TB15R_xVzDpK1RjSZFrXXa78VXa-192-48.png',
+ colSpan: 12,
+ customProps: {
+ type: 'label',
+ fontSize: '12px',
+ fontWeight: 'normal',
+ children: '文本内容',
+ },
+ }],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'tbrl',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [{
+ name: 'type',
+ label: '类型',
+ renderer: 'Select',
+ defaultValue: 'label',
+ params: [{
+ label: '一级标题',
+ value: 'h1',
+ }, {
+ label: '二级标题',
+ value: 'h2',
+ }, {
+ label: '三级标题',
+ value: 'h3',
+ }, {
+ label: '段落',
+ value: 'p',
+ }, {
+ label: '标签',
+ value: 'label',
+ }],
+ }, {
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ }, {
+ name: 'color',
+ label: '文字颜色',
+ renderer: 'Color',
+ }, {
+ name: 'fontSize',
+ label: '字号',
+ renderer: 'FontSize',
+ defaultValue: '12px',
+ }, {
+ name: 'fontWeight',
+ label: '字重',
+ renderer: 'FontWeight',
+ defaultValue: 'normal',
+ }, {
+ name: 'lineHeight',
+ label: '行高',
+ defaultValue: undefined,
+ renderer: 'LineHeight',
+ }, {
+ name: 'children',
+ label: '内容',
+ defaultValue: '文本内容',
+ renderer: 'TextArea',
+ }],
+ },
+};
+export default manifest;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/container.js
new file mode 100644
index 0000000000..d93e430ad4
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/container.js
@@ -0,0 +1,6 @@
+
+ import AIMakeText from './index.js';
+ import manifest from './manifest.js';
+
+ export default { origin: AIMakeText, manifest };
+
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/index.js
new file mode 100644
index 0000000000..966b7c766d
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/index.js
@@ -0,0 +1,95 @@
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+import HOCTextProps from '../utils/HOCTextProps';
+import HOCLayoutProps from '../utils/HOCLayoutProps';
+import HOCBackgroundProps from '../utils/HOCBackgroundProps';
+
+const AIMakeText =
+/* #__PURE__ */
+function (_Component) {
+ _inherits(AIMakeText, _Component);
+
+ function AIMakeText() {
+ let _this;
+
+ _classCallCheck(this, AIMakeText);
+
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ _this = _possibleConstructorReturn(this, _getPrototypeOf(AIMakeText).call(this, ...args));
+
+ _defineProperty(_assertThisInitialized(_this), "generateComponentType", function (componentType) {
+ const componentNameMap = {
+ h1: 'h1',
+ h2: 'h2',
+ h3: 'h3',
+ h4: 'h4',
+ h5: 'h5',
+ paragraph: 'p',
+ label: 'label',
+ };
+ return componentNameMap[componentType] || 'div';
+ });
+
+ return _this;
+ }
+
+ _createClass(AIMakeText, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const children = _this$props.children;
+ const type = _this$props.type;
+ const styleBoxModel = _this$props.styleBoxModel;
+ const styleText = _this$props.styleText;
+ const styleLayout = _this$props.styleLayout;
+ const styleBackground = _this$props.styleBackground;
+ const style = _this$props.style;
+ const styles = { ...styleBoxModel,
+ ...styleText,
+ ...styleLayout,
+ ...styleBackground,
+ ...style,
+ };
+ const Comp = this.generateComponentType(type);
+ const labelStyle = Comp === 'label' ? {
+ display: 'inline-block',
+ } : {};
+ return React.createElement(Comp, {
+ className: "AIMakeText",
+ style: Object.assign(labelStyle, styles),
+ }, [children]);
+ },
+ }]);
+
+ return AIMakeText;
+}(Component);
+
+_defineProperty(AIMakeText, "propTypes", {
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node, PropTypes.string]),
+ type: PropTypes.string,
+ styleBoxModel: PropTypes.object.isRequired,
+ styleText: PropTypes.object.isRequired,
+ styleLayout: PropTypes.object.isRequired,
+ styleBackground: PropTypes.object.isRequired,
+ style: PropTypes.object,
+});
+
+_defineProperty(AIMakeText, "defaultProps", {
+ children: '',
+ type: '',
+ // paragraph || label
+ style: {},
+});
+
+export default HOCBoxModelProps(HOCTextProps(HOCLayoutProps(HOCBackgroundProps(AIMakeText))));
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.js
new file mode 100644
index 0000000000..d0d95a4d25
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeText","title":"","docUrl":"","screenshot":"","npm":{"package":"@ali/lowcode-engine-material-parser","version":"0.1.0","exportName":"AIMakeText","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"children","propType":"oneOfType","description":""},{"name":"type","propType":"string","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleText","propType":"object","description":""},{"name":"styleLayout","propType":"object","description":""},{"name":"styleBackground","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/AIMakeText/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/amContainer.js
new file mode 100644
index 0000000000..45df1897e6
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/amContainer.js
@@ -0,0 +1,11 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = function () {
+ return Promise.resolve(component);
+};
+
+export default {
+ getComponent,
+ manifest: amManifest,
+};
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/amManifest.js
new file mode 100644
index 0000000000..8d79e974d8
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/amManifest.js
@@ -0,0 +1,25 @@
+const manifest = {
+ name: 'Root',
+ description: '底板',
+ coverImage: '',
+ category: '',
+ presets: [],
+ settings: {
+ type: 'container',
+ insertionModes: 'v',
+ handles: ['paste'],
+ shouldActive: true,
+ shouldDrag: false,
+ props: [{
+ name: 'padding',
+ label: '内边距',
+ renderer: 'Quadrant',
+ }, {
+ name: 'backgroundColor',
+ label: '背景颜色',
+ defaultValue: '#F5F6FA',
+ renderer: 'Color',
+ }],
+ },
+};
+export default manifest;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/container.js
new file mode 100644
index 0000000000..8ee7fea70d
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/container.js
@@ -0,0 +1,6 @@
+
+ import Root from './index.js';
+ import manifest from './manifest.js';
+
+ export default { origin: Root, manifest };
+
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/index.js
new file mode 100644
index 0000000000..a86785522e
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/index.js
@@ -0,0 +1,51 @@
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const Root =
+/* #__PURE__ */
+function (_React$Component) {
+ _inherits(Root, _React$Component);
+
+ function Root() {
+ _classCallCheck(this, Root);
+
+ return _possibleConstructorReturn(this, _getPrototypeOf(Root).apply(this, arguments));
+ }
+
+ _createClass(Root, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const style = _this$props.style;
+ const children = _this$props.children;
+ const newStyle = Object.assign({}, Root.defaultProps.style, style);
+ return React.createElement("div", {
+ style: newStyle,
+ }, children);
+ },
+ }]);
+
+ return Root;
+}(React.Component);
+
+_defineProperty(Root, "propTypes", {
+ style: PropTypes.object,
+ children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),
+});
+
+_defineProperty(Root, "defaultProps", {
+ style: {
+ padding: 0,
+ backgroundColor: '#f0f2f5',
+ minHeight: '100%',
+ },
+ children: null,
+});
+
+export default Root;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.js
new file mode 100644
index 0000000000..756d388b26
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.js
@@ -0,0 +1 @@
+{"componentName":"Root","title":"","docUrl":"","screenshot":"","npm":{"package":"@ali/lowcode-engine-material-parser","version":"0.1.0","exportName":"Root","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"style","propType":"object","description":"","defaultValue":"{\n padding: 0,\n backgroundColor: '#f0f2f5',\n minHeight: '100%'\n}"},{"name":"children","propType":"oneOfType","description":""}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/Root/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.css b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.css
new file mode 100644
index 0000000000..8692a70c54
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.css
@@ -0,0 +1,15 @@
+.text-left {
+ text-align: left;
+}
+.text-right {
+ text-align: right;
+}
+.text-center {
+ text-align: center;
+}
+.text-justify {
+ text-align: justify;
+}
+.text-nowrap {
+ white-space: nowrap;
+}
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.js
new file mode 100644
index 0000000000..4582418a46
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.js
@@ -0,0 +1 @@
+import "./index.css";
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.less b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.less
new file mode 100644
index 0000000000..dc3680eb4f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/style/index.less
@@ -0,0 +1,8 @@
+// Alignment
+.text-left { text-align: left; }
+.text-right { text-align: right; }
+.text-center { text-align: center; }
+.text-justify { text-align: justify; }
+.text-nowrap { white-space: nowrap; }
+
+// BoxModel
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCBackgroundProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCBackgroundProps.js
new file mode 100644
index 0000000000..6b4423a321
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCBackgroundProps.js
@@ -0,0 +1,74 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+/**
+ * (HOC)注入背景相关属性配置
+ * 包含 'backgroundColor'
+ * @param {*} WrappedComponent
+ */
+
+const HOCBackgroundProps = function (WrappedComponent) {
+ let _class; let _temp;
+
+ const PROPS = {
+ backgroundColor: 'backgroundColor',
+ };
+ return _temp = _class =
+ /* #__PURE__ */
+ function (_Component) {
+ _inherits(_class, _Component);
+
+ function _class() {
+ let _this;
+
+ _classCallCheck(this, _class);
+
+ for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {
+ _args[_key] = arguments[_key];
+ }
+
+ _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));
+
+ _defineProperty(_assertThisInitialized(_this), "parseStyle", function (args) {
+ const style = {};
+ Object.keys(PROPS).forEach(function (item) {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = args[item];
+ });
+ return style;
+ });
+
+ return _this;
+ }
+
+ _createClass(_class, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const backgroundColor = _this$props.backgroundColor;
+ const otherProps = _objectWithoutProperties(_this$props, ["backgroundColor"]);
+
+ return React.createElement(WrappedComponent, _extends({}, otherProps, {
+ styleBackground: this.parseStyle(this.props),
+ }));
+ },
+ }]);
+
+ return _class;
+ }(Component), _defineProperty(_class, "propTypes", {
+ backgroundColor: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ }), _defineProperty(_class, "defaultProps", {
+ backgroundColor: false,
+ }), _temp;
+};
+
+export default HOCBackgroundProps;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCBoxModelProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCBoxModelProps.js
new file mode 100644
index 0000000000..d710488e71
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCBoxModelProps.js
@@ -0,0 +1,103 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+const parseJoin = function (value) {
+ return value.join(' ');
+};
+/**
+ * (HOC)注入盒子模型相关属性配置
+ * 包含 'display', 'margin', 'border', 'padding', 'width', 'height', 'borderRadius'
+ * @param {*} WrappedComponent
+ */
+
+
+const HOCBoxModelProps = function (WrappedComponent) {
+ let _class; let _temp;
+
+ const PROPS = {
+ display: 'display',
+ margin: 'margin',
+ border: 'border',
+ padding: 'padding',
+ width: 'width',
+ height: 'height',
+ borderRadius: 'borderRadius',
+ };
+ return _temp = _class =
+ /* #__PURE__ */
+ function (_Component) {
+ _inherits(_class, _Component);
+
+ function _class() {
+ let _this;
+
+ _classCallCheck(this, _class);
+
+ for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {
+ _args[_key] = arguments[_key];
+ }
+
+ _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));
+
+ _defineProperty(_assertThisInitialized(_this), "parseStyle", function (args) {
+ const style = {};
+ Object.keys(PROPS).forEach(function (item) {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = Array.isArray(args[item]) ? parseJoin(args[item]) : args[item];
+ });
+ return style;
+ });
+
+ return _this;
+ }
+
+ _createClass(_class, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const display = _this$props.display;
+ const margin = _this$props.margin;
+ const border = _this$props.border;
+ const padding = _this$props.padding;
+ const width = _this$props.width;
+ const height = _this$props.height;
+ const borderRadius = _this$props.borderRadius;
+ const otherProps = _objectWithoutProperties(_this$props, ["display", "margin", "border", "padding", "width", "height", "borderRadius"]);
+
+ return React.createElement(WrappedComponent, _extends({}, otherProps, {
+ styleBoxModel: this.parseStyle(this.props),
+ }));
+ },
+ }]);
+
+ return _class;
+ }(Component), _defineProperty(_class, "propTypes", {
+ display: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ margin: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
+ border: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
+ padding: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
+ width: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ height: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ borderRadius: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ }), _defineProperty(_class, "defaultProps", {
+ display: false,
+ margin: false,
+ border: false,
+ padding: false,
+ width: false,
+ height: false,
+ borderRadius: false,
+ }), _temp;
+};
+
+export default HOCBoxModelProps;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCFlexLayoutProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCFlexLayoutProps.js
new file mode 100644
index 0000000000..684a4f2f39
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCFlexLayoutProps.js
@@ -0,0 +1,90 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+/**
+ * (HOC)注入flex布局相关属性配置
+ * 包含 'alignItems', 'justifyContent', 'flexDirection'
+ * @param {*} WrappedComponent
+ */
+
+const HOCFlexLayoutProps = function (WrappedComponent) {
+ let _class; let _temp;
+
+ const PROPS = {
+ alignItems: 'alignItems',
+ justifyContent: 'justifyContent',
+ flexDirection: 'flexDirection',
+ flexWrap: 'flexWrap',
+ };
+ return _temp = _class =
+ /* #__PURE__ */
+ function (_Component) {
+ _inherits(_class, _Component);
+
+ function _class() {
+ let _this;
+
+ _classCallCheck(this, _class);
+
+ for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {
+ _args[_key] = arguments[_key];
+ }
+
+ _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));
+
+ _defineProperty(_assertThisInitialized(_this), "parseStyle", function (args) {
+ const style = {};
+
+ if (args.style && args.style.display === 'flex') {
+ Object.keys(PROPS).forEach(function (item) {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = args[item];
+ });
+ }
+
+ return style;
+ });
+
+ return _this;
+ }
+
+ _createClass(_class, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const alignItems = _this$props.alignItems;
+ const justifyContent = _this$props.justifyContent;
+ const flexDirection = _this$props.flexDirection;
+ const flexWrap = _this$props.flexWrap;
+ const otherProps = _objectWithoutProperties(_this$props, ["alignItems", "justifyContent", "flexDirection", "flexWrap"]);
+
+ return React.createElement(WrappedComponent, _extends({}, otherProps, {
+ styleFlexLayout: this.parseStyle(this.props),
+ }));
+ },
+ }]);
+
+ return _class;
+ }(Component), _defineProperty(_class, "propTypes", {
+ alignItems: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ justifyContent: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ flexDirection: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ flexWrap: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ }), _defineProperty(_class, "defaultProps", {
+ alignItems: false,
+ justifyContent: false,
+ flexDirection: false,
+ flexWrap: false,
+ }), _temp;
+};
+
+export default HOCFlexLayoutProps;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCLayoutProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCLayoutProps.js
new file mode 100644
index 0000000000..4710d093ab
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCLayoutProps.js
@@ -0,0 +1,82 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+/**
+ * (HOC)注入布局相关属性配置
+ * 包含 'align', 'lineHeight', 'verticalAlign'
+ * @param {*} WrappedComponent
+ */
+
+const HOCLayoutProps = function (WrappedComponent) {
+ let _class; let _temp;
+
+ const PROPS = {
+ align: 'textAlign',
+ lineHeight: 'lineHeight',
+ verticalAlign: 'verticalAlign',
+ };
+ return _temp = _class =
+ /* #__PURE__ */
+ function (_Component) {
+ _inherits(_class, _Component);
+
+ function _class() {
+ let _this;
+
+ _classCallCheck(this, _class);
+
+ for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {
+ _args[_key] = arguments[_key];
+ }
+
+ _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));
+
+ _defineProperty(_assertThisInitialized(_this), "parseStyle", function (args) {
+ const style = {};
+ Object.keys(PROPS).forEach(function (item) {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = args[item];
+ });
+ return style;
+ });
+
+ return _this;
+ }
+
+ _createClass(_class, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const align = _this$props.align;
+ const lineHeight = _this$props.lineHeight;
+ const verticalAlign = _this$props.verticalAlign;
+ const otherProps = _objectWithoutProperties(_this$props, ["align", "lineHeight", "verticalAlign"]);
+
+ return React.createElement(WrappedComponent, _extends({}, otherProps, {
+ styleLayout: this.parseStyle(this.props),
+ }));
+ },
+ }]);
+
+ return _class;
+ }(Component), _defineProperty(_class, "propTypes", {
+ align: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ lineHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ verticalAlign: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ }), _defineProperty(_class, "defaultProps", {
+ align: false,
+ lineHeight: false,
+ verticalAlign: false,
+ }), _temp;
+};
+
+export default HOCLayoutProps;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCTextProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCTextProps.js
new file mode 100644
index 0000000000..fb685d23a7
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/basic/utils/HOCTextProps.js
@@ -0,0 +1,82 @@
+import _extends from "@babel/runtime/helpers/extends";
+import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
+import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
+import _createClass from "@babel/runtime/helpers/createClass";
+import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
+import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
+import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
+import _inherits from "@babel/runtime/helpers/inherits";
+import _defineProperty from "@babel/runtime/helpers/defineProperty";
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+/**
+ * (HOC)注入文本相关属性配置
+ * 包含 'fontSize', 'fontWeight', 'color'
+ * @param {*} WrappedComponent
+ */
+
+const HOCTextProps = function (WrappedComponent) {
+ let _class; let _temp;
+
+ const PROPS = {
+ fontSize: 'fontSize',
+ fontWeight: 'fontWeight',
+ color: 'color',
+ };
+ return _temp = _class =
+ /* #__PURE__ */
+ function (_Component) {
+ _inherits(_class, _Component);
+
+ function _class() {
+ let _this;
+
+ _classCallCheck(this, _class);
+
+ for (var _len = arguments.length, _args = new Array(_len), _key = 0; _key < _len; _key++) {
+ _args[_key] = arguments[_key];
+ }
+
+ _this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, ..._args));
+
+ _defineProperty(_assertThisInitialized(_this), "parseStyle", function (args) {
+ const style = {};
+ Object.keys(PROPS).forEach(function (item) {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = args[item];
+ });
+ return style;
+ });
+
+ return _this;
+ }
+
+ _createClass(_class, [{
+ key: "render",
+ value: function render() {
+ const _this$props = this.props;
+ const fontSize = _this$props.fontSize;
+ const fontWeight = _this$props.fontWeight;
+ const color = _this$props.color;
+ const otherProps = _objectWithoutProperties(_this$props, ["fontSize", "fontWeight", "color"]);
+
+ return React.createElement(WrappedComponent, _extends({}, otherProps, {
+ styleText: this.parseStyle(this.props),
+ }));
+ },
+ }]);
+
+ return _class;
+ }(Component), _defineProperty(_class, "propTypes", {
+ fontSize: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ fontWeight: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ color: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ }), _defineProperty(_class, "defaultProps", {
+ fontSize: false,
+ fontWeight: false,
+ color: false,
+ }), _temp;
+};
+
+export default HOCTextProps;
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/es/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/es/index.js
new file mode 100644
index 0000000000..aebb560679
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/es/index.js
@@ -0,0 +1,9 @@
+import AIMakeBlank from './basic/AIMakeBlank';
+import AIMakeIcon from './basic/AIMakeIcon';
+import AIMakeImage from './basic/AIMakeImage';
+import AIMakeLink from './basic/AIMakeLink';
+import AIMakePlaceholder from './basic/AIMakePlaceholder';
+import AIMakeText from './basic/AIMakeText';
+import Root from './basic/Root';
+
+export { AIMakeBlank, AIMakeIcon, AIMakeImage, AIMakeLink, AIMakePlaceholder, AIMakeText, Root };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/package.json b/modules/material-parser/test/fixtures/multiple-exported-component/package.json
new file mode 100644
index 0000000000..e9e7c8b11b
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "multiple-exported-component",
+ "description": "提供最基础、通用的物料组件",
+ "version": "1.0.0",
+ "main": "es/index.js",
+ "module": "es/index.js",
+ "dependencies": {
+ "classnames": "^2.2.6",
+ "prop-types": "^15.7.2",
+ "react": "^16.8.5",
+ "react-dom": "^16.8.5"
+ },
+ "devDependencies": {
+ "cross-spawn": "^6.0.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.6"
+ },
+ "publishConfig": {
+ "registry": "https://registry.npm.alibaba-inc.com"
+ }
+}
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/amContainer.js
new file mode 100644
index 0000000000..1eccfe0800
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/amContainer.js
@@ -0,0 +1,6 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = () => Promise.resolve(component);
+
+export default { getComponent, manifest: amManifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/amManifest.js
new file mode 100644
index 0000000000..66bb458d82
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/amManifest.js
@@ -0,0 +1,158 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+
+function _update(Nygma, node) {
+ const attributes = node.get();
+ const {
+ display,
+ flexDirection,
+ alignItems,
+ justifyContent,
+ flexWrap,
+ } = attributes;
+ const isFlex = display === 'flex';
+ node.set({
+ display,
+ flexDirection: isFlex ? flexDirection : undefined,
+ alignItems: isFlex ? alignItems : undefined,
+ justifyContent: isFlex ? justifyContent : undefined,
+ flexWrap: isFlex ? flexWrap : undefined,
+ });
+}
+
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeBlank',
+ // The description of current component.
+ description: '空白卡片',
+ // The coverimage's url of current component.
+ coverImage:
+ 'https://img.alicdn.com/tfs/TB1un9tqntYBeNjy1XdXXXXyVXa-366-124.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '布局', // card.blank
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [
+ {
+ alias: '空白卡片',
+ thumbnail:
+ 'https://img.alicdn.com/tfs/TB1ucPNVsbpK1RjSZFyXXX_qFXa-198-120.png',
+ colSpan: 12,
+ customProps: {
+ id: '',
+ textAlign: 'left',
+ padding: '12px',
+ width: '100%',
+ backgroundColor: '#FFF',
+ },
+ },
+ ],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'container',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'tbrlv',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ lifeCycle: {
+ didMount: (props) => {
+ const { Nygma, dragInstance } = props;
+ const Drager = dragInstance.NygmaNode;
+ _update(Nygma, Drager);
+ },
+ didUpdate: (Nygma, node, args) => {
+ const newvalue = args[1];
+ const oldvalue = args[2];
+ if (JSON.stringify(newvalue) !== JSON.stringify(oldvalue)) {
+ _update(Nygma, node);
+ }
+ },
+ },
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [
+ {
+ name: 'id',
+ label: 'id',
+ defaultValue: '',
+ renderer: 'Input',
+ },
+ {
+ name: 'textAlign',
+ label: '水平对齐',
+ defaultValue: 'left',
+ renderer: 'TextAlign',
+ },
+ {
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ },
+ {
+ name: 'padding',
+ label: '内边距',
+ renderer: 'Quadrant',
+ defaultValue: '12px',
+ },
+ {
+ name: 'width',
+ label: '宽度',
+ defaultValue: '100%',
+ renderer: 'Width',
+ },
+ {
+ name: 'height',
+ label: '高度',
+ renderer: 'Height',
+ defaultValue: undefined,
+ },
+ {
+ name: 'backgroundColor',
+ label: '背景颜色',
+ renderer: 'Color',
+ defaultValue: '#FFF',
+ },
+ {
+ name: 'border',
+ label: '边框',
+ renderer: 'BarBorder',
+ },
+ {
+ name: 'display',
+ label: '布局设置',
+ renderer: 'FlexLayout',
+ },
+ ],
+ },
+};
+
+export default manifest;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/container.js
new file mode 100644
index 0000000000..27019261b9
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/container.js
@@ -0,0 +1,5 @@
+
+import AIMakeBlank from '../../../es/basic/AIMakeBlank/index.js';
+import manifest from './manifest.js';
+
+export default { origin: AIMakeBlank, manifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/index.js
new file mode 100644
index 0000000000..1199896042
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/index.js
@@ -0,0 +1,61 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+import HOCLayoutProps from '../utils/HOCLayoutProps';
+import HOCBackgroundProps from '../utils/HOCBackgroundProps';
+import HOCFlexLayoutProps from '../utils/HOCFlexLayoutProps';
+
+class AIMakeBlank extends Component {
+ static propTypes = {
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ]),
+ styleBoxModel: PropTypes.object.isRequired,
+ styleLayout: PropTypes.object.isRequired,
+ styleBackground: PropTypes.object.isRequired,
+ styleFlexLayout: PropTypes.object.isRequired,
+ style: PropTypes.object,
+ id: PropTypes.string,
+ };
+
+ static defaultProps = {
+ children: [],
+ style: {},
+ id: '',
+ };
+
+ render() {
+ const merged = {};
+ const {
+ children,
+ styleBoxModel,
+ styleLayout,
+ styleBackground,
+ styleFlexLayout,
+ style,
+ id,
+ } = this.props;
+
+ const styles = {
+ ...styleBoxModel,
+ ...styleLayout,
+ ...styleBackground,
+ ...styleFlexLayout,
+ ...style,
+ };
+ if (id) {
+ merged.id = id;
+ }
+ return (
+
+ {children}
+
+ );
+ }
+}
+
+export default HOCBoxModelProps(
+ HOCLayoutProps(HOCBackgroundProps(HOCFlexLayoutProps(AIMakeBlank))),
+);
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.js
new file mode 100644
index 0000000000..17c6c16d07
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeBlank","title":"","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"AIMakeBlank","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"children","propType":"oneOfType","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleLayout","propType":"object","description":""},{"name":"styleBackground","propType":"object","description":""},{"name":"styleFlexLayout","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"},{"name":"id","propType":"string","description":""}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeBlank/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/IconFont.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/IconFont.js
new file mode 100644
index 0000000000..e0f766754e
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/IconFont.js
@@ -0,0 +1,51 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+// 缓存已加载的字体文件
+const customCache = new Set();
+
+// 动态加载字体文件
+export default function createFromIconfont(options) {
+ const { scriptUrl } = options;
+ if (
+ typeof document !== 'undefined'
+ && typeof window !== 'undefined'
+ && typeof document.createElement === 'function'
+ && typeof scriptUrl === 'string'
+ && scriptUrl.length
+ && !customCache.has(scriptUrl)
+ ) {
+ const script = document.createElement('script');
+ script.setAttribute('src', scriptUrl);
+ script.setAttribute('data-namespace', scriptUrl);
+ customCache.add(scriptUrl);
+ document.body.appendChild(script);
+ }
+
+ class IconFont extends Component {
+ render() {
+ const { type, ...restProps } = this.props;
+ const innerSvgProps = {
+ width: '1em',
+ height: '1em',
+ fill: 'currentColor',
+ 'aria-hidden': 'true',
+ focusable: 'false',
+ };
+ // 引用指定svg
+ const content = ;
+
+ return (
+
+
+
+ );
+ }
+ }
+
+ IconFont.propTypes = {
+ type: PropTypes.string.isRequired, // icon
+ };
+
+ return IconFont;
+}
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/amContainer.js
new file mode 100644
index 0000000000..98b0a96874
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/amContainer.js
@@ -0,0 +1,7 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+import createFromIconfont from './IconFont';
+
+const getComponent = () => Promise.resolve(component);
+
+export default { getComponent, manifest: amManifest, createFromIconfont };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/amManifest.js
new file mode 100644
index 0000000000..ae1354fc39
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/amManifest.js
@@ -0,0 +1,89 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeIcon',
+ // The description of current component.
+ description: '图标',
+ // The coverimage's url of current component.
+ coverImage: '',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: 'AIMakeIcon',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'rl',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [
+ {
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ },
+ {
+ name: 'color',
+ label: '图标颜色',
+ renderer: 'Color',
+ defaultValue: '#333',
+ },
+ {
+ name: 'fontSize',
+ label: '图标大小',
+ renderer: 'FontSize',
+ defaultValue: '16px',
+ },
+ {
+ name: 'display',
+ label: '显示',
+ defaultValue: 'inline-block',
+ },
+ {
+ name: 'className',
+ label: '图标类型',
+ defaultValue: 'iconfont',
+ renderer: false,
+ params: {
+ placeholder: '请输入Iconfont名',
+ },
+ },
+ ],
+ },
+};
+
+export default manifest;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/container.js
new file mode 100644
index 0000000000..d626b63fe2
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/container.js
@@ -0,0 +1,5 @@
+
+import AIMakeIcon from '../../../es/basic/AIMakeIcon/index.js';
+import manifest from './manifest.js';
+
+export default { origin: AIMakeIcon, manifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/index.js
new file mode 100644
index 0000000000..83dd1e910b
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/index.js
@@ -0,0 +1,59 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+
+import createFromIconfont from './IconFont';
+
+class AIMakeIcon extends Component {
+ static propTypes = {
+ className: PropTypes.string,
+ iconClassName: PropTypes.string,
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ]),
+ styleBoxModel: PropTypes.object.isRequired,
+ styleText: PropTypes.object.isRequired,
+ styleBackground: PropTypes.object.isRequired,
+ style: PropTypes.object,
+ };
+
+ static defaultProps = {
+ className: '',
+ iconClassName: 'iconfont',
+ children: '',
+ style: {},
+ };
+
+ render() {
+ const {
+ className,
+ iconClassName,
+ children,
+ styleBoxModel,
+ styleText,
+ styleBackground,
+ style,
+ ...otherProps
+ } = this.props;
+ const styles = {
+ ...styleBoxModel,
+ ...styleText,
+ ...styleBackground,
+ ...style,
+ };
+ return (
+
+ {children}
+
+ );
+ }
+}
+
+AIMakeIcon.createFromIconfont = createFromIconfont;
+
+export default AIMakeIcon;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.js
new file mode 100644
index 0000000000..21824462a3
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeIcon","title":"","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"AIMakeIcon","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"className","propType":"string","description":""},{"name":"iconClassName","propType":"string","description":""},{"name":"children","propType":"oneOfType","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleText","propType":"object","description":""},{"name":"styleBackground","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeIcon/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/amContainer.js
new file mode 100644
index 0000000000..1eccfe0800
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/amContainer.js
@@ -0,0 +1,6 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = () => Promise.resolve(component);
+
+export default { getComponent, manifest: amManifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/amManifest.js
new file mode 100644
index 0000000000..8e0bbf38a8
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/amManifest.js
@@ -0,0 +1,99 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeImage',
+ // The description of current component.
+ description: '图片',
+ // The coverimage's url of current component.
+ coverImage:
+ 'https://img.alicdn.com/tfs/TB17gMFp1uSBuNjy1XcXXcYjFXa-172-120.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '线条图像',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [
+ {
+ alias: '图片',
+ thumbnail:
+ 'https://img.alicdn.com/tfs/TB17gMFp1uSBuNjy1XcXXcYjFXa-172-120.png',
+ colSpan: 12,
+ customProps: {
+ width: '224px',
+ height: '126px',
+ src:
+ 'https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',
+ },
+ },
+ ],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'rl',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [
+ {
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ },
+ {
+ name: 'width',
+ label: '宽度',
+ defaultValue: '224px',
+ renderer: 'Width',
+ },
+ {
+ name: 'height',
+ label: '高度',
+ defaultValue: '126px',
+ renderer: 'Height',
+ },
+ {
+ name: 'src',
+ label: '图片URL',
+ renderer: 'Uploader',
+ placeholder:
+ 'eg: https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',
+ hint: '请填入图片的URL',
+ defaultValue:
+ 'https://img.alicdn.com/tfs/TB1RtEMGbSYBuNjSspfXXcZCpXa-448-252.png',
+ },
+ ],
+ },
+};
+
+export default manifest;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/container.js
new file mode 100644
index 0000000000..20f8d5899c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/container.js
@@ -0,0 +1,5 @@
+
+import AIMakeImage from '../../../es/basic/AIMakeImage/index.js';
+import manifest from './manifest.js';
+
+export default { origin: AIMakeImage, manifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/index.js
new file mode 100644
index 0000000000..edb316342d
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/index.js
@@ -0,0 +1,26 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+
+class AIMakeImage extends Component {
+ static propTypes = {
+ styleBoxModel: PropTypes.object.isRequired,
+ style: PropTypes.object,
+ };
+
+ static defaultProps = {
+ style: {},
+ };
+
+ render() {
+ const { styleBoxModel, style, ...otherProps } = this.props;
+ const styles = {
+ ...styleBoxModel,
+ ...style,
+ };
+ return
;
+ }
+}
+
+export default HOCBoxModelProps(AIMakeImage);
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.js
new file mode 100644
index 0000000000..b5ffde2844
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeImage","title":"","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"AIMakeImage","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"styleBoxModel","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeImage/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/amContainer.js
new file mode 100644
index 0000000000..1eccfe0800
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/amContainer.js
@@ -0,0 +1,6 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = () => Promise.resolve(component);
+
+export default { getComponent, manifest: amManifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/amManifest.js
new file mode 100644
index 0000000000..0797b01845
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/amManifest.js
@@ -0,0 +1,115 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeLink',
+ // The description of current component.
+ description: '链接',
+ // The coverimage's url of current component.
+ coverImage:
+ 'https://img.alicdn.com/tfs/TB1otbyVwTqK1RjSZPhXXXfOFXa-192-48.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '文本',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [
+ {
+ alias: '链接',
+ thumbnail:
+ 'https://img.alicdn.com/tfs/TB1otbyVwTqK1RjSZPhXXXfOFXa-192-48.png',
+ colSpan: 12,
+ customProps: {
+ color: '#3788FF',
+ fontSize: '12px',
+ fontWeight: 'normal',
+ href: '#',
+ children: '链接',
+ },
+ },
+ ],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'lrv',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [
+ {
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ },
+ {
+ name: 'color',
+ label: '文字颜色',
+ renderer: 'Color',
+ defaultValue: '#3788FF',
+ },
+ {
+ name: 'fontSize',
+ label: '字号',
+ renderer: 'FontSize',
+ defaultValue: '12px',
+ },
+ {
+ name: 'fontWeight',
+ label: '字重',
+ renderer: 'FontWeight',
+ defaultValue: 'normal',
+ },
+ {
+ name: 'lineHeight',
+ label: '行高',
+ defaultValue: undefined,
+ renderer: 'LineHeight',
+ },
+ {
+ name: 'href',
+ label: '链接URL',
+ renderer: 'Input',
+ placeholder: '请输入链接URL',
+ defaultValue: '#',
+ },
+ {
+ name: 'children',
+ label: '内容',
+ defaultValue: '链接',
+ renderer: 'TextArea',
+ },
+ ],
+ },
+};
+
+export default manifest;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/container.js
new file mode 100644
index 0000000000..d927906be4
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/container.js
@@ -0,0 +1,5 @@
+
+import AIMakeLink from '../../../es/basic/AIMakeLink/index.js';
+import manifest from './manifest.js';
+
+export default { origin: AIMakeLink, manifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/index.js
new file mode 100644
index 0000000000..eba2e50354
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/index.js
@@ -0,0 +1,57 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+import HOCTextProps from '../utils/HOCTextProps';
+import HOCLayoutProps from '../utils/HOCLayoutProps';
+import HOCBackgroundProps from '../utils/HOCBackgroundProps';
+
+class AIMakeLink extends Component {
+ static propTypes = {
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ]),
+ styleBoxModel: PropTypes.object.isRequired,
+ styleText: PropTypes.object.isRequired,
+ styleLayout: PropTypes.object.isRequired,
+ styleBackground: PropTypes.object.isRequired,
+ style: PropTypes.object,
+ };
+
+ static defaultProps = {
+ children: '',
+ style: {},
+ };
+
+ render() {
+ const {
+ children,
+ styleBoxModel,
+ styleText,
+ styleLayout,
+ styleBackground,
+ style,
+ ...otherProps
+ } = this.props;
+ const styles = {
+ ...styleBoxModel,
+ ...styleText,
+ ...styleLayout,
+ ...styleBackground,
+ ...style,
+ };
+ if (typeof children !== 'string') {
+ styles.display = 'inline-block';
+ }
+ return (
+
+ {[children]}
+
+ );
+ }
+}
+
+export default HOCBoxModelProps(
+ HOCTextProps(HOCLayoutProps(HOCBackgroundProps(AIMakeLink))),
+);
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.js
new file mode 100644
index 0000000000..377983d6df
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeLink","title":"","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"AIMakeLink","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"children","propType":"oneOfType","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleText","propType":"object","description":""},{"name":"styleLayout","propType":"object","description":""},{"name":"styleBackground","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeLink/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/amContainer.js
new file mode 100644
index 0000000000..1eccfe0800
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/amContainer.js
@@ -0,0 +1,6 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = () => Promise.resolve(component);
+
+export default { getComponent, manifest: amManifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/amManifest.js
new file mode 100644
index 0000000000..e4cb0e8e1a
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/amManifest.js
@@ -0,0 +1,115 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakePlaceholder',
+ // The description of current component.
+ description: '占位图',
+ // The coverimage's url of current component.
+ coverImage:
+ 'https://img.alicdn.com/tfs/TB1RxDup3mTBuNjy1XbXXaMrVXa-362-120.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '占位图',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [
+ {
+ alias: '占位图',
+ thumbnail:
+ 'https://img.alicdn.com/tfs/TB1RxDup3mTBuNjy1XbXXaMrVXa-362-120.png',
+ colSpan: 24,
+ customProps: {
+ width: '224px',
+ height: '126px',
+ backgroundColor: '#FFF6E0',
+ textAlign: 'center',
+ border: '1px dashed rgb(170, 170, 170)',
+ children: '暂不支持此组件',
+ },
+ },
+ ],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'lr',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [
+ {
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ },
+ {
+ name: 'width',
+ label: '宽度',
+ defaultValue: '224px',
+ renderer: 'Width',
+ },
+ {
+ name: 'height',
+ label: '高度',
+ defaultValue: '126px',
+ renderer: 'Height',
+ },
+ {
+ name: 'backgroundColor',
+ label: '背景色',
+ defaultValue: '#FFF6E0',
+ renderer: false,
+ },
+ {
+ name: 'textAlign',
+ label: '对齐',
+ defaultValue: 'center',
+ renderer: false,
+ },
+ {
+ name: 'border',
+ label: '边框',
+ defaultValue: '1px dashed rgb(170, 170, 170)',
+ renderer: false,
+ },
+ {
+ name: 'children',
+ label: '内容',
+ defaultValue: '暂不支持此组件',
+ renderer: false,
+ },
+ ],
+ },
+};
+
+export default manifest;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/container.js
new file mode 100644
index 0000000000..17f48df564
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/container.js
@@ -0,0 +1,5 @@
+
+import AIMakePlaceholder from '../../../es/basic/AIMakePlaceholder/index.js';
+import manifest from './manifest.js';
+
+export default { origin: AIMakePlaceholder, manifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/index.js
new file mode 100644
index 0000000000..60cdbb1ddc
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/index.js
@@ -0,0 +1,45 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+import HOCLayoutProps from '../utils/HOCLayoutProps';
+
+class AIMakePlaceholder extends Component {
+ static propTypes = {
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ]),
+ styleBoxModel: PropTypes.object.isRequired,
+ styleLayout: PropTypes.object.isRequired,
+ style: PropTypes.object,
+ };
+
+ static defaultProps = {
+ children: '',
+ style: {},
+ };
+
+ render() {
+ const {
+ children, styleBoxModel, styleLayout, style,
+ } = this.props;
+ const styles = {
+ ...styleBoxModel,
+ ...styleLayout,
+ ...style,
+ };
+ const placeholderStyle = {
+ display: 'inline-block',
+ border: '1px dashed #aaa',
+ lineHeight: styles.height,
+ backgroundColor: '#F5E075',
+ overflow: 'hidden',
+ textAlign: 'center',
+ ...styles,
+ };
+ return {children}
;
+ }
+}
+
+export default HOCBoxModelProps(HOCLayoutProps(AIMakePlaceholder));
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.js
new file mode 100644
index 0000000000..7456ed578a
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakePlaceholder","title":"","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"AIMakePlaceholder","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"children","propType":"oneOfType","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleLayout","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakePlaceholder/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/amContainer.js
new file mode 100644
index 0000000000..1eccfe0800
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/amContainer.js
@@ -0,0 +1,6 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = () => Promise.resolve(component);
+
+export default { getComponent, manifest: amManifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/amManifest.js
new file mode 100644
index 0000000000..b84fcba795
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/amManifest.js
@@ -0,0 +1,119 @@
+/**
+ * The template of manifest for AiMake studio.
+ */
+const manifest = {
+ // The name of current component.
+ name: 'AIMakeText',
+ // The description of current component.
+ description: '富文本',
+ // The coverimage's url of current component.
+ coverImage:
+ 'https://img.alicdn.com/tfs/TB15R_xVzDpK1RjSZFrXXa78VXa-192-48.png',
+ // The category of current component in AiMake studio.
+ // can be:
+ // `分栏` or `文本` or `按钮` or `标签` or `标签页` or `表格` or `单选` or `分割线`
+ // or `分页` or `复选` or `滑动条` or `进度条` or `卡片` or `开关` or `缺省状态`
+ // or `日期选择` or `输入框` or `搜索框` or `图表` or `图片` or `下拉选择` or `表单行`
+ // or `树控件` or `折叠面板` or `占位图`
+ category: '文本',
+ // The preview list of current component in AiMake studio.
+ // Each preset contains following keys:
+ // - `alias`: string. required. The previewing component's name to display
+ // - `thumbnail`: string. not required. The previewing component's thumbnail
+ // - `customProps`: object. not required.
+ // The previewing component's customize props, e.g. { [propName]: [propValue] }
+ // - `colSpan`: number. not required. default 24 (1~24). The previewing component's size when to display
+ presets: [
+ {
+ alias: '富文本',
+ thumbnail:
+ 'https://img.alicdn.com/tfs/TB15R_xVzDpK1RjSZFrXXa78VXa-192-48.png',
+ colSpan: 12,
+ customProps: {
+ type: 'label',
+ fontSize: '12px',
+ fontWeight: 'normal',
+ children: '文本内容',
+ },
+ },
+ ],
+ // Other settings of current component for AiMake studio.
+ settings: {
+ // The render type of current component in AiMake studio.
+ // can be:
+ // `element_inline` or `element_block` or `container`
+ type: 'element_inline',
+ // The insert mode of current component in AiMake studio.
+ // can be:
+ // one or combine of `t` and `b` and `r` and `l`
+ insertionModes: 'tbrl',
+ // The handle list of current component in AiMake studio.
+ // can be:
+ // an array contains one and more of ['cut', 'copy', 'paste', 'delete', 'duplicate']
+ handles: ['cut', 'copy', 'paste', 'delete', 'duplicate'],
+ // Whether the component can be actived.
+ shouldActive: true,
+ // Whether the component can be dragged.
+ shouldDrag: true,
+ // The props of current component in AiMake studio.
+ // Each property contains following keys:
+ // - `name`: string. required. The property's name
+ // - `label`: string. required. The property's name to display
+ // - `renderer`: string. required. The property's editor. can be: (@冰骊)
+ // - `defaultValue`: any. not required. The property's default value
+ // - `params`: any. not required. The parameters for property's editor
+ // - `placeholder`: string. not required. The placeholder for property's editor
+ // - `hint`: string. not required. The hint for property's editor
+ props: [
+ {
+ name: 'type',
+ label: '类型',
+ renderer: 'Select',
+ defaultValue: 'label',
+ params: [
+ { label: '一级标题', value: 'h1' },
+ { label: '二级标题', value: 'h2' },
+ { label: '三级标题', value: 'h3' },
+ { label: '段落', value: 'p' },
+ { label: '标签', value: 'label' },
+ ],
+ },
+ {
+ name: 'margin',
+ label: '外边距',
+ renderer: 'Quadrant',
+ },
+ {
+ name: 'color',
+ label: '文字颜色',
+ renderer: 'Color',
+ },
+ {
+ name: 'fontSize',
+ label: '字号',
+ renderer: 'FontSize',
+ defaultValue: '12px',
+ },
+ {
+ name: 'fontWeight',
+ label: '字重',
+ renderer: 'FontWeight',
+ defaultValue: 'normal',
+ },
+ {
+ name: 'lineHeight',
+ label: '行高',
+ defaultValue: undefined,
+ renderer: 'LineHeight',
+ },
+ {
+ name: 'children',
+ label: '内容',
+ defaultValue: '文本内容',
+ renderer: 'TextArea',
+ },
+ ],
+ },
+};
+
+export default manifest;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/container.js
new file mode 100644
index 0000000000..6bf3cca688
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/container.js
@@ -0,0 +1,5 @@
+
+import AIMakeText from '../../../es/basic/AIMakeText/index.js';
+import manifest from './manifest.js';
+
+export default { origin: AIMakeText, manifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/index.js
new file mode 100644
index 0000000000..133e940f45
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/index.js
@@ -0,0 +1,72 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+import HOCBoxModelProps from '../utils/HOCBoxModelProps';
+import HOCTextProps from '../utils/HOCTextProps';
+import HOCLayoutProps from '../utils/HOCLayoutProps';
+import HOCBackgroundProps from '../utils/HOCBackgroundProps';
+
+class AIMakeText extends Component {
+ static propTypes = {
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ PropTypes.string,
+ ]),
+ type: PropTypes.string,
+ styleBoxModel: PropTypes.object.isRequired,
+ styleText: PropTypes.object.isRequired,
+ styleLayout: PropTypes.object.isRequired,
+ styleBackground: PropTypes.object.isRequired,
+ style: PropTypes.object,
+ };
+
+ static defaultProps = {
+ children: '',
+ type: '', // paragraph || label
+ style: {},
+ };
+
+ generateComponentType = (componentType) => {
+ const componentNameMap = {
+ h1: 'h1',
+ h2: 'h2',
+ h3: 'h3',
+ h4: 'h4',
+ h5: 'h5',
+ paragraph: 'p',
+ label: 'label',
+ };
+ return componentNameMap[componentType] || 'div';
+ };
+
+ render() {
+ const {
+ children,
+ type,
+ styleBoxModel,
+ styleText,
+ styleLayout,
+ styleBackground,
+ style,
+ } = this.props;
+ const styles = {
+ ...styleBoxModel,
+ ...styleText,
+ ...styleLayout,
+ ...styleBackground,
+ ...style,
+ };
+ const Comp = this.generateComponentType(type);
+ const labelStyle = Comp === 'label' ? { display: 'inline-block' } : {};
+ return (
+
+ {[children]}
+
+ );
+ }
+}
+
+export default HOCBoxModelProps(
+ HOCTextProps(HOCLayoutProps(HOCBackgroundProps(AIMakeText))),
+);
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.js
new file mode 100644
index 0000000000..b275a18156
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.js
@@ -0,0 +1 @@
+{"componentName":"AIMakeText","title":"","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"AIMakeText","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"children","propType":"oneOfType","description":""},{"name":"type","propType":"string","description":""},{"name":"styleBoxModel","propType":"object","description":""},{"name":"styleText","propType":"object","description":""},{"name":"styleLayout","propType":"object","description":""},{"name":"styleBackground","propType":"object","description":""},{"name":"style","propType":"object","description":"","defaultValue":"{}"}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/AIMakeText/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/amContainer.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/amContainer.js
new file mode 100644
index 0000000000..1eccfe0800
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/amContainer.js
@@ -0,0 +1,6 @@
+import component from './index.js';
+import amManifest from './amManifest.js';
+
+const getComponent = () => Promise.resolve(component);
+
+export default { getComponent, manifest: amManifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/amManifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/amManifest.js
new file mode 100644
index 0000000000..951356cd0b
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/amManifest.js
@@ -0,0 +1,29 @@
+const manifest = {
+ name: 'Root',
+ description: '底板',
+ coverImage: '',
+ category: '',
+ presets: [],
+ settings: {
+ type: 'container',
+ insertionModes: 'v',
+ handles: ['paste'],
+ shouldActive: true,
+ shouldDrag: false,
+ props: [
+ {
+ name: 'padding',
+ label: '内边距',
+ renderer: 'Quadrant',
+ },
+ {
+ name: 'backgroundColor',
+ label: '背景颜色',
+ defaultValue: '#F5F6FA',
+ renderer: 'Color',
+ },
+ ],
+ },
+};
+
+export default manifest;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/container.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/container.js
new file mode 100644
index 0000000000..d3d95eef81
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/container.js
@@ -0,0 +1,5 @@
+
+import Root from '../../../es/basic/Root/index.js';
+import manifest from './manifest.js';
+
+export default { origin: Root, manifest };
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/index.js
new file mode 100644
index 0000000000..86cc89915a
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/index.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+class Root extends React.Component {
+ static propTypes = {
+ style: PropTypes.object,
+ children: PropTypes.oneOfType([
+ PropTypes.element,
+ PropTypes.arrayOf(PropTypes.element),
+ ]),
+ };
+
+ static defaultProps = {
+ style: {
+ padding: 0,
+ backgroundColor: '#f0f2f5',
+ minHeight: '100%',
+ },
+ children: null,
+ };
+
+ render() {
+ const { style, children } = this.props;
+ const newStyle = Object.assign({}, Root.defaultProps.style, style);
+ return {children}
;
+ }
+}
+
+export default Root;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.js
new file mode 100644
index 0000000000..2ec2d9e3ed
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.js
@@ -0,0 +1 @@
+{"componentName":"Root","title":"","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"Root","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"style","propType":"object","description":"","defaultValue":"{\n padding: 0,\n backgroundColor: '#f0f2f5',\n minHeight: '100%'\n}"},{"name":"children","propType":"oneOfType","description":""}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.json b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.json
new file mode 100644
index 0000000000..13da88146c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/Root/manifest.json
@@ -0,0 +1 @@
+{"title":"multiple-exported-component","docUrl":"","screenshot":"","npm":{"package":"multiple-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/style/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/style/index.js
new file mode 100644
index 0000000000..d74e52ee9f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/style/index.js
@@ -0,0 +1 @@
+import './index.less';
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/style/index.less b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/style/index.less
new file mode 100644
index 0000000000..dc3680eb4f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/style/index.less
@@ -0,0 +1,8 @@
+// Alignment
+.text-left { text-align: left; }
+.text-right { text-align: right; }
+.text-center { text-align: center; }
+.text-justify { text-align: justify; }
+.text-nowrap { white-space: nowrap; }
+
+// BoxModel
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCBackgroundProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCBackgroundProps.js
new file mode 100644
index 0000000000..012ade534b
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCBackgroundProps.js
@@ -0,0 +1,44 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+/**
+ * (HOC)注入背景相关属性配置
+ * 包含 'backgroundColor'
+ * @param {*} WrappedComponent
+ */
+const HOCBackgroundProps = (WrappedComponent) => {
+ const PROPS = {
+ backgroundColor: 'backgroundColor',
+ };
+ return class extends Component {
+ static propTypes = {
+ backgroundColor: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ };
+
+ static defaultProps = {
+ backgroundColor: false,
+ };
+
+ parseStyle = (args) => {
+ const style = {};
+ Object.keys(PROPS).forEach((item) => {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = args[item];
+ });
+ return style;
+ };
+
+ render() {
+ const { backgroundColor, ...otherProps } = this.props;
+ return (
+
+ );
+ }
+ };
+};
+
+export default HOCBackgroundProps;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCBoxModelProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCBoxModelProps.js
new file mode 100644
index 0000000000..9e879b652f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCBoxModelProps.js
@@ -0,0 +1,75 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+const parseJoin = value => value.join(' ');
+
+/**
+ * (HOC)注入盒子模型相关属性配置
+ * 包含 'display', 'margin', 'border', 'padding', 'width', 'height', 'borderRadius'
+ * @param {*} WrappedComponent
+ */
+const HOCBoxModelProps = (WrappedComponent) => {
+ const PROPS = {
+ display: 'display',
+ margin: 'margin',
+ border: 'border',
+ padding: 'padding',
+ width: 'width',
+ height: 'height',
+ borderRadius: 'borderRadius',
+ };
+ return class extends Component {
+ static propTypes = {
+ display: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ margin: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
+ border: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
+ padding: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
+ width: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ height: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ borderRadius: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ };
+
+ static defaultProps = {
+ display: false,
+ margin: false,
+ border: false,
+ padding: false,
+ width: false,
+ height: false,
+ borderRadius: false,
+ };
+
+ parseStyle = (args) => {
+ const style = {};
+ Object.keys(PROPS).forEach((item) => {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = Array.isArray(args[item])
+ ? parseJoin(args[item])
+ : args[item];
+ });
+ return style;
+ };
+
+ render() {
+ const {
+ display,
+ margin,
+ border,
+ padding,
+ width,
+ height,
+ borderRadius,
+ ...otherProps
+ } = this.props;
+ return (
+
+ );
+ }
+ };
+};
+
+export default HOCBoxModelProps;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCFlexLayoutProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCFlexLayoutProps.js
new file mode 100644
index 0000000000..eb1e1b31a8
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCFlexLayoutProps.js
@@ -0,0 +1,61 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+/**
+ * (HOC)注入flex布局相关属性配置
+ * 包含 'alignItems', 'justifyContent', 'flexDirection'
+ * @param {*} WrappedComponent
+ */
+const HOCFlexLayoutProps = (WrappedComponent) => {
+ const PROPS = {
+ alignItems: 'alignItems',
+ justifyContent: 'justifyContent',
+ flexDirection: 'flexDirection',
+ flexWrap: 'flexWrap',
+ };
+ return class extends Component {
+ static propTypes = {
+ alignItems: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ justifyContent: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ flexDirection: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ flexWrap: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ };
+
+ static defaultProps = {
+ alignItems: false,
+ justifyContent: false,
+ flexDirection: false,
+ flexWrap: false,
+ };
+
+ parseStyle = (args) => {
+ const style = {};
+ if (args.style && args.style.display === 'flex') {
+ Object.keys(PROPS).forEach((item) => {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = args[item];
+ });
+ }
+ return style;
+ };
+
+ render() {
+ const {
+ alignItems,
+ justifyContent,
+ flexDirection,
+ flexWrap,
+ ...otherProps
+ } = this.props;
+ return (
+
+ );
+ }
+ };
+};
+
+export default HOCFlexLayoutProps;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCLayoutProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCLayoutProps.js
new file mode 100644
index 0000000000..b16a8c1628
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCLayoutProps.js
@@ -0,0 +1,52 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+/**
+ * (HOC)注入布局相关属性配置
+ * 包含 'align', 'lineHeight', 'verticalAlign'
+ * @param {*} WrappedComponent
+ */
+const HOCLayoutProps = (WrappedComponent) => {
+ const PROPS = {
+ align: 'textAlign',
+ lineHeight: 'lineHeight',
+ verticalAlign: 'verticalAlign',
+ };
+ return class extends Component {
+ static propTypes = {
+ align: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ lineHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ verticalAlign: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ };
+
+ static defaultProps = {
+ align: false,
+ lineHeight: false,
+ verticalAlign: false,
+ };
+
+ parseStyle = (args) => {
+ const style = {};
+ Object.keys(PROPS).forEach((item) => {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = args[item];
+ });
+ return style;
+ };
+
+ render() {
+ const {
+ align, lineHeight, verticalAlign, ...otherProps
+ } = this.props;
+ return (
+
+ );
+ }
+ };
+};
+
+export default HOCLayoutProps;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCTextProps.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCTextProps.js
new file mode 100644
index 0000000000..c34b18d375
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/basic/utils/HOCTextProps.js
@@ -0,0 +1,52 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+/**
+ * (HOC)注入文本相关属性配置
+ * 包含 'fontSize', 'fontWeight', 'color'
+ * @param {*} WrappedComponent
+ */
+const HOCTextProps = (WrappedComponent) => {
+ const PROPS = {
+ fontSize: 'fontSize',
+ fontWeight: 'fontWeight',
+ color: 'color',
+ };
+ return class extends Component {
+ static propTypes = {
+ fontSize: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ fontWeight: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ color: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ };
+
+ static defaultProps = {
+ fontSize: false,
+ fontWeight: false,
+ color: false,
+ };
+
+ parseStyle = (args) => {
+ const style = {};
+ Object.keys(PROPS).forEach((item) => {
+ // if props isn't false
+ if (!args[item]) return;
+ style[PROPS[item]] = args[item];
+ });
+ return style;
+ };
+
+ render() {
+ const {
+ fontSize, fontWeight, color, ...otherProps
+ } = this.props;
+ return (
+
+ );
+ }
+ };
+};
+
+export default HOCTextProps;
diff --git a/modules/material-parser/test/fixtures/multiple-exported-component/src/index.js b/modules/material-parser/test/fixtures/multiple-exported-component/src/index.js
new file mode 100644
index 0000000000..9ae1753f60
--- /dev/null
+++ b/modules/material-parser/test/fixtures/multiple-exported-component/src/index.js
@@ -0,0 +1,17 @@
+import AIMakeBlank from './basic/AIMakeBlank';
+import AIMakeIcon from './basic/AIMakeIcon';
+import AIMakeImage from './basic/AIMakeImage';
+import AIMakeLink from './basic/AIMakeLink';
+import AIMakePlaceholder from './basic/AIMakePlaceholder';
+import AIMakeText from './basic/AIMakeText';
+import Root from './basic/Root';
+
+export {
+ AIMakeBlank,
+ AIMakeIcon,
+ AIMakeImage,
+ AIMakeLink,
+ AIMakePlaceholder,
+ AIMakeText,
+ Root,
+};
diff --git a/modules/material-parser/test/fixtures/rax-component/package.json b/modules/material-parser/test/fixtures/rax-component/package.json
new file mode 100644
index 0000000000..30fd28d511
--- /dev/null
+++ b/modules/material-parser/test/fixtures/rax-component/package.json
@@ -0,0 +1,65 @@
+{
+ "name": "@ali/chaoshi-meta-example",
+ "version": "1.0.0",
+ "description": "intro component",
+ "main": "lib/index.js",
+ "module": "es/index.js",
+ "miniappConfig": {
+ "main": "lib/miniapp/index",
+ "main:wechat": "lib/wechat-miniprogram/index"
+ },
+ "files": [
+ "build",
+ "dist",
+ "es",
+ "lib",
+ "material-meta.json"
+ ],
+ "keywords": [
+ "Rax",
+ "rax-component"
+ ],
+ "engines": {
+ "npm": ">=3.0.0"
+ },
+ "scripts": {
+ "start": "build-scripts start",
+ "build": "build-scripts build",
+ "eslint": "eslint --ext .js,.jsx,.ts,.tsx ./",
+ "eslint:fix": "npm run eslint -- --fix",
+ "stylelint": "stylelint \"**/*.{css,scss,less}\"",
+ "lint": "npm run eslint && npm run stylelint",
+ "prepublishOnly": "npm run build"
+ },
+ "dependencies": {
+ "@ali/pcom-chaoshi-meta-design": "^1.1.5",
+ "rax-text": "^2.0.0",
+ "rax-view": "^2.0.0"
+ },
+ "peerDependencies": {
+ "rax": "^1.1.0"
+ },
+ "devDependencies": {
+ "@alib/build-scripts": "^0.1.0",
+ "@alife/build-plugin-lowcode": "^1.0.17",
+ "@iceworks/spec": "^1.0.0",
+ "@types/rax": "^1.0.0",
+ "build-plugin-component": "^1.0.0",
+ "driver-universal": "^3.1.0",
+ "eslint": "^6.8.0",
+ "rax": "^1.1.0",
+ "rax-test-renderer": "^1.0.0",
+ "stylelint": "^13.7.2",
+ "typescript": "^3.7.3"
+ },
+ "componentConfig": {
+ "name": "ChaoshiMetaExample",
+ "title": "ChaoshiMetaExample",
+ "category": "Information"
+ },
+ "publishConfig": {
+ "registry": "https://registry.npm.alibaba-inc.com"
+ },
+ "license": "MIT",
+ "homepage": "https://unpkg.alibaba-inc.com/@ali/chaoshi-meta-example@1.0.0/build/index.html"
+}
diff --git a/modules/material-parser/test/fixtures/rax-component/src/index.css b/modules/material-parser/test/fixtures/rax-component/src/index.css
new file mode 100644
index 0000000000..41a09e7fe0
--- /dev/null
+++ b/modules/material-parser/test/fixtures/rax-component/src/index.css
@@ -0,0 +1,5 @@
+.rax-demo-title {
+ font-size: 45rpx;
+ font-weight: bold;
+ margin: 20rpx 0;
+}
diff --git a/modules/material-parser/test/fixtures/rax-component/src/index.tsx b/modules/material-parser/test/fixtures/rax-component/src/index.tsx
new file mode 100644
index 0000000000..bb498cd70e
--- /dev/null
+++ b/modules/material-parser/test/fixtures/rax-component/src/index.tsx
@@ -0,0 +1,22 @@
+import { createElement, forwardRef } from 'rax';
+import { Price as _Price, Title as _Title } from '@ali/pcom-chaoshi-meta-design';
+import View from 'rax-view';
+import Text from 'rax-text';
+import './index.css';
+
+interface Props {
+ a: string;
+}
+
+const MyComponent = forwardRef((props: Props, ref: any) => {
+ return (
+
+ Hello World!
+
+ );
+});
+
+export default MyComponent;
+
+export const Price = _Price;
+export const Title = _Title;
diff --git a/modules/material-parser/test/fixtures/single-exported-component/es/container.js b/modules/material-parser/test/fixtures/single-exported-component/es/container.js
new file mode 100644
index 0000000000..3ab0a3fb66
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/es/container.js
@@ -0,0 +1,6 @@
+
+ import Demo from './index.js';
+ import manifest from './manifest.js';
+
+ export default { origin: Demo, manifest };
+
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/single-exported-component/es/index.js b/modules/material-parser/test/fixtures/single-exported-component/es/index.js
new file mode 100644
index 0000000000..c5b8d35bcb
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/es/index.js
@@ -0,0 +1,97 @@
+import _classCallCheck from '@babel/runtime/helpers/classCallCheck';
+import _createClass from '@babel/runtime/helpers/createClass';
+import _possibleConstructorReturn from '@babel/runtime/helpers/possibleConstructorReturn';
+import _getPrototypeOf from '@babel/runtime/helpers/getPrototypeOf';
+import _inherits from '@babel/runtime/helpers/inherits';
+
+/* eslint-disable react/no-unused-prop-types */
+
+/* eslint-disable react/require-default-props */
+import React from 'react';
+import PropTypes from 'prop-types';
+import './main.css';
+
+const Demo =
+ /* #__PURE__ */
+ (function(_React$Component) {
+ _inherits(Demo, _React$Component);
+
+ function Demo() {
+ _classCallCheck(this, Demo);
+
+ return _possibleConstructorReturn(this, _getPrototypeOf(Demo).apply(this, arguments));
+ }
+
+ _createClass(Demo, [
+ {
+ key: 'render',
+ value: function render() {
+ return React.createElement('div', null, ' Test ');
+ },
+ },
+ ]);
+
+ return Demo;
+ })(React.Component);
+
+Demo.propTypes = {
+ optionalArray: PropTypes.array,
+ optionalBool: PropTypes.bool,
+ /**
+ * desc
+ * @param {string} title - The title of the book.
+ * @param {string} author - The author of the book.
+ * @returns {any}
+ */
+ optionalFunc: PropTypes.func,
+ optionalNumber: PropTypes.number,
+ optionalObject: PropTypes.object,
+ optionalString: PropTypes.string,
+ optionalSymbol: PropTypes.symbol,
+ // Anything that can be rendered: numbers, strings, elements or an array
+ // (or fragment) containing these types.
+ optionalNode: PropTypes.node,
+ // A React element (ie. ).
+ optionalElement: PropTypes.element,
+ // A React element type (ie. MyComponent).
+ optionalElementType: PropTypes.elementType,
+ // You can also declare that a prop is an instance of a class. This uses
+ // JS's instanceof operator.
+ optionalMessage: PropTypes.instanceOf(Demo),
+ // You can ensure that your prop is limited to specific values by treating
+ // it as an enum.
+ optionalEnum: PropTypes.oneOf(['News', 'Photos']),
+ // An object that could be one of many types
+ optionalUnion: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number,
+ PropTypes.instanceOf(Demo),
+ ]),
+ // An array of a certain type
+ optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
+ // An object with property values of a certain type
+ optionalObjectOf: PropTypes.objectOf(PropTypes.number),
+ // You can chain any of the above with `isRequired` to make sure a warning
+ // is shown if the prop isn't provided.
+ // An object taking on a particular shape
+ optionalObjectWithShape: PropTypes.shape({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }),
+ optionalObjectWithShape2: PropTypes.shape({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }).isRequired,
+ // An object with warnings on extra properties
+ optionalObjectWithStrictShape: PropTypes.exact({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }),
+ requiredFunc: PropTypes.func.isRequired,
+ // A value of any data type
+ requiredAny: PropTypes.any.isRequired,
+};
+Demo.defaultProps = {
+ optionalNumber: 123,
+};
+export default Demo;
diff --git a/modules/material-parser/test/fixtures/single-exported-component/es/main.css b/modules/material-parser/test/fixtures/single-exported-component/es/main.css
new file mode 100644
index 0000000000..620f1985f0
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/es/main.css
@@ -0,0 +1,6 @@
+@charset "UTF-8";
+/* 不引入依赖组件的样式,比如组件 import { Button } from '@alife/next'; */
+/* 不需要在main.scss中引入 @import '~@alife/next/lib/button/index.scss'; */
+/* 但是在lib/index.scss中需要引入 @import '~@alife/next/lib/button/index.scss'; */
+/* 如果需要引入主题变量引入此段 */
+/* 组件自身样式 */
diff --git a/modules/material-parser/test/fixtures/single-exported-component/es/main.scss b/modules/material-parser/test/fixtures/single-exported-component/es/main.scss
new file mode 100644
index 0000000000..ac45616a50
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/es/main.scss
@@ -0,0 +1,11 @@
+/* 不引入依赖组件的样式,比如组件 import { Button } from '@alife/next'; */
+/* 不需要在main.scss中引入 @import '~@alife/next/lib/button/index.scss'; */
+/* 但是在lib/index.scss中需要引入 @import '~@alife/next/lib/button/index.scss'; */
+
+/* 如果需要引入主题变量引入此段 */
+// @import '~@alife/next/variables.scss';
+
+/* 组件自身样式 */
+// .custom-component {
+// color: $color-brand1-1;
+// }
diff --git a/modules/material-parser/test/fixtures/single-exported-component/es/manifest.js b/modules/material-parser/test/fixtures/single-exported-component/es/manifest.js
new file mode 100644
index 0000000000..98cfde9b07
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/es/manifest.js
@@ -0,0 +1 @@
+{"componentName":"Demo","title":"","docUrl":"","screenshot":"","npm":{"package":"single-exported-component","version":"1.0.0","exportName":"Demo","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/index.js","destructuring":false,"subName":""},"props":[{"name":"optionalArray","propType":"array","description":""},{"name":"optionalBool","propType":"bool","description":""},{"name":"optionalFunc","propType":"func","description":""},{"name":"optionalNumber","propType":"number","description":""},{"name":"optionalObject","propType":"object","description":""},{"name":"optionalString","propType":"string","description":""},{"name":"optionalSymbol","propType":"symbol","description":""},{"name":"optionalNode","propType":"node","description":""},{"name":"optionalElement","propType":"element","description":""},{"name":"optionalElementType","propType":"elementType","description":""},{"name":"optionalMessage","propType":"instanceOf","description":""},{"name":"optionalEnum","propType":"oneOf","description":""},{"name":"optionalUnion","propType":"oneOfType","description":""},{"name":"optionalArrayOf","propType":"arrayOf","description":""},{"name":"optionalObjectOf","propType":"objectOf","description":""},{"name":"optionalObjectWithShape","propType":"shape","description":""},{"name":"optionalObjectWithShape2","propType":"shape","description":""},{"name":"optionalObjectWithStrictShape","propType":"exact","description":""},{"name":"requiredFunc","propType":"func","description":""},{"name":"requiredAny","propType":"any","description":""}]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/single-exported-component/es/manifest.json b/modules/material-parser/test/fixtures/single-exported-component/es/manifest.json
new file mode 100644
index 0000000000..32d6f59ddc
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/es/manifest.json
@@ -0,0 +1 @@
+{"title":"single-exported-component","docUrl":"","screenshot":"","npm":{"package":"single-exported-component","version":"1.0.0","exportName":"","main":"/Users/gengyang/code/frontend/low-code/ali-lowcode-engine/packages/material-parser/test/fixtures/single-exported-component/es/index.js","destructuring":false,"subName":""},"props":[]}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/single-exported-component/package.json b/modules/material-parser/test/fixtures/single-exported-component/package.json
new file mode 100644
index 0000000000..d1c283cd3a
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "single-exported-component",
+ "description": "",
+ "version": "1.0.0",
+ "main": "src/index.js",
+ "module": "es/index.js",
+ "files": [
+ "demo/",
+ "lib/",
+ "es/",
+ "build/"
+ ],
+ "scripts": {
+ "postversion": "node ./scripts/postversion.js"
+ },
+ "dependencies": {
+ "prop-types": "^15.7.2",
+ "react": "^16.8.5",
+ "react-dom": "^16.8.5"
+ },
+ "devDependencies": {
+ "cross-spawn": "^6.0.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.6"
+ },
+ "publishConfig": {
+ "registry": "https://registry.npm.alibaba-inc.com"
+ }
+}
diff --git a/modules/material-parser/test/fixtures/single-exported-component/src/index.js b/modules/material-parser/test/fixtures/single-exported-component/src/index.js
new file mode 100644
index 0000000000..e075c0fd16
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/src/index.js
@@ -0,0 +1,90 @@
+/* eslint-disable react/no-unused-prop-types */
+/* eslint-disable react/require-default-props */
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import './main.scss';
+
+const a = 1, Demo = (props) => {
+ return Test
;
+}
+
+Demo.staticMethod = () => {
+ console.log('static method');
+}
+
+Demo.propTypes = {
+ optionalArray: PropTypes.array,
+ optionalBool: PropTypes.bool,
+ /**
+ * desc
+ * @param {string} title - The title of the book.
+ * @param {string} author - The author of the book.
+ * @returns {any}
+ */
+ optionalFunc: PropTypes.func,
+ optionalNumber: PropTypes.number,
+ optionalObject: PropTypes.object,
+ optionalString: PropTypes.string,
+ optionalSymbol: PropTypes.symbol,
+
+ // Anything that can be rendered: numbers, strings, elements or an array
+ // (or fragment) containing these types.
+ optionalNode: PropTypes.node,
+
+ // A React element (ie. ).
+ optionalElement: PropTypes.element,
+
+ // A React element type (ie. MyComponent).
+ optionalElementType: PropTypes.elementType,
+
+ // You can also declare that a prop is an instance of a class. This uses
+ // JS's instanceof operator.
+ optionalMessage: PropTypes.instanceOf(Demo),
+
+ // You can ensure that your prop is limited to specific values by treating
+ // it as an enum.
+ optionalEnum: PropTypes.oneOf(['News', 'Photos']),
+
+ // An object that could be one of many types
+ optionalUnion: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number,
+ PropTypes.instanceOf(Demo),
+ ]),
+
+ // An array of a certain type
+ optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
+
+ // An object with property values of a certain type
+ optionalObjectOf: PropTypes.objectOf(PropTypes.number),
+
+ // You can chain any of the above with `isRequired` to make sure a warning
+ // is shown if the prop isn't provided.
+
+ // An object taking on a particular shape
+ optionalObjectWithShape: PropTypes.shape({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }),
+
+ optionalObjectWithShape2: PropTypes.shape({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }).isRequired,
+
+ // An object with warnings on extra properties
+ optionalObjectWithStrictShape: PropTypes.exact({
+ optionalProperty: PropTypes.string,
+ requiredProperty: PropTypes.number.isRequired,
+ }),
+
+ requiredFunc: PropTypes.func.isRequired,
+
+ // A value of any data type
+ requiredAny: PropTypes.any.isRequired,
+};
+
+Demo.defaultProps = {};
+
+export default Demo;
diff --git a/modules/material-parser/test/fixtures/single-exported-component/src/main.scss b/modules/material-parser/test/fixtures/single-exported-component/src/main.scss
new file mode 100644
index 0000000000..ac45616a50
--- /dev/null
+++ b/modules/material-parser/test/fixtures/single-exported-component/src/main.scss
@@ -0,0 +1,11 @@
+/* 不引入依赖组件的样式,比如组件 import { Button } from '@alife/next'; */
+/* 不需要在main.scss中引入 @import '~@alife/next/lib/button/index.scss'; */
+/* 但是在lib/index.scss中需要引入 @import '~@alife/next/lib/button/index.scss'; */
+
+/* 如果需要引入主题变量引入此段 */
+// @import '~@alife/next/variables.scss';
+
+/* 组件自身样式 */
+// .custom-component {
+// color: $color-brand1-1;
+// }
diff --git a/modules/material-parser/test/fixtures/transpiled-component/package.json b/modules/material-parser/test/fixtures/transpiled-component/package.json
new file mode 100644
index 0000000000..f718be664f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/transpiled-component/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "transpiled-component",
+ "version": "1.0.0",
+ "main": "lib/index.js",
+ "dependencies": {
+ "react": "^16.0.0"
+ }
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/ts-component/package.json b/modules/material-parser/test/fixtures/ts-component/package.json
new file mode 100644
index 0000000000..dd2cf3c826
--- /dev/null
+++ b/modules/material-parser/test/fixtures/ts-component/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "ts-component",
+ "description": "",
+ "version": "1.0.0",
+ "module": "src/index.tsx",
+ "main": "src/index.tsx",
+ "files": [
+ "demo/",
+ "lib/",
+ "es/",
+ "build/"
+ ],
+ "scripts": {
+ "postversion": "node ./scripts/postversion.js"
+ },
+ "dependencies": {
+ "prop-types": "^15.7.2",
+ "react": "^16.8.5",
+ "react-dom": "^16.8.5"
+ },
+ "devDependencies": {
+ "@types/cross-spawn": "^6.0.2",
+ "@types/prop-types": "^15.7.3",
+ "@types/react": "^16.9.46",
+ "@types/react-dom": "^16.9.8",
+ "cross-spawn": "^6.0.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.6"
+ },
+ "publishConfig": {
+ "registry": "https://registry.npm.alibaba-inc.com"
+ }
+}
diff --git a/modules/material-parser/test/fixtures/ts-component/src/index.tsx b/modules/material-parser/test/fixtures/ts-component/src/index.tsx
new file mode 100644
index 0000000000..71540c1f87
--- /dev/null
+++ b/modules/material-parser/test/fixtures/ts-component/src/index.tsx
@@ -0,0 +1,9 @@
+import App from './main-module';
+import SubModule from './sub-module';
+
+App.SubModule = SubModule;
+App.defaultProps = {
+ str: 'str2',
+};
+
+export default App;
diff --git a/modules/material-parser/test/fixtures/ts-component/src/main-module.tsx b/modules/material-parser/test/fixtures/ts-component/src/main-module.tsx
new file mode 100644
index 0000000000..48ea734b90
--- /dev/null
+++ b/modules/material-parser/test/fixtures/ts-component/src/main-module.tsx
@@ -0,0 +1,104 @@
+/* eslint-disable @typescript-eslint/ban-types */
+/* eslint-disable @typescript-eslint/indent */
+/* eslint-disable @typescript-eslint/no-unused-vars */
+/* eslint-disable @typescript-eslint/member-ordering */
+import * as React from 'react';
+import SubModule from './sub-module';
+
+enum Gender {
+ MALE,
+ FEMALE,
+}
+
+interface Obj {
+ s: string;
+ n: number;
+}
+
+type Func = (a: string) => JSX.Element;
+type Union =
+ | string
+ | number
+ | {
+ a: string;
+ };
+
+interface Props {
+ error(a: string): number;
+ void: void;
+ object: Object;
+ trigger?: Array<'click' | 'hover' | 'contextMenu'>;
+ str?: string;
+ num: number;
+ gender: Gender;
+ any: any;
+ bool: boolean;
+ tuple: [number, string, true];
+ enum: 'red' | 'yellow' | 'green';
+ arr: number[];
+ halfEmptyObj: {
+ [k: string]: any;
+ fun(a: string[]): void;
+ };
+ // eslint-disable-next-line @typescript-eslint/ban-types
+ emptyObj: {};
+ func(arg: string): number;
+ funcs: {
+ n(): number;
+ a(arg: string, num: number): void;
+ };
+ fuzzy:
+ | boolean
+ | 'object'
+ | number
+ | 'number'
+ | 'test'
+ | {
+ a: any;
+ sa: string[];
+ };
+ oneOf: boolean | 'test' | Obj;
+ refFunc(p: Props): void;
+ elementOrOther: JSX.Element | Func;
+ obj: {
+ a: number;
+ arrOfStr: string[];
+ arrOfObj: Obj[];
+ func: () => void;
+ };
+ objOf: {
+ [k: string]: number;
+ };
+ exact: {
+ a: number;
+ };
+ node?: React.ReactNode;
+ element?: JSX.Element;
+ elementType?: React.ElementType;
+ union: Union;
+ // eslint-disable-next-line @typescript-eslint/adjacent-overload-signatures
+ func2: Func;
+ html: HTMLBaseElement;
+ loading?: boolean | { delay?: number };
+}
+
+interface AppProps extends React.FC {
+ SubModule?: typeof SubModule;
+}
+
+const App: AppProps = React.forwardRef((props, ref: React.Ref) => {
+ return {props.str}
;
+});
+
+App.defaultProps = {
+ object: {
+ a: '1',
+ b: '2',
+ },
+ func(a: string) {
+ return 123;
+ },
+ str: 'str',
+};
+
+export default App;
diff --git a/modules/material-parser/test/fixtures/ts-component/src/sub-module.tsx b/modules/material-parser/test/fixtures/ts-component/src/sub-module.tsx
new file mode 100644
index 0000000000..acea70b08f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/ts-component/src/sub-module.tsx
@@ -0,0 +1,22 @@
+import * as React from 'react';
+
+interface Props {
+ name: string;
+}
+
+class SubModule extends React.Component {
+ static defaultProps = {
+ name: 'abc',
+ };
+
+ render() {
+ const { name } = this.props;
+ return hello, {name}
;
+ }
+}
+
+SubModule.defaultProps = {
+ name: 'abc',
+};
+
+export default SubModule;
diff --git a/modules/material-parser/test/fixtures/ts-component2/package.json b/modules/material-parser/test/fixtures/ts-component2/package.json
new file mode 100644
index 0000000000..95bb4bd8d8
--- /dev/null
+++ b/modules/material-parser/test/fixtures/ts-component2/package.json
@@ -0,0 +1,63 @@
+{
+ "name": "@alife/empty",
+ "version": "1.0.1",
+ "description": "空组件",
+ "files": [
+ "demo/",
+ "es/",
+ "lib/",
+ "build/",
+ "dist",
+ "material-meta.json"
+ ],
+ "main": "src/index.tsx",
+ "module": "src/index.tsx",
+ "stylePath": "style.js",
+ "scripts": {
+ "start": "build-scripts start",
+ "build": "build-scripts build",
+ "test": "build-scripts test",
+ "prepublishOnly": "npm run build",
+ "doc": "react-doc-gen",
+ "lint": "eslint --cache --ext .js,.jsx ./"
+ },
+ "keywords": [
+ "ice",
+ "react",
+ "component"
+ ],
+ "dependencies": {
+ "classnames": "^2.2.6",
+ "prop-types": "^15.5.8"
+ },
+ "devDependencies": {
+ "@alife/build-plugin-lowcode": "^1.0.7",
+ "@alib/build-scripts": "^0.1.3",
+ "@alifd/adaptor-generate": "^0.1.3",
+ "build-plugin-component": "^0.2.0",
+ "build-plugin-fusion": "^0.1.0",
+ "build-plugin-fusion-cool": "^0.1.0",
+ "build-plugin-moment-locales": "^0.1.0",
+ "react": "^16.3.0",
+ "react-dom": "^16.3.0",
+ "@ice/spec": "^1.0.0",
+ "eslint": "^6.0.1",
+ "@alifd/next": "1.x",
+ "@types/react": "^16.9.13",
+ "@types/react-dom": "^16.9.4"
+ },
+ "peerDependencies": {
+ "react": "^16.3.0",
+ "@alifd/next": "1.x"
+ },
+ "componentConfig": {
+ "name": "Empty",
+ "title": "empty",
+ "category": "DataDisplay"
+ },
+ "publishConfig": {
+ "registry": "https://registry.npm.alibaba-inc.com"
+ },
+ "license": "MIT",
+ "homepage": "https://unpkg.alibaba-inc.com/@alife/empty@1.0.1/build/index.html"
+}
diff --git a/modules/material-parser/test/fixtures/ts-component2/src/empty.tsx b/modules/material-parser/test/fixtures/ts-component2/src/empty.tsx
new file mode 100644
index 0000000000..f355d8e95c
--- /dev/null
+++ b/modules/material-parser/test/fixtures/ts-component2/src/empty.tsx
@@ -0,0 +1,22 @@
+import * as React from 'react';
+import classNames from 'classnames';
+import './index';
+interface DefaultEmptyImg {
+ className?: string;
+ imageStyle?: React.CSSProperties;
+}
+
+export const DefaultEmptyImg = (props: DefaultEmptyImg) => {
+ const { className, imageStyle, ...restProps } = props;
+ const prefixCls = 'design-empty-default';
+ const alt = 'empty';
+
+ return (
+
+
+

+
+
暂时没有数据
+
+ );
+};
diff --git a/modules/material-parser/test/fixtures/ts-component2/src/index.scss b/modules/material-parser/test/fixtures/ts-component2/src/index.scss
new file mode 100644
index 0000000000..e833d2c729
--- /dev/null
+++ b/modules/material-parser/test/fixtures/ts-component2/src/index.scss
@@ -0,0 +1,49 @@
+.design-empty {
+ margin: 0 8px;
+ font-size: 14px;
+ line-height: 1.5715;
+ text-align: center;
+
+ &-image {
+ height: 200px;
+ margin-bottom: 4px;
+
+ img {
+ height: 100%;
+ }
+
+ svg {
+ height: 100%;
+ margin: auto;
+ }
+ }
+
+ &-description {
+ margin: 0;
+ }
+
+ &-footer {
+ margin-top: 16px;
+ }
+}
+
+.design-empty-default {
+ margin: 0 8px;
+ font-size: 14px;
+ line-height: 1.5715;
+ text-align: center;
+
+ &-image {
+ height: 54px;
+ margin-bottom: 8px;
+
+ img {
+ height: 100%;
+ }
+ }
+
+ &-description {
+ font-size: 14px;
+ color: #c2c2c2;
+ }
+}
diff --git a/modules/material-parser/test/fixtures/ts-component2/src/index.tsx b/modules/material-parser/test/fixtures/ts-component2/src/index.tsx
new file mode 100644
index 0000000000..64cf75b100
--- /dev/null
+++ b/modules/material-parser/test/fixtures/ts-component2/src/index.tsx
@@ -0,0 +1,71 @@
+import * as React from 'react';
+import classNames from 'classnames';
+import { DefaultEmptyImg } from './empty';
+
+export interface EmptyProps extends React.HTMLAttributes {
+ className?: string;
+ style?: React.CSSProperties;
+ imageStyle?: React.CSSProperties;
+ image?: React.ReactNode | string;
+ description?: React.ReactNode;
+ children?: React.ReactNode;
+ type?: 'default' | 'custom'; // default 默认, custom 表示自定义
+}
+
+const prefixCls = 'design-empty';
+interface EmptyType extends React.FC {
+ IMAGE_TYPE_SERVERBUSY: string; //服务器繁忙
+ IMAGE_TYPE_SERVERNOFOUND: string; // 404
+ IMAGE_TYPE_FILENOFOUND: string; //文件不存在
+ IMAGE_TYPE_PROJECTNOFOUND: string; // 项目不存在
+ IMAGE_TYPE_EMPTY: string; //空
+}
+
+const Empty: EmptyType = (props: EmptyProps) => {
+ const {
+ className,
+ image = 'Empty.IMAGE_TYPE_EMPTY',
+ description,
+ children,
+ imageStyle,
+ type = 'custom',
+ ...restProps
+ } = props;
+
+ if (type === 'default') {
+ return ;
+ }
+
+ let imageNode: React.ReactNode = null;
+ const alt = typeof description === 'string' ? description : 'empty';
+
+ if (typeof image === 'string') {
+ imageNode =
;
+ } else {
+ imageNode = image;
+ }
+
+ return (
+
+
+ {imageNode}
+
+ {description &&
{description}
}
+ {children &&
{children}
}
+
+ );
+};
+
+//服务器繁忙
+Empty.IMAGE_TYPE_SERVERBUSY = 'https://img.alicdn.com/tfs/TB1qPJvTFY7gK0jSZKzXXaikpXa-400-400.png';
+//404
+Empty.IMAGE_TYPE_SERVERNOFOUND =
+ 'https://img.alicdn.com/tfs/TB18gVGTUH1gK0jSZSyXXXtlpXa-400-400.png';
+//文件不存在
+Empty.IMAGE_TYPE_FILENOFOUND = 'https://img.alicdn.com/tfs/TB1.ClQTUT1gK0jSZFrXXcNCXXa-400-400.png';
+//项目不存在
+Empty.IMAGE_TYPE_PROJECTNOFOUND =
+ 'https://img.alicdn.com/tfs/TB1ZWumfcieb18jSZFvXXaI3FXa-400-400.png';
+//空
+Empty.IMAGE_TYPE_EMPTY = 'https://img.alicdn.com/tfs/TB13G0LTNv1gK0jSZFFXXb0sXXa-54-54.svg';
+export default Empty;
diff --git a/modules/material-parser/test/fixtures/without-display-name/index.js b/modules/material-parser/test/fixtures/without-display-name/index.js
new file mode 100644
index 0000000000..986775591f
--- /dev/null
+++ b/modules/material-parser/test/fixtures/without-display-name/index.js
@@ -0,0 +1,12 @@
+var React = require('react');
+var PropTypes = require('prop-types');
+
+module.exports = class extends React.Component {
+ static propTypes = {
+ name: PropTypes.string
+ }
+
+ render() {
+ return {this.props.name}
+ }
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/fixtures/without-display-name/package.json b/modules/material-parser/test/fixtures/without-display-name/package.json
new file mode 100644
index 0000000000..c02728ebe9
--- /dev/null
+++ b/modules/material-parser/test/fixtures/without-display-name/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "without-display-name",
+ "version": "1.0.0",
+ "main": "index.js",
+ "dependencies": {
+ "react": "^16.0.0",
+ "prop-types": "latest"
+ }
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/helpers/index.ts b/modules/material-parser/test/helpers/index.ts
new file mode 100644
index 0000000000..2b0c7e70b9
--- /dev/null
+++ b/modules/material-parser/test/helpers/index.ts
@@ -0,0 +1,10 @@
+import { join } from 'path';
+
+const baseDir = join(__dirname, '../fixtures');
+
+/**
+ * 从 fixtures 下获取文件完整路径
+ */
+export const getFromFixtures = (...args: string[]) => {
+ return join(baseDir, ...args);
+};
diff --git a/modules/material-parser/test/index.test.ts b/modules/material-parser/test/index.test.ts
new file mode 100644
index 0000000000..7f4c03a439
--- /dev/null
+++ b/modules/material-parser/test/index.test.ts
@@ -0,0 +1,110 @@
+import { join } from 'path';
+import parse from '../src';
+import { IMaterializeOptions } from '../src/types';
+import { getFromFixtures } from './helpers';
+
+const multiExportedComptPath = getFromFixtures('multiple-exported-component');
+const singleExportedComptPath = getFromFixtures('single-exported-component');
+const tsComponent = getFromFixtures('ts-component');
+const tsComponent2 = getFromFixtures('ts-component2');
+const dtsComponent = getFromFixtures('dts-component');
+const transpiledComponent = getFromFixtures('transpiled-component');
+const withoutDisplayName = getFromFixtures('without-display-name');
+
+test('materialize single exported component by local', async done => {
+ const options: IMaterializeOptions = {
+ entry: singleExportedComptPath,
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('materialize multiple exported component by local', async done => {
+ const options: IMaterializeOptions = {
+ entry: multiExportedComptPath,
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('ts component by local', async done => {
+ const options: IMaterializeOptions = {
+ entry: tsComponent,
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('ts component 2 by local', async done => {
+ const options: IMaterializeOptions = {
+ entry: tsComponent2,
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('rax component by local', async done => {
+ const options: IMaterializeOptions = {
+ entry: 'src/index.tsx',
+ root: getFromFixtures('rax-component'),
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('d.ts component by local', async done => {
+ const options: IMaterializeOptions = {
+ entry: join(dtsComponent, 'src/index.jsx'),
+ root: dtsComponent,
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('transpiled component by local', async done => {
+ const options: IMaterializeOptions = {
+ entry: transpiledComponent,
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('without display name by local', async done => {
+ const options: IMaterializeOptions = {
+ entry: withoutDisplayName,
+ accesser: 'local',
+ };
+
+ const actual = await parse(options);
+
+ expect(actual).toMatchSnapshot();
+ done();
+});
diff --git a/modules/material-parser/test/localize.test.ts b/modules/material-parser/test/localize.test.ts
new file mode 100644
index 0000000000..bd6ceb6346
--- /dev/null
+++ b/modules/material-parser/test/localize.test.ts
@@ -0,0 +1,6 @@
+import {getPkgNameAndVersion} from '../src/localize';
+
+test('getPkgNameAndVersion from string', () => {
+ const result = getPkgNameAndVersion('react');
+ expect(result).toEqual({"name": "react"});
+});
\ No newline at end of file
diff --git a/modules/material-parser/test/online.test.ts b/modules/material-parser/test/online.test.ts
new file mode 100644
index 0000000000..8a67f1975b
--- /dev/null
+++ b/modules/material-parser/test/online.test.ts
@@ -0,0 +1,53 @@
+import { remove } from 'fs-extra';
+import parse from '../src';
+import { IMaterializeOptions } from '../src/types';
+
+test('materialize react-color by online', async (done) => {
+ const options: IMaterializeOptions = {
+ entry: 'react-color@2.19.3',
+ accesser: 'online',
+ };
+
+ const actual = await parse(options);
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('materialize mc-hello by online', async (done) => {
+ const options: IMaterializeOptions = {
+ entry: 'mc-hello@1.0.1',
+ accesser: 'online',
+ };
+
+ const actual = await parse(options);
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('materialize rc-picker by online', async (done) => {
+ const options: IMaterializeOptions = {
+ entry: 'rc-picker@2.4.3',
+ accesser: 'online',
+ };
+
+ const actual = await parse(options);
+ expect(actual).toMatchSnapshot();
+ done();
+});
+
+test('materialize online rax module by path & specify workDir', async (done) => {
+ const tempDir = './test/temp';
+ const options: IMaterializeOptions = {
+ name: 'rax-view',
+ version: '2.2.1',
+ entry: './es/common/index.d.ts',
+ accesser: 'online',
+ dslType: 'rax',
+ tempDir,
+ };
+
+ const actual = await parse(options);
+ await remove(tempDir);
+ expect(actual).toMatchSnapshot();
+ done();
+});
diff --git a/modules/material-parser/test/validate/__snapshots__/index.test.ts.snap b/modules/material-parser/test/validate/__snapshots__/index.test.ts.snap
new file mode 100644
index 0000000000..00fbd81fe4
--- /dev/null
+++ b/modules/material-parser/test/validate/__snapshots__/index.test.ts.snap
@@ -0,0 +1,23 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should be right in dir basic-error 1`] = `
+"[
+ {
+ \\"keyword\\": \\"required\\",
+ \\"dataPath\\": \\"\\",
+ \\"schemaPath\\": \\"#/required\\",
+ \\"params\\": {
+ \\"missingProperty\\": \\"props\\"
+ },
+ \\"message\\": \\"should have required property 'props'\\"
+ }
+]"
+`;
+
+exports[`should be right in dir basic-success 1`] = `true`;
+
+exports[`should be right in dir configure 1`] = `true`;
+
+exports[`should be right in dir props-basic-type 1`] = `true`;
+
+exports[`should be right in dir props-complex-type 1`] = `true`;
diff --git a/modules/material-parser/test/validate/fixtures/basic-error/schema.json b/modules/material-parser/test/validate/fixtures/basic-error/schema.json
new file mode 100644
index 0000000000..d1c6f5d8d0
--- /dev/null
+++ b/modules/material-parser/test/validate/fixtures/basic-error/schema.json
@@ -0,0 +1,18 @@
+{
+ "componentName": "Select",
+ "title": "下拉选择器",
+ "description": "适用于下拉选择,下拉多选等场景",
+ "tags": ["xx", "yy"],
+ "docUrl": "https://fusion-demo.alibaba-inc.com/demos/next/select",
+ "screenshot": "https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png",
+ "icon": "url/fsdfasdfa.svg",
+ "devMode": "proCode",
+ "npm": {
+ "package": "@ali/deep",
+ "exportName": "Button",
+ "subName": "Icon.Option",
+ "main": "",
+ "destructuring": true,
+ "version": "0.1.13"
+ }
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/validate/fixtures/basic-success/schema.json b/modules/material-parser/test/validate/fixtures/basic-success/schema.json
new file mode 100644
index 0000000000..3b0f63b83b
--- /dev/null
+++ b/modules/material-parser/test/validate/fixtures/basic-success/schema.json
@@ -0,0 +1,19 @@
+{
+ "componentName": "Select",
+ "title": "下拉选择器",
+ "description": "适用于下拉选择,下拉多选等场景",
+ "tags": ["xx", "yy"],
+ "docUrl": "https://fusion-demo.alibaba-inc.com/demos/next/select",
+ "screenshot": "https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png",
+ "icon": "url/fsdfasdfa.svg",
+ "devMode": "proCode",
+ "npm": {
+ "package": "@ali/deep",
+ "exportName": "Button",
+ "subName": "Icon.Option",
+ "main": "",
+ "destructuring": true,
+ "version": "0.1.13"
+ },
+ "props": []
+}
diff --git a/modules/material-parser/test/validate/fixtures/configure/schema.json b/modules/material-parser/test/validate/fixtures/configure/schema.json
new file mode 100644
index 0000000000..0bdce16239
--- /dev/null
+++ b/modules/material-parser/test/validate/fixtures/configure/schema.json
@@ -0,0 +1,68 @@
+{
+ "componentName": "Select",
+ "title": "下拉选择器",
+ "description": "适用于下拉选择,下拉多选等场景",
+ "tags": ["xx", "yy"],
+ "docUrl": "https://fusion-demo.alibaba-inc.com/demos/next/select",
+ "screenshot": "https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png",
+ "icon": "url/fsdfasdfa.svg",
+ "devMode": "proCode",
+ "npm": {
+ "package": "@ali/deep",
+ "exportName": "Button",
+ "subName": "Icon.Option",
+ "main": "",
+ "destructuring": true,
+ "version": "0.1.13"
+ },
+ "props": [],
+ "configure": {
+ "props": [
+ {
+ "type": "field",
+ "title": "field",
+ "name": "field",
+ "setter": {
+ "componentName": "Mixin",
+ "props": {
+ "onlyChangeType": false,
+ "defaultType": "Input",
+ "typeMap": {
+ "Input": {},
+ "Select": {}
+ }
+ }
+ }
+ },
+ {
+ "type": "group",
+ "title": "group",
+ "items": [
+ {
+ "type": "field",
+ "componentName": "Function",
+ "props": {
+ "defaultValue": "function(){ console.log('aloha') }"
+ }
+ },
+ {
+ "type": "field",
+ "componentName": "Number",
+ "props": {
+ "value": 123
+ }
+ }
+ ]
+ }
+ ],
+ "component": {
+ "isContainer": true,
+ "isModal": false,
+ "descriptor": "title",
+ "nestingRule": {
+ "childWhitelist": ["SelectOption"],
+ "parentWhitelist": ["Select", "Table"]
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/validate/fixtures/props-basic-type/schema.json b/modules/material-parser/test/validate/fixtures/props-basic-type/schema.json
new file mode 100644
index 0000000000..e8fecb328d
--- /dev/null
+++ b/modules/material-parser/test/validate/fixtures/props-basic-type/schema.json
@@ -0,0 +1,71 @@
+{
+ "componentName": "Select",
+ "title": "下拉选择器",
+ "description": "适用于下拉选择,下拉多选等场景",
+ "tags": ["xx", "yy"],
+ "docUrl": "https://fusion-demo.alibaba-inc.com/demos/next/select",
+ "screenshot": "https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png",
+ "icon": "url/fsdfasdfa.svg",
+ "devMode": "proCode",
+ "npm": {
+ "package": "@ali/deep",
+ "exportName": "Button",
+ "subName": "Icon.Option",
+ "main": "",
+ "destructuring": true,
+ "version": "0.1.13"
+ },
+ "props": [
+ {
+ "name": "placeholder",
+ "propType": "string",
+ "description": "占位提示",
+ "defaultValue": "请输入..."
+ },
+ {
+ "name": "disabled",
+ "propType": "bool",
+ "description": "disabled",
+ "defaultValue": false
+ },
+ {
+ "name": "size",
+ "propType": "number",
+ "description": "尺寸",
+ "defaultValue": 10
+ },
+ {
+ "name": "dataSource",
+ "propType": "array",
+ "description": "下拉选项配置",
+ "defaultValue": []
+ },
+ {
+ "name": "object",
+ "propType": "object",
+ "description": "object",
+ "defaultValue": {
+ "a": 123,
+ "b": 234
+ }
+ },
+ {
+ "name": "node",
+ "propType": "node",
+ "description": "node"
+ },
+ {
+ "name": "element",
+ "propType": "element",
+ "description": "element"
+ },
+ {
+ "name": "onClick",
+ "propType": {
+ "type": "func",
+ "isRequired": true
+ },
+ "description": "下拉选项配置"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/validate/fixtures/props-complex-type/schema.json b/modules/material-parser/test/validate/fixtures/props-complex-type/schema.json
new file mode 100644
index 0000000000..fdb40a5af9
--- /dev/null
+++ b/modules/material-parser/test/validate/fixtures/props-complex-type/schema.json
@@ -0,0 +1,95 @@
+{
+ "componentName": "Select",
+ "title": "下拉选择器",
+ "description": "适用于下拉选择,下拉多选等场景",
+ "tags": ["xx", "yy"],
+ "docUrl": "https://fusion-demo.alibaba-inc.com/demos/next/select",
+ "screenshot": "https://img.alicdn.com/tfs/TB1osvGNXzqK1RjSZFoXXbfcXXa-1149-854.png",
+ "icon": "url/fsdfasdfa.svg",
+ "devMode": "proCode",
+ "npm": {
+ "package": "@ali/deep",
+ "exportName": "Button",
+ "subName": "Icon.Option",
+ "main": "",
+ "destructuring": true,
+ "version": "0.1.13"
+ },
+ "props": [
+ {
+ "name": "oneOf",
+ "propType": {
+ "type": "oneOf",
+ "value": ["a", "b", "c"]
+ }
+ },
+ {
+ "name": "oneOfType",
+ "propType": {
+ "type": "oneOfType",
+ "value": ["string", "number", {
+ "type": "array",
+ "isRequired": true
+ }]
+ }
+ },
+ {
+ "name": "arrayOf",
+ "propType": "number"
+ },
+ {
+ "name": "objectOf",
+ "propType": "number"
+ },
+ {
+ "name": "size",
+ "propType": "number",
+ "description": "尺寸",
+ "defaultValue": 10
+ },
+ {
+ "name": "dataSource",
+ "propType": "array",
+ "description": "下拉选项配置",
+ "defaultValue": []
+ },
+ {
+ "name": "shape",
+ "propType": {
+ "type": "shape",
+ "value": [
+ {
+ "name": "color",
+ "propType": "string"
+ },
+ {
+ "name": "fontSize",
+ "propType": {
+ "type": "number",
+ "isRequired": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "exact",
+ "propType": {
+ "type": "exact",
+ "value": [
+ {
+ "name": "name",
+ "propType": "string"
+ },
+ {
+ "name": "quantity",
+ "propType": {
+ "type": "number",
+ "isRequired": true
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/modules/material-parser/test/validate/index.test.ts b/modules/material-parser/test/validate/index.test.ts
new file mode 100644
index 0000000000..68bb5dc1ba
--- /dev/null
+++ b/modules/material-parser/test/validate/index.test.ts
@@ -0,0 +1,25 @@
+import * as fs from 'fs';
+import yaml = require('js-yaml');
+import path = require('path');
+import {validate} from '../../src'
+
+let fixtures = fs.readdirSync(path.join(__dirname, 'fixtures'));
+fixtures = fixtures.filter(item => !item.includes('.skip'));
+if (fixtures.find(item => item.includes('.only'))) {
+ fixtures = fixtures.filter(item => item.includes('.only'));
+}
+
+for (const dir of fixtures) {
+ const fullPath = path.join(__dirname, 'fixtures', dir);
+ test(`should be right in dir ${dir}`, async (done) => {
+ const json: any = yaml.safeLoad(fs.readFileSync(path.resolve(fullPath, 'schema.json'), 'utf-8'));
+ let validateResult: any;
+ try {
+ validateResult = validate(json)
+ } catch (e) {
+ validateResult = e.message;
+ }
+ expect(validateResult).toMatchSnapshot();
+ done();
+ });
+}
diff --git a/modules/material-parser/tsconfig.json b/modules/material-parser/tsconfig.json
new file mode 100644
index 0000000000..d47e50fd15
--- /dev/null
+++ b/modules/material-parser/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ // Enable strictest settings like strictNullChecks & noImplicitAny.
+ "strict": false,
+ // Allow json import
+ "resolveJsonModule": true,
+ // skip type checking of declaration files
+ "skipLibCheck": true,
+ "baseUrl": "./packages",
+ "allowJs": true
+ },
+ "exclude": ["**/test", "**/lib", "**/dist", "**/es", "node_modules", "schemas"],
+ "include": ["src/**/*"]
+}
diff --git a/modules/material-parser/webpack.config.js b/modules/material-parser/webpack.config.js
new file mode 100644
index 0000000000..5132d598e2
--- /dev/null
+++ b/modules/material-parser/webpack.config.js
@@ -0,0 +1,40 @@
+const path = require('path');
+const nodeExternals = require('webpack-node-externals');
+const CopyPlugin = require('copy-webpack-plugin');
+
+module.exports = {
+ entry: './src/index.ts',
+ target: 'node',
+ output: {
+ path: path.resolve(__dirname, 'dist'),
+ filename: 'index.js',
+ library: {
+ type: 'commonjs2',
+ },
+ },
+ mode: 'production',
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: 'ts-loader',
+ exclude: /node_modules/,
+ },
+ ],
+ },
+ externalsPresets: { node: true }, // in order to ignore built-in modules like path, fs, etc.
+ externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
+ resolve: {
+ extensions: ['.tsx', '.ts', '.js'],
+ },
+ plugins: [
+ new CopyPlugin({
+ patterns: [
+ {
+ from: path.resolve(__dirname, 'src/parse/ts/tsconfig.json'),
+ to: path.resolve(__dirname, 'dist/tsconfig.json'),
+ },
+ ],
+ }),
+ ],
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000..7f8e3bcb83
--- /dev/null
+++ b/package.json
@@ -0,0 +1,56 @@
+{
+ "private": true,
+ "workspaces": {
+ "packages": [
+ "packages/*"
+ ],
+ "nohoist": [
+ "**/css-modules-typescript-loader",
+ "**/@alife/theme-lowcode-*"
+ ]
+ },
+ "scripts": {
+ "build": "./scripts/build.sh",
+ "build:npm": "lerna run build --stream",
+ "build:umd": "lerna run build:umd --stream",
+ "clean": "rm -rf ./packages/*/lib ./packages/*/es ./packages/*/dist ./packages/*/build",
+ "lint": "eslint --ext .ts,.tsx,.js,.jsx ./ --quiet",
+ "lint:fix": "eslint --ext .ts,.tsx,.js,.jsx ./ --quiet --fix",
+ "pub": "npm run watchdog:build && lerna publish patch --force-publish --exact --no-changelog",
+ "pub:premajor": "npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog",
+ "pub:prepatch": "npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog",
+ "pub:prerelease": "npm run watchdog:build && lerna publish prerelease --force-publish --exact --dist-tag beta --preid beta --no-changelog",
+ "setup": "./scripts/setup.sh",
+ "setup:test": "./scripts/setup-for-test.sh",
+ "setup:skip-build": "./scripts/setup-skip-build.sh",
+ "start": "./scripts/start.sh",
+ "start:demo": "./scripts/start.sh @ali/lowcode-demo",
+ "test": "lerna run test --stream",
+ "test:snapshot": "lerna run test:snapshot",
+ "watchdog:build": "node ./scripts/watchdog.js",
+ "f2elint:scan": "f2elint scan -q -i ./packages/*/src",
+ "f2elint:fix": "f2elint fix -i ./packages/*/src"
+ },
+ "husky": {
+ "hooks": {
+ "pre-commit": "f2elint commit-file-scan",
+ "commit-msg": "f2elint commit-msg-scan"
+ }
+ },
+ "devDependencies": {
+ "f2elint": "^2.0.1",
+ "husky": "^7.0.4",
+ "lerna": "^4.0.0",
+ "typescript": "^4.5.5"
+ },
+ "engines": {
+ "node": ">=14.17.0"
+ },
+ "tnpm": {
+ "mode": "yarn",
+ "lockfile": "enable"
+ },
+ "resolutions": {
+ "@builder/babel-preset-ice": "1.0.1"
+ }
+}
diff --git a/packages/designer/build.json b/packages/designer/build.json
new file mode 100644
index 0000000000..bd5cf18dde
--- /dev/null
+++ b/packages/designer/build.json
@@ -0,0 +1,5 @@
+{
+ "plugins": [
+ "build-plugin-component"
+ ]
+}
diff --git a/packages/designer/build.test.json b/packages/designer/build.test.json
new file mode 100644
index 0000000000..45f0dbdfd3
--- /dev/null
+++ b/packages/designer/build.test.json
@@ -0,0 +1,9 @@
+{
+ "plugins": [
+ "build-plugin-component",
+ "@alilc/lowcode-test-mate/plugin/index.ts"
+ ],
+ "babelPlugins": [
+ ["@babel/plugin-proposal-private-property-in-object", { "loose": true }]
+ ]
+}
diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js
new file mode 100644
index 0000000000..f602b9754e
--- /dev/null
+++ b/packages/designer/jest.config.js
@@ -0,0 +1,34 @@
+const esModules = ['@recore/obx-react'].join('|');
+
+module.exports = {
+ // transform: {
+ // '^.+\\.[jt]sx?$': 'babel-jest',
+ // // '^.+\\.(ts|tsx)$': 'ts-jest',
+ // // '^.+\\.(js|jsx)$': 'babel-jest',
+ // },
+ // testMatch: ['**/document/node/node.test.ts'],
+ // testMatch: ['**/designer/bultin-hotkey.test.ts'],
+ // testMatch: ['**/plugin/plugin-manager.test.ts'],
+ // testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
+ transformIgnorePatterns: [
+ `/node_modules/(?!${esModules})/`,
+ ],
+ setupFiles: ['./tests/fixtures/unhandled-rejection.ts'],
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
+ collectCoverage: false,
+ collectCoverageFrom: [
+ 'src/**/*.ts',
+ '!src/**/*.d.ts',
+ '!src/icons/**',
+ '!src/locale/**',
+ '!src/builtin-simulator/utils/**',
+ '!src/plugin/sequencify.ts',
+ '!src/document/node/exclusive-group.ts',
+ '!src/document/node/props/value-to-source.ts',
+ '!src/builtin-simulator/live-editing/live-editing.ts',
+ '!src/designer/offset-observer.ts',
+ '!src/designer/clipboard.ts',
+ '!**/node_modules/**',
+ '!**/vendor/**',
+ ],
+};
diff --git a/packages/designer/package.json b/packages/designer/package.json
new file mode 100644
index 0000000000..83cf3d2bdd
--- /dev/null
+++ b/packages/designer/package.json
@@ -0,0 +1,62 @@
+{
+ "name": "@alilc/lowcode-designer",
+ "version": "1.0.0",
+ "description": "Designer for Ali LowCode Engine",
+ "main": "lib/index.js",
+ "module": "es/index.js",
+ "files": [
+ "lib",
+ "es"
+ ],
+ "scripts": {
+ "build": "build-scripts build --skip-demo",
+ "test": "build-scripts test --config build.test.json",
+ "test:cov": "build-scripts test --config build.test.json --jest-coverage"
+ },
+ "license": "MIT",
+ "dependencies": {
+ "@alilc/lowcode-editor-core": "1.0.0",
+ "@alilc/lowcode-shell": "1.0.0",
+ "@alilc/lowcode-types": "1.0.0",
+ "@alilc/lowcode-utils": "1.0.0",
+ "classnames": "^2.2.6",
+ "enzyme": "^3.11.0",
+ "enzyme-adapter-react-16": "^1.15.5",
+ "react": "^16",
+ "react-dom": "^16.7.0",
+ "semver": "^7.3.5",
+ "zen-logger": "^1.1.0"
+ },
+ "devDependencies": {
+ "@alib/build-scripts": "^0.1.29",
+ "@alilc/lowcode-test-mate": "^1.0.1",
+ "@testing-library/react": "^11.2.2",
+ "@types/classnames": "^2.2.7",
+ "@types/jest": "^26.0.16",
+ "@types/lodash": "^4.14.165",
+ "@types/medium-editor": "^5.0.3",
+ "@types/node": "^13.7.1",
+ "@types/react": "^16",
+ "@types/react-dom": "^16",
+ "@types/semver": "7.3.9",
+ "babel-jest": "^26.5.2",
+ "build-plugin-component": "^0.2.10",
+ "build-scripts-config": "^0.1.8",
+ "jest": "^26.6.3",
+ "lodash": "^4.17.20",
+ "moment": "^2.29.1",
+ "typescript": "^4.0.3"
+ },
+ "publishConfig": {
+ "access": "public",
+ "registry": "https://registry.npmjs.org/"
+ },
+ "resolutions": {
+ "@builder/babel-preset-ice": "1.0.1"
+ },
+ "repository": {
+ "type": "http",
+ "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/designer"
+ },
+ "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
+}
diff --git a/packages/designer/src/builtin-simulator/README.md b/packages/designer/src/builtin-simulator/README.md
new file mode 100644
index 0000000000..f9f3ba43aa
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/README.md
@@ -0,0 +1 @@
+内置模拟器主进程
diff --git a/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less b/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less
new file mode 100644
index 0000000000..83a411e566
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less
@@ -0,0 +1,10 @@
+.lc-bem-tools {
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ overflow: visible;
+ z-index: 800;
+}
diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-container.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-container.tsx
new file mode 100644
index 0000000000..63874b4ca4
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/border-container.tsx
@@ -0,0 +1,119 @@
+import * as React from 'react';
+import { Component, Fragment, ReactElement, PureComponent } from 'react';
+import classNames from 'classnames';
+import { computed, observer, Title, globalLocale } from '@alilc/lowcode-editor-core';
+import { I18nData, isI18nData, TitleContent } from '@alilc/lowcode-types';
+import { DropLocation } from '../../designer';
+import { BuiltinSimulatorHost } from '../../builtin-simulator/host';
+import { ParentalNode } from '../../document/node';
+
+export class BorderContainerInstance extends PureComponent<{
+ title: TitleContent;
+ rect: DOMRect | null;
+ scale: number;
+ scrollX: number;
+ scrollY: number;
+}> {
+ render() {
+ const { title, rect, scale, scrollX, scrollY } = this.props;
+ if (!rect) {
+ return null;
+ }
+
+ const style = {
+ width: rect.width * scale,
+ height: rect.height * scale,
+ transform: `translate(${(scrollX + rect.left) * scale}px, ${(scrollY + rect.top) * scale}px)`,
+ };
+
+ const className = classNames('lc-borders lc-borders-detecting');
+
+ return (
+
+
+
+ );
+ }
+}
+
+function getTitle(title: string | I18nData | ReactElement) {
+ if (typeof title === 'string') return title;
+ if (isI18nData(title)) {
+ const locale = globalLocale.getLocale() || 'zh-CN';
+ return `将放入到此${title[locale]}`;
+ }
+ return '';
+}
+
+@observer
+export class BorderContainer extends Component<{
+ host: BuiltinSimulatorHost;
+}, {
+ target?: ParentalNode;
+}> {
+
+ state = {} as any;
+
+ @computed get scale() {
+ return this.props.host.viewport.scale;
+ }
+
+ @computed get scrollX() {
+ return this.props.host.viewport.scrollX;
+ }
+
+ @computed get scrollY() {
+ return this.props.host.viewport.scrollY;
+ }
+
+ componentDidMount() {
+ const { host } = this.props;
+
+ host.designer.editor.on('designer.dropLocation.change', (loc: DropLocation) => {
+ let { target } = this.state;
+ if (target === loc?.target) return;
+ this.setState({
+ target: loc?.target,
+ });
+ });
+ }
+
+ render() {
+ const { host } = this.props;
+ const { target } = this.state;
+ if (target == undefined) {
+ return null;
+ }
+ const instances = host.getComponentInstances(target!);
+ if (!instances || instances.length < 1) {
+ return null;
+ }
+
+ if (instances.length === 1) {
+ return (
+
+ );
+ }
+ return (
+
+ {instances.map((inst, i) => (
+
+ ))}
+
+ );
+ }
+}
diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx
new file mode 100644
index 0000000000..c0920c4506
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx
@@ -0,0 +1,162 @@
+import { Component, Fragment, PureComponent } from 'react';
+import classNames from 'classnames';
+import { computed, observer, Title } from '@alilc/lowcode-editor-core';
+import { TitleContent } from '@alilc/lowcode-types';
+import { getClosestNode } from '@alilc/lowcode-utils';
+
+import { BuiltinSimulatorHost } from '../host';
+
+
+export class BorderDetectingInstance extends PureComponent<{
+ title: TitleContent;
+ rect: DOMRect | null;
+ scale: number;
+ scrollX: number;
+ scrollY: number;
+ isLocked?: boolean;
+}> {
+ render() {
+ const { title, rect, scale, scrollX, scrollY, isLocked } = this.props;
+ if (!rect) {
+ return null;
+ }
+
+ const style = {
+ width: rect.width * scale,
+ height: rect.height * scale,
+ transform: `translate(${(scrollX + rect.left) * scale}px, ${(scrollY + rect.top) * scale}px)`,
+ };
+
+ const className = classNames('lc-borders lc-borders-detecting');
+
+ // TODO:
+ // 1. thinkof icon
+ // 2. thinkof top|bottom|inner space
+
+ return (
+
+
+ {
+ isLocked ? () : null
+ }
+
+ );
+ }
+}
+
+@observer
+export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {
+ @computed get scale() {
+ return this.props.host.viewport.scale;
+ }
+
+ @computed get scrollX() {
+ return this.props.host.viewport.scrollX;
+ }
+
+ @computed get scrollY() {
+ return this.props.host.viewport.scrollY;
+ }
+
+ @computed get current() {
+ const { host } = this.props;
+ const doc = host.currentDocument;
+ if (!doc) {
+ return null;
+ }
+ const { selection } = doc;
+ const { current } = host.designer.detecting;
+
+ if (!current || current.document !== doc || selection.has(current.id)) {
+ return null;
+ }
+ return current;
+ }
+
+ render() {
+ const { host } = this.props;
+ const { current } = this;
+
+
+ const canHoverHook = current?.componentMeta.getMetadata()?.configure.advanced?.callbacks?.onHoverHook;
+ const canHover = (canHoverHook && typeof canHoverHook === 'function') ? canHoverHook(current.internalToShellNode()) : true;
+
+
+ if (!canHover || !current || host.viewport.scrolling || host.liveEditing.editing) {
+ return null;
+ }
+
+ // rootNode, hover whole viewport
+ const focusNode = current.document.focusNode!;
+
+ if (!focusNode.contains(current)) {
+ return null;
+ }
+
+ if (current.contains(focusNode)) {
+ const bounds = host.viewport.bounds;
+ return (
+
+ );
+ }
+
+ const lockedNode = getClosestNode(current, (n) => {
+ // 假如当前节点就是 locked 状态,要从当前节点的父节点开始查找
+ return !!(current?.isLocked ? n.parent?.isLocked : n.isLocked);
+ });
+ if (lockedNode && lockedNode.getId() !== current.getId()) {
+ // 选中父节锁定的节点
+ return (
+
+ );
+ }
+
+ const instances = host.getComponentInstances(current);
+ if (!instances || instances.length < 1) {
+ return null;
+ }
+
+ if (instances.length === 1) {
+ return (
+
+ );
+ }
+ return (
+
+ {instances.map((inst, i) => (
+
+ ))}
+
+ );
+ }
+}
diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx
new file mode 100644
index 0000000000..d8e9c8ffc2
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx
@@ -0,0 +1,340 @@
+import React, { Component, Fragment } from 'react';
+import DragResizeEngine from './drag-resize-engine';
+import { observer, computed, globalContext, Editor } from '@alilc/lowcode-editor-core';
+import classNames from 'classnames';
+import { SimulatorContext } from '../context';
+import { BuiltinSimulatorHost } from '../host';
+import { OffsetObserver, Designer } from '../../designer';
+import { Node } from '../../document';
+
+@observer
+export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost }> {
+ static contextType = SimulatorContext;
+
+ get host(): BuiltinSimulatorHost {
+ return this.props.host;
+ }
+
+ get dragging(): boolean {
+ return this.host.designer.dragon.dragging;
+ }
+
+ @computed get selecting() {
+ const doc = this.host.currentDocument;
+ if (!doc || doc.suspensed) {
+ return null;
+ }
+ const { selection } = doc;
+ return this.dragging ? selection.getTopNodes() : selection.getNodes();
+ }
+
+ componentDidUpdate() {
+ // this.hoveringCapture.setBoundary(this.outline);
+ // this.willBind();
+ }
+
+ render() {
+ const { selecting } = this;
+ if (!selecting || selecting.length < 1) {
+ // DIRTY FIX, recore has a bug!
+ return ;
+ }
+
+ // const componentMeta = selecting[0].componentMeta;
+ // const metadata = componentMeta.getMetadata();
+
+ return (
+
+ {selecting.map((node) => (
+
+ ))}
+
+ );
+ }
+}
+
+@observer
+export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> {
+ static contextType = SimulatorContext;
+
+ get host(): BuiltinSimulatorHost {
+ return this.props.host;
+ }
+
+ get dragging(): boolean {
+ return this.host.designer.dragon.dragging;
+ }
+
+ @computed get instances() {
+ return this.host.getComponentInstances(this.props.node);
+ }
+
+ render() {
+ const { instances } = this;
+ const { node } = this.props;
+ const { designer } = this.host;
+
+ if (!instances || instances.length < 1 || this.dragging) {
+ return null;
+ }
+ return (
+
+ {instances.map((instance: any) => {
+ const observed = designer.createOffsetObserver({
+ node,
+ instance,
+ });
+ if (!observed) {
+ return null;
+ }
+ return (
+
+ );
+ })}
+
+ );
+ }
+}
+
+@observer
+export class BoxResizingInstance extends Component<{
+ observed: OffsetObserver;
+ highlight?: boolean;
+ dragging?: boolean;
+ designer?: Designer;
+}> {
+ // private outline: any;
+ private willUnbind: () => any;
+
+ // outline of eight direction
+ private outlineN: any;
+ private outlineE: any;
+ private outlineS: any;
+ private outlineW: any;
+ private outlineNE: any;
+ private outlineNW: any;
+ private outlineSE: any;
+ private outlineSW: any;
+
+ private dragEngine: DragResizeEngine;
+
+ constructor(props: any) {
+ super(props);
+ this.dragEngine = new DragResizeEngine(props.designer);
+ }
+
+ componentWillUnmount() {
+ if (this.willUnbind) {
+ this.willUnbind();
+ }
+ this.props.observed.purge();
+ }
+
+ componentDidMount() {
+ // this.hoveringCapture.setBoundary(this.outline);
+ this.willBind();
+
+ const resize = (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => {
+ const metadata = node.componentMeta.getMetadata();
+ if (
+ metadata.configure?.advanced?.callbacks &&
+ typeof metadata.configure.advanced.callbacks.onResize === 'function'
+ ) {
+ (e as any).trigger = direction;
+ (e as any).deltaX = moveX;
+ (e as any).deltaY = moveY;
+ const cbNode = node?.isNode ? node.internalToShellNode() : node;
+ metadata.configure.advanced.callbacks.onResize(e, cbNode);
+ }
+ };
+
+ const resizeStart = (e: MouseEvent, direction: string, node: any) => {
+ const metadata = node.componentMeta.getMetadata();
+ if (
+ metadata.configure?.advanced?.callbacks &&
+ typeof metadata.configure.advanced.callbacks.onResizeStart === 'function'
+ ) {
+ (e as any).trigger = direction;
+ const cbNode = node?.isNode ? node.internalToShellNode() : node;
+ metadata.configure.advanced.callbacks.onResizeStart(e, cbNode);
+ }
+ };
+
+ const resizeEnd = (e: MouseEvent, direction: string, node: any) => {
+ const metadata = node.componentMeta.getMetadata();
+ if (
+ metadata.configure?.advanced?.callbacks &&
+ typeof metadata.configure.advanced.callbacks.onResizeEnd === 'function'
+ ) {
+ (e as any).trigger = direction;
+ const cbNode = node?.isNode ? node.internalToShellNode() : node;
+ metadata.configure.advanced.callbacks.onResizeEnd(e, cbNode);
+ }
+
+ const editor = globalContext.get(Editor);
+ const npm = node?.componentMeta?.npm;
+ const selected =
+ [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
+ node?.componentMeta?.componentName ||
+ '';
+ editor?.emit('designer.border.resize', {
+ selected,
+ layout: node?.parent?.getPropValue('layout') || '',
+ });
+ };
+
+ this.dragEngine.onResize(resize);
+ this.dragEngine.onResizeStart(resizeStart);
+ this.dragEngine.onResizeEnd(resizeEnd);
+ }
+
+ willBind() {
+ if (this.willUnbind) {
+ this.willUnbind();
+ }
+
+ if (
+ !this.outlineN &&
+ !this.outlineE &&
+ !this.outlineS &&
+ !this.outlineW &&
+ !this.outlineNE &&
+ !this.outlineNW &&
+ !this.outlineSE &&
+ !this.outlineSW
+ ) {
+ return;
+ }
+
+ const unBind: any[] = [];
+ const { node } = this.props.observed;
+
+ unBind.push(
+ ...[
+ this.dragEngine.from(this.outlineN, 'n', () => node),
+ this.dragEngine.from(this.outlineE, 'e', () => node),
+ this.dragEngine.from(this.outlineS, 's', () => node),
+ this.dragEngine.from(this.outlineW, 'w', () => node),
+ this.dragEngine.from(this.outlineNE, 'ne', () => node),
+ this.dragEngine.from(this.outlineNW, 'nw', () => node),
+ this.dragEngine.from(this.outlineSE, 'se', () => node),
+ this.dragEngine.from(this.outlineSW, 'sw', () => node),
+ ],
+ );
+
+ this.willUnbind = () => {
+ if (unBind && unBind.length > 0) {
+ unBind.forEach((item) => {
+ item();
+ });
+ }
+ this.willUnbind = () => {};
+ };
+ }
+
+ render() {
+ const { observed } = this.props;
+ if (!observed.hasOffset) {
+ return null;
+ }
+
+ const { node, offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed;
+ let triggerVisible: any = [];
+ const metadata = node.componentMeta.getMetadata();
+ if (metadata.configure?.advanced?.getResizingHandlers) {
+ triggerVisible = metadata.configure.advanced.getResizingHandlers(node.internalToShellNode());
+ }
+
+ const baseSideClass = 'lc-borders lc-resize-side';
+ const baseCornerClass = 'lc-borders lc-resize-corner';
+
+ return (
+
+ {triggerVisible.includes('n') && (
+
{ this.outlineN = ref; }}
+ className={classNames(baseSideClass, 'n')}
+ style={{
+ height: 20,
+ transform: `translate(${offsetLeft}px, ${offsetTop - 10}px)`,
+ width: offsetWidth,
+ }}
+ />
+ )}
+ {triggerVisible.includes('ne') && (
+
{ this.outlineNE = ref; }}
+ className={classNames(baseCornerClass, 'ne')}
+ style={{
+ transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop - 3}px)`,
+ cursor: 'nesw-resize',
+ }}
+ />
+ )}
+ {triggerVisible.includes('e') && (
+
{ this.outlineE = ref; }}
+ style={{
+ height: offsetHeight,
+ transform: `translate(${offsetLeft + offsetWidth - 10}px, ${offsetTop}px)`,
+ width: 20,
+ }}
+ />
+ )}
+ {triggerVisible.includes('se') && (
+
{ this.outlineSE = ref; }}
+ className={classNames(baseCornerClass, 'se')}
+ style={{
+ transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop + offsetHeight - 5}px)`,
+ cursor: 'nwse-resize',
+ }}
+ />
+ )}
+ {triggerVisible.includes('s') && (
+
{ this.outlineS = ref; }}
+ className={classNames(baseSideClass, 's')}
+ style={{
+ height: 20,
+ transform: `translate(${offsetLeft}px, ${offsetTop + offsetHeight - 10}px)`,
+ width: offsetWidth,
+ }}
+ />
+ )}
+ {triggerVisible.includes('sw') && (
+
{ this.outlineSW = ref; }}
+ className={classNames(baseCornerClass, 'sw')}
+ style={{
+ transform: `translate(${offsetLeft - 3}px, ${offsetTop + offsetHeight - 5}px)`,
+ cursor: 'nesw-resize',
+ }}
+ />
+ )}
+ {triggerVisible.includes('w') && (
+
{ this.outlineW = ref; }}
+ className={classNames(baseSideClass, 'w')}
+ style={{
+ height: offsetHeight,
+ transform: `translate(${offsetLeft - 10}px, ${offsetTop}px)`,
+ width: 20,
+ }}
+ />
+ )}
+ {triggerVisible.includes('nw') && (
+
{ this.outlineNW = ref; }}
+ className={classNames(baseCornerClass, 'nw')}
+ style={{
+ transform: `translate(${offsetLeft - 3}px, ${offsetTop - 3}px)`,
+ cursor: 'nwse-resize',
+ }}
+ />
+ )}
+
+ );
+ }
+}
diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx
new file mode 100644
index 0000000000..2297ca04c2
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx
@@ -0,0 +1,226 @@
+import {
+ Component,
+ Fragment,
+ ReactNodeArray,
+ isValidElement,
+ cloneElement,
+ createElement,
+ ReactNode,
+ ComponentType,
+} from 'react';
+import classNames from 'classnames';
+import { observer, computed, Tip, globalContext, makeObservable } from '@alilc/lowcode-editor-core';
+import { createIcon, isReactComponent } from '@alilc/lowcode-utils';
+import { ActionContentObject, isActionContentObject } from '@alilc/lowcode-types';
+import { BuiltinSimulatorHost } from '../host';
+import { OffsetObserver } from '../../designer';
+import { Node } from '../../document';
+import NodeSelector from '../node-selector';
+
+@observer
+export class BorderSelectingInstance extends Component<{
+ observed: OffsetObserver;
+ highlight?: boolean;
+ dragging?: boolean;
+}> {
+ componentWillUnmount() {
+ this.props.observed.purge();
+ }
+
+ render() {
+ const { observed, highlight, dragging } = this.props;
+ if (!observed.hasOffset) {
+ return null;
+ }
+
+ const { offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed;
+
+ const style = {
+ width: offsetWidth,
+ height: offsetHeight,
+ transform: `translate3d(${offsetLeft}px, ${offsetTop}px, 0)`,
+ };
+
+ const className = classNames('lc-borders lc-borders-selecting', {
+ highlight,
+ dragging,
+ });
+
+ const hideSelectTools = observed.node.componentMeta.getMetadata().configure.advanced?.hideSelectTools;
+
+ if (hideSelectTools) {
+ return null;
+ }
+
+ return (
+
+ {!dragging && }
+
+ );
+ }
+}
+
+@observer
+class Toolbar extends Component<{ observed: OffsetObserver }> {
+ render() {
+ const { observed } = this.props;
+ const { height, width } = observed.viewport;
+ const BAR_HEIGHT = 20;
+ const MARGIN = 1;
+ const BORDER = 2;
+ const SPACE_HEIGHT = BAR_HEIGHT + MARGIN + BORDER;
+ const SPACE_MINIMUM_WIDTH = 160; // magic number,大致是 toolbar 的宽度
+ let style: any;
+ // 计算 toolbar 的上/下位置
+ if (observed.top > SPACE_HEIGHT) {
+ style = {
+ top: -SPACE_HEIGHT,
+ height: BAR_HEIGHT,
+ };
+ } else if (observed.bottom + SPACE_HEIGHT < height) {
+ style = {
+ bottom: -SPACE_HEIGHT,
+ height: BAR_HEIGHT,
+ };
+ } else {
+ style = {
+ height: BAR_HEIGHT,
+ top: Math.max(MARGIN, MARGIN - observed.top),
+ };
+ }
+ // 计算 toolbar 的左/右位置
+ if (SPACE_MINIMUM_WIDTH > observed.left + observed.width) {
+ style.left = Math.max(-BORDER, observed.left - width - BORDER);
+ } else {
+ style.right = Math.max(-BORDER, observed.right - width - BORDER);
+ style.justifyContent = 'flex-start';
+ }
+ const { node } = observed;
+ const actions: ReactNodeArray = [];
+ node.componentMeta.availableActions.forEach((action) => {
+ const { important, condition, content, name } = action;
+ if (node.isSlot() && (name === 'copy' || name === 'remove')) {
+ // FIXME: need this?
+ return;
+ }
+ if (important && (typeof condition === 'function' ? condition(node) !== false : condition !== false)) {
+ actions.push(createAction(content, name, node));
+ }
+ });
+ return (
+
+ {actions}
+
+
+ );
+ }
+}
+
+function createAction(content: ReactNode | ComponentType
| ActionContentObject, key: string, node: Node) {
+ if (isValidElement(content)) {
+ return cloneElement(content, { key, node });
+ }
+ if (isReactComponent(content)) {
+ return createElement(content, { key, node });
+ }
+ if (isActionContentObject(content)) {
+ const { action, title, icon } = content;
+ return (
+ {
+ action && action(node);
+ const editor = globalContext.get('editor');
+ const npm = node?.componentMeta?.npm;
+ const selected =
+ [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
+ node?.componentMeta?.componentName ||
+ '';
+ editor?.emit('designer.border.action', {
+ name: key,
+ selected,
+ });
+ }}
+ >
+ {icon && createIcon(icon)}
+ {title}
+
+ );
+ }
+ return null;
+}
+
+@observer
+export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> {
+ get host(): BuiltinSimulatorHost {
+ return this.props.host;
+ }
+
+ get dragging(): boolean {
+ return this.host.designer.dragon.dragging;
+ }
+
+ @computed get instances() {
+ return this.host.getComponentInstances(this.props.node);
+ }
+
+ render() {
+ const { instances } = this;
+ const { node } = this.props;
+ const { designer } = this.host;
+
+ if (!instances || instances.length < 1) {
+ return null;
+ }
+ return (
+
+ {instances.map((instance) => {
+ const observed = designer.createOffsetObserver({
+ node,
+ instance,
+ });
+ if (!observed) {
+ return null;
+ }
+ return ;
+ })}
+
+ );
+ }
+}
+
+@observer
+export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> {
+ get host(): BuiltinSimulatorHost {
+ return this.props.host;
+ }
+
+ get dragging(): boolean {
+ return this.host.designer.dragon.dragging;
+ }
+
+ @computed get selecting() {
+ const doc = this.host.currentDocument;
+ if (!doc || doc.suspensed || this.host.liveEditing.editing) {
+ return null;
+ }
+ const { selection } = doc;
+ return this.dragging ? selection.getTopNodes() : selection.getNodes();
+ }
+
+ render() {
+ const { selecting } = this;
+ if (!selecting || selecting.length < 1) {
+ return null;
+ }
+
+ return (
+
+ {selecting.map((node) => (
+
+ ))}
+
+ );
+ }
+}
diff --git a/packages/designer/src/builtin-simulator/bem-tools/borders.less b/packages/designer/src/builtin-simulator/bem-tools/borders.less
new file mode 100644
index 0000000000..2cdc9fb403
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/borders.less
@@ -0,0 +1,156 @@
+@scope: lc-borders;
+
+.@{scope} {
+ box-sizing: border-box;
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1;
+ border: 1px solid var(--color-brand-light);
+ will-change: transform, width, height;
+ overflow: visible;
+ & > &-title {
+ color: var(--color-brand-light);
+ transform: translateY(-100%);
+ font-weight: lighter;
+ }
+ & > &-status {
+ margin-left: 5px;
+ color: #3c3c3c;
+ transform: translateY(-100%);
+ font-weight: lighter;
+ }
+ & > &-actions {
+ position: absolute;
+ display: flex;
+ flex-direction: row-reverse;
+ align-items: stretch;
+ justify-content: flex-end;
+ pointer-events: all;
+ > * {
+ flex-shrink: 0;
+ }
+ }
+
+ &-action,
+ .ve-icon-button.ve-action-save {
+ box-sizing: border-box;
+ cursor: pointer;
+ height: 20px;
+ width: 20px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--color-brand, #006cff);
+ opacity: 1;
+ max-height: 100%;
+ overflow: hidden;
+ color: white;
+ &:hover {
+ background: var(--color-brand-light, #006cff);
+ }
+ }
+
+ &.lc-resize-corner {
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border: 1px solid #197aff;
+ background: #fff;
+ pointer-events: auto;
+ z-index: 2;
+ }
+
+ &.lc-resize-side {
+ border-width: 0;
+ z-index: 1;
+ pointer-events: auto;
+ align-items: center;
+ justify-content: center;
+ display: flex;
+
+ &:after {
+ content: "";
+ display: block;
+ border: 1px solid #197aff;
+ background: #fff;
+ // background: #738397;
+ border-radius: 2px;
+ // animation: flashing 1.5s infinite linear;
+ }
+
+ &.e,
+ &.w {
+ cursor: ew-resize;
+ &:after {
+ width: 4px;
+ // height: calc(100% - 20px);
+ min-height: 50%;
+ }
+ }
+
+ &.n,
+ &.s {
+ cursor: ns-resize;
+ &:after {
+ // width: calc(100% - 20px);
+ min-width: 50%;
+ height: 4px;
+ }
+ }
+ }
+
+ // &&-hovering {
+ &&-detecting {
+ z-index: 1;
+ border-style: dashed;
+ background: rgba(0,121,242,.04);
+
+ &.x-loop {
+ border-color: rgba(138, 93, 226, 0.8);
+ background: rgba(138, 93, 226, 0.04);
+
+ >.@{scope}-title {
+ color: rgba(138, 93, 226, 1.0);
+ }
+ }
+
+ &.x-condition {
+ border-color: rgba(255, 99, 8, 0.8);
+ background: rgba(255, 99, 8, 0.04);
+ >.@{scope}-title {
+ color: rgb(255, 99, 8);
+ }
+ }
+ }
+
+ &&-selecting {
+ z-index: 2;
+ border-width: 2px;
+
+ &.x-loop {
+ border-color: rgba(147, 112, 219, 1.0);
+ background: rgba(147, 112, 219, 0.04);
+
+ >@{scope}-title {
+ color: rgba(147, 112, 219, 1.0);
+ }
+ &.highlight {
+ background: transparent;
+ }
+ }
+
+ &.x-condition {
+ border-color: rgb(255, 99, 8);
+ >@{scope}-title {
+ color: rgb(255, 99, 8);
+ }
+ }
+
+ &.dragging {
+ background: rgba(182, 178, 178, 0.8);
+ border: none;
+ }
+ }
+}
diff --git a/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts b/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts
new file mode 100644
index 0000000000..68e1113577
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts
@@ -0,0 +1,158 @@
+import { EventEmitter } from 'events';
+import { ISimulatorHost } from '../../simulator';
+import { Designer, Point } from '../../designer';
+import { cursor } from '@alilc/lowcode-utils';
+// import Cursor from './cursor';
+// import Pages from './pages';
+
+function makeEventsHandler(
+ boostEvent: MouseEvent | DragEvent,
+ sensors: ISimulatorHost[],
+): (fn: (sdoc: Document) => void) => void {
+ const topDoc = window.document;
+ const sourceDoc = boostEvent.view?.document || topDoc;
+ // TODO: optimize this logic, reduce listener
+ // const boostPrevented = boostEvent.defaultPrevented;
+ const docs = new Set();
+ // if (boostPrevented || isDragEvent(boostEvent)) {
+ docs.add(topDoc);
+ // }
+ docs.add(sourceDoc);
+ // if (sourceDoc !== topDoc || isDragEvent(boostEvent)) {
+ sensors.forEach(sim => {
+ const sdoc = sim.contentDocument;
+ if (sdoc) {
+ docs.add(sdoc);
+ }
+ });
+ // }
+
+ return (handle: (sdoc: Document) => void) => {
+ docs.forEach(doc => handle(doc));
+ };
+}
+
+// 拖动缩放
+export default class DragResizeEngine {
+ private emitter: EventEmitter;
+
+ private dragResizing = false;
+
+ private designer: Designer;
+
+ constructor(designer: Designer) {
+ this.designer = designer;
+ this.emitter = new EventEmitter();
+ }
+
+ isDragResizing() {
+ return this.dragResizing;
+ }
+
+ /**
+ * drag reszie from
+ * @param shell
+ * @param direction n/s/e/w
+ * @param boost (e: MouseEvent) => VE.Node
+ */
+ from(shell: Element, direction: string, boost: (e: MouseEvent) => any) {
+ let node: any;
+ let startEvent: Point;
+
+ if (!shell) {
+ return () => {};
+ }
+
+ const move = (e: MouseEvent) => {
+ const x = createResizeEvent(e);
+ const moveX = x.clientX - startEvent.clientX;
+ const moveY = x.clientY - startEvent.clientY;
+
+ this.emitter.emit('resize', e, direction, node, moveX, moveY);
+ };
+
+ const masterSensors = this.getMasterSensors();
+
+ const createResizeEvent = (e: MouseEvent | DragEvent): Point => {
+ const sourceDocument = e.view?.document;
+
+ if (!sourceDocument || sourceDocument === document) {
+ return e;
+ }
+ const srcSim = masterSensors.find(sim => sim.contentDocument === sourceDocument);
+ if (srcSim) {
+ return srcSim.viewport.toGlobalPoint(e);
+ }
+ return e;
+ };
+
+ const over = (e: MouseEvent) => {
+ const handleEvents = makeEventsHandler(e, masterSensors);
+ handleEvents(doc => {
+ doc.removeEventListener('mousemove', move, true);
+ doc.removeEventListener('mouseup', over, true);
+ });
+
+ this.dragResizing = false;
+ this.designer.detecting.enable = true;
+ cursor.release();
+
+ this.emitter.emit('resizeEnd', e, direction, node);
+ };
+
+ const mousedown = (e: MouseEvent) => {
+ node = boost(e);
+ startEvent = createResizeEvent(e);
+ const handleEvents = makeEventsHandler(e, masterSensors);
+ handleEvents(doc => {
+ doc.addEventListener('mousemove', move, true);
+ doc.addEventListener('mouseup', over, true);
+ });
+
+ this.emitter.emit('resizeStart', e, direction, node);
+ this.dragResizing = true;
+ this.designer.detecting.enable = false;
+ cursor.addState('ew-resize');
+ };
+ shell.addEventListener('mousedown', mousedown);
+ return () => {
+ shell.removeEventListener('mousedown', mousedown);
+ };
+ }
+
+ onResizeStart(func: (e: MouseEvent, direction: string, node: any) => any) {
+ this.emitter.on('resizeStart', func);
+ return () => {
+ this.emitter.removeListener('resizeStart', func);
+ };
+ }
+
+ onResize(
+ func: (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => any,
+ ) {
+ this.emitter.on('resize', func);
+ return () => {
+ this.emitter.removeListener('resize', func);
+ };
+ }
+
+ onResizeEnd(func: (e: MouseEvent, direction: string, node: any) => any) {
+ this.emitter.on('resizeEnd', func);
+ return () => {
+ this.emitter.removeListener('resizeEnd', func);
+ };
+ }
+
+ private getMasterSensors(): ISimulatorHost[] {
+ return this.designer.project.documents
+ .map(doc => {
+ if (doc.active && doc.simulator?.sensorAvailable) {
+ return doc.simulator;
+ }
+ return null;
+ })
+ .filter(Boolean) as any;
+ }
+}
+
+// new DragResizeEngine();
diff --git a/packages/designer/src/builtin-simulator/bem-tools/index.tsx b/packages/designer/src/builtin-simulator/bem-tools/index.tsx
new file mode 100644
index 0000000000..bc485af1b4
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/index.tsx
@@ -0,0 +1,37 @@
+import React, { Component } from 'react';
+import { observer, engineConfig } from '@alilc/lowcode-editor-core';
+import { BorderDetecting } from './border-detecting';
+import { BorderContainer } from './border-container';
+import { BuiltinSimulatorHost } from '../host';
+import { BorderSelecting } from './border-selecting';
+import BorderResizing from './border-resizing';
+import { InsertionView } from './insertion';
+import './bem-tools.less';
+import './borders.less';
+
+@observer
+export class BemTools extends Component<{ host: BuiltinSimulatorHost }> {
+ render() {
+ const { host } = this.props;
+ const { designMode } = host;
+ const { scrollX, scrollY, scale } = host.viewport;
+ if (designMode === 'live') {
+ return null;
+ }
+ return (
+
+ { !engineConfig.get('disableDetecting') && }
+
+ { engineConfig.get('enableReactiveContainer') && }
+
+
+ {
+ host.designer.bemToolsManager.getAllBemTools().map(tools => {
+ const ToolsCls = tools.item;
+ return ;
+ })
+ }
+
+ );
+ }
+}
\ No newline at end of file
diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.less b/packages/designer/src/builtin-simulator/bem-tools/insertion.less
new file mode 100644
index 0000000000..770d3893ca
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.less
@@ -0,0 +1,28 @@
+.lc-insertion {
+ position: absolute;
+ top: -2px;
+ left: 0;
+ z-index: 12;
+ pointer-events: none !important;
+ background-color: var(--color-brand-light);
+ height: 4px;
+
+ &.cover {
+ top: 0;
+ height: auto;
+ width: auto;
+ border: none;
+ opacity: 0.3;
+ }
+
+ &.vertical {
+ top: 0;
+ left: -2px;
+ width: 4px;
+ height: auto;
+ }
+
+ &.invalid {
+ background-color: red;
+ }
+}
diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx b/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx
new file mode 100644
index 0000000000..d6f748debd
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx
@@ -0,0 +1,173 @@
+import { Component } from 'react';
+import { observer } from '@alilc/lowcode-editor-core';
+import { BuiltinSimulatorHost } from '../host';
+import {
+ DropLocation,
+ Rect,
+ isLocationChildrenDetail,
+ LocationChildrenDetail,
+ isVertical,
+} from '../../designer';
+import { ISimulatorHost } from '../../simulator';
+import { ParentalNode } from '../../document';
+import './insertion.less';
+import { NodeData, NodeSchema } from '@alilc/lowcode-types';
+
+interface InsertionData {
+ edge?: DOMRect;
+ insertType?: string;
+ vertical?: boolean;
+ nearRect?: Rect;
+ coverRect?: DOMRect;
+ nearNode?: NodeData;
+}
+
+/**
+ * 处理拖拽子节点(INode)情况
+ */
+function processChildrenDetail(sim: ISimulatorHost, container: ParentalNode, detail: LocationChildrenDetail): InsertionData {
+ let edge = detail.edge || null;
+
+ if (!edge) {
+ edge = sim.computeRect(container);
+ if (!edge) {
+ return {};
+ }
+ }
+
+ const ret: any = {
+ edge,
+ insertType: 'before',
+ };
+
+ if (detail.near) {
+ const { node, pos, rect, align } = detail.near;
+ ret.nearRect = rect || sim.computeRect(node);
+ ret.nearNode = node;
+ if (pos === 'replace') {
+ // FIXME: ret.nearRect mybe null
+ ret.coverRect = ret.nearRect;
+ ret.insertType = 'cover';
+ } else if (!ret.nearRect || (ret.nearRect.width === 0 && ret.nearRect.height === 0)) {
+ ret.nearRect = ret.edge;
+ ret.insertType = 'after';
+ ret.vertical = isVertical(ret.nearRect);
+ } else {
+ ret.insertType = pos;
+ ret.vertical = align ? align === 'V' : isVertical(ret.nearRect);
+ }
+ return ret;
+ }
+
+ // from outline-tree: has index, but no near
+ // TODO: think of shadowNode & ConditionFlow
+ const { index } = detail;
+ if (index == null) {
+ ret.coverRect = ret.edge;
+ ret.insertType = 'cover';
+ return ret;
+ }
+ let nearNode = container.children.get(index);
+ if (!nearNode) {
+ // index = 0, eg. nochild,
+ nearNode = container.children.get(index > 0 ? index - 1 : 0);
+ if (!nearNode) {
+ ret.insertType = 'cover';
+ ret.coverRect = edge;
+ return ret;
+ }
+ ret.insertType = 'after';
+ }
+ if (nearNode) {
+ ret.nearRect = sim.computeRect(nearNode);
+ if (!ret.nearRect || (ret.nearRect.width === 0 && ret.nearRect.height === 0)) {
+ ret.nearRect = ret.edge;
+ ret.insertType = 'after';
+ }
+ ret.vertical = isVertical(ret.nearRect);
+ ret.nearNode = nearNode;
+ } else {
+ ret.insertType = 'cover';
+ ret.coverRect = edge;
+ }
+ return ret;
+}
+
+/**
+ * 将 detail 信息转换为页面"坐标"信息
+ */
+function processDetail({ target, detail, document }: DropLocation): InsertionData {
+ const sim = document.simulator;
+ if (!sim) {
+ return {};
+ }
+ if (isLocationChildrenDetail(detail)) {
+ return processChildrenDetail(sim, target, detail);
+ } else {
+ // TODO: others...
+ const instances = sim.getComponentInstances(target);
+ if (!instances) {
+ return {};
+ }
+ const edge = sim.computeComponentInstanceRect(instances[0], target.componentMeta.rootSelector);
+ return edge ? { edge, insertType: 'cover', coverRect: edge } : {};
+ }
+}
+
+@observer
+export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> {
+ render() {
+ const { host } = this.props;
+ const loc = host.currentDocument?.dropLocation;
+ if (!loc) {
+ return null;
+ }
+ // 如果是个绝对定位容器,不需要渲染插入标记
+ if (loc.target.componentMeta.getMetadata().configure.advanced?.isAbsoluteLayoutContainer) {
+ return null;
+ }
+
+ const { scale, scrollX, scrollY } = host.viewport;
+ const { edge, insertType, coverRect, nearRect, vertical, nearNode } = processDetail(loc);
+
+ if (!edge) {
+ return null;
+ }
+
+ let className = 'lc-insertion';
+ if ((loc.detail as any)?.valid === false) {
+ className += ' invalid';
+ }
+ const style: any = {};
+ let x: number;
+ let y: number;
+ if (insertType === 'cover') {
+ className += ' cover';
+ x = (coverRect!.left + scrollX) * scale;
+ y = (coverRect!.top + scrollY) * scale;
+ style.width = coverRect!.width * scale;
+ style.height = coverRect!.height * scale;
+ } else {
+ if (!nearRect) {
+ return null;
+ }
+ if (vertical) {
+ className += ' vertical';
+ x = ((insertType === 'before' ? nearRect.left : nearRect.right) + scrollX) * scale;
+ y = (nearRect.top + scrollY) * scale;
+ style.height = nearRect!.height * scale;
+ } else {
+ x = (nearRect.left + scrollX) * scale;
+ y = ((insertType === 'before' ? nearRect.top : nearRect.bottom) + scrollY) * scale;
+ style.width = nearRect.width * scale;
+ }
+ if (y === 0 && (nearNode as NodeSchema)?.componentMeta?.isTopFixed) {
+ return null;
+ }
+ }
+ style.transform = `translate3d(${x}px, ${y}px, 0)`;
+ // style.transition = 'all 0.2s ease-in-out';
+
+ return ;
+ }
+}
diff --git a/packages/designer/src/builtin-simulator/bem-tools/manager.ts b/packages/designer/src/builtin-simulator/bem-tools/manager.ts
new file mode 100644
index 0000000000..3756600ed9
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/bem-tools/manager.ts
@@ -0,0 +1,37 @@
+import { ComponentType } from 'react';
+import { Designer } from '../../designer';
+import { invariant } from '../../utils';
+import { BuiltinSimulatorHost } from '../../builtin-simulator/host';
+
+export type BemToolsData = {
+ name: string;
+ item: ComponentType<{ host: BuiltinSimulatorHost }>;
+};
+
+export class BemToolsManager {
+ private designer: Designer;
+
+ private toolsContainer: BemToolsData[] = [];
+
+ constructor(designer: Designer) {
+ this.designer = designer;
+ }
+
+ addBemTools(toolsData: BemToolsData) {
+ const found = this.toolsContainer.find(item => item.name === toolsData.name);
+ invariant(!found, `${toolsData.name} already exists`);
+
+ this.toolsContainer.push(toolsData);
+ }
+
+ removeBemTools(name: string) {
+ const index = this.toolsContainer.findIndex(item => item.name === name);
+ if (index !== -1) {
+ this.toolsContainer.splice(index, 1);
+ }
+ }
+
+ getAllBemTools() {
+ return this.toolsContainer;
+ }
+}
\ No newline at end of file
diff --git a/packages/designer/src/builtin-simulator/context.ts b/packages/designer/src/builtin-simulator/context.ts
new file mode 100644
index 0000000000..1cfab438b5
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/context.ts
@@ -0,0 +1,4 @@
+import { createContext } from 'react';
+import { BuiltinSimulatorHost } from './host';
+
+export const SimulatorContext = createContext({} as any);
diff --git a/packages/designer/src/builtin-simulator/create-simulator.ts b/packages/designer/src/builtin-simulator/create-simulator.ts
new file mode 100644
index 0000000000..1d98fcd2ae
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/create-simulator.ts
@@ -0,0 +1,110 @@
+// NOTE: 仅用作类型标注,切勿作为实体使用
+import { BuiltinSimulatorHost } from './host';
+import {
+ AssetLevel,
+ AssetLevels,
+ AssetList,
+ isAssetBundle,
+ isAssetItem,
+ AssetType,
+ assetItem,
+ isCSSUrl,
+} from '@alilc/lowcode-utils';
+
+import { BuiltinSimulatorRenderer } from './renderer';
+
+export function createSimulator(
+ host: BuiltinSimulatorHost,
+ iframe: HTMLIFrameElement,
+ vendors: AssetList = [],
+): Promise {
+ const win: any = iframe.contentWindow;
+ const doc = iframe.contentDocument!;
+
+ win.LCSimulatorHost = host;
+
+ const styles: any = {};
+ const scripts: any = {};
+ AssetLevels.forEach((lv) => {
+ styles[lv] = [];
+ scripts[lv] = [];
+ });
+
+ function parseAssetList(assets: AssetList, level?: AssetLevel) {
+ for (let asset of assets) {
+ if (!asset) {
+ continue;
+ }
+ if (isAssetBundle(asset)) {
+ if (asset.assets) {
+ parseAssetList(
+ Array.isArray(asset.assets) ? asset.assets : [asset.assets],
+ asset.level || level,
+ );
+ }
+ continue;
+ }
+ if (Array.isArray(asset)) {
+ parseAssetList(asset, level);
+ continue;
+ }
+ if (!isAssetItem(asset)) {
+ asset = assetItem(isCSSUrl(asset) ? AssetType.CSSUrl : AssetType.JSUrl, asset, level)!;
+ }
+ const id = asset.id ? ` data-id="${asset.id}"` : '';
+ const lv = asset.level || level || AssetLevel.Environment;
+ if (asset.type === AssetType.JSUrl) {
+ (scripts[lv] || scripts[AssetLevel.App]).push(
+ ``,
+ );
+ } else if (asset.type === AssetType.JSText) {
+ (scripts[lv] || scripts[AssetLevel.App]).push(``);
+ } else if (asset.type === AssetType.CSSUrl) {
+ (styles[lv] || styles[AssetLevel.App]).push(
+ ``,
+ );
+ } else if (asset.type === AssetType.CSSText) {
+ (styles[lv] || styles[AssetLevel.App]).push(
+ ``,
+ );
+ }
+ }
+ }
+
+ parseAssetList(vendors);
+
+ const styleFrags = Object.keys(styles)
+ .map((key) => {
+ return `${styles[key].join('\n')}`;
+ })
+ .join('');
+ const scriptFrags = Object.keys(scripts)
+ .map((key) => {
+ return scripts[key].join('\n');
+ })
+ .join('');
+
+ doc.open();
+ doc.write(`
+
+
+
+ ${styleFrags}
+
+
+ ${scriptFrags}
+
+`);
+ doc.close();
+
+ return new Promise((resolve) => {
+ if (win.SimulatorRenderer || host.renderer) {
+ return resolve(win.SimulatorRenderer || host.renderer);
+ }
+ const loaded = () => {
+ resolve(win.SimulatorRenderer || host.renderer);
+ win.removeEventListener('load', loaded);
+ };
+ win.addEventListener('load', loaded);
+ });
+}
diff --git a/packages/designer/src/builtin-simulator/host-view.tsx b/packages/designer/src/builtin-simulator/host-view.tsx
new file mode 100644
index 0000000000..ff40362d15
--- /dev/null
+++ b/packages/designer/src/builtin-simulator/host-view.tsx
@@ -0,0 +1,121 @@
+import React, { Component } from 'react';
+import { observer, globalContext } from '@alilc/lowcode-editor-core';
+import { BuiltinSimulatorHost, BuiltinSimulatorProps } from './host';
+import { BemTools } from './bem-tools';
+import { Project } from '../project';
+import './host.less';
+
+/*
+ Simulator 模拟器,可替换部件,有协议约束, 包含画布的容器,使用场景:当 Canvas 大小变化时,用来居中处理 或 定位 Canvas
+ Canvas(DeviceShell) 设备壳层,通过背景图片来模拟,通过设备预设样式改变宽度、高度及定位 CanvasViewport
+ CanvasViewport 页面编排场景中宽高不可溢出 Canvas 区
+ Content(Shell) 内容外层,宽高紧贴 CanvasViewport,禁用边框,禁用 margin
+ BemTools 辅助显示层,初始相对 Content 位置 0,0,紧贴 Canvas, 根据 Content 滚动位置,改变相对位置
+*/
+
+type SimulatorHostProps = BuiltinSimulatorProps & {
+ project: Project;
+ onMount?: (host: BuiltinSimulatorHost) => void;
+};
+
+export class BuiltinSimulatorHostView extends Component {
+ readonly host: BuiltinSimulatorHost;
+
+ constructor(props: any) {
+ super(props);
+ const { project, onMount } = this.props;
+ this.host = (project.simulator as BuiltinSimulatorHost) || new BuiltinSimulatorHost(project);
+ this.host.setProps(this.props);
+ onMount?.(this.host);
+ }
+
+ shouldComponentUpdate(nextProps: BuiltinSimulatorProps) {
+ this.host.setProps(nextProps);
+ return false;
+ }
+
+ render() {
+ return (
+
+ {/* progressing.visible ?