From 3df360de85d425b2926ea50ff26a8df27ec36a78 Mon Sep 17 00:00:00 2001 From: gengyang Date: Fri, 7 Feb 2020 11:43:54 +0800 Subject: [PATCH] feat: complete component protocol json schema & validate method --- .editorconfig | 17 + .eslintignore | 15 + .eslintrc.js | 34 ++ .prettierignore | 4 + .prettierrc | 9 +- package.json | 15 +- packages/material-parser/README.md | 5 +- packages/material-parser/package.json | 35 ++ packages/material-parser/schemas/schema.json | 537 ++++++++++++++++++ packages/material-parser/schemas/schema.yml | 348 ++++++++++++ packages/material-parser/scripts/transform.js | 20 + packages/material-parser/src/index.ts | 2 + packages/material-parser/src/schema.json | 537 ++++++++++++++++++ packages/material-parser/src/validate.ts | 13 + .../fixtures/basic-error.skip/result.json | 3 + .../fixtures/basic-error.skip/src.json | 18 + .../fixtures/basic-success/result.json | 3 + .../validate/fixtures/basic-success/src.json | 18 + .../validate/fixtures/configure/result.json | 3 + .../test/validate/fixtures/configure/src.json | 68 +++ .../fixtures/props-basic-type/result.json | 3 + .../fixtures/props-basic-type/src.json | 71 +++ .../fixtures/props-complex-type/result.json | 3 + .../fixtures/props-complex-type/src.json | 95 ++++ .../material-parser/test/validate/index.ts | 52 ++ packages/material-parser/tsconfig.json | 9 + templates/src/index.d.ts | 0 templates/src/index.js | 3 + templates/src/index.js.map | 1 + tslint.json | 14 - 30 files changed, 1928 insertions(+), 27 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintignore create mode 100644 .eslintrc.js create mode 100644 .prettierignore create mode 100644 packages/material-parser/package.json create mode 100644 packages/material-parser/schemas/schema.json create mode 100644 packages/material-parser/schemas/schema.yml create mode 100644 packages/material-parser/scripts/transform.js create mode 100644 packages/material-parser/src/index.ts create mode 100644 packages/material-parser/src/schema.json create mode 100644 packages/material-parser/src/validate.ts create mode 100644 packages/material-parser/test/validate/fixtures/basic-error.skip/result.json create mode 100644 packages/material-parser/test/validate/fixtures/basic-error.skip/src.json create mode 100644 packages/material-parser/test/validate/fixtures/basic-success/result.json create mode 100644 packages/material-parser/test/validate/fixtures/basic-success/src.json create mode 100644 packages/material-parser/test/validate/fixtures/configure/result.json create mode 100644 packages/material-parser/test/validate/fixtures/configure/src.json create mode 100644 packages/material-parser/test/validate/fixtures/props-basic-type/result.json create mode 100644 packages/material-parser/test/validate/fixtures/props-basic-type/src.json create mode 100644 packages/material-parser/test/validate/fixtures/props-complex-type/result.json create mode 100644 packages/material-parser/test/validate/fixtures/props-complex-type/src.json create mode 100644 packages/material-parser/test/validate/index.ts create mode 100644 packages/material-parser/tsconfig.json create mode 100644 templates/src/index.d.ts create mode 100644 templates/src/index.js create mode 100644 templates/src/index.js.map delete mode 100644 tslint.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..0fb5f20ff --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +quote_type = single + +[*.md] +trim_trailing_whitespace = false + +[makefile] +indent_style = tab +indent_size = 4 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..70aca2e78 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,15 @@ +node_modules +dist +build +coverage +expected +website +gh-pages +vendors +packages/build-scripts/test +packages/build-scripts/bin +packages/build-scripts/lib +packages/build-plugin-store/lib +packages/build-plugin-ice-router/lib +packages/build-plugin-ice-stark-child/lib +packages/build-plugin-env-config/lib \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..0d763bae3 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,34 @@ +const { eslint, tslint, deepmerge } = require('@ice/spec'); + +const commonRules = { + 'global-require': 0, + 'import/no-dynamic-require': 0, + 'no-restricted-syntax': ['error', "BinaryExpression[operator='of']"], +}; + +const jsRules = deepmerge(eslint, { + rules: { + ...commonRules, + }, +}); + +const tsRules = deepmerge(tslint, { + rules: { + ...commonRules, + '@typescript-eslint/explicit-function-return-type': ['warn', { + allowTypedFunctionExpressions: true, + }], + }, +}); + +delete tsRules.root; + +module.exports = { + ...jsRules, + overrides: [ + { + ...tsRules, + files: ['**/*.ts', '**/*.tsx'], + }, + ], +}; diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..28af681fc --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +**/test/**/*.ts +**/test/**/*.js +**/template/**/*.template +**/template/**/*.tpl diff --git a/.prettierrc b/.prettierrc index cfb30e46b..0a11aaffb 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,6 @@ { - "semi": true, - "singleQuote": true, - "trailingComma": "es5" -} \ No newline at end of file + "trailingComma": "all", + "tabWidth": 2, + "semi": true, + "singleQuote": true +} diff --git a/package.json b/package.json index 556aca8c7..8be046891 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,11 @@ "name": "ali-lowcode-engine", "private": true, "scripts": { - "boot": "lerna bootstrap --registry http://registry.npm.alibaba-inc.com", + "boot": "lerna bootstrap --registry http://registry.npm.alibaba-inc.com --hoist", "clean": "rimraf ./packages/*/lib ./packages/*/node_modules", "pub": "npm run test && lerna publish --registry http://registry.npm.alibaba-inc.com", - "lint": "tslint -p tsconfig.json", - "lint:fix": "tslint --fix -p tsconfig.json", + "lint": "eslint --cache --quiet --ext .ts ./", + "lint:fix": "eslint --fix --cache --quiet --ext .ts ./", "build": "lerna run build", "test": "lerna run test" }, @@ -21,10 +21,9 @@ "prettier": "^1.15.3", "rimraf": "^2.6.3", "ts-node": "^7.0.1", - "tslint": "^5.12.0", - "tslint-config-prettier": "^1.17.0", - "tslint-plugin-prettier": "^2.0.1", - "typescript": "^3.2.2" + "typescript": "^3.2.2", + "@ice/spec": "^0.1.4", + "eslint": "^6.0.1" }, "engines": { "node": "^8 || ^10" @@ -32,7 +31,7 @@ "lint-staged": { "*.ts": [ "prettier --write", - "tslint --fix -p tsconfig.json", + "eslint --fix --cache --quiet --ext .ts ./", "git add" ] }, diff --git a/packages/material-parser/README.md b/packages/material-parser/README.md index e84288635..0dc4193c4 100644 --- a/packages/material-parser/README.md +++ b/packages/material-parser/README.md @@ -1 +1,4 @@ -入料模块 +# @ali/lowcode-engine-material-parser +> 入料模块 + + diff --git a/packages/material-parser/package.json b/packages/material-parser/package.json new file mode 100644 index 000000000..532ed1ecd --- /dev/null +++ b/packages/material-parser/package.json @@ -0,0 +1,35 @@ +{ + "name": "@ali/lowcode-engine-material-parser", + "version": "0.1.0", + "description": "material parser for Ali lowCode engine", + "main": "lib/index.js", + "files": [ + "lib", + "schemas" + ], + "devDependencies": { + "@types/js-yaml": "^3.12.2", + "ajv": "^6.10.2", + "better-ajv-errors": "^0.6.4", + "globby": "^10.0.1", + "jest": "^24.8.0", + "jest-watch-typeahead": "^0.3.1", + "js-yaml": "^3.13.1" + }, + "scripts": { + "build": "tsc", + "prebuild": "npm run schema", + "test": "ava", + "schema": "node ./scripts/transform.js" + }, + "ava": { + "compileEnhancements": false, + "extensions": [ + "ts" + ], + "require": [ + "ts-node/register" + ] + }, + "license": "MIT" +} diff --git a/packages/material-parser/schemas/schema.json b/packages/material-parser/schemas/schema.json new file mode 100644 index 000000000..7a5469a10 --- /dev/null +++ b/packages/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/packages/material-parser/schemas/schema.yml b/packages/material-parser/schemas/schema.yml new file mode 100644 index 000000000..7ddc5ad9d --- /dev/null +++ b/packages/material-parser/schemas/schema.yml @@ -0,0 +1,348 @@ +$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: {} # 暂未校验每个控件的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/packages/material-parser/scripts/transform.js b/packages/material-parser/scripts/transform.js new file mode 100644 index 000000000..b64b88a14 --- /dev/null +++ b/packages/material-parser/scripts/transform.js @@ -0,0 +1,20 @@ +const yaml = require('js-yaml'); +const fs = require('fs'); +const path = require('path'); +const Ajv = require('ajv'); + +const ajv = new Ajv(); + +const YamlPath = path.resolve(__dirname, '../schemas/schema.yml'); +const JsonPath = path.resolve(__dirname, '../src/schema.json'); +// Get document, or throw exception on error + +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'); +} catch (e) { + console.log(e); + process.exit(1); +} diff --git a/packages/material-parser/src/index.ts b/packages/material-parser/src/index.ts new file mode 100644 index 000000000..d8dfb55e8 --- /dev/null +++ b/packages/material-parser/src/index.ts @@ -0,0 +1,2 @@ +export { default as validate } from './validate'; +export { default as schema } from './schema.json'; diff --git a/packages/material-parser/src/schema.json b/packages/material-parser/src/schema.json new file mode 100644 index 000000000..7a5469a10 --- /dev/null +++ b/packages/material-parser/src/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/packages/material-parser/src/validate.ts b/packages/material-parser/src/validate.ts new file mode 100644 index 000000000..7309781da --- /dev/null +++ b/packages/material-parser/src/validate.ts @@ -0,0 +1,13 @@ +import Ajv from 'ajv'; +import schema from './schema.json'; + +const ajv = new Ajv({ jsonPointers: true }); +const validate = ajv.compile(schema); + +export default function validateSchema(json: object) { + if (validate(json) === false) { + throw new Error(JSON.stringify(validate.errors, null, 2)); + } + + return true; +} diff --git a/packages/material-parser/test/validate/fixtures/basic-error.skip/result.json b/packages/material-parser/test/validate/fixtures/basic-error.skip/result.json new file mode 100644 index 000000000..86a346c7d --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/basic-error.skip/result.json @@ -0,0 +1,3 @@ +{ + "success": true +} \ No newline at end of file diff --git a/packages/material-parser/test/validate/fixtures/basic-error.skip/src.json b/packages/material-parser/test/validate/fixtures/basic-error.skip/src.json new file mode 100644 index 000000000..d1c6f5d8d --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/basic-error.skip/src.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/packages/material-parser/test/validate/fixtures/basic-success/result.json b/packages/material-parser/test/validate/fixtures/basic-success/result.json new file mode 100644 index 000000000..86a346c7d --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/basic-success/result.json @@ -0,0 +1,3 @@ +{ + "success": true +} \ No newline at end of file diff --git a/packages/material-parser/test/validate/fixtures/basic-success/src.json b/packages/material-parser/test/validate/fixtures/basic-success/src.json new file mode 100644 index 000000000..d1c6f5d8d --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/basic-success/src.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/packages/material-parser/test/validate/fixtures/configure/result.json b/packages/material-parser/test/validate/fixtures/configure/result.json new file mode 100644 index 000000000..28e7be11d --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/configure/result.json @@ -0,0 +1,3 @@ +{ + "success": true +} \ No newline at end of file diff --git a/packages/material-parser/test/validate/fixtures/configure/src.json b/packages/material-parser/test/validate/fixtures/configure/src.json new file mode 100644 index 000000000..0bdce1623 --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/configure/src.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/packages/material-parser/test/validate/fixtures/props-basic-type/result.json b/packages/material-parser/test/validate/fixtures/props-basic-type/result.json new file mode 100644 index 000000000..28e7be11d --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/props-basic-type/result.json @@ -0,0 +1,3 @@ +{ + "success": true +} \ No newline at end of file diff --git a/packages/material-parser/test/validate/fixtures/props-basic-type/src.json b/packages/material-parser/test/validate/fixtures/props-basic-type/src.json new file mode 100644 index 000000000..e8fecb328 --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/props-basic-type/src.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/packages/material-parser/test/validate/fixtures/props-complex-type/result.json b/packages/material-parser/test/validate/fixtures/props-complex-type/result.json new file mode 100644 index 000000000..86a346c7d --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/props-complex-type/result.json @@ -0,0 +1,3 @@ +{ + "success": true +} \ No newline at end of file diff --git a/packages/material-parser/test/validate/fixtures/props-complex-type/src.json b/packages/material-parser/test/validate/fixtures/props-complex-type/src.json new file mode 100644 index 000000000..fdb40a5af --- /dev/null +++ b/packages/material-parser/test/validate/fixtures/props-complex-type/src.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/packages/material-parser/test/validate/index.ts b/packages/material-parser/test/validate/index.ts new file mode 100644 index 000000000..f37741cce --- /dev/null +++ b/packages/material-parser/test/validate/index.ts @@ -0,0 +1,52 @@ +import test from 'ava'; +import Ajv from 'ajv'; +import betterAjvErrors from 'better-ajv-errors'; + +import fs = require('fs'); +import yaml = require('js-yaml'); +import path = require('path'); +const schema = yaml.load(fs.readFileSync(path.resolve(__dirname, '../../schemas/schema.yml'), 'utf8')); +const ajv = new Ajv({jsonPointers: true}); +const validate = ajv.compile(schema); + +const shouldUpdate = process.env.UPDATE || false; + +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 (t) => { + const json = yaml.safeLoad(fs.readFileSync(path.resolve(fullPath, 'src.json'), 'utf-8')); + const result = JSON.parse(fs.readFileSync(path.resolve(fullPath, 'result.json'), 'utf-8')); + let validateResult: any = validate(json); + if (validateResult === true) { + validateResult = { + success: true, + }; + } else { + validateResult = { + success: false, + errors: validate.errors, + }; + } + + if (shouldUpdate) { + fs.writeFileSync( + path.resolve(fullPath, 'result.json'), + JSON.stringify(validateResult, null, 2), + 'utf-8', + ); + } else { + t.deepEqual(validateResult, result); + } + + if (validate.errors && validateResult.success === false && result.success === true) { + const output = betterAjvErrors(schema, json, validate.errors, {indent: 2}); + console.log(output); + } + }); +} \ No newline at end of file diff --git a/packages/material-parser/tsconfig.json b/packages/material-parser/tsconfig.json new file mode 100644 index 000000000..469dcb033 --- /dev/null +++ b/packages/material-parser/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib" + }, + "include": ["src/**/*"], + "exclude": ["schemas"] +} diff --git a/templates/src/index.d.ts b/templates/src/index.d.ts new file mode 100644 index 000000000..e69de29bb diff --git a/templates/src/index.js b/templates/src/index.js new file mode 100644 index 000000000..fb029417c --- /dev/null +++ b/templates/src/index.js @@ -0,0 +1,3 @@ +"use strict"; +// +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/templates/src/index.js.map b/templates/src/index.js.map new file mode 100644 index 000000000..67b67fe20 --- /dev/null +++ b/templates/src/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,EAAE"} \ No newline at end of file diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 7ad2bb75a..000000000 --- a/tslint.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint:recommended", - "tslint-config-prettier" - ], - "rulesDirectory": ["tslint-plugin-prettier"], - "rules": { - "prettier": true, - "object-literal-sort-keys": false, - "no-var-requires": false, - "no-console": false - } -} \ No newline at end of file