diff --git a/.eslintrc.js b/.eslintrc.js index b1f42868dfb8..2adc439e07cf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -48,6 +48,7 @@ module.exports = { 'react/prop-types': 0, 'react/no-find-dom-node': 0, 'react/no-unknown-property': 0, + 'import/no-named-default': 'off', quotes: [2, 'single', { avoidEscape: true, allowTemplateLiterals: true }], semi: [2, 'never'], 'simple-import-sort/imports': [2, { diff --git a/packages/postcss-unit-transform/.eslintrc.js b/packages/postcss-unit-transform/.eslintrc.js new file mode 100644 index 000000000000..f62166e98416 --- /dev/null +++ b/packages/postcss-unit-transform/.eslintrc.js @@ -0,0 +1,17 @@ +module.exports = { + parser: '@typescript-eslint/parser', + plugins: [ + '@typescript-eslint' + ], + parserOptions: { }, + extends: [ + 'eslint:recommended', + 'standard', + 'plugin:@typescript-eslint/recommended', + 'prettier' + ], + rules: { + '@typescript-eslint/no-unused-vars': 0, + '@typescript-eslint/no-var-requires': 0 + } +} diff --git a/packages/postcss-unit-transform/README.md b/packages/postcss-unit-transform/README.md new file mode 100644 index 000000000000..7bae3cd4a6f3 --- /dev/null +++ b/packages/postcss-unit-transform/README.md @@ -0,0 +1,3 @@ +# postcss-taro-unit-transform + +小程序的单位转换 diff --git a/packages/postcss-unit-transform/index.js b/packages/postcss-unit-transform/index.js new file mode 100644 index 000000000000..f2a0c1ebf46f --- /dev/null +++ b/packages/postcss-unit-transform/index.js @@ -0,0 +1,17 @@ +const postcss = require('postcss') + +module.exports = postcss.plugin('postcss-taro-unit-transform', plugin) + +function plugin (opts) { + return function (root) { + root.walkDecls(function (decl) { + let value = decl.value + value = value.replace(/([0-9.]+)px/ig, function (match, size) { + return (parseInt(size, 10) * 2) + 'px' + }).replace(/([0-9.]+)rpx/ig, function (match, size) { + return size + 'px' + }) + decl.value = value + }) + } +} diff --git a/packages/postcss-unit-transform/package.json b/packages/postcss-unit-transform/package.json new file mode 100644 index 000000000000..62c8519cc3f7 --- /dev/null +++ b/packages/postcss-unit-transform/package.json @@ -0,0 +1,19 @@ +{ + "name": "postcss-taro-unit-transform", + "version": "3.6.8", + "description": "小程序单位转换", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "luckyadam", + "license": "MIT", + "dependencies": { + "postcss": "^6.0.21", + "typescript": "^4.7.4" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.17.0", + "@typescript-eslint/parser": "^5.17.0" + } +} diff --git a/packages/postcss-unit-transform/yarn.lock b/packages/postcss-unit-transform/yarn.lock new file mode 100644 index 000000000000..c35b098af910 --- /dev/null +++ b/packages/postcss-unit-transform/yarn.lock @@ -0,0 +1,53 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&sync_timestamp=1589682811931&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +postcss@^6.0.21: + version "6.0.23" + resolved "https://registry.npm.taobao.org/postcss/download/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +supports-color@^5.3.0, supports-color@^5.4.0: + version "5.5.0" + resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" diff --git a/packages/taro-cli-convertor/package.json b/packages/taro-cli-convertor/package.json index 9e221d3fb691..b73c52fa77d5 100644 --- a/packages/taro-cli-convertor/package.json +++ b/packages/taro-cli-convertor/package.json @@ -30,16 +30,17 @@ "author": "O2Team", "license": "MIT", "dependencies": { + "@babel/generator": "^7.20.0", "@babel/template": "^7.20.0", "@babel/traverse": "^7.20.0", "@babel/types": "^7.20.0", + "@tarojs/cli": "workspace:*", "@tarojs/helper": "workspace:*", "@tarojs/taroize": "workspace:*", - "@tarojs/cli": "workspace:*", - "@tarojs/transformer-wx": "^2.2.10", - "postcss-taro-unit-transform": "^2.2.10", - "prettier": "^2.7.1", - "postcss": "^8.4.18" + "@tarojs/transformer-wx": "workspace:*", + "postcss": "^8.4.18", + "postcss-taro-unit-transform": "workspace:*", + "prettier": "^2.7.1" }, "devDependencies": { "@babel/parser": "^7.14.5", diff --git a/packages/taro-cli-convertor/src/index.ts b/packages/taro-cli-convertor/src/index.ts index 72f3890605e1..9f6729eb83ed 100644 --- a/packages/taro-cli-convertor/src/index.ts +++ b/packages/taro-cli-convertor/src/index.ts @@ -348,7 +348,7 @@ export default class Convertor { template( `import ${importName} from '${promoteRelativePath(path.relative(outputFilePath, importPath))}'`, babylonConfig - )() + )() as t.Statement ) }) } @@ -360,7 +360,7 @@ export default class Convertor { template( `import ${name} from '${promoteRelativePath(path.relative(sourceFilePath, component))}'`, babylonConfig - )() + )() as t.Statement ) }) } @@ -896,13 +896,17 @@ ${code} date, projectName, framework: this.framework, - compiler: 'webpack5' + compiler: 'webpack5', + typescript: false }) creator.template(templateName, path.join('config', 'dev.js'), path.join(configDir, 'dev.js'), { - framework: this.framework + framework: this.framework, + compiler: 'webpack5', + typescript: false }) creator.template(templateName, path.join('config', 'prod.js'), path.join(configDir, 'prod.js'), { - framework: this.framework + framework: this.framework, + typescript: false }) creator.template(templateName, 'project.config.json', path.join(this.convertRoot, 'project.config.json'), { description, diff --git a/packages/taro-transformer-wx/.eslintignore b/packages/taro-transformer-wx/.eslintignore new file mode 100644 index 000000000000..df0d70107835 --- /dev/null +++ b/packages/taro-transformer-wx/.eslintignore @@ -0,0 +1,4 @@ +/lib +/node_modules +t.js +tt.js \ No newline at end of file diff --git a/packages/taro-transformer-wx/.eslintrc.js b/packages/taro-transformer-wx/.eslintrc.js new file mode 100644 index 000000000000..3ec5c59edf52 --- /dev/null +++ b/packages/taro-transformer-wx/.eslintrc.js @@ -0,0 +1,44 @@ +module.exports = { + parser: '@typescript-eslint/parser', + plugins: [ + '@typescript-eslint' + ], + parserOptions: { }, + extends: [ + 'eslint:recommended', + 'standard', + 'plugin:@typescript-eslint/recommended', + 'prettier' + ], + rules: { + '@typescript-eslint/ban-ts-comment': 0, + '@typescript-eslint/explicit-function-return-type': 0, + '@typescript-eslint/explicit-module-boundary-types': 0, + '@typescript-eslint/indent': [2, 2], + '@typescript-eslint/member-delimiter-style': [1, { multiline: { delimiter: 'none' }, singleline: { delimiter: 'comma' } }], + '@typescript-eslint/no-empty-function': 0, + '@typescript-eslint/no-explicit-any': 0, + '@typescript-eslint/no-namespace': 0, + '@typescript-eslint/no-non-null-assertion': 0, + '@typescript-eslint/no-this-alias': 0, + '@typescript-eslint/no-unused-vars': 0, + '@typescript-eslint/no-use-before-define': [1, { functions: false, classes: false }], + '@typescript-eslint/no-var-requires': 0, + '@typescript-eslint/ban-types': 0, + 'no-restricted-globals': 'off', + 'no-cond-assign': 'off', + 'no-inner-declarations': 'off', + 'no-unmodified-loop-condition': 'off', + 'no-return-assign': 'off', + 'no-console': 'off', + 'no-self-compare': 'off', + 'no-control-regex': 'off', + 'no-new-func': 'off', + 'no-new': 'off', + 'prefer-const': 'off', + 'no-empty': 'off', + 'no-unsafe-optional-chaining': 'off', + 'no-prototype-builtins': 'off', + camelcase: 'off' + } +} diff --git a/packages/taro-transformer-wx/.gitignore b/packages/taro-transformer-wx/.gitignore new file mode 100644 index 000000000000..d1ba3df56449 --- /dev/null +++ b/packages/taro-transformer-wx/.gitignore @@ -0,0 +1,12 @@ +dist +node_modules +.cache +.DS_Store +lerna-debug.log +yarn-error.log +_book +.idea +lib +t.js +tt.js +test.js diff --git a/packages/taro-transformer-wx/.vscode/launch.json b/packages/taro-transformer-wx/.vscode/launch.json new file mode 100644 index 000000000000..ddfd37da6718 --- /dev/null +++ b/packages/taro-transformer-wx/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "name": "t.js", + "request": "launch", + "args": ["--runInBand"], + "cwd": "${workspaceFolder}", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "program": "${workspaceFolder}/t.js" + }, + { + "type": "node", + "name": "vscode-jest-tests", + "request": "launch", + "args": ["--runInBand"], + "cwd": "${workspaceFolder}", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "program": "${workspaceFolder}/node_modules/jest/bin/jest" + } + ] +} diff --git a/packages/taro-transformer-wx/CHANGELOG.md b/packages/taro-transformer-wx/CHANGELOG.md new file mode 100644 index 000000000000..a18f017a3cfa --- /dev/null +++ b/packages/taro-transformer-wx/CHANGELOG.md @@ -0,0 +1,43 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + + +## [0.0.69-beta.1](https://github.com/NervJS/taro/compare/v0.0.69-beta.0...v0.0.69-beta.1) (2018-07-09) + + +### Features + +* **transformer:** 支持 style 传入对象 ([d0be191](https://github.com/NervJS/taro/commit/d0be191)) + + + + + +## [0.0.67-beta.3](https://github.com/NervJS/taro/compare/v0.0.67-beta.2...v0.0.67-beta.3) (2018-07-04) + + +### Bug Fixes + +* **transformer:** 单独使用的自定义也加入 key ([a231a90](https://github.com/NervJS/taro/commit/a231a90)) +* **transformer:** 所有设置 if 条件都加入 block ([a32661e](https://github.com/NervJS/taro/commit/a32661e)) + + + + + +## [0.0.67-beta.1](https://github.com/NervJS/taro/compare/v0.0.67-beta.0...v0.0.67-beta.1) (2018-07-04) + + + + +**Note:** Version bump only for package @tarojs/transformer-wx + + +## [0.0.67-beta.0](https://github.com/NervJS/taro/compare/v0.0.66...v0.0.67-beta.0) (2018-07-04) + + +### Bug Fixes + +* **transformer:** 循环自定义组件的 iterator 重命名 ([a9cf461](https://github.com/NervJS/taro/commit/a9cf461)) diff --git a/packages/taro-transformer-wx/README.md b/packages/taro-transformer-wx/README.md new file mode 100644 index 000000000000..080b5161834b --- /dev/null +++ b/packages/taro-transformer-wx/README.md @@ -0,0 +1,3 @@ +# @tarojs/transformer-wx + +把 JSX 语法转换成可以在小程序运行的字符串模板。 \ No newline at end of file diff --git a/packages/taro-transformer-wx/index.js b/packages/taro-transformer-wx/index.js new file mode 100644 index 000000000000..6c4e96308ecf --- /dev/null +++ b/packages/taro-transformer-wx/index.js @@ -0,0 +1,4 @@ +var transform = require('./lib/src').default + +module.exports = transform +module.exports.default = transform diff --git a/packages/taro-transformer-wx/package.json b/packages/taro-transformer-wx/package.json new file mode 100644 index 000000000000..88e0986a86bc --- /dev/null +++ b/packages/taro-transformer-wx/package.json @@ -0,0 +1,112 @@ +{ + "name": "@tarojs/transformer-wx", + "version": "3.6.8", + "description": "Transfrom Nerv Component to Wechat mini program.", + "repository": { + "type": "git", + "url": "git+https://github.com/NervJS/taro.git" + }, + "main": "index.js", + "files": [ + "index.js", + "lib", + "cli.js", + "dist" + ], + "scripts": { + "test:cov": "jest --coverage && npm run lint", + "test": "jest packages/taro-transformer-wx/__tests__/base.spec.ts", + "testAll": "jest", + "dev": "tsc -w --pretty", + "lint": "tslint", + "build": "tsc" + }, + "author": "O2Team", + "license": "MIT", + "jest": { + "testEnvironment": "node", + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, + "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "jsx", + "json", + "node" + ], + "testPathIgnorePatterns": [ + "node_modules", + "utils" + ] + }, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "@babel/core": "^7.21.8", + "@babel/generator": "^7.21.4", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-decorators": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.14.5", + "@babel/plugin-proposal-optional-chaining": "^7.21.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-dynamic-import": "7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-flow-strip-types": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.14.5", + "@babel/preset-env": "^7.14.5", + "@babel/template": "7.21.9", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", + "babel-eslint": "^8.2.3", + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-mark-eval-scopes": "^0.4.3", + "babel-helper-remove-or-void": "^0.4.3", + "babel-plugin-danger-remove-unused-import": "^1.1.1", + "babel-plugin-minify-dead-code": "^1.3.2", + "babel-plugin-preval": "1.6.2", + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "babel-plugin-transform-class-properties": "^6.24.1", + "babel-plugin-transform-define": "^1.3.0", + "babel-plugin-transform-do-expressions": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-export-extensions": "^6.22.0", + "babel-plugin-transform-flow-strip-types": "^6.22.0", + "eslint-plugin-react": "7.10.0", + "eslint-plugin-taro": "2.2.19", + "html": "^1.0.0", + "lodash": "^4.17.21", + "lodash-es": "4.17.21", + "prettier": "^2.7.1", + "typescript": "^4.7.4" + }, + "devDependencies": { + "@tarojs/taro": "2.2.19", + "@types/babel-core": "6.25.6", + "@types/babel-generator": "6.25.3", + "@types/babel-template": "6.25.2", + "@types/babel-traverse": "6.25.3", + "@types/babel-types": "7.0.8", + "@types/eslint": "^7.14.3", + "@types/jest": "^22.2.3", + "@types/lodash": "^4.14.105", + "@types/node": "^9.6.2", + "babel-jest": "^29.5.0", + "eslint": "5.16.0", + "jest": "^29.3.1", + "jest-cli": "^29.3.1", + "ts-jest": "^29.0.5", + "tslint": "^5.10.0", + "tslint-config-prettier": "^1.10.0", + "tslint-config-standard": "^7.0.0" + }, + "publishConfig": { + "access": "public" + }, + "bugs": { + "url": "https://github.com/NervJS/taro/issues" + }, + "homepage": "https://github.com/NervJS/taro#readme" +} diff --git a/packages/taro-transformer-wx/src/adapter.ts b/packages/taro-transformer-wx/src/adapter.ts new file mode 100644 index 000000000000..c97f26587688 --- /dev/null +++ b/packages/taro-transformer-wx/src/adapter.ts @@ -0,0 +1,129 @@ +export const enum Adapters { + weapp = 'weapp', + swan = 'swan', + alipay = 'alipay', + quickapp = 'quickapp', + tt = 'tt', + qq = 'qq', + jd = 'jd' +} + +interface Adapter { + if: string + else: string + elseif: string + for: string + forItem: string + forIndex: string + key: string + type: Adapters +} + +const weixinAdapter: Adapter = { + if: 'wx:if', + else: 'wx:else', + elseif: 'wx:elif', + for: 'wx:for', + forItem: 'wx:for-item', + forIndex: 'wx:for-index', + key: 'wx:key', + type: Adapters.weapp +} + +const swanAdapter: Adapter = { + if: 's-if', + else: 's-else', + elseif: 's-elif', + for: 's-for', + forItem: 's-for-item', + forIndex: 's-for-index', + key: 's-key', + type: Adapters.swan +} + +const alipayAdapter: Adapter = { + if: 'a:if', + else: 'a:else', + elseif: 'a:elif', + for: 'a:for', + forItem: 'a:for-item', + forIndex: 'a:for-index', + key: 'a:key', + type: Adapters.alipay +} + +const ttAdapter: Adapter = { + if: 'tt:if', + else: 'tt:else', + elseif: 'tt:elif', + for: 'tt:for', + forItem: 'tt:for-item', + forIndex: 'tt:for-index', + key: 'tt:key', + type: Adapters.tt +} + +const quickappAdapter: Adapter = { + if: 'if', + else: 'else', + elseif: 'elif', + for: 'for', + forItem: 'for-item', + forIndex: 'for-index', + key: 'key', + type: Adapters.quickapp +} + +const qqAdapter: Adapter = { + if: 'qq:if', + else: 'qq:else', + elseif: 'qq:elif', + for: 'qq:for', + forItem: 'qq:for-item', + forIndex: 'qq:for-index', + key: 'qq:key', + type: Adapters.qq +} + +const jdAdapter: Adapter = { + if: 'jd:if', + else: 'jd:else', + elseif: 'jd:elif', + for: 'jd:for', + forItem: 'jd:for-item', + forIndex: 'jd:for-index', + key: 'jd:key', + type: Adapters.jd +} + +export let Adapter: Adapter = weixinAdapter + +export const isNewPropsSystem = () => { + return [Adapters.weapp, Adapters.swan, Adapters.tt, Adapters.qq, Adapters.alipay, Adapters.quickapp, Adapters.jd].includes(Adapter.type) +} + +export function setAdapter (adapter: Adapters) { + switch (adapter.toLowerCase()) { + case Adapters.swan: + Adapter = swanAdapter + break + case Adapters.alipay: + Adapter = alipayAdapter + break + case Adapters.tt: + Adapter = ttAdapter + break + case Adapters.quickapp: + Adapter = quickappAdapter + break + case Adapters.qq: + Adapter = qqAdapter + break + case Adapters.jd: + Adapter = jdAdapter + break + default: + Adapter = weixinAdapter + break + } +} diff --git a/packages/taro-transformer-wx/src/class-method-renamer.ts b/packages/taro-transformer-wx/src/class-method-renamer.ts new file mode 100644 index 000000000000..44836cdef935 --- /dev/null +++ b/packages/taro-transformer-wx/src/class-method-renamer.ts @@ -0,0 +1,77 @@ +import { NodePath,Visitor } from '@babel/traverse' +import * as t from '@babel/types' + +import { isDerivedFromThis } from './utils' + +function buildMethodName (n: string) { + return `render${n.charAt(0).toUpperCase() + n.slice(1)}` +} + +export const buildVistor = () => { + const renameMap = new Map() + + const classMethodRenamer: () => { + visitor: Visitor + } = () => { + return { + visitor: { + JSXElement (path) { + let methodName = '' + const classMethod = path.findParent(p => p.isClassMethod()) + if (classMethod && classMethod.isClassMethod() && t.isIdentifier(classMethod.node.key)) { + methodName = (classMethod.node.key as any).name + if (methodName.startsWith('render') || methodName === 'constructor') { + return + } + classMethod.node.key = t.identifier(buildMethodName(methodName)) + } + + const classProp = path.findParent(p => p.isClassProperty()) + if (classProp && classProp.isClassProperty()) { + methodName = (classProp.node.key as any).name + if (methodName.startsWith('render')) { + return + } + if (!t.isArrowFunctionExpression(classProp.node.value)) { + return + } + classProp.replaceWith(t.classMethod( + 'method', + t.identifier(buildMethodName(methodName)), + (classProp.node.value as any).params, + t.isBlockStatement((classProp.node.value as any).body) ? (classProp.node.value as any).body : t.blockStatement([ + t.returnStatement((classProp.node.value as any).body) + ]) + )) + return + } + + if (methodName.length > 0 && !methodName.startsWith('render')) { + renameMap.set(methodName, buildMethodName(methodName)) + } + }, + Identifier (path: NodePath) { + const name = path.node.name + if (renameMap.has(name)) { + const memberExpr = path.parentPath + if (memberExpr.isMemberExpression() && memberExpr.parentPath.isCallExpression()) { + const object = memberExpr.get('object') + if (t.isThisExpression(object)) { + path.replaceWith(t.identifier(buildMethodName(name))) + } else if (t.isIdentifier(object) && isDerivedFromThis(path.scope, object.name)) { + memberExpr.replaceWith(t.memberExpression( + t.thisExpression(), + t.identifier(buildMethodName(name)) + )) + } + } else if (memberExpr.isCallExpression() && isDerivedFromThis(path.scope, name)) { + path.scope.rename(name, buildMethodName(name)) + } + } + } + } + } + } + + return classMethodRenamer +} diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts new file mode 100644 index 000000000000..c4da5379fce8 --- /dev/null +++ b/packages/taro-transformer-wx/src/class.ts @@ -0,0 +1,1169 @@ +import generate from '@babel/generator' +import { NodePath } from '@babel/traverse' +import * as t from '@babel/types' +import { get as safeGet, kebabCase, set as safeSet,uniqueId } from 'lodash' +import { extname, sep } from 'path' + +import { Adapter, Adapters, isNewPropsSystem } from './adapter' +import { ANONYMOUS_FUNC, CLASS_COMPONENT_UID, COMPONENTS_PACKAGE_NAME, CONTEXT_PROVIDER,DEFAULT_Component_SET, DEFAULT_Component_SET_COPY, FN_PREFIX } from './constant' +import { isTestEnv } from './env' +import { Status } from './functional' +import { LoopRef } from './interface' +import { findJSXAttrByName } from './jsx' +import { RenderParser } from './render' +import { injectRenderPropsEmiter } from './render-props' +import { + codeFrameError, + createRandomLetters, + findFirstIdentifierFromMemberExpression, + findMethodName, + generateAnonymousState, + getSlotName, + getSuperClassPath, + hasComplexExpression, + incrementId, + isArrayMapCallExpression, + isContainJSXElement, + isContainStopPropagation, + isDerivedFromProps, + pathResolver} from './utils' + +const stopPropagationExpr = require('@babel/template').default(`typeof e === 'object' && e.stopPropagation && e.stopPropagation()`) + +// const stopPropagationExpr = require('babel-template')(`typeof e === 'object' && e.stopPropagation && e.stopPropagation()`) + +type ClassMethodsMap = Map> + +const NODE_MODULES = 'node_modules' + +function buildConstructor () { + const ctor = t.classMethod( + 'constructor', + t.identifier('constructor'), + [t.identifier('props')], + t.blockStatement([ + t.expressionStatement( + t.callExpression(t.identifier('super'), [ + t.identifier('props') + ]) + ) + ]) + ) + return ctor +} + +function processThisPropsFnMemberProperties ( + member: t.MemberExpression, + path: NodePath, + args: Array +) { + const propertyArray: string[] = [] + function traverseMember (member: t.MemberExpression) { + const object = member.object + const property = member.property + + if (t.isIdentifier(property)) { + propertyArray.push(property.name) + } + + if (t.isMemberExpression(object)) { + if (t.isThisExpression(object.object) && + t.isIdentifier(object.property) && + object.property.name === 'props' + ) { + if (!isNewPropsSystem()) { + path.replaceWith( + t.callExpression( + t.memberExpression(t.thisExpression(), t.identifier('__triggerPropsFn')), + [t.stringLiteral(propertyArray.reverse().join('.')), t.callExpression( + t.memberExpression(t.arrayExpression([t.nullLiteral()]), t.identifier('concat')), + [t.arrayExpression(args)] + )] + ) + ) + } + } + traverseMember(object) + } + } + traverseMember(member) +} + +interface Result { + template: string + components: { + name: string + path: string + type: string + }[] + componentProperies: string[] +} + +interface Ref { + refName?: string + type: 'component' | 'dom' + id: string + fn?: t.FunctionExpression | t.ArrowFunctionExpression | t.MemberExpression +} + +class Transformer { + public result: Result = { + template: '', + components: [], + componentProperies: [] + } + + private methods: ClassMethodsMap + private renderJSX: Map> = new Map() + private refIdMap: Map, Set> = new Map() + private initState: Set = new Set() + private customComponents: Map = new Map() + private anonymousMethod: Map = new Map() + private moduleNames: string[] + private classPath: NodePath + private customComponentNames = new Set() + private usedState = new Set() + private componentProperies: Set + private sourcePath: string + private sourceDir: string + private refs: Ref[] = [] + private loopRefs: Map = new Map() + private anonymousFuncCounter = incrementId() + private importJSXs = new Set() + private refObjExpr: t.ObjectExpression[] = [] + + constructor ( + path: NodePath, + sourcePath: string, + componentProperies: string[], + sourceDir: string, + methods: ClassMethodsMap + ) { + this.classPath = path + this.sourcePath = sourcePath + this.sourceDir = sourceDir + this.moduleNames = Object.keys(path.scope.getAllBindings('module')) + this.componentProperies = new Set(componentProperies) + this.methods = methods + this.compile() + } + + setMultipleSlots () { + const body = this.classPath.node.body.body + if (body.some(c => t.isClassProperty(c) && (c.key as any).name === 'multipleSlots')) { + return + } + const multipleSlots: any = t.classProperty(t.identifier('multipleSlots'), t.booleanLiteral(true)) + multipleSlots.static = true + body.push(multipleSlots) + } + + createStringRef (componentName: string, id: string, refName: string) { + this.refs.push({ + type: DEFAULT_Component_SET.has(componentName) ? 'dom' : 'component', + id, + refName + }) + } + + createFunctionRef (componentName: string, id: string, fn) { + this.refs.push({ + type: DEFAULT_Component_SET.has(componentName) ? 'dom' : 'component', + id, + fn + }) + } + + handleRefs () { + this.refObjExpr = this.refs.map(ref => { + return t.objectExpression([ + t.objectProperty( + t.identifier('type'), + t.stringLiteral(ref.type) + ), + t.objectProperty( + t.identifier('id'), + t.stringLiteral(ref.id) + ), + t.objectProperty( + t.identifier('refName'), + t.stringLiteral(ref.refName || '') + ), + t.objectProperty( + t.identifier('fn'), + ref.fn ? ref.fn : t.nullLiteral() + ) + ]) + }) + + const _constructor = this.classPath.node.body.body.find(item => { + const constructorName = isTestEnv ? 'constructor' : '_constructor' + if (t.isClassMethod(item) && t.isIdentifier(item.key) && item.key.name === constructorName) { + return true + } + return false + }) + + if (_constructor && t.isClassMethod(_constructor) && Adapter.type !== Adapters.quickapp) { + _constructor.body.body.push( + t.expressionStatement(t.assignmentExpression( + '=', + t.memberExpression(t.thisExpression(), t.identifier('$$refs')), + t.newExpression(t.memberExpression(t.identifier('Taro'), t.identifier('RefsArray')), []) + )) + ) + } + } + + setComponentPath () { + let componentPath + const nodeModulesIndex = this.sourcePath.indexOf(NODE_MODULES) + if (nodeModulesIndex >= 0) { + componentPath = this.sourcePath.substring(nodeModulesIndex) + } else { + componentPath = this.sourcePath.replace(this.sourceDir, '') + } + componentPath = componentPath.replace(extname(componentPath), '') + componentPath = componentPath.split(sep).join('/') + if (componentPath.startsWith('/')) { + componentPath = componentPath.slice(1) + } + const $$componentPath: any = t.classProperty(t.identifier('$$componentPath'), t.stringLiteral(componentPath)) + $$componentPath.static = true + this.classPath.node.body.body.push($$componentPath) + } + + buildAnonyMousFunc = (jsxExpr: NodePath, attr: NodePath, expr: t.Expression) => { + const exprPath = attr.get('value.expression') as any + const stemParent = jsxExpr.getStatementParent() as any + const counter = this.anonymousFuncCounter() + const anonymousFuncName = `${ANONYMOUS_FUNC}${counter}` + const isCatch = isContainStopPropagation(exprPath as any) + const classBody = this.classPath.node.body.body + const loopCallExpr = jsxExpr.findParent(p => isArrayMapCallExpression(p as any)) as NodePath + let index: t.Identifier + const self = this + if (loopCallExpr) { + index = safeGet(loopCallExpr, 'node.arguments[0].params[1]') as any + if (!t.isIdentifier(index)) { + index = t.identifier('__index' + counter) + safeSet(loopCallExpr, 'node.arguments[0].params[1]', index) + } + classBody.push(t.classProperty(t.identifier(anonymousFuncName + 'Map'), t.objectExpression([]))) + const indexKey = (stemParent as any).scope.generateUid('$indexKey') + // tslint:disable-next-line: no-inner-declarations + function findParentLoopCallExprIndices (callExpr: NodePath) { + const indices: Set = new Set([]) + // tslint:disable-next-line: no-conditional-assignment + while (callExpr = callExpr.findParent(p => isArrayMapCallExpression(p as any) && p !== callExpr) as NodePath) { + let index = safeGet(callExpr, 'node.arguments[0].params[1]') as any + if (!t.isIdentifier(index)) { + index = t.identifier('__index' + self.anonymousFuncCounter()) as any + safeSet(callExpr, 'node.arguments[0].params[1]', index) + } + indices.add(index as any) + } + return indices + } + const indices = [...findParentLoopCallExprIndices(loopCallExpr)].reverse() + const indexKeyDecl = t.variableDeclaration('const', [t.variableDeclarator( + t.identifier(indexKey), + indices.length === 0 + ? t.binaryExpression('+', t.stringLiteral(createRandomLetters(5)), index) + : t.templateLiteral( + [ + t.templateElement({ raw: createRandomLetters(5) }), + ...indices.map(() => t.templateElement({ raw: '-' })), + t.templateElement({ raw: '' }) + ], + [ + ...indices.map(i => t.identifier(i.name)), + index + ] + ) + )]) + + const func = loopCallExpr.node.arguments[0] + if (t.isArrowFunctionExpression(func)) { + const body = loopCallExpr.get('arguments')[0].get('body.body') as any + if (!t.isBlockStatement(func.body)) { + func.body = t.blockStatement([ + indexKeyDecl, + t.returnStatement(func.body) + ]) + } else { + // func.body.body.push(indexKeyDecl) + // 只有 path 的方法才能触发 traverse + body[body.length - 1].insertBefore(indexKeyDecl) + } + const arrayFunc = t.memberExpression( + t.memberExpression(t.thisExpression(), t.identifier(anonymousFuncName + 'Map')), + t.identifier(indexKey), + true + ) + classBody.push( + t.classMethod('method', t.identifier(anonymousFuncName), [t.identifier(indexKey), t.restElement(t.identifier('e'))], t.blockStatement([ + isCatch ? stopPropagationExpr() : t.emptyStatement(), + t.returnStatement(t.logicalExpression('&&', arrayFunc, t.callExpression(arrayFunc, [t.spreadElement(t.identifier('e'))]))) + ])) + ) + exprPath.replaceWith(t.callExpression( + t.memberExpression( + t.memberExpression(t.thisExpression(), t.identifier(anonymousFuncName)), + t.identifier('bind') + ), + [t.thisExpression(), t.identifier(indexKey)] + )) + body[body.length - 1].insertBefore( + t.expressionStatement(t.assignmentExpression( + '=', + arrayFunc, + expr + )) + ) + } else { + throw codeFrameError(func, '返回 JSX 的循环语句必须使用箭头函数') + } + } else { + classBody.push( + t.classMethod('method', t.identifier(anonymousFuncName), [t.identifier('e')], t.blockStatement([ + isCatch ? t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('e'), t.identifier('stopPropagation')), [])) : t.emptyStatement() + ])) + ) + exprPath.replaceWith(t.memberExpression(t.thisExpression(), t.identifier(anonymousFuncName))) + stemParent.insertBefore( + t.expressionStatement(t.assignmentExpression( + '=', + t.memberExpression(t.thisExpression(), t.identifier(anonymousFuncName)), + expr + )) + ) + } + } + + private jsxClosureFuncDecl = new Set>() + + renameJSXClassFunc = (propName: string, methodName: string, callPath: NodePath, args: any[], isClosure = false) => { + const parentPath = callPath.parentPath as any + if (parentPath.isCallExpression()) { + return + } + const callee = !isClosure + ? t.memberExpression( + t.thisExpression(), + t.identifier(`_create${propName.slice(6)}Data`) + ) + : t.identifier(propName) + const templateAttr = [ + t.jSXAttribute(t.jSXIdentifier('is'), t.stringLiteral(propName)), + t.jSXAttribute(t.jSXIdentifier('data'), t.jSXExpressionContainer( + t.callExpression( + t.callExpression(callee, [t.binaryExpression( + '+', + methodName === 'render' + ? t.identifier('__prefix') + : t.identifier(CLASS_COMPONENT_UID), + t.stringLiteral(createRandomLetters(10)) + )]), + args + ) + )) + ] + this.jsxClosureFuncDecl.add(parentPath) + callPath.replaceWith(t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('Template'), templateAttr), + t.jSXClosingElement(t.jSXIdentifier('Template')), + [], + false + )) + } + + traverse () { + const self = this + let hasRender = false + self.classPath.traverse({ + JSXOpeningElement: (path) => { + const jsx = path.node + const attrs = jsx.attributes + if (!t.isJSXIdentifier(jsx.name)) { + return + } + const loopCallExpr = path.findParent(p => isArrayMapCallExpression(p as any)) + const componentName = jsx.name.name + const refAttr = findJSXAttrByName(attrs as any, 'ref') + if (!refAttr) { + return + } + const idAttr = findJSXAttrByName(attrs as any, 'id') + let id: string = createRandomLetters(5) + let idExpr: t.Expression + if (!idAttr) { + if (loopCallExpr && loopCallExpr.isCallExpression()) { + const [ func ] = loopCallExpr.node.arguments + let indexId: t.Identifier | null = null + if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) { + const params = func.params as t.Identifier[] + indexId = params[1] + } + if (indexId === null || !t.isIdentifier(indexId)) { + throw codeFrameError(path.node, '在循环中使用 ref 必须暴露循环的第二个参数 `index`') + } + attrs.push(t.jSXAttribute(t.jSXIdentifier('id'), t.jSXExpressionContainer( + t.binaryExpression('+', t.stringLiteral(id), indexId) + ))) + } else { + attrs.push(t.jSXAttribute(t.jSXIdentifier('id'), t.stringLiteral(id))) + } + } else { + const idValue = idAttr.value + if (t.isStringLiteral(idValue)) { + id = idValue.value + } else if (t.isJSXExpressionContainer(idValue)) { + if (t.isStringLiteral(idValue.expression)) { + id = idValue.expression.value + } else { + idExpr = idValue.expression as t.TSNonNullExpression + } + } + } + if (t.isStringLiteral(refAttr.value)) { + if (loopCallExpr) { + throw codeFrameError(refAttr, '循环中的 ref 只能使用函数。') + } + this.createStringRef(componentName, id, refAttr.value.value) + } + if (t.isJSXExpressionContainer(refAttr.value)) { + const expr = refAttr.value.expression + if (t.isStringLiteral(expr)) { + if (loopCallExpr) { + throw codeFrameError(refAttr, '循环中的 ref 只能使用函数。') + } + this.createStringRef(componentName, id, expr.value) + } else if (t.isArrowFunctionExpression(expr) || t.isMemberExpression(expr)) { + const type = DEFAULT_Component_SET.has(componentName) ? 'dom' : 'component' + if (loopCallExpr) { + this.loopRefs.set(path.parentPath.node as t.JSXElement, { + id: idExpr! || id, + fn: expr, + type, + component: path.parentPath as NodePath + }) + } else { + this.refs.push({ + type, + id, + fn: expr + }) + } + } else if (t.isIdentifier(expr)) { + const type = DEFAULT_Component_SET.has(componentName) ? 'dom' : 'component' + const binding = path.scope.getBinding(expr.name) + const decl = t.expressionStatement( + t.assignmentExpression( + '=', + t.memberExpression(t.thisExpression(), expr), + expr + ) + ) + if (binding) { + binding.path.parentPath?.insertAfter(decl) + } else { + path.getStatementParent()?.insertBefore(decl) + } + this.refs.push({ + type, + id, + fn: t.memberExpression(t.thisExpression(), expr) + }) + } else { + throw codeFrameError(refAttr, 'ref 仅支持传入字符串、匿名箭头函数和 class 中已声明的函数') + } + } + if (Adapters.alipay === Adapter.type) { + attrs.push(t.jSXAttribute( + t.jSXIdentifier('onTaroCollectChilds'), + t.jSXExpressionContainer(t.memberExpression(t.thisExpression(), t.identifier('$collectChilds'))) + )) + } + for (const [index, attr] of attrs.entries()) { + if (attr === refAttr) { + attrs.splice(index, 1) + } + } + }, + ClassMethod (classMethodPath) { + const node = classMethodPath.node + if (t.isIdentifier(node.key)) { + const methodName = node.key.name + self.methods.set(methodName, classMethodPath as any) + if (methodName.startsWith('render')) { + if (!isContainJSXElement(classMethodPath as any)) { + throw codeFrameError(classMethodPath.node, '以 render 开头的类函数必须返回 JSX,否则会导致渲染失败。如果是为了渲染字符串,建议更名。\n' + + '以 VSCode 为例:右键点击选择方法名,点击 rename symbol(重命名符号),输入新方法名。') + } + hasRender = true + self.renderJSX.set(methodName, classMethodPath as any) + self.refIdMap.set(classMethodPath as any, new Set([])) + classMethodPath.traverse({ + ReturnStatement (returnPath) { + const arg = returnPath.node.argument + const ifStem = returnPath.findParent(p => p.isIfStatement()) + // tslint:disable-next-line: strict-type-predicates + if (ifStem && classMethodPath.node.body.body.some(s => s === ifStem.node) && ifStem.isIfStatement() && arg === null) { + const consequent = ifStem.get('consequent') + if (t.isBlockStatement(consequent) && (consequent as any).node.body.includes(returnPath.node)) { + returnPath.get('argument').replaceWith(t.nullLiteral()) + } + } + }, + CallExpression: { + enter (callPath: NodePath) { + const callee = callPath.get('callee') + const args = callPath.node.arguments + if (callee.isMemberExpression()) { + const { object, property } = callee.node + if (t.isThisExpression(object) && t.isIdentifier(property) && property.name.startsWith('render')) { + const propName = property.name + if (!self.methods.has(propName)) { + const o = getSuperClassPath(self.classPath) + if (o) { + const p = o.resolvePath.endsWith('.js') ? o.resolvePath.slice(0, o.resolvePath.length - 3) : o.resolvePath + self.importJSXs.add(``) + } + } + self.renameJSXClassFunc(propName, methodName, callPath, args) + } + } + if (callee.isIdentifier()) { + const nodeName = callee.node.name + if (nodeName.startsWith('renderClosure')) { + self.renameJSXClassFunc(nodeName, methodName, callPath, args, true) + } + } + }, + exit (callPath: NodePath) { + const jsxExpr = callPath.parentPath + if (!jsxExpr.isJSXExpressionContainer()) { + return + } + const jsxAttr = jsxExpr.parentPath + if (!jsxAttr.isJSXAttribute()) { + return + } + const { name: attrName } = jsxAttr.node + if (!t.isJSXIdentifier(attrName, { name: 'data' })) { + return + } + generateAnonymousState(callPath.scope, callPath as any, self.refIdMap.get(classMethodPath as any)!) + } + } + }) + } + if (methodName.startsWith('render')) { + self.renderJSX.set(methodName, classMethodPath as any) + self.refIdMap.set(classMethodPath as any, new Set([])) + } + if (methodName === 'constructor') { + classMethodPath.traverse({ + AssignmentExpression (p) { + if ( + t.isMemberExpression(p.node.left) && + t.isThisExpression(p.node.left.object) && + t.isIdentifier(p.node.left.property) && + p.node.left.property.name === 'state' && + t.isObjectExpression(p.node.right) + ) { + const properties = p.node.right.properties + properties.forEach(p => { + if (t.isObjectProperty(p) && t.isIdentifier(p.key)) { + self.initState.add(p.key.name) + } + }) + } + } + }) + } + } + }, + ClassBody: { + exit (path) { + const node = path.node as t.ClassBody + if (!hasRender) { + node.body.push(t.classMethod('method', t.identifier('_createData'), [], t.blockStatement([]))) + } + } + }, + IfStatement: (path) => { + const test = path.get('test') as NodePath + const consequent = path.get('consequent') as NodePath + if (isContainJSXElement(consequent) && hasComplexExpression(test as any)) { + this.renderJSX.forEach(method => { + const renderMethod = path.findParent(p => method === p) + if (renderMethod && renderMethod.isClassMethod()) { + const scope = renderMethod && renderMethod.scope || path.scope + generateAnonymousState(scope, test, this.refIdMap.get(renderMethod as any)!, true) + } + }) + } + }, + ClassProperty (path) { + const { key: { name }, value } = (path.node as any) + if (t.isArrowFunctionExpression(value) || t.isFunctionExpression(value)) { + self.methods.set(name, path as any) + if (name.startsWith('render')) { + path.replaceWith(t.classMethod( + 'method', + t.identifier(name), + value.params, + t.isBlockStatement(value.body) ? value.body : t.blockStatement([ + t.returnStatement(value.body) + ]) + )) + } + } + if (name === 'state' && t.isObjectExpression(value)) { + value.properties.forEach(p => { + if (t.isObjectProperty(p)) { + if (t.isIdentifier(p.key)) { + self.initState.add(p.key.name) + } + } + }) + } + }, + JSXExpressionContainer (path) { + const attr = path.findParent(p => p.isJSXAttribute()) as NodePath + if (!attr) { + const expr = path.get('expression') + if (expr.isBooleanLiteral() || expr.isNullLiteral()) { + path.remove() + return + } + } + const isFunctionProp = attr && typeof attr.node.name.name === 'string' && attr.node.name.name.startsWith('on') + let renderMethod: NodePath + self.renderJSX.forEach(method => { + renderMethod = path.findParent(p => method === p) as NodePath + }) + + const jsxReferencedIdentifiers = self.refIdMap.get(renderMethod!)! + + path.traverse({ + MemberExpression (path) { + const sibling = path.getSibling('property') + if ( + path.get('object').isThisExpression() && + (path.get('property').isIdentifier({ name: 'props' }) || path.get('property').isIdentifier({ name: 'state' })) && + sibling.isIdentifier() + ) { + if (!isFunctionProp) { + self.usedState.add(sibling.node.name) + } + } + } + }) + + const expression = path.get('expression') as NodePath + const scope = renderMethod! && renderMethod!.scope || path.scope + const calleeExpr = expression.get('callee') + const parentPath = path.parentPath + if ( + hasComplexExpression(expression as NodePath) && + !isFunctionProp && + !(calleeExpr && + t.isMemberExpression(calleeExpr) && + (calleeExpr as any).get('object').isMemberExpression() && + (calleeExpr as any).get('property').isIdentifier({ name: 'bind' })) // is not bind + ) { + const calleeName = t.isIdentifier(calleeExpr) && calleeExpr.name + if (typeof calleeName === 'string' && calleeName.startsWith('render') && isDerivedFromProps((calleeExpr as any).scope, calleeName)) { + return + } + if (t.isMemberExpression(calleeExpr) && isDerivedFromProps((calleeExpr as any).scope, findFirstIdentifierFromMemberExpression(calleeExpr).name)) { + const idName = findFirstIdentifierFromMemberExpression(calleeExpr).name + if (isDerivedFromProps((calleeExpr as any).scope, idName) && t.isIdentifier(calleeExpr.property) && calleeExpr.property.name.startsWith('render')) { + return + } + } + generateAnonymousState(scope, expression, jsxReferencedIdentifiers) + } else { + if (parentPath.isJSXAttribute()) { + if (!(expression.isMemberExpression() || expression.isIdentifier()) && parentPath.node.name.name === 'key') { + generateAnonymousState(scope, expression, jsxReferencedIdentifiers) + } + } + } + if (!attr) return + const key = attr.node.name + const value = attr.node.value + if (!t.isJSXIdentifier(key)) { + return + } + + const jsx = path.findParent(p => p.isJSXOpeningElement()) as NodePath + + if (t.isJSXIdentifier(key) && key.name.startsWith('on') && t.isJSXExpressionContainer(value)) { + const expr = value.expression + if ( + t.isCallExpression(expr) && + t.isMemberExpression(expr.callee) && + t.isIdentifier(expr.callee.property, { name: 'bind' }) && + !Status.isSFC + ) { + if ( + (!isNewPropsSystem()) || + (t.isJSXIdentifier(jsx.node.name) && DEFAULT_Component_SET.has(jsx.node.name.name)) + ) { + self.buildPropsAnonymousFunc(attr, expr, true, path) + } + } else if (t.isMemberExpression(expr)) { + if ( + (!isNewPropsSystem()) || + (t.isJSXIdentifier(jsx.node.name) && DEFAULT_Component_SET.has(jsx.node.name.name)) + ) { + self.buildPropsAnonymousFunc(attr, expr as any, false, path as any) + } + } else if (!t.isLiteral(expr)) { + self.buildAnonyMousFunc(path as any, attr, expr as any) + } else { + throw codeFrameError(path.node, '组件事件传参不能传入基本类型') + } + } + if (!jsx) return + const jsxName = jsx.node.name + if (!t.isJSXIdentifier(jsxName)) return + if (expression.isJSXElement()) return + if (DEFAULT_Component_SET.has(jsxName.name) || expression.isIdentifier() || expression.isMemberExpression() || expression.isLiteral() || expression.isLogicalExpression() || expression.isConditionalExpression() || key.name.startsWith('on') || expression.isCallExpression()) return + if (isContainJSXElement(path as any)) return + generateAnonymousState(scope, expression, jsxReferencedIdentifiers) + }, + Identifier (path) { + const isStartWithRender = /^render[A-Z]/.test(path.node.name) + const isInJSXExprContainer = !!path.findParent(p => p.isJSXExpressionContainer()) + if (!isInJSXExprContainer) { + return + } + if (path.node.name === 'children' || isStartWithRender) { + const parentPath = path.parentPath + const slot = t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('slot'), [], true), t.jSXClosingElement(t.jSXIdentifier('slot')), [], true) + if (isStartWithRender) { + slot.openingElement.attributes.push(t.jSXAttribute(t.jSXIdentifier('name'), t.stringLiteral(getSlotName(path.node.name)))) + self.setMultipleSlots() + } + if (parentPath.isCallExpression() && parentPath.parentPath.isJSXExpressionContainer()) { + if (isDerivedFromProps(path.scope, path.node.name)) { + injectRenderPropsEmiter(parentPath as any, path.node.name) + parentPath.replaceWith(slot) + } + } + if (parentPath.isMemberExpression() && parentPath.parentPath.isCallExpression()) { + if (isDerivedFromProps(path.scope, findFirstIdentifierFromMemberExpression(parentPath.node as any).name)) { + injectRenderPropsEmiter(parentPath.parentPath as any, path.node.name) + parentPath.parentPath.replaceWith(slot) + } + } + if ( + parentPath.isMemberExpression() && + parentPath.isReferenced() && + ( + parentPath.parentPath.isJSXExpressionContainer() || + parentPath.parentPath.isLogicalExpression() || + parentPath.parentPath.isConditionalExpression() + ) + ) { + const object = parentPath.get('object') + if (t.isIdentifier(object)) { + const objectName = object.name + if (isDerivedFromProps(path.scope, objectName)) { + parentPath.replaceWith(slot) + } + } + } else if (path.isReferencedIdentifier()) { + if (isDerivedFromProps(path.scope, 'children')) { + parentPath.replaceWith(slot) + } + } + } + }, + JSXElement (path) { + const id = path.node.openingElement.name + if ( + t.isJSXIdentifier(id) && + !DEFAULT_Component_SET.has(id.name) + ) { + if (self.moduleNames.indexOf(id.name) !== -1) { + const name = id.name + const binding = self.classPath.scope.getBinding(name) + if (binding && t.isImportDeclaration(binding.path.parent)) { + const sourcePath = binding.path.parent.source.value + const specs = binding.path.parent.specifiers.filter(s => t.isImportSpecifier(s)) as Array + if (binding.path.isImportDefaultSpecifier()) { + self.customComponents.set(name, { + sourcePath, + type: 'default' + }) + } else { + const spec = specs.find(s => s.local.name === name && (s.imported as any).name !== name) + if (spec) { + self.customComponents.set(name, { + sourcePath, + type: 'pattern', + imported: (spec.imported as t.StringLiteral).value + }) + } else { + self.customComponents.set(name, { + sourcePath, + type: 'pattern' + }) + } + } + } + } + + if (id.name.endsWith(CONTEXT_PROVIDER)) { + const valueAttr = path.node.openingElement.attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && a.name.name === 'value') + const contextName = id.name.slice(0, id.name.length - CONTEXT_PROVIDER.length) + if (valueAttr && t.isJSXAttribute(valueAttr)) { + if (t.isJSXElement(valueAttr.value)) { + throw codeFrameError(valueAttr.value, 'Provider 的 value 只能传入一个字符串或普通表达式,不能传入 JSX') + } else { + const value = t.isStringLiteral(valueAttr.value) ? valueAttr.value : (valueAttr.value as t.JSXExpressionContainer)!.expression + const expr = t.expressionStatement(t.callExpression( + t.memberExpression(t.identifier(contextName), t.identifier('Provider')), + [value as any] + )) + path.getStatementParent()?.insertBefore(expr) + path.replaceWith(t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('Block'), []), + t.jSXClosingElement(t.jSXIdentifier('Block')), + path.node.children as any + )) + } + } + } + } + }, + MemberExpression: (path) => { + const object = path.get('object') + const property = path.get('property') + if ( + !( + object.isThisExpression() && property.isIdentifier({ name: 'props' }) + ) + ) { + return + } + + const parentPath = path.parentPath + if (parentPath.isMemberExpression()) { + const siblingProp = parentPath.get('property') + if (t.isIdentifier(siblingProp)) { + const name = siblingProp.name + if (name === 'children') { + parentPath.replaceWith(t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('slot'), [], true), t.jSXClosingElement(t.jSXIdentifier('slot')), [], true)) + } else if (/^render[A-Z]/.test(name)) { + const slotName = getSlotName(name) + if (parentPath.parentPath.isCallExpression()) { + injectRenderPropsEmiter(parentPath.parentPath as any, name) + parentPath.parentPath.replaceWith(t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('slot'), [ + t.jSXAttribute(t.jSXIdentifier('name'), t.stringLiteral(slotName)) + ], true), t.jSXClosingElement(t.jSXIdentifier('slot')), [])) + } else { + parentPath.replaceWith(t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('slot'), [ + t.jSXAttribute(t.jSXIdentifier('name'), t.stringLiteral(slotName)) + ], true), t.jSXClosingElement(t.jSXIdentifier('slot')), [])) + } + this.setMultipleSlots() + } else { + self.componentProperies.add(siblingProp.name) + } + } + } else if (parentPath.isVariableDeclarator()) { + const siblingId = parentPath.get('id') + if (t.isObjectPattern(siblingId)) { + const properties = siblingId.properties + for (const prop of properties) { + if (t.isRestProperty(prop)) { + throw codeFrameError(prop.loc, 'this.props 不支持使用 rest property 语法,请把每一个 prop 都单独列出来') + } else if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) { + self.componentProperies.add(prop.key.name) + } + } + } + } + }, + + CallExpression (path) { + const node = path.node + const callee = node.callee + if (t.isMemberExpression(callee) && t.isMemberExpression(callee.object)) { + const property = callee.property + if (t.isIdentifier(property)) { + if (property.name.startsWith('on')) { + self.componentProperies.add(`${FN_PREFIX}${property.name}`) + processThisPropsFnMemberProperties(callee, path as any, (node as any).arguments) + } else if (property.name === 'call' || property.name === 'apply') { + self.componentProperies.add(`${FN_PREFIX}${property.name}`) + processThisPropsFnMemberProperties(callee.object, path as any, (node as any).arguments) + } + } + } + } + }) + } + + buildPropsAnonymousFunc = (attr: NodePath, expr: t.CallExpression, isBind = false, path) => { + const { code } = generate(expr as any) + const id = t.isMemberExpression(expr.callee) ? findFirstIdentifierFromMemberExpression(expr.callee) : null + if ( + code.startsWith('this.props') || + (id && isDerivedFromProps(attr.scope, id.name)) + ) { + const methodName = findMethodName(expr) + const uniqueMethodName = `${methodName}${String(isBind)}` + const hasMethodName = this.anonymousMethod.has(uniqueMethodName) || !methodName + const funcName = hasMethodName + ? this.anonymousMethod.get(uniqueMethodName)! + // 测试时使用1个稳定的 uniqueID 便于测试,实际使用5个英文字母,否则小程序不支持 + : isTestEnv ? uniqueId('funPrivate') : `funPrivate${createRandomLetters(5)}` + this.anonymousMethod.set(uniqueMethodName, funcName) + + const newVal = isBind + ? t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier(funcName)), t.identifier('bind')), expr.arguments || []) + : t.memberExpression(t.thisExpression(), t.identifier(funcName)); + (attr.get('value.expression') as any).replaceWith(newVal) + this.methods.set(funcName, null as any) + this.componentProperies.add(methodName) + if (hasMethodName) { + return + } + const attrName = attr.node.name + if (t.isJSXIdentifier(attrName) && attrName.name.startsWith('on')) { + this.componentProperies.add(`${FN_PREFIX}${attrName.name}`) + } + if (methodName.startsWith('on')) { + this.componentProperies.add(`${FN_PREFIX}${methodName}`) + } + const method = !isNewPropsSystem() ? + t.classMethod('method', t.identifier(funcName), [], t.blockStatement([ + t.expressionStatement(t.callExpression( + t.memberExpression(t.thisExpression(), t.identifier('__triggerPropsFn')), + [t.stringLiteral(methodName), t.arrayExpression([t.spreadElement(t.identifier('arguments'))])] + )) + ])) : + t.classMethod('method', t.identifier(funcName), [], t.blockStatement([ + t.returnStatement(t.callExpression( + t.memberExpression( + t.memberExpression( + t.memberExpression(t.thisExpression(), t.identifier('props')), + t.identifier(methodName) + ), + t.identifier('apply') + ), + [ + isBind ? t.identifier('this') : t.identifier('undefined'), + t.callExpression( + t.memberExpression( + t.memberExpression(t.memberExpression(t.identifier('Array'), t.identifier('prototype')), t.identifier('slice')), + t.identifier('call') + ), + [t.identifier('arguments'), t.numericLiteral(1)] + ) + ] + )) + ])) + this.classPath.node.body.body = this.classPath.node.body.body.concat(method) + // @ts-ignore + } else if (t.isMemberExpression(expr) && !t.isThisExpression(expr.object)) { + // @TODO: 新旧 props 系统在事件处理上耦合太深,快应用应用新 props 把旧 props 系统逻辑全部清楚 + this.buildAnonyMousFunc(path, attr, expr) + } + } + + setComponents () { + const components: string[] = [] + this.customComponents.forEach((component, name) => { + if (name.startsWith('Taro') && component.sourcePath === COMPONENTS_PACKAGE_NAME) { + return + } + if (Adapter.type === Adapters.quickapp && DEFAULT_Component_SET_COPY.has(name)) { + return + } + components.push(name) + this.result.components.push({ + path: pathResolver(component.sourcePath, this.sourcePath), + name: component.imported ? kebabCase(name) + '|' + kebabCase(component.imported) : kebabCase(name), + type: component.type + }) + }) + this.classPath.node.body.body.push( + t.classProperty(t.identifier('customComponents'), t.arrayExpression( + components.map(c => t.stringLiteral(c)) + )) + ) + } + + setMethods () { + const methods: Array> = (this.classPath as any).get('body').get('body') + for (const method of methods) { + if (method.isClassMethod()) { + const key = method.get('key') + if (key.isIdentifier()) { + this.methods.set(key.node.name, method) + } + } + } + } + + resetConstructor () { + const body = this.classPath.node.body.body + if (!this.methods.has('constructor')) { + const ctor = buildConstructor() + body.unshift(ctor) + } + if (isTestEnv) { + return + } + for (const method of body) { + if (t.isClassMethod(method) && method.kind === 'constructor') { + method.kind = 'method' + method.key = t.identifier('_constructor') + if (t.isBlockStatement(method.body)) { + for (const statement of method.body.body) { + if (t.isExpressionStatement(statement)) { + const expr = statement.expression + if (t.isCallExpression(expr) && (t.isIdentifier(expr.callee, { name: 'super' }) || t.isSuper(expr.callee))) { + expr.callee = t.memberExpression(t.identifier('super'), t.identifier('_constructor')) + } + } + } + } + } + } + } + + handleLifecyclePropParam (propParam: t.LVal, properties: Set) { + let propsName: string | null = null + if (!propParam) { + return null + } + if (t.isIdentifier(propParam)) { + propsName = propParam.name + } else if (t.isObjectPattern(propParam)) { + for (const prop of propParam.properties) { + if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) { + properties.add(prop.key.name) + } else if (t.isRestElement(prop) && t.isIdentifier(prop.argument)) { + propsName = prop.argument.name + } + } + } else { + throw codeFrameError(propParam.loc, '此生命周期的第一个参数只支持写标识符或对象解构') + } + return propsName + } + + findMoreProps () { + // 第一个参数是 props 的生命周期 + const lifeCycles = new Set([ + // 'constructor', + 'componentDidUpdate', + 'shouldComponentUpdate', + 'getDerivedStateFromProps', + 'getSnapshotBeforeUpdate', + 'componentWillReceiveProps', + 'componentWillUpdate' + ]) + const properties = new Set() + this.methods.forEach((method, name) => { + if (!lifeCycles.has(name)) { + return + } + const node = method.node + let propsName: null | string = null + if (t.isClassMethod(node)) { + propsName = this.handleLifecyclePropParam(node.params[0], properties) + } else if (t.isArrowFunctionExpression(node.value) || t.isFunctionExpression(node.value)) { + propsName = this.handleLifecyclePropParam(node.value.params[0], properties) + } + if (propsName === null) { + return + } + method.traverse({ + MemberExpression (path) { + if (!path.isReferencedMemberExpression()) { + return + } + const { object, property } = path.node + if (t.isIdentifier(object, { name: propsName }) && t.isIdentifier(property)) { + properties.add(property.name) + } + }, + VariableDeclarator (path) { + const { id, init } = path.node + if (t.isObjectPattern(id) && t.isIdentifier(init, { name: propsName })) { + for (const prop of id.properties) { + if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) { + properties.add(prop.key.name) + } + } + } + } + }) + properties.forEach((value) => { + this.componentProperies.add(value) + }) + }) + } + + parseRender () { + if (this.importJSXs.size) { + this.importJSXs.forEach(s => { + this.result.template += s + '\n' + }) + } + if (this.renderJSX.size) { + this.renderJSX.forEach((method, methodName) => { + this.result.template = this.result.template + + new RenderParser( + method, + this.methods, + this.initState, + this.refIdMap.get(method)!, + this.usedState, + this.customComponentNames, + this.componentProperies, + this.loopRefs, + this.refObjExpr, + methodName + ).outputTemplate + '\n' + }) + } else { + throw codeFrameError(this.classPath.node.loc, '没有定义 render 方法') + } + } + + clearClosureMethods () { + this.classPath.node.body.body = this.classPath.node.body.body.filter(m => { + if (m && t.isClassMethod(m) && t.isIdentifier(m.key) && m.key.name.startsWith('_createClosure')) { + return false + } + return true + }) + } + + compile () { + this.traverse() + this.setMethods() + this.setComponents() + this.resetConstructor() + this.findMoreProps() + this.handleRefs() + this.parseRender() + this.setComponentPath() + this.clearClosureMethods() + this.result.componentProperies = [...this.componentProperies] + } +} + +export { Transformer } diff --git a/packages/taro-transformer-wx/src/constant.ts b/packages/taro-transformer-wx/src/constant.ts new file mode 100644 index 000000000000..61f70ca93518 --- /dev/null +++ b/packages/taro-transformer-wx/src/constant.ts @@ -0,0 +1,172 @@ +import { Adapters } from './adapter' + +export const THIRD_PARTY_COMPONENTS = new Set() + +// tslint:disable-next-line:variable-name +export const DEFAULT_Component_SET = new Set([ + 'View', + 'ScrollView', + 'Swiper', + 'CoverView', + 'CoverImage', + 'Icon', + 'Text', + 'RichText', + 'Progress', + 'Button', + 'Checkbox', + 'Form', + 'Input', + 'Label', + 'Picker', + 'PickerView', + 'PickerViewColumn', + 'Radio', + 'RadioGroup', + 'CheckboxGroup', + 'Slider', + 'Switch', + 'Textarea', + 'Navigator', + 'Audio', + 'Image', + 'Video', + 'Camera', + 'LivePlayer', + 'LivePusher', + 'Map', + 'Canvas', + 'OpenData', + 'WebView', + 'SwiperItem', + 'MovableArea', + 'MovableView', + 'FunctionalPageNavigator', + 'Ad', + 'Block', + 'Import', + 'OfficialAccount', + 'Template', + 'Editor' +]) + +// tslint:disable-next-line:variable-name +export const DEFAULT_Component_SET_COPY = new Set([]) +DEFAULT_Component_SET.forEach((c) => DEFAULT_Component_SET_COPY.add(c)) + +export const INTERNAL_SAFE_GET = 'internal_safe_get' + +export const TARO_PACKAGE_NAME = '@tarojs/taro' + +export const COMPONENTS_PACKAGE_NAME = '@tarojs/components' + +export const REDUX_PACKAGE_NAME = '@tarojs/redux' + +export const MOBX_PACKAGE_NAME = '@tarojs/mobx' + +export const MAP_CALL_ITERATOR = '__item' + +export const INTERNAL_INLINE_STYLE = 'internal_inline_style' + +export const INTERNAL_GET_ORIGNAL = 'internal_get_original' + +export const HANDLE_LOOP_REF = 'handleLoopRef' + +export const PROPS_MANAGER = 'propsManager' + +export const GEN_COMP_ID = 'genCompid' + +export const GEN_LOOP_COMPID = 'genLoopCompid' + +export const CLASS_COMPONENT_UID = '_$uid' + +export let LOOP_STATE = '$loopState' + +export const setLoopState = (s: string) => LOOP_STATE = s + +export let PREV_COMPID = '$prevCompid' + +export let COMPID = '$compid' + +export const setCompId = (s: string) => COMPID = s + +export let LOOP_ORIGINAL = '$original' + +export const setLoopOriginal = (s: string) => LOOP_ORIGINAL = s + +export let LOOP_CALLEE = '$anonymousCallee_' + +export let setLoopCallee = (s: string) => LOOP_CALLEE = s + +export const CONTEXT_PROVIDER = 'PrivateContextProvider' + +export const SPECIAL_COMPONENT_PROPS = new Map>() + +export let IS_TARO_READY = '$taroCompReady' + +export const setIsTaroReady = (s: string) => IS_TARO_READY = s + +SPECIAL_COMPONENT_PROPS.set( + 'Progress', + new Set([ + 'activeColor', + 'backgroundColor' + ]) +) + +export const IMAGE_COMPONENTS = new Set([ + 'Image', + 'CoverImage' +]) + +export const swanSpecialAttrs = { + 'ScrollView': ['scrollTop', 'scrollLeft', 'scrollIntoView'], + 'Input': ['value'], + 'Textarea': ['value'], + 'MovableView': ['x', 'y'], + 'Slider': ['value'] +} + +export const ALIPAY_BUBBLE_EVENTS = new Set([ + 'onTouchStart', + 'onTouchMove', + 'onTouchEnd', + 'onTouchCancel', + 'onClick', + 'onLongTap' +]) + +export const ANONYMOUS_FUNC = 'anonymousFunc' + +export const TRANSFORM_COMPONENT_PROPS = new Map() + +TRANSFORM_COMPONENT_PROPS.set(Adapters.alipay, { + 'Canvas': { + 'canvasId': 'id' + } +}) + +export const lessThanSignPlacehold = '__LESS_THAN_SIGN_PLACEHOLDER__' + +export let FN_PREFIX = '__fn_' + +export const setFnPrefix = (s: string) => FN_PREFIX = s + +export const quickappComponentName = new Set([ + 'Swiper', + 'Audio', + 'Image', + 'Progress', + // 'Text', + 'Input', + 'Label', + 'Picker', + 'Slider', + 'Switch', + 'Textarea', + 'Video', + 'Camera', + 'Canvas', + 'Map', + 'Button' +]) diff --git a/packages/taro-transformer-wx/src/create-html-element.ts b/packages/taro-transformer-wx/src/create-html-element.ts new file mode 100644 index 000000000000..15d7ea96792c --- /dev/null +++ b/packages/taro-transformer-wx/src/create-html-element.ts @@ -0,0 +1,118 @@ +import { camelCase } from 'lodash' + +import { Adapter,Adapters } from './adapter' +import { DEFAULT_Component_SET_COPY, LOOP_ORIGINAL,quickappComponentName } from './constant' +import { isTestEnv } from './env' +import { transformOptions } from './options' + +const voidHtmlTags = new Set([ + // 'image', + 'img', + 'input', + 'import' +]) + +if (isTestEnv) { + voidHtmlTags.add('image') +} + +export const capitalized = (name: string) => name.charAt(0).toUpperCase() + name.slice(1) + +interface Options { + name: string + attributes: object + value: string + + +} + +function stringifyAttributes (input: object, componentName: string) { + const attributes: string[] = [] + + for (const key of Object.keys(input)) { + let value = input[key] + + if (value === false) { + continue + } + + if (Array.isArray(value)) { + value = value.join(' ') + } + + let attribute = key + + if (Adapters.quickapp === Adapter.type && key === 'style') { + const nameCapitalized = capitalized(componentName) + if ( + !['div', 'text'].includes(componentName) && + (quickappComponentName.has(nameCapitalized) || DEFAULT_Component_SET_COPY.has(nameCapitalized)) + ) { + attribute = 'customstyle' + } + } + + if ( + process.env.NODE_ENV !== 'test' && + (Adapters.weapp === Adapter.type || Adapters.qq === Adapter.type) && + key === Adapter.key && + typeof value === 'string' + ) { + value = value.split(`${LOOP_ORIGINAL}.`).join('') + } + + if (value !== true) { + attribute += `="${String(value)}"` + } + + attributes.push(attribute) + } + + return attributes.length > 0 ? ' ' + attributes.join(' ') : '' + +} + +export const createHTMLElement = (options: Options, isFirstEmit = false) => { + options = Object.assign( + { + name: 'div', + attributes: {}, + value: '' + }, + options + ) + const name = options.name + if (Adapters.quickapp === Adapter.type) { + const nameCapitalized = capitalized(name) + if (quickappComponentName.has(nameCapitalized)) { + options.name = `taro-${name}` + if (options.attributes.className) { + options.attributes.class = options.attributes.className + delete options.attributes.className + } + } + if (isFirstEmit && name === 'div' && transformOptions.isRoot) { + options.name = 'taro-page' + for (const key in options.attributes) { + if (options.attributes.hasOwnProperty(key)) { + const attr = options.attributes[key] + options.attributes[camelCase(key)] = attr + delete options.attributes[key] + } + } + } + if (name === 'view') { + options.name = 'div' + } + } + + const isVoidTag = voidHtmlTags.has(options.name) + + let ret = `<${options.name}${stringifyAttributes(options.attributes, name)}${isVoidTag ? `/` : '' }>` + + if (!isVoidTag) { + ret += `${options.value}` + } + + return ret +} diff --git a/packages/taro-transformer-wx/src/env.ts b/packages/taro-transformer-wx/src/env.ts new file mode 100644 index 000000000000..d32c965d6a72 --- /dev/null +++ b/packages/taro-transformer-wx/src/env.ts @@ -0,0 +1 @@ +export const isTestEnv = process.env.NODE_ENV === 'test' diff --git a/packages/taro-transformer-wx/src/eslint.ts b/packages/taro-transformer-wx/src/eslint.ts new file mode 100644 index 000000000000..351fa37fab53 --- /dev/null +++ b/packages/taro-transformer-wx/src/eslint.ts @@ -0,0 +1,62 @@ +// import * as t from '@babel/types' +import { PluginPass } from '@babel/core' +import { Visitor } from '@babel/traverse' +import { CLIEngine } from 'eslint' + +import { codeFrameError } from './utils' + +const cli = new CLIEngine({ + baseConfig: { + extends: ['plugin:taro/transformer'] + }, + rules: { + 'react/no-multi-comp': [2, { ignoreStateless: false }] + }, + plugins: ['react'], + useEslintrc: false, + parser: 'babel-eslint', + parserOptions: { + ecmaVersion: 2018, + ecmaFeatures: { + jsx: true, + legacyDecorators: true + } + }, + settings: { + react: { + pragma: 'Taro', + version: 'detect' + } + } +} as any) + +export const eslintValidation: () => { + visitor: Visitor +} = () => { + return { + visitor: { + Program (_, state: PluginPass) { + const { file: { code } } = state + const report = cli.executeOnText(code) + if (report.errorCount > 0) { + for (const result of report.results) { + for (const msg of result.messages) { + const err = codeFrameError({ + start: { + line: msg.line, + column: msg.column + }, + end: { + line: msg.endLine, + column: msg.endColumn + } + }, msg.message) + // tslint:disable-next-line + console.warn('\n' + `ESLint(${msg.ruleId}) 错误:` + err.message.replace('Declare only one React component per file', '一个文件只能定义一个 Taro 类或 Taro 函数式组件') + '\n') + } + } + } + } + } + } +} diff --git a/packages/taro-transformer-wx/src/functional.ts b/packages/taro-transformer-wx/src/functional.ts new file mode 100644 index 000000000000..f429dc7619f7 --- /dev/null +++ b/packages/taro-transformer-wx/src/functional.ts @@ -0,0 +1,195 @@ +import generate from '@babel/generator' +import { Visitor } from '@babel/traverse' +import * as t from '@babel/types' +import { cloneDeep } from 'lodash' + +import { DEFAULT_Component_SET } from './constant' +import { transformOptions } from './options' +import { injectRenderPropsListener } from './render-props' +import { buildConstVariableDeclaration,codeFrameError } from './utils' + +function initialIsCapital (word: string) { + return word[0] !== word[0].toLowerCase() +} + +export const Status = { + isSFC: false +} + +const renderFnReg = /^render[A-Z]/ + +export const functionalComponent: () => { + visitor: Visitor +} = () => { + let propsIdentifier: t.Identifier | null + let propsList: string[] = [] + return { + visitor: { + JSXElement (path) { + const arrowFuncExpr = path.findParent(p => p.isArrowFunctionExpression()) + const funcExpr = path.findParent(p => p.isFunctionExpression()) + if (funcExpr && funcExpr.isFunctionExpression() && funcExpr.parentPath.isVariableDeclarator()) { + const { params, body, async } = funcExpr.node + funcExpr.replaceWith(t.arrowFunctionExpression(params as Array, body as any, async)) + return + } + if (arrowFuncExpr && arrowFuncExpr.isArrowFunctionExpression()) { + if (arrowFuncExpr.parentPath.isVariableDeclarator()) { + const valDecl = arrowFuncExpr.parentPath.parentPath + if (!valDecl.isVariableDeclaration() && !valDecl.isFunctionDeclaration() && !valDecl.isFunctionExpression()) { + throw codeFrameError(valDecl.node, '函数式组件不能同时定义多个值') + } + const id = arrowFuncExpr.parentPath.node.id + if (!t.isIdentifier(id)) { + throw codeFrameError(id, '函数式组件只能使用普通标识符定义') + } + if (!initialIsCapital(id.name)) { + return + } + const hasClassDecl = arrowFuncExpr.findParent(p => p.isClassDeclaration()) + if (hasClassDecl) { + // @TODO: 加上链接 + return + } + const { body } = arrowFuncExpr.node + if (t.isBlockStatement(body)) { + valDecl.replaceWith(t.functionDeclaration(id, arrowFuncExpr.node.params as any, body)) + } else { + valDecl.replaceWith(t.functionDeclaration(id, arrowFuncExpr.node.params as any, t.blockStatement([ + t.returnStatement(body as any) + ]))) + } + return + } else if (arrowFuncExpr.parentPath.isExportDefaultDeclaration()) { + const { body, params } = arrowFuncExpr.node + const func = t.functionDeclaration( + t.identifier('AnonymousSFC'), + params as any, + t.isBlockStatement(body) ? body : t.blockStatement([ + t.returnStatement(body as any) + ]) + ) + arrowFuncExpr.parentPath.insertAfter(t.exportDefaultDeclaration(t.identifier('AnonymousSFC'))) + arrowFuncExpr.parentPath.replaceWith(func) + return + } + } + + const functionDecl = path.findParent(p => p.isFunctionDeclaration()) + if (functionDecl && functionDecl.isFunctionDeclaration()) { + propsIdentifier = null + propsList = [] + const hasClassDecl = path.findParent(p => p.isClassDeclaration() || p.isClassExpression()) + if (hasClassDecl) { + // @TODO: 加上链接 + return + } + let { id, body, params } = functionDecl.node + let arg: null | t.LVal = null + // tslint:disable-next-line: strict-type-predicates + if (id === null) { + functionDecl.node.id = t.identifier('YourShouldGiveTheComponentAName') + id = functionDecl.node.id + } + if (params.length > 1) { + throw codeFrameError(id, '函数式组件的参数最多只能传入一个') + } else if (params.length === 1) { + arg = params[0] as any + } + if (!(typeof id === 'undefined') && !initialIsCapital(id.name)) { + throw codeFrameError(id, `普通函数式组件命名规则请遵守帕斯卡命名法(Pascal Case), 如果是在函数内声明闭包组件,则需要使用函数表达式的写法。 +形如: +const ${id?.name} = ${generate(t.arrowFunctionExpression(params as any, body as any)).code} + `) + } + const insertDecls: t.VariableDeclaration[] = [] + if (arg) { + if (t.isIdentifier(arg)) { + insertDecls.push(buildConstVariableDeclaration(arg.name, t.memberExpression(t.thisExpression(), t.identifier('props')))) + propsIdentifier = arg + } else if (t.isObjectPattern(arg)) { + let hasChildren = false + for (const [index, p] of arg.properties.entries()) { + if (t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'children' })) { + hasChildren = true + arg.properties.splice(index, 1) + } else if (t.isObjectProperty(p) && t.isIdentifier(p.key)) { + propsList.push(p.key.name) + } + } + insertDecls.push( + t.variableDeclaration('const', [ + t.variableDeclarator(arg, t.memberExpression(t.thisExpression(), t.identifier('props'))) + ]) + ) + if (hasChildren) { + insertDecls.push( + t.variableDeclaration('const', [ + t.variableDeclarator(t.objectPattern([ + t.objectProperty(t.identifier('children'), t.identifier('children')) as any + ]), t.memberExpression(t.thisExpression(), t.identifier('props'))) + ]) + ) + } + } else if (t.isAssignmentPattern(arg)) { + throw codeFrameError(arg, '给函数式组件的第一个参数设置默认参数是没有意义的,因为 props 永远都有值(不传 props 的时候是个空对象),所以默认参数永远都不会执行。') + } else { + throw codeFrameError(arg, '函数式组件只支持传入一个简单标识符或使用对象结构') + } + } + Status.isSFC = true + path.traverse({ + JSXExpressionContainer (path) { + const expr = path.get('expression').node + if (t.isMemberExpression(expr)) { + const { object, property } = expr + if ( + t.isIdentifier(object) && + t.isIdentifier(property) && + renderFnReg.test(property.name) && + propsIdentifier && + object.name === propsIdentifier.name + ) { + path.set('expression', t.memberExpression( + t.memberExpression(t.thisExpression(), t.identifier('props')), + t.identifier(property.name) + )) + } + } else if (t.isIdentifier(expr)) { + if (!renderFnReg.test(expr.name)) return + const prop = propsList.find(prop => prop === expr.name) + if (!prop) return + path.set('expression', t.memberExpression( + t.memberExpression(t.thisExpression(), t.identifier('props')), + t.identifier(expr.name) + )) + } + } + }) + const cloneBody = cloneDeep(body) as any + insertDecls.forEach(decl => cloneBody.body.unshift(decl)) + const classDecl = t.classDeclaration(id as t.Identifier, t.memberExpression(t.identifier('Taro'), t.identifier('Component')), t.classBody([ + t.classMethod('method', t.identifier('render'), [], cloneBody) + ]), []) + functionDecl.replaceWith(classDecl) + } + }, + JSXAttribute (path) { + const { name, value } = path.node + const jsxElementPath = path.parentPath.parentPath + if (t.isJSXIdentifier(name) && t.isJSXElement(jsxElementPath) && transformOptions.isNormal !== true) { + const componentName = ((jsxElementPath.node as any).openingElement as any).name.name + if (/^render[A-Z]/.test(name.name) && !DEFAULT_Component_SET.has(componentName)) { + if (!t.isJSXExpressionContainer(value)) { + throw codeFrameError(value, '以 render 开头的 props 只能传入包含一个 JSX 元素的 JSX 表达式。') + } + const expression = value.expression + if (t.isArrowFunctionExpression(expression)) { + injectRenderPropsListener(path as any, name.name, expression, componentName) + } + } + } + } + } + } +} diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts new file mode 100644 index 000000000000..859740d3c147 --- /dev/null +++ b/packages/taro-transformer-wx/src/index.ts @@ -0,0 +1,942 @@ +import * as babel from '@babel/core' +import generate from '@babel/generator' +// import * as template from '@babel/template' +// const template = require('babel-template') +import classProperties from '@babel/plugin-proposal-class-properties' +import decorators from '@babel/plugin-proposal-decorators' +import objectRestSpread from '@babel/plugin-proposal-object-rest-spread' +import optionalChaining from '@babel/plugin-proposal-optional-chaining' +import asyncGenerators from '@babel/plugin-syntax-async-generators' +import dynamicImport from '@babel/plugin-syntax-dynamic-import' +import asyncFunctions from '@babel/plugin-transform-async-to-generator' +import exponentiationOperator from '@babel/plugin-transform-exponentiation-operator' +import flowStrip from '@babel/plugin-transform-flow-strip-types' +import jsxPlugin from '@babel/plugin-transform-react-jsx' +import traverse, { Binding, NodePath } from '@babel/traverse' +import * as t from '@babel/types' +import { prettyPrint } from 'html' +import { cloneDeep, get as safeGet, isArray,snakeCase } from 'lodash' +// import { transform as parse } from '@babel/core' +// import parser from '@babel/parser' +import * as ts from 'typescript' + +import { Adapter,Adapters, setAdapter } from './adapter' +import { Transformer } from './class' +import { + COMPONENTS_PACKAGE_NAME, + CONTEXT_PROVIDER, + DEFAULT_Component_SET, + GEN_COMP_ID, + GEN_LOOP_COMPID, + HANDLE_LOOP_REF, + IMAGE_COMPONENTS, + INTERNAL_GET_ORIGNAL, + INTERNAL_INLINE_STYLE, + INTERNAL_SAFE_GET, + lessThanSignPlacehold, + MOBX_PACKAGE_NAME, + PROPS_MANAGER, + quickappComponentName, + REDUX_PACKAGE_NAME, + setCompId, + setFnPrefix, + setIsTaroReady, + setLoopCallee, + setLoopOriginal, + setLoopState, + TARO_PACKAGE_NAME, + THIRD_PARTY_COMPONENTS} from './constant' +import { isTestEnv } from './env' +// import { Options, setTransformOptions, buildBabelTransformOptions } from './options' +import { Options, setTransformOptions } from './options' +import { + codeFrameError, + findFirstIdentifierFromMemberExpression, + getSuperClassCode, + isArrayMapCallExpression, + isContainJSXElement, + replaceJSXTextWithTextComponent, + setting} from './utils' + +const template = require('@babel/template') + + + +function getIdsFromMemberProps (member: t.MemberExpression) { + let ids: string[] = [] + const { object, property } = member + if (t.isMemberExpression(object)) { + ids = ids.concat(getIdsFromMemberProps(object)) + } + if (t.isThisExpression(object)) { + ids.push('this') + } + if (t.isIdentifier(object)) { + ids.push(object.name) + } + if (t.isIdentifier(property)) { + ids.push(property.name) + } + return ids +} + +/** + * TS 编译器会把 class property 移到构造器, + * 而小程序要求 `config` 和所有函数在初始化(after new Class)之后就收集到所有的函数和 config 信息, + * 所以当如构造器里有 this.func = () => {...} 的形式,就给他转换成普通的 classProperty function + * 如果有 config 就给他还原 + */ +function resetTSClassProperty (body: (t.ClassMethod | t.ClassProperty)[]) { + for (const method of body) { + if (t.isClassMethod(method) && method.kind === 'constructor') { + if (t.isBlockStatement(method.body)) { + method.body.body = method.body.body.filter(statement => { + if (t.isExpressionStatement(statement) && t.isAssignmentExpression(statement.expression)) { + const expr = statement.expression + const { left, right } = expr + if ( + t.isMemberExpression(left) && + t.isThisExpression(left.object) && + t.isIdentifier(left.property) + ) { + if ( + (t.isArrowFunctionExpression(right) || t.isFunctionExpression(right)) + || + (left.property.name === 'config' && t.isObjectExpression(right)) + ) { + const classProp = t.classProperty(left.property, right) + body.push(classProp) + handleThirdPartyComponent(classProp) + return false + } + } + } + return true + }) + } + } + } +} + +function handleClosureJSXFunc (jsx: NodePath, mainClass: NodePath) { + // 在 ./functional.ts 会把 FunctionExpression 转化为 arrowFunctionExpr + // 所以我们这里只处理一种情况 + const arrowFunc = jsx.findParent(p => p.isArrowFunctionExpression()) + if (arrowFunc && arrowFunc.isArrowFunctionExpression()) { + const parentPath = arrowFunc.parentPath + if (parentPath.isVariableDeclarator()) { + const id = parentPath.node.id + if (t.isIdentifier(id) && /^render[A-Z]/.test(id.name)) { + const funcName = `renderClosure${id.name.slice(6, id.name.length)}` + mainClass.node.body.body.push( + t.classProperty( + t.identifier(funcName), + cloneDeep(arrowFunc.node as any) + ) + ) + parentPath.scope.rename(id.name, funcName) + arrowFunc.replaceWith(t.memberExpression( + t.thisExpression(), + t.identifier(funcName) + ) as any) + } + } + } +} + +function findDeclarationScope (path: NodePath, id: t.Identifier) { + const scopePath = path.findParent(p => !!p.scope.getOwnBindingIdentifier(id.name)) + if (scopePath) { + return scopePath + } + throw codeFrameError(path.node, '该引用从未被定义') +} + +function buildFullPathThisPropsRef (id: t.Identifier, memberIds: string[], path: NodePath) { + const scopePath = findDeclarationScope(path, id) + const binding = scopePath.scope.getOwnBinding(id.name) + if (binding) { + const bindingPath = binding.path + if (bindingPath.isVariableDeclarator()) { + const dclId = bindingPath.get('id') + const dclInit = bindingPath.get('init') + let dclInitIds: string[] = [] + if (t.isMemberExpression(dclInit)) { + dclInitIds = getIdsFromMemberProps((dclInit as any).node) + if (t.isIdentifier(dclId)) { + memberIds.shift() + } + if (dclInitIds[0] === 'this' && dclInitIds[1] === 'props') { + return template(dclInitIds.concat(memberIds).join('.'))().expression + } + } + } + } +} + +function handleThirdPartyComponent (expr: t.ClassMethod | t.ClassProperty) { + if (t.isClassProperty(expr) && (expr.key as t.Identifier).name === 'config' && t.isObjectExpression(expr.value)) { + const properties = expr.value.properties + findThirdPartyComponent(properties as any) + } +} + +function findThirdPartyComponent (properties: (t.ObjectMethod | t.ObjectProperty | t.SpreadProperty)[]) { + for (const prop of properties) { + if ( + t.isObjectProperty(prop) && + (t.isIdentifier(prop.key, { name: 'usingComponents' }) || t.isStringLiteral(prop.key, { value: 'usingComponents' })) && + t.isObjectExpression(prop.value) + ) { + for (const value of prop.value.properties) { + if (t.isObjectProperty(value)) { + if (t.isStringLiteral(value.key)) { + THIRD_PARTY_COMPONENTS.add(value.key.value) + } + if (t.isIdentifier(value.key)) { + THIRD_PARTY_COMPONENTS.add(value.key.name) + } + } + } + } + } +} +interface Result { + template?: string + componentProperies?: string[] +} + +export interface TransformResult extends Result { + ast: t.File + code?: string + imageSrcs?: string + compressedTemplate?: string + sourcemap?: object + components: { + name: string + path: string + type: string + }[] +} + +export type TransformOptions = Options + + +function parseCode (code: string) { + return (babel.transformSync(code, { + ast: true, + sourceType: 'module', + plugins: [ + classProperties, + jsxPlugin, + flowStrip, + asyncFunctions, + exponentiationOperator, + asyncGenerators, + objectRestSpread, + [decorators, {legacy: true}], + dynamicImport, + optionalChaining + ] + }) as { ast: t.File }).ast +} + +export default function transform (options: TransformOptions): TransformResult { + if (options.adapter) { + setAdapter(options.adapter) + if (Adapter.type === Adapters.quickapp) { + DEFAULT_Component_SET.clear() + DEFAULT_Component_SET.add('div') + DEFAULT_Component_SET.add('Text') + setFnPrefix('prv-fn-') + } + } + if (Adapter.type === Adapters.swan || Adapter.type === Adapters.quickapp) { + setLoopOriginal('privateOriginal') + setLoopCallee('anonymousCallee_') + setLoopState('loopState') + } + if (Adapter.type === Adapters.quickapp) { + setIsTaroReady('priTaroCompReady') + setCompId('priCompid') + } + const defaultResult: TransformResult = { + ast: {} as any, + code: '', + imageSrcs: '', + compressedTemplate: '', + components: [] + } + THIRD_PARTY_COMPONENTS.clear() + const code = options.isTyped + ? ts.transpile(options.code, { + jsx: options.sourcePath.endsWith('.tsx') ? ts.JsxEmit.Preserve : ts.JsxEmit.None, + target: ts.ScriptTarget.ESNext, + importHelpers: true, + noEmitHelpers: true, + emitDecoratorMetadata: process.env.TS_METADATA === 'true' + }) + : options.code + options.env = Object.assign({ 'process.env.TARO_ENV': options.adapter || 'weapp' }, options.env || {}) + setTransformOptions(options) + setting.sourceCode = code + let hasReduxBinding = false + // babel-traverse 无法生成 Hub + // 导致 Path#getSource|buildCodeFrameError 都无法直接使用 + // 原因大概是 babylon.parse 没有生成 File 实例导致 scope 和 path 原型上都没有 `file` + // 将来升级到 babel@7 可以直接用 parse 而不是 transform + // const ast = parser.parse(code, buildBabelTransformOptions() as any) as t.File + + const ast = parseCode(code) + + + // traverse(ast, { + // JSXElement (p) { + // setIsNormal(false) + // p.stop() + // }, + // ImportDeclaration (path) { + // const { source, specifiers } = path.node + // if (source.value === TARO_PACKAGE_NAME) { + // if (specifiers.some(s => s.local.name === 'Component')) { + // setIsNormal(false) + // path.stop() + // } + // } + // } + // }) + if (options.isNormal) { + if (options.isTyped) { + const mainClassNode = ast.program.body.find(v => { + return t.isClassDeclaration(v) + }) as t.ClassDeclaration | undefined + if (mainClassNode) { + resetTSClassProperty(mainClassNode.body.body as any) + } + } + const code = generate(ast.program as any).code + return { + ...defaultResult, + ast, + code + } + } + // transformFromAst(ast, code) + let result + const componentSourceMap = new Map() + const imageSource = new Set() + const importSources = new Set() + const classMethods = new Map>() + let componentProperies: string[] = [] + let mainClass!: NodePath + let storeName!: string + let renderMethod!: NodePath + let isImportTaro = false + traverse(ast as any, { + Program: { + exit (path) { + for (const stem of path.node.body) { + if (t.isImportDeclaration(stem)) { + if (stem.source.value === TARO_PACKAGE_NAME) { + const specs = stem.specifiers + if (specs.some(s => t.isImportDefaultSpecifier(s) && s.local.name === 'Taro')) { + continue + } + specs.unshift(t.importDefaultSpecifier(t.identifier('Taro'))) + } + } + } + } + }, + MemberExpression (path) { + const { property } = path.node + const right = path.getSibling('right') + if (t.isIdentifier(property, { name: 'config' }) && path.parentPath.isAssignmentExpression() && right.isObjectExpression()) { + const properties = right.node.properties + findThirdPartyComponent(properties as any) + } + }, + JSXText (path) { + if (Adapter.type !== Adapters.quickapp) { + return + } + const value = path.node.value + if (!value.trim()) { + return + } + + replaceJSXTextWithTextComponent(path as any) + }, + TemplateLiteral (path) { + const nodes: t.Expression[] = [] + const { quasis, expressions } = path.node + let index = 0 + if (path.parentPath.isTaggedTemplateExpression()) { + return + } + for (const elem of quasis) { + if (elem.value.cooked) { + nodes.push(t.stringLiteral(elem.value.cooked)) + } + + if (index < expressions.length) { + const expr = expressions[index++] + if (!t.isStringLiteral(expr, { value: '' })) { + nodes.push(expr as any) + } + } + } + + // + 号连接符必须保证第一和第二个 node 都是字符串 + if (!t.isStringLiteral(nodes[0]) && !t.isStringLiteral(nodes[1])) { + nodes.unshift(t.stringLiteral('')) + } + + let root = nodes[0] + for (let i = 1; i < nodes.length; i++) { + root = t.binaryExpression('+', root, nodes[i]) + } + path.replaceWith(root as any) + }, + ClassDeclaration (path) { + mainClass = path as any + const superClass = getSuperClassCode(path as any) + if (superClass) { + try { + componentProperies = transform({ + isRoot: false, + isApp: false, + code: superClass.code, + isTyped: true, + sourcePath: superClass.sourcePath, + sourceDir: options.sourceDir + }).componentProperies! + } catch (error) { + // + } + } + }, + ClassExpression (path) { + mainClass = path as any + }, + ClassMethod (path) { + if (t.isIdentifier(path.node.key)) { + if (path.node.key.name === 'render') { + renderMethod = path as any + } + classMethods.set(path.node.key.name, path as any) + } + }, + IfStatement (path) { + const consequent = path.get('consequent') + if (!consequent.isBlockStatement()) { + consequent.replaceWith( + t.blockStatement([ + consequent.node as any + ]) as any + ) + } + }, + CallExpression (path) { + const callee = path.get('callee') + if (isContainJSXElement(path as any)) { + return + } + if (callee.isReferencedMemberExpression()) { + const id = findFirstIdentifierFromMemberExpression(callee.node as any) + const property = callee.node.property + if (t.isIdentifier(property) && property.name.startsWith('on')) { + const funcExpr = path.findParent(p => p.isFunctionExpression()) + if (funcExpr && funcExpr.isFunctionExpression()) { + const taroAPI = funcExpr.findParent(p => p.isCallExpression() && t.isMemberExpression(p.node.callee) && t.isIdentifier(p.node.callee.object, { name: 'Taro' })) + if (taroAPI && taroAPI.isCallExpression()) { + throw codeFrameError(funcExpr.node, '在回调函数使用从 props 传递的函数时,请把回调函数改造为箭头函数并一直使用 `this` 取值') + } + } + } + const calleeIds = getIdsFromMemberProps(callee.node as any) + if (t.isIdentifier(id) && id.name.startsWith('on') && Adapters.alipay !== Adapter.type) { + const fullPath = buildFullPathThisPropsRef(id, calleeIds, path as any) + if (fullPath) { + path.replaceWith( + t.callExpression( + fullPath, + path.node.arguments as any + ) as any + ) + } + } + } + + if (callee.isReferencedIdentifier()) { + const id = callee.node as t.Identifier + const ids = [id.name] + if (id.name.startsWith('on')) { + const funcExpr = path.findParent(p => p.isFunctionExpression()) + if (funcExpr && funcExpr.isFunctionExpression()) { + const taroAPI = funcExpr.findParent(p => p.isCallExpression() && t.isMemberExpression(p.node.callee) && t.isIdentifier(p.node.callee.object, { name: 'Taro' })) + if (taroAPI && taroAPI.isCallExpression()) { + throw codeFrameError(funcExpr.node, '在回调函数使用从 props 传递的函数时,请把回调函数改造为箭头函数并一直使用 `this` 取值') + } + } + const fullPath = buildFullPathThisPropsRef(id, ids, path as any) + if (fullPath) { + path.replaceWith( + t.callExpression( + fullPath, + path.node.arguments as any + ) as any + ) + } + } + } + }, + // JSXIdentifier (path) { + // const parentPath = path.parentPath + // if (!parentPath.isJSXAttribute()) { + // return + // } + // const element = parentPath.parentPath + // if (!element.isJSXOpeningElement()) { + // return + // } + // const elementName = element.get('name') + // if (!elementName.isJSXIdentifier()) { + // return + // } + // if (DEFAULT_Component_SET.has(elementName.node.name)) { + // return + // } + + // const expr = parentPath.get('value.expression') + + // }, + JSXMemberExpression (path) { + const { property, object } = path.node + if (!t.isJSXIdentifier(property, { name: 'Provider' })) { + throw codeFrameError(property, '只能在使用 Context.Provider 的情况下才能使用 JSX 成员表达式') + } + if (!t.isJSXIdentifier(object)) { + return + } + const jsx = path.parentPath.parentPath + if (jsx?.isJSXElement()) { + const componentName = `${object.name}${CONTEXT_PROVIDER}` + jsx.node.openingElement.name = t.jSXIdentifier(componentName) as any + if (jsx.node.closingElement) { + jsx.node.closingElement.name = t.jSXIdentifier(componentName) as any + } + } + }, + JSXElement (path) { + const assignment = path.findParent(p => p.isAssignmentExpression()) + if (assignment && assignment.isAssignmentExpression() && !options.isTyped) { + const left = assignment.node.left + if (t.isIdentifier(left)) { + const binding = assignment.scope.getBinding(left.name) + if (binding && binding.scope === assignment.scope) { + if (binding.path.isVariableDeclarator()) { + binding.path.node.init = path.node + assignment.remove() + } else { + throw codeFrameError(path.node, '同一个作用域的JSX 变量延时赋值没有意义。详见:https://github.com/NervJS/taro/issues/550') + } + } + } + } + + const switchStatement = path.findParent(p => p.isSwitchStatement()) + if (switchStatement && switchStatement.isSwitchStatement()) { + const { discriminant, cases } = switchStatement.node + const ifStatement = cases.map((Case, index) => { + const [ consequent ] = Case.consequent + if (!t.isBlockStatement(consequent)) { + throw codeFrameError(switchStatement.node, '含有 JSX 的 switch case 语句必须每种情况都用花括号 `{}` 包裹结果') + } + const block = t.blockStatement(consequent.body.filter(b => !t.isBreakStatement(b)) as any) + if (index !== cases.length - 1 && t.isNullLiteral(Case.test)) { + throw codeFrameError(Case, '含有 JSX 的 switch case 语句只有最后一个 case 才能是 default') + } + // tslint:disable-next-line: strict-type-predicates + const test = Case.test === null ? t.nullLiteral() : t.binaryExpression('===', discriminant as any, Case.test as any) + return { block, test } + }).reduceRight((ifStatement, item) => { + if (t.isNullLiteral(item.test)) { + ifStatement.alternate = item.block + return ifStatement + } + const newStatement = t.ifStatement( + item.test, + item.block, + t.isBooleanLiteral(ifStatement.test, { value: false }) + ? ifStatement.alternate + : ifStatement + ) + return newStatement + }, t.ifStatement(t.booleanLiteral(false), t.blockStatement([]))) + + switchStatement.insertAfter(ifStatement as any) + switchStatement.remove() + } + const isForStatement = (p) => p && (p.isForStatement() || p.isForInStatement() || p.isForOfStatement()) + + const forStatement = path.findParent(isForStatement) + if (isForStatement(forStatement)) { + throw codeFrameError(forStatement?.node, '不能使用 for 循环操作 JSX 元素,详情:https://github.com/NervJS/taro/blob/master/packages/eslint-plugin-taro/docs/manipulate-jsx-as-array.md') + } + + const loopCallExpr = path.findParent(p => isArrayMapCallExpression(p as any)) + if (loopCallExpr && loopCallExpr.isCallExpression()) { + const [ func ] = loopCallExpr.node.arguments + if (t.isArrowFunctionExpression(func) && !t.isBlockStatement(func.body)) { + func.body = t.blockStatement([ + t.returnStatement(func.body as any) + ]) as any + } + } + handleClosureJSXFunc(path as any, mainClass) + }, + JSXOpeningElement (path) { + const { name } = path.node.name as t.JSXIdentifier + const binding = path.scope.getBinding(name) + if (process.env.NODE_ENV !== 'test' && binding && binding.kind === 'module') { + const bindingPath = binding.path + if (bindingPath.parentPath?.isImportDeclaration()) { + const source = bindingPath.parentPath.node.source + if (DEFAULT_Component_SET.has(name) && source.value !== COMPONENTS_PACKAGE_NAME) { + throw codeFrameError(bindingPath.parentPath.node, `内置组件名: '${name}' 只能从 ${COMPONENTS_PACKAGE_NAME} 引入。`) + } + + if (name === 'Fragment') { + path.node.name = t.jSXIdentifier('block') as any + } + } + } + + if (Adapter.type === Adapters.quickapp) { + if (name === 'View') { + path.node.name = t.jSXIdentifier('div') as any + } + if (name === 'Block') { + path.node.name = t.jSXIdentifier('block') as any + } + } + + if (name === 'Provider') { + const modules = path.scope.getAllBindings('module') + const providerBinding = Object.values(modules).some((m: Binding) => m.identifier.name === 'Provider') + if (providerBinding) { + path.node.name = t.jSXIdentifier('View') as any + const store = path.node.attributes.find(attr => t.isJSXAttribute(attr) && attr.name.name === 'store') + if (store && t.isJSXAttribute(store) && t.isJSXExpressionContainer(store.value) && t.isIdentifier(store.value.expression)) { + storeName = store.value.expression.name + } + path.node.attributes = [] + } + } + + if (IMAGE_COMPONENTS.has(name)) { + for (const attr of path.node.attributes) { + if ( + t.isJSXAttribute(attr) && attr.name.name === 'src' + ) { + if (t.isJSXAttribute(attr) && t.isStringLiteral(attr.value)) { + imageSource.add(attr.value.value) + } else if (t.isJSXAttribute(attr) && t.isJSXExpressionContainer(attr.value)) { + if (t.isStringLiteral(attr.value.expression)) { + imageSource.add(attr.value.expression.value) + } + } + } + } + } + }, + JSXAttribute (path) { + const { name, value } = path.node + + if (options.jsxAttributeNameReplace) { + for (const r in options.jsxAttributeNameReplace) { + if (options.jsxAttributeNameReplace.hasOwnProperty(r)) { + const element = options.jsxAttributeNameReplace[r] + if (t.isJSXIdentifier(name, { name: r })) { + path.node.name = t.jSXIdentifier(element) as any + } + } + } + } + + // tslint:disable-next-line: strict-type-predicates + if (!t.isJSXIdentifier(name) || value === null || t.isStringLiteral(value) || t.isJSXElement(value)) { + return + } + + const expr = (value as t.JSXExpressionContainer)?.expression as any + const exprPath = path.get('value.expression') + const classDecl = path.findParent(p => p.isClassDeclaration()) + const classDeclName = classDecl && classDecl.isClassDeclaration() && safeGet(classDecl, 'node.id.name', '') + let isConverted = false + if (classDeclName) { + isConverted = classDeclName === '_C' || classDeclName.endsWith('Tmpl') + } + if (!t.isBinaryExpression(expr, { operator: '+' }) && !t.isLiteral(expr) && name.name === 'style' && !isConverted) { + const jsxID = path.findParent(p => p.isJSXOpeningElement())?.get('name') as any + if (jsxID && jsxID.isJSXIdentifier() && DEFAULT_Component_SET.has(jsxID.node.name)) { + if (!isArray(exprPath)) { + exprPath.replaceWith( + t.callExpression(t.identifier(INTERNAL_INLINE_STYLE), [expr]) as any + ) + } else { + exprPath.forEach(item => item.replaceWith( + t.callExpression(t.identifier(INTERNAL_INLINE_STYLE), [expr]) as any + )) + } + + } + } + + if (name.name.startsWith('on')) { + if ((exprPath as NodePath).isReferencedIdentifier()) { + const ids = [expr.name] + const fullPath = buildFullPathThisPropsRef(expr, ids, path as any) + if (fullPath) { + (exprPath as NodePath).replaceWith(fullPath) + } + } + + if ((exprPath as NodePath).isReferencedMemberExpression()) { + const id = findFirstIdentifierFromMemberExpression(expr) + const ids = getIdsFromMemberProps(expr) + if (t.isIdentifier(id)) { + const fullPath = buildFullPathThisPropsRef(id, ids, path as any) + if (fullPath) { + (exprPath as NodePath).replaceWith(fullPath) + } + } + } + + // @TODO: bind 的处理待定 + } + }, + ClassProperty (path) { + const { key: { name }, value } = path.node as any + if (t.isArrowFunctionExpression(value) || t.isFunctionExpression(value)) { + classMethods.set(name, path as any) + if (name.startsWith('render')) { + path.replaceWith(t.classMethod( + 'method', + t.identifier(name), + value.params, + t.isBlockStatement(value.body) ? value.body : t.blockStatement([ + t.returnStatement(value.body) + ]) + ) as any) + } + } + if (Adapter.type !== Adapters.quickapp) { + return + } + if ((path.node.key as t.Identifier).name === 'defaultProps' && t.isObjectExpression(path.node.value)) { + const props = path.node.value.properties + for (const prop of props) { + if (t.isObjectProperty(prop)) { + if (t.isStringLiteral(prop.key) && /[A-Z]/.test(prop.key.value) && !prop.key.value.startsWith('on')) { + prop.key = t.stringLiteral(snakeCase(prop.key.value)) as any + } + if (t.isIdentifier(prop.key) && /[A-Z]/.test(prop.key.name) && !prop.key.name.startsWith('on')) { + prop.key = t.identifier(snakeCase(prop.key.name)) as any + } + } + } + } + }, + AssignmentExpression (path) { + if (Adapter.type !== Adapters.quickapp) { + return + } + const { left, right } = path.node + if (t.isMemberExpression(left) && t.isIdentifier(left.property, { name: 'defaultProps' }) && t.isObjectExpression(right)) { + const props = right.properties + for (const prop of props) { + if (t.isObjectProperty(prop)) { + if (t.isStringLiteral(prop.key) && /[A-Z]/.test(prop.key.value) && !prop.key.value.startsWith('on')) { + prop.key = t.stringLiteral(snakeCase(prop.key.value)) as any + } + if (t.isIdentifier(prop.key) && /[A-Z]/.test(prop.key.name) && !prop.key.name.startsWith('on')) { + prop.key = t.identifier(snakeCase(prop.key.name)) as any + } + } + } + } + }, + ImportDeclaration (path) { + const source = path.node.source.value + if (importSources.has(source)) { + throw codeFrameError(path.node, '无法在同一文件重复 import 相同的包。') + } else { + importSources.add(source) + } + const names: string[] = [] + if (source === COMPONENTS_PACKAGE_NAME && Adapters.quickapp === Adapter.type) { + path.node.specifiers.forEach((s) => { + if (t.isImportSpecifier(s)) { + const originalName = (s.imported as t.Identifier).name + if (quickappComponentName.has(originalName)) { + const importedName = `Taro${originalName}` + ;(s.imported as t.Identifier).name = importedName + s.local.name = importedName + } + } + }) + } + if (source === TARO_PACKAGE_NAME) { + isImportTaro = true + path.node.specifiers.push( + t.importSpecifier(t.identifier(INTERNAL_SAFE_GET), t.identifier(INTERNAL_SAFE_GET)) as any, + t.importSpecifier(t.identifier(INTERNAL_GET_ORIGNAL), t.identifier(INTERNAL_GET_ORIGNAL)) as any, + t.importSpecifier(t.identifier(INTERNAL_INLINE_STYLE), t.identifier(INTERNAL_INLINE_STYLE)) as any, + t.importSpecifier(t.identifier(HANDLE_LOOP_REF), t.identifier(HANDLE_LOOP_REF)) as any, + t.importSpecifier(t.identifier(GEN_COMP_ID), t.identifier(GEN_COMP_ID)) as any, + t.importSpecifier(t.identifier(GEN_LOOP_COMPID), t.identifier(GEN_LOOP_COMPID)) as any + ) + if (Adapter.type !== Adapters.alipay) { + path.node.specifiers.push( + t.importSpecifier(t.identifier(PROPS_MANAGER), t.identifier(PROPS_MANAGER)) as any + ) + } + } + if ( + source === REDUX_PACKAGE_NAME || source === MOBX_PACKAGE_NAME + ) { + path.node.specifiers.forEach((s, index, specs) => { + if (s.local.name === 'Provider') { + specs.splice(index, 1) + specs.push( + t.importSpecifier(t.identifier('setStore'), t.identifier('setStore')) as any + ) + if (source === REDUX_PACKAGE_NAME) { + hasReduxBinding = true + specs.push( + t.importSpecifier(t.identifier('ReduxContext'), t.identifier('ReduxContext')) as any + ) + } + } + }) + } + path.traverse({ + ImportDefaultSpecifier (path) { + const name = path.node.local.name + names.push(name) + }, + ImportSpecifier (path) { + const name = (path.node.imported as t.Identifier).name + names.push(name) + if (source === TARO_PACKAGE_NAME && name === 'Component') { + path.node.local = t.identifier('__BaseComponent') as any + } + } + }) + componentSourceMap.set(source, names) + } + }) + + if (!isImportTaro) { + const specifiers = [ + t.importDefaultSpecifier(t.identifier('Taro')), + t.importSpecifier(t.identifier(INTERNAL_SAFE_GET), t.identifier(INTERNAL_SAFE_GET)), + t.importSpecifier(t.identifier(INTERNAL_GET_ORIGNAL), t.identifier(INTERNAL_GET_ORIGNAL)), + t.importSpecifier(t.identifier(INTERNAL_INLINE_STYLE), t.identifier(INTERNAL_INLINE_STYLE)), + t.importSpecifier(t.identifier(HANDLE_LOOP_REF), t.identifier(HANDLE_LOOP_REF)), + t.importSpecifier(t.identifier(GEN_COMP_ID), t.identifier(GEN_COMP_ID)), + t.importSpecifier(t.identifier(GEN_LOOP_COMPID), t.identifier(GEN_LOOP_COMPID)) + ] + if (Adapter.type !== Adapters.alipay) { + specifiers.push(t.importSpecifier(t.identifier(PROPS_MANAGER), t.identifier(PROPS_MANAGER))) + } + ast.program.body.unshift( + t.importDeclaration(specifiers, t.stringLiteral('@tarojs/taro')) + ) + } + + if (!mainClass) { + const code = generate(ast.program as any).code + return { + ...defaultResult, + ast, + code + } + } + + if (Adapter.type === Adapters.alipay) { + const body = ast.program.body + for (const i in body) { + if (t.isImportDeclaration(body[i]) && !t.isImportDeclaration(body[Number(i) + 1])) { + body.splice(Number(i) + 1, 0, t.variableDeclaration( + 'const', + [t.variableDeclarator( + t.identifier('propsManager'), + t.memberExpression( + t.identifier('my'), + t.identifier('propsManager') + ) + )] + )) + break + } + } + } + + mainClass.node.body.body.forEach(handleThirdPartyComponent) + const storeBinding = mainClass.scope.getBinding(storeName) + mainClass.scope.rename('Component', '__BaseComponent') + if (storeBinding) { + const statementPath = storeBinding.path.getStatementParent() + if (statementPath) { + ast.program.body.every((node, index, body) => { + if (node === statementPath.node) { + const settingReduxProvider = t.expressionStatement( + t.callExpression(t.memberExpression(t.identifier('ReduxContext'), t.identifier('Provider')), [ + t.objectExpression([ + t.objectProperty(t.identifier('store'), t.identifier(storeName)) + ]) + ]) + ) + const ifStem = t.ifStatement(t.memberExpression(t.identifier('ReduxContext'), t.identifier('Provider')), t.blockStatement([ + settingReduxProvider, + settingReduxProvider // 第一次调用初始化,第二次赋值 + ])) + body.splice(index + 1, 0, t.expressionStatement( + t.callExpression(t.identifier('setStore'), [ + t.identifier(storeName) + ]) + ), hasReduxBinding ? ifStem : t.emptyStatement()) + return false + } + return true + }) + } + } + resetTSClassProperty(mainClass.node.body.body as any) + if (options.isApp) { + renderMethod.replaceWith( + t.classMethod('method', t.identifier('_createData'), [], t.blockStatement([])) as any + ) + const code = generate(ast.program as any).code + return { + ...defaultResult, + ast, + code + } + } + result = new Transformer(mainClass as any, options.sourcePath, componentProperies, options.sourceDir!, classMethods as any).result + result.code = generate(ast.program as any).code + result.ast = ast + const lessThanSignReg = new RegExp(lessThanSignPlacehold, 'g') + result.compressedTemplate = result.template.replace(lessThanSignReg, '<') + result.template = prettyPrint(result.template, { + max_char: 0, + unformatted: isTestEnv ? [] : ['text'] + }) + result.template = result.template.replace(lessThanSignReg, '<') + result.imageSrcs = Array.from(imageSource) + return result +} diff --git a/packages/taro-transformer-wx/src/interface.d.ts b/packages/taro-transformer-wx/src/interface.d.ts new file mode 100644 index 000000000000..83285b42cdde --- /dev/null +++ b/packages/taro-transformer-wx/src/interface.d.ts @@ -0,0 +1,9 @@ +import { NodePath } from '@babel/traverse' +import * as t from '@babel/types' + +interface LoopRef { + id: string | t.Expression, + fn: t.FunctionExpression | t.ArrowFunctionExpression | t.MemberExpression, + type: 'component' | 'dom', + component: NodePath +} diff --git a/packages/taro-transformer-wx/src/jsx.ts b/packages/taro-transformer-wx/src/jsx.ts new file mode 100644 index 000000000000..dde7b34be20e --- /dev/null +++ b/packages/taro-transformer-wx/src/jsx.ts @@ -0,0 +1,348 @@ +import generate from '@babel/generator' +import { NodePath } from '@babel/traverse' +import * as t from '@babel/types' +import { kebabCase, snakeCase } from 'lodash' + +import { Adapter, Adapters, isNewPropsSystem } from './adapter' +import { + DEFAULT_Component_SET, + DEFAULT_Component_SET_COPY, + FN_PREFIX, + lessThanSignPlacehold, + SPECIAL_COMPONENT_PROPS, + swanSpecialAttrs, + THIRD_PARTY_COMPONENTS, + TRANSFORM_COMPONENT_PROPS} from './constant' +import { createHTMLElement } from './create-html-element' +import { Status } from './functional' +import { transformOptions } from './options' +import { codeFrameError, decodeUnicode } from './utils' + +export function isStartWithWX (str: string) { + return str[0] === 'w' && str[1] === 'x' +} + +const specialComponentName = ['block', 'Block', 'slot', 'Slot'] + +export function removeJSXThisProperty (path: NodePath) { + if (!path.parentPath.isCallExpression()) { + const p = path.getSibling('property') + if ( + p.isIdentifier({ name: 'props' }) || + p.isIdentifier({ name: 'state' }) + ) { + path.parentPath.replaceWithSourceString('this') + } else { + path.parentPath.replaceWith(p) + } + } +} + +export function findJSXAttrByName (attrs: (t.JSXAttribute | t.JSXSpreadAttribute)[], name: string) { + for (const attr of attrs) { + if (!t.isJSXAttribute(attr)) continue + + if (!t.isJSXIdentifier(attr.name)) { + break + } + if (attr.name.name === name) { + return attr + } + } + return null +} + +export function buildRefTemplate (name: string, refName?: string, loop?: boolean, key?: t.JSXAttribute) { + const isSwan = Adapter.type === Adapters.swan + const dataString = isSwan ? `{{{...${refName ? `${loop ? '' : '$$'}${refName}` : '__data'}}}}` : `{{...${refName ? `${loop ? '' : '$$'}${refName}` : '__data'}}}` + const attrs = [ + t.jSXAttribute(t.jSXIdentifier('is'), t.stringLiteral(name)), + t.jSXAttribute(t.jSXIdentifier('data'), t.stringLiteral(dataString)) + ] + if (key) { + attrs.push(key) + } + return t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('template'), attrs), + t.jSXClosingElement(t.jSXIdentifier('template')), + [] + ) +} + +export function buildJSXAttr (name: string, value: t.Identifier | t.Expression) { + return t.jSXAttribute(t.jSXIdentifier(name), t.jSXExpressionContainer(value)) +} + +export function newJSXIfAttr ( + jsx: t.JSXElement, + value: t.Identifier | t.Expression +) { + jsx.openingElement.attributes.push(buildJSXAttr(Adapter.if, value)) +} + +export function setJSXAttr ( + jsx: t.JSXElement, + name: string, + value?: t.StringLiteral | t.JSXExpressionContainer | t.JSXElement, + path?: NodePath +) { + if ((name === Adapter.forIndex || name === Adapter.forItem) && Adapter.type === Adapters.quickapp) { + return + } + const element = jsx.openingElement + // tslint:disable-next-line: strict-type-predicates + if (element == null || !t.isJSXIdentifier(element.name)) { + return + } + if (element.name.name === 'Block' || element.name.name === 'block' || !path) { + jsx.openingElement.attributes.push( + t.jSXAttribute(t.jSXIdentifier(name), value) + ) + } else { + const block = buildBlockElement() + setJSXAttr(block, name, value) + block.children = [jsx] + path.node = block + } +} + +export function buildTrueJSXAttrValue () { + return t.jSXExpressionContainer(t.booleanLiteral(true)) +} + +export function generateJSXAttr (ast: t.Node) { + const options = { + quotes: "single", + retainFunctionParens: true // 如果您需要 JSON 兼容的字符串,请改用此选项 + }; + const code = decodeUnicode( + generate(ast,options).code + ) + .replace(/ t.isLiteral(p)) +} + +export function buildBlockElement (attrs: t.JSXAttribute[] = [], isView = false) { + let blockName = Adapter.type === Adapters.quickapp ? 'div' : 'block' + if (isView) { + blockName = 'View' + } + return t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier(blockName), attrs), + t.jSXClosingElement(t.jSXIdentifier(blockName)), + [] + ) +} + +function parseJSXChildren ( + children: (t.JSXElement | t.JSXText | t.JSXExpressionContainer)[] +): string { + return children + .reduce((str, child) => { + if (t.isJSXText(child)) { + const strings: string[] = [] + child.value.split(/(\r?\n\s*)/).forEach((val) => { + const value = val + .replace(/\u00a0/g, ' ') + .replace(/\u2002/g, ' ') + .replace(/\u2003/g, ' ') + if (!value) { + return + } + if (value.startsWith('\n')) { + return + } + strings.push(value) + }) + return str + strings.join('') + } + if (t.isJSXElement(child)) { + return str + parseJSXElement(child) + } + if (t.isJSXExpressionContainer(child)) { + if (t.isJSXElement(child.expression)) { + return str + parseJSXElement(child.expression) + } + return str + `{${generateJSXAttr(child)}}` + } + return str + }, '') +} + +export function parseJSXElement (element: t.JSXElement, isFirstEmit = false): string { + const children = element.children + const { attributes, name } = element.openingElement + const TRIGGER_OBSERER = Adapter.type === Adapters.swan || Adapter.type === Adapters.quickapp ? 'privateTriggerObserer' : '__triggerObserer' + const TRIGGER_OBSERER_KEY = Adapter.type === Adapters.quickapp ? 'privateTriggerObsererKey' : '_triggerObserer' + if (t.isJSXMemberExpression(name)) { + throw codeFrameError(name.loc, '暂不支持 JSX 成员表达式') + } + const componentName = name.name + const isDefaultComponent = DEFAULT_Component_SET.has(componentName as string) + const componentSpecialProps = SPECIAL_COMPONENT_PROPS.get(componentName as string) + const componentTransfromProps = TRANSFORM_COMPONENT_PROPS.get(Adapter.type) + let hasElseAttr = false + const isJSXMetHod = componentName === 'Template' && attributes.some(a => t.isJSXAttribute(a) && a.name.name === 'is' && t.isStringLiteral(a.value) && a.value.value.startsWith('render')) + attributes.forEach((a, index) => { + if (t.isJSXAttribute(a) && a.name.name === Adapter.else && !['block', 'Block'].includes(componentName as string) && !isDefaultComponent) { + hasElseAttr = true + attributes.splice(index, 1) + } + }) + if (hasElseAttr) { + return createHTMLElement({ + name: 'block', + attributes: { + [Adapter.else]: true + }, + value: parseJSXChildren([element]) + }) + } + let attributesTrans = {} + if (attributes.length) { + attributesTrans = attributes.reduce((obj, attr) => { + if (t.isJSXSpreadAttribute(attr)) { + if (isNewPropsSystem()) return {} + // @ts-ignore + throw codeFrameError(attr.loc, 'JSX 参数暂不支持 ...spread 表达式') + } + let name = attr.name.name + if (DEFAULT_Component_SET.has(componentName as string)) { + if (name === 'className') { + name = 'class' + } + if (typeof name === 'string' && /(^on[A-Z_])|(^catch[A-Z_])/.test(name) && Adapter.type === Adapters.quickapp) { + name = name.toLowerCase() + } + } + if (Adapters.quickapp === Adapter.type && !DEFAULT_Component_SET_COPY.has(componentName as string) && typeof name === 'string' && !/(^on[A-Z_])|(^catch[A-Z_])/.test(name)) { + name = snakeCase(name) + } + let value: string | boolean = true + let attrValue = attr.value + if (typeof name === 'string') { + const isAlipayOrQuickappEvent = (Adapter.type === Adapters.alipay || Adapter.type === Adapters.quickapp) && /(^on[A-Z_])|(^catch[A-Z_])/.test(name) + if (t.isStringLiteral(attrValue)) { + value = attrValue.value + } else if (t.isJSXExpressionContainer(attrValue)) { + let isBindEvent = + (name.startsWith('bind') && name !== 'bind') || (name.startsWith('catch') && name !== 'catch') + const options = { + quotes: 'single', + concise: true + }; + let code = decodeUnicode(generate(attrValue.expression, options).code) + .replace(/"/g, "'") + .replace(/(this\.props\.)|(this\.state\.)/g, '') + .replace(/this\./g, '') + if ( + Adapters.swan === Adapter.type && + code !== 'true' && + code !== 'false' && + swanSpecialAttrs[componentName as string] && + swanSpecialAttrs[componentName as string].includes(name) + ) { + value = `{= ${code} =}` + } else { + if (Adapter.key === name) { + const splitCode = code.split('.') + if (splitCode.length > 1) { + value = splitCode.slice(1).join('.') + } else { + value = code + } + } else { + const isTemplateData = isJSXMetHod && name === 'data' + value = isBindEvent || isAlipayOrQuickappEvent ? code : `{{${isJSXMetHod && name === 'data' ? '...' : ''}${code}}}` + if (isTemplateData && Adapters.swan === Adapter.type) { + value = `{${value}}` + } + } + } + if (Adapter.type === Adapters.swan && name === Adapter.for) { + value = code + } + if (t.isStringLiteral(attrValue.expression)) { + value = attrValue.expression.value + } + // tslint:disable-next-line: strict-type-predicates + } else if (attrValue === null && name !== Adapter.else) { + value = `{{true}}` + } + if (THIRD_PARTY_COMPONENTS.has(componentName as string) && /^bind/.test(name) && name.includes('-')) { + name = name.replace(/^bind/, 'bind:') + } + if (componentTransfromProps && componentTransfromProps[componentName as string]) { + const transfromProps = componentTransfromProps[componentName as string] + Object.keys(transfromProps).forEach(oriName => { + if (name === oriName) { + name = transfromProps[oriName] + } + }) + } + if ((componentName === 'Input' || componentName === 'input') && name === 'maxLength') { + obj.maxlength = value + } else if ( + (componentSpecialProps && componentSpecialProps.has(name)) || + name.startsWith(FN_PREFIX) || + isAlipayOrQuickappEvent + ) { + obj[name] = value + } else { + obj[isDefaultComponent && !name.includes('-') && !name.includes(':') ? kebabCase(name) : name] = value + } + } + if (!isDefaultComponent && !specialComponentName.includes(componentName as string) && !isNewPropsSystem()) { + obj[TRIGGER_OBSERER] = `{{ ${TRIGGER_OBSERER_KEY} }}` + } + return obj + }, {}) + } else if (!isDefaultComponent && !specialComponentName.includes(componentName as string)) { + if (!isNewPropsSystem()) { + attributesTrans[TRIGGER_OBSERER] = `{{ ${TRIGGER_OBSERER_KEY} }}` + } + } + + let elementStr + + if (isFirstEmit && Adapters.quickapp === Adapter.type && !transformOptions.isRoot) { + const rootAttributes = Object.assign({}, attributesTrans) + delete rootAttributes[Adapter.if] + elementStr = createHTMLElement({ + name: kebabCase(componentName as string), + attributes: rootAttributes, + value: createHTMLElement({ + name: 'block', + attributes: { [Adapter.if]: attributesTrans[Adapter.if] }, + value: parseJSXChildren(children as any) + }) + }, isFirstEmit) + } else { + elementStr = createHTMLElement({ + name: kebabCase(componentName as string), + attributes: attributesTrans, + value: parseJSXChildren(children as any) + }, isFirstEmit) + } + + return elementStr +} + +export function generateHTMLTemplate (template: t.JSXElement, name: string) { + return createHTMLElement({ + name: 'template', + attributes: { + name + }, + value: parseJSXElement(template) + }) +} diff --git a/packages/taro-transformer-wx/src/lifecycle.ts b/packages/taro-transformer-wx/src/lifecycle.ts new file mode 100644 index 000000000000..f52025784000 --- /dev/null +++ b/packages/taro-transformer-wx/src/lifecycle.ts @@ -0,0 +1,31 @@ +export enum Lifecycle { + constructor = 'constructor', + componentWillMount = 'componentWillMount', + componentDidMount = 'componentDidMount', + componentWillUpdate = 'componentWillUpdate', + componentDidUpdate = 'componentDidUpdate', + componentWillUnmount = 'componentWillUnmount', + componentDidCatch = 'componentDidCatch', + componentDidShow = 'componentDidShow', + componentDidHide = 'componentDidHide', + componentDidAttached = 'componentDidAttached', + componentDidMoved = 'componentDidMoved', + shouldComponentUpdate = 'shouldComponentUpdate', + componentWillReceiveProps = 'componentWillReceiveProps' +} + +export const PageLifecycle = { + [Lifecycle.componentDidMount]: 'onLaunch', + [Lifecycle.componentWillMount]: 'onLoad', + [Lifecycle.componentWillUnmount]: 'onUnload', + [Lifecycle.componentDidShow]: 'onShow', + [Lifecycle.componentDidHide]: 'onHide' +} + +export const ComponentLifeCycle = { + [Lifecycle.componentWillMount]: 'created', + [Lifecycle.componentDidAttached]: 'attached', + [Lifecycle.componentDidMount]: 'ready', + [Lifecycle.componentDidMoved]: 'moved', + [Lifecycle.componentWillUnmount]: 'detached' +} diff --git a/packages/taro-transformer-wx/src/options.ts b/packages/taro-transformer-wx/src/options.ts new file mode 100644 index 000000000000..78410689900b --- /dev/null +++ b/packages/taro-transformer-wx/src/options.ts @@ -0,0 +1,68 @@ +import { TransformOptions } from '@babel/core' + +import { Adapters } from './adapter' +import { buildVistor } from './class-method-renamer' +import { isTestEnv } from './env' +import { eslintValidation } from './eslint' +import { functionalComponent, Status } from './functional' + +export interface Options { + isRoot?: boolean + isApp?: boolean + // outputPath: string, + sourcePath: string + sourceDir?: string + code: string + isTyped: boolean + isNormal?: boolean + env?: Object + adapter?: Adapters + jsxAttributeNameReplace?: Object + rootProps?: object +} + +export let transformOptions: Options = {} as Options + +export const setTransformOptions = (options: Options) => { + transformOptions = { ...options } +} + +export const buildBabelTransformOptions: () => TransformOptions = () => { + Status.isSFC = false + let plugins = [ + require('babel-plugin-transform-do-expressions'), + require('babel-plugin-transform-export-extensions'), + require('babel-plugin-transform-flow-strip-types'), + [require('babel-plugin-transform-define').default, transformOptions.env] + ] + if (!transformOptions.isNormal) { + plugins.push(buildVistor()) + } + return { + filename: transformOptions.sourcePath, + babelrc: false, + parserOpts: { + sourceType: 'module', + plugins: [ + 'classProperties', + 'jsx', + 'flow', + 'flowComment', + 'trailingFunctionCommas', + 'asyncFunctions', + 'exponentiationOperator', + 'asyncGenerators', + 'objectRestSpread', + 'decorators', + 'dynamicImport', + 'doExpressions', + 'exportExtensions' + ] as any[] + }, + plugins: plugins + .concat(require('babel-plugin-preval')) + .concat(process.env.TARO_ENV === 'rn' ? [] : functionalComponent) + .concat(process.env.ESLINT === 'false' || transformOptions.isNormal || transformOptions.isTyped ? [] : eslintValidation) + .concat((isTestEnv) ? [] : require('babel-plugin-minify-dead-code').default) + } +} diff --git a/packages/taro-transformer-wx/src/plugins.ts b/packages/taro-transformer-wx/src/plugins.ts new file mode 100644 index 000000000000..2ef27fb089a7 --- /dev/null +++ b/packages/taro-transformer-wx/src/plugins.ts @@ -0,0 +1,50 @@ +import * as t from '@babel/types' + +function isString (node) { + return t.isLiteral(node as any) && typeof node.value === 'string' +} + +function buildBinaryExpression (left, right) { + return t.binaryExpression('+', left, right) +} +export function templateLiterals (path, state) { + + let nodes: Array = [] + + const expressions = path.get('expressions') + + for (const elem of (path.node.quasis)) { + nodes.push(t.stringLiteral(elem.value.cooked)) + + const expr = expressions.shift() + if (expr) { + // tslint:disable-next-line:no-multi-spaces + if (state.opts.spec && !expr.isBaseType('string') && !expr.isBaseType('number')) { + nodes.push(t.callExpression(t.identifier('String'), [expr.node])) + } else { + nodes.push(expr.node) + } + } + } + + // filter out empty string literals + nodes = nodes.filter((n) => !t.isLiteral(n, { value: '' })) + + // since `+` is left-to-right associative + // ensure the first node is a string if first/second isn't + if (!isString(nodes[0]) && !isString(nodes[1])) { + nodes.unshift(t.stringLiteral('')) + } + + if (nodes.length > 1) { + let root = buildBinaryExpression(nodes.shift(), nodes.shift()) + + for (const node of nodes) { + root = buildBinaryExpression(root, node) + } + + path.replaceWith(root) + } else { + path.replaceWith(nodes[0]) + } +} diff --git a/packages/taro-transformer-wx/src/plugins/remove-dead-code.js b/packages/taro-transformer-wx/src/plugins/remove-dead-code.js new file mode 100644 index 000000000000..421b5b17c771 --- /dev/null +++ b/packages/taro-transformer-wx/src/plugins/remove-dead-code.js @@ -0,0 +1,1344 @@ +/* eslint-disable */ +// 修改自: https://github.com/babel/minify/blob/master/packages/babel-plugin-minify-dead-code-elimination/src/index.js +// 主要更改了 `toStatements` 函数,remove if statement 发生在 render JSX 函数时不生成 block statement +const { some } = require("lodash"); +const { markEvalScopes, hasEval } = require("babel-helper-mark-eval-scopes"); +const evaluate = require("babel-helper-evaluate-path"); + +function evaluateTruthy(path) { + const res = evaluate(path); + if (res.confident) return !!res.value; +} + + +function prevSiblings(path) { + const parentPath = path.parentPath; + const siblings = []; + + let key = parentPath.key; + + while ((path = parentPath.getSibling(--key)).type) { + siblings.push(path); + } + return siblings; +} + +function forEachAncestor(path, callback) { + while ((path = path.parentPath)) { + callback(path); + } +} + +function containJSXElement (path) { + let matched = false + path.traverse({ + JSXElement (p) { + matched = true + p.stop() + } + }) + return matched +} + +module.exports = ({ types: t, traverse }) => { + const removeOrVoid = require("babel-helper-remove-or-void")(t); + const shouldRevisit = Symbol("shouldRevisit"); + + // this is used for tracking fn params that can be removed + // as traversal takes place from left and + // unused params can be removed only on the right + const markForRemoval = Symbol("markForRemoval"); + + const main = { + // remove side effectless statement + ExpressionStatement(path) { + if (path.get("expression").isPure()) { + removeOrVoid(path); + } + }, + + Function: { + // Let's take all the vars in a function that are not in the top level scope and hoist them + // with the first var declaration in the top-level scope. This transform in itself may + // not yield much returns (or even can be marginally harmful to size). However it's great + // for taking away statements from blocks that can be only expressions which the `simplify` + // plugin can turn into other things (e.g. if => conditional). + exit(path) { + // This hurts gzip size. + if (!this.optimizeRawSize) { + return; + } + + const { node, scope } = path; + const seen = new Set(); + const declars = []; + const mutations = []; + for (const name in scope.bindings) { + const binding = scope.bindings[name]; + if (!binding.path.isVariableDeclarator()) { + continue; + } + + const declarPath = binding.path.parentPath; + if (seen.has(declarPath)) { + continue; + } + seen.add(declarPath); + + if (declarPath.parentPath.isForInStatement()) { + continue; + } + + if (declarPath.parentPath.parentPath.isFunction()) { + continue; + } + + if (!declarPath.node || !declarPath.node.declarations) { + continue; + } + + const assignmentSequence = []; + for (const declar of declarPath.node.declarations) { + declars.push(declar); + if (declar.init) { + assignmentSequence.push( + t.assignmentExpression("=", declar.id, declar.init) + ); + mutations.push(() => { + declar.init = null; + }); + } + } + + if (assignmentSequence.length) { + mutations.push(() => + declarPath.replaceWith(t.sequenceExpression(assignmentSequence)) + ); + } else { + mutations.push(() => removeOrVoid(declarPath)); + } + } + + if (declars.length) { + mutations.forEach(f => f()); + for (const statement of node.body.body) { + if (t.isVariableDeclaration(statement)) { + statement.declarations.push(...declars); + return; + } + } + const varDecl = t.variableDeclaration("var", declars); + node.body.body.unshift(varDecl); + } + } + }, + + // Remove bindings with no references. + Scope: { + exit(path) { + if (path.node[shouldRevisit]) { + delete path.node[shouldRevisit]; + path.visit(); + } + }, + + enter(path) { + if (path.isProgram()) { + return; + } + + if (hasEval(path.scope)) { + return; + } + + const { scope } = path; + + // if the scope is created by a function, we obtain its + // parameter list + const canRemoveParams = path.isFunction() && path.node.kind !== "set"; + const paramsList = canRemoveParams ? path.get("params") : []; + + for (let i = paramsList.length - 1; i >= 0; i--) { + const param = paramsList[i]; + + if (param.isIdentifier()) { + const binding = scope.bindings[param.node.name]; + if (!binding) continue; + + if (binding.referenced) { + // when the first binding is referenced (right to left) + // exit without marking anything after this + break; + } + + binding[markForRemoval] = true; + continue; + } else if (param.isAssignmentPattern()) { + const left = param.get("left"); + const right = param.get("right"); + + if (left.isIdentifier() && right.isPure()) { + const binding = scope.bindings[left.node.name]; + if (binding.referenced) { + // when the first binding is referenced (right to left) + // exit without marking anything after this + break; + } + + binding[markForRemoval] = true; + continue; + } + } + + // other patterns - assignment, object have side-effects + // and cannot be safely removed + break; + } + + for (const name in scope.bindings) { + const binding = scope.bindings[name]; + + if (!binding.referenced && binding.kind !== "module") { + if ( + binding.kind === "param" && + (this.keepFnArgs || !binding[markForRemoval]) + ) { + continue; + } else if (binding.path.isVariableDeclarator()) { + const declaration = binding.path.parentPath; + const maybeBlockParent = declaration.parentPath; + if ( + maybeBlockParent && + maybeBlockParent.isForXStatement({ + left: declaration.node + }) + ) { + // Can't remove if in a for-in/for-of/for-await statement `for (var x in wat)`. + continue; + } + } else if (!scope.isPure(binding.path.node)) { + // TODO: AssignmentPattern are marked as impure and unused ids aren't removed yet + continue; + } else if ( + binding.path.isFunctionExpression() || + binding.path.isClassExpression() + ) { + // `bar(function foo() {})` foo is not referenced but it's used. + continue; + } else if ( + // ClassDeclaration has binding in two scopes + // 1. The scope in which it is declared + // 2. The class's own scope + binding.path.isClassDeclaration() && + binding.path === scope.path + ) { + continue; + } + + const mutations = []; + let bail = false; + // Make sure none of the assignments value is used + binding.constantViolations.forEach(p => { + if (bail || p === binding.path) { + return; + } + + if (!p.parentPath.isExpressionStatement()) { + bail = true; + } + + if (p.isAssignmentExpression()) { + if ( + t.isArrayPattern(p.node.left) || + t.isObjectPattern(p.node.left) + ) { + bail = true; + } else if (p.get("right").isPure()) { + mutations.push(() => removeOrVoid(p)); + } else { + mutations.push(() => p.replaceWith(p.get("right"))); + } + } + }); + + if (bail) { + continue; + } + + if (binding.path.isVariableDeclarator()) { + if (!binding.path.get("id").isIdentifier()) { + // deopt for object and array pattern + continue; + } + + // if declarator has some impure init expression + // var x = foo(); + // => foo(); + if ( + binding.path.node.init && + !scope.isPure(binding.path.node.init) && + binding.path.parentPath.node.declarations + ) { + // binding path has more than one declarations + if (binding.path.parentPath.node.declarations.length !== 1) { + continue; + } + binding.path.parentPath.replaceWith(binding.path.node.init); + } else { + updateReferences(binding.path, this); + removeOrVoid(binding.path); + } + } else { + updateReferences(binding.path, this); + removeOrVoid(binding.path); + } + + mutations.forEach(f => f()); + scope.removeBinding(name); + } else if (binding.constant) { + if ( + binding.path.isFunctionDeclaration() || + (binding.path.isVariableDeclarator() && + binding.path.get("init").isFunction()) + ) { + const fun = binding.path.isFunctionDeclaration() + ? binding.path + : binding.path.get("init"); + let allInside = true; + for (const ref of binding.referencePaths) { + if (!ref.find(p => p.node === fun.node)) { + allInside = false; + break; + } + } + + if (allInside) { + scope.removeBinding(name); + updateReferences(binding.path, this); + removeOrVoid(binding.path); + continue; + } + } + + if ( + binding.references === 1 && + binding.kind !== "param" && + binding.kind !== "module" && + binding.constant + ) { + let replacement = binding.path.node; + let replacementPath = binding.path; + let isReferencedBefore = false; + + const refPath = binding.referencePaths[0]; + + if (t.isVariableDeclarator(replacement)) { + const _prevSiblings = prevSiblings(replacementPath); + // traverse ancestors of a reference checking if it's before declaration + forEachAncestor(refPath, ancestor => { + if (_prevSiblings.indexOf(ancestor) > -1) { + isReferencedBefore = true; + } + }); + + // deopt if reference is in different scope than binding + // since we don't know if it's sync or async execution + // (i.e. whether value has been assigned to a reference or not) + if (isReferencedBefore && refPath.scope !== binding.scope) { + continue; + } + + // simulate hoisting by replacing value + // with undefined if declaration is after reference + replacement = isReferencedBefore + ? t.unaryExpression("void", t.numericLiteral(0), true) + : replacement.init; + + // Bail out for ArrayPattern and ObjectPattern + // TODO: maybe a more intelligent approach instead of simply bailing out + if (!replacementPath.get("id").isIdentifier()) { + continue; + } + replacementPath = replacementPath.get("init"); + } + + if (!replacement) { + continue; + } + + if (!scope.isPure(replacement, true) && !isReferencedBefore) { + continue; + } + + let bail = false; + + if (replacementPath.isIdentifier()) { + const binding = scope.getBinding(replacement.name); + // the reference should be in the same scope + // and the replacement should be a constant - this is to + // ensure that the duplication of replacement is not affected + // https://github.com/babel/minify/issues/685 + bail = !( + binding && + refPath.scope.getBinding(replacement.name) === binding && + binding.constantViolations.length === 0 + ); + } else { + replacementPath.traverse({ + Function(path) { + path.skip(); + }, + + ReferencedIdentifier({ node }) { + if (bail) { + return; + } + const binding = scope.getBinding(node.name); + if ( + binding && + refPath.scope.getBinding(node.name) === binding + ) { + bail = binding.constantViolations.length > 0; + } + } + }); + } + + if (bail) { + continue; + } + + let parent = binding.path.parent; + if (t.isVariableDeclaration(parent)) { + parent = binding.path.parentPath.parent; + } + + // 1. Make sure we share the parent with the node. In other words it's lexically defined + // and not in an if statement or otherwise. + // 2. If the replacement is an object then we have to make sure we are not in a loop or a function + // because otherwise we'll be inlining and doing a lot more allocation than we have to + // which would also could affect correctness in that they are not the same reference. + let mayLoop = false; + const sharesRoot = refPath.find(({ node }) => { + if (!mayLoop) { + mayLoop = + t.isWhileStatement(node) || + t.isFor(node) || + t.isFunction(node); + } + return node === parent; + }); + + // Anything that inherits from Object. + const isObj = n => + t.isFunction(n) || + t.isObjectExpression(n) || + t.isArrayExpression(n); + + const isReplacementObj = + isObj(replacement) || some(replacement, isObj); + + if (!sharesRoot || (isReplacementObj && mayLoop)) { + continue; + } + + // check if it's safe to replace + // To solve https://github.com/babel/minify/issues/691 + // Here we bail for property checks using the "in" operator + // This is because - `in` is a side-effect-free operation but the property + // could be deleted between the replacementPath and referencePath + // It is expensive to compute the delete operation and we bail for + // all the binary "in" operations + let inExpression = replacementPath.isBinaryExpression({ + operator: "in" + }); + + if (!inExpression) { + replacementPath.traverse({ + Function(path) { + path.skip(); + }, + BinaryExpression(path) { + if (path.node.operator === "in") { + inExpression = true; + path.stop(); + } + } + }); + } + + if (inExpression) { + continue; + } + + const replaced = replace(binding.referencePaths[0], { + binding, + scope, + replacement, + replacementPath + }); + + if (replaced) { + scope.removeBinding(name); + if (binding.path.node) { + removeOrVoid(binding.path); + } + } + } + } + } // end-for-of + } + }, + + // Remove unreachable code. + BlockStatement(path) { + const paths = path.get("body"); + + let purge = false; + + for (let i = 0; i < paths.length; i++) { + const p = paths[i]; + + if (!purge && p.isCompletionStatement()) { + purge = true; + continue; + } + + if (purge && !canExistAfterCompletion(p)) { + removeOrVoid(p); + } + } + }, + + // Double check unreachable code and remove return statements that + // have no semantic meaning + ReturnStatement(path) { + const { node } = path; + if (!path.inList) { + return; + } + + // Not last in its block? (See BlockStatement visitor) + if ( + path.container.length - 1 !== path.key && + !canExistAfterCompletion(path.getSibling(path.key + 1)) && + path.parentPath.isBlockStatement() + ) { + // This is probably a new oppurtinity by some other transform + // let's call the block visitor on this again before proceeding. + path.parentPath.pushContext(path.context); + path.parentPath.visit(); + path.parentPath.popContext(); + + return; + } + + if (node.argument) { + return; + } + + let noNext = true; + let parentPath = path.parentPath; + while (parentPath && !parentPath.isFunction() && noNext) { + // https://github.com/babel/minify/issues/265 + if (hasLoopParent(parentPath)) { + noNext = false; + break; + } + + const nextPath = parentPath.getSibling(parentPath.key + 1); + if (nextPath.node) { + if (nextPath.isReturnStatement()) { + nextPath.pushContext(path.context); + nextPath.visit(); + nextPath.popContext(); + if (parentPath.getSibling(parentPath.key + 1).node) { + noNext = false; + break; + } + } else { + noNext = false; + break; + } + } + + parentPath = parentPath.parentPath; + } + + if (noNext) { + removeOrVoid(path); + } + }, + + ConditionalExpression(path) { + const { node } = path; + const evaluateTest = evaluateTruthy(path.get("test")); + if (evaluateTest === true) { + path.replaceWith(node.consequent); + } else if (evaluateTest === false) { + path.replaceWith(node.alternate); + } + }, + + SwitchStatement: { + exit(path) { + const discriminantPath = path.get("discriminant"); + const evaluated = evaluate(discriminantPath, { tdz: this.tdz }); + + if (!evaluated.confident) return; + + // the simplify transformation might have brought in the previous + // expressions into the switch's test expression and instead of + // bailing out of impure path, we collect the impurities of it's + // a sequence expression and bail out if the primary test itself + // is impure + let beforeTest = []; + if (t.isSequenceExpression(discriminantPath.node)) { + const expressions = discriminantPath.get("expressions"); + const lastExpression = expressions[expressions.length - 1]; + if (!lastExpression.isPure()) { + return; + } + + beforeTest = [ + t.expressionStatement( + t.sequenceExpression( + expressions + .slice(0, expressions.length - 1) + .map(path => path.node) + ) + ) + ]; + } else if (!discriminantPath.isPure()) { + return; + } + + const discriminant = evaluated.value; + const cases = path.get("cases"); + + let matchingCaseIndex = -1; + let defaultCaseIndex = -1; + + for (let i = 0; i < cases.length; i++) { + const test = cases[i].get("test"); + + // handle default case + if (test.node === null) { + defaultCaseIndex = i; + continue; + } + + const testResult = evaluate(test, { + tdz: this.tdz + }); + + // if we are not able to deternine a test during + // compile time, we terminate immediately + if (!testResult.confident) return; + + if (testResult.value === discriminant) { + matchingCaseIndex = i; + break; + } + } + + let result; + + if (matchingCaseIndex === -1) { + if (defaultCaseIndex === -1) { + path.skip(); + path.replaceWithMultiple(extractVars(path)); + return; + } else { + result = getStatementsUntilBreak(defaultCaseIndex); + } + } else { + result = getStatementsUntilBreak(matchingCaseIndex); + } + + if (result.bail) return; + + // we extract vars from the entire switch statement + // and there will be duplicates which + // will be again removed by DCE + replaceSwitch([ + ...extractVars(path), + ...beforeTest, + ...result.statements + ]); + + function getStatementsUntilBreak(start) { + const result = { bail: false, statements: [] }; + + for (let i = start; i < cases.length; i++) { + const consequent = cases[i].get("consequent"); + + for (let j = 0; j < consequent.length; j++) { + const _isBreaking = isBreaking(consequent[j], path); + if (_isBreaking.bail) { + result.bail = true; + return result; + } + if (_isBreaking.break) { + // compute no more + // exit out of the loop + return result; + } else { + result.statements.push(consequent[j].node); + } + } + } + + return result; + } + + function replaceSwitch(statements) { + let isBlockRequired = false; + + for (let i = 0; i < statements.length; i++) { + if (t.isVariableDeclaration(statements[i], { kind: "let" })) { + isBlockRequired = true; + break; + } + if (t.isVariableDeclaration(statements[i], { kind: "const" })) { + isBlockRequired = true; + break; + } + } + + if (isBlockRequired) { + path.replaceWith(t.BlockStatement(statements)); + } else { + path.replaceWithMultiple(statements); + } + } + } + }, + + WhileStatement(path) { + const test = path.get("test"); + const result = evaluate(test, { tdz: this.tdz }); + if (result.confident && test.isPure() && !result.value) { + path.remove(); + } + }, + + ForStatement(path) { + const test = path.get("test"); + if (!test.isPure()) return; + + const result = evaluate(test, { tdz: this.tdz }); + if (result.confident) { + if (result.value) { + test.remove(); + } else { + const init = path.get("init"); + if (init.node && !init.isPure()) { + path.replaceWith(init); + } else { + path.remove(); + } + } + } + }, + + DoWhileStatement(path) { + const test = path.get("test"); + const result = evaluate(test, { tdz: this.tdz }); + if (result.confident && test.isPure() && !result.value) { + const body = path.get("body"); + + if (body.isBlockStatement()) { + const stmts = body.get("body"); + for (const stmt of stmts) { + const _isBreaking = isBreaking(stmt, path); + if (_isBreaking.bail || _isBreaking.break) return; + const _isContinuing = isContinuing(stmt, path); + if (_isContinuing.bail || isContinuing.continue) return; + } + path.replaceWith(body.node); + } else if (body.isBreakStatement()) { + const _isBreaking = isBreaking(body, path); + if (_isBreaking.bail) return; + if (_isBreaking.break) path.remove(); + } else if (body.isContinueStatement()) { + return; + } else { + path.replaceWith(body.node); + } + } + }, + + // Join assignment and definition when in sequence. + // var x; x = 1; -> var x = 1; + AssignmentExpression(path) { + if ( + !path.get("left").isIdentifier() || + !path.parentPath.isExpressionStatement() + ) { + return; + } + + const prev = path.parentPath.getSibling(path.parentPath.key - 1); + if (!(prev && prev.isVariableDeclaration())) { + return; + } + + const declars = prev.node.declarations; + if ( + declars.length !== 1 || + declars[0].init || + declars[0].id.name !== path.get("left").node.name + ) { + return; + } + declars[0].init = path.node.right; + removeOrVoid(path); + }, + + // Remove named function expression name. While this is dangerous as it changes + // `function.name` all minifiers do it and hence became a standard. + FunctionExpression(path) { + if (!this.keepFnName) { + removeUnreferencedId(path); + } + }, + + // remove class names + ClassExpression(path) { + if (!this.keepClassName) { + removeUnreferencedId(path); + } + }, + + // Put the `var` in the left if feasible. + ForInStatement(path) { + const left = path.get("left"); + if (!left.isIdentifier()) { + return; + } + + const binding = path.scope.getBinding(left.node.name); + if (!binding) { + return; + } + + if ( + binding.scope.getFunctionParent() !== path.scope.getFunctionParent() + ) { + return; + } + + if (!binding.path.isVariableDeclarator()) { + return; + } + + if ( + binding.path.parentPath.parentPath.isForInStatement({ + left: binding.path.parent + }) + ) { + return; + } + + // If it has company then it's probably more efficient to keep. + if (binding.path.parent.declarations.length > 1) { + return; + } + + // meh + if (binding.path.node.init) { + return; + } + + removeOrVoid(binding.path); + path.node.left = t.variableDeclaration("var", [ + t.variableDeclarator(left.node) + ]); + binding.path = path.get("left").get("declarations")[0]; + } + }; + + return { + name: "minify-dead-code-elimination", + visitor: { + IfStatement: { + exit(path, { opts: { tdz = false } = {} }) { + const consequent = path.get("consequent"); + const alternate = path.get("alternate"); + const test = path.get("test"); + + const evalResult = evaluate(test, { tdz }); + const isPure = test.isPure(); + + const replacements = []; + const isRenderFunction = !!path.findParent(p => p.isClassMethod() && t.isIdentifier(p.node.key) && p.node.key.name.startsWith('render')) && containJSXElement(path) + if (evalResult.confident && !isPure && test.isSequenceExpression()) { + replacements.push( + t.expressionStatement(extractSequenceImpure(test)) + ); + } + + // we can check if a test will be truthy 100% and if so then we can inline + // the consequent and completely ignore the alternate + // + // if (true) { foo; } -> { foo; } + // if ("foo") { foo; } -> { foo; } + // + if (evalResult.confident && evalResult.value) { + path.replaceWithMultiple([ + ...replacements, + ...toStatements(consequent, isRenderFunction), + ...extractVars(alternate) + ]); + return; + } + + // we can check if a test will be falsy 100% and if so we can inline the + // alternate if there is one and completely remove the consequent + // + // if ("") { bar; } else { foo; } -> { foo; } + // if ("") { bar; } -> + // + if (evalResult.confident && !evalResult.value) { + if (alternate.node) { + path.replaceWithMultiple([ + ...replacements, + ...toStatements(alternate, isRenderFunction), + ...extractVars(consequent) + ]); + return; + } else { + path.replaceWithMultiple([ + ...replacements, + ...extractVars(consequent) + ]); + } + } + + // remove alternate blocks that are empty + // + // if (foo) { foo; } else {} -> if (foo) { foo; } + // + if (alternate.isBlockStatement() && !alternate.node.body.length) { + alternate.remove(); + // For if-statements babel-traverse replaces with an empty block + path.node.alternate = null; + } + + // if the consequent block is empty turn alternate blocks into a consequent + // and flip the test + // + // if (foo) {} else { bar; } -> if (!foo) { bar; } + // + if ( + consequent.isBlockStatement() && + !consequent.node.body.length && + alternate.isBlockStatement() && + alternate.node.body.length + ) { + consequent.replaceWith(alternate.node); + alternate.remove(); + // For if-statements babel-traverse replaces with an empty block + path.node.alternate = null; + test.replaceWith(t.unaryExpression("!", test.node, true)); + } + } + }, + + EmptyStatement(path) { + if (path.parentPath.isBlockStatement() || path.parentPath.isProgram()) { + path.remove(); + } + }, + + Program: { + exit( + path, + { + opts: { + // set defaults + optimizeRawSize = false, + keepFnName = false, + keepClassName = false, + keepFnArgs = false, + tdz = false + } = {} + } = {} + ) { + (traverse.clearCache || traverse.cache.clear)(); + path.scope.crawl(); + + markEvalScopes(path); + + // We need to run this plugin in isolation. + path.traverse(main, { + functionToBindings: new Map(), + optimizeRawSize, + keepFnName, + keepClassName, + keepFnArgs, + tdz + }); + } + } + } + }; + + function toStatements(path, isRenderFunction) { + const { node } = path; + if (path.isBlockStatement()) { + if (isRenderFunction) { + return node.body + } + let hasBlockScoped = false; + + for (let i = 0; i < node.body.length; i++) { + const bodyNode = node.body[i]; + if (t.isBlockScoped(bodyNode)) { + hasBlockScoped = true; + } + } + + if (!hasBlockScoped) { + return node.body; + } + } + return [node]; + } + + // Extracts vars from a path + // Useful for removing blocks or paths that can contain + // variable declarations inside them + // Note: + // drops are inits + // extractVars({ var x = 5, y = x }) => var x, y; + function extractVars(path) { + const declarators = []; + + if (path.isVariableDeclaration({ kind: "var" })) { + for (const decl of path.node.declarations) { + const bindingIds = Object.keys(t.getBindingIdentifiers(decl.id)); + + declarators.push( + ...bindingIds.map(name => t.variableDeclarator(t.identifier(name))) + ); + } + } else { + path.traverse({ + VariableDeclaration(varPath) { + if (!varPath.isVariableDeclaration({ kind: "var" })) return; + + if (!isSameFunctionScope(varPath, path)) return; + + for (const decl of varPath.node.declarations) { + const bindingIds = Object.keys(t.getBindingIdentifiers(decl.id)); + declarators.push( + ...bindingIds.map(name => + t.variableDeclarator(t.identifier(name)) + ) + ); + } + } + }); + } + + if (declarators.length <= 0) return []; + + return [t.variableDeclaration("var", declarators)]; + } + + function replace(path, options) { + const { replacement, replacementPath, scope, binding } = options; + + // Same name, different binding. + if (scope.getBinding(path.node.name) !== binding) { + return; + } + + // We don't want to move code around to different scopes because: + // 1. Original bindings that is referenced could be shadowed + // 2. Moving defintions to potentially hot code is bad + if (scope !== path.scope) { + if (t.isClass(replacement) || t.isFunction(replacement)) { + return; + } + + let bail = false; + traverse( + replacement, + { + Function(path) { + if (bail) { + return; + } + bail = true; + path.stop(); + } + }, + scope + ); + + if (bail) { + return; + } + } + + // Avoid recursion. + if (path.find(({ node }) => node === replacement)) { + return; + } + + // https://github.com/babel/minify/issues/611 + // this is valid only for FunctionDeclaration where we convert + // function declaration to expression in the next step + if (replacementPath.isFunctionDeclaration()) { + const fnName = replacementPath.get("id").node.name; + for (let name in replacementPath.scope.bindings) { + if (name === fnName) { + return; + } + } + } + + // https://github.com/babel/minify/issues/130 + if (!t.isExpression(replacement)) { + t.toExpression(replacement); + } + + // We don't remove fn name here, we let the FnExpr & ClassExpr visitors + // check its references and remove unreferenced ones + // if (t.isFunction(replacement)) { + // replacement.id = null; + // } + + path.replaceWith(replacement); + return true; + } + + function updateReferences(fnToDeletePath) { + if (!fnToDeletePath.isFunction()) { + return; + } + + fnToDeletePath.traverse({ + ReferencedIdentifier(path) { + const { node, scope } = path; + const binding = scope.getBinding(node.name); + + if ( + !binding || + !binding.path.isFunction() || + binding.scope === scope || + !binding.constant + ) { + return; + } + + const index = binding.referencePaths.indexOf(path); + if (index === -1) { + return; + } + binding.references--; + binding.referencePaths.splice(index, 1); + if (binding.references === 0) { + binding.referenced = false; + } + + if (binding.references <= 1 && binding.scope.path.node) { + binding.scope.path.node[shouldRevisit] = true; + } + } + }); + } + + function removeUnreferencedId(path) { + const id = path.get("id").node; + if (!id) { + return; + } + + const { node, scope } = path; + const binding = scope.getBinding(id.name); + + // Check if shadowed or is not referenced. + if (binding && (binding.path.node !== node || !binding.referenced)) { + node.id = null; + } + } + + // path1 -> path2 + // is path1 an ancestor of path2 + function isAncestor(path1, path2) { + return !!path2.findParent(parent => parent === path1); + } + + function isSameFunctionScope(path1, path2) { + return path1.scope.getFunctionParent() === path2.scope.getFunctionParent(); + } + + function isBreaking(stmt, path) { + return isControlTransfer(stmt, path, "break"); + } + + function isContinuing(stmt, path) { + return isControlTransfer(stmt, path, "continue"); + } + + // tells if a "stmt" is a break/continue statement + function isControlTransfer(stmt, path, control = "break") { + const { [control]: type } = { + break: "BreakStatement", + continue: "ContinueStatement" + }; + if (!type) { + throw new Error("Can only handle break and continue statements"); + } + const checker = `is${type}`; + + if (stmt[checker]()) { + return _isControlTransfer(stmt, path); + } + + let isTransferred = false; + let result = { + [control]: false, + bail: false + }; + + stmt.traverse({ + [type](cPath) { + // if we already detected a break/continue statement, + if (isTransferred) return; + + result = _isControlTransfer(cPath, path); + + if (result.bail || result[control]) { + isTransferred = true; + } + } + }); + + return result; + + function _isControlTransfer(cPath, path) { + const label = cPath.get("label"); + + if (label.node !== null) { + // labels are fn scoped and not accessible by inner functions + // path is the switch statement + if (!isSameFunctionScope(path, cPath)) { + // we don't have to worry about this break statement + return { + break: false, + bail: false + }; + } + + // here we handle the break labels + // if they are outside switch, we bail out + // if they are within the case, we keep them + let labelPath; + if (path.scope.getLabel) { + labelPath = getLabel(label.node.name, path); + } else { + labelPath = path.scope.getBinding(label.node.name).path; + } + const _isAncestor = isAncestor(labelPath, path); + + return { + bail: _isAncestor, + [control]: _isAncestor + }; + } + + // set the flag that it is indeed breaking + let isCTransfer = true; + + // this flag is to capture + // switch(0) { case 0: while(1) if (x) break; } + let possibleRunTimeControlTransfer = false; + + // and compute if it's breaking the correct thing + let parent = cPath.parentPath; + + while (parent !== stmt.parentPath) { + // loops and nested switch cases + if (parent.isLoop() || parent.isSwitchCase()) { + // invalidate all the possible runtime breaks captured + // while (1) { if (x) break; } + possibleRunTimeControlTransfer = false; + + // and set that it's not breaking our switch statement + isCTransfer = false; + break; + } + // + // this is a special case and depends on + // the fact that SwitchStatement is handled in the + // exit hook of the traverse + // + // switch (0) { + // case 0: if (x) break; + // } + // + // here `x` is runtime only. + // in this case, we need to bail out. So we depend on exit hook + // of switch so that, it would have visited the IfStatement first + // before the SwitchStatement and would have removed the + // IfStatement if it was a compile time determined + // + if (parent.isIfStatement()) { + possibleRunTimeControlTransfer = true; + } + parent = parent.parentPath; + } + + return { + [control]: possibleRunTimeControlTransfer || isCTransfer, + bail: possibleRunTimeControlTransfer + }; + } + } + + // things that are hoisted + function canExistAfterCompletion(path) { + return ( + path.isFunctionDeclaration() || + path.isVariableDeclaration({ kind: "var" }) + ); + } + + function getLabel(name, _path) { + let label, + path = _path; + do { + label = path.scope.getLabel(name); + if (label) { + return label; + } + } while ((path = path.parentPath)); + return null; + } + + function hasLoopParent(path) { + let parent = path; + do { + if (parent.isLoop()) { + return true; + } + } while ((parent = parent.parentPath)); + return false; + } + + function extractSequenceImpure(seq) { + const expressions = seq.get("expressions"); + const result = []; + for (let i = 0; i < expressions.length; i++) { + if (!expressions[i].isPure()) { + result.push(expressions[i].node); + } + } + return t.sequenceExpression(result); + } +}; \ No newline at end of file diff --git a/packages/taro-transformer-wx/src/render-props.ts b/packages/taro-transformer-wx/src/render-props.ts new file mode 100644 index 000000000000..802c4c175a2c --- /dev/null +++ b/packages/taro-transformer-wx/src/render-props.ts @@ -0,0 +1,106 @@ +import { NodePath } from '@babel/traverse' +import * as t from '@babel/types' +import { get as safeGet } from 'lodash' + +import { buildBlockElement } from './jsx' +import { buildConstVariableDeclaration, codeFrameError,createRandomLetters } from './utils' + +const renderPropsMap = new Map() + +const RENDER_PROPS_EVENTS = '$$renderPropsEvents' + +export function injectRenderPropsListener (attrPath: NodePath, attrName: string, attrExpr: t.ArrowFunctionExpression, componentName: string) { + let renderClosureFuncName = renderPropsMap.get(componentName + '_' + attrName); + if (!renderClosureFuncName) { + const randomLetters = createRandomLetters(5); + renderClosureFuncName = attrName + randomLetters; + renderPropsMap.set(componentName + '_' + attrName, renderClosureFuncName); + } + const jsxDecl = buildConstVariableDeclaration(renderClosureFuncName, attrExpr) + const block = buildBlockElement([], true) + const renderPropsArgs = t.memberExpression(t.thisExpression(), t.identifier(renderClosureFuncName)) + block.children = [ + t.jSXExpressionContainer(t.callExpression(t.identifier(renderClosureFuncName), [renderPropsArgs])) + ] + const listener = buildListener(renderClosureFuncName, renderPropsArgs) + const stemParent = attrPath.getStatementParent() + stemParent?.insertBefore(listener) + stemParent?.insertBefore(jsxDecl) + attrPath.get('value').replaceWith(t.jSXExpressionContainer(block)) + setRenderPropsEvents(attrPath, renderClosureFuncName) +} + +function setRenderPropsEvents (attrPath: NodePath, renderClosureFuncName: string) { + const classDecl = attrPath.findParent(p => p.isClassDeclaration()) + if (classDecl && classDecl.isClassDeclaration()) { + let hasEvent = false + for (const s of classDecl.node.body.body) { + if (t.isClassProperty(s) && (s.key as any).name === RENDER_PROPS_EVENTS && t.isArrayExpression(s.value)) { + hasEvent = true + if (s.value.elements.some(e => t.isStringLiteral(e) && e.value === renderClosureFuncName)) { + break + } + s.value.elements.push(t.stringLiteral(renderClosureFuncName)) + } + } + + if (!hasEvent) { + classDecl.node.body.body.push(t.classProperty( + t.identifier(RENDER_PROPS_EVENTS), + t.arrayExpression([t.stringLiteral(renderClosureFuncName)]) + )) + } + } +} + +export function injectRenderPropsEmiter (callExpr: NodePath, attrName: string) { + const classDecl = callExpr.findParent(p => p.isClassDeclaration()) + const classDeclName = classDecl && classDecl.isClassDeclaration() && safeGet(classDecl, 'node.id.name', '') + if (typeof classDeclName !== 'string') { + throw codeFrameError(classDecl, '使用 render props 必须指定 class 的名称。') + } + const renderClosureFuncName = renderPropsMap.get(classDeclName + '_' + attrName) || '' + const args: (t.Expression | t.SpreadElement)[] = [t.stringLiteral(renderClosureFuncName)] + if (Array.isArray(callExpr.node.arguments) && callExpr.node.arguments.length) { + args.push(callExpr.node.arguments[0] as t.Identifier) + } + const emitter = t.callExpression( + t.memberExpression(buildEventCenterMemberExpr(), t.identifier('trigger')), + args + ) + const stemParent = callExpr.getStatementParent() + stemParent?.insertBefore(t.expressionStatement(emitter)) +} + +function buildListener (renderClosureFuncName: string, renderPropsArgs: t.MemberExpression) { + return t.expressionStatement( + t.callExpression( + t.memberExpression( + buildEventCenterMemberExpr(), + t.identifier('on') + ), + [t.stringLiteral(renderClosureFuncName), t.arrowFunctionExpression([t.identifier('e')], t.blockStatement([ + t.ifStatement( + t.unaryExpression('!', t.callExpression( + t.memberExpression(t.identifier('Taro'), t.identifier('shallowEqual')), + [t.identifier('e'), renderPropsArgs] + )), + t.blockStatement([ + t.expressionStatement(t.assignmentExpression('=', renderPropsArgs, t.identifier('e'))), + t.expressionStatement(t.callExpression( + t.memberExpression(t.thisExpression(), t.identifier('setState')), + [t.objectExpression([])] + )) + ]) + ) + ]))] + ) + ) +} + +function buildEventCenterMemberExpr () { + return t.memberExpression( + t.identifier('Taro'), + t.identifier('eventCenter') + ) +} diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts new file mode 100644 index 000000000000..ae3ecf7a156a --- /dev/null +++ b/packages/taro-transformer-wx/src/render.ts @@ -0,0 +1,2544 @@ +import { transform as parse } from '@babel/core' +import generate from '@babel/generator' +import traverse, { NodePath, Scope, Visitor } from '@babel/traverse' +import * as t from '@babel/types' +import { cloneDeep, difference, get as safeGet, snakeCase,uniq } from 'lodash' + +import { Adapter, Adapters, isNewPropsSystem } from './adapter' +import { + ALIPAY_BUBBLE_EVENTS, + CLASS_COMPONENT_UID, + COMPID, + DEFAULT_Component_SET, + DEFAULT_Component_SET_COPY, + FN_PREFIX, + GEN_COMP_ID, + HANDLE_LOOP_REF, + INTERNAL_GET_ORIGNAL, + IS_TARO_READY, + LOOP_CALLEE, + LOOP_ORIGINAL, + LOOP_STATE, + MAP_CALL_ITERATOR, + PREV_COMPID, + PROPS_MANAGER, + THIRD_PARTY_COMPONENTS} from './constant' +import { isTestEnv } from './env' +import { Status } from './functional' +import { LoopRef } from './interface' +import { + buildBlockElement, + generateJSXAttr, + parseJSXElement, + setJSXAttr} from './jsx' +import { buildBabelTransformOptions,transformOptions } from './options' +import { + buildConstVariableDeclaration, + codeFrameError, + createRandomLetters, + findFirstIdentifierFromMemberExpression, + findIdentifierFromStatement, + findMethodName, + findParentLoops, + genCompid, + generateAnonymousState, + generateMemberExpressionArray, + getSlotName, + getSuperClassCode, + hasComplexExpression, + incrementId, + isArrayMapCallExpression, + isBlockIfStatement, + isContainFunction, + isContainJSXElement, + isContainStopPropagation, + isDerivedFromProps, + isEmptyDeclarator, + isVarName, + newJSXIfAttr, + noop, + replaceJSXTextWithTextComponent, + reverseBoolean, + setAncestorCondition, + setParentCondition, + setTemplate, + toLetters} from './utils' + +const template = require('@babel/template') +// const template = require('babel-template') + +type ClassMethodsMap = Map> + +function findParents (path: NodePath, predicates: (p: NodePath) => boolean) { + const parents: NodePath[] = [] + // tslint:disable-next-line:no-conditional-assignment + while (path.parentPath) { + if (path.parentPath != null) { + path = path.parentPath as any + if (predicates(path)) { + parents.push(path as any) + } + } + } + + return parents +} + +function isClassDcl (p: NodePath) { + return p.isClassExpression() || p.isClassDeclaration() +} + +interface JSXHandler { + parentNode: t.Node + parentPath: NodePath + statementParent?: NodePath + isReturnStatement?: boolean + isFinalReturn?: boolean + isIfStemInLoop?: boolean +} + +function isChildrenOfJSXAttr (p: NodePath) { + return !!p.findParent(p => p.isJSXAttribute()) +} + +function buildAssignState ( + pendingState: t.ObjectExpression +) { + return t.expressionStatement( + t.callExpression( + t.memberExpression(t.identifier('Object'), t.identifier('assign')), + [ + t.memberExpression(t.thisExpression(), t.identifier('state')), + pendingState + ] + ) + ) +} + +const incrementCalleeId = incrementId() +const incrementLoopArrayId = incrementId() + +export class RenderParser { + public outputTemplate: string + + private classProperties = new Set() + private templates = new Map() + private jsxDeclarations = new Set>() + private loopScopes = new Set() + private returnedPaths: NodePath[] = [] + private usedThisState = new Set() + private loopComponents = new Map, NodePath>() + private loopComponentNames = new Map, string>() + private loopRefIdentifiers = new Map>() + private reserveStateWords = new Set(Status.isSFC ? [] : ['state', 'props']) + private topLevelIfStatement = new Set>() + private usedEvents = new Set() + private customComponentNames: Set + private loopCalleeId = new Set() + private usedThisProperties = new Set() + private incrementCalleeId = isTestEnv ? incrementId() : incrementCalleeId + private loopArrayId = isTestEnv ? incrementId() : incrementLoopArrayId + private classComputedState = new Set() + private propsSettingExpressions = new Map t.ExpressionStatement)[]>() + private genCompidExprs = new Set() + private loopCallees = new Set() + private loopIfStemComponentMap = new Map, t.JSXElement>() + private hasNoReturnLoopStem = false + private isDefaultRender = false + // private renderArg: t.Identifier | t.ObjectPattern | null = null + private renderMethodName = '' + private deferedHandleClosureJSXFunc: Function[] = [] + private ancestorConditions: Set = new Set() + + private renderPath: NodePath + private methods: ClassMethodsMap + private initState: Set + private referencedIdentifiers: Set + private renderScope: Scope + private usedState: Set + private componentProperies: Set + private loopRefs: Map + private refObjExpr: t.ObjectExpression[] + private upperCaseComponentProps: Set + + private finalReturnElement!: t.JSXElement + + handleJSXElement = ( + jsxElementPath: NodePath, + func: ({ parentNode, parentPath, statementParent, isReturnStatement, isFinalReturn }: JSXHandler) => void + ) => { + const parentNode = jsxElementPath.parent as any + const parentPath = jsxElementPath.parentPath as any + const isJSXChildren = t.isJSXElement(parentNode) + if (!isJSXChildren) { + let statementParent = jsxElementPath.getStatementParent() as any + const isReturnStatement = statementParent?.isReturnStatement() + const isIfStemInLoop = this.isIfStemInLoop(jsxElementPath) + const isFinalReturn = statementParent?.getFunctionParent()?.isClassMethod() + if ( + !( + statementParent?.isVariableDeclaration() || + statementParent?.isExpressionStatement() + ) + ) { + statementParent = statementParent?.findParent( + s => s.isVariableDeclaration() || s.isExpressionStatement() + ) as NodePath + } + if (t.isVariableDeclarator(parentNode)) { + if (statementParent) { + const name = findIdentifierFromStatement(statementParent.node as t.VariableDeclaration) + // setTemplate(name, path, templates) + name && this.templates.set(name, jsxElementPath.node) + } + } + func({ parentNode, parentPath, statementParent, isReturnStatement, isFinalReturn, isIfStemInLoop }) + } + } + + private isIfStemInLoop = (p: NodePath): boolean => { + const ifStem = p.findParent(p => p.isIfStatement()) + if (ifStem && ifStem.isIfStatement()) { + const loopStem = ifStem.findParent(p => p.isCallExpression()) + if (loopStem && isArrayMapCallExpression(loopStem as any)) { + return true + } + } + return false + } + + isLiteralOrUndefined = (node: t.Node): node is t.Literal | t.Identifier => t.isLiteral(node) || t.isIdentifier(node, { name: 'undefined' }) + + handleConditionExpr ({ parentNode, parentPath, statementParent }: JSXHandler, jsxElementPath: NodePath) { + if (parentPath.isObjectProperty()) { + const value = parentPath.get('value') + if (value !== jsxElementPath) { + return + } + if (!parentPath.parentPath.isObjectExpression()) { + return + } + const properties = parentPath.parentPath.get('properties') + if (!parentPath.parentPath.parentPath.isMemberExpression()) { + return + } + const rval = parentPath.parentPath.parentPath.get('property') as NodePath + if (!rval || !rval.node || !Array.isArray(properties)) { + return + } + const children = properties.map(p => p).map((p, index) => { + const block = buildBlockElement() + const leftExpression = p.key + const tester = t.binaryExpression('===', leftExpression as any, rval.node as any) + block.children = [t.jSXExpressionContainer((p.node as any).value)] + if (index === 0) { + newJSXIfAttr(block, tester) + } else { + setJSXAttr(block, Adapter.elseif, t.jSXExpressionContainer(tester)) + } + return block + }) + const block = buildBlockElement() + block.children = children + parentPath.parentPath.parentPath.replaceWith(block) + } else if (t.isLogicalExpression(parentNode)) { + const { left, operator, right } = parentNode + const leftExpression = parentPath.get('left') as NodePath + if (operator === '&&' && t.isExpression(left)) { + if (hasComplexExpression(leftExpression as any)) { + generateAnonymousState(this.renderScope, leftExpression, this.referencedIdentifiers, true) + } + const block = buildBlockElement() + newJSXIfAttr(block, leftExpression.node) + block.children = [jsxElementPath.node] + parentPath.replaceWith(block) + if (statementParent) { + const name = findIdentifierFromStatement(statementParent.node as t.VariableDeclaration) + setTemplate(name, jsxElementPath as any, this.templates) + // name && templates.set(name, path.node) + } + } + if (operator === '||' && t.isExpression(left)) { + const newNode = t.conditionalExpression(left, left, right) + parentPath.replaceWith(newNode) + // this.handleConditionExpr({ parentNode: newNode, parentPath, statementParent }, jsxElementPath) + } + } else if (t.isConditionalExpression(parentNode)) { + const { consequent, alternate } = parentNode + const testExpression = parentPath.get('test') as NodePath + const block = buildBlockElement() + if (hasComplexExpression(testExpression as any)) { + generateAnonymousState(parentPath.scope, testExpression, this.referencedIdentifiers, true) + } + const test = testExpression.node + if (t.isJSXElement(consequent) && this.isLiteralOrUndefined(alternate)) { + const { value, confident } = (parentPath.get('alternate') as NodePath).evaluate() + if (confident && !value || t.isIdentifier({ name: 'undefined' })) { + newJSXIfAttr(block, test) + block.children = [ jsxElementPath.node ] + // newJSXIfAttr(jsxElementPath.node, test) + parentPath.replaceWith(block) + } else { + const block2 = buildBlockElement() + block.children = [consequent] + newJSXIfAttr(block, test) + setJSXAttr(block2, Adapter.else) + block2.children = [t.jSXExpressionContainer(alternate)] + const parentBlock = buildBlockElement() + parentBlock.children = [block, block2] + parentPath.replaceWith(parentBlock) + } + if (statementParent) { + const name = findIdentifierFromStatement( + statementParent.node as t.VariableDeclaration + ) + setTemplate(name, jsxElementPath as any, this.templates) + // name && templates.set(name, path.node) + } + } else if (this.isLiteralOrUndefined(consequent) && t.isJSXElement(alternate)) { + const { value, confident } = (parentPath.get('consequent') as NodePath).evaluate() + if (confident && !value || t.isIdentifier({ name: 'undefined' })) { + newJSXIfAttr(block, reverseBoolean(test)) + block.children = [ jsxElementPath.node ] + // newJSXIfAttr(jsxElementPath.node, test) + parentPath.replaceWith(block) + } else { + const block2 = buildBlockElement() + block.children = [t.jSXExpressionContainer(consequent)] + newJSXIfAttr(block, test) + setJSXAttr(block2, Adapter.else) + block2.children = [alternate] + const parentBlock = buildBlockElement() + parentBlock.children = [block, block2] + parentPath.replaceWith(parentBlock) + } + if (statementParent) { + const name = findIdentifierFromStatement( + statementParent.node as t.VariableDeclaration + ) + setTemplate(name, jsxElementPath as any, this.templates) + // name && templates.set(name, path.node) + } + } else if (t.isJSXElement(consequent) && t.isJSXElement(alternate)) { + const block2 = buildBlockElement() + block.children = [consequent] + newJSXIfAttr(block, test) + setJSXAttr(block2, Adapter.else) + block2.children = [alternate] + const parentBlock = buildBlockElement() + parentBlock.children = [block, block2] + parentPath.replaceWith(parentBlock) + if (statementParent) { + const name = findIdentifierFromStatement( + statementParent.node as t.VariableDeclaration + ) + setTemplate(name, jsxElementPath as any, this.templates) + } + } else if (t.isJSXElement(consequent) && t.isCallExpression(alternate) && !isArrayMapCallExpression(parentPath.get('alternate') as any)) { + const id = generateAnonymousState(this.renderScope, parentPath.get('alternate') as any, this.referencedIdentifiers, true) + ;(parentPath.get('alternate') as NodePath).replaceWith(id) + // + } else if (t.isJSXElement(alternate) && t.isCallExpression(consequent) && !isArrayMapCallExpression(parentPath.get('consequent') as any)) { + const id = generateAnonymousState(this.renderScope, parentPath.get('consequent') as any, this.referencedIdentifiers, true) + ;(parentPath.get('consequent') as NodePath).replaceWith(id) + } else if (t.isJSXElement(alternate) && isArrayMapCallExpression(parentPath.get('consequent') as any)) { + // + } else if (t.isJSXElement(consequent) && isArrayMapCallExpression(parentPath.get('alternate') as any)) { + // + } else { + block.children = [t.jSXExpressionContainer(consequent)] + newJSXIfAttr(block, test) + const block2 = buildBlockElement() + setJSXAttr(block2, Adapter.else) + block2.children = [t.jSXExpressionContainer(alternate)] + const parentBlock = buildBlockElement() + parentBlock.children = [block, block2] + parentPath.replaceWith(parentBlock) + if (statementParent) { + const name = findIdentifierFromStatement( + statementParent.node as t.VariableDeclaration + ) + setTemplate(name, jsxElementPath as any, this.templates) + } + } + } + } + + setProperies () { + if (!this.isDefaultRender) { + return + } + const properties: t.ObjectProperty[] = [] + this.componentProperies.forEach((propName) => { + const p = Adapters.quickapp === Adapters.quickapp && this.upperCaseComponentProps.has(propName) && !propName.startsWith('prv-fn') ? snakeCase(propName) : propName + properties.push( + t.objectProperty(t.stringLiteral(p), t.objectExpression([ + t.objectProperty(t.stringLiteral('type'), t.nullLiteral()), + t.objectProperty(t.stringLiteral('value'), t.nullLiteral()) + ])) + ) + }) + let classProp = t.classProperty( + t.identifier('properties'), + t.objectExpression(properties) + ) as any + classProp.static = true + const classPath = this.renderPath.findParent(isClassDcl as any) as NodePath + Adapter.type !== Adapters.alipay && classPath.node.body.body.unshift(classProp) + } + + setLoopRefFlag () { + if (this.loopRefs.size) { + const classPath = this.renderPath.findParent(isClassDcl as any) as NodePath + classPath.node.body.body.unshift(t.classProperty(t.identifier('$$hasLoopRef'), t.booleanLiteral(true))) + } + } + + replaceIdWithTemplate = (handleRefId = false) => (path: NodePath) => { + if (!t.isJSXAttribute(path.parent)) { + path.traverse({ + Identifier: (path) => { + const parentPath = path.parentPath + if ( + parentPath.isConditionalExpression() || + parentPath.isLogicalExpression() || + path.isReferencedIdentifier() + ) { + const name = path.node.name + if (handleRefId && Object.keys(this.renderScope.getAllBindings()).includes(name)) { + this.addRefIdentifier(path as any, path.node as any) + // referencedIdentifiers.add(path.node) + } + if (this.templates.has(name)) { + path.replaceWith(this.templates.get(name)!) + } + } + } + }) + } + } + + // hasStateOrProps = (key: 'state' | 'props') => (p: t.Identifier | t.AssignmentPattern | t.RestProperty) => t.isObjectProperty(p) && t.isIdentifier(p.key) && p.key.name === key + hasStateOrProps = (key: 'state' | 'props') => (p: t.ObjectProperty | t.RestElement) => t.isObjectProperty(p) && t.isIdentifier(p.key) && p.key.name === key + + private destructStateOrProps ( + key: 'state' | 'props', + path: NodePath, + properties: (t.ObjectProperty | t.RestElement)[], + parentPath: NodePath + ) { + const hasStateOrProps = properties.filter(p => t.isObjectProperty(p) && t.isIdentifier(p.key) && key === p.key.name) + if (hasStateOrProps.length === 0) { + return + } + if (hasStateOrProps.length !== properties.length) { + throw codeFrameError(path.node, 'state 或 props 只能单独从 this 中解构') + } + const declareState = template(`const ${key} = this.${key};`)() + if (properties.length > 1) { + const index = properties.findIndex(p => t.isIdentifier((p as t.ObjectProperty).key, { name: key })) + properties.splice(index, 1) + parentPath.insertAfter(declareState) + } else { + parentPath.insertAfter(declareState) + parentPath.remove() + } + } + + private returnedifStemJSX = new Set() + + private loopComponentVisitor: Visitor = { + VariableDeclarator: (path) => { + const id = path.get('id') + const init = path.get('init') + const parentPath = path.parentPath + if ( + id.isObjectPattern() && + init.isThisExpression() && + parentPath.isVariableDeclaration() + ) { + const { properties } = id.node + this.destructStateOrProps('state', path as any, properties as any, parentPath as any) + this.destructStateOrProps('props', path as any, properties as any, parentPath as any) + } + }, + JSXElement: { + enter: (jsxElementPath: NodePath) => { + this.handleJSXElement(jsxElementPath, (options) => { + this.handleConditionExpr(options, jsxElementPath) + if (this.isIfStemInLoop(jsxElementPath)) { + this.handleJSXInIfStatement(jsxElementPath, options) + this.removeJSXStatement() + } + if (options.parentPath.isReturnStatement() && this.returnedifStemJSX.has(options.parentPath.scope)) { + const block = buildBlockElement() + setJSXAttr(block, Adapter.else) + block.children = [jsxElementPath.node] + jsxElementPath.replaceWith(block) + this.returnedifStemJSX.delete(options.parentPath.scope) + } + }) + }, + exit: (jsxElementPath: NodePath) => { + this.handleJSXElement(jsxElementPath, ({ parentNode, parentPath, statementParent, isFinalReturn }) => { + if (statementParent && statementParent.findParent(p => p === this.renderPath)) { + this.jsxDeclarations.add(statementParent) + } + if (t.isReturnStatement(parentNode)) { + if (!isFinalReturn) { + const callExpr = parentPath.findParent(p => p.isCallExpression()) + if (callExpr && callExpr.isCallExpression()) { + const callee = callExpr.node.callee + if (this.loopComponents.has(callExpr)) { + return + } + if ( + t.isMemberExpression(callee) && + t.isIdentifier(callee.property) && + callee.property.name === 'map' + ) { + let ary = callee.object + if (t.isCallExpression(ary) || isContainFunction((callExpr.get('callee') as any).get('object'))) { + this.loopCallees.add(ary) + const variableName = `${LOOP_CALLEE}_${this.incrementCalleeId()}` + callExpr.getStatementParent()?.insertBefore( + buildConstVariableDeclaration(variableName, setParentCondition(jsxElementPath as any, ary, true)) + ) + ary = t.identifier(variableName) + } + if (t.isMemberExpression(ary)) { + const id = findFirstIdentifierFromMemberExpression(ary) + if (t.isIdentifier(id)) { + this.referencedIdentifiers.add(id) + } + } else if (t.isIdentifier(ary)) { + const parentCallExpr = callExpr.find(p => p.isCallExpression()) + if (!isArrayMapCallExpression(parentCallExpr as any) && parentCallExpr !== callExpr) { + this.referencedIdentifiers.add(ary) + } + } + const block = buildBlockElement() + const hasIfAttr = jsxElementPath.node.openingElement.attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && a.name.name === Adapter.if) + const needWrapper = Adapters.swan === Adapter.type && hasIfAttr + if (needWrapper) { + block.children = [jsxElementPath.node] + jsxElementPath.replaceWith(block) + } + setJSXAttr(needWrapper ? block : jsxElementPath.node, Adapter.for, t.jSXExpressionContainer(ary)) + this.loopCalleeId.add(findFirstIdentifierFromMemberExpression(callee)) + const [func] = callExpr.node.arguments + if ( + t.isFunctionExpression(func) || + t.isArrowFunctionExpression(func) + ) { + const [item, index] = func.params + let itemName = '' + let indexName = '' + if (t.isIdentifier(item)) { + if (Adapters.quickapp !== Adapter.type) { + setJSXAttr( + needWrapper ? block : jsxElementPath.node, + Adapter.forItem, + t.stringLiteral(item.name) + ) + } else { + itemName = item.name + } + this.loopScopes.add(item.name) + } else if (t.isObjectPattern(item)) { + throw codeFrameError(item.loc, 'JSX map 循环参数暂时不支持使用 Object pattern 解构。') + } else { + setJSXAttr( + needWrapper ? block : jsxElementPath.node, + Adapter.forItem, + t.stringLiteral('__item') + ) + func.params[0] = t.identifier('__item') + } + if (t.isIdentifier(index)) { + if (Adapters.quickapp !== Adapter.type) { + setJSXAttr( + needWrapper ? block : jsxElementPath.node, + Adapter.forIndex, + t.stringLiteral(index.name) + ) + } else { + indexName = index.name + } + this.loopScopes.add(index.name) + // tslint:disable-next-line: strict-type-predicates + } else if (index === undefined) { + if (process.env.NODE_ENV !== 'test') { + const uid = this.renderScope.generateUid('anonIdx') + func.params[1] = t.identifier(uid) + setJSXAttr( + needWrapper ? block : jsxElementPath.node, + Adapter.forIndex, + t.stringLiteral(this.renderScope.generateUid('anonIdx')) + ) + } + } else { + throw codeFrameError(index, '包含 JSX 的 map 循环第二个参数只能是一个普通标识符') + } + if (Adapters.quickapp === Adapter.type) { + if (itemName || indexName) { + const code = generateJSXAttr(ary) + let forExpr: string + if (itemName && !indexName) { + forExpr = `${itemName} in ${code}` + } else { + forExpr = `(${indexName}, ${itemName}) in ${code}` + } + setJSXAttr(jsxElementPath.node, Adapter.for, t.stringLiteral(`{{${forExpr}}}`)) + } + // if (itemName && !indexName) { + // const forExpr = gene + // } + } + this.loopComponents.set(callExpr as any, jsxElementPath) + let loopComponentName + const parentCallee = callExpr.findParent(c => isArrayMapCallExpression(c as any)) + if (isArrayMapCallExpression(parentCallee as any)) { + loopComponentName = `${LOOP_CALLEE}_${this.incrementCalleeId()}` + } else { + loopComponentName = 'loopArray' + this.loopArrayId() + } + this.loopComponentNames.set(callExpr as any, loopComponentName) + // caller.replaceWith(jsxElementPath.node) + if (statementParent) { + const name = findIdentifierFromStatement( + statementParent.node as t.VariableDeclaration + ) + // setTemplate(name, path, templates) + name && this.templates.set(name, jsxElementPath.node) + } + } + } + } + } + } else if (t.isArrowFunctionExpression(parentNode)) { + parentPath.replaceWith( + t.arrowFunctionExpression(parentNode.params, t.blockStatement([ + t.returnStatement(jsxElementPath.node) + ])) + ) + } + }) + } + } + } + + private renameIfScopeVaribale = (blockStatement: NodePath): Visitor => { + return { + VariableDeclarator: (path) => { + const { id, init } = path.node + const ifStem = path.parentPath.parentPath?.parentPath + if (!t.isIfStatement(ifStem) || isContainJSXElement(path as any)) { + return + } + if (t.isIdentifier(id)) { + if (id.name.startsWith('loopArray') || id.name.startsWith(LOOP_CALLEE)) { + this.renderPath.node.body.body.unshift( + t.variableDeclaration('let', [t.variableDeclarator(t.identifier(id.name))]) + ) + path.parentPath.replaceWith( + template('ID = INIT;')({ ID: t.identifier(id.name), INIT: init }) + ) + } else if (id.name.startsWith('$props__')) { + path.skip() + } else { + const newId = this.renderScope.generateDeclaredUidIdentifier('$' + id.name) + blockStatement.scope.rename(id.name, newId.name) + path.parentPath.replaceWith( + template('ID = INIT;')({ ID: newId, INIT: init || t.identifier('undefined') }) + ) + } + } + }, + JSXElement: (jsxElementPath) => { + this.handleJSXElement(jsxElementPath, (options) => { + this.handleConditionExpr(options, jsxElementPath) + }) + }, + JSXExpressionContainer: this.replaceIdWithTemplate(true) as any + } + } + + findParallelIfStem = (p: NodePath) => { + const exprs: Set> = new Set() + let expr = p.parentPath + while (t.isIfStatement(expr)) { + exprs.add(expr as any) + expr = expr.parentPath + } + return exprs + } + + private handleJSXInIfStatement (jsxElementPath: NodePath, { parentNode, parentPath, isFinalReturn, isIfStemInLoop }: JSXHandler) { + if (t.isReturnStatement(parentNode)) { + if (!isFinalReturn && !isIfStemInLoop) { + + } else { + const ifStatement = parentPath.findParent(p => p.isIfStatement()) as any + const blockStatement = parentPath.findParent(p => p.isBlockStatement() && (p.parentPath === ifStatement)) as NodePath + const loopCallExpr = jsxElementPath.findParent(p => isArrayMapCallExpression(p as any)) as null | NodePath + if (loopCallExpr && loopCallExpr.findParent(p => p.isIfStatement())) { + throw codeFrameError(loopCallExpr.node, '在循环的上级和内部都有 if-else 的情况,需要把循环的内部 if-else return 的 JSX 设置为一个变量,保证单个 return 语句。\n 示例:https://gist.github.com/yuche/f6a0933df2537407abe0f426f774f670') + } + if (blockStatement && blockStatement.isBlockStatement()) { + blockStatement.traverse(this.renameIfScopeVaribale(blockStatement)) + } + + const blockAttrs: t.JSXAttribute[] = [] + if ((isNewPropsSystem()) && !this.finalReturnElement && process.env.NODE_ENV !== 'test') { + if (this.isDefaultRender && Adapter.type !== Adapters.swan) { + blockAttrs.push(t.jSXAttribute( + t.jSXIdentifier(Adapter.if), + t.jSXExpressionContainer(t.jSXIdentifier(IS_TARO_READY) as any) + )) + } + } + const block = this.finalReturnElement || buildBlockElement(blockAttrs) + if (isBlockIfStatement(ifStatement, blockStatement)) { + let { test, alternate, consequent } = ifStatement.node + if (hasComplexExpression(ifStatement.get('test') as NodePath)) { + ifStatement.node.test = test = generateAnonymousState(blockStatement.scope, ifStatement.get('test') as any, this.referencedIdentifiers, true) + } + // blockStatement.node.body.push(t.returnStatement( + // t.memberExpression(t.thisExpression(), t.identifier('state')) + // )) + if (alternate === blockStatement.node) { + throw codeFrameError(parentNode.loc, '不必要的 else 分支,请遵从 ESLint consistent-return: https://eslint.org/docs/rules/consistent-return') + } else if (consequent === blockStatement.node) { + const parentIfStatement = ifStatement?.findParent(p => p.isIfStatement()) + if (parentIfStatement) { + setJSXAttr( + jsxElementPath.node, + Adapter.elseif, + t.jSXExpressionContainer(test), + jsxElementPath + ) + if (loopCallExpr && this.loopIfStemComponentMap.has(loopCallExpr)) { + const block = this.loopIfStemComponentMap.get(loopCallExpr)! + block.children.push(jsxElementPath.node) + } + } else { + if (isIfStemInLoop && loopCallExpr && loopCallExpr.isCallExpression()) { + if (this.loopIfStemComponentMap.has(loopCallExpr)) { + const component = this.loopIfStemComponentMap.get(loopCallExpr)! + newJSXIfAttr(jsxElementPath.node, test, jsxElementPath) + component.children.push(jsxElementPath.node) + } else { + newJSXIfAttr(jsxElementPath.node, test, jsxElementPath) + this.loopIfStemComponentMap.set(loopCallExpr, block) + const arrowFunc = loopCallExpr.node.arguments[0] + if (t.isArrowFunctionExpression(arrowFunc) && t.isBlockStatement(arrowFunc.body) && !arrowFunc.body.body.some(s => t.isReturnStatement(s))) { + arrowFunc.body.body.push(t.returnStatement(buildBlockElement())) + this.hasNoReturnLoopStem = true + } + } + let scope + try { + scope = (loopCallExpr.get('arguments')[0].get('body') as NodePath).scope + } catch (error) { + // + } + if (scope) { + this.returnedifStemJSX.add(scope) + } + } else { + if (this.topLevelIfStatement.size > 0) { + setJSXAttr( + jsxElementPath.node, + Adapter.elseif, + t.jSXExpressionContainer(test), + jsxElementPath + ) + } else { + newJSXIfAttr(jsxElementPath.node, test, jsxElementPath) + this.topLevelIfStatement.add(ifStatement as any) + } + } + } + } + } else if (block.children.length !== 0) { + if (this.topLevelIfStatement.size > 0) { + setJSXAttr(jsxElementPath.node, Adapter.else) + } + } + block.children.push(jsxElementPath.node) + if (!this.loopIfStemComponentMap.has(loopCallExpr as any)) { + this.finalReturnElement = block + } + this.returnedPaths.push(parentPath) + } + } else if (t.isArrowFunctionExpression(parentNode)) { + // console.log('arrow') + } else if (t.isAssignmentExpression(parentNode)) { + const ifStatement = parentPath.findParent(p => p.isIfStatement()) as NodePath + const blockStatement = parentPath.findParent(p => p.isBlockStatement() && (p.parentPath === ifStatement)) as NodePath + if (blockStatement && blockStatement.isBlockStatement()) { + blockStatement.traverse(this.renameIfScopeVaribale(blockStatement)) + } + if (t.isIdentifier(parentNode.left)) { + const assignmentName = parentNode.left.name + const renderScope: Scope = isIfStemInLoop ? jsxElementPath.findParent(p => isArrayMapCallExpression(p as any))?.get('arguments')[0].get('body').scope : this.renderScope + const bindingNode = renderScope.getOwnBinding(assignmentName)!.path.node as any + // tslint:disable-next-line + const parallelIfStems = this.findParallelIfStem(ifStatement as any) + const parentIfStatement = ifStatement?.findParent(p => + p.isIfStatement() && !parallelIfStems.has(p as any) + ) as NodePath + // @TODO: 重构 this.templates 为基于作用域的 HashMap,现在仍然可能会存在重复的情况 + let block = this.templates.get(assignmentName) || buildBlockElement() + let isElse = false + if (isEmptyDeclarator(bindingNode)) { + const blockStatement = parentPath.findParent(p => + p.isBlockStatement() + ) + if (isBlockIfStatement(ifStatement, blockStatement)) { + const { test, alternate, consequent } = ifStatement?.node + if (alternate === blockStatement?.node) { + const newBlock = buildBlockElement() + setJSXAttr(newBlock, Adapter.else) + newBlock.children = [jsxElementPath.node] + jsxElementPath.node = newBlock + } else if (consequent === blockStatement?.node) { + const parentIfStatement = ifStatement?.findParent(p => + p.isIfStatement() + ) as NodePath + const assignments: t.AssignmentExpression[] = [] + let isAssignedBefore = false + // @TODO: 重构这两种循环为通用模块 + + // 如果这个 JSX assigmnent 的作用域中有其他的 if block 曾经赋值过,它应该是 else-if + if (blockStatement && blockStatement.isBlockStatement()) { + for (const parentStatement of blockStatement.node.body) { + if (t.isIfStatement(parentStatement) && t.isBlockStatement(parentStatement.consequent)) { + const statements = parentStatement.consequent.body + for (const statement of statements) { + if (t.isExpressionStatement(statement) && t.isAssignmentExpression(statement.expression) && t.isIdentifier(statement.expression.left, { name: assignmentName })) { + isAssignedBefore = true + } + } + } + } + } + + // 如果这个 JSX assigmnent 的的父级作用域中的 prev sibling 有相同的赋值,它应该是 else-if + if (parentIfStatement) { + const { consequent } = parentIfStatement.node + if (t.isBlockStatement(consequent)) { + const body = consequent.body + for (const parentStatement of body) { + if (t.isIfStatement(parentStatement) && t.isBlockStatement(parentStatement.consequent)) { + const statements = parentStatement.consequent.body + for (const statement of statements) { + if (t.isExpressionStatement(statement) && t.isAssignmentExpression(statement.expression) && t.isIdentifier(statement.expression.left, { name: assignmentName })) { + assignments.push(statement.expression) + } + } + } + } + } + } + if ( + ( + parentIfStatement && + ( + parentIfStatement.get('alternate') === ifStatement || + assignments.findIndex(a => a === parentNode) > 0 + ) + ) + || + isAssignedBefore + ) { + setJSXAttr( + jsxElementPath.node, + Adapter.elseif, + t.jSXExpressionContainer(test), + jsxElementPath + ) + } else { + if (parentIfStatement) { + if (this.isEmptyBlock(block)) { + newJSXIfAttr(block, parentIfStatement.node.test, jsxElementPath) + } else if (parentIfStatement.node.alternate === ifStatement?.parent) { + const newBlock = buildBlockElement() + setJSXAttr( + newBlock, + Adapter.else + ) + this.insertElseBlock(block, newBlock, parentIfStatement.node.test) + isElse = true + } else { + const newBlock = buildBlockElement() + setJSXAttr( + newBlock, + Adapter.elseif, + t.jSXExpressionContainer(parentIfStatement.node.test), + jsxElementPath + ) + block.children.push(newBlock) + } + } + newJSXIfAttr(jsxElementPath.node, test, jsxElementPath) + } + } + const ifAttr = block.openingElement.attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && a.name.name === Adapter.if) + if (ifAttr && t.isJSXAttribute(ifAttr) && t.isJSXExpressionContainer(ifAttr.value, { expression: test })) { + const newBlock = buildBlockElement() + newBlock.children = [block, jsxElementPath.node] + block = newBlock + } else if ( + parentIfStatement && ifStatement?.parentPath !== parentIfStatement + ) { + let hasNest = false + this.handleNestedIfStatement(block, jsxElementPath.node, parentIfStatement.node.test, hasNest, isElse || !!ifStatement?.findParent(p => p.node === parentIfStatement.node.alternate)) + if (!hasNest && parentIfStatement.get('alternate') !== ifStatement) { + const ifAttr = block.openingElement.attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && a.name.name === Adapter.if) + if (ifAttr && t.isJSXAttribute(ifAttr) && t.isJSXExpressionContainer(ifAttr.value, { expression: parentIfStatement.node.test })) { + const newBlock = buildBlockElement() + block.children.push(jsxElementPath.node) + newBlock.children = [block] + block = newBlock + } + } + } else { + block.children.push(jsxElementPath.node) + } + // setTemplate(name, path, templates) + assignmentName && this.templates.set(assignmentName, block) + if (isIfStemInLoop) { + this.replaceIdWithTemplate()(renderScope.path as any) + this.returnedPaths.push(parentPath) + } + } + } else { + throw codeFrameError( + jsxElementPath.node.loc, + '请将 JSX 赋值表达式初始化为 null,然后再进行 if 条件表达式赋值。' + ) + } + } + } else if (!t.isJSXElement(parentNode)) { + // throwError(path, '考虑只对 JSX 元素赋值一次。') + } + } + + insertElseBlock = (block: t.JSXElement, jsx: t.JSXElement, test: t.Expression) => { + if (this.isEmptyBlock(block)) { + return + } + + for (const child of block.children) { + if (!t.isJSXElement(child)) { + continue + } + const ifAttr = child.openingElement.attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && a.name.name === Adapter.if) + const ifElseAttr = child.openingElement.attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && a.name.name === Adapter.elseif) + if ( + (ifAttr && t.isJSXAttribute(ifAttr) && t.isJSXExpressionContainer(ifAttr.value, { expression: test })) + || + (ifElseAttr && t.isJSXAttribute(ifElseAttr) && t.isJSXExpressionContainer(ifElseAttr.value, { expression: test })) + ) { + block.children.push(jsx) + break + } else { + this.insertElseBlock(child, jsx, test) + } + } + } + + handleNestedIfStatement = (block: t.JSXElement, jsx: t.JSXElement, test: t.Expression, hasNest: boolean, isElse: boolean) => { + if (this.isEmptyBlock(block)) { + return + } + + for (const [index, child] of block.children.entries()) { + if (!t.isJSXElement(child)) { + continue + } + const ifAttr = child.openingElement.attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && a.name.name === Adapter.if) + const ifElseAttr = child.openingElement.attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && a.name.name === Adapter.elseif) + if ( + (ifAttr && t.isJSXAttribute(ifAttr) && t.isJSXExpressionContainer(ifAttr.value, { expression: test })) + || + (ifElseAttr && t.isJSXAttribute(ifElseAttr) && t.isJSXExpressionContainer(ifElseAttr.value, { expression: test })) + ) { + if (isElse) { + const nextChild = block.children[index + 1] + if (t.isJSXElement(nextChild)) { + nextChild.children.push(jsx) + } + } else { + child.children.push(jsx) + } + hasNest = true + break + } else { + this.handleNestedIfStatement(child, jsx, test, hasNest, isElse) + } + } + } + + isEmptyBlock = ((block: t.JSXElement) => block.children.length === 0 && block.openingElement.attributes.length === 0) + + private genPropsSettingExpression (properties: Array | t.Identifier, id: t.StringLiteral | t.Identifier, previd: t.Identifier): t.Expression { + return t.callExpression( + t.memberExpression(t.identifier(PROPS_MANAGER), t.identifier('set')), + [Array.isArray(properties) ? t.objectExpression(properties as any) : properties, id, previd] + ) + } + + private getPropsFromAttrs (openingElement: t.JSXOpeningElement): Array { + const attrs = openingElement.attributes + const properties: Array = [] + openingElement.attributes = attrs.filter(attr => { + if (t.isJSXSpreadAttribute(attr)) { + // @ts-ignore + properties.push(t.spreadProperty(attr.argument)) + return false + } else if (t.isJSXAttribute(attr)) { + const { name, value } = attr + if (t.isJSXIdentifier(name) + && name.name !== 'key' + && name.name !== 'id' + && !(name.name === 'extraProps' && Adapter.type === Adapters.weapp) + && name.name !== Adapter.for + && name.name !== Adapter.forItem + && name.name !== Adapter.forIndex + && name.name.indexOf('render') !== 0 + && !t.isJSXElement(value) + && !name.name.includes('-') + ) { + // tslint:disable-next-line: strict-type-predicates + const v: t.StringLiteral | t.Expression | t.BooleanLiteral = value === null + ? t.booleanLiteral(true) + : (t.isJSXExpressionContainer(value) + ? value.expression + : value + ) as t.StringLiteral | t.Expression | t.BooleanLiteral + v && properties.push(t.objectProperty(t.stringLiteral(name.name), v)) + return false + } + return true + } + }) + return properties + } + + private prefixExpr = () => this.isDefaultRender ? t.identifier('__prefix') : t.identifier(CLASS_COMPONENT_UID) + + private propsDecls = new Map>() + + private isInternalComponent = (element: t.JSXOpeningElement) => { + return t.isJSXIdentifier(element.name) && + !DEFAULT_Component_SET.has(element.name.name) && + !DEFAULT_Component_SET_COPY.has(element.name.name) && + /[A-Z]/.test(element.name.name.charAt(0)) + } + + private addIdToElement (jsxElementPath: NodePath) { + const openingElement = jsxElementPath.node.openingElement + if (openingElement.attributes.find(attr => { + return t.isJSXAttribute(attr) && attr.name.name === 'compid' + })) { + return + } + if (this.isInternalComponent(openingElement)) { + if (this.isEmptyProps(openingElement.attributes) && Adapter.type !== Adapters.swan) { + return + } + const compId = genCompid() + const prevName = `${PREV_COMPID}__${compId}` + const name = `${COMPID}__${compId}` + const variableName = t.identifier(name) + this.referencedIdentifiers.add(variableName) + const idExpr = t.variableDeclaration('const', [ + t.variableDeclarator( + t.arrayPattern([t.identifier(prevName), variableName]), + t.callExpression(t.identifier(GEN_COMP_ID), [ + t.binaryExpression( + '+', + this.prefixExpr(), + t.stringLiteral(name) + ) + ]) + ) + ]) + + // createData 中设置 props + const properties = this.getPropsFromAttrs(openingElement) + const propsId = `$props__${compId}` + const collectedProps = buildConstVariableDeclaration(propsId, t.objectExpression(properties as any)) + const result = jsxElementPath.getStatementParent()?.insertBefore(collectedProps) as any + this.propsDecls.set(propsId, result[0]) + const propsSettingExpr = this.genPropsSettingExpression(t.identifier(propsId), variableName, t.identifier(prevName)) + this.genCompidExprs.add(idExpr) + const expr = setAncestorCondition(jsxElementPath as any, propsSettingExpr) + this.ancestorConditions.add(expr) + const ifStatement = jsxElementPath.findParent(p => p.isIfStatement()) + const blockStatement = jsxElementPath.findParent(p => p.isBlockStatement()) as NodePath + let blockStem = this.renderPath.node.body + if (ifStatement && blockStatement) { + const consequent = ifStatement.get('consequent') + const alternate = ifStatement.get('alternate') + if (blockStatement === consequent || blockStatement === alternate) { + blockStem = blockStatement.node + } + } + const funcs = this.propsSettingExpressions.get(blockStem) + const func = () => t.expressionStatement(expr) + this.propsSettingExpressions.set(blockStem, funcs ? [...funcs, func] : [func]) + + // xml 中打上组件 ID + setJSXAttr(jsxElementPath.node, 'compid', t.jSXExpressionContainer(variableName)) + } + } + + private handleComponents (renderBody: NodePath) { + renderBody.traverse({ + JSXElement: jsxElementPath => this.addIdToElement(jsxElementPath as any) + }) + } + + private jsxElementVisitor: Visitor = { + JSXElement: (jsxElementPath) => { + this.handleJSXElement(jsxElementPath as any, (options) => { + this.handleConditionExpr(options, jsxElementPath) + this.handleJSXInIfStatement(jsxElementPath, options) + }) + + // handle jsx attrs + jsxElementPath.traverse(this.jsxAttrVisitor) + } + } + + private jsxAttrVisitor: Visitor = { + JSXExpressionContainer: (path) => { + if (!isChildrenOfJSXAttr(path as any)) { + return + } + const expression = path.get('expression') as NodePath + if (expression.isStringLiteral()) { + path.replaceWith(expression) + } else if (expression.isCallExpression()) { + const node = expression.node + if ( + t.isMemberExpression(node.callee) && + t.isIdentifier(node.callee.property) && + node.callee.property.name === 'bind' + ) { + const JSXElement = path.findParent(p => p.isJSXElement()) + ?.node as t.JSXElement + const componentName = JSXElement.openingElement.name + if ( + isNewPropsSystem() && + t.isJSXIdentifier(componentName) + ) { + if (THIRD_PARTY_COMPONENTS.has(componentName.name)) { + // + } else if (!DEFAULT_Component_SET.has(componentName.name)) { + return + } + } + + // const JSXAttribute = path.findParent(p => p.isJSXAttribute()) + let bindCalleeName: string | null = null + if (t.isIdentifier(node.callee.object)) { + bindCalleeName = node.callee.object.name + } else if (t.isMemberExpression(node.callee.object)) { + if (t.isIdentifier(node.callee.object.property)) { + bindCalleeName = node.callee.object.property.name + } + } + if (bindCalleeName !== null) { + const attr = path.parentPath.node as t.JSXAttribute + let bindEventName = attr.name.name as string + bindEventName = bindEventName.replace(/^bind|^catch/, '') + + const args = expression.get('arguments') as any + (args as NodePath[]).forEach((arg, index) => { + const node = arg.node + const argName = generate(node as any).code + if (index === 0) { + setJSXAttr( + JSXElement, + `data-e-${bindEventName}-so`, + t.stringLiteral(argName) + ) + } else { + let expr: any = null + if (t.isIdentifier(node) && path.scope.hasBinding(argName)) { + this.addRefIdentifier(path as any, node) + expr = t.jSXExpressionContainer(node) + } else if (t.isMemberExpression(node)) { + const id = findFirstIdentifierFromMemberExpression(node) + this.addRefIdentifier(path as any, id) + expr = t.jSXExpressionContainer(node) + } else if (node.type === 'NumericLiteral' || t.isStringLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node)) { + expr = t.jSXExpressionContainer(node as any) + } else if (hasComplexExpression(arg)) { + const isCookedLoop = JSXElement.openingElement.attributes.some(attr => t.isJSXAttribute(attr) && attr.name.name === Adapter.for) + if (isCookedLoop) { + throw codeFrameError(arg.node, '在循环中使用 bind 时,需要声明将此复杂表达式声明为一个变量再放入 bind 参数中。') + } else { + const id = generateAnonymousState(this.renderScope, arg as any, this.referencedIdentifiers) + expr = t.jSXExpressionContainer(id) + } + } else { + expr = t.jSXExpressionContainer(t.identifier(argName)) + } + setJSXAttr( + JSXElement, + `data-e-${bindEventName}-a-${toLetters(index)}`, + expr + ) + } + }) + expression.replaceWith(t.stringLiteral(`${bindCalleeName}`)) + } + } + } + }, + JSXAttribute: (path) => { + const { name, value } = path.node + let eventShouldBeCatched = false + const jsxElementPath = path.parentPath.parentPath + if (t.isJSXIdentifier(name) && jsxElementPath?.isJSXElement()) { + const componentName = (jsxElementPath.node.openingElement as any).name.name + const isThirdPartyKey = name.name === 'taroKey' + if (name.name === 'key' || isThirdPartyKey) { + if (THIRD_PARTY_COMPONENTS.has(componentName as string) && !isThirdPartyKey) { + return + } + const jsx = path.findParent(p => p.isJSXElement()) + const loopBlock = jsx?.findParent(p => { + if (p.isJSXElement()) { + const element = p.get('openingElement') as NodePath + if (element.get('name').isJSXIdentifier({ name: 'block' })) { + const attrs = element.node.attributes + const hasWXForLoop = attrs.some(attr => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: Adapter.for })) + const hasWXKey = attrs.some(attr => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: Adapter.key })) + return hasWXForLoop && !hasWXKey + } + } + return false + }) as NodePath + if (loopBlock) { + setJSXAttr(loopBlock.node, Adapter.key, (value as t.StringLiteral | t.JSXExpressionContainer | t.JSXElement)!) + path.remove() + } else { + path.get('name').replaceWith(t.jSXIdentifier(Adapter.key)) + } + } else if ( + name.name.startsWith('on') + ) { + if (t.isJSXExpressionContainer(value)) { + const methodName = findMethodName(value.expression as any) + methodName && this.usedEvents.add(methodName) + const method = this.methods.get(methodName) + const classDecl = path.findParent(p => p.isClassDeclaration()) + const componentName = jsxElementPath.node.openingElement.name + // if (method && t.isIdentifier(method.node.key)) { + // this.usedEvents.add(methodName) + // } else if (method === null) { + // this.usedEvents.add(methodName) + // } + if (!generate(value.expression as any ).code.includes('.bind') && + ( + !isNewPropsSystem() || + (t.isJSXIdentifier(componentName) && DEFAULT_Component_SET.has(componentName.name)) + ) + ) { + path.node.value = t.stringLiteral(`${methodName}`) + } + if (this.methods.has(methodName)) { + eventShouldBeCatched = isContainStopPropagation(method as any) + } + if (classDecl && classDecl.isClassDeclaration()) { + const superClass = getSuperClassCode(classDecl as any) + if (superClass) { + try { + const ast = parse(superClass.code, buildBabelTransformOptions())?.ast as t.File + traverse(ast, { + ClassMethod (p) { + if (!p.get('key').isIdentifier({ name: methodName })) { + return + } + eventShouldBeCatched = isContainStopPropagation(method as any) + }, + ClassProperty (p) { + if (!p.get('key').isIdentifier({ name: methodName })) { + return + } + eventShouldBeCatched = isContainStopPropagation(method as any) + } + }) + } catch (error) { + // + } + } + } + if (t.isJSXIdentifier(componentName) && !DEFAULT_Component_SET.has(componentName.name)) { + const element = path.parent as t.JSXOpeningElement + if (process.env.NODE_ENV !== 'test' && Adapter.type !== Adapters.alipay) { + const fnName = `${FN_PREFIX}${name.name}` + element.attributes = element.attributes.concat([t.jSXAttribute(t.jSXIdentifier(fnName))]) + } + } + } + if ( + t.isJSXIdentifier(jsxElementPath.node.openingElement.name) + ) { + const componentName = jsxElementPath.node.openingElement.name.name + if (Adapter.type === Adapters.alipay) { + let transformName = name.name + if (DEFAULT_Component_SET.has(componentName) && ALIPAY_BUBBLE_EVENTS.has(name.name)) { + if (name.name === 'onClick') { + transformName = eventShouldBeCatched ? 'catchTap' : 'onTap' + } else { + transformName = `${eventShouldBeCatched ? 'catch' : 'on'}${name.name.slice(2)}` + } + } + path.node.name = t.jSXIdentifier(transformName) + } else if (Adapter.type === Adapters.quickapp) { + const transformName = name.name + path.node.name = t.jSXIdentifier(transformName) + } else if (DEFAULT_Component_SET.has(componentName)) { + let transformName = `${eventShouldBeCatched ? 'catch' : 'bind'}` + + name.name.slice(2).toLowerCase() + if (name.name === 'onClick') { + transformName = eventShouldBeCatched ? 'catchtap' : 'bindtap' + } + path.node.name = t.jSXIdentifier(transformName) + } else if (THIRD_PARTY_COMPONENTS.has(componentName)) { + path.node.name = t.jSXIdentifier('bind' + name.name[2].toLowerCase() + name.name.slice(3)) + } else { + path.node.name = t.jSXIdentifier('bind' + name.name.toLowerCase()) + } + } + // let transformName = `${eventShouldBeCatched ? 'catch' : 'bind'}` + name.name.slice(2, name.name.length) + // transformName = eventShouldBeCatched + // ? CATCH_EVENT_MAP.get(name.name)! + // : BIND_EVENT_MAP.get(name.name)! + } else if (/^render[A-Z]/.test(name.name) && !DEFAULT_Component_SET.has(componentName)) { + if (!t.isJSXExpressionContainer(value)) { + throw codeFrameError(value, '以 render 开头的 props 只能传入包含一个 JSX 元素的 JSX 表达式。') + } + const expression = value.expression + if (!t.isJSXElement(expression)) { + throw codeFrameError(value, '以 render 开头的 props 只能传入包含一个 JSX 元素的 JSX 表达式。') + } + const slotName = getSlotName(name.name) + const slot = cloneDeep(expression) + const view = t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('View'), []), + t.jSXClosingElement(t.jSXIdentifier('View')), + [] + ) + view.children.push(slot) + setJSXAttr(view, 'slot', t.stringLiteral(slotName)) + jsxElementPath.node.children.push(view) + path.remove() + } + } + }, + Identifier: (path) => { + if (!isChildrenOfJSXAttr(path as any)) { + return + } + if (!path.isReferencedIdentifier()) { + return + } + const parentPath = path.parentPath + if ( + parentPath.isConditionalExpression() || + parentPath.isLogicalExpression() || + parentPath.isJSXExpressionContainer() || + parentPath.isBinaryExpression() || + this.renderScope.hasOwnBinding(path.node.name) + ) { + this.addRefIdentifier(path as any, path.node as any) + } + }, + MemberExpression: { + exit: (path: NodePath) => { + const { object, property } = path.node + if (!path.isReferencedMemberExpression()) { + return + } + if (!t.isThisExpression(object)) { + return + } + const reserves = new Set([ + 'state', + 'props', + ...this.methods.keys() + ]) + if (t.isIdentifier(property) || t.isMemberExpression(property)) { + const id = t.isIdentifier(property) ? property : findFirstIdentifierFromMemberExpression(property) + if (reserves.has(id.name)) { + return + } + const jsxAttr = path.findParent(p => p.isJSXAttribute()) as NodePath + if (jsxAttr && t.isJSXIdentifier(jsxAttr.node.name) && jsxAttr.node.name.name.startsWith('on')) { + return + } + if (t.isIdentifier(id) && !(id.name.startsWith('_create') && id.name.endsWith('Data'))) { + this.referencedIdentifiers.add(id) + this.usedThisProperties.add(id.name) + } + } + }, + enter: (path) => { + if (!isChildrenOfJSXAttr(path as any)) { + return + } + if (!path.isReferencedMemberExpression() || path.parentPath.isMemberExpression()) { + return + } + const { object, property } = path.node + if ( + t.isMemberExpression(object) && + t.isThisExpression(object.object) && + t.isIdentifier(object.property, { name: 'state' }) + ) { + if (t.isIdentifier(property)) { + this.usedThisState.add(property.name) + } else if (t.isMemberExpression(property)) { + const id = findFirstIdentifierFromMemberExpression(property) + if (id && this.renderScope.hasBinding(id.name)) { + this.usedThisState.add(id.name) + } + } + return + } + const code = generate(path.node as any).code + if (code.includes('this.$router.params') && t.isIdentifier(property)) { + const name = this.renderScope.generateUid(property.name) + const dcl = buildConstVariableDeclaration(name, path.node as any) + this.renderPath.node.body.body.unshift(dcl) + path.replaceWith(t.identifier(name)) + } + const parentPath = path.parentPath + const id = findFirstIdentifierFromMemberExpression(path.node as any) + if (t.isThisExpression(id)) { + return + } + if ( + parentPath.isConditionalExpression() || + parentPath.isLogicalExpression() || + parentPath.isJSXExpressionContainer() || + parentPath.isBinaryExpression() || + (this.renderScope.hasOwnBinding(id.name)) + ) { + this.addRefIdentifier(path as any, id) + } + } + }, + ArrowFunctionExpression: (path) => { + if (!isChildrenOfJSXAttr(path as any)) { + return + } + const uid = path.scope.generateUid('_anonymous_function_') + const c = t.classProperty(t.identifier(uid), path.node as any) + this.classProperties.add(c) + } + } + + private visitors: Visitor = { + MemberExpression: (path) => { + const { object, property } = path.node + if (t.isThisExpression(object) && t.isIdentifier(property) && property.name.startsWith('renderClosure')) { + const parentPath = path.parentPath + if (parentPath.isVariableDeclarator()) { + const id = parentPath.node.id + if (t.isIdentifier(id) && id.name.startsWith('renderClosure')) { + this.deferedHandleClosureJSXFunc.push(() => { + const classMethod = this.methods.get(id.name) + if (classMethod && classMethod.isClassMethod()) { + path.replaceWith(t.arrowFunctionExpression([t.identifier(CLASS_COMPONENT_UID)], t.blockStatement([ + t.returnStatement(t.arrowFunctionExpression(classMethod.node.params as any, classMethod.node.body)) + ]))) + // classMethod.node.body.body = [] + } + }) + } + } + } + + if (t.isThisExpression(object) && t.isIdentifier(property) && /^render[A-Z]/.test(this.renderMethodName)) { + const s = new Set(['state', 'props']) + if (s.has(property.name) && path.parentPath.isMemberExpression()) { + const p = path.parentPath.node.property + let id = { name: 'example' } + if (t.isIdentifier(p)) { + id = p + } else if (t.isMemberExpression(p)) { + id = findFirstIdentifierFromMemberExpression(p) + } + // tslint:disable-next-line: no-console + console.warn(codeFrameError(path.parentPath.node, + `\n 在形如以 render 开头的 ${this.renderMethodName}() 类函数中,请先把 this.${property.name} 解构出来才进行使用。\n 例如: const { ${id.name} } = this.${property.name}`).message + ) + } + } + }, + VariableDeclarator: (path) => { + const init = path.get('init') + const id = path.get('id') + const ifStem = init.findParent(p => p.isIfStatement()) + // tslint:disable-next-line: strict-type-predicates + if (ifStem && init.node === null) { + init.replaceWith(t.identifier('undefined')) + } + let isDerivedFromState = false + if (init.isMemberExpression()) { + const object = init.get('object') + if (t.isMemberExpression(object) && t.isThisExpression(object.object) && t.isIdentifier(object.property, { name: 'state' })) { + isDerivedFromState = true + } + if (t.isThisExpression(object) && t.isIdentifier(init.get('property'), { name: 'state' })) { + isDerivedFromState = true + } + } + if (!isDerivedFromState) { + const errMsg = 'Warning: render 函数定义一个不从 this.state 解构或赋值而来的变量,此变量又与 this.state 下的变量重名可能会导致无法渲染。' + if (id.isIdentifier()) { + const name = id.node.name + if (this.initState.has(name)) { + // tslint:disable-next-line + console.log(codeFrameError(id.node, errMsg).message) + } + } + if (id.isObjectPattern()) { + const { properties } = id.node + for (const p of properties) { + if (t.isIdentifier(p)) { + // @ts-ignore + if (this.initState.has(p.name)) { + // tslint:disable-next-line + console.log(codeFrameError(id.node, errMsg).message) + } + } + // @ts-ignore + if (t.isSpreadProperty(p) && t.isIdentifier(p.argument)) { + // @ts-ignore + if (this.initState.has(p.argument.name)) { + // tslint:disable-next-line + console.log(codeFrameError(id.node, errMsg).message) + } + } + } + } + } + }, + JSXEmptyExpression (path) { + const parent = path.parentPath + if (path.parentPath.isJSXExpressionContainer()) { + parent.remove() + } + }, + NullLiteral (path) { + const statementParent = path.getStatementParent() + const callExprs = findParents(path as any, p => p.isCallExpression()) + if (callExprs.some(callExpr => callExpr && t.isIdentifier(callExpr.node.callee) && /^use[A-Z]/.test(callExpr.node.callee.name))) { + return + } + if (statementParent && statementParent.isReturnStatement() && !t.isBinaryExpression(path.parent) && !isChildrenOfJSXAttr(path as any)) { + path.replaceWith( + t.jSXElement( + t.jSXOpeningElement( + t.jSXIdentifier('View'), + [] + ), + undefined, + [], + true + ) + ) + } + }, + ReturnStatement: (path) => { + const parentPath = path.parentPath + if ( + parentPath.parentPath?.isClassMethod() || + (parentPath.parentPath?.isIfStatement() && parentPath.parentPath.parentPath.isClassMethod()) + ) { + this.replaceIdWithTemplate()(path as any) + } + }, + + ...this.jsxElementVisitor, + JSXExpressionContainer: this.replaceIdWithTemplate(true) as any + } + + handleQuickappProps () { + if (Adapter.type !== Adapters.quickapp) { + return + } + + this.renderPath.traverse({ + Identifier: (path) => { + if (!this.upperCaseComponentProps.has(path.node.name)) { + return + } + + if (isDerivedFromProps(this.renderScope, path.node.name)) { + this.renderScope.rename(path.node.name, snakeCase(path.node.name)) + path.replaceWith(t.identifier(snakeCase(path.node.name))) + } + + const sibling = path.getSibling('object') + if (sibling && sibling.isMemberExpression() && t.isThisExpression(sibling.get('object')) && t.isIdentifier(sibling.get('property'), { name: 'props' })) { + path.replaceWith(t.identifier(snakeCase(path.node.name))) + } + } + }) + } + + /** + * + * @param renderPath + * @param referencedIdentifiers + * 这三个属性是需要单独传入的 + */ + constructor ( + renderPath: NodePath, + methods: ClassMethodsMap, + initState: Set, + referencedIdentifiers: Set, + usedState: Set, + customComponentNames: Set, + componentProperies: Set, + loopRefs: Map, + refObjExpr: t.ObjectExpression[], + methodName: string + ) { + this.renderPath = renderPath + this.methods = methods + this.initState = initState + this.referencedIdentifiers = referencedIdentifiers + this.usedState = usedState + this.customComponentNames = customComponentNames + this.componentProperies = componentProperies + this.loopRefs = loopRefs + this.refObjExpr = refObjExpr + const renderBody = renderPath.get('body') + this.renderScope = renderBody.scope + this.isDefaultRender = methodName === 'render' + this.upperCaseComponentProps = new Set(Array.from(this.componentProperies).filter(p => /[A-Z]/.test(p) && !p.startsWith('on'))) + + const [, error] = renderPath.node.body.body.filter(s => t.isReturnStatement(s)) + if (error) { + throw codeFrameError(error.loc, 'render 函数顶级作用域暂时只支持一个 return') + } + + if (t.isIdentifier(this.renderPath.node.key)) { + this.renderMethodName = this.renderPath.node.key.name + } else { + throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') + } + + this.handleQuickappProps() + + renderBody.traverse(this.loopComponentVisitor) + if (this.hasNoReturnLoopStem) { + renderBody.traverse({ + JSXElement: (this.loopComponentVisitor.JSXElement as any).exit[0] + }) + } + this.handleLoopComponents() + if (isNewPropsSystem()) { + this.handleComponents(renderBody as any) + } + renderBody.traverse(this.visitors) + if (Adapter.type === Adapters.quickapp) { + renderBody.traverse(this.quickappVistor) + } + + if (t.isIdentifier(this.renderPath.node.key)) { + this.renderPath.node.key.name = this.getCreateJSXMethodName(this.renderMethodName) + } + + this.setOutputTemplate() + this.checkDuplicateName() + this.removeJSXStatement() + this.setUsedState() + this.setPendingState() + this.setCustomEvent() + this.createData() + if (Adapter.type === Adapters.quickapp) { + this.setProperies() + } + this.setLoopRefFlag() + this.handleClosureComp() + } + + private handleClosureComp () { + this.deferedHandleClosureJSXFunc.forEach(func => func()) + } + + private quickappVistor: Visitor = { + JSXExpressionContainer (path) { + if (path.parentPath.isJSXAttribute() || isContainJSXElement(path as any)) { + return + } + replaceJSXTextWithTextComponent(path as any) + } + } + + checkDuplicateData () { + this.initState.forEach((stateName) => { + if (this.templates.has(stateName)) { + throw codeFrameError(this.templates.get(stateName)!, `自定义变量组件名: \`${stateName}\` 和已有 this.state.${stateName} 重复。请使用另一个变量名。`) + } + }) + + this.componentProperies.forEach((componentName) => { + if (this.componentProperies.has(componentName)) { + throw codeFrameError(this.renderPath.node, `state: \`${componentName}\` 和已有 this.props.${componentName} 重复。请使用另一个变量名。`) + } + if (this.templates.has(componentName)) { + throw codeFrameError(this.templates.get(componentName)!, `自定义变量组件名: \`${componentName}\` 和已有 this.props.${componentName} 重复。请使用另一个变量名。`) + } + }) + } + + addRefIdentifier (path: NodePath, id: t.Identifier) { + const arrayMap = path.findParent(p => isArrayMapCallExpression(p as any)) + if (arrayMap && arrayMap.isCallExpression()) { + this.loopRefIdentifiers.set(id.name, arrayMap) + } else { + id && this.referencedIdentifiers.add(id) + } + } + + isEmptyProps = (attrs: (t.JSXAttribute | t.JSXSpreadAttribute)[]) => attrs.filter(a => { + if (t.isJSXSpreadAttribute(a)) return true + const list = [Adapter.for, Adapter.forIndex, Adapter.forItem, 'id'] + Adapter.type === Adapters.weapp && list.push('extraProps') + return !list.includes(a.name.name as string) + }).length === 0 + + findParentIndices (callee: NodePath, indexId: t.Identifier) { + const loopIndices: string[] = [] + const loops = t.arrayExpression([]) + findParentLoops(callee, this.loopComponentNames, loops) + for (const el of loops.elements) { + if (t.isObjectExpression(el)) { + for (const prop of el.properties) { + if (t.isObjectProperty(prop) && t.isIdentifier(prop.key, { name: 'indexId' }) && t.isIdentifier(prop.value)) { + loopIndices.push(prop.value.name) + } + } + } + } + + if (loopIndices.length === 0) { + if (t.isIdentifier(indexId!)) { + loopIndices.push(indexId!.name) + } else { + throw codeFrameError(callee.node, '循环中使用自定义组件需要暴露循环的 index') + } + } + + return loopIndices + } + + /** + * jsxDeclarations, + * renderScope, + * methods, + * loopScopes, + * initState, + * templates + */ + handleLoopComponents = () => { + const replaceQueue: Function[] = [] + let hasLoopRef = false + this.loopComponents.forEach((component, callee) => { + if (!callee.isCallExpression()) { + return + } + if (this.loopIfStemComponentMap.has(callee)) { + const block = this.loopIfStemComponentMap.get(callee)! + const attrs = component.node.openingElement.attributes + const wxForDirectives = new Set([Adapter.for, Adapter.forIndex, Adapter.forItem]) + const ifAttrs = attrs.filter(a => t.isJSXAttribute(a) && wxForDirectives.has(a.name.name as string)) + if (ifAttrs.length) { + block.openingElement.attributes.push(...ifAttrs) + component.node.openingElement.attributes = attrs.filter(a => t.isJSXAttribute(a) && !wxForDirectives.has(a.name.name as string)) + } + setJSXAttr(component.node, Adapter.else) + block.children.push(component.node) + component.replaceWith(block) + } + for (const dcl of this.jsxDeclarations) { + const isChildren = dcl && dcl.findParent(d => d === callee) + if (isChildren) { + this.jsxDeclarations.delete(dcl) + dcl.remove() + } + } + const blockStatementPath = component.findParent(p => p.isBlockStatement()) as NodePath + const body = blockStatementPath.node.body + let loopRefComponent: t.JSXElement | null = null + this.loopRefs.forEach((ref, jsx) => { + if (ref.component.findParent(p => p === component)) { + loopRefComponent = jsx + } + }) + const [ func ] = callee.node.arguments + let indexId: t.Identifier | null = null + let itemId: t.Identifier | null = null + if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) { + const params = func.params as t.Identifier[] + if (Array.isArray(params)) { + indexId = params[1] + itemId = params[0] + } + } + if (this.loopRefs.has(component.node) || loopRefComponent!) { + hasLoopRef = true + const ref = this.loopRefs.get(component.node)! || this.loopRefs.get(loopRefComponent!) + if (indexId === null || !t.isIdentifier(indexId)) { + throw codeFrameError(component.node, '在循环中使用 ref 必须暴露循环的第二个参数 `index`') + } + const id = typeof ref.id === 'string' ? t.binaryExpression('+', t.stringLiteral(ref.id), indexId) : ref.id + const args: any[] = [ + t.identifier('__scope'), + t.binaryExpression('+', t.stringLiteral('#'), id) + ] + if (ref.type === 'component') { + args.push(t.stringLiteral('component')) + } else { + args.push(t.stringLiteral('dom')) + } + args.push(ref.fn) + const callHandleLoopRef = t.callExpression(t.identifier(HANDLE_LOOP_REF), args) + + const loopRefStatement = t.expressionStatement( + t.logicalExpression( + '&&', + t.logicalExpression('&&', t.identifier('__scope'), t.identifier('__isRunloopRef')), + callHandleLoopRef + ) + ) + + body.splice(body.length - 1, 0, !isTestEnv ? loopRefStatement : t.expressionStatement(callHandleLoopRef)) + } + + if (isNewPropsSystem()) { + const loopIndices: string[] = this.findParentIndices(callee, indexId!) + const deferCallBack: Function[] = [] + + blockStatementPath.traverse({ + CallExpression (path) { + const pathCallee = path.node.callee + if ( + t.isMemberExpression(pathCallee) && + t.isThisExpression(pathCallee.object) && + t.isIdentifier(pathCallee.property) && + pathCallee.property.name.startsWith('_create') && + pathCallee.property.name.endsWith('Data') + ) { + const arg = path.node.arguments[0] + if (t.isBinaryExpression(arg)) { + deferCallBack.push(() => { + path.node.arguments = [ + t.binaryExpression('+', arg, t.templateLiteral( + [ + t.templateElement({ raw: '' }), + ...loopIndices.map(() => t.templateElement({ raw: '' })) + ], + loopIndices.map(l => t.identifier(l)) + )) + ] + }) + } + } + }, + JSXElement: path => { + const element = path.node.openingElement + if (this.isInternalComponent(element)) { + if (this.isEmptyProps(element.attributes) && Adapter.type !== Adapters.swan) { + return + } + + // createData 函数里加入 compid 相关逻辑 + const compid = genCompid() + const prevVariableName = `${PREV_COMPID}__${compid}` + const variableName = `${COMPID}__${compid}` + const tpmlExprs: t.Expression[] = [] + for (let index = 0; index < loopIndices.length; index++) { + const element = loopIndices[index] + tpmlExprs.push(t.identifier(element)) + if (loopIndices[index + 1]) { + tpmlExprs.push(t.stringLiteral('-')) + } + } + const compidTempDecl = t.variableDeclaration('const', [ + t.variableDeclarator( + t.arrayPattern([t.identifier(prevVariableName), t.identifier(variableName)]), + t.callExpression( + t.identifier(GEN_COMP_ID), + [t.templateLiteral( + [ + t.templateElement({ raw: '' }), + t.templateElement({ raw: createRandomLetters(10) }), + ...tpmlExprs.map(() => t.templateElement({ raw: '' })) + ], + [ + this.prefixExpr(), + ...tpmlExprs + ] + ), t.booleanLiteral(true)] + ) + ) + ]) + + const properties = this.getPropsFromAttrs(element) + const propsSettingExpr = this.genPropsSettingExpression(properties, t.identifier(variableName), t.identifier(prevVariableName)) + const expr = setAncestorCondition(path as any, propsSettingExpr) + this.ancestorConditions.add(expr) + + body.splice(body.length - 1, 0, compidTempDecl, t.expressionStatement(expr)) + + // wxml 组件打上 compid + const [ func ] = callee.node.arguments + let forItem: t.Identifier | null = null + if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) { + forItem = func.params[0] as t.Identifier + } + if (forItem === null || !t.isIdentifier(forItem)) { + throw codeFrameError(callee.node, '在循环中使用自定义组件时必须暴露循环的第一个参数 `item`') + } + element.attributes.push(t.jSXAttribute( + t.jSXIdentifier('compid'), + t.jSXExpressionContainer(t.memberExpression(forItem, t.identifier(variableName))) + )) + } + } + }) + + deferCallBack.forEach(cb => cb()) + } + + let stateToBeAssign = new Set( + difference( + Object.keys(blockStatementPath.scope.getAllBindings()), + Object.keys(this.renderScope.getAllBindings()) + ).filter(i => { + return !this.methods.has(i) + }) + .filter(i => !this.loopScopes.has(i)) + .filter(i => !this.initState.has(i)) + .filter(i => !this.templates.has(i)) + .filter(i => !i.includes('.')) + .filter(i => i !== MAP_CALL_ITERATOR) + ) + if (body.length > 1) { + const [ func ] = callee.node.arguments + if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) { + const [ item, indexParam ] = func.params as t.Identifier[] + const parents = findParents(callee as any, (p) => isArrayMapCallExpression(p)) + const iterators = new Set( + [item.name, ...parents + .map((p) => safeGet(p, 'node.arguments[0].params[0].name', '')) + .filter(Boolean)] + ) + for (const [ index, statement ] of body.entries()) { + if (t.isVariableDeclaration(statement)) { + for (const dcl of statement.declarations) { + if (t.isIdentifier(dcl.id)) { + const name = dcl.id.name + if ( + name.startsWith(LOOP_STATE) || + name.startsWith(LOOP_CALLEE) || + name.startsWith(COMPID) || + name.startsWith('_$indexKey') + ) { + stateToBeAssign.add(name) + dcl.id = t.identifier(name) + } + } else if (t.isArrayPattern(dcl.id)) { + dcl.id.elements.forEach(stm => { + if (t.isIdentifier(stm)) { + const name = stm.name + if ( + name.startsWith(LOOP_STATE) || + name.startsWith(LOOP_CALLEE) || + name.startsWith(COMPID) || + name.startsWith('_$indexKey') + ) { + stateToBeAssign.add(name) + } + } + }) + } + } + } + if (t.isReturnStatement(statement)) { + body.splice(index, 1) + } + } + stateToBeAssign.forEach(s => this.loopRefIdentifiers.set(s, callee)) + const properties = Array.from(stateToBeAssign).map(state => t.objectProperty(t.identifier(state), t.identifier(state))) + // tslint:disable-next-line:no-inner-declarations + function replaceOriginal (path, parent, name) { + if ( + (path.isReferencedIdentifier() || t.isAssignmentExpression(parent)) && + iterators.has(name) && + !(t.isMemberExpression(parent) && t.isIdentifier(parent.property, { name: LOOP_ORIGINAL })) && + !(t.isMemberExpression(parent) && t.isIdentifier(parent.property) && (parent.property.name.startsWith(LOOP_STATE) || parent.property.name.startsWith(LOOP_CALLEE) || parent.property.name.startsWith(COMPID))) + ) { + path.replaceWith(t.memberExpression( + t.identifier(name), + t.identifier(LOOP_ORIGINAL) + )) + } + } + const bodyPath = (callee.get('arguments') as any)[0].get('body') + bodyPath.traverse({ + Identifier (path) { + const name = path.node.name + const parent = path.parent + replaceOriginal(path, parent, name) + } + }) + const replacements = new Set() + component.traverse({ + JSXAttribute: !t.isIdentifier(indexParam) ? noop : (path: NodePath) => { + const { value } = path.node + if (t.isJSXExpressionContainer(value) && t.isJSXIdentifier(path.node.name, { name: 'key' }) && t.isIdentifier(value.expression, { name: indexParam.name })) { + if (process.env.TERM_PROGRAM || isTestEnv) { // 无法找到 cli 名称的工具(例如 idea/webstorm)显示这个报错可能会乱码 + // tslint:disable-next-line:no-console + console.log(codeFrameError(value.expression, '建议修改:使用循环的 index 变量作为 key 是一种反优化。参考:https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md').message) + } + } + }, + JSXExpressionContainer: this.replaceIdWithTemplate() as any, + Identifier: (path) => { + const name = path.node.name + const parent = path.parent + const parentCallExpr = path.findParent(p => p.isCallExpression()) + if (replacements.has(parent) || ( + this.renderScope.hasOwnBinding(name) && + (this.loopCalleeId.has(path.node as any) || parentCallExpr && this.loopCalleeId.has(parentCallExpr.node as any)) + )) { + return + } + + if (stateToBeAssign.has(name) && path.isReferencedIdentifier()) { + if (t.isMemberExpression(parent) && t.isIdentifier(parent.property, { name: 'map' })) { + const grandParentPath = path.parentPath.parentPath + if (grandParentPath?.isCallExpression() && this.loopComponents.has(grandParentPath)) { + return + } + } + if (path.findParent(p => this.loopCallees.has(p.node as any))) { + return + } + const parentCondition = path.findParent(p => p.isConditionalExpression() || p.isLogicalExpression()) + if (parentCondition) { + const varDecl = parentCondition.findParent(p => p.isVariableDeclarator()) + if (varDecl && varDecl.isVariableDeclarator()) { + const init = varDecl.node.id + if (t.isIdentifier(init) && init.name.startsWith(LOOP_STATE)) { + return + } + } + if (path.findParent(p => this.ancestorConditions.has(p.node as any))) { + return + } + } + const replacement = t.memberExpression( + t.identifier(item.name), + path.node + ) + path.replaceWith(replacement) + replacements.add(replacement) + } else { + replaceOriginal(path, parent, name) + } + + }, + MemberExpression (path) { + const { object, property } = path.node + if (t.isThisExpression(object) && t.isIdentifier(property)) { + if (property.name === 'state' && path.parentPath.isMemberExpression() && path.parentPath.parentPath.isMemberExpression()) { + // tslint:disable-next-line + console.warn( + codeFrameError(path.parentPath.parentPath.node, + `在循环中使用 this.state.xx.xx 可能会存在问题,请给 xx 起一个别名,例如 const { xx } = this.state` + ) + ) + } + } + } + }) + const originalProp = t.objectProperty( + t.identifier(LOOP_ORIGINAL), + t.memberExpression( + t.identifier(item.name), + t.identifier(LOOP_ORIGINAL) + ) + ) + properties.push(originalProp) + body.unshift( + t.expressionStatement(t.assignmentExpression('=', t.identifier(item.name), t.objectExpression([ + t.objectProperty( + t.identifier(LOOP_ORIGINAL), + t.callExpression(t.identifier(INTERNAL_GET_ORIGNAL), [t.identifier(item.name)]) + ) + ]))) + ) + const returnStatement = t.returnStatement(properties.length ? t.objectExpression(properties) : item) + const parentCallee = callee.findParent(c => isArrayMapCallExpression(c as any)) + if (isArrayMapCallExpression(parentCallee as NodePath)) { + const [ func ] = (parentCallee?.node as t.CallExpression).arguments + const { object } = callee.node.callee as t.MemberExpression + if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) { + const funcBody = func.body + if (t.isBlockStatement(funcBody)) { + if (t.isIdentifier(object) || t.isMemberExpression(object)) { + const variableName = this.loopComponentNames.get(callee) as string + funcBody.body.splice( + funcBody.body.length - 1, + 0, + buildConstVariableDeclaration( + variableName, + setParentCondition(component as any, callee.node, true) + ) + ) + const iterator = func.params[0] + component.node.openingElement.attributes.forEach(attr => { + if (t.isJSXAttribute(attr) && attr.name.name === Adapter.for && t.isIdentifier(iterator)) { + attr.value = t.jSXExpressionContainer( + t.memberExpression( + iterator, + t.identifier(variableName) + ) + ) + } + }) + } else { + throw codeFrameError(object.loc, '多层循环中循环的数组只能是一个变量或成员表达式,可以尝试把该表达式赋值给循环内部的一个新变量。') + } + } + } + body.push(returnStatement) + } else { + body.push(returnStatement) + const stateName = this.loopComponentNames.get(callee) as string + // setJSXAttr(returned, Adapter.for, t.identifier(stateName)) + this.addRefIdentifier(callee as any, t.identifier(stateName)) + // this.referencedIdentifiers.add(t.identifier(stateName)) + if (Adapters.quickapp === Adapter.type) { + let itemName = itemId!.name + let indexName = indexId!.name + if (itemName || indexName) { + let forExpr: string + if (itemName && !indexName) { + forExpr = `${itemName} in ${stateName}` + } else { + forExpr = `(${indexName}, ${itemName}) in ${stateName}` + } + setJSXAttr(component.node, Adapter.for, t.stringLiteral(`{{${forExpr}}}`)) + } + } else if (Adapters.swan === Adapter.type) { + const attributes = component.node.openingElement.attributes + const keyAttribute: t.JSXAttribute | undefined = attributes.find(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name, { name: 'key' })) as t.JSXAttribute | undefined + if (keyAttribute && t.isJSXExpressionContainer(keyAttribute.value)) { + let itemName = itemId!.name + const expressionArray = generateMemberExpressionArray(keyAttribute.value.expression as t.MemberExpression) + expressionArray[0] = itemName // 将key属性的值MemberExpression的首位(对象)替换成forItem + const memberExpressionString = expressionArray.join('.') + const forExpr = `${stateName} trackBy ${memberExpressionString}` + setJSXAttr(component.node, Adapter.for, t.stringLiteral(forExpr)) + } else { + setJSXAttr(component.node, Adapter.for, t.jSXExpressionContainer(t.identifier(stateName))) + } + } else { + setJSXAttr(component.node, Adapter.for, t.jSXExpressionContainer(t.identifier(stateName))) + } + const returnBody = this.renderPath.node.body.body + const ifStem = callee.findParent(p => p.isIfStatement()) + // @TEST + if (ifStem && ifStem.isIfStatement()) { + const consequent = ifStem.get('consequent') + if (t.isBlockStatement(consequent)) { + const assignment = t.expressionStatement( + t.assignmentExpression( + '=', + t.identifier(stateName), + setParentCondition(component as any, callee.node, true) + ) + ) + returnBody.unshift( + t.variableDeclaration('let', [t.variableDeclarator(t.identifier(stateName))]) + ) + if (callee.findParent(p => p === consequent)) { + (consequent as any).node.body.push(assignment) + } else { + const alternate = ifStem.get('alternate') + if (t.isBlockStatement(alternate)) { + (alternate as any).node.body.push(assignment) + } else { + (consequent as any).node.body.push(assignment) + } + } + } + } else { + const decl = buildConstVariableDeclaration(stateName, setParentCondition(component as any, callee.node, true)) + returnBody.push(decl) + } + } + } + } + replaceQueue.push(() => { + const statement = component.getStatementParent() + callee.replaceWith( + statement?.isReturnStatement() + ? (statement.get('argument') as NodePath).node + : component.node + ) + }) + }) + if (hasLoopRef) { + const scopeDecl = template('const __scope = this.$scope')() + this.renderPath.node.body.body.unshift(scopeDecl) + } + replaceQueue.forEach(func => func()) + } + + setOutputTemplate () { + if (Adapter.type === Adapters.quickapp && transformOptions.rootProps && transformOptions.isRoot) { + const attrs: t.JSXAttribute[] = [] + for (const key in transformOptions.rootProps) { + if (transformOptions.rootProps.hasOwnProperty(key)) { + const value = transformOptions.rootProps[key] + const keyName = key + '__temp' + const decl = buildConstVariableDeclaration(keyName, t.identifier(JSON.stringify(value))) + this.referencedIdentifiers.add(t.identifier(keyName)) + this.renderPath.node.body.body.push(decl) + attrs.push(t.jSXAttribute(t.jSXIdentifier(key), t.jSXExpressionContainer(t.identifier(keyName)))) + } + } + this.finalReturnElement.openingElement.attributes.push(...attrs) + } + if (!this.finalReturnElement) { + throw codeFrameError(this.renderPath.node, '没有找到返回的 JSX 元素,你是不是忘记 return 了?') + } + this.outputTemplate = parseJSXElement(this.finalReturnElement, true) + if (!this.isDefaultRender) { + this.outputTemplate = `` + } + } + + removeJSXStatement () { + this.jsxDeclarations.forEach(d => d && !d.removed && isContainJSXElement(d) && d.remove()) + this.returnedPaths.forEach((p: NodePath) => { + if (p.removed) { + return + } + const ifStem = p.findParent(_ => _.isIfStatement()) + if (ifStem) { + const node = p.node + if (!node) { + return + } + if (t.isJSXElement(node.argument)) { + const jsx = node.argument + if (jsx.children.length === 0 && jsx.openingElement.attributes.length === 0 && !this.isIfStemInLoop(p.get('argument') as any)) { + node.argument = t.nullLiteral() + } else { + p.remove() + } + } else { + const isValid = p.get('argument').evaluateTruthy() + if (isValid === false) { + node.argument = t.nullLiteral() + } else { + p.remove() + } + } + } else { + p.remove() + } + }) + } + + setReserveWord = (word: string) => { + const binding = this.renderScope.getOwnBinding(word) + let hasStateId = false + if (binding) { + const path = binding.path + const id = path.get('id') as NodePath + const init = path.get('init') + if (t.isThisExpression(init)) { + return hasStateId + } + if (id.isObjectPattern()) { + hasStateId = (id.node.properties as (t.RestProperty | t.ObjectProperty)[]).some(p => { + return (t.isObjectProperty(p) && t.isIdentifier(p.key, { name: word })) + || (t.isRestProperty(p) && t.isIdentifier((p as t.RestProperty).argument, { name: word })) + }) + } else if (id.isIdentifier({ name: word })) { + hasStateId = true + } + if (hasStateId) { + this.referencedIdentifiers.add(t.identifier(word)) + } + } + if (hasStateId) { + this.reserveStateWords.delete(word) + } + } + + setCustomEvent () { + const classPath = this.renderPath.findParent(isClassDcl as any) as NodePath + const eventPropName = Adapter.type === Adapters.quickapp ? 'privateTaroEvent' : '$$events' + const body = classPath.node.body.body.find(b => t.isClassProperty(b) && (b.key as t.Identifier).name === eventPropName) as t.ClassProperty + const usedEvents = Array.from(this.usedEvents).map(s => t.stringLiteral(s)) + if (body && t.isArrayExpression(body.value)) { + body.value = t.arrayExpression(uniq(body.value.elements.concat(usedEvents))) + } else { + let classProp = t.classProperty(t.identifier(eventPropName), t.arrayExpression(usedEvents)) as any // babel 6 typing 没有 static + classProp.static = true + classPath.node.body.body.unshift(classProp) + } + } + + setUsedState () { + if (!this.isDefaultRender) { + return + } + for (const [ key, method ] of this.methods) { + if (method) { + if (method.isClassMethod()) { + const kind = method.node.kind + if (kind === 'get') { + this.classComputedState.add(key) + } + } + } + } + + let componentProperies = cloneDeep(this.componentProperies) + + componentProperies.forEach(s => { + if (s.startsWith(FN_PREFIX)) { + const eventName = s.slice(5) + if (componentProperies.has(eventName)) { + componentProperies.delete(s) + componentProperies.delete(eventName) + } + } + }) + + if (Adapter.type === Adapters.quickapp) { + componentProperies = new Set(Array.from(componentProperies).map(p => this.upperCaseComponentProps.has(p) && !p.startsWith('on') && !p.startsWith('prv-fn') ? snakeCase(p) : p)) + } + + Array.from(this.reserveStateWords).forEach(this.setReserveWord) + let usedState = Array.from( + new Set( + Array.from(this.referencedIdentifiers) + .map(i => i.name) + .concat([...this.initState, ...this.usedThisState, ...componentProperies, ...this.classComputedState]) + ) + ) + .concat(...this.usedState) + // .filter(i => { + // return !methods.has(i) + // }) + .filter(i => !this.loopScopes.has(i)) + .filter(i => !this.templates.has(i)) + .filter(Boolean) + + if (Adapter.type === Adapters.quickapp) { + usedState = usedState + .filter(i => !new Set([...this.upperCaseComponentProps].map(i => i.toLowerCase())).has(i)) + .filter(i => !this.upperCaseComponentProps.has(i)) + } + + const classPath = this.renderPath.findParent(isClassDcl as any) as NodePath + classPath.node.body.body.unshift(t.classProperty(t.identifier('$usedState'), t.arrayExpression( + [...new Set( + usedState + .filter(s => !this.loopScopes.has(s.split('.')[0])) + .filter(i => i !== MAP_CALL_ITERATOR && !this.reserveStateWords.has(i)) + .filter(i => isVarName(i)) + .filter(i => !this.loopRefIdentifiers.has(i)) + .concat(Array.from(this.customComponentNames)) + )] + .map(s => t.stringLiteral(s)) + ))) + } + + checkDuplicateName () { + this.loopScopes.forEach(s => { + if (s.includes('anonIdx')) { + return + } + if (this.renderPath.scope.hasBinding(s)) { + const err = codeFrameError(this.renderPath.scope.getBinding(s)!.path.node, '此变量声明与循环变量冲突,可能会造成问题。') + // tslint:disable-next-line: no-console + console.warn('Warning: ', err.message) + this.loopScopes.delete(s) + } + }) + } + + setPendingState () { + let propertyKeys = Array.from( + new Set(Array.from(this.referencedIdentifiers) + .map(i => i.name)) + ) + .filter(i => { + const method = this.methods.get(i) + let isGet = false + if (method) { + if (method.isClassMethod()) { + const kind = method.node.kind + if (kind === 'get') { + isGet = true + } + } + } + return !this.methods.has(i) || isGet + }) + .filter(i => !this.loopScopes.has(i)) + .filter(i => !this.templates.has(i)) + .filter(i => isVarName(i)) + .filter(i => i !== MAP_CALL_ITERATOR && !this.reserveStateWords.has(i)) + .filter(i => !i.startsWith('$$')) + .filter(i => !i.startsWith('_$indexKey')) + .filter(i => !this.loopRefIdentifiers.has(i)) + + if (this.isDefaultRender) { + propertyKeys = propertyKeys.filter(i => !this.initState.has(i)) + } + + let properties = propertyKeys.map(i => t.objectProperty(t.identifier(i), t.identifier(i))) + const pendingState = t.objectExpression( + properties.concat( + Array.from(this.classComputedState).filter(i => { + return !propertyKeys.includes(i) + }).map(i => { + return t.objectProperty( + t.identifier(i), + t.memberExpression(t.thisExpression(), t.identifier(i)) + ) + }) + ) + ) + this.propsSettingExpressions.forEach((exprs, stem) => { + stem.body.push(...exprs.map(e => e())) + }) + this.renderPath.node.body.body.unshift(...Array.from(this.genCompidExprs)) + if (this.isDefaultRender) { + if (this.refObjExpr && this.refObjExpr.length) { + this.renderPath.node.body.body.push(t.expressionStatement( + t.callExpression( + t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('$$refs')), t.identifier('pushRefs')), + [t.arrayExpression(this.refObjExpr)] + ) + )) + } + this.renderPath.node.body.body = this.renderPath.node.body.body.concat( + // ...propsStatement, + buildAssignState(pendingState), + t.returnStatement( + t.memberExpression(t.thisExpression(), t.identifier('state')) + ) + ) + } else { + const usedState = Array.from(this.usedThisState).map(s => t.objectProperty(t.identifier(s), t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('state')), t.identifier(s)))) + this.renderPath.node.body.body.push( + // ...propsStatement, + t.returnStatement(t.objectExpression(pendingState.properties.concat(usedState))) + ) + + const { async, body, params } = this.renderPath.node + this.renderPath.replaceWith( + t.classMethod('method', t.identifier(`_create${this.renderMethodName.slice(6)}Data`), [t.identifier(CLASS_COMPONENT_UID)], t.blockStatement([ + t.returnStatement(t.arrowFunctionExpression( + params as any, + body, + async + )) + ])) + ) + } + this.renderPath.traverse({ + Identifier: (path) => { + if (this.propsDecls.has(path.node.name) && path.parentPath.isCallExpression()) { + const { callee } = path.parentPath.node + if (t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: PROPS_MANAGER }) && t.isIdentifier(callee.property, { name: 'set' })) { + const decl = this.propsDecls.get(path.node.name)! + path.replaceWith(decl.node.declarations[0].init as any) + this.propsDecls.delete(path.node.name) + !decl.removed && decl.remove() + } + } + } + }) + } + + getCreateJSXMethodName = (name: string) => `_create${name.slice(6)}Data` + + createData () { + if (!this.isDefaultRender) { + return + } + const renderBody = this.renderPath.get('body') + renderBody.traverse({ + ThisExpression (path) { + const property = path.getSibling('property') + if (property.isIdentifier({ name : 'state' })) { + property.replaceWith(t.identifier('__state')) + } + if (property.isIdentifier({ name : 'props' })) { + property.replaceWith(t.identifier('__props')) + } + } + }) + + this.usedThisProperties.forEach(prop => { + if (this.renderScope.hasBinding(prop)) { + const binding = this.renderScope.getBinding(prop)! + throw codeFrameError(binding.path.node, `此变量声明与 this.${prop} 的声明冲突,请更改其中一个变量名。详情见:https://github.com/NervJS/taro/issues/822`) + } + }) + + this.renderPath.node.body.body.unshift( + template(`this.__state = arguments[0] || this.state || {};`)(), + template(`this.__props = arguments[1] || this.props || {};`)(), + template(`const __isRunloopRef = arguments[2];`)(), + template(`const __prefix = this.$prefix`)(), + this.usedThisProperties.size + ? t.variableDeclaration( + 'const', + [ + t.variableDeclarator( + t.objectPattern(Array.from(this.usedThisProperties).map(p => t.objectProperty( + t.identifier(p), + t.identifier(p) + ) as any)), + t.thisExpression() + ) + ] + ) + : t.emptyStatement() + ) + + if (t.isIdentifier(this.renderPath.node.key)) { + this.renderPath.node.key.name = '_createData' + } + } +} diff --git a/packages/taro-transformer-wx/src/utils.ts b/packages/taro-transformer-wx/src/utils.ts new file mode 100644 index 000000000000..ff4cd5e59203 --- /dev/null +++ b/packages/taro-transformer-wx/src/utils.ts @@ -0,0 +1,716 @@ +import { codeFrameColumns } from '@babel/code-frame' +import generate from '@babel/generator' +import { NodePath, Scope } from '@babel/traverse' +import * as t from '@babel/types' +import * as fs from 'fs' +import { cloneDeep } from 'lodash' +import * as path from 'path' + +import { Adapter, Adapters } from './adapter' +import { IS_TARO_READY,LOOP_STATE, TARO_PACKAGE_NAME } from './constant' +import { buildBlockElement } from './jsx' +import { transformOptions } from './options' +// const template = require('babel-template') +const template = require('@babel/template') + +export function replaceJSXTextWithTextComponent (path: NodePath) { + const parent = path.findParent(p => p.isJSXElement()) + if (parent && parent.isJSXElement() && t.isJSXIdentifier(parent.node.openingElement.name) && parent.node.openingElement.name.name !== 'Text') { + path.replaceWith(t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('Text'), []), + t.jSXClosingElement(t.jSXIdentifier('Text')), + [path.isJSXText() ? t.jSXText(path.node.value) : path.node] + )) + } +} + +export function isDerivedFromProps (scope: Scope, bindingName: string) { + const binding = scope.getBinding(bindingName) + if (binding && binding.path.isVariableDeclarator()) { + const init = binding.path.get('init') as any + if (t.isMemberExpression(init)) { + const { object, property } = init + if (t.isThisExpression(object) && t.isIdentifier(property, { name: 'props' })) { + return true + } + } + if (t.isIdentifier(init)) { + return isDerivedFromProps(scope, init.name) + } + } + return false +} + +export function isDerivedFromThis (scope: Scope, bindingName: string) { + const binding = scope.getBinding(bindingName) + if (binding && binding.path.isVariableDeclarator()) { + const init = binding.path.get('init') + if (t.isThisExpression(init)) { + return true + } + } + return false +} + +export const incrementId = () => { + let id = 0 + return () => id++ +} + +// tslint:disable-next-line:no-empty +export const noop = function () {} + +export function getSuperClassCode (path: NodePath) { + const obj = getSuperClassPath(path) + if (obj) { + const { sourceValue, resolvePath } = obj + try { + const code = fs.readFileSync(resolvePath + (transformOptions.isTyped ? '.tsx' : '.js'), 'utf8') + return { + code, + sourcePath: sourceValue + } + } catch (error) { + + } + } +} + +export function getSuperClassPath (path: NodePath) { + const superClass = path.node.superClass + if (t.isIdentifier(superClass)) { + const binding = path.scope.getBinding(superClass.name) + if (binding && binding.kind === 'module') { + const bindingPath = binding.path.parentPath + if (t.isImportDeclaration(bindingPath)) { + const source = (bindingPath.node as any).source + if (source.value === TARO_PACKAGE_NAME) { + return + } + return { + sourceValue: source.value, + resolvePath: pathResolver(source.value, transformOptions.sourcePath) + } + } + } + } +} + +export function isContainStopPropagation (path: NodePath | null | undefined) { + let matched = false + if (path) { + const visitor = { + Identifier (p) { + if ( + p.node.name === 'stopPropagation' && + p.parentPath.parentPath.isCallExpression() + ) { + matched = true + } + } + } + if (path.isIdentifier()) { + const binding = path.scope.getBinding(path.node.name) + if (binding) { + binding.path.traverse(visitor) + } + } else { + path.traverse(visitor) + } + } + return matched +} + +export function decodeUnicode (s: string) { + return unescape(s.replace(/\\(u[0-9a-fA-F]{4})/gm, '%$1')) +} + +export function isVarName (str: string | unknown) { + if (typeof str !== 'string') { + return false + } + + if (str.trim() !== str) { + return false + } + + try { + // tslint:disable-next-line:no-unused-expression + new Function(str, 'var ' + str) + } catch (e) { + return false + } + + return true +} + +export function findMethodName (expression: t.Expression): string { + let methodName + if ( + t.isIdentifier(expression) || + t.isJSXIdentifier(expression) + ) { + methodName = expression.name + } else if (t.isStringLiteral(expression)) { + methodName = expression.value + } else if ( + t.isMemberExpression(expression) && + t.isIdentifier(expression.property) + ) { + const { code } = generate(expression) + const ids = code.split('.') + if (ids[0] === 'this' && ids[1] === 'props' && ids[2]) { + methodName = code.replace('this.props.', '') + } else { + methodName = expression.property.name + } + } else if ( + t.isCallExpression(expression) && + t.isMemberExpression(expression.callee) && + t.isIdentifier(expression.callee.object) + ) { + methodName = expression.callee.object.name + } else if ( + t.isCallExpression(expression) && + t.isMemberExpression(expression.callee) && + t.isMemberExpression(expression.callee.object) && + t.isIdentifier(expression.callee.property) && + expression.callee.property.name === 'bind' && + t.isIdentifier(expression.callee.object.property) + ) { + methodName = expression.callee.object.property.name + } else { + throw codeFrameError(expression.loc, '当 props 为事件时(props name 以 `on` 开头),只能传入一个 this 作用域下的函数。') + } + return methodName +} + +export function setParentCondition (jsx: NodePath, expr: t.Expression, array = false) { + const conditionExpr = jsx.findParent(p => p.isConditionalExpression()) + const logicExpr = jsx.findParent(p => p.isLogicalExpression({ operator: '&&' })) + if (array) { + const ifAttrSet = new Set([ + Adapter.if, + Adapter.else + ]) + const logicalJSX = jsx.findParent(p => p.isJSXElement() && p.node.openingElement.attributes.some(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && ifAttrSet.has(a.name.name))) as NodePath + if (logicalJSX) { + const attr = logicalJSX.node.openingElement.attributes.find(a => t.isJSXAttribute(a) && ifAttrSet.has(a.name.name as string)) + if (attr) { + if (t.isJSXAttribute(attr) && attr.name.name === Adapter.else) { + const prevElement: NodePath = (logicalJSX as any).getPrevSibling() + if (prevElement && prevElement.isJSXElement()) { + const attr = prevElement.node.openingElement.attributes.find(a => t.isJSXAttribute(a) && a.name.name === Adapter.if) + if (attr && t.isJSXAttribute(attr) && t.isJSXExpressionContainer(attr.value)) { + expr = t.conditionalExpression(reverseBoolean(cloneDeep((attr.value as any).expression)), expr, t.arrayExpression()) + return expr + } + } + } else if (t.isJSXAttribute(attr) && t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value)) { + expr = t.conditionalExpression(cloneDeep((attr.value as any).expression), expr, t.arrayExpression()) + return expr + } + } + } + } + if (conditionExpr && conditionExpr.isConditionalExpression()) { + const consequent = conditionExpr.get('consequent') + if (consequent === jsx || jsx.findParent(p => p === consequent)) { + expr = t.conditionalExpression(cloneDeep((conditionExpr.get('test') as NodePath).node) as any, expr, array ? t.arrayExpression([]) : t.nullLiteral()) + } + } + if (logicExpr && logicExpr.isLogicalExpression({ operator: '&&' })) { + const consequent = logicExpr.get('right') + if (consequent === jsx || jsx.findParent(p => p === consequent)) { + expr = t.conditionalExpression(cloneDeep((logicExpr.get('left') as NodePath).node) as any, expr, array ? t.arrayExpression([]) : t.nullLiteral()) + } + } + return expr +} + +export function generateAnonymousState ( + scope: Scope, + expression: NodePath, + refIds: Set, + isLogical?: boolean +) { + let variableName = `anonymousState_${scope.generateUid()}` + let statementParent = expression.getStatementParent() + if (!statementParent) { + throw codeFrameError(expression.node.loc, '无法生成匿名 State,尝试先把值赋到一个变量上再把变量调换。') + } + const jsx = isLogical ? expression : expression.findParent(p => p.isJSXElement()) + const callExpr = jsx?.findParent(p => p.isCallExpression() && isArrayMapCallExpression(p as any)) as NodePath + const ifExpr = jsx?.findParent(p => p.isIfStatement()) + const blockStatement = jsx?.findParent(p => p.isBlockStatement() && p.parentPath === ifExpr) as NodePath + const expr = setParentCondition(jsx as any, cloneDeep(expression.node)) + if (!callExpr) { + refIds.add(t.identifier(variableName)) + statementParent.insertBefore( + buildConstVariableDeclaration(variableName, expr) + ) + if (blockStatement && blockStatement.isBlockStatement()) { + blockStatement.traverse({ + VariableDeclarator: (path) => { + const { id, init } = path.node + const isArrowFunctionInJSX = path.findParent(p => p.isJSXAttribute() || + ( + p.isAssignmentExpression() && t.isMemberExpression(p.node.left) && t.isThisExpression(p.node.left.object) + && t.isIdentifier(p.node.left.property) && p.node.left.property.name.startsWith('') + ) + ) + if (isArrowFunctionInJSX) { + return + } + // tslint:disable-next-line: strict-type-predicates + if (t.isIdentifier(id) && !id.name.startsWith(LOOP_STATE) && !id.name.startsWith('_$') && init != null) { + const newId = scope.generateDeclaredUidIdentifier('$' + id.name) + refIds.forEach((refId) => { + if (refId.name === variableName && !variableName.startsWith('_$')) { + refIds.delete(refId) + } + }) + variableName = newId.name + if (Adapter.type === Adapters.quickapp && variableName.startsWith('_$')) { + const newVarName = variableName.slice(2) + scope.rename(variableName, newVarName) + variableName = newVarName + } + refIds.add(t.identifier(variableName)) + blockStatement.scope.rename(id.name, newId.name) + path.parentPath.replaceWith( + template('ID = INIT;')({ ID: newId, INIT: init }) + ) + } + } + }) + } + } else { + variableName = `${LOOP_STATE}_${callExpr.scope.generateUid()}` + const func = callExpr.node.arguments[0] + if (t.isArrowFunctionExpression(func)) { + if (!t.isBlockStatement(func.body)) { + func.body = t.blockStatement([ + buildConstVariableDeclaration(variableName, expr), + t.returnStatement(func.body) + ]) + } else { + if (ifExpr && ifExpr.isIfStatement() && ifExpr.findParent(p => p === callExpr)) { + const consequent = ifExpr.get('consequent') as NodePath + const test = ifExpr.get('test') + if (t.isBlockStatement(consequent)) { + if (jsx != null && jsx === test || jsx?.findParent(p => p === test)) { + func.body.body.unshift(buildConstVariableDeclaration(variableName, expr)) + } else { + // func.body.body.unshift(t.variableDeclaration('let', [t.variableDeclarator(t.identifier(variableName), t.nullLiteral())])) + (consequent.node as any).body.push(t.expressionStatement(t.assignmentExpression( + '=', + t.identifier(variableName), + expr + ))) + } + } else { + throw codeFrameError(consequent.node, 'if 表达式的结果必须由一个花括号包裹') + } + } else { + func.body.body.splice(func.body.body.length - 1, 0, buildConstVariableDeclaration(variableName, expr)) + } + } + } + } + const id = t.identifier(variableName) + expression.replaceWith(id) + return id +} + +export function isArrayMapCallExpression (callExpression: NodePath): callExpression is NodePath { + return callExpression && + t.isCallExpression(callExpression.node) && + t.isMemberExpression(callExpression.node.callee) && + t.isIdentifier(callExpression.node.callee.property, { name: 'map' }) +} + +export function buildConstVariableDeclaration ( + variableName: string, + expresion: t.Expression +) { + return t.variableDeclaration('const', [ + t.variableDeclarator(t.identifier(variableName), expresion) + ]) +} + +export function setTemplate (name: string, path: NodePath, templates) { + const parentPath = path.parentPath + const jsxChildren = parentPath?.findParent(p => p.isJSXElement()) + if (name && !jsxChildren) { + templates.set(name, path.node) + } +} + +export function isContainFunction (p: NodePath) { + let bool = false + p.traverse({ + CallExpression () { + bool = true + } + }) + return bool +} + +function slash (input: string) { + const isExtendedLengthPath = /^\\\\\?\\/.test(input) + const hasNonAscii = /[^\u0000-\u0080]+/.test(input) + const hasChinese = /[^\u4e00-\u9fa5]+/.test(input) // has Chinese characters + + if (isExtendedLengthPath || (hasNonAscii && !hasChinese)) { + return input + } + + return input.replace(/\\/g, '/') +} + +export function pathResolver (source: string, location: string) { + const extName = path.extname(source) + const promotedPath = source + if (!['js', 'tsx'].includes(extName)) { + try { + const pathExist = fs.existsSync(path.resolve(path.dirname(location), source, 'index.js')) + const tsxPathExist = fs.existsSync(path.resolve(path.dirname(location), source, 'index.tsx')) + if (pathExist || tsxPathExist) { + let p = path.join(promotedPath, 'index') + if (!p.startsWith('.')) { + p = './' + p + } + return slash(p) + } + return slash(promotedPath) + } catch (error) { + return slash(promotedPath) + } + } + return slash(promotedPath.split('.').slice(0, -1).join('.')) +} + +export const setting = { + sourceCode: '' +} + +export function codeFrameError (node, msg: string) { + let errMsg = '' + try { + errMsg = codeFrameColumns(setting.sourceCode, node && node.type && node.loc ? node.loc : node, { + highlightCode: true + }) + } catch (error) { + errMsg = 'failed to locate source' + } + return new Error(`${msg} +----- +${errMsg}`) +} + +export function createUUID () { + return '$' + 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + let r = Math.random() * 16 | 0 + let v = c === 'x' ? r : (r & 0x3 | 0x8) + return v.toString(16) + }).replace(/-/g, '').slice(0, 8) +} + +let count = 0 +export function createRandomLetters (n: number) { + const countStr = (count++).toString() + let letters = '' + for (const s of countStr) { + letters += String.fromCharCode(97 + parseInt(s, 10)) + } + const padding = n - letters.length + for (let i = 0; i < padding; i++) { + letters += 'z' + } + return letters +} + +export function isBlockIfStatement (ifStatement, blockStatement): ifStatement is NodePath { + return ifStatement && blockStatement && + ifStatement.isIfStatement() && + blockStatement.isBlockStatement() +} + +export function buildCodeFrame (code: string) { + return (loc: t.SourceLocation) => codeFrameColumns(code, loc) as string +} + +export function isNumeric (n) { + return !isNaN(parseFloat(n)) && isFinite(n) +} + +export function buildJSXAttr (name: string, value: t.Identifier | t.Expression) { + return t.jSXAttribute(t.jSXIdentifier(name), t.jSXExpressionContainer(value)) +} + +export function newJSXIfAttr (jsx: t.JSXElement, value: t.Identifier | t.Expression, path?: NodePath) { + const element = jsx.openingElement + if (!t.isJSXIdentifier(element.name)) { + return + } + if (element.name.name === 'Block' || element.name.name === 'block' || !path) { + const attrs = element.attributes + if (!attrs.some(a => t.isJSXAttribute(a) && a.name.name === Adapter.for)) { + element.attributes.push(buildJSXAttr(Adapter.if, value)) + } else if (path) { + const block = buildBlockElement() + newJSXIfAttr(block, value) + block.children.push(jsx) + path.node = block + } + } else { + const block = buildBlockElement() + newJSXIfAttr(block, value) + block.children.push(jsx) + path.node = block + } +} + +export function getSlotName (name: string) { + return name.slice(6).toLowerCase() +} + +export function isContainJSXElement (path: NodePath) { + let matched = false + path.traverse({ + JSXElement (p) { + matched = true + p.stop() + } + }) + return matched +} + +export function hasComplexExpression (path: NodePath) { + let matched = false + if (isContainJSXElement(path)) { + return false + } + if (path.isObjectExpression()) { + return true + } + if (path.isTemplateLiteral() || path.isCallExpression()) { + return true + } + if (path.isArrayExpression()) { + const { elements } = path.node + if (elements.some(el => t.isObjectExpression(el as any) || t.isArrayExpression(el))) { + return true + } + } + path.traverse({ + CallExpression: (p) => { + matched = true + p.stop() + }, + TemplateLiteral (p) { + matched = true + p.stop() + }, + ObjectExpression (p) { + matched = true + p.stop() + }, + ArrayExpression (p) { + const { elements } = p.node + if (elements.some(el => t.isObjectExpression(el as any))) { + return true + } + }, + TaggedTemplateExpression (p) { + matched = true + p.stop() + }, + MemberExpression (path) { + const jsxElement = path.findParent(p => p.isJSXExpressionContainer()) + const object = path.get('object') + const property = path.get('property') + const parentPath = path.parentPath + if ( + jsxElement && + object.isThisExpression() && + property.isIdentifier({ name: 'state' }) && + parentPath.isMemberExpression() && + parentPath.parentPath.isMemberExpression() + ) { + const sourceCode = parentPath.parentPath.getSource() + if (sourceCode.includes('[') && sourceCode.includes(']')) { + matched = true + path.stop() + } + } + } + }) + return matched +} + +export function findFirstIdentifierFromMemberExpression (node: t.MemberExpression, member?): t.Identifier { + let id + let object = node.object as any + while (true) { + if (t.identifier(object) && !t.isMemberExpression(object)) { + id = object + if (member) { + object = member + } + break + } + object = object.object + } + return id +} + +export function generateMemberExpressionArray (node: t.MemberExpression): string[] { + let {object, property}: {object: any, property: any} = node + let result = [property] + while (true) { + if (t.identifier(object) && !t.isMemberExpression(object)) { + result.push(object); + break + } + property = object.property + result.push(property) + object = object.object + } + return result.reverse().map((a: t.Identifier) => a.name) +} + +export function getArgumentName (arg) { + if (t.isThisExpression(arg)) { + return 'this' + } else if (t.isNullLiteral(arg)) { + return 'null' + } else if (t.isStringLiteral(arg) || t.isNumericLiteral(arg)) { + return arg.value + } else if (t.isIdentifier(arg)) { + return arg.name + } else { + return generate(arg).code + } + throw new Error(`bind 不支持传入该参数: ${arg}`) +} + +export function isAllLiteral (...args) { + return args.every(p => t.isLiteral(p)) +} + +export function reverseBoolean (expression: t.Expression) { + return t.unaryExpression( + '!', + expression + ) +} + +export function isEmptyDeclarator (node: t.Node) { + if ( + t.isVariableDeclarator(node) && + // tslint:disable-next-line: strict-type-predicates + (node.init === null || + t.isNullLiteral(node.init)) + ) { + return true + } + return false +} + +export function toLetters (num: number): string { + let mod = num % 26 + let pow = num / 26 | 0 + let out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z') + const letter = pow ? toLetters(pow) + out : out + return letter.toLowerCase() +} + +export function findIdentifierFromStatement (statement: t.Node) { + if (t.isVariableDeclaration(statement)) { + const declarator = statement.declarations.find(s => t.isIdentifier(s.id)) + if (declarator && t.isIdentifier(declarator.id)) { + return declarator.id.name + } + } + return '__return' +} + +let id = 0 +export function genCompid (): string { + return String(id++) +} + +export function findParentLoops ( + callee: NodePath, + names: Map, string>, + loops: t.ArrayExpression +) { + let indexId: t.Identifier | null = null + let name: string | undefined + const [ func ] = callee.node.arguments + if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) { + const params = func.params as t.Identifier[] + indexId = params[1] + name = names.get(callee) + } + + if (indexId === null || !t.isIdentifier(indexId)) { + indexId = t.identifier(callee.scope.generateUid('anonIdx')); + (func as any).params = [(func as any).params[0], indexId] + } + + if (!name) { + throw codeFrameError(callee.node, '找不到循环对应的名称') + } + + loops.elements.unshift(t.objectExpression([ + t.objectProperty(t.identifier('indexId'), indexId), + t.objectProperty(t.identifier('name'), t.stringLiteral(name)) + ])) + + const parentCallExpr = callee.findParent(p => p.isCallExpression()) + if (parentCallExpr && parentCallExpr.isCallExpression()) { + const callee = parentCallExpr.node.callee + if ( + t.isMemberExpression(callee) && + t.isIdentifier(callee.property) && + callee.property.name === 'map' + ) { + findParentLoops(parentCallExpr as any, names, loops) + } + } +} + +export function setAncestorCondition (jsx: NodePath, expr: t.Expression): t.Expression { + const ifAttrSet = new Set([ + Adapter.if, + Adapter.else + ]) + const logicalJSX = jsx.findParent(p => p.isJSXElement() && p.node.openingElement.attributes.some(a => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name) && ifAttrSet.has(a.name.name))) as NodePath + if (logicalJSX) { + const attr = (logicalJSX.node as any).openingElement.attributes.find(a => t.isJSXAttribute(a) && ifAttrSet.has(a.name.name as string)) + if (attr && t.isJSXAttribute(attr)) { + if (attr.name.name === Adapter.else) { + const prevElement: NodePath = (logicalJSX as any).getPrevSibling() + if (prevElement && prevElement.isJSXElement()) { + const attr = prevElement.node.openingElement.attributes.find(a => t.isJSXAttribute(a) && a.name.name === Adapter.if) + if (attr && t.isJSXAttribute(attr) && !t.isJSXElement(attr.value)) { + const condition = reverseBoolean(cloneDeep((attr.value as any)?.expression)) + expr = t.logicalExpression('&&', setAncestorCondition(logicalJSX, condition), expr) + } + } + } else if (t.isJSXExpressionContainer(attr.value)) { + const condition = cloneDeep(attr.value.expression) + if (t.isJSXIdentifier(condition, { name: IS_TARO_READY })) { + return expr + } + const ifStem = logicalJSX.findParent(p => p.isIfStatement()) + expr = t.logicalExpression('&&', setAncestorCondition(logicalJSX, ifStem && ifStem.isIfStatement() ? attr.value.expression as any : condition as any), expr) + } + } + } + + return expr +} diff --git a/packages/taro-transformer-wx/tsconfig.json b/packages/taro-transformer-wx/tsconfig.json new file mode 100644 index 000000000000..4eb96cbdef68 --- /dev/null +++ b/packages/taro-transformer-wx/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "removeComments": false, + "preserveConstEnums": true, + "moduleResolution": "node", + "experimentalDecorators": true, + "noImplicitAny": false, + "allowSyntheticDefaultImports": true, + "outDir": "lib", + "noUnusedLocals": true, + "noUnusedParameters": true, + "strictNullChecks": true, + "sourceMap": true, + "baseUrl": ".", + "rootDir": ".", + "allowJs": true, + "skipLibCheck": true + }, + "include": ["src"], + "exclude": ["__tests__", "node_modules", "dist", "tests", "jest", "lib", "**/*.test.ts", "**/*.spec.ts"], + "compileOnSave": false +} diff --git a/packages/taro-transformer-wx/yarn.lock b/packages/taro-transformer-wx/yarn.lock new file mode 100644 index 000000000000..56e85cc356e7 --- /dev/null +++ b/packages/taro-transformer-wx/yarn.lock @@ -0,0 +1,4319 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.0.0-beta.44.tgz?cache=0&sync_timestamp=1593522948158&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + dependencies: + "@babel/highlight" "7.0.0-beta.44" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.35", "@babel/code-frame@^7.0.0-beta.44": + version "7.10.4" + resolved "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522948158&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.0.0-beta.44.tgz?cache=0&sync_timestamp=1593522965477&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + dependencies: + "@babel/types" "7.0.0-beta.44" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.0.0-beta.44.tgz?cache=0&sync_timestamp=1593522977138&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.0.0-beta.44.tgz?cache=0&sync_timestamp=1593521294451&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.0.0-beta.44.tgz?cache=0&sync_timestamp=1593522967620&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.npm.taobao.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.10.4.tgz?cache=0&sync_timestamp=1593521083613&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-validator-identifier%2Fdownload%2F%40babel%2Fhelper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.0.0-beta.44.tgz?cache=0&sync_timestamp=1593521095576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhighlight%2Fdownload%2F%40babel%2Fhighlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.10.4.tgz?cache=0&sync_timestamp=1593521095576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhighlight%2Fdownload%2F%40babel%2Fhighlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.0.0-beta.44.tgz?cache=0&sync_timestamp=1593522838025&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + +"@types/babel-core@6.25.6": + version "6.25.6" + resolved "https://registry.npm.taobao.org/@types/babel-core/download/@types/babel-core-6.25.6.tgz#9e4faefcb300fd3abf0d2c2d85c505071462c1e1" + dependencies: + "@types/babel-generator" "*" + "@types/babel-template" "*" + "@types/babel-traverse" "*" + "@types/babel-types" "*" + "@types/babylon" "*" + +"@types/babel-generator@*", "@types/babel-generator@6.25.3": + version "6.25.3" + resolved "https://registry.npm.taobao.org/@types/babel-generator/download/@types/babel-generator-6.25.3.tgz#8f06caa12d0595a0538560abe771966d77d29286" + dependencies: + "@types/babel-types" "*" + +"@types/babel-template@*", "@types/babel-template@6.25.2": + version "6.25.2" + resolved "https://registry.npm.taobao.org/@types/babel-template/download/@types/babel-template-6.25.2.tgz#3c4cde02dbcbbf461a58d095a9f69f35eabd5f06" + dependencies: + "@types/babel-types" "*" + "@types/babylon" "*" + +"@types/babel-traverse@*": + version "6.25.5" + resolved "https://registry.npm.taobao.org/@types/babel-traverse/download/@types/babel-traverse-6.25.5.tgz#6d293cf7523e48b524faa7b86dc3c488191484e5" + dependencies: + "@types/babel-types" "*" + +"@types/babel-traverse@6.25.3": + version "6.25.3" + resolved "https://registry.npm.taobao.org/@types/babel-traverse/download/@types/babel-traverse-6.25.3.tgz#34dd69d1e469aee75e20ba00fbc52c7bc717b1c8" + dependencies: + "@types/babel-types" "*" + +"@types/babel-types@*", "@types/babel-types@7.0.8": + version "7.0.8" + resolved "https://registry.npm.taobao.org/@types/babel-types/download/@types/babel-types-7.0.8.tgz#267f405bda841ffae731e7714166b88254cc3e19" + +"@types/babylon@*": + version "6.16.5" + resolved "https://registry.npm.taobao.org/@types/babylon/download/@types/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4" + dependencies: + "@types/babel-types" "*" + +"@types/eslint@^4.16.5": + version "4.16.8" + resolved "https://registry.npm.taobao.org/@types/eslint/download/@types/eslint-4.16.8.tgz#856f0eb8a312d25a7989b6d0ab708e8d5f8cc7ee" + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "0.0.45" + resolved "https://registry.npm.taobao.org/@types/estree/download/@types/estree-0.0.45.tgz?cache=0&sync_timestamp=1592943929870&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Festree%2Fdownload%2F%40types%2Festree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" + +"@types/jest@^22.2.3": + version "22.2.3" + resolved "https://registry.npm.taobao.org/@types/jest/download/@types/jest-22.2.3.tgz?cache=0&sync_timestamp=1594068215981&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjest%2Fdownload%2F%40types%2Fjest-22.2.3.tgz#0157c0316dc3722c43a7b71de3fdf3acbccef10d" + +"@types/json-schema@*": + version "7.0.5" + resolved "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" + +"@types/lodash@^4.14.105": + version "4.14.157" + resolved "https://registry.npm.taobao.org/@types/lodash/download/@types/lodash-4.14.157.tgz?cache=0&sync_timestamp=1592998007083&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Flodash%2Fdownload%2F%40types%2Flodash-4.14.157.tgz#fdac1c52448861dfde1a2e1515dbc46e54926dc8" + +"@types/node@^9.6.2": + version "9.6.56" + resolved "https://registry.npm.taobao.org/@types/node/download/@types/node-9.6.56.tgz?cache=0&sync_timestamp=1594397594455&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-9.6.56.tgz#036f665320d2f04bd62c0cd83222254a6a3b4437" + +abab@^2.0.0: + version "2.0.3" + resolved "https://registry.npm.taobao.org/abab/download/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" + +acorn-globals@^4.1.0: + version "4.3.4" + resolved "https://registry.npm.taobao.org/acorn-globals/download/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" + dependencies: + acorn "^6.0.1" + acorn-walk "^6.0.1" + +acorn-jsx@^5.0.0: + version "5.2.0" + resolved "https://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-5.2.0.tgz?cache=0&sync_timestamp=1589684116279&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-jsx%2Fdownload%2Facorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" + +acorn-walk@^6.0.1: + version "6.2.0" + resolved "https://registry.npm.taobao.org/acorn-walk/download/acorn-walk-6.2.0.tgz?cache=0&sync_timestamp=1592373614214&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-walk%2Fdownload%2Facorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" + +acorn@^5.5.3: + version "5.7.4" + resolved "https://registry.npm.taobao.org/acorn/download/acorn-5.7.4.tgz?cache=0&sync_timestamp=1591869398104&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" + +acorn@^6.0.1, acorn@^6.0.7: + version "6.4.1" + resolved "https://registry.npm.taobao.org/acorn/download/acorn-6.4.1.tgz?cache=0&sync_timestamp=1591869398104&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + +ajv@^6.10.2, ajv@^6.5.5, ajv@^6.9.1: + version "6.12.3" + resolved "https://registry.npm.taobao.org/ajv/download/ajv-6.12.3.tgz?cache=0&sync_timestamp=1593876933357&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706" + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.npm.taobao.org/ansi-escapes/download/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-2.2.1.tgz?cache=0&sync_timestamp=1589682811931&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&sync_timestamp=1589682811931&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.npm.taobao.org/anymatch/download/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/anymatch/download/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.npm.taobao.org/append-transform/download/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + dependencies: + default-require-extensions "^1.0.0" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/arr-diff/download/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/arr-diff/download/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/arr-flatten/download/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/arr-union/download/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/array-equal/download/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + +array-includes@^3.1.1: + version "3.1.1" + resolved "https://registry.npm.taobao.org/array-includes/download/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0" + is-string "^1.0.5" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.npm.taobao.org/array-unique/download/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/arrify/download/arrify-1.0.1.tgz?cache=0&sync_timestamp=1589684737833&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farrify%2Fdownload%2Farrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/assign-symbols/download/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/astral-regex/download/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + +async-each@^1.0.0: + version "1.0.3" + resolved "https://registry.npm.taobao.org/async-each/download/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + +async@^2.1.4: + version "2.6.3" + resolved "https://registry.npm.taobao.org/async/download/async-2.6.3.tgz?cache=0&sync_timestamp=1589682717913&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fasync%2Fdownload%2Fasync-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.npm.taobao.org/atob/download/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz?cache=0&sync_timestamp=1589682812085&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws-sign2%2Fdownload%2Faws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.8.0: + version "1.10.0" + resolved "https://registry.npm.taobao.org/aws4/download/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" + +babel-code-frame@^6.26.0, babel-code-frame@^6.8.0: + version "6.26.0" + resolved "https://registry.npm.taobao.org/babel-code-frame/download/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@6.10.4: + version "6.10.4" + resolved "https://registry.npm.taobao.org/babel-core/download/babel-core-6.10.4.tgz#283f2212bb03d4e5cd7498b9886efbf6fc2e238e" + dependencies: + babel-code-frame "^6.8.0" + babel-generator "^6.9.0" + babel-helpers "^6.8.0" + babel-messages "^6.8.0" + babel-register "^6.9.0" + babel-runtime "^6.9.1" + babel-template "^6.9.0" + babel-traverse "^6.10.4" + babel-types "^6.9.1" + babylon "^6.7.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.4.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-exists "^1.0.0" + path-is-absolute "^1.0.0" + private "^0.1.6" + shebang-regex "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + +babel-core@6.26.3, babel-core@^6.0.0, babel-core@^6.26.0, babel-core@^6.26.3: + version "6.26.3" + resolved "https://registry.npm.taobao.org/babel-core/download/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-eslint@^8.2.3: + version "8.2.6" + resolved "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-8.2.6.tgz#6270d0c73205628067c0f7ae1693a9e797acefd9" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + eslint-scope "3.7.1" + eslint-visitor-keys "^1.0.0" + +babel-generator@^6.18.0, babel-generator@^6.26.0, babel-generator@^6.9.0: + version "6.26.1" + resolved "https://registry.npm.taobao.org/babel-generator/download/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-evaluate-path@^0.5.0: + version "0.5.0" + resolved "https://registry.npm.taobao.org/babel-helper-evaluate-path/download/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.npm.taobao.org/babel-helper-function-name/download/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.npm.taobao.org/babel-helper-get-function-arity/download/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-mark-eval-scopes@^0.4.3: + version "0.4.3" + resolved "https://registry.npm.taobao.org/babel-helper-mark-eval-scopes/download/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562" + +babel-helper-remove-or-void@^0.4.3: + version "0.4.3" + resolved "https://registry.npm.taobao.org/babel-helper-remove-or-void/download/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60" + +babel-helpers@^6.24.1, babel-helpers@^6.8.0: + version "6.24.1" + resolved "https://registry.npm.taobao.org/babel-helpers/download/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-jest@^22.4.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/babel-jest/download/babel-jest-22.4.4.tgz?cache=0&sync_timestamp=1592925358068&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-jest%2Fdownload%2Fbabel-jest-22.4.4.tgz#977259240420e227444ebe49e226a61e49ea659d" + dependencies: + babel-plugin-istanbul "^4.1.5" + babel-preset-jest "^22.4.4" + +babel-jest@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/babel-jest/download/babel-jest-23.6.0.tgz?cache=0&sync_timestamp=1592925358068&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-jest%2Fdownload%2Fbabel-jest-23.6.0.tgz#a644232366557a2240a0c083da6b25786185a2f1" + dependencies: + babel-plugin-istanbul "^4.1.6" + babel-preset-jest "^23.2.0" + +babel-macros@^1.1.1: + version "1.2.0" + resolved "https://registry.npm.taobao.org/babel-macros/download/babel-macros-1.2.0.tgz#39e47ed6d286d4a98f1948d8bab45dac17e4e2d4" + dependencies: + cosmiconfig "3.1.0" + +babel-messages@^6.23.0, babel-messages@^6.8.0: + version "6.23.0" + resolved "https://registry.npm.taobao.org/babel-messages/download/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-danger-remove-unused-import@^1.1.1: + version "1.1.2" + resolved "https://registry.npm.taobao.org/babel-plugin-danger-remove-unused-import/download/babel-plugin-danger-remove-unused-import-1.1.2.tgz#ac39c30edfe524ef8cfc411fec5edc479d19e132" + +babel-plugin-istanbul@^4.1.5, babel-plugin-istanbul@^4.1.6: + version "4.1.6" + resolved "https://registry.npm.taobao.org/babel-plugin-istanbul/download/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.13.0" + find-up "^2.1.0" + istanbul-lib-instrument "^1.10.1" + test-exclude "^4.2.1" + +babel-plugin-jest-hoist@^22.4.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/babel-plugin-jest-hoist/download/babel-plugin-jest-hoist-22.4.4.tgz?cache=0&sync_timestamp=1592925433898&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-plugin-jest-hoist%2Fdownload%2Fbabel-plugin-jest-hoist-22.4.4.tgz#b9851906eab34c7bf6f8c895a2b08bea1a844c0b" + +babel-plugin-jest-hoist@^23.2.0: + version "23.2.0" + resolved "https://registry.npm.taobao.org/babel-plugin-jest-hoist/download/babel-plugin-jest-hoist-23.2.0.tgz?cache=0&sync_timestamp=1592925433898&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-plugin-jest-hoist%2Fdownload%2Fbabel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" + +babel-plugin-minify-dead-code@^1.3.2: + version "1.3.2" + resolved "https://registry.npm.taobao.org/babel-plugin-minify-dead-code/download/babel-plugin-minify-dead-code-1.3.2.tgz#7cd45c95c52700f00680a37377e00accad45b188" + dependencies: + babel-core "6.10.4" + +babel-plugin-preval@1.6.2: + version "1.6.2" + resolved "https://registry.npm.taobao.org/babel-plugin-preval/download/babel-plugin-preval-1.6.2.tgz#8f580a1d4579d5fc79f1cfaee6f9fe0996fdeb1f" + dependencies: + babel-macros "^1.1.1" + babel-register "^6.26.0" + babylon "^6.18.0" + require-from-string "^2.0.1" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.npm.taobao.org/babel-plugin-syntax-class-properties/download/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-do-expressions@^6.8.0: + version "6.13.0" + resolved "https://registry.npm.taobao.org/babel-plugin-syntax-do-expressions/download/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.npm.taobao.org/babel-plugin-syntax-dynamic-import/download/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.npm.taobao.org/babel-plugin-syntax-export-extensions/download/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.npm.taobao.org/babel-plugin-syntax-flow/download/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-object-rest-spread@^6.13.0: + version "6.13.0" + resolved "https://registry.npm.taobao.org/babel-plugin-syntax-object-rest-spread/download/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.npm.taobao.org/babel-plugin-transform-class-properties/download/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-define@^1.3.0: + version "1.3.2" + resolved "https://registry.npm.taobao.org/babel-plugin-transform-define/download/babel-plugin-transform-define-1.3.2.tgz#4bdbfe35a839fc206e0f60a7a9ae3b82d5e11808" + dependencies: + lodash "^4.17.11" + traverse "0.6.6" + +babel-plugin-transform-do-expressions@^6.22.0: + version "6.22.0" + resolved "https://registry.npm.taobao.org/babel-plugin-transform-do-expressions/download/babel-plugin-transform-do-expressions-6.22.0.tgz?cache=0&sync_timestamp=1589963707825&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-plugin-transform-do-expressions%2Fdownload%2Fbabel-plugin-transform-do-expressions-6.22.0.tgz#28ccaf92812d949c2cd1281f690c8fdc468ae9bb" + dependencies: + babel-plugin-syntax-do-expressions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.26.2: + version "6.26.2" + resolved "https://registry.npm.taobao.org/babel-plugin-transform-es2015-modules-commonjs/download/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.npm.taobao.org/babel-plugin-transform-es2015-template-literals/download/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-export-extensions@^6.22.0: + version "6.22.0" + resolved "https://registry.npm.taobao.org/babel-plugin-transform-export-extensions/download/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-flow-strip-types@^6.22.0: + version "6.22.0" + resolved "https://registry.npm.taobao.org/babel-plugin-transform-flow-strip-types/download/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.npm.taobao.org/babel-plugin-transform-strict-mode/download/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-jest@^22.4.3, babel-preset-jest@^22.4.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/babel-preset-jest/download/babel-preset-jest-22.4.4.tgz?cache=0&sync_timestamp=1592925429126&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-preset-jest%2Fdownload%2Fbabel-preset-jest-22.4.4.tgz#ec9fbd8bcd7dfd24b8b5320e0e688013235b7c39" + dependencies: + babel-plugin-jest-hoist "^22.4.4" + babel-plugin-syntax-object-rest-spread "^6.13.0" + +babel-preset-jest@^23.2.0: + version "23.2.0" + resolved "https://registry.npm.taobao.org/babel-preset-jest/download/babel-preset-jest-23.2.0.tgz?cache=0&sync_timestamp=1592925429126&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-preset-jest%2Fdownload%2Fbabel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46" + dependencies: + babel-plugin-jest-hoist "^23.2.0" + babel-plugin-syntax-object-rest-spread "^6.13.0" + +babel-register@^6.26.0, babel-register@^6.9.0: + version "6.26.0" + resolved "https://registry.npm.taobao.org/babel-register/download/babel-register-6.26.0.tgz?cache=0&sync_timestamp=1589683619427&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-register%2Fdownload%2Fbabel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2: + version "6.26.0" + resolved "https://registry.npm.taobao.org/babel-runtime/download/babel-runtime-6.26.0.tgz?cache=0&sync_timestamp=1589682807065&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-runtime%2Fdownload%2Fbabel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.9.0: + version "6.26.0" + resolved "https://registry.npm.taobao.org/babel-template/download/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@6.26.0, babel-traverse@^6.0.0, babel-traverse@^6.10.4, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.npm.taobao.org/babel-traverse/download/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@6.26.0, babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.24.1, babel-types@^6.26.0, babel-types@^6.9.1: + version "6.26.0" + resolved "https://registry.npm.taobao.org/babel-types/download/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.npm.taobao.org/babylon/download/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + +babylon@^6.18.0, babylon@^6.7.0: + version "6.18.0" + resolved "https://registry.npm.taobao.org/babylon/download/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.npm.taobao.org/base/download/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz?cache=0&sync_timestamp=1589682746075&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbcrypt-pbkdf%2Fdownload%2Fbcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-1.13.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbinary-extensions%2Fdownload%2Fbinary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.npm.taobao.org/bindings/download/bindings-1.5.0.tgz?cache=0&sync_timestamp=1589682780212&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbindings%2Fdownload%2Fbindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + dependencies: + file-uri-to-path "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.npm.taobao.org/braces/download/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.npm.taobao.org/braces/download/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/browser-process-hrtime/download/browser-process-hrtime-1.0.0.tgz?cache=0&sync_timestamp=1589683598073&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrowser-process-hrtime%2Fdownload%2Fbrowser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + +browser-resolve@^1.11.2, browser-resolve@^1.11.3: + version "1.11.3" + resolved "https://registry.npm.taobao.org/browser-resolve/download/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + dependencies: + resolve "1.1.7" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/bser/download/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + +builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.npm.taobao.org/builtin-modules/download/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/cache-base/download/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/callsites/download/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/callsites/download/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-4.1.0.tgz?cache=0&sync_timestamp=1589682790492&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +capture-exit@^1.2.0: + version "1.2.0" + resolved "https://registry.npm.taobao.org/capture-exit/download/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + dependencies: + rsvp "^3.3.3" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.npm.taobao.org/chardet/download/chardet-0.7.0.tgz?cache=0&sync_timestamp=1594010664806&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchardet%2Fdownload%2Fchardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + +chokidar@^1.6.0: + version "1.7.0" + resolved "https://registry.npm.taobao.org/chokidar/download/chokidar-1.7.0.tgz?cache=0&sync_timestamp=1589682823083&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchokidar%2Fdownload%2Fchokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +ci-info@^1.5.0: + version "1.6.0" + resolved "https://registry.npm.taobao.org/ci-info/download/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.npm.taobao.org/cli-width/download/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/cliui/download/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz?cache=0&sync_timestamp=1589683669101&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fco%2Fdownload%2Fco-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.12.1: + version "2.20.3" + resolved "https://registry.npm.taobao.org/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1592632082677&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.7: + version "1.6.2" + resolved "https://registry.npm.taobao.org/concat-stream/download/concat-stream-1.6.2.tgz?cache=0&sync_timestamp=1589682751334&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fconcat-stream%2Fdownload%2Fconcat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.1: + version "1.7.0" + resolved "https://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.7.0.tgz?cache=0&sync_timestamp=1589682764242&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fconvert-source-map%2Fdownload%2Fconvert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + dependencies: + safe-buffer "~5.1.1" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.6.11" + resolved "https://registry.npm.taobao.org/core-js/download/core-js-2.6.11.tgz?cache=0&sync_timestamp=1589682726446&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cosmiconfig@3.1.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/cosmiconfig/download/cosmiconfig-3.1.0.tgz?cache=0&sync_timestamp=1589682806671&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcosmiconfig%2Fdownload%2Fcosmiconfig-3.1.0.tgz#640a94bf9847f321800403cd273af60665c73397" + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^3.0.0" + require-from-string "^2.0.1" + +cpx@^1.5.0: + version "1.5.0" + resolved "https://registry.npm.taobao.org/cpx/download/cpx-1.5.0.tgz#185be018511d87270dedccc293171e37655ab88f" + dependencies: + babel-runtime "^6.9.2" + chokidar "^1.6.0" + duplexer "^0.1.1" + glob "^7.0.5" + glob2base "^0.0.12" + minimatch "^3.0.2" + mkdirp "^0.5.1" + resolve "^1.1.7" + safe-buffer "^5.0.1" + shell-quote "^1.6.1" + subarg "^1.0.0" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.8" + resolved "https://registry.npm.taobao.org/cssom/download/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + +cssstyle@^1.0.0: + version "1.4.0" + resolved "https://registry.npm.taobao.org/cssstyle/download/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" + dependencies: + cssom "0.3.x" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz?cache=0&sync_timestamp=1589682745367&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdashdash%2Fdownload%2Fdashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +data-urls@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/data-urls/download/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + dependencies: + abab "^2.0.0" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + +debug@^2.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + dependencies: + ms "^2.1.1" + +debug@^4.0.1: + version "4.1.1" + resolved "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz?cache=0&sync_timestamp=1589891993007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.npm.taobao.org/decode-uri-component/download/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/default-require-extensions/download/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + dependencies: + strip-bom "^2.0.0" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.npm.taobao.org/define-property/download/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/detect-indent/download/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/detect-newline/download/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + +diff@^3.2.0: + version "3.5.0" + resolved "https://registry.npm.taobao.org/diff/download/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npm.taobao.org/diff/download/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + +doctrine@0.7.2: + version "0.7.2" + resolved "https://registry.npm.taobao.org/doctrine/download/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" + dependencies: + esutils "^1.1.6" + isarray "0.0.1" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/doctrine/download/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/doctrine/download/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + dependencies: + esutils "^2.0.2" + +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/domexception/download/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + dependencies: + webidl-conversions "^4.0.2" + +duplexer@^0.1.1: + version "0.1.1" + resolved "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz?cache=0&sync_timestamp=1589682745945&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fecc-jsbn%2Fdownload%2Fecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.npm.taobao.org/end-of-stream/download/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + dependencies: + once "^1.4.0" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npm.taobao.org/error-ex/download/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5: + version "1.17.6" + resolved "https://registry.npm.taobao.org/es-abstract/download/es-abstract-1.17.6.tgz?cache=0&sync_timestamp=1592109007044&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fes-abstract%2Fdownload%2Fes-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.0" + is-regex "^1.1.0" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escodegen@^1.9.1: + version "1.14.3" + resolved "https://registry.npm.taobao.org/escodegen/download/escodegen-1.14.3.tgz?cache=0&sync_timestamp=1592866129129&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescodegen%2Fdownload%2Fescodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-plugin-react@7.10.0: + version "7.10.0" + resolved "https://registry.npm.taobao.org/eslint-plugin-react/download/eslint-plugin-react-7.10.0.tgz#af5c1fef31c4704db02098f9be18202993828b50" + dependencies: + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.2" + +eslint-scope@3.7.1: + version "3.7.1" + resolved "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-3.7.1.tgz?cache=0&sync_timestamp=1591269986906&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-4.0.3.tgz?cache=0&sync_timestamp=1591269986906&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-scope%2Fdownload%2Feslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.1: + version "1.4.3" + resolved "https://registry.npm.taobao.org/eslint-utils/download/eslint-utils-1.4.3.tgz?cache=0&sync_timestamp=1592222145079&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-utils%2Fdownload%2Feslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.npm.taobao.org/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz?cache=0&sync_timestamp=1592583313176&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + +eslint@5.16.0: + version "5.16.0" + resolved "https://registry.npm.taobao.org/eslint/download/eslint-5.16.0.tgz?cache=0&sync_timestamp=1593807592600&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint%2Fdownload%2Feslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.3" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.2.2" + js-yaml "^3.13.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.11" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" + +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.npm.taobao.org/espree/download/espree-5.0.1.tgz?cache=0&sync_timestamp=1591269387241&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fespree%2Fdownload%2Fespree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + dependencies: + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz?cache=0&sync_timestamp=1589682833047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fesprima%2Fdownload%2Fesprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + +esquery@^1.0.1: + version "1.3.1" + resolved "https://registry.npm.taobao.org/esquery/download/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.npm.taobao.org/esrecurse/download/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + dependencies: + estraverse "^4.1.0" + +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.3.0" + resolved "https://registry.npm.taobao.org/estraverse/download/estraverse-4.3.0.tgz?cache=0&sync_timestamp=1589682722601&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + +estraverse@^5.1.0: + version "5.1.0" + resolved "https://registry.npm.taobao.org/estraverse/download/estraverse-5.1.0.tgz?cache=0&sync_timestamp=1589682722601&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" + +esutils@^1.1.6: + version "1.1.6" + resolved "https://registry.npm.taobao.org/esutils/download/esutils-1.1.6.tgz?cache=0&sync_timestamp=1589682816934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fesutils%2Fdownload%2Fesutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375" + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npm.taobao.org/esutils/download/esutils-2.0.3.tgz?cache=0&sync_timestamp=1589682816934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fesutils%2Fdownload%2Fesutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + +exec-sh@^0.2.0: + version "0.2.2" + resolved "https://registry.npm.taobao.org/exec-sh/download/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + dependencies: + merge "^1.2.0" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.npm.taobao.org/execa/download/execa-0.7.0.tgz?cache=0&sync_timestamp=1594145085955&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexeca%2Fdownload%2Fexeca-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/execa/download/execa-1.0.0.tgz?cache=0&sync_timestamp=1594145085955&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexeca%2Fdownload%2Fexeca-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npm.taobao.org/exit/download/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.npm.taobao.org/expand-range/download/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expect@^22.4.0: + version "22.4.3" + resolved "https://registry.npm.taobao.org/expect/download/expect-22.4.3.tgz?cache=0&sync_timestamp=1592925438156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexpect%2Fdownload%2Fexpect-22.4.3.tgz#d5a29d0a0e1fb2153557caef2674d4547e914674" + dependencies: + ansi-styles "^3.2.0" + jest-diff "^22.4.3" + jest-get-type "^22.4.3" + jest-matcher-utils "^22.4.3" + jest-message-util "^22.4.3" + jest-regex-util "^22.4.3" + +expect@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/expect/download/expect-23.6.0.tgz?cache=0&sync_timestamp=1592925438156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexpect%2Fdownload%2Fexpect-23.6.0.tgz#1e0c8d3ba9a581c87bd71fb9bc8862d443425f98" + dependencies: + ansi-styles "^3.2.0" + jest-diff "^23.6.0" + jest-get-type "^22.1.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz?cache=0&sync_timestamp=1589682707348&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fextend%2Fdownload%2Fextend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.npm.taobao.org/external-editor/download/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.npm.taobao.org/extglob/download/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.npm.taobao.org/extglob/download/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.npm.taobao.org/fb-watchman/download/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + dependencies: + bser "2.1.1" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/figures/download/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.npm.taobao.org/file-entry-cache/download/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + dependencies: + flat-cache "^2.0.1" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.npm.taobao.org/filename-regex/download/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.npm.taobao.org/fileset/download/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.npm.taobao.org/fill-range/download/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/fill-range/download/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +find-index@^0.1.1: + version "0.1.1" + resolved "https://registry.npm.taobao.org/find-index/download/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.npm.taobao.org/find-up/download/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/find-up/download/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/flat-cache/download/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.npm.taobao.org/flatted/download/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.npm.taobao.org/for-own/download/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.npm.taobao.org/fragment-cache/download/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fs-extra@6.0.0: + version "6.0.0" + resolved "https://registry.npm.taobao.org/fs-extra/download/fs-extra-6.0.0.tgz?cache=0&sync_timestamp=1591229972229&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffs-extra%2Fdownload%2Ffs-extra-6.0.0.tgz#0f0afb290bb3deb87978da816fcd3c7797f3a817" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0, fsevents@^1.2.3: + version "1.2.13" + resolved "https://registry.npm.taobao.org/fsevents/download/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/get-stream/download/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/get-stream/download/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.npm.taobao.org/get-value/download/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz?cache=0&sync_timestamp=1589682745510&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgetpass%2Fdownload%2Fgetpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.npm.taobao.org/glob-base/download/glob-base-0.3.0.tgz?cache=0&sync_timestamp=1589720788114&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob-base%2Fdownload%2Fglob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/glob-parent/download/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob2base@^0.0.12: + version "0.0.12" + resolved "https://registry.npm.taobao.org/glob2base/download/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" + dependencies: + find-index "^0.1.1" + +glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: + version "7.1.6" + resolved "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz?cache=0&sync_timestamp=1589682812051&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob%2Fdownload%2Fglob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0, globals@^11.7.0: + version "11.12.0" + resolved "https://registry.npm.taobao.org/globals/download/globals-11.12.0.tgz?cache=0&sync_timestamp=1591426414289&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobals%2Fdownload%2Fglobals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.npm.taobao.org/globals/download/globals-9.18.0.tgz?cache=0&sync_timestamp=1591426414289&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobals%2Fdownload%2Fglobals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.2.4" + resolved "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz?cache=0&sync_timestamp=1589682809142&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgraceful-fs%2Fdownload%2Fgraceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.npm.taobao.org/growly/download/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + +handlebars@^4.0.3: + version "4.7.6" + resolved "https://registry.npm.taobao.org/handlebars/download/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz?cache=0&sync_timestamp=1589682732850&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhar-schema%2Fdownload%2Fhar-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~5.1.3: + version "5.1.3" + resolved "https://registry.npm.taobao.org/har-validator/download/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/has-ansi/download/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/has-flag/download/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.npm.taobao.org/has-value/download/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/has-value/download/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.npm.taobao.org/has-values/download/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/has-values/download/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/home-or-tmp/download/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.8.8" + resolved "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-2.8.8.tgz?cache=0&sync_timestamp=1594427993800&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhosted-git-info%2Fdownload%2Fhosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/html-encoding-sniffer/download/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + dependencies: + whatwg-encoding "^1.0.1" + +html@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/html/download/html-1.0.0.tgz#a544fa9ea5492bfb3a2cca8210a10be7b5af1f61" + dependencies: + concat-stream "^1.4.7" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz?cache=0&sync_timestamp=1589682811784&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-signature%2Fdownload%2Fhttp-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&sync_timestamp=1594184264130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + +import-fresh@^3.0.0: + version "3.2.1" + resolved "https://registry.npm.taobao.org/import-fresh/download/import-fresh-3.2.1.tgz?cache=0&sync_timestamp=1589682760620&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/import-local/download/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz?cache=0&sync_timestamp=1589682822213&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finherits%2Fdownload%2Finherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + +inquirer@^6.2.2: + version "6.5.2" + resolved "https://registry.npm.taobao.org/inquirer/download/inquirer-6.5.2.tgz?cache=0&sync_timestamp=1594394152454&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finquirer%2Fdownload%2Finquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +invariant@^2.2.0, invariant@^2.2.2, invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.npm.taobao.org/invariant/download/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/invert-kv/download/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/invert-kv/download/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-callable@^1.1.4, is-callable@^1.2.0: + version "1.2.0" + resolved "https://registry.npm.taobao.org/is-callable/download/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" + +is-ci@^1.0.10: + version "1.2.1" + resolved "https://registry.npm.taobao.org/is-ci/download/is-ci-1.2.1.tgz?cache=0&sync_timestamp=1589682764432&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-ci%2Fdownload%2Fis-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" + dependencies: + ci-info "^1.5.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.npm.taobao.org/is-date-object/download/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.npm.taobao.org/is-directory/download/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.npm.taobao.org/is-dotfile/download/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.npm.taobao.org/is-equal-shallow/download/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/is-extglob/download/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/is-finite/download/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-generator-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/is-generator-fn/download/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/is-glob/download/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/is-number/download/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/is-number/download/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.npm.taobao.org/is-plain-object/download/is-plain-object-2.0.4.tgz?cache=0&sync_timestamp=1593243702704&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-plain-object%2Fdownload%2Fis-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.npm.taobao.org/is-posix-bracket/download/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/is-primitive/download/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/is-regex/download/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" + dependencies: + has-symbols "^1.0.1" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.npm.taobao.org/is-string/download/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.npm.taobao.org/is-symbol/download/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + dependencies: + has-symbols "^1.0.1" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.npm.taobao.org/is-utf8/download/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/is-windows/download/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz?cache=0&sync_timestamp=1589682812472&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fisexe%2Fdownload%2Fisexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npm.taobao.org/isobject/download/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz?cache=0&sync_timestamp=1589682770538&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fisstream%2Fdownload%2Fisstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istanbul-api@^1.1.14, istanbul-api@^1.3.1: + version "1.3.7" + resolved "https://registry.npm.taobao.org/istanbul-api/download/istanbul-api-1.3.7.tgz#a86c770d2b03e11e3f778cd7aedd82d2722092aa" + dependencies: + async "^2.1.4" + fileset "^2.0.2" + istanbul-lib-coverage "^1.2.1" + istanbul-lib-hook "^1.2.2" + istanbul-lib-instrument "^1.10.2" + istanbul-lib-report "^1.1.5" + istanbul-lib-source-maps "^1.2.6" + istanbul-reports "^1.5.1" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + +istanbul-lib-coverage@^1.1.1, istanbul-lib-coverage@^1.2.0, istanbul-lib-coverage@^1.2.1: + version "1.2.1" + resolved "https://registry.npm.taobao.org/istanbul-lib-coverage/download/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" + +istanbul-lib-hook@^1.2.2: + version "1.2.2" + resolved "https://registry.npm.taobao.org/istanbul-lib-hook/download/istanbul-lib-hook-1.2.2.tgz#bc6bf07f12a641fbf1c85391d0daa8f0aea6bf86" + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.10.2, istanbul-lib-instrument@^1.8.0: + version "1.10.2" + resolved "https://registry.npm.taobao.org/istanbul-lib-instrument/download/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.2.1" + semver "^5.3.0" + +istanbul-lib-report@^1.1.5: + version "1.1.5" + resolved "https://registry.npm.taobao.org/istanbul-lib-report/download/istanbul-lib-report-1.1.5.tgz#f2a657fc6282f96170aaf281eb30a458f7f4170c" + dependencies: + istanbul-lib-coverage "^1.2.1" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.2.1, istanbul-lib-source-maps@^1.2.4, istanbul-lib-source-maps@^1.2.6: + version "1.2.6" + resolved "https://registry.npm.taobao.org/istanbul-lib-source-maps/download/istanbul-lib-source-maps-1.2.6.tgz#37b9ff661580f8fca11232752ee42e08c6675d8f" + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^1.2.1" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + +istanbul-reports@^1.5.1: + version "1.5.1" + resolved "https://registry.npm.taobao.org/istanbul-reports/download/istanbul-reports-1.5.1.tgz#97e4dbf3b515e8c484caea15d6524eebd3ff4e1a" + dependencies: + handlebars "^4.0.3" + +jest-changed-files@^22.2.0: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-changed-files/download/jest-changed-files-22.4.3.tgz?cache=0&sync_timestamp=1592925426671&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-changed-files%2Fdownload%2Fjest-changed-files-22.4.3.tgz#8882181e022c38bd46a2e4d18d44d19d90a90fb2" + dependencies: + throat "^4.0.0" + +jest-changed-files@^23.4.2: + version "23.4.2" + resolved "https://registry.npm.taobao.org/jest-changed-files/download/jest-changed-files-23.4.2.tgz?cache=0&sync_timestamp=1592925426671&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-changed-files%2Fdownload%2Fjest-changed-files-23.4.2.tgz#1eed688370cd5eebafe4ae93d34bb3b64968fe83" + dependencies: + throat "^4.0.0" + +jest-cli@^22.1.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/jest-cli/download/jest-cli-22.4.4.tgz?cache=0&sync_timestamp=1592925430808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-cli%2Fdownload%2Fjest-cli-22.4.4.tgz#68cd2a2aae983adb1e6638248ca21082fd6d9e90" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.11" + import-local "^1.0.0" + is-ci "^1.0.10" + istanbul-api "^1.1.14" + istanbul-lib-coverage "^1.1.1" + istanbul-lib-instrument "^1.8.0" + istanbul-lib-source-maps "^1.2.1" + jest-changed-files "^22.2.0" + jest-config "^22.4.4" + jest-environment-jsdom "^22.4.1" + jest-get-type "^22.1.0" + jest-haste-map "^22.4.2" + jest-message-util "^22.4.0" + jest-regex-util "^22.1.0" + jest-resolve-dependencies "^22.1.0" + jest-runner "^22.4.4" + jest-runtime "^22.4.4" + jest-snapshot "^22.4.0" + jest-util "^22.4.1" + jest-validate "^22.4.4" + jest-worker "^22.2.2" + micromatch "^2.3.11" + node-notifier "^5.2.1" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + yargs "^10.0.3" + +jest-cli@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-cli/download/jest-cli-23.6.0.tgz?cache=0&sync_timestamp=1592925430808&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-cli%2Fdownload%2Fjest-cli-23.6.0.tgz#61ab917744338f443ef2baa282ddffdd658a5da4" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.11" + import-local "^1.0.0" + is-ci "^1.0.10" + istanbul-api "^1.3.1" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-source-maps "^1.2.4" + jest-changed-files "^23.4.2" + jest-config "^23.6.0" + jest-environment-jsdom "^23.4.0" + jest-get-type "^22.1.0" + jest-haste-map "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve-dependencies "^23.6.0" + jest-runner "^23.6.0" + jest-runtime "^23.6.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + jest-watcher "^23.4.0" + jest-worker "^23.2.0" + micromatch "^2.3.11" + node-notifier "^5.2.1" + prompts "^0.1.9" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + yargs "^11.0.0" + +jest-config@^22.4.3, jest-config@^22.4.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/jest-config/download/jest-config-22.4.4.tgz#72a521188720597169cd8b4ff86934ef5752d86a" + dependencies: + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^22.4.1" + jest-environment-node "^22.4.1" + jest-get-type "^22.1.0" + jest-jasmine2 "^22.4.4" + jest-regex-util "^22.1.0" + jest-resolve "^22.4.2" + jest-util "^22.4.1" + jest-validate "^22.4.4" + pretty-format "^22.4.0" + +jest-config@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-config/download/jest-config-23.6.0.tgz#f82546a90ade2d8c7026fbf6ac5207fc22f8eb1d" + dependencies: + babel-core "^6.0.0" + babel-jest "^23.6.0" + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^23.4.0" + jest-environment-node "^23.4.0" + jest-get-type "^22.1.0" + jest-jasmine2 "^23.6.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + micromatch "^2.3.11" + pretty-format "^23.6.0" + +jest-diff@^22.4.0, jest-diff@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-diff/download/jest-diff-22.4.3.tgz#e18cc3feff0aeef159d02310f2686d4065378030" + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.4.3" + pretty-format "^22.4.3" + +jest-diff@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-diff/download/jest-diff-23.6.0.tgz#1500f3f16e850bb3d71233408089be099f610c7d" + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.1.0" + pretty-format "^23.6.0" + +jest-docblock@^22.4.0, jest-docblock@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-docblock/download/jest-docblock-22.4.3.tgz#50886f132b42b280c903c592373bb6e93bb68b19" + dependencies: + detect-newline "^2.1.0" + +jest-docblock@^23.2.0: + version "23.2.0" + resolved "https://registry.npm.taobao.org/jest-docblock/download/jest-docblock-23.2.0.tgz#f085e1f18548d99fdd69b20207e6fd55d91383a7" + dependencies: + detect-newline "^2.1.0" + +jest-each@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-each/download/jest-each-23.6.0.tgz?cache=0&sync_timestamp=1592925338581&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-each%2Fdownload%2Fjest-each-23.6.0.tgz#ba0c3a82a8054387016139c733a05242d3d71575" + dependencies: + chalk "^2.0.1" + pretty-format "^23.6.0" + +jest-environment-jsdom@^22.4.1: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-environment-jsdom/download/jest-environment-jsdom-22.4.3.tgz?cache=0&sync_timestamp=1592925351546&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-environment-jsdom%2Fdownload%2Fjest-environment-jsdom-22.4.3.tgz#d67daa4155e33516aecdd35afd82d4abf0fa8a1e" + dependencies: + jest-mock "^22.4.3" + jest-util "^22.4.3" + jsdom "^11.5.1" + +jest-environment-jsdom@^23.4.0: + version "23.4.0" + resolved "https://registry.npm.taobao.org/jest-environment-jsdom/download/jest-environment-jsdom-23.4.0.tgz?cache=0&sync_timestamp=1592925351546&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-environment-jsdom%2Fdownload%2Fjest-environment-jsdom-23.4.0.tgz#056a7952b3fea513ac62a140a2c368c79d9e6023" + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + jsdom "^11.5.1" + +jest-environment-node@^22.4.1: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-environment-node/download/jest-environment-node-22.4.3.tgz?cache=0&sync_timestamp=1592925435622&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-environment-node%2Fdownload%2Fjest-environment-node-22.4.3.tgz#54c4eaa374c83dd52a9da8759be14ebe1d0b9129" + dependencies: + jest-mock "^22.4.3" + jest-util "^22.4.3" + +jest-environment-node@^23.4.0: + version "23.4.0" + resolved "https://registry.npm.taobao.org/jest-environment-node/download/jest-environment-node-23.4.0.tgz?cache=0&sync_timestamp=1592925435622&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-environment-node%2Fdownload%2Fjest-environment-node-23.4.0.tgz#57e80ed0841dea303167cce8cd79521debafde10" + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + +jest-get-type@^22.1.0, jest-get-type@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-get-type/download/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" + +jest-haste-map@^22.4.2: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-haste-map/download/jest-haste-map-22.4.3.tgz?cache=0&sync_timestamp=1592925431293&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-haste-map%2Fdownload%2Fjest-haste-map-22.4.3.tgz#25842fa2ba350200767ac27f658d58b9d5c2e20b" + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + jest-docblock "^22.4.3" + jest-serializer "^22.4.3" + jest-worker "^22.4.3" + micromatch "^2.3.11" + sane "^2.0.0" + +jest-haste-map@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-haste-map/download/jest-haste-map-23.6.0.tgz?cache=0&sync_timestamp=1592925431293&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-haste-map%2Fdownload%2Fjest-haste-map-23.6.0.tgz#2e3eb997814ca696d62afdb3f2529f5bbc935e16" + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + invariant "^2.2.4" + jest-docblock "^23.2.0" + jest-serializer "^23.0.1" + jest-worker "^23.2.0" + micromatch "^2.3.11" + sane "^2.0.0" + +jest-jasmine2@^22.4.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/jest-jasmine2/download/jest-jasmine2-22.4.4.tgz#c55f92c961a141f693f869f5f081a79a10d24e23" + dependencies: + chalk "^2.0.1" + co "^4.6.0" + expect "^22.4.0" + graceful-fs "^4.1.11" + is-generator-fn "^1.0.0" + jest-diff "^22.4.0" + jest-matcher-utils "^22.4.0" + jest-message-util "^22.4.0" + jest-snapshot "^22.4.0" + jest-util "^22.4.1" + source-map-support "^0.5.0" + +jest-jasmine2@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-jasmine2/download/jest-jasmine2-23.6.0.tgz#840e937f848a6c8638df24360ab869cc718592e0" + dependencies: + babel-traverse "^6.0.0" + chalk "^2.0.1" + co "^4.6.0" + expect "^23.6.0" + is-generator-fn "^1.0.0" + jest-diff "^23.6.0" + jest-each "^23.6.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + pretty-format "^23.6.0" + +jest-leak-detector@^22.4.0: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-leak-detector/download/jest-leak-detector-22.4.3.tgz?cache=0&sync_timestamp=1592925342819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-leak-detector%2Fdownload%2Fjest-leak-detector-22.4.3.tgz#2b7b263103afae8c52b6b91241a2de40117e5b35" + dependencies: + pretty-format "^22.4.3" + +jest-leak-detector@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-leak-detector/download/jest-leak-detector-23.6.0.tgz?cache=0&sync_timestamp=1592925342819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-leak-detector%2Fdownload%2Fjest-leak-detector-23.6.0.tgz#e4230fd42cf381a1a1971237ad56897de7e171de" + dependencies: + pretty-format "^23.6.0" + +jest-matcher-utils@^22.4.0, jest-matcher-utils@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-matcher-utils/download/jest-matcher-utils-22.4.3.tgz?cache=0&sync_timestamp=1592925437754&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-matcher-utils%2Fdownload%2Fjest-matcher-utils-22.4.3.tgz#4632fe428ebc73ebc194d3c7b65d37b161f710ff" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.4.3" + pretty-format "^22.4.3" + +jest-matcher-utils@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-matcher-utils/download/jest-matcher-utils-23.6.0.tgz?cache=0&sync_timestamp=1592925437754&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-matcher-utils%2Fdownload%2Fjest-matcher-utils-23.6.0.tgz#726bcea0c5294261a7417afb6da3186b4b8cac80" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + pretty-format "^23.6.0" + +jest-message-util@^22.4.0, jest-message-util@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-message-util/download/jest-message-util-22.4.3.tgz?cache=0&sync_timestamp=1592925344786&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-message-util%2Fdownload%2Fjest-message-util-22.4.3.tgz#cf3d38aafe4befddbfc455e57d65d5239e399eb7" + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + +jest-message-util@^23.4.0: + version "23.4.0" + resolved "https://registry.npm.taobao.org/jest-message-util/download/jest-message-util-23.4.0.tgz?cache=0&sync_timestamp=1592925344786&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-message-util%2Fdownload%2Fjest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f" + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + +jest-mock@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-mock/download/jest-mock-22.4.3.tgz?cache=0&sync_timestamp=1592925333333&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-mock%2Fdownload%2Fjest-mock-22.4.3.tgz#f63ba2f07a1511772cdc7979733397df770aabc7" + +jest-mock@^23.2.0: + version "23.2.0" + resolved "https://registry.npm.taobao.org/jest-mock/download/jest-mock-23.2.0.tgz?cache=0&sync_timestamp=1592925333333&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-mock%2Fdownload%2Fjest-mock-23.2.0.tgz#ad1c60f29e8719d47c26e1138098b6d18b261134" + +jest-regex-util@^22.1.0, jest-regex-util@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-regex-util/download/jest-regex-util-22.4.3.tgz#a826eb191cdf22502198c5401a1fc04de9cef5af" + +jest-regex-util@^23.3.0: + version "23.3.0" + resolved "https://registry.npm.taobao.org/jest-regex-util/download/jest-regex-util-23.3.0.tgz#5f86729547c2785c4002ceaa8f849fe8ca471bc5" + +jest-resolve-dependencies@^22.1.0: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-resolve-dependencies/download/jest-resolve-dependencies-22.4.3.tgz?cache=0&sync_timestamp=1592925367038&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-resolve-dependencies%2Fdownload%2Fjest-resolve-dependencies-22.4.3.tgz#e2256a5a846732dc3969cb72f3c9ad7725a8195e" + dependencies: + jest-regex-util "^22.4.3" + +jest-resolve-dependencies@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-resolve-dependencies/download/jest-resolve-dependencies-23.6.0.tgz?cache=0&sync_timestamp=1592925367038&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-resolve-dependencies%2Fdownload%2Fjest-resolve-dependencies-23.6.0.tgz#b4526af24c8540d9a3fab102c15081cf509b723d" + dependencies: + jest-regex-util "^23.3.0" + jest-snapshot "^23.6.0" + +jest-resolve@^22.4.2: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-resolve/download/jest-resolve-22.4.3.tgz?cache=0&sync_timestamp=1592925431706&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-resolve%2Fdownload%2Fjest-resolve-22.4.3.tgz#0ce9d438c8438229aa9b916968ec6b05c1abb4ea" + dependencies: + browser-resolve "^1.11.2" + chalk "^2.0.1" + +jest-resolve@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-resolve/download/jest-resolve-23.6.0.tgz?cache=0&sync_timestamp=1592925431706&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-resolve%2Fdownload%2Fjest-resolve-23.6.0.tgz#cf1d1a24ce7ee7b23d661c33ba2150f3aebfa0ae" + dependencies: + browser-resolve "^1.11.3" + chalk "^2.0.1" + realpath-native "^1.0.0" + +jest-runner@^22.4.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/jest-runner/download/jest-runner-22.4.4.tgz#dfca7b7553e0fa617e7b1291aeb7ce83e540a907" + dependencies: + exit "^0.1.2" + jest-config "^22.4.4" + jest-docblock "^22.4.0" + jest-haste-map "^22.4.2" + jest-jasmine2 "^22.4.4" + jest-leak-detector "^22.4.0" + jest-message-util "^22.4.0" + jest-runtime "^22.4.4" + jest-util "^22.4.1" + jest-worker "^22.2.2" + throat "^4.0.0" + +jest-runner@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-runner/download/jest-runner-23.6.0.tgz#3894bd219ffc3f3cb94dc48a4170a2e6f23a5a38" + dependencies: + exit "^0.1.2" + graceful-fs "^4.1.11" + jest-config "^23.6.0" + jest-docblock "^23.2.0" + jest-haste-map "^23.6.0" + jest-jasmine2 "^23.6.0" + jest-leak-detector "^23.6.0" + jest-message-util "^23.4.0" + jest-runtime "^23.6.0" + jest-util "^23.4.0" + jest-worker "^23.2.0" + source-map-support "^0.5.6" + throat "^4.0.0" + +jest-runtime@^22.4.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/jest-runtime/download/jest-runtime-22.4.4.tgz?cache=0&sync_timestamp=1592925498800&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-runtime%2Fdownload%2Fjest-runtime-22.4.4.tgz#9ba7792fc75582a5be0f79af6f8fe8adea314048" + dependencies: + babel-core "^6.0.0" + babel-jest "^22.4.4" + babel-plugin-istanbul "^4.1.5" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + graceful-fs "^4.1.11" + jest-config "^22.4.4" + jest-haste-map "^22.4.2" + jest-regex-util "^22.1.0" + jest-resolve "^22.4.2" + jest-util "^22.4.1" + jest-validate "^22.4.4" + json-stable-stringify "^1.0.1" + micromatch "^2.3.11" + realpath-native "^1.0.0" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^10.0.3" + +jest-runtime@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-runtime/download/jest-runtime-23.6.0.tgz?cache=0&sync_timestamp=1592925498800&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-runtime%2Fdownload%2Fjest-runtime-23.6.0.tgz#059e58c8ab445917cd0e0d84ac2ba68de8f23082" + dependencies: + babel-core "^6.0.0" + babel-plugin-istanbul "^4.1.6" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.1.11" + jest-config "^23.6.0" + jest-haste-map "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.6.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + micromatch "^2.3.11" + realpath-native "^1.0.0" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^11.0.0" + +jest-serializer@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-serializer/download/jest-serializer-22.4.3.tgz?cache=0&sync_timestamp=1592927136659&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-serializer%2Fdownload%2Fjest-serializer-22.4.3.tgz#a679b81a7f111e4766235f4f0c46d230ee0f7436" + +jest-serializer@^23.0.1: + version "23.0.1" + resolved "https://registry.npm.taobao.org/jest-serializer/download/jest-serializer-23.0.1.tgz?cache=0&sync_timestamp=1592927136659&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-serializer%2Fdownload%2Fjest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165" + +jest-snapshot@^22.4.0: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-snapshot/download/jest-snapshot-22.4.3.tgz?cache=0&sync_timestamp=1592925362593&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-snapshot%2Fdownload%2Fjest-snapshot-22.4.3.tgz#b5c9b42846ffb9faccb76b841315ba67887362d2" + dependencies: + chalk "^2.0.1" + jest-diff "^22.4.3" + jest-matcher-utils "^22.4.3" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^22.4.3" + +jest-snapshot@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-snapshot/download/jest-snapshot-23.6.0.tgz?cache=0&sync_timestamp=1592925362593&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-snapshot%2Fdownload%2Fjest-snapshot-23.6.0.tgz#f9c2625d1b18acda01ec2d2b826c0ce58a5aa17a" + dependencies: + babel-types "^6.0.0" + chalk "^2.0.1" + jest-diff "^23.6.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-resolve "^23.6.0" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^23.6.0" + semver "^5.5.0" + +jest-util@^22.4.1, jest-util@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-util/download/jest-util-22.4.3.tgz?cache=0&sync_timestamp=1592925342680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-util%2Fdownload%2Fjest-util-22.4.3.tgz#c70fec8eec487c37b10b0809dc064a7ecf6aafac" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^22.4.3" + mkdirp "^0.5.1" + source-map "^0.6.0" + +jest-util@^23.4.0: + version "23.4.0" + resolved "https://registry.npm.taobao.org/jest-util/download/jest-util-23.4.0.tgz?cache=0&sync_timestamp=1592925342680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-util%2Fdownload%2Fjest-util-23.4.0.tgz#4d063cb927baf0a23831ff61bec2cbbf49793561" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^23.4.0" + mkdirp "^0.5.1" + slash "^1.0.0" + source-map "^0.6.0" + +jest-validate@^22.4.4: + version "22.4.4" + resolved "https://registry.npm.taobao.org/jest-validate/download/jest-validate-22.4.4.tgz?cache=0&sync_timestamp=1592925336825&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-validate%2Fdownload%2Fjest-validate-22.4.4.tgz#1dd0b616ef46c995de61810d85f57119dbbcec4d" + dependencies: + chalk "^2.0.1" + jest-config "^22.4.4" + jest-get-type "^22.1.0" + leven "^2.1.0" + pretty-format "^22.4.0" + +jest-validate@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest-validate/download/jest-validate-23.6.0.tgz?cache=0&sync_timestamp=1592925336825&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-validate%2Fdownload%2Fjest-validate-23.6.0.tgz#36761f99d1ed33fcd425b4e4c5595d62b6597474" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + leven "^2.1.0" + pretty-format "^23.6.0" + +jest-watcher@^23.4.0: + version "23.4.0" + resolved "https://registry.npm.taobao.org/jest-watcher/download/jest-watcher-23.4.0.tgz?cache=0&sync_timestamp=1592925436843&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-watcher%2Fdownload%2Fjest-watcher-23.4.0.tgz#d2e28ce74f8dad6c6afc922b92cabef6ed05c91c" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + string-length "^2.0.0" + +jest-worker@^22.2.2, jest-worker@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/jest-worker/download/jest-worker-22.4.3.tgz#5c421417cba1c0abf64bf56bd5fb7968d79dd40b" + dependencies: + merge-stream "^1.0.1" + +jest-worker@^23.2.0: + version "23.2.0" + resolved "https://registry.npm.taobao.org/jest-worker/download/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9" + dependencies: + merge-stream "^1.0.1" + +jest@^23.0.1: + version "23.6.0" + resolved "https://registry.npm.taobao.org/jest/download/jest-23.6.0.tgz?cache=0&sync_timestamp=1592925503333&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest%2Fdownload%2Fjest-23.6.0.tgz#ad5835e923ebf6e19e7a1d7529a432edfee7813d" + dependencies: + import-local "^1.0.0" + jest-cli "^23.6.0" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.npm.taobao.org/js-tokens/download/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + +js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.7.0, js-yaml@^3.9.0: + version "3.14.0" + resolved "https://registry.npm.taobao.org/js-yaml/download/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz?cache=0&sync_timestamp=1589682745609&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjsbn%2Fdownload%2Fjsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsdom@^11.5.1: + version "11.12.0" + resolved "https://registry.npm.taobao.org/jsdom/download/jsdom-11.12.0.tgz?cache=0&sync_timestamp=1594341265247&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjsdom%2Fdownload%2Fjsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" + dependencies: + abab "^2.0.0" + acorn "^5.5.3" + acorn-globals "^4.1.0" + array-equal "^1.0.0" + cssom ">= 0.3.2 < 0.4.0" + cssstyle "^1.0.0" + data-urls "^1.0.0" + domexception "^1.0.1" + escodegen "^1.9.1" + html-encoding-sniffer "^1.0.2" + left-pad "^1.3.0" + nwsapi "^2.0.7" + parse5 "4.0.0" + pn "^1.1.0" + request "^2.87.0" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" + tough-cookie "^2.3.4" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.3" + whatwg-mimetype "^2.1.0" + whatwg-url "^6.4.1" + ws "^5.2.0" + xml-name-validator "^3.0.0" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.npm.taobao.org/jsesc/download/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npm.taobao.org/jsesc/download/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/json-stable-stringify/download/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz?cache=0&sync_timestamp=1589682771374&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-stringify-safe%2Fdownload%2Fjson-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.4.0: + version "0.4.0" + resolved "https://registry.npm.taobao.org/json5/download/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.npm.taobao.org/json5/download/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.npm.taobao.org/jsonify/download/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jsx-ast-utils@^2.0.1: + version "2.4.1" + resolved "https://registry.npm.taobao.org/jsx-ast-utils/download/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e" + dependencies: + array-includes "^3.1.1" + object.assign "^4.1.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/kind-of/download/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + +kleur@^2.0.1: + version "2.0.2" + resolved "https://registry.npm.taobao.org/kleur/download/kleur-2.0.2.tgz#b704f4944d95e255d038f0cb05fb8a602c55a300" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/lcid/download/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/lcid/download/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + dependencies: + invert-kv "^2.0.0" + +left-pad@^1.3.0: + version "1.3.0" + resolved "https://registry.npm.taobao.org/left-pad/download/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/leven/download/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/load-json-file/download/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/locate-path/download/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.npm.taobao.org/lodash.sortby/download/lodash.sortby-4.7.0.tgz?cache=0&sync_timestamp=1589683608371&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.sortby%2Fdownload%2Flodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + +lodash@4.17.19, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.0: + version "4.17.19" + resolved "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226931791&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" + +loose-envify@^1.0.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.npm.taobao.org/makeerror/download/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.npm.taobao.org/map-age-cleaner/download/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.npm.taobao.org/map-cache/download/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/map-visit/download/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.4" + resolved "https://registry.npm.taobao.org/math-random/download/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/mem/download/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.npm.taobao.org/mem/download/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/merge-stream/download/merge-stream-1.0.1.tgz?cache=0&sync_timestamp=1589682763068&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmerge-stream%2Fdownload%2Fmerge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + dependencies: + readable-stream "^2.0.1" + +merge@^1.2.0: + version "1.2.1" + resolved "https://registry.npm.taobao.org/merge/download/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + +micromatch@^2.1.5, micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.npm.taobao.org/micromatch/download/micromatch-2.3.11.tgz?cache=0&sync_timestamp=1589682762554&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmicromatch%2Fdownload%2Fmicromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.npm.taobao.org/micromatch/download/micromatch-3.1.10.tgz?cache=0&sync_timestamp=1589682762554&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmicromatch%2Fdownload%2Fmicromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.npm.taobao.org/mime-db/download/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.27" + resolved "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.27.tgz?cache=0&sync_timestamp=1589682770020&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-types%2Fdownload%2Fmime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + dependencies: + mime-db "1.44.0" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + +minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz?cache=0&sync_timestamp=1589682820731&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminimist%2Fdownload%2Fminimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.npm.taobao.org/mixin-deep/download/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.5.tgz?cache=0&sync_timestamp=1589682820707&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmkdirp%2Fdownload%2Fmkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + dependencies: + minimist "^1.2.5" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.npm.taobao.org/mute-stream/download/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@^2.12.1: + version "2.14.1" + resolved "https://registry.npm.taobao.org/nan/download/nan-2.14.1.tgz?cache=0&sync_timestamp=1589682780413&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnan%2Fdownload%2Fnan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.npm.taobao.org/nanomatch/download/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npm.taobao.org/natural-compare/download/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.2.tgz?cache=0&sync_timestamp=1594317434347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fneo-async%2Fdownload%2Fneo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.npm.taobao.org/nice-try/download/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npm.taobao.org/node-int64/download/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + +node-notifier@^5.2.1: + version "5.4.3" + resolved "https://registry.npm.taobao.org/node-notifier/download/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50" + dependencies: + growly "^1.3.0" + is-wsl "^1.1.0" + semver "^5.5.0" + shellwords "^0.1.1" + which "^1.3.0" + +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.npm.taobao.org/normalize-package-data/download/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz?cache=0&sync_timestamp=1589682839339&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnumber-is-nan%2Fdownload%2Fnumber-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +nwsapi@^2.0.7: + version "2.2.0" + resolved "https://registry.npm.taobao.org/nwsapi/download/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz?cache=0&sync_timestamp=1589682811909&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Foauth-sign%2Fdownload%2Foauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + +object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.7.0: + version "1.8.0" + resolved "https://registry.npm.taobao.org/object-inspect/download/object-inspect-1.8.0.tgz?cache=0&sync_timestamp=1592545231350&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-inspect%2Fdownload%2Fobject-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npm.taobao.org/object-keys/download/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/object-visit/download/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/object.assign/download/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/object.getownpropertydescriptors/download/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.npm.taobao.org/object.omit/download/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.npm.taobao.org/onetime/download/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +optionator@^0.8.1, optionator@^0.8.2: + version "0.8.3" + resolved "https://registry.npm.taobao.org/optionator/download/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.npm.taobao.org/os-homedir/download/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/os-locale/download/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/os-locale/download/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/os-tmpdir/download/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/p-defer/download/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/p-is-promise/download/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.npm.taobao.org/p-limit/download/p-limit-1.3.0.tgz?cache=0&sync_timestamp=1594559734248&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-limit%2Fdownload%2Fp-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/p-locate/download/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/p-try/download/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/parent-module/download/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + dependencies: + callsites "^3.0.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.npm.taobao.org/parse-glob/download/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.npm.taobao.org/parse-json/download/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse-json@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/parse-json/download/parse-json-3.0.0.tgz#fa6f47b18e23826ead32f263e744d0e1e847fb13" + dependencies: + error-ex "^1.3.1" + +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/parse5/download/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.npm.taobao.org/pascalcase/download/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-exists@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/path-exists/download/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/path-exists/download/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/path-exists/download/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/path-is-inside/download/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/path-key/download/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5, path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.npm.taobao.org/path-parse/download/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/path-type/download/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.npm.taobao.org/pinkie-promise/download/pinkie-promise-2.0.1.tgz?cache=0&sync_timestamp=1589682729560&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpinkie-promise%2Fdownload%2Fpinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.npm.taobao.org/pinkie/download/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/pn/download/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.npm.taobao.org/preserve/download/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +prettier@^2.7.1: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +pretty-format@^22.4.0, pretty-format@^22.4.3: + version "22.4.3" + resolved "https://registry.npm.taobao.org/pretty-format/download/pretty-format-22.4.3.tgz?cache=0&sync_timestamp=1592925335887&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpretty-format%2Fdownload%2Fpretty-format-22.4.3.tgz#f873d780839a9c02e9664c8a082e9ee79eaac16f" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + +pretty-format@^23.6.0: + version "23.6.0" + resolved "https://registry.npm.taobao.org/pretty-format/download/pretty-format-23.6.0.tgz?cache=0&sync_timestamp=1592925335887&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpretty-format%2Fdownload%2Fpretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + +private@^0.1.6, private@^0.1.8: + version "0.1.8" + resolved "https://registry.npm.taobao.org/private/download/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + +prompts@^0.1.9: + version "0.1.14" + resolved "https://registry.npm.taobao.org/prompts/download/prompts-0.1.14.tgz#a8e15c612c5c9ec8f8111847df3337c9cbd443b2" + dependencies: + kleur "^2.0.1" + sisteransi "^0.1.1" + +prop-types@^15.6.2: + version "15.7.2" + resolved "https://registry.npm.taobao.org/prop-types/download/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz?cache=0&sync_timestamp=1589682803838&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpunycode%2Fdownload%2Fpunycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.npm.taobao.org/randomatic/download/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +react-is@^16.8.1: + version "16.13.1" + resolved "https://registry.npm.taobao.org/react-is/download/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/read-pkg-up/download/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/read-pkg/download/read-pkg-1.1.0.tgz?cache=0&sync_timestamp=1589682810106&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fread-pkg%2Fdownload%2Fread-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.2.2: + version "2.3.7" + resolved "https://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.7.tgz?cache=0&sync_timestamp=1589682741447&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.npm.taobao.org/readdirp/download/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +realpath-native@^1.0.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/realpath-native/download/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" + dependencies: + util.promisify "^1.0.0" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.npm.taobao.org/regex-cache/download/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.npm.taobao.org/regex-not/download/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/regexpp/download/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz?cache=0&sync_timestamp=1589682793094&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frepeat-string%2Fdownload%2Frepeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.npm.taobao.org/repeating/download/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request-promise-core@1.1.3: + version "1.1.3" + resolved "https://registry.npm.taobao.org/request-promise-core/download/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" + dependencies: + lodash "^4.17.15" + +request-promise-native@^1.0.5: + version "1.0.8" + resolved "https://registry.npm.taobao.org/request-promise-native/download/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" + dependencies: + request-promise-core "1.1.3" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +request@^2.87.0: + version "2.88.2" + resolved "https://registry.npm.taobao.org/request/download/request-2.88.2.tgz?cache=0&sync_timestamp=1589682741998&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frequest%2Fdownload%2Frequest-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-from-string@^2.0.1: + version "2.0.2" + resolved "https://registry.npm.taobao.org/require-from-string/download/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/require-main-filename/download/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/resolve-cwd/download/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/resolve-from/download/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/resolve-from/download/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.npm.taobao.org/resolve-url/download/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.npm.taobao.org/resolve/download/resolve-1.1.7.tgz?cache=0&sync_timestamp=1589682751623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fresolve%2Fdownload%2Fresolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2: + version "1.17.0" + resolved "https://registry.npm.taobao.org/resolve/download/resolve-1.17.0.tgz?cache=0&sync_timestamp=1589682751623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fresolve%2Fdownload%2Fresolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + dependencies: + path-parse "^1.0.6" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/restore-cursor/download/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.npm.taobao.org/ret/download/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.npm.taobao.org/rimraf/download/rimraf-2.6.3.tgz?cache=0&sync_timestamp=1589682814592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + dependencies: + glob "^7.1.3" + +rimraf@^2.5.4, rimraf@^2.6.1: + version "2.7.1" + resolved "https://registry.npm.taobao.org/rimraf/download/rimraf-2.7.1.tgz?cache=0&sync_timestamp=1589682814592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + dependencies: + glob "^7.1.3" + +rsvp@^3.3.3: + version "3.6.2" + resolved "https://registry.npm.taobao.org/rsvp/download/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + +run-async@^2.2.0: + version "2.4.1" + resolved "https://registry.npm.taobao.org/run-async/download/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + +rxjs@^6.4.0: + version "6.6.0" + resolved "https://registry.npm.taobao.org/rxjs/download/rxjs-6.6.0.tgz?cache=0&sync_timestamp=1593794895607&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frxjs%2Fdownload%2Frxjs-6.6.0.tgz#af2901eedf02e3a83ffa7f886240ff9018bbec84" + dependencies: + tslib "^1.9.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.2: + version "5.2.1" + resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz?cache=0&sync_timestamp=1589682795646&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589682795646&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.npm.taobao.org/safe-regex/download/safe-regex-1.1.0.tgz?cache=0&sync_timestamp=1589682757445&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-regex%2Fdownload%2Fsafe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz?cache=0&sync_timestamp=1589682784154&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafer-buffer%2Fdownload%2Fsafer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sane@^2.0.0: + version "2.5.2" + resolved "https://registry.npm.taobao.org/sane/download/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" + dependencies: + anymatch "^2.0.0" + capture-exit "^1.2.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.2.3" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1: + version "5.7.1" + resolved "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1589682805026&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/set-value/download/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shell-quote@^1.6.1: + version "1.7.2" + resolved "https://registry.npm.taobao.org/shell-quote/download/shell-quote-1.7.2.tgz?cache=0&sync_timestamp=1589682755902&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshell-quote%2Fdownload%2Fshell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.npm.taobao.org/shellwords/download/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.3.tgz?cache=0&sync_timestamp=1589682814780&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsignal-exit%2Fdownload%2Fsignal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + +sisteransi@^0.1.1: + version "0.1.1" + resolved "https://registry.npm.taobao.org/sisteransi/download/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/slash/download/slash-1.0.0.tgz?cache=0&sync_timestamp=1589682715547&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslash%2Fdownload%2Fslash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/slice-ansi/download/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/snapdragon-node/download/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.npm.taobao.org/snapdragon-util/download/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.npm.taobao.org/snapdragon/download/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.npm.taobao.org/source-map-resolve/download/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.npm.taobao.org/source-map-support/download/source-map-support-0.4.18.tgz?cache=0&sync_timestamp=1589682814927&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map-support@^0.5.0, source-map-support@^0.5.5, source-map-support@^0.5.6: + version "0.5.19" + resolved "https://registry.npm.taobao.org/source-map-support/download/source-map-support-0.5.19.tgz?cache=0&sync_timestamp=1589682814927&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.npm.taobao.org/source-map-url/download/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.npm.taobao.org/spdx-correct/download/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.npm.taobao.org/spdx-exceptions/download/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.npm.taobao.org/spdx-expression-parse/download/spdx-expression-parse-3.0.1.tgz?cache=0&sync_timestamp=1589682794533&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fspdx-expression-parse%2Fdownload%2Fspdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.npm.taobao.org/spdx-license-ids/download/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.npm.taobao.org/split-string/download/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stack-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.npm.taobao.org/stack-utils/download/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.npm.taobao.org/static-extend/download/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.npm.taobao.org/stealthy-require/download/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/string-length/download/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.npm.taobao.org/string-width/download/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trimend@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/string.prototype.trimend/download/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimstart@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/string.prototype.trimstart/download/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz?cache=0&sync_timestamp=1589682743884&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring_decoder%2Fdownload%2Fstring_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1589682795383&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + dependencies: + ansi-regex "^4.1.0" + +strip-bom@3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/strip-bom/download/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/strip-bom/download/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/strip-eof/download/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-2.0.1.tgz?cache=0&sync_timestamp=1594567532500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/subarg/download/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + dependencies: + minimist "^1.1.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.2: + version "3.2.3" + resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" + +symbol-tree@^3.2.2: + version "3.2.4" + resolved "https://registry.npm.taobao.org/symbol-tree/download/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.npm.taobao.org/table/download/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +test-exclude@^4.2.1: + version "4.2.3" + resolved "https://registry.npm.taobao.org/test-exclude/download/test-exclude-4.2.3.tgz#a9a5e64474e4398339245a0a769ad7c2f4a97c20" + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npm.taobao.org/text-table/download/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.npm.taobao.org/throat/download/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz?cache=0&sync_timestamp=1589683627670&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fthrough%2Fdownload%2Fthrough-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz?cache=0&sync_timestamp=1589684134816&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftmp%2Fdownload%2Ftmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.npm.taobao.org/tmpl/download/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.npm.taobao.org/to-object-path/download/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.npm.taobao.org/to-regex/download/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.5.0.tgz?cache=0&sync_timestamp=1589682815640&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftough-cookie%2Fdownload%2Ftough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/tr46/download/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + dependencies: + punycode "^2.1.0" + +traverse@0.6.6: + version "0.6.6" + resolved "https://registry.npm.taobao.org/traverse/download/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.npm.taobao.org/trim-right/download/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +ts-jest@^22.4.6: + version "22.4.6" + resolved "https://registry.npm.taobao.org/ts-jest/download/ts-jest-22.4.6.tgz?cache=0&sync_timestamp=1594634982569&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fts-jest%2Fdownload%2Fts-jest-22.4.6.tgz#a5d7f5e8b809626d1f4143209d301287472ec344" + dependencies: + babel-core "^6.26.3" + babel-plugin-istanbul "^4.1.6" + babel-plugin-transform-es2015-modules-commonjs "^6.26.2" + babel-preset-jest "^22.4.3" + cpx "^1.5.0" + fs-extra "6.0.0" + jest-config "^22.4.3" + lodash "^4.17.10" + pkg-dir "^2.0.0" + source-map-support "^0.5.5" + yargs "^11.0.0" + +tslib@1.9.0: + version "1.9.0" + resolved "https://registry.npm.taobao.org/tslib/download/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + +tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: + version "1.13.0" + resolved "https://registry.npm.taobao.org/tslib/download/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" + +tslint-config-prettier@^1.10.0: + version "1.18.0" + resolved "https://registry.npm.taobao.org/tslint-config-prettier/download/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37" + +tslint-config-standard@^7.0.0: + version "7.1.0" + resolved "https://registry.npm.taobao.org/tslint-config-standard/download/tslint-config-standard-7.1.0.tgz#6bcc435a179478e365f6cc62312a561221985760" + dependencies: + tslint-eslint-rules "^5.3.1" + +tslint-eslint-rules@^5.3.1: + version "5.4.0" + resolved "https://registry.npm.taobao.org/tslint-eslint-rules/download/tslint-eslint-rules-5.4.0.tgz#e488cc9181bf193fe5cd7bfca213a7695f1737b5" + dependencies: + doctrine "0.7.2" + tslib "1.9.0" + tsutils "^3.0.0" + +tslint@^5.10.0: + version "5.20.1" + resolved "https://registry.npm.taobao.org/tslint/download/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" + dependencies: + "@babel/code-frame" "^7.0.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^4.0.1" + glob "^7.1.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + mkdirp "^0.5.1" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.8.0" + tsutils "^2.29.0" + +tsutils@^2.29.0: + version "2.29.0" + resolved "https://registry.npm.taobao.org/tsutils/download/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + dependencies: + tslib "^1.8.1" + +tsutils@^3.0.0: + version "3.17.1" + resolved "https://registry.npm.taobao.org/tsutils/download/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + dependencies: + tslib "^1.8.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz?cache=0&sync_timestamp=1589682745749&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftweetnacl%2Fdownload%2Ftweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.npm.taobao.org/type-check/download/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +typescript@^3.2.2: + version "3.9.6" + resolved "https://registry.npm.taobao.org/typescript/download/typescript-3.9.6.tgz?cache=0&sync_timestamp=1594618757668&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftypescript%2Fdownload%2Ftypescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a" + +uglify-js@^3.1.4: + version "3.10.0" + resolved "https://registry.npm.taobao.org/uglify-js/download/uglify-js-3.10.0.tgz?cache=0&sync_timestamp=1592744803278&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuglify-js%2Fdownload%2Fuglify-js-3.10.0.tgz#397a7e6e31ce820bfd1cb55b804ee140c587a9e7" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/union-value/download/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/unset-value/download/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.npm.taobao.org/uri-js/download/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.npm.taobao.org/urix/download/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.npm.taobao.org/use/download/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util.promisify@^1.0.0: + version "1.0.1" + resolved "https://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.1.tgz?cache=0&sync_timestamp=1589682767473&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futil.promisify%2Fdownload%2Futil.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.npm.taobao.org/uuid/download/uuid-3.4.0.tgz?cache=0&sync_timestamp=1592944143460&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.npm.taobao.org/validate-npm-package-license/download/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +w3c-hr-time@^1.0.1: + version "1.0.2" + resolved "https://registry.npm.taobao.org/w3c-hr-time/download/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + dependencies: + browser-process-hrtime "^1.0.0" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.npm.taobao.org/walker/download/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.npm.taobao.org/watch/download/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.npm.taobao.org/webidl-conversions/download/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: + version "1.0.5" + resolved "https://registry.npm.taobao.org/whatwg-encoding/download/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: + version "2.3.0" + resolved "https://registry.npm.taobao.org/whatwg-mimetype/download/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + +whatwg-url@^6.4.1: + version "6.5.0" + resolved "https://registry.npm.taobao.org/whatwg-url/download/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.npm.taobao.org/whatwg-url/download/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@^1.2.12, which@^1.2.9, which@^1.3.0: + version "1.3.1" + resolved "https://registry.npm.taobao.org/which/download/which-1.3.1.tgz?cache=0&sync_timestamp=1589682812246&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwhich%2Fdownload%2Fwhich-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz?cache=0&sync_timestamp=1589683603678&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fword-wrap%2Fdownload%2Fword-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/wordwrap/download/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^2.1.0: + version "2.4.3" + resolved "https://registry.npm.taobao.org/write-file-atomic/download/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +write@1.0.3: + version "1.0.3" + resolved "https://registry.npm.taobao.org/write/download/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + dependencies: + mkdirp "^0.5.1" + +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.npm.taobao.org/ws/download/ws-5.2.2.tgz?cache=0&sync_timestamp=1593925481882&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fws%2Fdownload%2Fws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + dependencies: + async-limiter "~1.0.0" + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.npm.taobao.org/xml-name-validator/download/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.npm.taobao.org/y18n/download/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yargs-parser@^8.1.0: + version "8.1.0" + resolved "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" + dependencies: + camelcase "^4.1.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + +yargs@^10.0.3: + version "10.1.2" + resolved "https://registry.npm.taobao.org/yargs/download/yargs-10.1.2.tgz?cache=0&sync_timestamp=1594421142336&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^8.1.0" + +yargs@^11.0.0: + version "11.1.1" + resolved "https://registry.npm.taobao.org/yargs/download/yargs-11.1.1.tgz?cache=0&sync_timestamp=1594421142336&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-11.1.1.tgz#5052efe3446a4df5ed669c995886cc0f13702766" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" diff --git a/packages/taroize/package.json b/packages/taroize/package.json index add0e72a3253..426b24303417 100644 --- a/packages/taroize/package.json +++ b/packages/taroize/package.json @@ -18,7 +18,24 @@ "author": "yuche", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.14.5", + "@babel/code-frame": "^7.21.4", + "@babel/core": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-decorators": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.14.5", + "@babel/plugin-proposal-optional-chaining": "^7.21.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-dynamic-import": "7.8.3", + "@babel/plugin-syntax-flow": "^7.22.5", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-flow-strip-types": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.14.5", + "@babel/preset-react": "^7.14.5", + "@babel/template": "7.21.9", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", "babel-core": "^6.26.3", "babel-generator": "^6.26.1", "babel-template": "^6.26.0", diff --git a/packages/taroize/src/index.ts b/packages/taroize/src/index.ts index b97c0783a71b..e44c991fd6bb 100644 --- a/packages/taroize/src/index.ts +++ b/packages/taroize/src/index.ts @@ -1,4 +1,4 @@ -import * as t from 'babel-types' +import * as t from '@babel/types' import { errors, resetGlobals, THIRD_PARTY_COMPONENTS } from './global' import { parseScript } from './script' diff --git a/packages/taroize/src/json.ts b/packages/taroize/src/json.ts index 6695dfa97048..1f15922f8af0 100644 --- a/packages/taroize/src/json.ts +++ b/packages/taroize/src/json.ts @@ -1,4 +1,4 @@ -import * as t from 'babel-types' +import * as t from '@babel/types' import { buildTemplate } from './utils' diff --git a/packages/taroize/src/script.ts b/packages/taroize/src/script.ts index a802c761e7b1..d663f444d782 100644 --- a/packages/taroize/src/script.ts +++ b/packages/taroize/src/script.ts @@ -1,5 +1,5 @@ -import traverse, { NodePath, Visitor } from 'babel-traverse' -import * as t from 'babel-types' +import traverse, { NodePath, Visitor } from '@babel/traverse' +import * as t from '@babel/types' import { usedComponents } from './global' import { buildBlockElement, buildImportStatement, buildRender, codeFrameError, parseCode } from './utils' @@ -26,10 +26,11 @@ export function replaceIdentifier (callee: NodePath) { } } +// babel 6升级babel 7适配 export function replaceMemberExpression (callee: NodePath) { if (callee.isMemberExpression()) { - const object = callee.get('object') - if (object.isIdentifier({ name: 'wx' })) { + const object = callee.get('object') as NodePath + if (t.isIdentifier(object.node, { name: 'wx' })) { object.replaceWith(t.identifier('Taro')) } } @@ -62,8 +63,8 @@ export function parseScript ( }, CallExpression (path) { const callee = path.get('callee') - replaceIdentifier(callee) - replaceMemberExpression(callee) + replaceIdentifier(callee as NodePath) + replaceMemberExpression(callee as NodePath) if ( callee.isIdentifier({ name: 'Page' }) || callee.isIdentifier({ name: 'Component' }) || @@ -129,8 +130,8 @@ function parsePage ( pagePath.traverse({ CallExpression (path) { const callee = path.get('callee') - replaceIdentifier(callee) - replaceMemberExpression(callee) + replaceIdentifier(callee as NodePath) + replaceMemberExpression(callee as NodePath) } }) if (refId) { diff --git a/packages/taroize/src/template.ts b/packages/taroize/src/template.ts index f8c1bb3bf459..b50061ab5f47 100644 --- a/packages/taroize/src/template.ts +++ b/packages/taroize/src/template.ts @@ -1,5 +1,5 @@ -import { NodePath } from 'babel-traverse' -import * as t from 'babel-types' +import { NodePath } from '@babel/traverse' +import * as t from '@babel/types' import * as fs from 'fs' import { dirname, extname, relative, resolve } from 'path' @@ -37,14 +37,14 @@ export function parseTemplate (path: NodePath, dirPath: string) { } const openingElement = path.get('openingElement') const attrs = openingElement.get('attributes') - const is = attrs.find(attr => attr.get('name').isJSXIdentifier({ name: 'is' })) - const data = attrs.find(attr => attr.get('name').isJSXIdentifier({ name: 'data' })) - // const spread = attrs.find(attr => attr.get('name').isJSXIdentifier({ name: 'spread' })) - const name = attrs.find(attr => attr.get('name').isJSXIdentifier({ name: 'name' })) + const is = attrs.find(attr => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === 'is') + const data = attrs.find(attr => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === 'data') + const name = attrs.find(attr => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === 'name') + const refIds = new Set() - const loopIds = new Set() + const loopIds = new Set() const imports: any[] = [] - if (name) { + if (name && t.isJSXAttribute(name.node)) { const value = name.node.value if (value === null || !t.isStringLiteral(value)) { throw new Error('template 的 `name` 属性只能是字符串') @@ -83,7 +83,7 @@ export function parseTemplate (path: NodePath, dirPath: string) { name: className, ast: classDecl } - } else if (is) { + } else if (is && t.isJSXAttribute(is.node)) { const value = is.node.value if (!value) { throw new Error('template 的 `is` 属性不能为空') @@ -91,7 +91,7 @@ export function parseTemplate (path: NodePath, dirPath: string) { if (t.isStringLiteral(value)) { const className = buildTemplateName(value.value) const attributes: t.JSXAttribute[] = [] - if (data) { + if (data && t.isJSXAttribute(data.node)) { attributes.push(data.node) } path.replaceWith(t.jSXElement( @@ -104,7 +104,7 @@ export function parseTemplate (path: NodePath, dirPath: string) { if (t.isStringLiteral(value.expression)) { const className = buildTemplateName(value.expression.value) const attributes: t.JSXAttribute[] = [] - if (data) { + if (data && t.isJSXAttribute(data.node)) { attributes.push(data.node) } path.replaceWith(t.jSXElement( @@ -119,7 +119,7 @@ export function parseTemplate (path: NodePath, dirPath: string) { throw new Error('当 template is 标签是三元表达式时,他的两个值都必须为字符串') } const attributes: t.JSXAttribute[] = [] - if (data) { + if (data && t.isJSXAttribute(data.node)) { attributes.push(data.node) } const block = buildBlockElement() @@ -168,7 +168,7 @@ export function getWXMLsource (dirPath: string, src: string, type: string) { export function parseModule (jsx: NodePath, dirPath: string, type: 'include' | 'import') { const openingElement = jsx.get('openingElement') const attrs = openingElement.get('attributes') - const src = attrs.find(attr => attr.get('name').isJSXIdentifier({ name: 'src' })) + const src = attrs.find(attr => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === 'src') if (!src) { throw new Error(`${type} 标签必须包含 \`src\` 属性`) } @@ -176,10 +176,10 @@ export function parseModule (jsx: NodePath, dirPath: string, type: dirPath = dirname(dirPath) } const value = src.get('value') - if (!value.isStringLiteral()) { + if (!t.isStringLiteral(value)) { throw new Error(`${type} 标签的 src 属性值必须是一个字符串`) } - let srcValue = value.node.value + let srcValue = value.value if (srcValue.startsWith('/')) { const vpath = resolve(setting.rootPath, srcValue.substr(1)) if (!fs.existsSync(vpath)) { diff --git a/packages/taroize/src/utils.ts b/packages/taroize/src/utils.ts index cb300a583a23..ef039ad36bc6 100644 --- a/packages/taroize/src/utils.ts +++ b/packages/taroize/src/utils.ts @@ -1,14 +1,25 @@ import { codeFrameColumns } from '@babel/code-frame' -import { transform } from 'babel-core' -import * as template from 'babel-template' -import { NodePath } from 'babel-traverse' -import * as t from 'babel-types' +import * as babel from '@babel/core' +import { parse } from '@babel/parser' +import classProperties from '@babel/plugin-proposal-class-properties' +import decorators from '@babel/plugin-proposal-decorators' +import objectRestSpread from '@babel/plugin-proposal-object-rest-spread' +import optionalChaining from '@babel/plugin-proposal-optional-chaining' +import asyncGenerators from '@babel/plugin-syntax-async-generators' +import dynamicImport from '@babel/plugin-syntax-dynamic-import' +import asyncFunctions from '@babel/plugin-transform-async-to-generator' +import exponentiationOperator from '@babel/plugin-transform-exponentiation-operator' +import flowStrip from '@babel/plugin-transform-flow-strip-types' +import jsxPlugin from '@babel/plugin-transform-react-jsx' +import { default as template } from '@babel/template' +import { NodePath } from '@babel/traverse' +import * as t from '@babel/types' import { camelCase, capitalize } from 'lodash' export function isAliasThis (p: NodePath, name: string) { const binding = p.scope.getBinding(name) if (binding) { - return binding.path.isVariableDeclarator() && binding.path.get('init').isThisExpression() + return binding.path.isVariableDeclarator() && t.isThisExpression(binding.path.get('init')) } return false } @@ -33,27 +44,44 @@ export function isValidVarName (str?: string) { } export function parseCode (code: string) { - return (transform(code, { - parserOpts: { - sourceType: 'module', - plugins: [ - 'classProperties', - 'jsx', - 'flow', - 'flowComment', - 'trailingFunctionCommas', - 'asyncFunctions', - 'exponentiationOperator', - 'asyncGenerators', - 'objectRestSpread', - 'decorators', - 'dynamicImport' - ] - } + return (babel.transformSync(code, { + ast: true, + sourceType: 'module', + plugins: [ + classProperties, + jsxPlugin, + flowStrip, + asyncFunctions, + exponentiationOperator, + asyncGenerators, + objectRestSpread, + [decorators, { legacy: true }], + dynamicImport, + optionalChaining + ] }) as { ast: t.File }).ast } -export const buildTemplate = (str: string) => template(str)().expression as t.Expression +export const buildTemplate = (str: string) => { + + // 检查字符串中是否包含占位符 + const hasPlaceholder = /{{\s*(\w+)\s*}/.test(str) + + let ast + if (hasPlaceholder) { + // 如果存在占位符,则使用模板创建AST + const astTemplate = template(str) + ast = astTemplate({}) + } else { + // 否则直接解析字符串为AST + ast = parse(str).program.body[0] + } + if (t.isExpressionStatement(ast)) { + return ast.expression + } else { + throw new Error(`Invalid AST. Expected an ExpressionStatement`) + } +} export function buildBlockElement () { return t.jSXElement( diff --git a/packages/taroize/src/vue.ts b/packages/taroize/src/vue.ts index 2b2da8be093e..e2b50e2b3c91 100644 --- a/packages/taroize/src/vue.ts +++ b/packages/taroize/src/vue.ts @@ -1,6 +1,6 @@ /* eslint-disable camelcase */ -import traverse, { Visitor } from 'babel-traverse' -import * as t from 'babel-types' +import traverse, { NodePath,Visitor } from '@babel/traverse' +import * as t from '@babel/types' import * as fs from 'fs' import { parse, stringify } from 'himalaya-wxml' import { kebabCase } from 'lodash' @@ -33,8 +33,8 @@ export function parseVue (dirPath: string, wxml: string, jsCode = ''): Result { }, CallExpression (path) { const callee = path.get('callee') - replaceIdentifier(callee) - replaceMemberExpression(callee) + replaceIdentifier(callee as NodePath) + replaceMemberExpression(callee as NodePath) if ( callee.isIdentifier({ name: 'Page' }) || callee.isIdentifier({ name: 'Component' }) || diff --git a/packages/taroize/src/wxml.ts b/packages/taroize/src/wxml.ts index 098a34d71ed1..1e9046506694 100644 --- a/packages/taroize/src/wxml.ts +++ b/packages/taroize/src/wxml.ts @@ -1,6 +1,10 @@ /* eslint-disable camelcase */ -import traverse, { NodePath, Visitor } from 'babel-traverse' -import * as t from 'babel-types' +import traverse, { NodePath, Visitor } from '@babel/traverse' +import * as t from '@babel/types' +import { + printLog, + processTypeEnum +} from '@tarojs/helper' import { parse as parseFile } from 'babylon' import { parse } from 'himalaya-wxml' import { camelCase, cloneDeep } from 'lodash' @@ -128,14 +132,19 @@ export const createWxmlVistor = ( // 把 hidden 转换为 wxif if (name.name === 'hidden') { const value = path.get('value') as NodePath - if (t.isJSXExpressionContainer(value)) { + if (t.isJSXExpressionContainer(value) && !t.isJSXEmptyExpression(value.node.expression)) { const exclamation = t.unaryExpression('!', value.node.expression) path.set('value', t.jSXExpressionContainer(exclamation)) path.set('name', t.jSXIdentifier(WX_IF)) } } - const valueCopy = cloneDeep(path.get('value').node) + const valueCopy = cloneDeep(path.get('value').node) + + if (typeof valueCopy === 'undefined' || t.isJSXFragment(valueCopy)) { + return + } + transformIf(name.name, path, jsx, valueCopy) const loopItem = transformLoop(name.name, path, jsx, valueCopy) if (loopItem) { @@ -189,8 +198,8 @@ export const createWxmlVistor = ( JSXAttribute: jsxAttrVisitor, JSXIdentifier: renameJSXKey }) - const slotAttr = attrs.find(a => a.node?.name.name === 'slot') - if (slotAttr) { + const slotAttr = attrs.find(a => t.isJSXAttribute(a.node) && a.node?.name.name === 'slot') + if (slotAttr && t.isJSXAttribute(slotAttr.node)) { const slotValue = slotAttr.node.value if (slotValue && t.isStringLiteral(slotValue)) { const slotName = slotValue.value @@ -216,9 +225,9 @@ export const createWxmlVistor = ( } const tagName = jsxName.node.name if (tagName === 'Slot') { - const nameAttr = attrs.find(a => a.node.name.name === 'name') + const nameAttr = attrs.find(a => t.isJSXAttribute(a.node) && a.node.name.name === 'name') let slotName = '' - if (nameAttr) { + if (nameAttr && t.isJSXAttribute(nameAttr.node)) { if (nameAttr.node.value && t.isStringLiteral(nameAttr.node.value)) { slotName = nameAttr.node.value.value } else { @@ -236,7 +245,7 @@ export const createWxmlVistor = ( } } if (tagName === 'Wxs') { - wxses.push(getWXS(attrs.map(a => a.node), path, imports)) + wxses.push(getWXS(attrs.map(a => a.node as t.JSXAttribute), path, imports)) } if (tagName === 'Template') { // path.traverse({ @@ -466,8 +475,8 @@ function transformLoop ( return } const attrs = jsxElement.get('attributes').map(a => a.node) - const wxForItem = attrs.find(a => a.name.name === WX_FOR_ITEM) - const hasSinglewxForItem = wxForItem && wxForItem.value && t.isJSXExpressionContainer(wxForItem.value) + const wxForItem = attrs.find(a => t.isJSXAttribute(a) && a.name.name === WX_FOR_ITEM) + const hasSinglewxForItem = wxForItem && t.isJSXAttribute(wxForItem) && wxForItem.value && t.isJSXExpressionContainer(wxForItem.value) if (hasSinglewxForItem || name === WX_FOR || name === 'wx:for-items') { if (!value || !t.isJSXExpressionContainer(value)) { throw new Error('wx:for 的值必须使用 "{{}}" 包裹') @@ -479,7 +488,7 @@ function transformLoop ( .get('openingElement') .get('attributes') .forEach(p => { - const node = p.node + const node = p.node as t.JSXAttribute if (node.name.name === WX_FOR_ITEM) { if (!node.value || !t.isStringLiteral(node.value)) { throw new Error(WX_FOR_ITEM + ' 的值必须是一个字符串') @@ -500,7 +509,7 @@ function transformLoop ( .get('openingElement') .get('attributes') .forEach(p => { - const node = p.node + const node = p.node as t.JSXAttribute if (node.name.name === WX_KEY && t.isStringLiteral(node.value)) { if (node.value.value === '*this') { node.value = t.jSXExpressionContainer(t.identifier(item.value)) @@ -510,6 +519,10 @@ function transformLoop ( } }) + if (t.isJSXEmptyExpression(value.expression)) { + printLog(processTypeEnum.WARNING, 'value.expression', 'wxml.ts -> t.isJSXEmptyExpression(value.expression)') + return + } const replacement = t.jSXExpressionContainer( t.callExpression( t.memberExpression(value.expression, t.identifier('map')), @@ -546,13 +559,13 @@ function transformIf ( if (name !== WX_IF) { return } - if (jsx.node.openingElement.attributes.some(a => a.name.name === 'slot')) { + if (jsx.node.openingElement.attributes.some(a => t.isJSXAttribute(a) && a.name.name === 'slot')) { return } const conditions: Condition[] = [] let siblings: NodePath[] = [] try { - siblings = jsx.getAllNextSiblings().filter(s => !(s.isJSXExpressionContainer() && s.get('expression').isJSXEmptyExpression())) + siblings = jsx.getAllNextSiblings().filter(s => !(s.isJSXExpressionContainer() && t.isJSXEmptyExpression(s.get('expression')))) as any } catch (error) { return } @@ -569,9 +582,9 @@ function transformIf ( }) attr.remove() for (let index = 0; index < siblings.length; index++) { - const sibling = siblings[index] - const next = cloneDeep(siblings[index + 1]) - const currMatches = findWXIfProps(sibling) + const sibling = siblings[index] as NodePath + const next = cloneDeep(siblings[index + 1]) as NodePath + const currMatches = findWXIfProps(sibling) const nextMatches = findWXIfProps(next) if (currMatches === null) { break @@ -591,14 +604,16 @@ function transformIf ( function handleConditions (conditions: Condition[]) { if (conditions.length === 1) { const ct = conditions[0] - try { - ct.path.replaceWith( - t.jSXExpressionContainer( - t.logicalExpression('&&', ct.tester.expression, cloneDeep(ct.path.node)) + if (!t.isJSXEmptyExpression(ct.tester.expression)) { + try { + ct.path.replaceWith( + t.jSXExpressionContainer( + t.logicalExpression('&&', ct.tester.expression, cloneDeep(ct.path.node)) + ) ) - ) - } catch (error) { - // + } catch (error) { + // + } } } if (conditions.length > 1) { @@ -606,7 +621,7 @@ function handleConditions (conditions: Condition[]) { const lastCon = conditions[lastLength] let lastAlternate: t.Expression = cloneDeep(lastCon.path.node) try { - if (lastCon.condition === WX_ELSE_IF) { + if (lastCon.condition === WX_ELSE_IF && !t.isJSXEmptyExpression(lastCon.tester.expression)) { lastAlternate = t.logicalExpression( '&&', lastCon.tester.expression, @@ -616,14 +631,20 @@ function handleConditions (conditions: Condition[]) { const node = conditions .slice(0, lastLength) .reduceRight((acc: t.Expression, condition) => { + if (t.isJSXEmptyExpression(condition.tester.expression)) { + printLog(processTypeEnum.WARNING, 'condition.tester.expression', 't.isJSXEmptyExpression(condition.tester.expression)') + return null + } return t.conditionalExpression( condition.tester.expression, cloneDeep(condition.path.node), acc ) }, lastAlternate) - conditions[0].path.replaceWith(t.jSXExpressionContainer(node)) - conditions.slice(1).forEach(c => c.path.remove()) + if (node != null) { + conditions[0].path.replaceWith(t.jSXExpressionContainer(node)) + conditions.slice(1).forEach(c => c.path.remove()) + } } catch (error) { console.error('wx:elif 的值需要用双括号 `{{}}` 包裹它的值') } @@ -631,7 +652,7 @@ function handleConditions (conditions: Condition[]) { } function findWXIfProps ( - jsx: NodePath + jsx: NodePath ): { reg: RegExpMatchArray, tester: AttrValue } | null { let matches: { reg: RegExpMatchArray, tester: AttrValue } | null = null jsx && @@ -640,8 +661,8 @@ function findWXIfProps ( .get('openingElement') .get('attributes') .some(path => { - const attr = path.node - if (t.isJSXIdentifier(attr.name)) { + const attr = path.node as any + if (t.isJSXIdentifier(attr.name) && attr != null) { const name = attr.name.name if (name === WX_IF) { return true @@ -816,7 +837,7 @@ function parseAttribute (attr: Attribute) { } } else if (content.includes(':') || (content.includes('...') && content.includes(','))) { const file = parseFile(`var a = ${attr.value!.slice(1, attr.value!.length - 1)}`, { plugins: ['objectRestSpread'] }) - expr = file.program.body[0].declarations[0].init + expr = (file.program.body[0] as any).declarations[0].init } else { const err = `转换模板参数: \`${key}: ${value}\` 报错` throw new Error(err)