From 6dfe0173c0ef7bfb6abd431f5ef0130f379d43e8 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 23 Jul 2022 20:49:04 +0200 Subject: [PATCH 01/44] feat!: Migrate to babel toolchain BREAKING CHANGE: Internally react-docgen now uses babel only. There are tons of breaking changes in this new version. Read the MIGRATE.md Release-As: v6.0.0-alpha.4 --- .eslintrc.js | 5 +- README.md | 3 +- bin/__tests__/react-docgen-test.ts | 2 +- package.json | 22 +- src/Documentation.ts | 43 +- src/FileState.ts | 86 + src/__tests__/__snapshots__/main-test.ts.snap | 3355 +++++++++-------- src/__tests__/main-test.ts | 44 +- src/__tests__/parse-test.ts | 14 +- src/babelParser.ts | 46 +- .../componentMethodsHandler-test.ts.snap | 4 +- .../defaultPropsHandler-test.ts.snap | 52 + .../componentDocblockHandler-test.ts | 253 +- .../__tests__/componentMethodsHandler-test.ts | 85 +- .../componentMethodsJsDocHandler-test.ts | 2 +- .../__tests__/defaultPropsHandler-test.ts | 234 +- .../__tests__/displayNameHandler-test.ts | 402 +- .../__tests__/flowTypeHandler-test.ts | 218 +- .../__tests__/propDocblockHandler-test.ts | 81 +- .../propTypeCompositionHandler-test.ts | 70 +- .../__tests__/propTypeHandler-test.ts | 156 +- src/handlers/componentDocblockHandler.ts | 43 +- src/handlers/componentMethodsHandler.ts | 130 +- src/handlers/defaultPropsHandler.ts | 175 +- src/handlers/displayNameHandler.ts | 62 +- src/handlers/flowTypeHandler.ts | 92 +- src/handlers/index.ts | 13 +- src/handlers/propDocBlockHandler.ts | 36 +- src/handlers/propTypeCompositionHandler.ts | 53 +- src/handlers/propTypeHandler.ts | 81 +- src/importer/ignoreImports.ts | 8 +- src/importer/index.ts | 17 + src/importer/makeFsImporter.ts | 170 +- src/main.ts | 47 +- src/parse.ts | 64 +- ...lExportedComponentDefinitions-test.ts.snap | 3221 ++++++++++++++++ .../findAllComponentDefinitions-test.ts | 109 +- ...indAllExportedComponentDefinitions-test.ts | 948 ++--- .../findExportedComponentDefinition-test.ts | 572 +-- src/resolver/findAllComponentDefinitions.ts | 56 +- .../findAllExportedComponentDefinitions.ts | 138 +- .../findExportedComponentDefinition.ts | 146 +- src/resolver/index.ts | 7 +- .../getClassMemberValuePath-test.ts.snap | 93 + .../__snapshots__/getMembers-test.ts.snap | 635 +--- .../getMethodDocumentation-test.ts.snap | 99 + .../__snapshots__/getNameOrValue-test.ts.snap | 13 + ...resolveGenericTypeAnnotations-test.ts.snap | 56 - src/utils/__tests__/docblock-test.ts | 8 +- src/utils/__tests__/expressionTo-test.ts | 50 +- src/utils/__tests__/flowUtilityTypes-test.ts | 75 +- .../__tests__/getClassMemberValuePath-test.ts | 111 +- src/utils/__tests__/getFlowType-test.ts | 854 +++-- .../__tests__/getMemberExpressionRoot-test.ts | 19 +- .../getMemberExpressionValuePath-test.ts | 40 +- .../__tests__/getMemberValuePath-test.ts | 105 +- src/utils/__tests__/getMembers-test.ts | 10 +- .../__tests__/getMethodDocumentation-test.ts | 240 +- src/utils/__tests__/getNameOrValue-test.ts | 28 + src/utils/__tests__/getParameterName-test.ts | 36 +- src/utils/__tests__/getPropType-test.ts | 281 +- src/utils/__tests__/getPropertyName-test.ts | 94 +- .../__tests__/getPropertyValuePath-test.ts | 68 +- src/utils/__tests__/getTSType-test.ts | 684 ++-- src/utils/__tests__/getTypeAnnotation-test.ts | 9 +- .../isDestructuringAssignment-test.ts | 10 +- .../isExportsOrModuleAssignment-test.ts | 18 +- .../__tests__/isReactCloneElementCall-test.ts | 53 +- .../__tests__/isReactComponentClass-test.ts | 165 +- .../__tests__/isReactComponentMethod-test.ts | 50 +- .../__tests__/isReactCreateClassCall-test.ts | 79 +- .../isReactCreateElementCall-test.ts | 55 +- .../__tests__/isReactForwardRefCall-test.ts | 57 +- .../__tests__/isRequiredPropType-test.ts | 22 +- .../__tests__/isStatelessComponent-test.ts | 117 +- .../__tests__/isUnreachableFlowType-test.ts | 12 +- src/utils/__tests__/match-test.ts | 4 +- .../normalizeClassDefinition-test.ts | 123 +- src/utils/__tests__/printValue-test.ts | 35 +- .../resolveExportDeclaration-test.ts | 56 +- .../resolveGenericTypeAnnotations-test.ts | 16 +- src/utils/__tests__/resolveHOC-test.ts | 104 +- .../resolveObjectKeysToArray-test.ts | 77 +- .../resolveObjectValuesToArray-test.ts | 85 +- src/utils/__tests__/resolveToModule-test.ts | 70 +- src/utils/__tests__/resolveToValue-test.ts | 180 +- .../__tests__/setPropDescription-test.ts | 21 +- src/utils/docblock.ts | 19 +- src/utils/expressionTo.ts | 71 +- src/utils/flowUtilityTypes.ts | 21 +- src/utils/getClassMemberValuePath.ts | 52 +- src/utils/getFlowType.ts | 294 +- src/utils/getFlowTypeFromReactComponent.ts | 154 - src/utils/getMemberExpressionRoot.ts | 18 +- src/utils/getMemberExpressionValuePath.ts | 97 +- src/utils/getMemberValuePath.ts | 146 +- src/utils/getMembers.ts | 51 +- src/utils/getMethodDocumentation.ts | 254 +- src/utils/getNameOrValue.ts | 26 +- src/utils/getParameterName.ts | 63 +- src/utils/getPropType.ts | 178 +- src/utils/getPropertyName.ts | 64 +- src/utils/getPropertyValuePath.ts | 31 +- src/utils/getTSType.ts | 331 +- src/utils/getTypeAnnotation.ts | 25 +- src/utils/getTypeFromReactComponent.ts | 160 + src/utils/getTypeIdentifier.ts | 13 + src/utils/getTypeParameters.ts | 55 +- src/utils/index.ts | 44 +- src/utils/isDestructuringAssignment.ts | 16 +- src/utils/isExportsOrModuleAssignment.ts | 17 +- src/utils/isReactBuiltinCall.ts | 79 +- src/utils/isReactChildrenElementCall.ts | 23 +- src/utils/isReactCloneElementCall.ts | 9 +- src/utils/isReactComponentClass.ts | 81 +- src/utils/isReactComponentMethod.ts | 15 +- src/utils/isReactCreateClassCall.ts | 24 +- src/utils/isReactCreateElementCall.ts | 9 +- src/utils/isReactForwardRefCall.ts | 10 +- src/utils/isReactModuleName.ts | 6 +- src/utils/isRequiredPropType.ts | 12 +- src/utils/isStatelessComponent.ts | 189 +- src/utils/isUnreachableFlowType.ts | 11 +- src/utils/match.ts | 9 +- src/utils/normalizeClassDefinition.ts | 100 +- src/utils/parseJsDoc.ts | 8 +- src/utils/postProcessDocumentation.ts | 22 +- src/utils/printValue.ts | 44 +- src/utils/resolveExportDeclaration.ts | 40 +- .../resolveFunctionDefinitionToReturnValue.ts | 34 +- src/utils/resolveGenericTypeAnnotation.ts | 40 +- src/utils/resolveHOC.ts | 43 +- src/utils/resolveObjectKeysToArray.ts | 140 +- src/utils/resolveObjectValuesToArray.ts | 166 +- src/utils/resolveToModule.ts | 78 +- src/utils/resolveToValue.ts | 266 +- src/utils/setPropDescription.ts | 16 +- src/utils/traverse.ts | 48 +- src/utils/ts-types/index.ts | 176 + tests/NodePathSerializer.js | 17 +- tests/setupTestFramework.ts | 33 +- tests/utils.ts | 289 +- tsconfig.json | 7 +- yarn.lock | 145 +- 144 files changed, 12442 insertions(+), 8329 deletions(-) create mode 100644 src/FileState.ts create mode 100644 src/resolver/__tests__/__snapshots__/findAllExportedComponentDefinitions-test.ts.snap create mode 100644 src/utils/__tests__/__snapshots__/getClassMemberValuePath-test.ts.snap create mode 100644 src/utils/__tests__/__snapshots__/getNameOrValue-test.ts.snap create mode 100644 src/utils/__tests__/getNameOrValue-test.ts delete mode 100644 src/utils/getFlowTypeFromReactComponent.ts create mode 100644 src/utils/getTypeFromReactComponent.ts create mode 100644 src/utils/getTypeIdentifier.ts create mode 100644 src/utils/ts-types/index.ts diff --git a/.eslintrc.js b/.eslintrc.js index a52a8921957..8af62029cbb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -8,10 +8,10 @@ module.exports = { sourceType: 'module', }, rules: { - strict: ['error', 'never'], 'no-shadow': 'error', 'no-var': 'error', 'prefer-const': 'error', + strict: ['error', 'never'], }, env: { node: true, @@ -36,6 +36,9 @@ module.exports = { rules: { '@typescript-eslint/array-type': ['error', { default: 'array-simple' }], '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/consistent-type-imports': 'error', + '@typescript-eslint/no-duplicate-imports': 'error', + '@typescript-eslint/sort-type-union-intersection-members': 'error', }, }, { diff --git a/README.md b/README.md index 2a9acd60d8a..8d1ab41d9d2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ `react-docgen` is a CLI and toolbox to help extracting information from [React][] components, and generate documentation from it. -It uses [ast-types][] and [@babel/parser][] to parse the source into an AST and provides methods to process this AST to extract the desired information. The output / return value is a JSON blob / JavaScript object. +It uses [@babel/parser][] to parse the source into an AST and provides methods to process this AST to extract the desired information. The output / return value is a JSON blob / JavaScript object. It provides a default implementation for React components defined via `React.createClass`, [ES2015 class definitions][classes] or functions @@ -425,6 +425,5 @@ The structure of the JSON blob / JavaScript object is as follows: [react]: http://facebook.github.io/react/ [flow]: http://flowtype.org/ [typescript]: http://typescriptlang.org/ -[ast-types]: https://github.com/benjamn/ast-types [@babel/parser]: https://github.com/babel/babel/tree/master/packages/babel-parser [classes]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes diff --git a/bin/__tests__/react-docgen-test.ts b/bin/__tests__/react-docgen-test.ts index 9b31b71537f..d2923e234d3 100644 --- a/bin/__tests__/react-docgen-test.ts +++ b/bin/__tests__/react-docgen-test.ts @@ -36,7 +36,7 @@ const component = fs.readFileSync( path.join(__dirname, '__fixtures__/Component.js'), ); -describe('react-docgen CLI', () => { +describe.skip('react-docgen CLI', () => { let tempDir = ''; let tempComponents: string[] = []; let tempNoComponents: string[] = []; diff --git a/package.json b/package.json index 233f451b42f..e5522bc70e5 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dist" ], "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "main": "dist/main.js", "typings": "dist/main.d.ts", @@ -31,10 +31,8 @@ "lint": "eslint . --ext .js,.ts --report-unused-disable-directives", "fix": "eslint . --ext .js,.ts --fix --report-unused-disable-directives", "prepare": "yarn build", - "preversion": "yarn lint", "start": "cd website && yarn && yarn start", - "test": "yarn build && jest", - "watch": "yarn build --watch" + "test": "yarn build && jest" }, "keywords": [ "react", @@ -45,21 +43,23 @@ }, "license": "MIT", "dependencies": { - "@babel/core": "^7.7.5", - "@babel/generator": "^7.12.11", - "ast-types": "^0.14.2", + "@babel/core": "^7.18.9", + "@babel/generator": "^7.18.9", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", "commander": "^2.19.0", "doctrine": "^3.0.0", - "estree-to-babel": "^3.1.0", - "neo-async": "^2.6.1", - "node-dir": "^0.1.10", - "resolve": "^1.17.0", + "neo-async": "^2.6.2", + "node-dir": "^0.1.17", + "resolve": "^1.22.1", "strip-indent": "^3.0.0" }, "devDependencies": { + "@types/babel__traverse": "7.17.1", "@types/cross-spawn": "6.0.2", "@types/doctrine": "0.0.5", "@types/jest": "28.1.6", + "@types/resolve": "1.20.2", "@types/rimraf": "3.0.2", "@typescript-eslint/eslint-plugin": "5.32.0", "@typescript-eslint/parser": "5.32.0", diff --git a/src/Documentation.ts b/src/Documentation.ts index 332465341b1..c8bce1513e5 100644 --- a/src/Documentation.ts +++ b/src/Documentation.ts @@ -9,14 +9,14 @@ export interface DocumentationObject { export interface MethodParameter { name: string; type?: TypeDescriptor | null; - optional?: boolean; + optional: boolean; } export interface MethodReturn { type: TypeDescriptor | undefined; } -export type MethodModifier = 'static' | 'generator' | 'async' | 'get' | 'set'; +export type MethodModifier = 'async' | 'generator' | 'get' | 'set' | 'static'; export interface MethodDescriptor { name: string; @@ -29,25 +29,25 @@ export interface MethodDescriptor { export interface PropTypeDescriptor { name: + | 'any' + | 'array' | 'arrayOf' + | 'bool' | 'custom' + | 'element' + | 'elementType' | 'enum' - | 'array' - | 'bool' + | 'exact' | 'func' + | 'instanceOf' + | 'node' | 'number' | 'object' - | 'string' - | 'any' - | 'element' - | 'node' - | 'symbol' | 'objectOf' | 'shape' - | 'exact' - | 'union' - | 'elementType' - | 'instanceOf'; + | 'string' + | 'symbol' + | 'union'; value?: unknown; raw?: string; computed?: boolean; @@ -57,6 +57,11 @@ export interface PropTypeDescriptor { required?: boolean; } +export interface DefaultValueDescriptor { + value: unknown; + computed: boolean; +} + export interface BaseType { required?: boolean; nullable?: boolean; @@ -91,14 +96,14 @@ export interface FunctionSignatureType extends BaseType { raw: string; signature: { arguments: Array>; - return: TypeDescriptor; + return?: TypeDescriptor; }; } export interface TSFunctionSignatureType extends FunctionSignatureType { signature: { arguments: Array>; - return: TypeDescriptor; + return?: TypeDescriptor; this?: TypeDescriptor; }; } @@ -110,7 +115,7 @@ export interface ObjectSignatureType raw: string; signature: { properties: Array<{ - key: string | TypeDescriptor; + key: TypeDescriptor | string; value: TypeDescriptor; }>; constructor?: TypeDescriptor; @@ -118,10 +123,10 @@ export interface ObjectSignatureType } export type TypeDescriptor = - | SimpleType - | LiteralType | ElementsType + | LiteralType | ObjectSignatureType + | SimpleType | T; export interface PropDescriptor { @@ -129,7 +134,7 @@ export interface PropDescriptor { flowType?: TypeDescriptor; tsType?: TypeDescriptor; required?: boolean; - defaultValue?: unknown; + defaultValue?: DefaultValueDescriptor; description?: string; } diff --git a/src/FileState.ts b/src/FileState.ts new file mode 100644 index 00000000000..a306ec561f1 --- /dev/null +++ b/src/FileState.ts @@ -0,0 +1,86 @@ +import type { Options, Parser } from './babelParser'; +import type { HubInterface, Scope, Visitor } from '@babel/traverse'; +import traverse, { NodePath } from '@babel/traverse'; +import type { File, Node, Program } from '@babel/types'; +import type { Importer, ImportPath } from './importer'; + +export default class FileState { + opts: Options; + path: NodePath; + ast: File; + scope: Scope; + code: string; + + #importer: Importer; + #parser: Parser; + + hub: HubInterface = { + // keep it for the usage in babel-core, ex: path.hub.file.opts.filename + file: this, + parse: this.parse.bind(this), + import: this.import.bind(this), + getCode: () => this.code, + getScope: () => this.scope, + addHelper: () => undefined, + buildError: ( + node: Node, + msg: string, + Error: new (message?: string) => E, + ): E & { node: Node } => { + const err = new Error(msg); + (err as E & { node: Node }).node = node; + return err as E & { node: Node }; + }, + }; + + constructor( + options: Options, + { + code, + ast, + importer, + parser, + }: { code: string; ast: File; importer: Importer; parser: Parser }, + ) { + this.opts = options; + this.code = code; + this.ast = ast; + this.#importer = importer; + this.#parser = parser; + + this.path = NodePath.get({ + hub: this.hub, + parentPath: null, + parent: this.ast, + container: this.ast, + key: 'program', + // @ts-expect-error TODO FIX DT https://github.com/babel/babel/blob/b58e35b6aa30a4c58da3147ae4a1fb5cef2073c9/packages/babel-traverse/src/path/context.ts#L158 + }).setContext() as NodePath; + this.scope = this.path.scope; + } + + import(path: ImportPath, name: string): NodePath | null { + return this.#importer(path, name, this); + } + + /** + * Parse a new file + */ + parse(code: string): FileState { + const ast = this.#parser(code); + + return new FileState(this.opts, { + ast, + code, + importer: this.#importer, + parser: this.#parser, + }); + } + + /** + * Traverse the current file + */ + traverse(visitors: Visitor, state?: unknown): void { + traverse(this.ast, visitors, this.scope, state); + } +} diff --git a/src/__tests__/__snapshots__/main-test.ts.snap b/src/__tests__/__snapshots__/main-test.ts.snap index 82ca744c118..b3a55bf4443 100644 --- a/src/__tests__/__snapshots__/main-test.ts.snap +++ b/src/__tests__/__snapshots__/main-test.ts.snap @@ -1,285 +1,467 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`main fixtures processes component "component_1.js" without errors 1`] = ` -Object { - "description": "The is a component to test the document generation", - "displayName": "Component", - "methods": Array [], -} +exports[`main Class definition parses with custom handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + }, +] `; -exports[`main fixtures processes component "component_2.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "button", - "methods": Array [ - Object { - "docblock": null, - "modifiers": Array [ - "static", - "get", - ], - "name": "displayName", - "params": Array [], - "returns": null, - }, - Object { - "docblock": null, - "modifiers": Array [ - "static", - "get", - ], - "name": "defaultProps", - "params": Array [], - "returns": null, - }, - ], - "props": Object { - "type": Object { - "defaultValue": Object { - "computed": false, - "value": "\\"primary\\"", - }, - "required": false, +exports[`main Class definition parses with default resolver/handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + "displayName": "ABC", + "methods": Array [], + "props": Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "true", + }, + "description": "Example prop description", + "required": false, + "type": Object { + "name": "bool", + }, + }, }, }, -} +] `; -exports[`main fixtures processes component "component_3.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Test", - "methods": Array [], - "props": Object { - "style": Object { - "description": "", - "required": false, - "type": Object { - "name": "object", - }, - }, +exports[`main React.createClass parses with custom handlers 1`] = ` +Array [ + Object { + "description": "Example component description", }, -} +] `; -exports[`main fixtures processes component "component_4.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Parent", - "methods": Array [], - "props": Object { - "child": Object { - "description": "", - "required": true, - "type": Object { - "computed": true, - "name": "shape", - "value": "Child.propTypes", +exports[`main React.createClass parses with default resolver/handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + "displayName": "ABC", + "methods": Array [ + Object { + "docblock": null, + "modifiers": Array [], + "name": "getDefaultProps", + "params": Array [], + "returns": null, + }, + ], + "props": Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "true", + }, + "description": "Example prop description", + "required": false, + "type": Object { + "name": "bool", + }, }, }, - "childExact": Object { - "description": "", - "required": true, - "type": Object { - "computed": true, - "name": "exact", - "value": "Child.propTypes", + }, +] +`; + +exports[`main Stateless Component definition: ArrowFunctionExpression parses with custom handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + }, +] +`; + +exports[`main Stateless Component definition: ArrowFunctionExpression parses with default resolver/handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + "displayName": "ABC", + "methods": Array [], + "props": Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "true", + }, + "description": "Example prop description", + "required": false, + "type": Object { + "name": "bool", + }, }, }, - "extendedChild": Object { - "description": "", - "required": true, - "type": Object { - "name": "shape", - "value": Object { - "adopted": Object { - "name": "bool", - "required": true, - }, + }, +] +`; + +exports[`main Stateless Component definition: FunctionDeclaration parses with custom handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + }, +] +`; + +exports[`main Stateless Component definition: FunctionDeclaration parses with default resolver/handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + "displayName": "ABC", + "methods": Array [], + "props": Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "true", + }, + "description": "Example prop description", + "required": false, + "type": Object { + "name": "bool", }, }, }, - "extendedChildExact": Object { - "description": "", - "required": true, - "type": Object { - "name": "exact", - "value": Object { - "adopted": Object { - "name": "bool", - "required": true, - }, + }, +] +`; + +exports[`main Stateless Component definition: FunctionExpression parses with custom handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + }, +] +`; + +exports[`main Stateless Component definition: FunctionExpression parses with default resolver/handlers 1`] = ` +Array [ + Object { + "description": "Example component description", + "displayName": "ABC", + "methods": Array [], + "props": Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "true", + }, + "description": "Example prop description", + "required": false, + "type": Object { + "name": "bool", }, }, }, - "something": Object { - "description": "", - "required": true, + }, +] +`; + +exports[`main fixtures processes component "component_1.js" without errors 1`] = ` +Array [ + Object { + "description": "The is a component to test the document generation", + "displayName": "Component", + "methods": Array [], + }, +] +`; + +exports[`main fixtures processes component "component_2.js" without errors 1`] = ` +Array [ + Object { + "description": "", + "displayName": "button", + "methods": Array [ + Object { + "docblock": null, + "modifiers": Array [ + "static", + "get", + ], + "name": "displayName", + "params": Array [], + "returns": null, + }, + Object { + "docblock": null, + "modifiers": Array [ + "static", + "get", + ], + "name": "defaultProps", + "params": Array [], + "returns": null, + }, + ], + "props": Object { "type": Object { - "name": "string", + "defaultValue": Object { + "computed": false, + "value": "\\"primary\\"", + }, + "required": false, }, }, }, -} +] `; -exports[`main fixtures processes component "component_5.js" without errors 1`] = ` -Object { - "childContext": Object { - "color": Object { - "required": false, - "type": Object { - "name": "string", +exports[`main fixtures processes component "component_3.js" without errors 1`] = ` +Array [ + Object { + "description": "", + "displayName": "Test", + "methods": Array [], + "props": Object { + "style": Object { + "description": "", + "required": false, + "type": Object { + "name": "object", + }, }, }, }, - "context": Object { - "config": Object { - "required": false, - "type": Object { - "name": "object", +] +`; + +exports[`main fixtures processes component "component_4.js" without errors 1`] = ` +Array [ + Object { + "description": "", + "displayName": "Parent", + "methods": Array [], + "props": Object { + "child": Object { + "description": "", + "required": true, + "type": Object { + "computed": true, + "name": "shape", + "value": "Child.propTypes", + }, + }, + "childExact": Object { + "description": "", + "required": true, + "type": Object { + "computed": true, + "name": "exact", + "value": "Child.propTypes", + }, + }, + "extendedChild": Object { + "description": "", + "required": true, + "type": Object { + "name": "shape", + "value": Object { + "adopted": Object { + "name": "bool", + "required": true, + }, + }, + }, + }, + "extendedChildExact": Object { + "description": "", + "required": true, + "type": Object { + "name": "exact", + "value": Object { + "adopted": Object { + "name": "bool", + "required": true, + }, + }, + }, + }, + "something": Object { + "description": "", + "required": true, + "type": Object { + "name": "string", + }, }, }, }, - "description": "", - "displayName": "Button", - "methods": Array [], - "props": Object { - "children": Object { - "description": "", - "required": true, - "type": Object { - "name": "string", +] +`; + +exports[`main fixtures processes component "component_5.js" without errors 1`] = ` +Array [ + Object { + "childContext": Object { + "color": Object { + "required": false, + "type": Object { + "name": "string", + }, }, }, - "onClick": Object { - "description": "", - "required": false, - "type": Object { - "name": "func", + "context": Object { + "config": Object { + "required": false, + "type": Object { + "name": "object", + }, }, }, - "style": Object { - "defaultValue": Object { - "computed": false, - "value": "{}", + "description": "", + "displayName": "Button", + "methods": Array [], + "props": Object { + "children": Object { + "description": "", + "required": true, + "type": Object { + "name": "string", + }, }, - "description": "", - "required": false, - "type": Object { - "name": "object", + "onClick": Object { + "description": "", + "required": false, + "type": Object { + "name": "func", + }, + }, + "style": Object { + "defaultValue": Object { + "computed": false, + "value": "{}", + }, + "description": "", + "required": false, + "type": Object { + "name": "object", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_6.js" without errors 1`] = ` -Object { - "childContext": Object { - "color": Object { - "required": false, - "type": Object { - "name": "string", - }, - }, - }, - "context": Object { - "config": Object { - "required": false, - "type": Object { - "name": "object", +Array [ + Object { + "childContext": Object { + "color": Object { + "required": false, + "type": Object { + "name": "string", + }, }, }, - }, - "description": "", - "displayName": "Button", - "methods": Array [], - "props": Object { - "children": Object { - "description": "", - "required": true, - "type": Object { - "name": "string", + "context": Object { + "config": Object { + "required": false, + "type": Object { + "name": "object", + }, }, }, - "onClick": Object { - "description": "", - "required": false, - "type": Object { - "name": "func", + "description": "", + "displayName": "Button", + "methods": Array [], + "props": Object { + "children": Object { + "description": "", + "required": true, + "type": Object { + "name": "string", + }, }, - }, - "style": Object { - "defaultValue": Object { - "computed": false, - "value": "{}", + "onClick": Object { + "description": "", + "required": false, + "type": Object { + "name": "func", + }, }, - "description": "", - "required": false, - "type": Object { - "name": "object", + "style": Object { + "defaultValue": Object { + "computed": false, + "value": "{}", + }, + "description": "", + "required": false, + "type": Object { + "name": "object", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_7.js" without errors 1`] = ` -Object { - "description": "The is a component to test the document generation", - "displayName": "Component", - "methods": Array [], -} +Array [ + Object { + "description": "The is a component to test the document generation", + "displayName": "Component", + "methods": Array [], + }, +] `; exports[`main fixtures processes component "component_8.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Parent", - "methods": Array [ - Object { - "docblock": null, - "modifiers": Array [], - "name": "onChangeSlider", - "params": Array [ - Object { - "name": "[min, max]", - "optional": undefined, - "type": null, - }, - ], - "returns": null, - }, - ], -} +Array [ + Object { + "description": "", + "displayName": "Parent", + "methods": Array [ + Object { + "docblock": null, + "modifiers": Array [], + "name": "onChangeSlider", + "params": Array [ + Object { + "name": "[min, max]", + "optional": false, + "type": null, + }, + ], + "returns": null, + }, + ], + }, +] `; exports[`main fixtures processes component "component_9.js" without errors 1`] = ` -Object { - "description": "Should be recognized as component.", - "displayName": "ExampleComponent", - "methods": Array [], -} +Array [ + Object { + "description": "Should be recognized as component.", + "displayName": "ExampleComponent", + "methods": Array [], + }, +] `; exports[`main fixtures processes component "component_10.js" without errors 1`] = ` -Object { - "description": "React component that display current time at current location.", - "displayName": "Clock", - "methods": Array [ - Object { - "description": "Update clock state with new time", - "docblock": "Update clock state with new time", - "modifiers": Array [], - "name": "updateClock", - "params": Array [], - "returns": null, - }, - Object { - "description": "Parse current Date object", - "docblock": "Parse current Date object +Array [ + Object { + "description": "React component that display current time at current location.", + "displayName": "Clock", + "methods": Array [ + Object { + "description": "Update clock state with new time", + "docblock": "Update clock state with new time", + "modifiers": Array [], + "name": "updateClock", + "params": Array [], + "returns": null, + }, + Object { + "description": "Parse current Date object", + "docblock": "Parse current Date object @returns {Object} currentTime @returns {int} currentTime.hour @@ -288,1684 +470,1759 @@ Object { @returns {string} currentTime.dayOfWeek @returns {string} currentTime.month @returns {int} currentTime.date", - "modifiers": Array [], - "name": "getTime", - "params": Array [], - "returns": Object { - "description": "currentTime", - "type": Object { - "name": "Object", + "modifiers": Array [], + "name": "getTime", + "params": Array [], + "returns": Object { + "description": "currentTime", + "type": Object { + "name": "Object", + }, }, }, - }, - Object { - "description": "Update current clock for every 1 second", - "docblock": "Update current clock for every 1 second", - "modifiers": Array [], - "name": "setTimer", - "params": Array [], - "returns": null, - }, - ], - "props": Object { - "title": Object { - "description": "A text display current's user identity, + Object { + "description": "Update current clock for every 1 second", + "docblock": "Update current clock for every 1 second", + "modifiers": Array [], + "name": "setTimer", + "params": Array [], + "returns": null, + }, + ], + "props": Object { + "title": Object { + "description": "A text display current's user identity, \\"Nobody\\" if no one is detected in the background, \\"Hi, ..name\\" if an user is detected", - "required": false, - "type": Object { - "name": "string", + "required": false, + "type": Object { + "name": "string", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_11.js" without errors 1`] = ` -Object { - "composes": Array [ - "OtherProps", - ], - "description": "", - "displayName": "MyComponent", - "methods": Array [], - "props": Object { - "fooProp": Object { - "description": "fooProp is spread in from a locally resolved type", - "flowType": Object { - "name": "string", - }, - "required": false, - }, - "prop1": Object { - "description": "The first prop", - "flowType": Object { - "name": "string", +Array [ + Object { + "composes": Array [ + "OtherProps", + ], + "description": "", + "displayName": "MyComponent", + "methods": Array [], + "props": Object { + "fooProp": Object { + "description": "fooProp is spread in from a locally resolved type", + "flowType": Object { + "name": "string", + }, + "required": false, }, - "required": true, - }, - "prop2": Object { - "description": "The second, covariant prop", - "flowType": Object { - "name": "number", + "prop1": Object { + "description": "The first prop", + "flowType": Object { + "name": "string", + }, + "required": true, + }, + "prop2": Object { + "description": "The second, covariant prop", + "flowType": Object { + "name": "number", + }, + "required": true, }, - "required": true, }, }, -} +] `; exports[`main fixtures processes component "component_12.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Paper", - "methods": Array [], - "props": Object { - "anchorOrigin": Object { - "defaultValue": Object { - "computed": false, - "value": "{ +Array [ + Object { + "description": "", + "displayName": "Paper", + "methods": Array [], + "props": Object { + "anchorOrigin": Object { + "defaultValue": Object { + "computed": false, + "value": "{ vertical: 'top', horizontal: 'left', }", - }, - "description": "This is the point on the anchor where the popover's + }, + "description": "This is the point on the anchor where the popover's \`anchorEl\` will attach to. This is not used when the anchorReference is 'anchorPosition'. Options: vertical: [top, center, bottom]; horizontal: [left, center, right].", - "flowType": Object { - "name": "signature", - "raw": "{ + "flowType": Object { + "name": "signature", + "raw": "{ horizontal: 'left' | 'center' | 'right' | number, vertical: 'top' | 'center' | 'bottom' | number, }", - "signature": Object { - "properties": Array [ - Object { - "key": "horizontal", - "value": Object { - "elements": Array [ - Object { - "name": "literal", - "value": "'left'", - }, - Object { - "name": "literal", - "value": "'center'", - }, - Object { - "name": "literal", - "value": "'right'", - }, - Object { - "name": "number", - }, - ], - "name": "union", - "raw": "'left' | 'center' | 'right' | number", - "required": true, + "signature": Object { + "properties": Array [ + Object { + "key": "horizontal", + "value": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "'left'", + }, + Object { + "name": "literal", + "value": "'center'", + }, + Object { + "name": "literal", + "value": "'right'", + }, + Object { + "name": "number", + }, + ], + "name": "union", + "raw": "'left' | 'center' | 'right' | number", + "required": true, + }, }, - }, - Object { - "key": "vertical", - "value": Object { - "elements": Array [ - Object { - "name": "literal", - "value": "'top'", - }, - Object { - "name": "literal", - "value": "'center'", - }, - Object { - "name": "literal", - "value": "'bottom'", - }, - Object { - "name": "number", - }, - ], - "name": "union", - "raw": "'top' | 'center' | 'bottom' | number", - "required": true, + Object { + "key": "vertical", + "value": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "'top'", + }, + Object { + "name": "literal", + "value": "'center'", + }, + Object { + "name": "literal", + "value": "'bottom'", + }, + Object { + "name": "number", + }, + ], + "name": "union", + "raw": "'top' | 'center' | 'bottom' | number", + "required": true, + }, }, - }, - ], + ], + }, + "type": "object", }, - "type": "object", - }, - "required": false, - }, - "children": Object { - "description": "@ignore", - "flowType": Object { - "name": "Node", + "required": false, }, - "required": false, - }, - "classes": Object { - "description": "Useful to extend the style applied to components.", - "flowType": Object { - "name": "Object", + "children": Object { + "description": "@ignore", + "flowType": Object { + "name": "Node", + }, + "required": false, }, - "required": false, - }, - "component": Object { - "defaultValue": Object { - "computed": false, - "value": "'div'", + "classes": Object { + "description": "Useful to extend the style applied to components.", + "flowType": Object { + "name": "Object", + }, + "required": false, }, - "description": "The component used for the root node. + "component": Object { + "defaultValue": Object { + "computed": false, + "value": "'div'", + }, + "description": "The component used for the root node. This currently has to be flow cast in defaultProps as of flow 0.59.0", - "flowType": Object { - "name": "ElementType", - }, - "required": false, - }, - "elevation": Object { - "defaultValue": Object { - "computed": false, - "value": "2", + "flowType": Object { + "name": "ElementType", + }, + "required": false, }, - "description": "Shadow depth, corresponds to \`dp\` in the spec. + "elevation": Object { + "defaultValue": Object { + "computed": false, + "value": "2", + }, + "description": "Shadow depth, corresponds to \`dp\` in the spec. It's accepting values between 0 and 24 inclusive.", - "flowType": Object { - "name": "number", - }, - "required": false, - }, - "labelRowsPerPage": Object { - "defaultValue": Object { - "computed": false, - "value": "'Rows per page:'", + "flowType": Object { + "name": "number", + }, + "required": false, }, - "description": "Useful to customize the rows per page label. Invoked with a \`{ from, to, count, page }\` + "labelRowsPerPage": Object { + "defaultValue": Object { + "computed": false, + "value": "'Rows per page:'", + }, + "description": "Useful to customize the rows per page label. Invoked with a \`{ from, to, count, page }\` object.", - "flowType": Object { - "name": "Node", - }, - "required": false, - }, - "timeout": Object { - "defaultValue": Object { - "computed": false, - "value": "300", + "flowType": Object { + "name": "Node", + }, + "required": false, }, - "description": "The duration for the transition, in milliseconds. + "timeout": Object { + "defaultValue": Object { + "computed": false, + "value": "300", + }, + "description": "The duration for the transition, in milliseconds. You may specify a single timeout for all transitions, or individually with an object. Set to 'auto' to automatically calculate transition time based on height.", - "flowType": Object { - "elements": Array [ - Object { - "name": "number", - }, - Object { - "name": "signature", - "raw": "{ enter?: number, exit?: number }", - "signature": Object { - "properties": Array [ - Object { - "key": "enter", - "value": Object { - "name": "number", - "required": false, + "flowType": Object { + "elements": Array [ + Object { + "name": "number", + }, + Object { + "name": "signature", + "raw": "{ enter?: number, exit?: number }", + "signature": Object { + "properties": Array [ + Object { + "key": "enter", + "value": Object { + "name": "number", + "required": false, + }, }, - }, - Object { - "key": "exit", - "value": Object { - "name": "number", - "required": false, + Object { + "key": "exit", + "value": Object { + "name": "number", + "required": false, + }, }, - }, - ], + ], + }, + "type": "object", }, - "type": "object", - }, - Object { - "name": "literal", - "value": "'auto'", - }, - ], - "name": "union", - "raw": "number | { enter?: number, exit?: number } | 'auto'", + Object { + "name": "literal", + "value": "'auto'", + }, + ], + "name": "union", + "raw": "number | { enter?: number, exit?: number } | 'auto'", + }, + "required": false, }, - "required": false, - }, - "transition": Object { - "description": "Transition component.", - "flowType": Object { - "elements": Array [ - Object { - "name": "unknown", - }, - ], - "name": "ComponentType", - "raw": "ComponentType<*>", + "transition": Object { + "description": "Transition component.", + "flowType": Object { + "elements": Array [ + Object { + "name": "unknown", + }, + ], + "name": "ComponentType", + "raw": "ComponentType<*>", + }, + "required": true, }, - "required": true, }, }, -} +] `; exports[`main fixtures processes component "component_13.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Foo", - "methods": Array [], - "props": Object { - "RootComponent": Object { - "description": "", - "flowType": Object { - "name": "ReactElementType", - "raw": "React.ElementType", - }, - "required": false, - }, - "align": Object { - "description": "", - "flowType": Object { - "elements": Array [ - Object { - "name": "literal", - "value": "\\"left\\"", - }, - Object { - "name": "literal", - "value": "\\"center\\"", - }, - Object { - "name": "literal", - "value": "\\"right\\"", - }, - Object { - "name": "literal", - "value": "\\"justify\\"", - }, - ], - "name": "union", - "raw": "\\"left\\" | \\"center\\" | \\"right\\" | \\"justify\\"", +Array [ + Object { + "description": "", + "displayName": "Foo", + "methods": Array [], + "props": Object { + "RootComponent": Object { + "description": "", + "flowType": Object { + "name": "ReactElementType", + "raw": "React.ElementType", + }, + "required": false, }, - "required": false, - }, - "capitalize": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "align": Object { + "description": "", + "flowType": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"left\\"", + }, + Object { + "name": "literal", + "value": "\\"center\\"", + }, + Object { + "name": "literal", + "value": "\\"right\\"", + }, + Object { + "name": "literal", + "value": "\\"justify\\"", + }, + ], + "name": "union", + "raw": "\\"left\\" | \\"center\\" | \\"right\\" | \\"justify\\"", + }, + "required": false, }, - "required": false, - }, - "center": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "capitalize": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "children": Object { - "description": "", - "flowType": Object { - "name": "ReactNode", - "raw": "React.Node", + "center": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "className": Object { - "description": "", - "flowType": Object { - "name": "string", + "children": Object { + "description": "", + "flowType": Object { + "name": "ReactNode", + "raw": "React.Node", + }, + "required": false, }, - "required": false, - }, - "color": Object { - "description": "", - "flowType": Object { - "name": "string", + "className": Object { + "description": "", + "flowType": Object { + "name": "string", + }, + "required": false, }, - "required": false, - }, - "justify": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "color": Object { + "description": "", + "flowType": Object { + "name": "string", + }, + "required": false, }, - "required": false, - }, - "leading": Object { - "description": "", - "flowType": Object { - "elements": Array [ - Object { - "name": "literal", - "value": "\\"none\\"", - }, - Object { - "name": "literal", - "value": "\\"tight\\"", - }, - Object { - "name": "literal", - "value": "\\"normal\\"", - }, - Object { - "name": "literal", - "value": "\\"loose\\"", - }, - ], - "name": "union", - "raw": "\\"none\\" | \\"tight\\" | \\"normal\\" | \\"loose\\"", + "justify": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "leadingLoose": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "leading": Object { + "description": "", + "flowType": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"none\\"", + }, + Object { + "name": "literal", + "value": "\\"tight\\"", + }, + Object { + "name": "literal", + "value": "\\"normal\\"", + }, + Object { + "name": "literal", + "value": "\\"loose\\"", + }, + ], + "name": "union", + "raw": "\\"none\\" | \\"tight\\" | \\"normal\\" | \\"loose\\"", + }, + "required": false, }, - "required": false, - }, - "leadingNone": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "leadingLoose": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "leadingNormal": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "leadingNone": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "leadingTight": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "leadingNormal": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "left": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "leadingTight": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "lowercase": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "left": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "muted": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "lowercase": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "right": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "muted": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "size": Object { - "description": "", - "flowType": Object { - "name": "string", + "right": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "tracking": Object { - "description": "", - "flowType": Object { - "elements": Array [ - Object { - "name": "literal", - "value": "\\"tight\\"", - }, - Object { - "name": "literal", - "value": "\\"normal\\"", - }, - Object { - "name": "literal", - "value": "\\"wide\\"", - }, - ], - "name": "union", - "raw": "\\"tight\\" | \\"normal\\" | \\"wide\\"", + "size": Object { + "description": "", + "flowType": Object { + "name": "string", + }, + "required": false, }, - "required": false, - }, - "trackingNormal": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "tracking": Object { + "description": "", + "flowType": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"tight\\"", + }, + Object { + "name": "literal", + "value": "\\"normal\\"", + }, + Object { + "name": "literal", + "value": "\\"wide\\"", + }, + ], + "name": "union", + "raw": "\\"tight\\" | \\"normal\\" | \\"wide\\"", + }, + "required": false, }, - "required": false, - }, - "trackingTight": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "trackingNormal": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "trackingWide": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "trackingTight": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "transform": Object { - "description": "", - "flowType": Object { - "elements": Array [ - Object { - "name": "literal", - "value": "\\"lowercase\\"", - }, - Object { - "name": "literal", - "value": "\\"uppercase\\"", - }, - Object { - "name": "literal", - "value": "\\"capitalize\\"", - }, - ], - "name": "union", - "raw": "\\"lowercase\\" | \\"uppercase\\" | \\"capitalize\\"", + "trackingWide": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, - }, - "uppercase": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "transform": Object { + "description": "", + "flowType": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"lowercase\\"", + }, + Object { + "name": "literal", + "value": "\\"uppercase\\"", + }, + Object { + "name": "literal", + "value": "\\"capitalize\\"", + }, + ], + "name": "union", + "raw": "\\"lowercase\\" | \\"uppercase\\" | \\"capitalize\\"", + }, + "required": false, }, - "required": false, - }, - "wrap": Object { - "description": "", - "flowType": Object { - "name": "boolean", + "uppercase": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, + }, + "wrap": Object { + "description": "", + "flowType": Object { + "name": "boolean", + }, + "required": false, }, - "required": false, }, }, -} +] `; exports[`main fixtures processes component "component_14.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "UncoloredView", - "methods": Array [], - "props": Object { - "color": Object { - "description": "", - "flowType": Object { - "name": "string", - "nullable": true, - }, - "required": false, +Array [ + Object { + "description": "", + "displayName": "UncoloredView", + "methods": Array [], + "props": Object { + "color": Object { + "description": "", + "flowType": Object { + "name": "string", + "nullable": true, + }, + "required": false, + }, }, }, -} +] `; exports[`main fixtures processes component "component_15.js" without errors 1`] = ` -Object { - "composes": Array [ - "BarProps", - "BarProps2", - "BarProps3", - ], - "description": "", - "displayName": "Foo", - "methods": Array [], - "props": Object { - "other": Object { - "description": "", - "flowType": Object { - "name": "literal", - "value": "'a'", - }, - "required": true, - }, - "other2": Object { - "description": "", - "flowType": Object { - "name": "literal", - "value": "'b'", +Array [ + Object { + "composes": Array [ + "BarProps", + "BarProps2", + "BarProps3", + ], + "description": "", + "displayName": "Foo", + "methods": Array [], + "props": Object { + "other": Object { + "description": "", + "flowType": Object { + "name": "literal", + "value": "'a'", + }, + "required": true, }, - "required": true, - }, - "other3": Object { - "description": "", - "flowType": Object { - "name": "literal", - "value": "'c'", + "other2": Object { + "description": "", + "flowType": Object { + "name": "literal", + "value": "'b'", + }, + "required": true, }, - "required": true, - }, - "other4": Object { - "description": "", - "flowType": Object { - "name": "literal", - "value": "'g'", + "other3": Object { + "description": "", + "flowType": Object { + "name": "literal", + "value": "'c'", + }, + "required": true, }, - "required": true, - }, - "other5": Object { - "description": "", - "flowType": Object { - "name": "literal", - "value": "'f'", + "other4": Object { + "description": "", + "flowType": Object { + "name": "literal", + "value": "'g'", + }, + "required": true, }, - "required": true, - }, - "somePropOverride": Object { - "description": "", - "flowType": Object { - "name": "literal", - "value": "'baz'", + "other5": Object { + "description": "", + "flowType": Object { + "name": "literal", + "value": "'f'", + }, + "required": true, + }, + "somePropOverride": Object { + "description": "", + "flowType": Object { + "name": "literal", + "value": "'baz'", + }, + "required": true, }, - "required": true, }, }, -} +] `; exports[`main fixtures processes component "component_16.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Foo", - "methods": Array [], - "props": Object { - "bar": Object { - "defaultValue": Object { - "computed": false, - "value": "null", - }, - "description": "This does something.", - "required": false, - "type": Object { - "name": "custom", - "raw": "PropTypes.node", +Array [ + Object { + "description": "", + "displayName": "Foo", + "methods": Array [], + "props": Object { + "bar": Object { + "defaultValue": Object { + "computed": false, + "value": "null", + }, + "description": "This does something.", + "required": false, + "type": Object { + "name": "custom", + "raw": "PropTypes.node", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_17.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Foo", - "methods": Array [], - "props": Object { - "exactProp": Object { - "description": "", - "required": false, - "type": Object { - "name": "exact", - "value": Object { - "c": Object { - "description": "Comment for property c", - "name": "string", - "required": false, - }, - "d": Object { - "name": "number", - "required": false, +Array [ + Object { + "description": "", + "displayName": "Foo", + "methods": Array [], + "props": Object { + "exactProp": Object { + "description": "", + "required": false, + "type": Object { + "name": "exact", + "value": Object { + "c": Object { + "description": "Comment for property c", + "name": "string", + "required": false, + }, + "d": Object { + "name": "number", + "required": false, + }, }, }, }, - }, - "oneOfTypeProp": Object { - "description": "", - "required": false, - "type": Object { - "name": "union", - "value": Array [ - Object { - "description": "Comment for type string", - "name": "string", - }, - Object { - "name": "number", - }, - ], + "oneOfTypeProp": Object { + "description": "", + "required": false, + "type": Object { + "name": "union", + "value": Array [ + Object { + "description": "Comment for type string", + "name": "string", + }, + Object { + "name": "number", + }, + ], + }, }, - }, - "shapeProp": Object { - "description": "", - "required": false, - "type": Object { - "name": "shape", - "value": Object { - "a": Object { - "description": "Comment for property a", - "name": "string", - "required": false, - }, - "b": Object { - "name": "number", - "required": false, + "shapeProp": Object { + "description": "", + "required": false, + "type": Object { + "name": "shape", + "value": Object { + "a": Object { + "description": "Comment for property a", + "name": "string", + "required": false, + }, + "b": Object { + "name": "number", + "required": false, + }, }, }, }, }, }, -} +] `; exports[`main fixtures processes component "component_18.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "UncoloredView", - "methods": Array [], - "props": Object { - "color": Object { - "description": "", - "flowType": Object { - "name": "string", - "nullable": true, - }, - "required": false, - "type": Object { - "name": "string", - }, - }, - "id": Object { - "defaultValue": Object { - "computed": false, - "value": "'test-forward-ref-default'", +Array [ + Object { + "description": "", + "displayName": "UncoloredView", + "methods": Array [], + "props": Object { + "color": Object { + "description": "", + "flowType": Object { + "name": "string", + "nullable": true, + }, + "required": false, + "type": Object { + "name": "string", + }, }, - "description": "", - "required": false, - "type": Object { - "name": "string", + "id": Object { + "defaultValue": Object { + "computed": false, + "value": "'test-forward-ref-default'", + }, + "description": "", + "required": false, + "type": Object { + "name": "string", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_19.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Component", - "methods": Array [], - "props": Object { - "data": Object { - "description": "", - "flowType": Object { - "elements": Array [ - Object { - "name": "mixed", - }, - ], - "name": "Array", - "raw": "Array", +Array [ + Object { + "description": "", + "displayName": "Component", + "methods": Array [], + "props": Object { + "data": Object { + "description": "", + "flowType": Object { + "elements": Array [ + Object { + "name": "mixed", + }, + ], + "name": "Array", + "raw": "Array", + }, + "required": false, }, - "required": false, }, }, -} +] `; exports[`main fixtures processes component "component_20.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Button", - "methods": Array [], - "props": Object { - "@computed#children": Object { - "defaultValue": Object { - "computed": false, - "value": "\\"default\\"", - }, - "description": "This is a test", - "required": false, - "type": Object { - "name": "string", +Array [ + Object { + "description": "", + "displayName": "Button", + "methods": Array [], + "props": Object { + "@computed#children": Object { + "defaultValue": Object { + "computed": false, + "value": "\\"default\\"", + }, + "description": "This is a test", + "required": false, + "type": Object { + "name": "string", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_21.tsx" without errors 1`] = ` -Object { - "description": "This is a typescript class component", - "displayName": "TSComponent", - "methods": Array [], - "props": Object { - "bar": Object { - "description": "Required prop", - "required": true, - "tsType": Object { - "name": "number", +Array [ + Object { + "description": "This is a typescript class component", + "displayName": "TSComponent", + "methods": Array [], + "props": Object { + "bar": Object { + "description": "Required prop", + "required": true, + "tsType": Object { + "name": "number", + }, }, - }, - "baz": Object { - "description": "Complex union prop", - "required": true, - "tsType": Object { - "elements": Array [ - Object { - "name": "number", - }, - Object { - "name": "signature", - "raw": "{ enter?: number, exit?: number }", - "signature": Object { - "properties": Array [ - Object { - "key": "enter", - "value": Object { - "name": "number", - "required": false, + "baz": Object { + "description": "Complex union prop", + "required": true, + "tsType": Object { + "elements": Array [ + Object { + "name": "number", + }, + Object { + "name": "signature", + "raw": "{ enter?: number, exit?: number }", + "signature": Object { + "properties": Array [ + Object { + "key": "enter", + "value": Object { + "name": "number", + "required": false, + }, }, - }, - Object { - "key": "exit", - "value": Object { - "name": "number", - "required": false, + Object { + "key": "exit", + "value": Object { + "name": "number", + "required": false, + }, }, - }, - ], + ], + }, + "type": "object", }, - "type": "object", - }, - Object { - "name": "literal", - "value": "'auto'", - }, - ], - "name": "union", - "raw": "number | { enter?: number, exit?: number } | 'auto'", + Object { + "name": "literal", + "value": "'auto'", + }, + ], + "name": "union", + "raw": "number | { enter?: number, exit?: number } | 'auto'", + }, }, - }, - "foo": Object { - "description": "Optional prop", - "required": false, - "tsType": Object { - "name": "string", + "foo": Object { + "description": "Optional prop", + "required": false, + "tsType": Object { + "name": "string", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_22.tsx" without errors 1`] = ` -Object { - "description": "This is a TypeScript function component", - "displayName": "TSFunctionComponent", - "methods": Array [], - "props": Object { - "align": Object { - "description": "", - "required": false, - "tsType": Object { - "elements": Array [ - Object { - "name": "literal", - "value": "\\"left\\"", - }, - Object { - "name": "literal", - "value": "\\"center\\"", - }, - Object { - "name": "literal", - "value": "\\"right\\"", - }, - Object { - "name": "literal", - "value": "\\"justify\\"", - }, - ], - "name": "union", - "raw": "\\"left\\" | \\"center\\" | \\"right\\" | \\"justify\\"", +Array [ + Object { + "description": "This is a TypeScript function component", + "displayName": "TSFunctionComponent", + "methods": Array [], + "props": Object { + "align": Object { + "description": "", + "required": false, + "tsType": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"left\\"", + }, + Object { + "name": "literal", + "value": "\\"center\\"", + }, + Object { + "name": "literal", + "value": "\\"right\\"", + }, + Object { + "name": "literal", + "value": "\\"justify\\"", + }, + ], + "name": "union", + "raw": "\\"left\\" | \\"center\\" | \\"right\\" | \\"justify\\"", + }, }, - }, - "center": Object { - "description": "", - "required": false, - "tsType": Object { - "name": "boolean", + "center": Object { + "description": "", + "required": false, + "tsType": Object { + "name": "boolean", + }, }, - }, - "justify": Object { - "description": "", - "required": false, - "tsType": Object { - "name": "boolean", + "justify": Object { + "description": "", + "required": false, + "tsType": Object { + "name": "boolean", + }, }, - }, - "left": Object { - "description": "", - "required": false, - "tsType": Object { - "name": "boolean", + "left": Object { + "description": "", + "required": false, + "tsType": Object { + "name": "boolean", + }, }, - }, - "right": Object { - "description": "", - "required": false, - "tsType": Object { - "name": "boolean", + "right": Object { + "description": "", + "required": false, + "tsType": Object { + "name": "boolean", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_23.tsx" without errors 1`] = ` -Object { - "composes": Array [ - "OtherProps", - ], - "description": "This is a typescript class component", - "displayName": "TSComponent", - "methods": Array [], - "props": Object { - "bar": Object { - "description": "Required prop", - "required": true, - "tsType": Object { - "name": "number", +Array [ + Object { + "composes": Array [ + "OtherProps", + ], + "description": "This is a typescript class component", + "displayName": "TSComponent", + "methods": Array [], + "props": Object { + "bar": Object { + "description": "Required prop", + "required": true, + "tsType": Object { + "name": "number", + }, }, - }, - "baz": Object { - "description": "Complex union prop", - "required": true, - "tsType": Object { - "elements": Array [ - Object { - "name": "number", - }, - Object { - "name": "signature", - "raw": "{ enter?: number, exit?: number }", - "signature": Object { - "properties": Array [ - Object { - "key": "enter", - "value": Object { - "name": "number", - "required": false, + "baz": Object { + "description": "Complex union prop", + "required": true, + "tsType": Object { + "elements": Array [ + Object { + "name": "number", + }, + Object { + "name": "signature", + "raw": "{ enter?: number, exit?: number }", + "signature": Object { + "properties": Array [ + Object { + "key": "enter", + "value": Object { + "name": "number", + "required": false, + }, }, - }, - Object { - "key": "exit", - "value": Object { - "name": "number", - "required": false, + Object { + "key": "exit", + "value": Object { + "name": "number", + "required": false, + }, }, - }, - ], + ], + }, + "type": "object", }, - "type": "object", - }, - Object { - "name": "literal", - "value": "'auto'", - }, - ], - "name": "union", - "raw": "number | { enter?: number, exit?: number } | 'auto'", + Object { + "name": "literal", + "value": "'auto'", + }, + ], + "name": "union", + "raw": "number | { enter?: number, exit?: number } | 'auto'", + }, }, - }, - "foo": Object { - "description": "Optional prop", - "required": false, - "tsType": Object { - "name": "string", + "foo": Object { + "description": "Optional prop", + "required": false, + "tsType": Object { + "name": "string", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_24.js" without errors 1`] = ` -Object { - "composes": Array [ - "OtherProps", - ], - "description": "This is a flow class component with an interface as props", - "displayName": "FlowComponent", - "methods": Array [], - "props": Object { - "bar": Object { - "description": "Required prop", - "flowType": Object { - "name": "number", - }, - "required": true, - }, - "baz": Object { - "description": "Complex union prop", - "flowType": Object { - "elements": Array [ - Object { - "name": "number", - }, - Object { - "name": "signature", - "raw": "{ enter?: number, exit?: number }", - "signature": Object { - "properties": Array [ - Object { - "key": "enter", - "value": Object { - "name": "number", - "required": false, +Array [ + Object { + "composes": Array [ + "OtherProps", + ], + "description": "This is a flow class component with an interface as props", + "displayName": "FlowComponent", + "methods": Array [], + "props": Object { + "bar": Object { + "description": "Required prop", + "flowType": Object { + "name": "number", + }, + "required": true, + }, + "baz": Object { + "description": "Complex union prop", + "flowType": Object { + "elements": Array [ + Object { + "name": "number", + }, + Object { + "name": "signature", + "raw": "{ enter?: number, exit?: number }", + "signature": Object { + "properties": Array [ + Object { + "key": "enter", + "value": Object { + "name": "number", + "required": false, + }, }, - }, - Object { - "key": "exit", - "value": Object { - "name": "number", - "required": false, + Object { + "key": "exit", + "value": Object { + "name": "number", + "required": false, + }, }, - }, - ], + ], + }, + "type": "object", }, - "type": "object", - }, - Object { - "name": "literal", - "value": "'auto'", - }, - ], - "name": "union", - "raw": "number | { enter?: number, exit?: number } | 'auto'", + Object { + "name": "literal", + "value": "'auto'", + }, + ], + "name": "union", + "raw": "number | { enter?: number, exit?: number } | 'auto'", + }, + "required": true, }, - "required": true, - }, - "foo": Object { - "description": "Optional prop", - "flowType": Object { - "name": "string", + "foo": Object { + "description": "Optional prop", + "flowType": Object { + "name": "string", + }, + "required": false, }, - "required": false, }, }, -} +] `; exports[`main fixtures processes component "component_25.tsx" without errors 1`] = ` -Object { - "description": "This is a typescript class component", - "displayName": "TSComponent", - "methods": Array [], - "props": Object { - "bar": Object { - "description": "Required prop", - "required": true, - "tsType": Object { - "elements": Array [ - Object { - "name": "Child", - }, - ], - "name": "Array", - "raw": "Array", +Array [ + Object { + "description": "This is a typescript class component", + "displayName": "TSComponent", + "methods": Array [], + "props": Object { + "bar": Object { + "description": "Required prop", + "required": true, + "tsType": Object { + "elements": Array [ + Object { + "name": "Child", + }, + ], + "name": "Array", + "raw": "Array", + }, }, - }, - "baz": Object { - "description": "Complex union prop", - "required": true, - "tsType": Object { - "name": "number", + "baz": Object { + "description": "Complex union prop", + "required": true, + "tsType": Object { + "name": "number", + }, }, - }, - "foo": Object { - "description": "Optional prop", - "required": false, - "tsType": Object { - "name": "Child", + "foo": Object { + "description": "Optional prop", + "required": false, + "tsType": Object { + "name": "Child", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_26.js" without errors 1`] = ` -Object { - "description": "This is a typescript class component", - "displayName": "FlowComponent", - "methods": Array [], - "props": Object { - "bar": Object { - "description": "Required prop", - "flowType": Object { - "elements": Array [ - Object { - "name": "Child", - }, - ], - "name": "Array", - "raw": "Array", +Array [ + Object { + "description": "This is a typescript class component", + "displayName": "FlowComponent", + "methods": Array [], + "props": Object { + "bar": Object { + "description": "Required prop", + "flowType": Object { + "elements": Array [ + Object { + "name": "Child", + }, + ], + "name": "Array", + "raw": "Array", + }, + "required": true, }, - "required": true, - }, - "baz": Object { - "description": "Complex union prop", - "flowType": Object { - "name": "number", + "baz": Object { + "description": "Complex union prop", + "flowType": Object { + "name": "number", + }, + "required": true, }, - "required": true, - }, - "foo": Object { - "description": "Optional prop", - "flowType": Object { - "name": "Child", + "foo": Object { + "description": "Optional prop", + "flowType": Object { + "name": "Child", + }, + "required": false, }, - "required": false, }, }, -} +] `; exports[`main fixtures processes component "component_27.tsx" without errors 1`] = ` -Object { - "description": "This is a typescript class component", - "displayName": "TSComponent", - "methods": Array [ - Object { - "description": "This is a method", - "docblock": "This is a method", - "modifiers": Array [], - "name": "foo", - "params": Array [ - Object { - "name": "a", +Array [ + Object { + "description": "This is a typescript class component", + "displayName": "TSComponent", + "methods": Array [ + Object { + "description": "This is a method", + "docblock": "This is a method", + "modifiers": Array [], + "name": "foo", + "params": Array [ + Object { + "name": "a", + "optional": false, + "type": Object { + "name": "string", + }, + }, + ], + "returns": Object { "type": Object { "name": "string", }, }, - ], - "returns": Object { - "type": Object { - "name": "string", - }, }, - }, - Object { - "description": "This is a public method", - "docblock": "This is a public method", - "modifiers": Array [], - "name": "bar", - "params": Array [ - Object { - "name": "a", + Object { + "description": "This is a public method", + "docblock": "This is a public method", + "modifiers": Array [], + "name": "bar", + "params": Array [ + Object { + "name": "a", + "optional": false, + "type": Object { + "name": "string", + }, + }, + ], + "returns": Object { "type": Object { "name": "string", }, }, - ], - "returns": Object { - "type": Object { + }, + ], + "props": Object { + "foo": Object { + "description": "", + "required": true, + "tsType": Object { "name": "string", }, }, }, - ], - "props": Object { - "foo": Object { - "description": "", - "required": true, - "tsType": Object { - "name": "string", - }, - }, }, -} +] `; exports[`main fixtures processes component "component_28.tsx" without errors 1`] = ` -Object { - "description": "Example component description", - "displayName": "ABC", - "methods": Array [], - "props": Object { - "foo": Object { - "defaultValue": Object { - "computed": false, - "value": "true", - }, - "description": "Example prop description", - "required": false, - "tsType": Object { - "name": "boolean", +Array [ + Object { + "description": "Example component description", + "displayName": "ABC", + "methods": Array [], + "props": Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "true", + }, + "description": "Example prop description", + "required": false, + "tsType": Object { + "name": "boolean", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_29.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "MyComponent", - "methods": Array [], - "props": Object { - "prop": Object { - "description": "", - "flowType": Object { - "name": "T", - }, - "required": true, +Array [ + Object { + "description": "", + "displayName": "MyComponent", + "methods": Array [], + "props": Object { + "prop": Object { + "description": "", + "flowType": Object { + "name": "T", + }, + "required": true, + }, }, }, -} +] `; exports[`main fixtures processes component "component_30.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "MyComponent", - "methods": Array [], - "props": Object { - "prop": Object { - "description": "", - "flowType": Object { - "name": "string", - }, - "required": true, +Array [ + Object { + "description": "", + "displayName": "MyComponent", + "methods": Array [], + "props": Object { + "prop": Object { + "description": "", + "flowType": Object { + "name": "string", + }, + "required": true, + }, }, }, -} +] `; exports[`main fixtures processes component "component_31.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "MyComponent", - "methods": Array [], - "props": Object { - "prop": Object { - "description": "", - "flowType": Object { - "name": "T", - }, - "required": true, +Array [ + Object { + "description": "", + "displayName": "MyComponent", + "methods": Array [], + "props": Object { + "prop": Object { + "description": "", + "flowType": Object { + "name": "T", + }, + "required": true, + }, }, }, -} +] `; exports[`main fixtures processes component "component_32.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "Segments", - "methods": Array [ - Object { - "docblock": null, - "modifiers": Array [], - "name": "foo", - "params": Array [ - Object { - "name": "props", - "optional": undefined, - "type": Object { - "alias": "Props", - "name": "signature", - "raw": "{ +Array [ + Object { + "description": "", + "displayName": "Segments", + "methods": Array [ + Object { + "docblock": null, + "modifiers": Array [], + "name": "foo", + "params": Array [ + Object { + "name": "props", + "optional": false, + "type": Object { + "alias": "Props", + "name": "signature", + "raw": "{ segments: Array, }", - "signature": Object { - "properties": Array [ - Object { - "key": "segments", - "value": Object { - "elements": Array [ - Object { - "name": "T", - }, - ], - "name": "Array", - "raw": "Array", - "required": true, + "signature": Object { + "properties": Array [ + Object { + "key": "segments", + "value": Object { + "elements": Array [ + Object { + "name": "T", + }, + ], + "name": "Array", + "raw": "Array", + "required": true, + }, }, - }, - ], + ], + }, + "type": "object", }, - "type": "object", - }, - }, - ], - "returns": null, - }, - ], - "props": Object { - "segments": Object { - "description": "", - "flowType": Object { - "elements": Array [ - Object { - "name": "T", }, ], - "name": "Array", - "raw": "Array", + "returns": null, + }, + ], + "props": Object { + "segments": Object { + "description": "", + "flowType": Object { + "elements": Array [ + Object { + "name": "T", + }, + ], + "name": "Array", + "raw": "Array", + }, + "required": true, }, - "required": true, }, }, -} +] `; exports[`main fixtures processes component "component_33.tsx" without errors 1`] = ` -Object { - "description": "This is a typescript component with imported prop types", - "displayName": "ImportedExtendedComponent", - "methods": Array [], - "props": Object { - "bar": Object { - "description": "", - "required": true, - "tsType": Object { - "name": "number", +Array [ + Object { + "description": "This is a typescript component with imported prop types", + "displayName": "ImportedExtendedComponent", + "methods": Array [], + "props": Object { + "bar": Object { + "description": "", + "required": true, + "tsType": Object { + "name": "number", + }, }, - }, - "foo": Object { - "description": "", - "required": true, - "tsType": Object { - "name": "string", + "foo": Object { + "description": "", + "required": true, + "tsType": Object { + "name": "string", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_34.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "CustomButton", - "methods": Array [], - "props": Object { - "children": Object { - "description": "", - "required": true, - "type": Object { - "name": "string", +Array [ + Object { + "description": "", + "displayName": "CustomButton", + "methods": Array [], + "props": Object { + "children": Object { + "description": "", + "required": true, + "type": Object { + "name": "string", + }, }, - }, - "color": Object { - "description": "", - "required": false, - "type": Object { - "name": "string", + "color": Object { + "description": "", + "required": false, + "type": Object { + "name": "string", + }, }, - }, - "onClick": Object { - "description": "", - "required": false, - "type": Object { - "name": "func", + "onClick": Object { + "description": "", + "required": false, + "type": Object { + "name": "func", + }, }, - }, - "style": Object { - "description": "", - "required": false, - "type": Object { - "name": "object", + "style": Object { + "description": "", + "required": false, + "type": Object { + "name": "object", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_35.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "SuperCustomButton", - "methods": Array [], - "props": Object { - "children": Object { - "description": "", - "required": true, - "type": Object { - "name": "string", +Array [ + Object { + "description": "", + "displayName": "SuperCustomButton", + "methods": Array [], + "props": Object { + "children": Object { + "description": "", + "required": true, + "type": Object { + "name": "string", + }, }, - }, - "onClick": Object { - "description": "", - "required": false, - "type": Object { - "name": "func", + "onClick": Object { + "description": "", + "required": false, + "type": Object { + "name": "func", + }, }, - }, - "style": Object { - "description": "", - "required": false, - "type": Object { - "name": "object", + "style": Object { + "description": "", + "required": false, + "type": Object { + "name": "object", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_36.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "SuperDuperCustomButton", - "methods": Array [], - "props": Object { - "children": Object { - "description": "", - "required": true, - "type": Object { - "name": "string", +Array [ + Object { + "description": "", + "displayName": "SuperDuperCustomButton", + "methods": Array [], + "props": Object { + "children": Object { + "description": "", + "required": true, + "type": Object { + "name": "string", + }, }, - }, - "onClick": Object { - "description": "", - "required": false, - "type": Object { - "name": "func", + "onClick": Object { + "description": "", + "required": false, + "type": Object { + "name": "func", + }, }, - }, - "style": Object { - "description": "", - "required": false, - "type": Object { - "name": "object", + "style": Object { + "description": "", + "required": false, + "type": Object { + "name": "object", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_37.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "SuperDuperCustomButton", - "methods": Array [], - "props": Object { - "children": Object { - "description": "", - "required": true, - "type": Object { - "name": "string", +Array [ + Object { + "description": "", + "displayName": "SuperDuperCustomButton", + "methods": Array [], + "props": Object { + "children": Object { + "description": "", + "required": true, + "type": Object { + "name": "string", + }, }, - }, - "onClick": Object { - "description": "", - "required": false, - "type": Object { - "name": "func", + "onClick": Object { + "description": "", + "required": false, + "type": Object { + "name": "func", + }, }, - }, - "style": Object { - "description": "", - "required": false, - "type": Object { - "name": "object", + "style": Object { + "description": "", + "required": false, + "type": Object { + "name": "object", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_38.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "SuperDuperCustomButton", - "methods": Array [], - "props": Object { - "children": Object { - "description": "", - "required": true, - "type": Object { - "name": "string", +Array [ + Object { + "description": "", + "displayName": "SuperDuperCustomButton", + "methods": Array [], + "props": Object { + "children": Object { + "description": "", + "required": true, + "type": Object { + "name": "string", + }, }, - }, - "onClick": Object { - "description": "", - "required": false, - "type": Object { - "name": "func", + "onClick": Object { + "description": "", + "required": false, + "type": Object { + "name": "func", + }, }, - }, - "style": Object { - "description": "", - "required": false, - "type": Object { - "name": "object", + "style": Object { + "description": "", + "required": false, + "type": Object { + "name": "object", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_39.tsx" without errors 1`] = ` -Object { - "description": "This is a typescript component with imported prop types", - "displayName": "ImportedComponent", - "methods": Array [], - "props": Object { - "foo": Object { - "description": "", - "required": true, - "tsType": Object { - "name": "string", +Array [ + Object { + "description": "This is a typescript component with imported prop types", + "displayName": "ImportedComponent", + "methods": Array [], + "props": Object { + "foo": Object { + "description": "", + "required": true, + "tsType": Object { + "name": "string", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_40.js" without errors 1`] = ` -Object { - "description": "", - "displayName": "SuperDuperCustomButton", - "methods": Array [], - "props": Object { - "size": Object { - "defaultValue": Object { - "computed": true, - "value": "Sizes.EXTRA_LARGE", - }, - "description": "", - "required": false, - "type": Object { - "computed": true, - "name": "enum", - "value": "Object.values(Sizes)", +Array [ + Object { + "description": "", + "displayName": "SuperDuperCustomButton", + "methods": Array [], + "props": Object { + "size": Object { + "defaultValue": Object { + "computed": true, + "value": "Sizes.EXTRA_LARGE", + }, + "description": "", + "required": false, + "type": Object { + "computed": true, + "name": "enum", + "value": "Object.values(Sizes)", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_41.tsx" without errors 1`] = ` -Object { - "description": "", - "displayName": "MyComponent", - "methods": Array [], - "props": Object { - "value": Object { - "description": "String value of a number", - "required": false, - "tsType": Object { - "name": "STRING_VALS[number]", - "raw": "typeof STRING_VALS[number]", +Array [ + Object { + "description": "", + "displayName": "MyComponent", + "methods": Array [], + "props": Object { + "value": Object { + "description": "String value of a number", + "required": false, + "tsType": Object { + "name": "STRING_VALS[number]", + "raw": "typeof STRING_VALS[number]", + }, }, }, }, -} +] `; exports[`main fixtures processes component "component_42.js" without errors 1`] = ` -Object { - "description": "", - "methods": Array [], - "props": Object { - "foo": Object { - "defaultValue": Object { - "computed": false, - "value": "'bar'", - }, - "required": false, +Array [ + Object { + "description": "", + "methods": Array [], + "props": Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "'bar'", + }, + "required": false, + }, }, }, -} +] `; exports[`main fixtures processes component "component_43.tsx" without errors 1`] = ` -Object { - "description": "", - "displayName": "MenuItem", - "methods": Array [], - "props": Object { - "children": Object { - "description": "Menu item contents.", - "required": false, - "type": Object { - "name": "node", +Array [ + Object { + "description": "", + "displayName": "MenuItem", + "methods": Array [], + "props": Object { + "children": Object { + "description": "Menu item contents.", + "required": false, + "type": Object { + "name": "node", + }, }, - }, - "classes": Object { - "description": "Override or extend the styles applied to the component. See CSS API below for more details.", - "required": false, - "type": Object { - "name": "object", + "classes": Object { + "description": "Override or extend the styles applied to the component. See CSS API below for more details.", + "required": false, + "type": Object { + "name": "object", + }, }, - }, - "component": Object { - "defaultValue": Object { - "computed": false, - "value": "'li'", + "component": Object { + "defaultValue": Object { + "computed": false, + "value": "'li'", + }, + "required": false, }, - "required": false, - }, - "disableGutters": Object { - "defaultValue": Object { - "computed": false, - "value": "false", + "disableGutters": Object { + "defaultValue": Object { + "computed": false, + "value": "false", + }, + "required": false, }, - "required": false, }, }, -} +] `; exports[`main fixtures processes component "flow-export-type.js" without errors 1`] = ` -Object { - "description": "This is a Flow class component", - "displayName": "FlowComponent", - "methods": Array [ - Object { - "docblock": null, - "modifiers": Array [], - "name": "foo", - "params": Array [ - Object { - "name": "a", - "optional": undefined, +Array [ + Object { + "description": "This is a Flow class component", + "displayName": "FlowComponent", + "methods": Array [ + Object { + "docblock": null, + "modifiers": Array [], + "name": "foo", + "params": Array [ + Object { + "name": "a", + "optional": false, + "type": Object { + "name": "string", + }, + }, + ], + "returns": Object { "type": Object { "name": "string", }, }, - ], - "returns": Object { - "type": Object { - "name": "string", - }, }, - }, - Object { - "docblock": null, - "modifiers": Array [], - "name": "bar", - "params": Array [ - Object { - "name": "a", - "optional": undefined, + Object { + "docblock": null, + "modifiers": Array [], + "name": "bar", + "params": Array [ + Object { + "name": "a", + "optional": false, + "type": Object { + "name": "string", + }, + }, + ], + "returns": Object { "type": Object { "name": "string", }, }, - ], - "returns": Object { - "type": Object { + }, + ], + "props": Object { + "foo": Object { + "description": "", + "flowType": Object { "name": "string", }, + "required": true, }, }, - ], - "props": Object { - "foo": Object { - "description": "", - "flowType": Object { - "name": "string", - }, - "required": true, - }, }, -} +] `; exports[`main fixtures processes component "flow-import-type.js" without errors 1`] = ` -Object { - "description": "This is a Flow component with imported prop types", - "displayName": "ImportedComponent", - "methods": Array [], - "props": Object { - "foo": Object { - "description": "", - "flowType": Object { - "name": "string", - }, - "required": true, +Array [ + Object { + "description": "This is a Flow component with imported prop types", + "displayName": "ImportedComponent", + "methods": Array [], + "props": Object { + "foo": Object { + "description": "", + "flowType": Object { + "name": "string", + }, + "required": true, + }, }, }, -} +] `; exports[`main fixtures processes component "flow-spread-import-type.js" without errors 1`] = ` -Object { - "description": "This is a Flow component with imported prop types", - "displayName": "ImportedExtendedComponent", - "methods": Array [], - "props": Object { - "bar": Object { - "description": "", - "flowType": Object { - "name": "number", - }, - "required": true, - }, - "foo": Object { - "description": "", - "flowType": Object { - "name": "string", +Array [ + Object { + "description": "This is a Flow component with imported prop types", + "displayName": "ImportedExtendedComponent", + "methods": Array [], + "props": Object { + "bar": Object { + "description": "", + "flowType": Object { + "name": "number", + }, + "required": true, + }, + "foo": Object { + "description": "", + "flowType": Object { + "name": "string", + }, + "required": true, }, - "required": true, }, }, -} +] `; diff --git a/src/__tests__/main-test.ts b/src/__tests__/main-test.ts index f98566bcb45..c51f5691d8f 100644 --- a/src/__tests__/main-test.ts +++ b/src/__tests__/main-test.ts @@ -4,34 +4,17 @@ import { handlers, parse, importers } from '../main'; import { ERROR_MISSING_DEFINITION } from '../parse'; describe('main', () => { - function test(source) { + function test(source: string) { it('parses with default resolver/handlers', () => { const docs = parse(source); - expect(docs).toEqual({ - displayName: 'ABC', - description: 'Example component description', - methods: [], - props: { - foo: { - type: { - name: 'bool', - }, - defaultValue: { - computed: false, - value: 'true', - }, - description: 'Example prop description', - required: false, - }, - }, - }); + expect(docs).toMatchSnapshot(); }); it('parses with custom handlers', () => { - const docs = parse(source, null, [handlers.componentDocblockHandler]); - expect(docs).toEqual({ - description: 'Example component description', - }); + const docs = parse(source, undefined, [ + handlers.componentDocblockHandler, + ]); + expect(docs).toMatchSnapshot(); }); } @@ -220,11 +203,16 @@ describe('main', () => { it(`processes component "${fileNames[i]}" without errors`, () => { let result; expect(() => { - result = parse(fileContent, null, null, { - importer: importers.makeFsImporter(), - filename: filePath, - babelrc: false, - }); + result = parse( + fileContent, + undefined, + undefined, + importers.makeFsImporter(), + { + filename: filePath, + babelrc: false, + }, + ); }).not.toThrowError(); expect(result).toMatchSnapshot(); }); diff --git a/src/__tests__/parse-test.ts b/src/__tests__/parse-test.ts index 7c5237db030..6dcfbe9efd4 100644 --- a/src/__tests__/parse-test.ts +++ b/src/__tests__/parse-test.ts @@ -1,12 +1,12 @@ import fs from 'fs'; import { directory as tempDirectory } from 'tempy'; -import { expression, noopImporter } from '../../tests/utils'; +import { parse as testParse, noopImporter } from '../../tests/utils'; import parse, { ERROR_MISSING_DEFINITION } from '../parse'; describe('parse', () => { it('allows custom component definition resolvers', () => { - const path = expression('{foo: "bar"}'); - const resolver = jest.fn(() => path); + const path = testParse.expression('{foo: "bar"}'); + const resolver = jest.fn(() => [path]); const handler = jest.fn(); parse('//empty', resolver, [handler], noopImporter); @@ -15,7 +15,7 @@ describe('parse', () => { }); it('errors if component definition is not found', () => { - const resolver = jest.fn(); + const resolver = jest.fn(() => []); expect(() => parse('//empty', resolver, [], noopImporter)).toThrowError( ERROR_MISSING_DEFINITION, ); @@ -35,7 +35,7 @@ describe('parse', () => { fs.writeFileSync(`${dir}/.babelrc`, '{}'); expect(() => - parse('const chained = () => a |> b', () => null, [], noopImporter, { + parse('const chained = () => a |> b', () => [], [], noopImporter, { cwd: dir, filename: `${dir}/component.js`, }), @@ -50,7 +50,7 @@ describe('parse', () => { it('supports custom parserOptions with plugins', () => { expect(() => - parse('const chained: Type = 1;', () => null, [], noopImporter, { + parse('const chained: Type = 1;', () => [], [], noopImporter, { parserOptions: { plugins: [ // no flow @@ -63,7 +63,7 @@ describe('parse', () => { it('supports custom parserOptions without plugins', () => { expect(() => - parse('const chained: Type = 1;', () => null, [], noopImporter, { + parse('const chained: Type = 1;', () => [], [], noopImporter, { parserOptions: { allowSuperOutsideMethod: true, }, diff --git a/src/babelParser.ts b/src/babelParser.ts index 2664f3244be..4936de3a9f7 100644 --- a/src/babelParser.ts +++ b/src/babelParser.ts @@ -1,10 +1,6 @@ -import { - loadPartialConfig, - parseSync, - ParserOptions, - TransformOptions, - ParseResult, -} from '@babel/core'; +import type { ParserOptions, TransformOptions } from '@babel/core'; +import { loadPartialConfig, parseSync } from '@babel/core'; +import type { File } from '@babel/types'; import path from 'path'; const TYPESCRIPT_EXTS = { @@ -46,14 +42,7 @@ function getDefaultPlugins( } export type Options = TransformOptions & { parserOptions?: ParserOptions }; -export type FileNodeWithOptions = ParseResult & { - program: { options: Options }; - __src: string; -}; - -export interface Parser { - parse: (src: string) => FileNodeWithOptions; -} +export type Parser = (src: string) => File; function buildPluginList( parserOptions: ParserOptions | undefined, @@ -75,9 +64,13 @@ function buildPluginList( plugins = getDefaultPlugins(babelOptions); } - // Ensure we always have estree plugin enabled, if we add it a second time - // here it does not matter - plugins.push('estree'); + // Ensure that the estree plugin is never active + if (plugins.includes('estree')) { + throw new Error( + //TODO not throw, just remove + 'The estree plugin is active for @babel/parser. As of version 6 react-docgen must have this plugin disabled.', + ); + } return plugins; } @@ -102,16 +95,13 @@ export default function buildParse(options: Options = {}): Parser { ...babelOptions, }; - return { - parse(src: string): FileNodeWithOptions { - const ast = parseSync(src, opts) as FileNodeWithOptions | null; + return (src: string): File => { + const ast = parseSync(src, opts); + + if (!ast) { + throw new Error('Unable to parse source code.'); + } - if (!ast) { - throw new Error('Unable to parse source code.'); - } - // Attach options to the Program node, for use when processing imports. - ast.program.options = options; - return ast; - }, + return ast; }; } diff --git a/src/handlers/__tests__/__snapshots__/componentMethodsHandler-test.ts.snap b/src/handlers/__tests__/__snapshots__/componentMethodsHandler-test.ts.snap index 30016d48f9c..98103bb0480 100644 --- a/src/handlers/__tests__/__snapshots__/componentMethodsHandler-test.ts.snap +++ b/src/handlers/__tests__/__snapshots__/componentMethodsHandler-test.ts.snap @@ -120,7 +120,7 @@ Array [ "params": Array [ Object { "name": "bar", - "optional": undefined, + "optional": false, "type": Object { "name": "number", }, @@ -144,7 +144,7 @@ Array [ "params": Array [ Object { "name": "bar", - "optional": undefined, + "optional": false, "type": Object { "name": "number", }, diff --git a/src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.ts.snap b/src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.ts.snap index f77a409b805..346974ae2f4 100644 --- a/src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.ts.snap +++ b/src/handlers/__tests__/__snapshots__/defaultPropsHandler-test.ts.snap @@ -97,6 +97,17 @@ Object { } `; +exports[`defaultPropsHandler ClassDeclaration with static defaultProps should find prop default values that are literals 2`] = ` +Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "\\"bar\\"", + }, + }, +} +`; + exports[`defaultPropsHandler ClassDeclaration with static defaultProps should resolve local spreads 1`] = ` Object { "bar": Object { @@ -368,6 +379,17 @@ Object { } `; +exports[`defaultPropsHandler ObjectExpression can resolve object methods 1`] = ` +Object { + "foo": Object { + "defaultValue": Object { + "computed": false, + "value": "\\"bar\\"", + }, + }, +} +`; + exports[`defaultPropsHandler ObjectExpression handles computed properties 1`] = ` Object { "@computed#bar": Object { @@ -478,12 +500,42 @@ Object { "value": "[\\"foo\\", \\"bar\\"]", }, }, + "bigint": Object { + "defaultValue": Object { + "computed": false, + "value": "1n", + }, + }, + "falseliteral": Object { + "defaultValue": Object { + "computed": false, + "value": "false", + }, + }, "foo": Object { "defaultValue": Object { "computed": false, "value": "\\"bar\\"", }, }, + "nullliteral": Object { + "defaultValue": Object { + "computed": false, + "value": "null", + }, + }, + "regex": Object { + "defaultValue": Object { + "computed": false, + "value": "/./", + }, + }, + "trueliteral": Object { + "defaultValue": Object { + "computed": false, + "value": "true", + }, + }, } `; diff --git a/src/handlers/__tests__/componentDocblockHandler-test.ts b/src/handlers/__tests__/componentDocblockHandler-test.ts index d268b035924..e62f40218bb 100644 --- a/src/handlers/__tests__/componentDocblockHandler-test.ts +++ b/src/handlers/__tests__/componentDocblockHandler-test.ts @@ -1,29 +1,33 @@ -import { parse, noopImporter, makeMockImporter } from '../../../tests/utils'; +import { makeMockImporter, parse } from '../../../tests/utils'; import componentDocblockHandler from '../componentDocblockHandler'; import Documentation from '../../Documentation'; -import DocumentationMock from '../../__mocks__/Documentation'; -import { NodePath } from 'ast-types/lib/node-path'; +import type DocumentationMock from '../../__mocks__/Documentation'; +import type { NodePath } from '@babel/traverse'; +import type { + ArrowFunctionExpression, + ClassExpression, + ExportDefaultDeclaration, + ExportNamedDeclaration, + ExpressionStatement, + FunctionExpression, + Node, + ObjectExpression, + VariableDeclaration, +} from '@babel/types'; jest.mock('../../Documentation'); describe('componentDocblockHandler', () => { let documentation: Documentation & DocumentationMock; - function lastStatement(src: string): NodePath { - const programPath = parse(src); - return programPath.get('body', programPath.node.body.length - 1); - } - - function beforeLastStatement(src: string): NodePath { - const programPath = parse(src); - return programPath.get('body', programPath.node.body.length - 2); - } - beforeEach(() => { documentation = new Documentation() as Documentation & DocumentationMock; }); - function test(definitionSrc: string, parseFunc: (src: string) => NodePath) { + function test( + definitionSrc: string, + parseFunc: (src: string) => NodePath, + ) { it('finds docblocks for component definitions', () => { const definition = parseFunc(` import something from 'somewhere'; @@ -32,9 +36,9 @@ describe('componentDocblockHandler', () => { * Component description */ ${definitionSrc} - `); + `) as NodePath; - componentDocblockHandler(documentation, definition, noopImporter); + componentDocblockHandler(documentation, definition); expect(documentation.description).toBe('Component description'); }); @@ -46,17 +50,17 @@ describe('componentDocblockHandler', () => { * This is not a docblock', */ ${definitionSrc} - `); + `) as NodePath; - componentDocblockHandler(documentation, definition, noopImporter); + componentDocblockHandler(documentation, definition); expect(documentation.description).toBe(''); definition = parseFunc(` // Inline comment' ${definitionSrc} - `); + `) as NodePath; - componentDocblockHandler(documentation, definition, noopImporter); + componentDocblockHandler(documentation, definition); expect(documentation.description).toBe(''); }); @@ -69,9 +73,9 @@ describe('componentDocblockHandler', () => { */ var something_else = "foo"; ${definitionSrc} - `); + `) as NodePath; - componentDocblockHandler(documentation, definition, noopImporter); + componentDocblockHandler(documentation, definition); expect(documentation.description).toBe(''); }); } @@ -80,7 +84,11 @@ describe('componentDocblockHandler', () => { * Decorates can only be assigned to class and therefore only make sense for * class declarations and export declarations. */ - function testDecorators(classSrc, parseFunc, exportSrc = '') { + function testDecorators( + classSrc: string, + parseFunc: (src: string) => NodePath, + exportSrc = '', + ) { describe('decorators', () => { it("uses the docblock above the decorator if it's the only one", () => { const definition = parseFunc(` @@ -92,9 +100,9 @@ describe('componentDocblockHandler', () => { @Decorator1 @Decorator2 ${classSrc} - `); + `) as NodePath; - componentDocblockHandler(documentation, definition, noopImporter); + componentDocblockHandler(documentation, definition); expect(documentation.description).toBe('Component description'); }); @@ -112,132 +120,133 @@ describe('componentDocblockHandler', () => { * Component description */ ${classSrc} - `); + `) as NodePath; - componentDocblockHandler(documentation, definition, noopImporter); + componentDocblockHandler(documentation, definition); expect(documentation.description).toBe('Component description'); }); }); } - function testImports(exportSrc, parseFunc, importName, useDefault = false) { + function testImports( + exportSrc: string, + importName: string, + useDefault = false, + ) { const importDef = useDefault ? `${importName}` : `{ ${importName} }`; const mockImporter = makeMockImporter({ - test1: parseFunc(` + test1: stmtLast => + stmtLast( + ` /** * Component description */ ${exportSrc} - `), + `, + false, + 0, + ).get('declaration') as NodePath, - test2: lastStatement(` + test2: stmtLast => + stmtLast(` import ${importDef} from 'test1'; - export default ${importName}; `).get('declaration'), }); describe('imports', () => { it('can use a custom importer to resolve docblocks on imported components', () => { - const program = lastStatement(` - import ${importDef} from 'test1'; - - export default ${importName}; - `).get('declaration'); - - componentDocblockHandler(documentation, program, mockImporter); + const program = parse + .statementLast( + `import ${importDef} from 'test1'; + export default ${importName};`, + mockImporter, + ) + .get('declaration'); + + componentDocblockHandler(documentation, program); expect(documentation.description).toBe('Component description'); }); }); it('traverses multiple imports', () => { - const program = lastStatement(` - import ${importDef} from 'test2'; - - export default ${importName}; - `).get('declaration'); - - componentDocblockHandler(documentation, program, mockImporter); + const program = parse + .statementLast( + `import ${importDef} from 'test2'; + export default ${importName};`, + mockImporter, + ) + .get('declaration'); + + componentDocblockHandler(documentation, program); expect(documentation.description).toBe('Component description'); }); } describe('React.createClass', () => { test('var Component = React.createClass({})', src => - lastStatement(src).get('declarations', 0, 'init', 'arguments', 0)); - testImports( - 'export var Component = React.createClass({})', - src => lastStatement(src).get('declaration'), - 'Component', - ); + parse + .statementLast(src) + .get('declarations.0.init.arguments.0') as NodePath); + testImports('export var Component = React.createClass({})', 'Component'); }); describe('ClassDeclaration', () => { - test('class Component {}', src => lastStatement(src)); - testDecorators('class Component {}', src => lastStatement(src)); - testImports( - 'export class Component {}', - src => lastStatement(src).get('declaration'), - 'Component', - ); + test('class Component {}', src => parse.statementLast(src)); + testDecorators('class Component {}', src => parse.statementLast(src)); + testImports('export class Component {}', 'Component'); }); describe('ClassExpression', () => { test('var Component = class {};', src => - lastStatement(src).get('declarations', 0, 'init')); - testImports( - 'export var Component = class {};', - src => lastStatement(src).get('declaration'), - 'Component', - ); + parse + .statementLast(src) + .get('declarations.0.init') as NodePath); + testImports('export var Component = class {};', 'Component'); }); describe('Stateless functions', () => { - test('function Component() {}', src => lastStatement(src)); - testImports( - 'export function Component() {}', - src => lastStatement(src).get('declaration'), - 'Component', - ); + test('function Component() {}', src => parse.statementLast(src)); + testImports('export function Component() {}', 'Component'); test('var Component = function () {};', src => - lastStatement(src).get('declarations', 0, 'init')); - testImports( - 'export var Component = function () {};', - src => lastStatement(src).get('declaration'), - 'Component', - ); + parse + .statementLast(src) + .get('declarations.0.init') as NodePath); + testImports('export var Component = function () {};', 'Component'); test('var Component = () => {}', src => - lastStatement(src).get('declarations', 0, 'init')); - testImports( - 'export var Component = () => {}', - src => lastStatement(src).get('declaration'), - 'Component', - ); + parse + .statementLast(src) + .get('declarations.0.init') as NodePath); + testImports('export var Component = () => {}', 'Component'); }); describe('ES6 default exports', () => { describe('Default React.createClass export', () => { test('export default React.createClass({});', src => - lastStatement(src).get('declaration', 'arguments', 0)); + parse + .statementLast(src) + .get('declaration.arguments.0') as NodePath); }); describe('Default class declaration export', () => { test('export default class Component {}', src => - lastStatement(src).get('declaration')); + parse.statementLast(src).get('declaration')); testDecorators( 'class Component {}', - src => lastStatement(src).get('declaration'), + src => + parse.statementLast(src).get('declaration'), 'export default', ); }); describe('Default class expression export', () => { test('export default class {}', src => - lastStatement(src).get('declaration')); + parse.statementLast(src).get('declaration')); testDecorators( 'class {}', - src => lastStatement(src).get('declaration'), + src => + parse.statementLast(src).get('declaration'), 'export default', ); }); @@ -245,17 +254,23 @@ describe('componentDocblockHandler', () => { describe('Default stateless function export', () => { describe('named function', () => { test('export default function Component() {}', src => - lastStatement(src).get('declaration')); + parse + .statementLast(src) + .get('declaration')); }); describe('anonymous function', () => { test('export default function() {}', src => - lastStatement(src).get('declaration')); + parse + .statementLast(src) + .get('declaration')); }); describe('arrow function', () => { test('export default () => {}', src => - lastStatement(src).get('declaration')); + parse + .statementLast(src) + .get('declaration')); }); }); }); @@ -263,22 +278,20 @@ describe('componentDocblockHandler', () => { describe('ES6 named exports', () => { describe('Named React.createClass export', () => { test('export var Component = React.createClass({});', src => - lastStatement(src).get( - 'declaration', - 'declarations', - '0', - 'init', - 'arguments', - 0, - )); + parse + .statementLast(src) + .get( + 'declaration.declarations.0.init.arguments.0', + ) as NodePath); }); describe('Named class declaration export', () => { test('export class Component {}', src => - lastStatement(src).get('declaration')); + parse.statementLast(src).get('declaration')); testDecorators( 'class Component {}', - src => lastStatement(src).get('declaration'), + src => + parse.statementLast(src).get('declaration'), 'export', ); }); @@ -286,17 +299,17 @@ describe('componentDocblockHandler', () => { describe('Named stateless function', () => { describe('named function', () => { test('export function Component() {}', src => - lastStatement(src).get('declaration')); + parse.statementLast(src).get('declaration')); }); describe('anonymous function', () => { test('export var Component = function() {}', src => - lastStatement(src).get('declaration')); + parse.statementLast(src).get('declaration')); }); describe('arrow function', () => { test('export var Component = () => {}', src => - lastStatement(src).get('declaration')); + parse.statementLast(src).get('declaration')); }); }); }); @@ -308,13 +321,11 @@ describe('componentDocblockHandler', () => { test(` React.forwardRef((props, ref) => {}); import React from "react";`, src => - beforeLastStatement(src).get('expression')); + parse.statement(src, -2).get('expression')); testImports( - ` - export default React.forwardRef((props, ref) => {}); - import React from 'react';`, - src => beforeLastStatement(src).get('declaration'), + `import React from 'react'; + export default React.forwardRef((props, ref) => {});`, 'RefComponent', useDefault, ); @@ -323,32 +334,34 @@ describe('componentDocblockHandler', () => { describe('inline implementation with memo', () => { test(` React.memo(React.forwardRef((props, ref) => {})); - import React from "react";`, src => - beforeLastStatement(src).get('expression')); + import React from "react"; + `, src => + parse.statement(src, -2).get('expression')); testImports( ` - export default React.memo(React.forwardRef((props, ref) => {})); - import React from 'react';`, - src => beforeLastStatement(src).get('declaration'), + export default React.memo(React.forwardRef((props, ref) => {})); + import React from 'react'; + `, 'RefComponent', useDefault, ); }); describe('out of line implementation', () => { - test(`let Component = (props, ref) => {}; + test(` + let Component = (props, ref) => {}; React.forwardRef(Component); import React from "react"; - `, src => beforeLastStatement(src).get('expression')); + `, src => + parse.statement(src, -2).get('expression')); testImports( ` - let Component = (props, ref) => {}; - export default React.forwardRef(Component); - import React from 'react'; + let Component = (props, ref) => {}; + export default React.forwardRef(Component); + import React from 'react'; `, - src => beforeLastStatement(src).get('declaration'), `RefComponent`, useDefault, ); diff --git a/src/handlers/__tests__/componentMethodsHandler-test.ts b/src/handlers/__tests__/componentMethodsHandler-test.ts index 0f78e02837d..a56994d6dfd 100644 --- a/src/handlers/__tests__/componentMethodsHandler-test.ts +++ b/src/handlers/__tests__/componentMethodsHandler-test.ts @@ -1,7 +1,14 @@ -import { parse, noopImporter, makeMockImporter } from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import componentMethodsHandler from '../componentMethodsHandler'; import Documentation from '../../Documentation'; -import DocumentationMock from '../../__mocks__/Documentation'; +import type DocumentationMock from '../../__mocks__/Documentation'; +import type { + ArrowFunctionExpression, + ClassDeclaration, + ExportDefaultDeclaration, + FunctionDeclaration, +} from '@babel/types'; +import type { NodePath } from '@babel/traverse'; jest.mock('../../Documentation'); @@ -13,23 +20,26 @@ describe('componentMethodsHandler', () => { }); const mockImporter = makeMockImporter({ - baz: parse(` + baz: stmtLast => + stmtLast(` export default (foo: string): string => {}; - `).get('body', 0, 'declaration'), + `).get('declaration'), - foo: parse(` + foo: stmtLast => + stmtLast(` export default function(bar: number): number { return bar; } - `).get('body', 0, 'declaration'), + `).get('declaration'), - doFoo: parse(` + doFoo: stmtLast => + stmtLast(` export default () => {}; - `).get('body', 0, 'declaration'), + `).get('declaration'), }); - function test(definition, importer) { - componentMethodsHandler(documentation, definition, importer); + function test(definition) { + componentMethodsHandler(documentation, definition); expect(documentation.methods).toEqual([ { name: 'foo', @@ -41,6 +51,7 @@ describe('componentMethodsHandler', () => { params: [ { name: 'bar', + optional: false, type: { name: 'number' }, }, ], @@ -55,6 +66,7 @@ describe('componentMethodsHandler', () => { params: [ { name: 'foo', + optional: false, type: { name: 'string' }, }, ], @@ -71,7 +83,7 @@ describe('componentMethodsHandler', () => { it('extracts the documentation for an ObjectExpression', () => { const src = ` - ({ + { /** * The foo method */ @@ -95,10 +107,10 @@ describe('componentMethodsHandler', () => { render() { return null; }, - }) + } `; - test(parse(src).get('body', 0, 'expression'), noopImporter); + test(parse.expression(src)); }); it('can resolve an imported method on an ObjectExpression', () => { @@ -131,7 +143,7 @@ describe('componentMethodsHandler', () => { }) `; - test(parse(src).get('body', 1, 'expression'), mockImporter); + test(parse.expressionLast(src, mockImporter)); }); it('extracts the documentation for a ClassDeclaration', () => { @@ -166,7 +178,7 @@ describe('componentMethodsHandler', () => { } `; - test(parse(src).get('body', 0), noopImporter); + test(parse.statement(src)); }); it('can resolve an imported method on a ClassDeclaration', () => { @@ -202,7 +214,7 @@ describe('componentMethodsHandler', () => { } `; - test(parse(src).get('body', 1), mockImporter); + test(parse.statementLast(src, mockImporter)); }); it('should handle and ignore computed methods', () => { @@ -232,8 +244,7 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 0), - noopImporter, + parse.statement(src), ); expect(documentation.methods).toMatchSnapshot(); }); @@ -264,8 +275,7 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 1), - mockImporter, + parse.statementLast(src, mockImporter), ); expect(documentation.methods).toMatchSnapshot(); }); @@ -287,8 +297,7 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 0), - noopImporter, + parse.statement(src), ); expect((documentation.methods as unknown[]).length).toBe(0); }); @@ -299,8 +308,10 @@ describe('componentMethodsHandler', () => { (props) => {} `; - const definition = parse(src).get('body', 0, 'expression'); - componentMethodsHandler(documentation, definition, noopImporter); + const definition = parse + .statement(src) + .get('expression') as NodePath; + componentMethodsHandler(documentation, definition); expect(documentation.methods).toEqual([]); }); @@ -314,8 +325,9 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 0, 'declarations', 0, 'init'), - noopImporter, + parse + .statement(src) + .get('declarations.0.init') as NodePath, ); expect(documentation.methods).toMatchSnapshot(); }); @@ -329,8 +341,9 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 0, 'declarations', 0, 'init'), - mockImporter, + parse + .statement(src, mockImporter) + .get('declarations.0.init') as NodePath, ); expect(documentation.methods).toMatchSnapshot(); }); @@ -345,8 +358,9 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 0, 'expression', 'right'), - noopImporter, + parse + .statement(src) + .get('expression.right') as NodePath, ); expect(documentation.methods).toMatchSnapshot(); }); @@ -360,8 +374,9 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 0, 'expression', 'right'), - mockImporter, + parse + .statement(src, mockImporter) + .get('expression.right') as NodePath, ); expect(documentation.methods).toMatchSnapshot(); }); @@ -376,8 +391,7 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 0), - noopImporter, + parse.statement(src), ); expect(documentation.methods).toMatchSnapshot(); }); @@ -391,8 +405,7 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, - parse(src).get('body', 0), - mockImporter, + parse.statement(src, mockImporter), ); expect(documentation.methods).toMatchSnapshot(); }); diff --git a/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts b/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts index 95fc1388ba3..e16a3ac9e7c 100644 --- a/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts +++ b/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts @@ -1,5 +1,5 @@ import Documentation from '../../Documentation'; -import DocumentationMock from '../../__mocks__/Documentation'; +import type DocumentationMock from '../../__mocks__/Documentation'; import componentMethodsJsDocHandler from '../componentMethodsJsDocHandler'; describe('componentMethodsJsDocHandler', () => { diff --git a/src/handlers/__tests__/defaultPropsHandler-test.ts b/src/handlers/__tests__/defaultPropsHandler-test.ts index f0156aa774d..42f4ff03cce 100644 --- a/src/handlers/__tests__/defaultPropsHandler-test.ts +++ b/src/handlers/__tests__/defaultPropsHandler-test.ts @@ -1,6 +1,8 @@ -import { parse, noopImporter, makeMockImporter } from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import type { ObjectExpression } from '@babel/types'; +import { parse, makeMockImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; -import DocumentationMock from '../../__mocks__/Documentation'; +import type DocumentationMock from '../../__mocks__/Documentation'; import defaultPropsHandler from '../defaultPropsHandler'; jest.mock('../../Documentation'); @@ -12,7 +14,8 @@ describe('defaultPropsHandler', () => { }); const mockImporter = makeMockImporter({ - getDefaultProps: parse(` + getDefaultProps: stmtLast => + stmtLast(` import baz from 'baz'; export default function() { return { @@ -22,44 +25,68 @@ describe('defaultPropsHandler', () => { abc: {xyz: abc.def, 123: 42} }; } - `).get('body', 1, 'declaration'), + `).get('declaration'), - baz: parse(` + baz: stmtLast => + stmtLast(` export default ["foo", "bar"]; - `).get('body', 0, 'declaration'), + `).get('declaration'), - other: parse(` + other: stmtLast => + stmtLast(` export default { bar: "foo" }; - `).get('body', 0, 'declaration'), + `).get('declaration'), - defaultProps: parse(` + defaultProps: stmtLast => + stmtLast(` export default { foo: "bar", bar: 42, baz: ["foo", "bar"], abc: {xyz: abc.def, 123: 42} }; - `).get('body', 0, 'declaration'), + `).get('declaration'), }); describe('ObjectExpression', () => { it('should find prop default values that are literals', () => { const src = ` - ({ + { getDefaultProps: function() { return { foo: "bar", bar: 42, + falseliteral: false, + trueliteral: true, + nullliteral: null, + regex: /./, + bigint: 1n, baz: ["foo", "bar"], abc: {xyz: abc.def, 123: 42} }; } - }) + } `; defaultPropsHandler( documentation, - parse(src).get('body', 0, 'expression'), - noopImporter, + parse.expression(src), + ); + expect(documentation.descriptors).toMatchSnapshot(); + }); + + it('can resolve object methods', () => { + const src = ` + { + getDefaultProps() { + return { + foo: "bar", + }; + } + } + `; + defaultPropsHandler( + documentation, + parse.expression(src), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -78,11 +105,7 @@ describe('defaultPropsHandler', () => { getDefaultProps: getDefaultProps }) `; - defaultPropsHandler( - documentation, - parse(src).get('body', 1, 'expression'), - noopImporter, - ); + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -96,8 +119,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'expression'), - mockImporter, + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -115,8 +137,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 0, 'expression'), - noopImporter, + parse(src).get('body.0.expression') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -135,8 +156,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'expression'), - mockImporter, + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -152,11 +172,7 @@ describe('defaultPropsHandler', () => { } }) `; - defaultPropsHandler( - documentation, - parse(src).get('body', 0, 'expression'), - noopImporter, - ); + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -174,8 +190,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'expression'), - mockImporter, + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -193,11 +208,7 @@ describe('defaultPropsHandler', () => { } }) `; - defaultPropsHandler( - documentation, - parse(src).get('body', 1, 'expression'), - noopImporter, - ); + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -215,8 +226,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'expression'), - mockImporter, + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -234,11 +244,21 @@ describe('defaultPropsHandler', () => { }; } `; - defaultPropsHandler( - documentation, - parse(src).get('body', 0), - noopImporter, - ); + defaultPropsHandler(documentation, parse(src).get('body')[0]); + expect(documentation.descriptors).toMatchSnapshot(); + }); + + it('should find prop default values that are literals', () => { + const src = ` + class Foo { + static get defaultProps() { + return { + foo: "bar", + }; + } + } + `; + defaultPropsHandler(documentation, parse(src).get('body')[0]); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -251,8 +271,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1), - mockImporter, + parse.statementLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -268,11 +287,7 @@ describe('defaultPropsHandler', () => { }; } `; - defaultPropsHandler( - documentation, - parse(src).get('body', 1), - noopImporter, - ); + defaultPropsHandler(documentation, parse.statementLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -288,8 +303,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1), - mockImporter, + parse.statementLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -304,11 +318,7 @@ describe('defaultPropsHandler', () => { }; } `; - defaultPropsHandler( - documentation, - parse(src).get('body', 1), - noopImporter, - ); + defaultPropsHandler(documentation, parse.statementLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -324,8 +334,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1), - mockImporter, + parse.statementLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -344,8 +353,7 @@ describe('defaultPropsHandler', () => { }`; defaultPropsHandler( documentation, - parse(src).get('body', 0, 'declarations', 0, 'init'), - noopImporter, + parse.statement(src).get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -359,8 +367,9 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'declarations', 0, 'init'), - mockImporter, + parse + .statementLast(src, mockImporter) + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -368,19 +377,17 @@ describe('defaultPropsHandler', () => { it('should only consider Property nodes, not e.g. spread properties', () => { const src = ` - ({ + { getDefaultProps: function() { return { ...Foo.bar, bar: 42, }; } - }) + } `; - const definition = parse(src).get('body', 0, 'expression'); - expect(() => - defaultPropsHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse.expression(src); + expect(() => defaultPropsHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -396,10 +403,8 @@ describe('defaultPropsHandler', () => { } }) `; - const definition = parse(src).get('body', 1, 'expression'); - expect(() => - defaultPropsHandler(documentation, definition, mockImporter), - ).not.toThrow(); + const definition = parse.expressionLast(src, mockImporter); + expect(() => defaultPropsHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -413,11 +418,7 @@ describe('defaultPropsHandler', () => { abc = {xyz: abc.def, 123: 42} }) =>
`; - defaultPropsHandler( - documentation, - parse(src).get('body', 0, 'expression'), - noopImporter, - ); + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -430,8 +431,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'expression'), - mockImporter, + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -448,8 +448,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 0, 'declarations', 0, 'init'), - noopImporter, + parse.statement(src).get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -464,8 +463,9 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'declarations', 0, 'init'), - mockImporter, + parse + .statement(src, mockImporter, 1) + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -478,8 +478,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'declarations', 0, 'init'), - noopImporter, + parse.statement(src, 1).get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -492,8 +491,9 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'declarations', 0, 'init'), - mockImporter, + parse + .statement(src, mockImporter, 1) + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -507,11 +507,7 @@ describe('defaultPropsHandler', () => { abc: defg = {xyz: abc.def, 123: 42} }) =>
`; - defaultPropsHandler( - documentation, - parse(src).get('body', 0, 'expression'), - noopImporter, - ); + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -524,8 +520,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 1, 'expression'), - mockImporter, + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -538,23 +533,14 @@ describe('defaultPropsHandler', () => { foo = ImportedComponent, }) =>
`; - defaultPropsHandler( - documentation, - parse(src).get('body', 1, 'expression'), - noopImporter, - ); + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); it('should work with no defaults', () => { - const src = ` - ({ foo }) =>
- `; - defaultPropsHandler( - documentation, - parse(src).get('body', 0, 'expression'), - noopImporter, - ); + const src = `({ foo }) =>
`; + + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); }); @@ -565,11 +551,7 @@ describe('defaultPropsHandler', () => { import React from 'react'; React.forwardRef(({ foo = 'bar' }, ref) =>
{foo}
); `; - defaultPropsHandler( - documentation, - parse(src).get('body', 1, 'expression'), - noopImporter, - ); + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -581,8 +563,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 2, 'expression'), - mockImporter, + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -593,11 +574,7 @@ describe('defaultPropsHandler', () => { const Component = React.forwardRef(({ foo }, ref) =>
{foo}
); Component.defaultProps = { foo: 'baz' }; `; - defaultPropsHandler( - documentation, - parse(src).get('body', 1), - noopImporter, - ); + defaultPropsHandler(documentation, parse.statement(src, 1)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -608,11 +585,7 @@ describe('defaultPropsHandler', () => { const Component = React.forwardRef(({ bar }, ref) =>
{bar}
); Component.defaultProps = other; `; - defaultPropsHandler( - documentation, - parse(src).get('body', 2), - mockImporter, - ); + defaultPropsHandler(documentation, parse.statement(src, mockImporter, 2)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -622,11 +595,7 @@ describe('defaultPropsHandler', () => { const ComponentImpl = ({ foo = 'bar' }, ref) =>
{foo}
; React.forwardRef(ComponentImpl); `; - defaultPropsHandler( - documentation, - parse(src).get('body', 2, 'expression'), - noopImporter, - ); + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -639,8 +608,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse(src).get('body', 3, 'expression'), - mockImporter, + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); diff --git a/src/handlers/__tests__/displayNameHandler-test.ts b/src/handlers/__tests__/displayNameHandler-test.ts index 916c2e594e4..9314247723c 100644 --- a/src/handlers/__tests__/displayNameHandler-test.ts +++ b/src/handlers/__tests__/displayNameHandler-test.ts @@ -1,12 +1,13 @@ -import { - expression, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; import displayNameHandler from '../displayNameHandler'; -import DocumentationMock from '../../__mocks__/Documentation'; +import type DocumentationMock from '../../__mocks__/Documentation'; +import type { + ArrowFunctionExpression, + ExpressionStatement, + FunctionExpression, +} from '@babel/types'; +import type { NodePath } from '@babel/traverse'; jest.mock('../../Documentation'); @@ -18,161 +19,182 @@ describe('defaultPropsHandler', () => { }); const mockImporter = makeMockImporter({ - foobarbaz: statement(` + foobarbaz: stmt => + stmt(` export default "FooBarBaz" `).get('declaration'), - foo: statement(` + foo: stmt => + stmt(` export default {bar: 'baz'}; `).get('declaration'), - bar: statement(` + bar: stmt => + stmt(` export default {baz: 'foo'}; `).get('declaration'), }); it('extracts the displayName', () => { - let definition = expression('({displayName: "FooBar"})'); - displayNameHandler(documentation, definition, noopImporter); + let definition: NodePath = parse.expression('{displayName: "FooBar"}'); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBar'); - definition = statement(` + definition = parse + .statement( + ` ({displayName: foobarbaz}); import foobarbaz from 'foobarbaz'; - `).get('expression'); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ) + .get('expression'); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); - definition = statement(` + definition = parse.statement(` class Foo { static displayName = "BarFoo"; } `); - displayNameHandler(documentation, definition, noopImporter); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('BarFoo'); - definition = statement(` + definition = parse.statement( + ` class Foo { static displayName = foobarbaz; } import foobarbaz from 'foobarbaz'; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); it('resolves identifiers', () => { - let definition = statement(` + let definition: NodePath = parse + .statement( + ` ({displayName: name}) var name = 'abc'; - `).get('expression'); - displayNameHandler(documentation, definition, noopImporter); + `, + ) + .get('expression'); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('abc'); - definition = statement(` + definition = parse + .statement( + ` ({displayName: name}) import foobarbaz from 'foobarbaz'; var name = foobarbaz; - `).get('expression'); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ) + .get('expression'); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); - definition = statement(` + definition = parse.statement(` class Foo { static displayName = name; } var name = 'xyz'; `); - displayNameHandler(documentation, definition, noopImporter); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('xyz'); - definition = statement(` + definition = parse.statement( + ` class Foo { static displayName = name; } import foobarbaz from 'foobarbaz'; var name = foobarbaz; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); it('ignores non-literal names', () => { - let definition = expression('({displayName: foo.bar})'); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + let definition = parse.expression('{displayName: foo.bar}'); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).not.toBeDefined(); - definition = statement(` + definition = parse.statement(` class Foo { static displayName = foo.bar; } `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).not.toBeDefined(); }); it('can resolve non-literal names with appropriate importer', () => { - let definition = statement(` + let definition = parse + .statement( + ` ({displayName: foo.bar}); import foo from 'foo'; - `).get('expression'); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ) + .get('expression'); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); - definition = statement(` + definition = parse.statement( + ` class Foo { static displayName = bar.baz; } import bar from 'bar'; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('foo'); }); describe('ClassDeclaration', () => { it('considers the class name', () => { - const definition = statement(` + const definition = parse.statement(` class Foo { } `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers a static displayName class property', () => { - const definition = statement(` + const definition = parse.statement(` class Foo { static displayName = 'foo'; } `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('foo'); }); it('considers static displayName getter', () => { - const definition = statement(` + const definition = parse.statement(` class Foo { static get displayName() { return 'foo'; } } `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('foo'); }); it('resolves variables in displayName getter', () => { - const definition = statement(` + const definition = parse.statement(` class Foo { static get displayName() { return abc; @@ -180,321 +202,307 @@ describe('defaultPropsHandler', () => { } const abc = 'bar'; `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('bar'); }); it('resolves imported variables in displayName getter', () => { - let definition = statement(` + let definition = parse.statement( + ` class Foo { static get displayName() { return foobarbaz; } } import foobarbaz from 'foobarbaz'; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); - definition = statement(` + definition = parse.statement( + ` class Foo { static get displayName() { return foo.bar; } } import foo from 'foo'; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); }); describe('FunctionDeclaration', () => { it('considers the function name', () => { - const definition = statement('function Foo () {}'); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse.statement('function Foo () {}'); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers a static displayName object property', () => { - const definition = statement(` + const definition = parse.statement(` function Foo () {} Foo.displayName = 'Bar'; `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves variable assigned to displayName object property', () => { - const definition = statement(` + const definition = parse.statement(` function Foo () {} Foo.displayName = bar; var bar = 'Bar'; `); - displayNameHandler(documentation, definition, noopImporter); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('Bar'); }); it('resolves imported variable assigned to displayName object property', () => { - let definition = statement(` + let definition = parse.statement( + ` function Foo () {} import foobarbaz from 'foobarbaz'; Foo.displayName = foobarbaz; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); - definition = statement(` + definition = parse.statement( + ` function Foo () {} import foo from 'foo'; Foo.displayName = foo.bar; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); }); describe('FunctionExpression', () => { it('considers the variable name', () => { - const definition = statement('var Foo = function () {};').get( - 'declarations', - 0, - 'init', - ); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition: NodePath = parse + .statement('var Foo = function () {};') + .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers the variable name on assign', () => { - const definition = statement('Foo = function () {};').get( - 'expression', - 'right', - ); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse + .statement('Foo = function () {};') + .get('expression.right') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers a static displayName object property over variable name', () => { - const definition = statement(` + const definition = parse.statement(` var Foo = function () {}; Foo.displayName = 'Bar'; `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves variable assigned to displayName object property over variable name', () => { - const definition = statement(` + const definition = parse.statement(` var Foo = function () {}; Foo.displayName = bar; var bar = 'Bar'; `); - displayNameHandler(documentation, definition, noopImporter); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('Bar'); }); it('resolves imported variable assigned to displayName object property over variable name', () => { - let definition = statement(` + let definition = parse.statement( + ` var Foo = function () {}; import foobarbaz from 'foobarbaz'; Foo.displayName = foobarbaz; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); - definition = statement(` + definition = parse.statement( + ` var Foo = function () {}; import foo from 'foo'; Foo.displayName = foo.bar; - `); - displayNameHandler(documentation, definition, mockImporter); + `, + mockImporter, + ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); }); describe('ArrowFunctionExpression', () => { it('considers the variable name', () => { - const definition = statement('var Foo = () => {};').get( - 'declarations', - 0, - 'init', - ); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse + .statement('var Foo = () => {};') + .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers the variable name even if wrapped', () => { - const definition = statement('var Foo = React.forwardRef(() => {});').get( - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse + .statement('var Foo = React.forwardRef(() => {});') + .get( + 'declarations.0.init.arguments.0', + ) as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers the variable name when handling forwardRef', () => { - const definition = statement(` + const definition = parse + .statement( + ` var Foo = React.forwardRef(() => {}); import React from "react"; - `).get('declarations', 0, 'init'); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + `, + ) + .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers the variable name on assign', () => { - const definition = statement('Foo = () => {};').get( - 'expression', - 'right', - ); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse + .statement('Foo = () => {};') + .get('expression.right') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers the variable name on assign even if wrapped', () => { - const definition = statement('Foo = React.forwardRef(() => {});').get( - 'expression', - 'right', - 'arguments', - 0, - ); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse + .statement('Foo = React.forwardRef(() => {});') + .get( + 'expression.right.arguments.0', + ) as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers the variable name on assign when handling forwardRef call', () => { - const definition = statement(` + const definition = parse + .statement( + ` Foo = React.forwardRef(() => {}); import React from "react"; - `).get('expression', 'right'); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + `, + ) + .get('expression.right') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); it('considers a static displayName object property over variable name', () => { - const definition = statement(` + const definition = parse.statement(` var Foo = () => {}; Foo.displayName = 'Bar'; `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves a variable assigned to displayName object property over variable name', () => { - const definition = statement(` + const definition = parse.statement(` var Foo = () => {}; Foo.displayName = bar; var bar = 'Bar'; `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves imported variable assigned to displayName object property over variable name', () => { - let definition = statement(` + let definition = parse.statement( + ` var Foo = () => {}; import foobarbaz from 'foobarbaz'; Foo.displayName = foobarbaz; - `); - expect(() => - displayNameHandler(documentation, definition, mockImporter), - ).not.toThrow(); + `, + mockImporter, + ); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('FooBarBaz'); - definition = statement(` + definition = parse.statement( + ` var Foo = () => {}; import foo from 'foo'; Foo.displayName = foo.bar; - `); - expect(() => - displayNameHandler(documentation, definition, mockImporter), - ).not.toThrow(); + `, + mockImporter, + ); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('baz'); }); it('considers a static displayName object property over variable name even if wrapped', () => { - const definition = statement(` + const definition = parse.statement(` var Foo = React.forwardRef(() => {}); Foo.displayName = 'Bar'; `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves a variable assigned to displayName object property over variable name even if wrapped', () => { - const definition = statement(` + const definition = parse.statement(` var Foo = React.forwardRef(() => {}); Foo.displayName = bar; var bar = 'Bar'; `); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves imported variable assigned to displayName object property over variable name even if wrapped', () => { - let definition = statement(` + let definition = parse.statement( + ` var Foo = React.forwardRef(() => {}); import foobarbaz from 'foobarbaz'; Foo.displayName = foobarbaz; - `); - expect(() => - displayNameHandler(documentation, definition, mockImporter), - ).not.toThrow(); + `, + mockImporter, + ); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('FooBarBaz'); - definition = statement(` + definition = parse.statement( + ` var Foo = React.forwardRef(() => {}); import foo from 'foo'; Foo.displayName = foo.bar; - `); - expect(() => - displayNameHandler(documentation, definition, mockImporter), - ).not.toThrow(); + `, + mockImporter, + ); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('baz'); }); it('ignores assignment to non-literal/identifier', () => { - const definition = statement('Foo.Bar = () => {};').get( - 'expression', - 'right', - ); - expect(() => - displayNameHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse + .statement('Foo.Bar = () => {};') + .get('expression.right') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).not.toBeDefined(); }); }); diff --git a/src/handlers/__tests__/flowTypeHandler-test.ts b/src/handlers/__tests__/flowTypeHandler-test.ts index e73d4dc60bc..f4c471eef6a 100644 --- a/src/handlers/__tests__/flowTypeHandler-test.ts +++ b/src/handlers/__tests__/flowTypeHandler-test.ts @@ -1,13 +1,9 @@ -import { - expression, - statement, - parse, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; import flowTypeHandler from '../flowTypeHandler'; -import DocumentationMock from '../../__mocks__/Documentation'; +import type DocumentationMock from '../../__mocks__/Documentation'; +import type { ExportNamedDeclaration, ExpressionStatement } from '@babel/types'; +import type { NodePath } from '@babel/traverse'; jest.mock('../../Documentation'); jest.mock('../../utils/getFlowType', () => ({ @@ -23,7 +19,8 @@ describe('flowTypeHandler', () => { }); const mockImporter = makeMockImporter({ - something: statement(` + something: stmtLast => + stmtLast(` export type Props = { foo: string, bar?: number, @@ -33,10 +30,10 @@ describe('flowTypeHandler', () => { def: "test" | 1 | true, foobar: Foo & Bar, }; - `).get('declaration'), + `).get('declaration') as NodePath, }); - function template(src, typeObject) { + function template(src: string, typeObject: string): string { return ` ${src} var React = require('React'); @@ -46,7 +43,7 @@ describe('flowTypeHandler', () => { `; } - function test(getSrc) { + function test(getSrc: (src: string) => NodePath) { it('detects types correctly', () => { const flowTypesSrc = ` { @@ -57,7 +54,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition, noopImporter); + flowTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -87,7 +84,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition, noopImporter); + flowTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -112,7 +109,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition, noopImporter); + flowTypeHandler(documentation, definition); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -126,7 +123,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition, noopImporter); + flowTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -150,7 +147,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition, noopImporter); + flowTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -172,7 +169,7 @@ describe('flowTypeHandler', () => { const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition, noopImporter); + flowTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -189,7 +186,7 @@ describe('flowTypeHandler', () => { describe('TypeAlias', () => { describe('class definition for flow <0.53', () => { test(propTypesSrc => - statement( + parse.statement( template( 'class Foo extends Component {}', propTypesSrc, @@ -200,7 +197,7 @@ describe('flowTypeHandler', () => { describe('class definition for flow >=0.53 without State', () => { test(propTypesSrc => - statement( + parse.statement( template('class Foo extends Component {}', propTypesSrc), ), ); @@ -208,7 +205,7 @@ describe('flowTypeHandler', () => { describe('class definition for flow >=0.53 with State', () => { test(propTypesSrc => - statement( + parse.statement( template( 'class Foo extends Component {}', propTypesSrc, @@ -219,7 +216,7 @@ describe('flowTypeHandler', () => { describe('class definition with inline props', () => { test(propTypesSrc => - statement( + parse.statement( template( 'class Foo extends Component { props: Props; }', propTypesSrc, @@ -230,41 +227,41 @@ describe('flowTypeHandler', () => { describe('stateless component', () => { test(propTypesSrc => - statement(template('(props: Props) =>
;', propTypesSrc)).get( - 'expression', - ), + parse + .statement( + template('(props: Props) =>
;', propTypesSrc), + ) + .get('expression'), ); }); }); it('does not error if flowTypes cannot be found', () => { - let definition = expression('{fooBar: 42}'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); - - definition = statement('class Foo extends Component {}'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); - - definition = statement('() =>
'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); + let definition = parse.expression('{fooBar: 42}'); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + + definition = parse.statement('class Foo extends Component {}'); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + + definition = parse.statement('() =>
'); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); }); it('supports intersection proptypes', () => { - const definition = statement(` + const definition = parse + .statement( + ` (props: Props) =>
; var React = require('React'); import type Imported from 'something'; type Props = Imported & { foo: 'bar' }; - `).get('expression'); + `, + ) + .get('expression'); - flowTypeHandler(documentation, definition, noopImporter); + flowTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -276,23 +273,27 @@ describe('flowTypeHandler', () => { }); it('does support utility types inline', () => { - const definition = statement(` + const definition = parse + .statement( + ` (props: $ReadOnly) =>
; var React = require('React'); type Props = { foo: 'fooValue' }; - `).get('expression'); + `, + ) + .get('expression'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); it('does not support union proptypes', () => { - const definition = statement(` + const definition = parse + .statement( + ` (props: Props) =>
; var React = require('React'); @@ -300,91 +301,125 @@ describe('flowTypeHandler', () => { type Other = { bar: 'barValue' }; type Props = Imported | Other | { foo: 'fooValue' }; - `).get('expression'); + `, + ) + .get('expression'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); }); describe('imported prop types', () => { it('does not resolve type included by require', () => { - const definition = statement(` + const definition = parse + .statement( + ` (props: Props) =>
; var React = require('React'); var Component = React.Component; var Props = require('something'); - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); - expect(() => - flowTypeHandler(documentation, definition, mockImporter), - ).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); }); it('imported', () => { - const definition = statement(` + const definition = parse + .statement( + ` (props: Props) =>
; var React = require('React'); var Component = React.Component; import { Props } from 'something'; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); - expect(documentation.descriptors).toEqual({}); - - expect(() => - flowTypeHandler(documentation, definition, mockImporter), - ).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); - it('type imported', () => { - const definition = statement(` + it('type not imported', () => { + const definition = parse + .statement( + ` (props: Props) =>
; var React = require('React'); var Component = React.Component; import type { Props } from 'something'; - `).get('expression'); + `, + ) + .get('expression'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); + }); + + it('type imported', () => { + const definition = parse + .statement( + ` + (props: Props) =>
; + var React = require('React'); + var Component = React.Component; - expect(() => - flowTypeHandler(documentation, definition, mockImporter), - ).not.toThrow(); + import type { Props } from 'something'; + `, + mockImporter, + ) + .get('expression'); + + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); it('does not resolve types not in scope', () => { - const definition = statement(` + const definition = parse + .statement( + ` + (props: Props) =>
; + var React = require('React'); + var Component = React.Component; + `, + mockImporter, + ) + .get('expression'); + + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(documentation.descriptors).toEqual({}); + + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(documentation.descriptors).toEqual({}); + }); + + it('does not resolve types not in scope', () => { + const definition = parse + .statement( + ` (props: Props) =>
; var React = require('React'); var Component = React.Component; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(() => - flowTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); - expect(() => - flowTypeHandler(documentation, definition, mockImporter), - ).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); }); }); @@ -398,8 +433,7 @@ describe('flowTypeHandler', () => { `; flowTypeHandler( documentation, - parse(src).get('body', 2, 'expression'), - noopImporter, + parse(src).get('body.2.expression') as NodePath, ); expect(documentation.descriptors).toEqual({ foo: { @@ -419,8 +453,7 @@ describe('flowTypeHandler', () => { `; flowTypeHandler( documentation, - parse(src).get('body', 3, 'expression'), - noopImporter, + parse(src).get('body.3.expression') as NodePath, ); expect(documentation.descriptors).toEqual({ foo: { @@ -440,8 +473,7 @@ describe('flowTypeHandler', () => { `; flowTypeHandler( documentation, - parse(src).get('body', 3, 'expression', 'right'), - noopImporter, + parse(src).get('body.3.expression.right') as NodePath, ); expect(documentation.descriptors).toEqual({ foo: { diff --git a/src/handlers/__tests__/propDocblockHandler-test.ts b/src/handlers/__tests__/propDocblockHandler-test.ts index a4293739764..a06c7aad0d8 100644 --- a/src/handlers/__tests__/propDocblockHandler-test.ts +++ b/src/handlers/__tests__/propDocblockHandler-test.ts @@ -1,11 +1,9 @@ -import { - expression, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import type { ExpressionStatement } from '@babel/types'; +import { parse, makeMockImporter, noopImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; -import DocumentationMock from '../../__mocks__/Documentation'; +import type { Importer } from '../../importer'; +import type DocumentationMock from '../../__mocks__/Documentation'; import propDocBlockHandler from '../propDocBlockHandler'; jest.mock('../../Documentation'); @@ -18,7 +16,8 @@ describe('propDocBlockHandler', () => { }); const mockImporter = makeMockImporter({ - props: statement(` + props: stmtLast => + stmtLast(` export default { /** * A comment on imported props @@ -28,9 +27,12 @@ describe('propDocBlockHandler', () => { `).get('declaration'), }); - function test(getSrc, parse) { + function test( + getSrc: (src: string) => string, + parseSrc: (src: string, importer?: Importer) => NodePath, + ) { it('finds docblocks for prop types', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ /** @@ -45,7 +47,7 @@ describe('propDocBlockHandler', () => { ), ); - propDocBlockHandler(documentation, definition, noopImporter); + propDocBlockHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { description: 'Foo comment', @@ -57,7 +59,7 @@ describe('propDocBlockHandler', () => { }); it('can handle multline comments', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ /** @@ -71,7 +73,7 @@ describe('propDocBlockHandler', () => { ), ); - propDocBlockHandler(documentation, definition, noopImporter); + propDocBlockHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { description: @@ -81,7 +83,7 @@ describe('propDocBlockHandler', () => { }); it('ignores non-docblock comments', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ /** @@ -98,7 +100,7 @@ describe('propDocBlockHandler', () => { ), ); - propDocBlockHandler(documentation, definition, noopImporter); + propDocBlockHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { description: 'Foo comment', @@ -110,7 +112,7 @@ describe('propDocBlockHandler', () => { }); it('only considers the comment with the property below it', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ /** @@ -122,7 +124,7 @@ describe('propDocBlockHandler', () => { ), ); - propDocBlockHandler(documentation, definition, noopImporter); + propDocBlockHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { description: 'Foo comment', @@ -134,7 +136,7 @@ describe('propDocBlockHandler', () => { }); it('understands and ignores the spread operator', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ ...Bar.propTypes, @@ -146,7 +148,7 @@ describe('propDocBlockHandler', () => { ), ); - propDocBlockHandler(documentation, definition, noopImporter); + propDocBlockHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { description: 'Foo comment', @@ -155,7 +157,7 @@ describe('propDocBlockHandler', () => { }); it('resolves variables', () => { - const definition = parse(` + const definition = parseSrc(` ${getSrc('Props')} var Props = { /** @@ -165,7 +167,7 @@ describe('propDocBlockHandler', () => { }; `); - propDocBlockHandler(documentation, definition, noopImporter); + propDocBlockHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { description: 'Foo comment', @@ -174,12 +176,15 @@ describe('propDocBlockHandler', () => { }); it('resolves imported variables', () => { - const definition = parse(` + const definition = parseSrc( + ` ${getSrc('Props')} import Props from 'props'; - `); + `, + mockImporter, + ); - propDocBlockHandler(documentation, definition, mockImporter); + propDocBlockHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { description: 'A comment on imported props', @@ -188,7 +193,8 @@ describe('propDocBlockHandler', () => { }); it('resolves imported variables that are spread', () => { - const definition = parse(` + const definition = parseSrc( + ` ${getSrc('Props')} import ExtraProps from 'props'; var Props = { @@ -198,9 +204,11 @@ describe('propDocBlockHandler', () => { */ bar: Prop.bool, } - `); + `, + mockImporter, + ); - propDocBlockHandler(documentation, definition, mockImporter); + propDocBlockHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { description: 'A comment on imported props', @@ -215,7 +223,8 @@ describe('propDocBlockHandler', () => { describe('React.createClass', () => { test( propTypesSrc => `({propTypes: ${propTypesSrc}})`, - src => statement(src).get('expression'), + (src, importer = noopImporter) => + parse.statement(src, importer).get('expression'), ); }); @@ -227,7 +236,7 @@ describe('propDocBlockHandler', () => { static propTypes = ${propTypesSrc}; } `, - src => statement(src), + (src, importer = noopImporter) => parse.statement(src, importer), ); }); @@ -240,20 +249,16 @@ describe('propDocBlockHandler', () => { } } `, - src => statement(src), + (src, importer = noopImporter) => parse.statement(src, importer), ); }); }); it('does not error if propTypes cannot be found', () => { - let definition = expression('{fooBar: 42}'); - expect(() => - propDocBlockHandler(documentation, definition, noopImporter), - ).not.toThrow(); + let definition = parse.expression('{fooBar: 42}'); + expect(() => propDocBlockHandler(documentation, definition)).not.toThrow(); - definition = statement('class Foo {}'); - expect(() => - propDocBlockHandler(documentation, definition, noopImporter), - ).not.toThrow(); + definition = parse.statement('class Foo {}'); + expect(() => propDocBlockHandler(documentation, definition)).not.toThrow(); }); }); diff --git a/src/handlers/__tests__/propTypeCompositionHandler-test.ts b/src/handlers/__tests__/propTypeCompositionHandler-test.ts index 65a3ef536ae..e08a9d487a2 100644 --- a/src/handlers/__tests__/propTypeCompositionHandler-test.ts +++ b/src/handlers/__tests__/propTypeCompositionHandler-test.ts @@ -1,12 +1,10 @@ -import { - expression, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter, noopImporter } from '../../../tests/utils'; import propTypeCompositionHandler from '../propTypeCompositionHandler'; import Documentation from '../../Documentation'; -import DocumentationMock from '../../__mocks__/Documentation'; +import type DocumentationMock from '../../__mocks__/Documentation'; +import type { NodePath } from '@babel/traverse'; +import type { Importer } from '../../importer'; +import type { ExpressionStatement } from '@babel/types'; jest.mock('../../Documentation'); jest.mock('../../utils/getPropType', () => () => ({})); @@ -19,38 +17,43 @@ describe('propTypeCompositionHandler', () => { }); const mockImporter = makeMockImporter({ - 'Foo.react': statement(` - export default Component; + 'Foo.react': stmtLast => + stmtLast(` function Component() {} Component.propTypes = { foo: 'bar' }; + export default Component; `).get('declaration'), - SharedProps: statement(` + SharedProps: stmtLast => + stmtLast(` export default { bar: 'baz' }; `).get('declaration'), }); - function test(getSrc, parse) { + function test( + getSrc: (src: string) => string, + parseSrc: (src: string, importer?: Importer) => NodePath, + ) { it('understands assignment from module', () => { - let definition = parse(` + let definition = parseSrc(` ${getSrc('Foo.propTypes')} var Foo = require("Foo.react"); `); - propTypeCompositionHandler(documentation, definition, noopImporter); + propTypeCompositionHandler(documentation, definition); expect(documentation.composes).toEqual(['Foo.react']); documentation = new Documentation() as Documentation & DocumentationMock; - definition = parse(` + definition = parseSrc(` ${getSrc('SharedProps')} var SharedProps = require("SharedProps"); `); - propTypeCompositionHandler(documentation, definition, noopImporter); + propTypeCompositionHandler(documentation, definition); expect(documentation.composes).toEqual(['SharedProps']); }); @@ -61,13 +64,13 @@ describe('propTypeCompositionHandler', () => { ...SharedProps, }`, ); - const definition = parse(` + const definition = parseSrc(` ${definitionSrc} var Foo = require("Foo.react"); var SharedProps = require("SharedProps"); `); - propTypeCompositionHandler(documentation, definition, noopImporter); + propTypeCompositionHandler(documentation, definition); expect(documentation.composes).toEqual(['Foo.react', 'SharedProps']); }); @@ -78,13 +81,16 @@ describe('propTypeCompositionHandler', () => { ...SharedProps, }`, ); - const definition = parse(` + const definition = parseSrc( + ` ${definitionSrc} import Foo from "Foo.react"; import SharedProps from "SharedProps"; - `); + `, + mockImporter, + ); - propTypeCompositionHandler(documentation, definition, mockImporter); + propTypeCompositionHandler(documentation, definition); expect(documentation.composes).toEqual([]); }); @@ -95,13 +101,16 @@ describe('propTypeCompositionHandler', () => { ...NotFound, }`, ); - const definition = parse(` + const definition = parseSrc( + ` ${definitionSrc} import Foo from "Foo.react"; import NotFound from "NotFound"; - `); + `, + mockImporter, + ); - propTypeCompositionHandler(documentation, definition, mockImporter); + propTypeCompositionHandler(documentation, definition); expect(documentation.composes).toEqual(['NotFound']); }); } @@ -109,7 +118,8 @@ describe('propTypeCompositionHandler', () => { describe('React.createClass', () => { test( propTypesSrc => `({propTypes: ${propTypesSrc}})`, - src => statement(src).get('expression'), + (src, importer = noopImporter) => + parse.statement(src, importer).get('expression'), ); }); @@ -121,7 +131,7 @@ describe('propTypeCompositionHandler', () => { static propTypes = ${propTypesSrc}; } `, - src => statement(src), + (src, importer = noopImporter) => parse.statement(src, importer), ); }); @@ -134,20 +144,20 @@ describe('propTypeCompositionHandler', () => { } } `, - src => statement(src), + (src, importer = noopImporter) => parse.statement(src, importer), ); }); }); it('does not error if propTypes cannot be found', () => { - let definition = expression('{fooBar: 42}'); + let definition = parse.expression('{fooBar: 42}'); expect(() => - propTypeCompositionHandler(documentation, definition, noopImporter), + propTypeCompositionHandler(documentation, definition), ).not.toThrow(); - definition = statement('class Foo {}'); + definition = parse.statement('class Foo {}'); expect(() => - propTypeCompositionHandler(documentation, definition, noopImporter), + propTypeCompositionHandler(documentation, definition), ).not.toThrow(); }); }); diff --git a/src/handlers/__tests__/propTypeHandler-test.ts b/src/handlers/__tests__/propTypeHandler-test.ts index 4d3fdbc137d..7c86591a622 100644 --- a/src/handlers/__tests__/propTypeHandler-test.ts +++ b/src/handlers/__tests__/propTypeHandler-test.ts @@ -1,13 +1,11 @@ -import { - statement, - expression, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter, noopImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; -import DocumentationMock from '../../__mocks__/Documentation'; +import type DocumentationMock from '../../__mocks__/Documentation'; import { propTypeHandler } from '../propTypeHandler'; import getPropType from '../../utils/getPropType'; +import type { NodePath } from '@babel/traverse'; +import type { Importer } from '../../importer'; +import type { ExpressionStatement } from '@babel/types'; const getPropTypeMock = getPropType as jest.Mock; @@ -22,39 +20,45 @@ describe('propTypeHandler', () => { }); const mockImporter = makeMockImporter({ - props: statement(` - export default {bar: PropTypes.bool}; + props: stmtLast => + stmtLast(` import { PropTypes } from 'react'; + export default {bar: PropTypes.bool}; `).get('declaration'), - simpleProp: statement(` - export default PropTypes.array.isRequired; + simpleProp: stmtLast => + stmtLast(` import { PropTypes } from 'react'; + export default PropTypes.array.isRequired; `).get('declaration'), - complexProp: statement(` - export default prop; + complexProp: stmtLast => + stmtLast(` var prop = PropTypes.oneOfType([PropTypes.number, PropTypes.bool]).isRequired; import { PropTypes } from 'react'; + export default prop; `).get('declaration'), - foo: statement(` - export default PropTypes.bool; - import { PropTypes } from 'react'; + foo: stmtLast => + stmtLast(` + import { PropTypes } from 'react'; + export default PropTypes.bool; `).get('declaration'), - bar: statement(` - export default PropTypes.bool; - import { PropTypes } from 'react'; + bar: stmtLast => + stmtLast(` + import { PropTypes } from 'react'; + export default PropTypes.bool; `).get('declaration'), - baz: statement(` - export default OtherPropTypes.bool; - import { PropTypes as OtherPropTypes } from 'react'; + baz: stmtLast => + stmtLast(` + import { PropTypes as OtherPropTypes } from 'react'; + export default OtherPropTypes.bool; `).get('declaration'), }); - function template(src) { + function template(src: string) { return ` ${src} var React = require('React'); @@ -63,26 +67,29 @@ describe('propTypeHandler', () => { `; } - function test(getSrc, parse) { + function test( + getSrc: (src: string) => string, + parseSrc: (src: string, importer?: Importer) => NodePath, + ) { it('passes the correct argument to getPropType', () => { const propTypesSrc = `{ foo: PropTypes.bool, abc: PropTypes.xyz, }`; - const definition = parse(getSrc(propTypesSrc)); - const propTypesAST = expression(propTypesSrc); + const definition = parseSrc(getSrc(propTypesSrc)); + const propTypesAST = parse.expression(propTypesSrc); - const fooPath = propTypesAST.get('properties', 0, 'value'); - const xyzPath = propTypesAST.get('properties', 1, 'value'); + const fooPath = propTypesAST.get('properties.0.value') as NodePath; + const xyzPath = propTypesAST.get('properties.1.value') as NodePath; - propTypeHandler(documentation, definition, noopImporter); + propTypeHandler(documentation, definition); expect(getPropTypeMock.mock.calls[0][0]).toEqualASTNode(fooPath); expect(getPropTypeMock.mock.calls[1][0]).toEqualASTNode(xyzPath); }); it('finds definitions via React.PropTypes', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ foo: PropTypes.bool, @@ -92,7 +99,7 @@ describe('propTypeHandler', () => { ), ); - propTypeHandler(documentation, definition, noopImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { type: {}, @@ -110,7 +117,7 @@ describe('propTypeHandler', () => { }); it('finds definitions via the ReactPropTypes module', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ foo: require("ReactPropTypes").bool, @@ -118,7 +125,7 @@ describe('propTypeHandler', () => { ), ); - propTypeHandler(documentation, definition, noopImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { type: {}, @@ -128,7 +135,7 @@ describe('propTypeHandler', () => { }); it('detects whether a prop is required', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ simple_prop: PropTypes.array.isRequired, @@ -138,7 +145,7 @@ describe('propTypeHandler', () => { ), ); - propTypeHandler(documentation, definition, noopImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ simple_prop: { type: {}, @@ -152,7 +159,7 @@ describe('propTypeHandler', () => { }); it('handles computed properties', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ [foo]: PropTypes.array.isRequired, @@ -162,12 +169,12 @@ describe('propTypeHandler', () => { ), ); - propTypeHandler(documentation, definition, noopImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toMatchSnapshot(); }); it('ignores complex computed properties', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ [() => {}]: PropTypes.array.isRequired, @@ -177,12 +184,12 @@ describe('propTypeHandler', () => { ), ); - propTypeHandler(documentation, definition, noopImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toMatchSnapshot(); }); it('only considers definitions from React or ReactPropTypes', () => { - const definition = parse( + const definition = parseSrc( getSrc( `{ custom_propA: PropTypes.bool, @@ -191,7 +198,7 @@ describe('propTypeHandler', () => { ), ); - propTypeHandler(documentation, definition, noopImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ custom_propA: { type: {}, @@ -209,12 +216,12 @@ describe('propTypeHandler', () => { it('resolves variables', () => { const definitionSrc = getSrc('props'); - const definition = parse(` + const definition = parseSrc(` ${definitionSrc} var props = {bar: PropTypes.bool}; `); - propTypeHandler(documentation, definition, noopImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ bar: { type: {}, @@ -225,12 +232,15 @@ describe('propTypeHandler', () => { it('resolves imported variables', () => { const definitionSrc = getSrc('props'); - const definition = parse(` + const definition = parseSrc( + ` ${definitionSrc} import props from 'props'; - `); + `, + mockImporter, + ); - propTypeHandler(documentation, definition, mockImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ bar: { type: {}, @@ -247,16 +257,19 @@ describe('propTypeHandler', () => { simple_prop: simpleProp, complex_prop: complexProp, }`); - const definition = parse(` + const definition = parseSrc( + ` ${definitionSrc} import foo from 'foo'; import bar from 'bar'; import baz from 'baz'; import simpleProp from 'simpleProp'; import complexProp from 'complexProp'; - `); + `, + mockImporter, + ); - propTypeHandler(documentation, definition, mockImporter); + propTypeHandler(documentation, definition); expect(documentation.descriptors).toMatchSnapshot(); }); } @@ -264,7 +277,8 @@ describe('propTypeHandler', () => { describe('React.createClass', () => { test( propTypesSrc => template(`({propTypes: ${propTypesSrc}})`), - src => statement(src).get('expression'), + (src, importer = noopImporter) => + parse.statement(src, importer).get('expression'), ); }); @@ -277,7 +291,7 @@ describe('propTypeHandler', () => { static propTypes = ${propTypesSrc}; } `), - src => statement(src), + (src, importer = noopImporter) => parse.statement(src, importer), ); }); @@ -291,7 +305,7 @@ describe('propTypeHandler', () => { } } `), - src => statement(src), + (src, importer = noopImporter) => parse.statement(src, importer), ); }); }); @@ -303,37 +317,27 @@ describe('propTypeHandler', () => { var Component = (props) =>
; Component.propTypes = ${propTypesSrc}; `), - src => statement(src), + (src, importer = noopImporter) => parse.statement(src, importer), ); }); it('does not error if propTypes cannot be found', () => { - let definition = expression('{fooBar: 42}'); - expect(() => - propTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); - - definition = statement('class Foo {}'); - expect(() => - propTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); - - definition = statement('function Foo() {}'); - expect(() => - propTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); - - definition = expression('() => {}'); - expect(() => - propTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); + let definition = parse.expression('{fooBar: 42}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + + definition = parse.statement('class Foo {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + + definition = parse.statement('function Foo() {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + + definition = parse.expression('() => {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); }); // This case is handled by propTypeCompositionHandler it('does not error if propTypes is a member expression', () => { - const definition = expression('{propTypes: Foo.propTypes}'); - expect(() => - propTypeHandler(documentation, definition, noopImporter), - ).not.toThrow(); + const definition = parse.expression('{propTypes: Foo.propTypes}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); }); }); diff --git a/src/handlers/componentDocblockHandler.ts b/src/handlers/componentDocblockHandler.ts index f1f47f89851..6be89acd77e 100644 --- a/src/handlers/componentDocblockHandler.ts +++ b/src/handlers/componentDocblockHandler.ts @@ -1,20 +1,17 @@ -import { namedTypes as t } from 'ast-types'; import type Documentation from '../Documentation'; import { getDocblock } from '../utils/docblock'; import isReactForwardRefCall from '../utils/isReactForwardRefCall'; import resolveToValue from '../utils/resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath, Node } from '@babel/traverse'; +import type { ClassDeclaration, ClassExpression } from '@babel/types'; -function isClassDefinition(nodePath: NodePath): boolean { - const node = nodePath.node; - return t.ClassDeclaration.check(node) || t.ClassExpression.check(node); +function isClassDefinition( + path: NodePath, +): path is NodePath { + return path.isClassDeclaration() || path.isClassExpression(); } -function getDocblockFromComponent( - path: NodePath, - importer: Importer, -): string | null { +function getDocblockFromComponent(path: NodePath): string | null { let description: string | null = null; if (isClassDefinition(path)) { @@ -22,22 +19,22 @@ function getDocblockFromComponent( // attached to the last decorator instead as trailing comment. if (path.node.decorators && path.node.decorators.length > 0) { description = getDocblock( - path.get('decorators', path.node.decorators.length - 1), + path.get('decorators')[path.node.decorators.length - 1], true, ); } } if (description == null) { // Find parent statement (e.g. var Component = React.createClass();) - let searchPath = path; - while (searchPath && !t.Statement.check(searchPath.node)) { - searchPath = searchPath.parent; + let searchPath: NodePath | null = path; + while (searchPath && !searchPath.isStatement()) { + searchPath = searchPath.parentPath; } if (searchPath) { // If the parent is an export statement, we have to traverse one more up if ( - t.ExportNamedDeclaration.check(searchPath.parentPath.node) || - t.ExportDefaultDeclaration.check(searchPath.parentPath.node) + searchPath.parentPath.isExportNamedDeclaration() || + searchPath.parentPath.isExportDefaultDeclaration() ) { searchPath = searchPath.parentPath; } @@ -45,12 +42,12 @@ function getDocblockFromComponent( } } if (!description) { - const searchPath = isReactForwardRefCall(path, importer) - ? path.get('arguments', 0) + const searchPath = isReactForwardRefCall(path) + ? path.get('arguments')[0] : path; - const inner = resolveToValue(searchPath, importer); + const inner = resolveToValue(searchPath); if (inner.node !== path.node) { - return getDocblockFromComponent(inner, importer); + return getDocblockFromComponent(inner); } } return description; @@ -62,10 +59,6 @@ function getDocblockFromComponent( export default function componentDocblockHandler( documentation: Documentation, path: NodePath, - importer: Importer, ): void { - documentation.set( - 'description', - getDocblockFromComponent(path, importer) || '', - ); + documentation.set('description', getDocblockFromComponent(path) || ''); } diff --git a/src/handlers/componentMethodsHandler.ts b/src/handlers/componentMethodsHandler.ts index 87c2678cbe5..279d73c0b52 100644 --- a/src/handlers/componentMethodsHandler.ts +++ b/src/handlers/componentMethodsHandler.ts @@ -1,5 +1,5 @@ -import { namedTypes as t } from 'ast-types'; import getMemberValuePath from '../utils/getMemberValuePath'; +import type { MethodNodePath } from '../utils/getMethodDocumentation'; import getMethodDocumentation from '../utils/getMethodDocumentation'; import isReactComponentClass from '../utils/isReactComponentClass'; import isReactComponentMethod from '../utils/isReactComponentMethod'; @@ -7,15 +7,9 @@ import type Documentation from '../Documentation'; import match from '../utils/match'; import { traverseShallow } from '../utils/traverse'; import resolveToValue from '../utils/resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; -import { Scope } from 'ast-types/lib/scope'; +import type { NodePath, Scope } from '@babel/traverse'; +import type { AssignmentExpression, Identifier } from '@babel/types'; -function isPublicClassProperty(path: NodePath): boolean { - return ( - t.ClassProperty.check(path.node) && !t.ClassPrivateProperty.check(path.node) - ); -} /** * The following values/constructs are considered methods: * @@ -24,44 +18,49 @@ function isPublicClassProperty(path: NodePath): boolean { * - Public class fields in classes whose value are a functions * - Object properties whose values are functions */ -function isMethod(path: NodePath, importer: Importer): boolean { - const isProbablyMethod = - (t.MethodDefinition.check(path.node) && path.node.kind !== 'constructor') || - ((isPublicClassProperty(path) || t.Property.check(path.node)) && - t.Function.check(resolveToValue(path.get('value'), importer).node)); +function isMethod(path: NodePath): boolean { + let isProbablyMethod = + (path.isClassMethod() && path.node.kind !== 'constructor') || + path.isObjectMethod(); + + if ( + !isProbablyMethod && + (path.isClassProperty() || path.isObjectProperty()) + ) { + const value = resolveToValue(path.get('value') as NodePath); + isProbablyMethod = value.isFunction(); + } - return isProbablyMethod && !isReactComponentMethod(path, importer); + return isProbablyMethod && !isReactComponentMethod(path); } function findAssignedMethods( scope: Scope, - idPath: NodePath, - importer: Importer, -): NodePath[] { - const results: NodePath[] = []; + idPath: NodePath, +): Array> { + const results: Array> = []; - if (!t.Identifier.check(idPath.node)) { + if (!idPath.hasNode() || !idPath.isIdentifier()) { return results; } const name = idPath.node.name; - const idScope = idPath.scope.lookup(idPath.node.name); + const idScope = idPath.scope.getBinding(idPath.node.name)?.scope; - traverseShallow(scope.path, { - visitAssignmentExpression: function (path) { + traverseShallow(scope.path.node, { + AssignmentExpression(path) { const node = path.node; if ( match(node.left, { type: 'MemberExpression', object: { type: 'Identifier', name }, }) && - path.scope.lookup(name) === idScope && - t.Function.check(resolveToValue(path.get('right'), importer).node) + path.scope.getBinding(name)?.scope === idScope && + resolveToValue(path.get('right')).isFunction() ) { results.push(path); - return false; + path.skip(); } - return this.traverse(path); }, }); @@ -75,59 +74,66 @@ function findAssignedMethods( export default function componentMethodsHandler( documentation: Documentation, path: NodePath, - importer: Importer, ): void { // Extract all methods from the class or object. - let methodPaths: NodePath[] = []; - if (isReactComponentClass(path, importer)) { - methodPaths = path - .get('body', 'body') - .filter((body: NodePath) => isMethod(body, importer)); - } else if (t.ObjectExpression.check(path.node)) { - methodPaths = path - .get('properties') - .filter((props: NodePath) => isMethod(props, importer)); + let methodPaths: Array<{ path: MethodNodePath; isStatic?: boolean }> = []; + if (isReactComponentClass(path)) { + methodPaths = ( + path + .get('body') + .get('body') + .filter(body => isMethod(body)) as MethodNodePath[] + ).map(p => ({ path: p })); + } else if (path.isObjectExpression()) { + methodPaths = ( + path + .get('properties') + .filter(props => isMethod(props)) as MethodNodePath[] + ).map(p => ({ path: p })); // Add the statics object properties. - const statics = getMemberValuePath(path, 'statics', importer); - if (statics) { - statics.get('properties').each((p: NodePath) => { - if (isMethod(p, importer)) { - p.node.static = true; - methodPaths.push(p); + const statics = getMemberValuePath(path, 'statics'); + if (statics && statics.isObjectExpression()) { + statics.get('properties').forEach(property => { + if (isMethod(property)) { + methodPaths.push({ + path: property as MethodNodePath, + isStatic: true, + }); } }); } } else if ( - t.VariableDeclarator.check(path.parent.node) && - path.parent.node.init === path.node && - t.Identifier.check(path.parent.node.id) + path.parentPath && + path.parentPath.isVariableDeclarator() && + path.parentPath.node.init === path.node && + path.parentPath.get('id').isIdentifier() ) { methodPaths = findAssignedMethods( - path.parent.scope, - path.parent.get('id'), - importer, - ); + path.parentPath.scope, + path.parentPath.get('id') as NodePath, + ).map(p => ({ path: p })); } else if ( - t.AssignmentExpression.check(path.parent.node) && - path.parent.node.right === path.node && - t.Identifier.check(path.parent.node.left) + path.parentPath && + path.parentPath.isAssignmentExpression() && + path.parentPath.node.right === path.node && + path.parentPath.get('left').isIdentifier() ) { methodPaths = findAssignedMethods( - path.parent.scope, - path.parent.get('left'), - importer, - ); - } else if (t.FunctionDeclaration.check(path.node)) { + path.parentPath.scope, + path.parentPath.get('left') as NodePath, + ).map(p => ({ path: p })); + } else if (path.isFunctionDeclaration()) { methodPaths = findAssignedMethods( - path.parent.scope, + path.parentPath.scope, path.get('id'), - importer, - ); + ).map(p => ({ path: p })); } documentation.set( 'methods', - methodPaths.map(p => getMethodDocumentation(p, importer)).filter(Boolean), + methodPaths + .map(({ path: p, isStatic }) => getMethodDocumentation(p, { isStatic })) + .filter(Boolean), ); } diff --git a/src/handlers/defaultPropsHandler.ts b/src/handlers/defaultPropsHandler.ts index d5496bcd952..a7a92fd5c77 100644 --- a/src/handlers/defaultPropsHandler.ts +++ b/src/handlers/defaultPropsHandler.ts @@ -1,4 +1,3 @@ -import { namedTypes as t } from 'ast-types'; import getPropertyName from '../utils/getPropertyName'; import getMemberValuePath from '../utils/getMemberValuePath'; import printValue from '../utils/printValue'; @@ -7,83 +6,87 @@ import resolveFunctionDefinitionToReturnValue from '../utils/resolveFunctionDefi import isReactComponentClass from '../utils/isReactComponentClass'; import isReactForwardRefCall from '../utils/isReactForwardRefCall'; import type Documentation from '../Documentation'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; - -function getDefaultValue(path: NodePath, importer: Importer) { - let node = path.node; - let defaultValue; - if (t.Literal.check(node)) { - // @ts-ignore - defaultValue = node.raw; +import type { DefaultValueDescriptor } from '../Documentation'; +import type { NodePath } from '@babel/traverse'; +import type { + Node, + ObjectMethod, + ObjectProperty, + RestElement, + SpreadElement, +} from '@babel/types'; + +function getDefaultValue(path: NodePath): DefaultValueDescriptor | null { + let defaultValue: string | undefined; + let resolvedPath = path; + let valuePath = path; + if (path.isBooleanLiteral()) { + defaultValue = `${path.node.value}`; + } else if (path.isNullLiteral()) { + defaultValue = 'null'; + } else if (path.isLiteral()) { + defaultValue = path.node.extra?.raw as string; } else { - if (t.AssignmentPattern.check(path.node)) { - path = resolveToValue(path.get('right'), importer); + if (path.isAssignmentPattern()) { + resolvedPath = resolveToValue(path.get('right')); } else { - path = resolveToValue(path, importer); + resolvedPath = resolveToValue(path); } - if (t.ImportDeclaration.check(path.node)) { - defaultValue = node.name; + if (resolvedPath.isImportDeclaration() && path.isIdentifier()) { + defaultValue = path.node.name; } else { - node = path.node; - defaultValue = printValue(path); + valuePath = resolvedPath; + defaultValue = printValue(resolvedPath); } } if (typeof defaultValue !== 'undefined') { return { value: defaultValue, computed: - t.CallExpression.check(node) || - t.MemberExpression.check(node) || - t.Identifier.check(node), + valuePath.isCallExpression() || + valuePath.isMemberExpression() || + valuePath.isIdentifier(), }; } return null; } -function getStatelessPropsPath( - componentDefinition: NodePath, - importer: Importer, -): NodePath { - let value = resolveToValue(componentDefinition, importer); +function getStatelessPropsPath(componentDefinition: NodePath): NodePath { + let value = resolveToValue(componentDefinition); - if (isReactForwardRefCall(value, importer)) { - value = resolveToValue(value.get('arguments', 0), importer); + if (isReactForwardRefCall(value)) { + value = resolveToValue(value.get('arguments')[0]); } - return value.get('params', 0); + return value.get('params')[0]; } -function getDefaultPropsPath( - componentDefinition: NodePath, - importer: Importer, -): NodePath | null { - let defaultPropsPath = getMemberValuePath( +function getDefaultPropsPath(componentDefinition: NodePath): NodePath | null { + let defaultPropsPath: NodePath | null = getMemberValuePath( componentDefinition, 'defaultProps', - importer, ); if (!defaultPropsPath) { return null; } - defaultPropsPath = resolveToValue(defaultPropsPath, importer); + defaultPropsPath = resolveToValue(defaultPropsPath); if (!defaultPropsPath) { return null; } if ( - t.FunctionExpression.check(defaultPropsPath.node) || - t.FunctionDeclaration.check(defaultPropsPath.node) + defaultPropsPath.isFunctionExpression() || + defaultPropsPath.isFunctionDeclaration() || + defaultPropsPath.isClassMethod() || + defaultPropsPath.isObjectMethod() ) { // Find the value that is returned from the function and process it if it is // an object literal. - const returnValue = resolveFunctionDefinitionToReturnValue( - defaultPropsPath, - importer, - ); - if (returnValue && t.ObjectExpression.check(returnValue.node)) { + const returnValue = + resolveFunctionDefinitionToReturnValue(defaultPropsPath); + if (returnValue && returnValue.isObjectExpression()) { defaultPropsPath = returnValue; } } @@ -91,80 +94,76 @@ function getDefaultPropsPath( } function getDefaultValuesFromProps( - properties: NodePath, + properties: Array< + NodePath + >, documentation: Documentation, isStateless: boolean, - importer: Importer, -) { - properties - // Don't evaluate property if component is functional and the node is not an AssignmentPattern - .filter( - propertyPath => - !isStateless || - t.AssignmentPattern.check(propertyPath.get('value').node), - null, - ) - .forEach(propertyPath => { - if (t.Property.check(propertyPath.node)) { - const propName = getPropertyName(propertyPath, importer); - if (!propName) return; - - const propDescriptor = documentation.getPropDescriptor(propName); - const defaultValue = getDefaultValue( - isStateless - ? propertyPath.get('value', 'right') - : propertyPath.get('value'), - importer, - ); - if (defaultValue) { - propDescriptor.defaultValue = defaultValue; +): void { + properties.forEach(propertyPath => { + if (propertyPath.isObjectProperty()) { + const propName = getPropertyName(propertyPath); + + if (!propName) return; + + let valuePath = propertyPath.get('value'); + + if (isStateless) { + if (valuePath.isAssignmentPattern()) { + valuePath = valuePath.get('right'); + } else { + // Don't evaluate property if component is functional and the node is not an AssignmentPattern + return; } - } else if (t.SpreadElement.check(propertyPath.node)) { - const resolvedValuePath = resolveToValue( - propertyPath.get('argument'), - importer, + } + + // Initialize the prop descriptor here after the early return from above + const propDescriptor = documentation.getPropDescriptor(propName); + const defaultValue = getDefaultValue(valuePath); + + if (defaultValue) { + propDescriptor.defaultValue = defaultValue; + } + } else if (propertyPath.isSpreadElement()) { + const resolvedValuePath = resolveToValue(propertyPath.get('argument')); + + if (resolvedValuePath.isObjectExpression()) { + getDefaultValuesFromProps( + resolvedValuePath.get('properties'), + documentation, + isStateless, ); - if (t.ObjectExpression.check(resolvedValuePath.node)) { - getDefaultValuesFromProps( - resolvedValuePath.get('properties'), - documentation, - isStateless, - importer, - ); - } } - }); + } + }); } export default function defaultPropsHandler( documentation: Documentation, componentDefinition: NodePath, - importer: Importer, ): void { let statelessProps: NodePath | null = null; - const defaultPropsPath = getDefaultPropsPath(componentDefinition, importer); + const defaultPropsPath = getDefaultPropsPath(componentDefinition); /** * function, lazy, memo, forwardRef etc components can resolve default props as well */ - if (!isReactComponentClass(componentDefinition, importer)) { - statelessProps = getStatelessPropsPath(componentDefinition, importer); + if (!isReactComponentClass(componentDefinition)) { + statelessProps = getStatelessPropsPath(componentDefinition); } // Do both statelessProps and defaultProps if both are available so defaultProps can override - if (statelessProps && t.ObjectPattern.check(statelessProps.node)) { + if (statelessProps && statelessProps.isObjectPattern()) { getDefaultValuesFromProps( statelessProps.get('properties'), documentation, true, - importer, ); } - if (defaultPropsPath && t.ObjectExpression.check(defaultPropsPath.node)) { + if (defaultPropsPath && defaultPropsPath.isObjectExpression()) { getDefaultValuesFromProps( defaultPropsPath.get('properties'), documentation, false, - importer, ); } } diff --git a/src/handlers/displayNameHandler.ts b/src/handlers/displayNameHandler.ts index 7034a091ac7..10daec4c1b3 100644 --- a/src/handlers/displayNameHandler.ts +++ b/src/handlers/displayNameHandler.ts @@ -1,67 +1,69 @@ -import { namedTypes as t } from 'ast-types'; import getMemberValuePath from '../utils/getMemberValuePath'; import getNameOrValue from '../utils/getNameOrValue'; import isReactForwardRefCall from '../utils/isReactForwardRefCall'; import resolveToValue from '../utils/resolveToValue'; import resolveFunctionDefinitionToReturnValue from '../utils/resolveFunctionDefinitionToReturnValue'; import type Documentation from '../Documentation'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { Node, NodePath } from '@babel/traverse'; export default function displayNameHandler( documentation: Documentation, path: NodePath, - importer: Importer, ): void { - let displayNamePath = getMemberValuePath(path, 'displayName', importer); + let displayNamePath: NodePath | null = getMemberValuePath( + path, + 'displayName', + ); if (!displayNamePath) { // Function and class declarations need special treatment. The name of the // function / class is the displayName - if ( - t.ClassDeclaration.check(path.node) || - t.FunctionDeclaration.check(path.node) - ) { - documentation.set('displayName', getNameOrValue(path.get('id'))); + // TODO test class declaration without id + if (path.isClassDeclaration() || path.isFunctionDeclaration()) { + documentation.set( + 'displayName', + getNameOrValue(path.get('id') as NodePath), + ); } else if ( - t.ArrowFunctionExpression.check(path.node) || - t.FunctionExpression.check(path.node) || - isReactForwardRefCall(path, importer) + path.isArrowFunctionExpression() || + path.isFunctionExpression() || + isReactForwardRefCall(path) ) { let currentPath = path; - while (currentPath.parent) { - if (t.VariableDeclarator.check(currentPath.parent.node)) { + while (currentPath.parentPath) { + if (currentPath.parentPath.isVariableDeclarator()) { documentation.set( 'displayName', - getNameOrValue(currentPath.parent.get('id')), + getNameOrValue(currentPath.parentPath.get('id')), ); return; - } else if (t.AssignmentExpression.check(currentPath.parent.node)) { - const leftPath = currentPath.parent.get('left'); - if ( - t.Identifier.check(leftPath.node) || - t.Literal.check(leftPath.node) - ) { + } else if (currentPath.parentPath.isAssignmentExpression()) { + const leftPath = currentPath.parentPath.get('left'); + if (leftPath.isIdentifier() || leftPath.isLiteral()) { documentation.set('displayName', getNameOrValue(leftPath)); return; } } - currentPath = currentPath.parent; + currentPath = currentPath.parentPath; } } return; } - displayNamePath = resolveToValue(displayNamePath, importer); + displayNamePath = resolveToValue(displayNamePath); // If display name is defined as a getter we get a function expression as // value. In that case we try to determine the value from the return // statement. - if (t.FunctionExpression.check(displayNamePath.node)) { - displayNamePath = resolveFunctionDefinitionToReturnValue( - displayNamePath, - importer, - ); + if ( + displayNamePath.isFunctionExpression() || + displayNamePath.isClassMethod() || + displayNamePath.isObjectMethod() // TODO test objectmethod? Do we need it? + ) { + displayNamePath = resolveFunctionDefinitionToReturnValue(displayNamePath); } - if (!displayNamePath || !t.Literal.check(displayNamePath.node)) { + if ( + !displayNamePath || + (!displayNamePath.isStringLiteral() && !displayNamePath.isNumericLiteral()) + ) { return; } documentation.set('displayName', displayNamePath.node.value); diff --git a/src/handlers/flowTypeHandler.ts b/src/handlers/flowTypeHandler.ts index a78151f69ac..9a76cd9ee9a 100644 --- a/src/handlers/flowTypeHandler.ts +++ b/src/handlers/flowTypeHandler.ts @@ -1,74 +1,62 @@ -import { namedTypes as t } from 'ast-types'; import type Documentation from '../Documentation'; import { unwrapUtilityType } from '../utils/flowUtilityTypes'; import getFlowType from '../utils/getFlowType'; -import getFlowTypeFromReactComponent, { - applyToFlowTypeProperties, -} from '../utils/getFlowTypeFromReactComponent'; +import getTypeFromReactComponent, { + applyToTypeProperties, +} from '../utils/getTypeFromReactComponent'; import getPropertyName from '../utils/getPropertyName'; import getTSType from '../utils/getTSType'; import type { TypeParameters } from '../utils/getTypeParameters'; import resolveToValue from '../utils/resolveToValue'; import setPropDescription from '../utils/setPropDescription'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { FlowType } from '@babel/types'; function setPropDescriptor( documentation: Documentation, path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): void { - if (t.ObjectTypeSpreadProperty.check(path.node)) { - const argument = unwrapUtilityType(path.get('argument')); + if (path.isObjectTypeSpreadProperty()) { + const argument = unwrapUtilityType( + path.get('argument'), + ) as NodePath; - if (t.ObjectTypeAnnotation.check(argument.node)) { - applyToFlowTypeProperties( + if (argument.isObjectTypeAnnotation()) { + applyToTypeProperties( documentation, argument, (propertyPath, innerTypeParams) => { - setPropDescriptor( - documentation, - propertyPath, - innerTypeParams, - importer, - ); + setPropDescriptor(documentation, propertyPath, innerTypeParams); }, typeParams, - importer, ); return; } - const name = argument.get('id').get('name'); - const resolvedPath = resolveToValue( - name, - // TODO: Make this configurable with a pragma comment? - importer, - ); + // TODO what about other types here + const id = argument.get('id') as NodePath; + if (!id.hasNode() || !id.isIdentifier()) { + return; + } + const resolvedPath = resolveToValue(id); - if (resolvedPath && t.TypeAlias.check(resolvedPath.node)) { + if (resolvedPath && resolvedPath.isTypeAlias()) { const right = resolvedPath.get('right'); - applyToFlowTypeProperties( + applyToTypeProperties( documentation, right, (propertyPath, innerTypeParams) => { - setPropDescriptor( - documentation, - propertyPath, - innerTypeParams, - importer, - ); + setPropDescriptor(documentation, propertyPath, innerTypeParams); }, typeParams, - importer, ); - } else if (!argument.node.typeParameters) { - documentation.addComposes(name.node.name); + } else if (!argument.has('typeParameters')) { + documentation.addComposes(id.node.name); } - } else if (t.ObjectTypeProperty.check(path.node)) { - const type = getFlowType(path.get('value'), typeParams, importer); - const propName = getPropertyName(path, importer); + } else if (path.isObjectTypeProperty()) { + const type = getFlowType(path.get('value'), typeParams); + const propName = getPropertyName(path); if (!propName) return; const propDescriptor = documentation.getPropDescriptor(propName); @@ -78,11 +66,15 @@ function setPropDescriptor( // We are doing this here instead of in a different handler // to not need to duplicate the logic for checking for // imported types that are spread in to props. - setPropDescription(documentation, path, importer); - } else if (t.TSPropertySignature.check(path.node)) { - const type = getTSType(path.get('typeAnnotation'), typeParams, importer); + setPropDescription(documentation, path); + } else if (path.isTSPropertySignature()) { + const typeAnnotation = path.get('typeAnnotation'); + if (!typeAnnotation.hasNode()) { + return; + } + const type = getTSType(typeAnnotation, typeParams); - const propName = getPropertyName(path, importer); + const propName = getPropertyName(path); if (!propName) return; const propDescriptor = documentation.getPropDescriptor(propName); @@ -92,7 +84,7 @@ function setPropDescriptor( // We are doing this here instead of in a different handler // to not need to duplicate the logic for checking for // imported types that are spread in to props. - setPropDescription(documentation, path, importer); + setPropDescription(documentation, path); } } @@ -100,25 +92,25 @@ function setPropDescriptor( * This handler tries to find flow Type annotated react components and extract * its types to the documentation. It also extracts docblock comments which are * inlined in the type definition. + * + * TODO either rename this handler or split in flow vs ts */ export default function flowTypeHandler( documentation: Documentation, path: NodePath, - importer: Importer, ): void { - const flowTypesPath = getFlowTypeFromReactComponent(path, importer); + const typesPath = getTypeFromReactComponent(path); - if (!flowTypesPath) { + if (!typesPath) { return; } - applyToFlowTypeProperties( + applyToTypeProperties( documentation, - flowTypesPath, + typesPath, (propertyPath, typeParams) => { - setPropDescriptor(documentation, propertyPath, typeParams, importer); + setPropDescriptor(documentation, propertyPath, typeParams); }, null, - importer, ); } diff --git a/src/handlers/index.ts b/src/handlers/index.ts index 24aba34fbcc..1481e385f27 100644 --- a/src/handlers/index.ts +++ b/src/handlers/index.ts @@ -1,13 +1,18 @@ +import type { NodePath } from '@babel/traverse'; +import type Documentation from '../Documentation'; + export { default as componentDocblockHandler } from './componentDocblockHandler'; export { default as componentMethodsHandler } from './componentMethodsHandler'; export { default as componentMethodsJsDocHandler } from './componentMethodsJsDocHandler'; export { default as defaultPropsHandler } from './defaultPropsHandler'; +export { default as displayNameHandler } from './displayNameHandler'; +export { default as flowTypeHandler } from './flowTypeHandler'; +export { default as propDocBlockHandler } from './propDocBlockHandler'; +export { default as propTypeCompositionHandler } from './propTypeCompositionHandler'; export { propTypeHandler, contextTypeHandler, childContextTypeHandler, } from './propTypeHandler'; -export { default as propTypeCompositionHandler } from './propTypeCompositionHandler'; -export { default as propDocBlockHandler } from './propDocBlockHandler'; -export { default as displayNameHandler } from './displayNameHandler'; -export { default as flowTypeHandler } from './flowTypeHandler'; + +export type Handler = (documentation: Documentation, path: NodePath) => void; diff --git a/src/handlers/propDocBlockHandler.ts b/src/handlers/propDocBlockHandler.ts index 5d9eaba4437..5112f6bd89a 100644 --- a/src/handlers/propDocBlockHandler.ts +++ b/src/handlers/propDocBlockHandler.ts @@ -1,29 +1,27 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { Node } from '@babel/types'; import getMemberValuePath from '../utils/getMemberValuePath'; import resolveToValue from '../utils/resolveToValue'; import setPropDescription from '../utils/setPropDescription'; import type Documentation from '../Documentation'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; function resolveDocumentation( documentation: Documentation, path: NodePath, - importer: Importer, ): void { - if (!t.ObjectExpression.check(path.node)) { + if (!path.isObjectExpression()) { return; } - path.get('properties').each(propertyPath => { - if (t.Property.check(propertyPath.node)) { - setPropDescription(documentation, propertyPath, importer); - } else if (t.SpreadElement.check(propertyPath.node)) { - const resolvedValuePath = resolveToValue( - propertyPath.get('argument'), - importer, - ); - resolveDocumentation(documentation, resolvedValuePath, importer); + path.get('properties').forEach(propertyPath => { + if (propertyPath.isSpreadElement()) { + const resolvedValuePath = resolveToValue(propertyPath.get('argument')); + resolveDocumentation(documentation, resolvedValuePath); + } else if ( + propertyPath.isObjectProperty() || + propertyPath.isObjectMethod() + ) { + setPropDescription(documentation, propertyPath); } }); } @@ -31,16 +29,18 @@ function resolveDocumentation( export default function propDocBlockHandler( documentation: Documentation, path: NodePath, - importer: Importer, ): void { - let propTypesPath = getMemberValuePath(path, 'propTypes', importer); + let propTypesPath: NodePath | null = getMemberValuePath( + path, + 'propTypes', + ); if (!propTypesPath) { return; } - propTypesPath = resolveToValue(propTypesPath, importer); + propTypesPath = resolveToValue(propTypesPath); if (!propTypesPath) { return; } - resolveDocumentation(documentation, propTypesPath, importer); + resolveDocumentation(documentation, propTypesPath); } diff --git a/src/handlers/propTypeCompositionHandler.ts b/src/handlers/propTypeCompositionHandler.ts index 20893d20232..4bb85f5e036 100644 --- a/src/handlers/propTypeCompositionHandler.ts +++ b/src/handlers/propTypeCompositionHandler.ts @@ -1,21 +1,16 @@ -import { namedTypes as t } from 'ast-types'; import getMemberValuePath from '../utils/getMemberValuePath'; import resolveToModule from '../utils/resolveToModule'; import resolveToValue from '../utils/resolveToValue'; import type Documentation from '../Documentation'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { ObjectExpression, Node } from '@babel/types'; /** * It resolves the path to its module name and adds it to the "composes" entry * in the documentation. */ -function amendComposes( - documentation: Documentation, - path: NodePath, - importer: Importer, -): void { - const moduleName = resolveToModule(path, importer); +function amendComposes(documentation: Documentation, path: NodePath): void { + const moduleName = resolveToModule(path); if (moduleName) { documentation.addComposes(moduleName); } @@ -23,19 +18,14 @@ function amendComposes( function processObjectExpression( documentation: Documentation, - path: NodePath, - importer: Importer, + path: NodePath, ): void { - path.get('properties').each(function (propertyPath) { - switch (propertyPath.node.type) { - // @ts-ignore - case t.SpreadElement.name: - amendComposes( - documentation, - resolveToValue(propertyPath.get('argument'), importer), - importer, - ); - break; + path.get('properties').forEach(propertyPath => { + if (propertyPath.isSpreadElement()) { + amendComposes( + documentation, + resolveToValue(propertyPath.get('argument')), + ); } }); } @@ -43,24 +33,23 @@ function processObjectExpression( export default function propTypeCompositionHandler( documentation: Documentation, path: NodePath, - importer: Importer, ): void { - let propTypesPath = getMemberValuePath(path, 'propTypes', importer); + let propTypesPath: NodePath | null = getMemberValuePath( + path, + 'propTypes', + ); if (!propTypesPath) { return; } - propTypesPath = resolveToValue(propTypesPath, importer); + propTypesPath = resolveToValue(propTypesPath); if (!propTypesPath) { return; } - switch (propTypesPath.node.type) { - // @ts-ignore - case t.ObjectExpression.name: - processObjectExpression(documentation, propTypesPath, importer); - break; - default: - amendComposes(documentation, propTypesPath, importer); - break; + if (propTypesPath.isObjectExpression()) { + processObjectExpression(documentation, propTypesPath); + return; } + + amendComposes(documentation, propTypesPath); } diff --git a/src/handlers/propTypeHandler.ts b/src/handlers/propTypeHandler.ts index 0d846a116fa..e8d67d60d0d 100644 --- a/src/handlers/propTypeHandler.ts +++ b/src/handlers/propTypeHandler.ts @@ -1,4 +1,3 @@ -import { namedTypes as t } from 'ast-types'; import getPropType from '../utils/getPropType'; import getPropertyName from '../utils/getPropertyName'; import getMemberValuePath from '../utils/getMemberValuePath'; @@ -9,11 +8,11 @@ import resolveToModule from '../utils/resolveToModule'; import resolveToValue from '../utils/resolveToValue'; import type Documentation from '../Documentation'; import type { PropDescriptor, PropTypeDescriptor } from '../Documentation'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { Node } from '@babel/types'; -function isPropTypesExpression(path: NodePath, importer: Importer): boolean { - const moduleName = resolveToModule(path, importer); +function isPropTypesExpression(path: NodePath): boolean { + const moduleName = resolveToModule(path); if (moduleName) { return isReactModuleName(moduleName) || moduleName === 'ReactPropTypes'; } @@ -23,48 +22,33 @@ function isPropTypesExpression(path: NodePath, importer: Importer): boolean { function amendPropTypes( getDescriptor: (propName: string) => PropDescriptor, path: NodePath, - importer: Importer, ): void { - if (!t.ObjectExpression.check(path.node)) { + if (!path.isObjectExpression()) { return; } - path.get('properties').each((propertyPath: NodePath): void => { - switch (propertyPath.node.type) { - // @ts-ignore - case t.Property.name: { - const propName = getPropertyName(propertyPath, importer); - if (!propName) return; + path.get('properties').forEach(propertyPath => { + if (propertyPath.isObjectProperty()) { + const propName = getPropertyName(propertyPath); + if (!propName) return; - const propDescriptor = getDescriptor(propName); - const valuePath = resolveToValue(propertyPath.get('value'), importer); - const type: PropTypeDescriptor = isPropTypesExpression( - valuePath, - importer, - ) - ? getPropType(valuePath, importer) - : { name: 'custom', raw: printValue(valuePath) }; + const propDescriptor = getDescriptor(propName); + const valuePath = resolveToValue(propertyPath.get('value')); + const type: PropTypeDescriptor = isPropTypesExpression(valuePath) + ? getPropType(valuePath) + : { name: 'custom', raw: printValue(valuePath) }; - if (type) { - propDescriptor.type = type; - propDescriptor.required = - type.name !== 'custom' && isRequiredPropType(valuePath); - } - break; + if (type) { + propDescriptor.type = type; + propDescriptor.required = + type.name !== 'custom' && isRequiredPropType(valuePath); } - // @ts-ignore - case t.SpreadElement.name: { - const resolvedValuePath = resolveToValue( - propertyPath.get('argument'), - importer, - ); - switch (resolvedValuePath.node.type) { - // @ts-ignore - case t.ObjectExpression.name: // normal object literal - amendPropTypes(getDescriptor, resolvedValuePath, importer); - break; - } - break; + } + if (propertyPath.isSpreadElement()) { + const resolvedValuePath = resolveToValue(propertyPath.get('argument')); + if (resolvedValuePath.isObjectExpression()) { + // normal object literal + amendPropTypes(getDescriptor, resolvedValuePath); } } }); @@ -72,17 +56,16 @@ function amendPropTypes( function getPropTypeHandler( propName: string, -): (documentation: Documentation, path: NodePath, importer: Importer) => void { - return function ( - documentation: Documentation, - path: NodePath, - importer: Importer, - ) { - let propTypesPath = getMemberValuePath(path, propName, importer); +): (documentation: Documentation, path: NodePath) => void { + return function (documentation: Documentation, path: NodePath) { + let propTypesPath: NodePath | null = getMemberValuePath( + path, + propName, + ); if (!propTypesPath) { return; } - propTypesPath = resolveToValue(propTypesPath, importer); + propTypesPath = resolveToValue(propTypesPath); if (!propTypesPath) { return; } @@ -97,7 +80,7 @@ function getPropTypeHandler( default: getDescriptor = documentation.getPropDescriptor; } - amendPropTypes(getDescriptor.bind(documentation), propTypesPath, importer); + amendPropTypes(getDescriptor.bind(documentation), propTypesPath); }; } diff --git a/src/importer/ignoreImports.ts b/src/importer/ignoreImports.ts index d9a4cf1b93b..7d44ece037b 100644 --- a/src/importer/ignoreImports.ts +++ b/src/importer/ignoreImports.ts @@ -1,3 +1,7 @@ -export default function ignoreImports(): null { +import type { Importer } from '.'; + +const ignoreImports: Importer = function (): null { return null; -} +}; + +export default ignoreImports; diff --git a/src/importer/index.ts b/src/importer/index.ts index 17a159fd73d..97434bbb0d8 100644 --- a/src/importer/index.ts +++ b/src/importer/index.ts @@ -1,4 +1,21 @@ +import type { NodePath } from '@babel/traverse'; +import type { + ExportAllDeclaration, + ExportNamedDeclaration, + ImportDeclaration, +} from '@babel/types'; +import type FileState from '../FileState'; import ignoreImports from './ignoreImports'; import makeFsImporter from './makeFsImporter'; +export type ImportPath = NodePath< + ExportAllDeclaration | ExportNamedDeclaration | ImportDeclaration +>; + +export type Importer = ( + path: ImportPath, + name: string, + state: FileState, +) => NodePath | null; + export { ignoreImports, makeFsImporter }; diff --git a/src/importer/makeFsImporter.ts b/src/importer/makeFsImporter.ts index a9e9b2056d0..643186e4f26 100644 --- a/src/importer/makeFsImporter.ts +++ b/src/importer/makeFsImporter.ts @@ -1,14 +1,13 @@ -import { namedTypes as t, NodePath as NodePathConstructor } from 'ast-types'; import { traverseShallow } from '../utils/traverse'; import resolve from 'resolve'; import { dirname } from 'path'; -import buildParser from '../babelParser'; -import type { Options } from '../babelParser'; import fs from 'fs'; -import type { NodePath } from 'ast-types/lib/node-path'; -import { Importer } from '../parse'; +import type { NodePath } from '@babel/traverse'; +import type { VariableDeclaration } from '@babel/types'; +import type { Importer, ImportPath } from '.'; +import type FileState from '../FileState'; -function defaultLookupModule(filename, basedir) { +function defaultLookupModule(filename: string, basedir: string): string { return resolve.sync(filename, { basedir, extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx'], @@ -21,26 +20,27 @@ export default function makeFsImporter( filename: string, basedir: string, ) => string = defaultLookupModule, - cache: Map = new Map(), + cache: Map = new Map(), ): Importer { return resolveImportedValue; function resolveImportedValue( - path: NodePath, + path: ImportPath, name: string, + state: FileState, seen: Set = new Set(), ): NodePath | null { // Bail if no filename was provided for the current source file. // Also never traverse into react itself. - const source = path.node.source.value; - const options = getOptions(path); - if (!options || !options.filename || source === 'react') { + const source = path.node.source?.value; + const options = state.opts; + if (!source || !options || !options.filename || source === 'react') { return null; } // Resolve the imported module using the Node resolver const basedir = dirname(options.filename); - let resolvedSource; + let resolvedSource: string | undefined; try { resolvedSource = lookupModule(source, basedir); @@ -55,92 +55,98 @@ export default function makeFsImporter( seen.add(resolvedSource); - let nextPath = cache.get(resolvedSource); - if (!nextPath) { + let nextState = cache.get(resolvedSource); + if (!nextState) { // Read and parse the code const src = fs.readFileSync(resolvedSource, 'utf8'); - const parseOptions: Options = { - ...options, - parserOptions: {}, - filename: resolvedSource, - }; - - const parser = buildParser(parseOptions); - const ast = parser.parse(src); - ast.__src = src; - nextPath = new NodePathConstructor(ast).get('program') as NodePath; - cache.set(resolvedSource, nextPath); - } - - return findExportedValue(nextPath, name, seen); - } + nextState = state.parse(src); - // Find the root Program node, which we attached our options too in babelParser.js - function getOptions(path: NodePath): Options { - while (!t.Program.check(path.node)) { - path = path.parentPath; + cache.set(resolvedSource, nextState); } - // @ts-ignore - return path.node.options || {}; + return findExportedValue(nextState, name, seen); } // Traverses the program looking for an export that matches the requested name function findExportedValue( - programPath: NodePath, + state: FileState, name: string, seen: Set, ): NodePath | null { let resultPath: NodePath | null = null; - traverseShallow(programPath, { - visitExportNamedDeclaration(path: NodePath) { - const { declaration, specifiers, source } = path.node; - if (declaration && declaration.id && declaration.id.name === name) { - resultPath = path.get('declaration'); - } else if (declaration && declaration.declarations) { - path.get('declaration', 'declarations').each((declPath: NodePath) => { - const decl = declPath.node; - // TODO: ArrayPattern and ObjectPattern - if ( - t.Identifier.check(decl.id) && - decl.id.name === name && - decl.init - ) { - resultPath = declPath.get('init'); - } - }); - } else if (specifiers) { - path.get('specifiers').each((specifierPath: NodePath) => { - if (specifierPath.node.exported.name === name) { - if (source) { - const local = specifierPath.node.local.name; - resultPath = resolveImportedValue(path, local, seen); - } else { - resultPath = specifierPath.get('local'); + traverseShallow( + state.ast, + { + ExportNamedDeclaration(path) { + const { declaration, specifiers, source } = path.node; + if ( + declaration && + 'id' in declaration && + declaration.id && + 'name' in declaration.id && + declaration.id.name === name + ) { + resultPath = path.get('declaration') as NodePath; + } else if ( + declaration && + 'declarations' in declaration && + declaration.declarations + ) { + (path.get('declaration') as NodePath) + .get('declarations') + .forEach(declPath => { + const id = declPath.get('id'); + // TODO: ArrayPattern and ObjectPattern + if ( + id.isIdentifier() && + id.node.name === name && + 'init' in declPath.node && + declPath.node.init + ) { + resultPath = declPath.get('init') as NodePath; + } + }); + } else if (specifiers) { + path.get('specifiers').forEach(specifierPath => { + if ( + 'name' in specifierPath.node.exported && + specifierPath.node.exported.name === name + ) { + // TODO TESTME with ExportDefaultSpecifier + if (source) { + const local = + 'local' in specifierPath.node + ? specifierPath.node.local.name + : 'default'; + resultPath = resolveImportedValue(path, local, state, seen); + } else if ('local' in specifierPath.node) { + resultPath = specifierPath.get('local') as NodePath; + } } - } - }); - } - - return false; - }, - visitExportDefaultDeclaration(path: NodePath) { - if (name === 'default') { - resultPath = path.get('declaration'); - } - - return false; - }, - visitExportAllDeclaration(path: NodePath) { - const resolvedPath = resolveImportedValue(path, name, seen); - if (resolvedPath) { - resultPath = resolvedPath; - } - - return false; + }); + } + + return false; + }, + ExportDefaultDeclaration(path) { + if (name === 'default') { + resultPath = path.get('declaration'); + } + + return false; + }, + ExportAllDeclaration(path) { + const resolvedPath = resolveImportedValue(path, name, state, seen); + if (resolvedPath) { + resultPath = resolvedPath; + } + + return false; + }, }, - }); + state.scope, + ); return resultPath; } diff --git a/src/main.ts b/src/main.ts index d7e9d7e89dd..0f09aa5fcff 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,8 +4,11 @@ import * as AllResolver from './resolver'; import * as AllImporter from './importer'; import * as utils from './utils'; import type { Options } from './babelParser'; -import type { DocumentationObject } from './Documentation'; -import type { Handler, Resolver, Importer } from './parse'; +import type { DocumentationObject as Documentation } from './Documentation'; +import type { Resolver } from './resolver'; +import type { Importer } from './importer'; +import type { Handler } from './handlers'; +import type FileState from './FileState'; const defaultResolver: Resolver = AllResolver.findExportedComponentDefinition; const defaultHandlers: Handler[] = [ @@ -21,7 +24,21 @@ const defaultHandlers: Handler[] = [ allHandlers.componentMethodsHandler, allHandlers.componentMethodsJsDocHandler, ]; -const defaultImporter: Importer = AllImporter.ignoreImports; +const defaultImporter: Importer = AllImporter.makeFsImporter(); + +declare module '@babel/traverse' { + export interface HubInterface { + file: FileState; + parse: typeof FileState.prototype.parse; + import: typeof FileState.prototype.import; + } + + export interface Hub { + file: FileState; + parse: typeof FileState.prototype.parse; + import: typeof FileState.prototype.import; + } +} /** * See `parse.js` for more information about the arguments. This function @@ -36,22 +53,14 @@ const defaultImporter: Importer = AllImporter.ignoreImports; * documentation (from a docblock). */ function defaultParse( - src: string | Buffer, - resolver?: Resolver | undefined | null, - handlers?: Handler[] | undefined | null, + src: Buffer | string, + resolver: Resolver = defaultResolver, + handlers: Handler[] = defaultHandlers, + importer: Importer = defaultImporter, // Used for backwards compatibility of this method - options: Options & { importer?: Importer } = {}, -): DocumentationObject[] | DocumentationObject { - if (!resolver) { - resolver = defaultResolver; - } - if (!handlers) { - handlers = defaultHandlers; - } - - const { importer = defaultImporter, ...opts } = options; - - return parse(String(src), resolver, handlers, importer, opts); + options: Options = {}, +): Documentation | Documentation[] { + return parse(String(src), resolver, handlers, importer, options); } export { @@ -62,3 +71,5 @@ export { AllImporter as importers, utils, }; + +export type { Importer, Handler, Resolver, FileState, Options, Documentation }; diff --git a/src/parse.ts b/src/parse.ts index 062ded63ec5..15d5558492a 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -1,39 +1,24 @@ -import type { NodePath } from 'ast-types/lib/node-path'; import Documentation from './Documentation'; import type { DocumentationObject } from './Documentation'; import postProcessDocumentation from './utils/postProcessDocumentation'; import buildParser from './babelParser'; -import type { Options, Parser, FileNodeWithOptions } from './babelParser'; +import type { Options } from './babelParser'; +import type { NodePath } from '@babel/traverse'; +import type { Handler } from './handlers'; +import type { Importer } from './importer'; +import type { Resolver } from './resolver'; +import FileState from './FileState'; const ERROR_MISSING_DEFINITION = 'No suitable component definition found.'; -export type Importer = ( - path: NodePath, - name: string, -) => NodePath | null | undefined; - -export type Handler = ( - documentation: Documentation, - path: NodePath, - importer: Importer, -) => void; -export type Resolver = ( - node: FileNodeWithOptions, - parser: Parser, - importer: Importer, -) => NodePath | NodePath[] | null | undefined; - function executeHandlers( handlers: Handler[], - componentDefinitions: Array>, - importer: Importer, + componentDefinitions: NodePath[], ): DocumentationObject[] { return componentDefinitions.map( (componentDefinition: NodePath): DocumentationObject => { const documentation = new Documentation(); - handlers.forEach(handler => - handler(documentation, componentDefinition, importer), - ); + handlers.forEach(handler => handler(documentation, componentDefinition)); return postProcessDocumentation(documentation.toObject()); }, ); @@ -55,33 +40,30 @@ function executeHandlers( * information from it. They get also passed a reference to a `Documentation` * object to attach the information to. A reference to the parser is parsed as the * last argument. - * - * If `resolver` returns an array of component definitions, `parse` will return - * an array of documentation objects. If `resolver` returns a single node - * instead, `parse` will return a documentation object. */ export default function parse( - src: string, + code: string, resolver: Resolver, handlers: Handler[], importer: Importer, options: Options = {}, -): DocumentationObject[] | DocumentationObject { +): DocumentationObject[] { const parser = buildParser(options); - const ast = parser.parse(src); - ast.__src = src; - const componentDefinitions = resolver(ast, parser, importer); + const ast = parser(code); - if (Array.isArray(componentDefinitions)) { - if (componentDefinitions.length === 0) { - throw new Error(ERROR_MISSING_DEFINITION); - } - return executeHandlers(handlers, componentDefinitions, importer); - } else if (componentDefinitions) { - return executeHandlers(handlers, [componentDefinitions], importer)[0]; - } + const fileState = new FileState(options, { + ast, + code, + importer, + parser, + }); - throw new Error(ERROR_MISSING_DEFINITION); + const componentDefinitions = resolver(fileState); + + if (componentDefinitions.length === 0) { + throw new Error(ERROR_MISSING_DEFINITION); + } + return executeHandlers(handlers, componentDefinitions); } export { ERROR_MISSING_DEFINITION }; diff --git a/src/resolver/__tests__/__snapshots__/findAllExportedComponentDefinitions-test.ts.snap b/src/resolver/__tests__/__snapshots__/findAllExportedComponentDefinitions-test.ts.snap new file mode 100644 index 00000000000..339bca1c2bb --- /dev/null +++ b/src/resolver/__tests__/__snapshots__/findAllExportedComponentDefinitions-test.ts.snap @@ -0,0 +1,3221 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`findAllExportedComponentDefinitions CommonJS module exports React.createClass does not process X.createClass of other modules 1`] = `Array []`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports React.createClass finds React.createClass 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports React.createClass finds React.createClass, independent of the var name 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports React.createClass resolves an imported variable to React.createClass 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports class definitions finds class declarations 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports class definitions finds class definition, independent of the var name 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "R", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports class definitions finds class expression 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports class definitions resolves an imported variable to class declaration 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports class definitions resolves an imported variable to class expression 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports forwardRef components finds forwardRef components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "extra": Object { + "parenStart": 209, + "parenthesized": true, + }, + "openingElement": Node { + "attributes": Array [ + Node { + "name": Node { + "name": "ref", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "name": "ref", + "type": "Identifier", + }, + "type": "JSXExpressionContainer", + }, + }, + Node { + "name": Node { + "name": "style", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "properties": Array [ + Node { + "computed": false, + "key": Node { + "name": "backgroundColor", + "type": "Identifier", + }, + "method": false, + "shorthand": false, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "object": Node { + "name": "props", + "type": "Identifier", + }, + "property": Node { + "name": "color", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + }, + ], + "type": "ObjectExpression", + }, + "type": "JSXExpressionContainer", + }, + }, + ], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [ + Node { + "name": "props", + "type": "Identifier", + }, + Node { + "name": "ref", + "type": "Identifier", + }, + ], + "type": "ArrowFunctionExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports forwardRef components finds none inline forwardRef components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "name": "ColoredView", + "type": "Identifier", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports forwardRef components resolves an imported forwardRef component 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "extra": Object { + "parenStart": 87, + "parenthesized": true, + }, + "openingElement": Node { + "attributes": Array [ + Node { + "name": Node { + "name": "ref", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "name": "ref", + "type": "Identifier", + }, + "type": "JSXExpressionContainer", + }, + }, + Node { + "name": Node { + "name": "style", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "properties": Array [ + Node { + "computed": false, + "key": Node { + "name": "backgroundColor", + "type": "Identifier", + }, + "method": false, + "shorthand": false, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "object": Node { + "name": "props", + "type": "Identifier", + }, + "property": Node { + "name": "color", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + }, + ], + "type": "ObjectExpression", + }, + "type": "JSXExpressionContainer", + }, + }, + ], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [ + Node { + "name": "props", + "type": "Identifier", + }, + Node { + "name": "ref", + "type": "Identifier", + }, + ], + "type": "ArrowFunctionExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; React.createClass finds assignments to exports 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; React.createClass finds exported components only once 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; React.createClass finds multiple exported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; React.createClass finds multiple exported components with hocs 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; React.createClass finds only exported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; React.createClass finds only exported components on export 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; React.createClass supports imported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; class definition finds assignments to exports 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "R", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; class definition finds exported components only once 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentA", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "R", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; class definition finds multiple exported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentA", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "R", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "R", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; class definition finds only exported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "R", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; class definition finds only exported components on export 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "R", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports module.exports = ; / exports.foo = ; class definition supports imported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports stateless components does not process X.createElement of other modules 1`] = `Array []`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports stateless components finds stateless component with JSX 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports stateless components finds stateless components with React.createElement, independent of the var name 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "arguments": Array [ + Node { + "extra": Object { + "raw": "'div'", + "rawValue": "div", + }, + "type": "StringLiteral", + "value": "div", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "R", + "type": "Identifier", + }, + "property": Node { + "name": "createElement", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports stateless components resolves an imported stateless component with JSX 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions CommonJS module exports stateless components resolves an imported stateless component with React.createElement 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "arguments": Array [ + Node { + "extra": Object { + "raw": "'div'", + "rawValue": "div", + }, + "type": "StringLiteral", + "value": "div", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "createElement", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export ; class definition finds multiple components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentA", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export ; class definition finds named exports 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export ; class definition finds only exported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export ; function declaration finds multiple components 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "body": Array [ + Node { + "argument": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "type": "ReturnStatement", + }, + ], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": Node { + "name": "ComponentA", + "type": "Identifier", + }, + "params": Array [], + "type": "FunctionDeclaration", + }, + Node { + "async": false, + "body": Node { + "body": Array [ + Node { + "argument": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "type": "ReturnStatement", + }, + ], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "params": Array [], + "type": "FunctionDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export ; function declaration finds named exports 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "body": Array [ + Node { + "argument": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "type": "ReturnStatement", + }, + ], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "params": Array [], + "type": "FunctionDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export ; function declaration finds only exported components 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "body": Array [ + Node { + "argument": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "type": "ReturnStatement", + }, + ], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "params": Array [], + "type": "FunctionDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; React.createClass finds exported components only once 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; React.createClass finds exported specifiers 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; React.createClass finds exported specifiers 2 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; React.createClass finds exported specifiers 3 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; React.createClass finds multiple components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; React.createClass finds multiple components with hocs 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; React.createClass finds only exported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; React.createClass supports imported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; class definition finds exported components only once 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; class definition finds exported specifiers 1 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; class definition finds exported specifiers 2 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; class definition finds exported specifiers 3 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; class definition finds multiple components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; class definition finds multiple components with hocs 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentA", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; class definition finds only exported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; class definition supports imported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; forwardRef components finds forwardRef components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "extra": Object { + "parenStart": 230, + "parenthesized": true, + }, + "openingElement": Node { + "attributes": Array [ + Node { + "name": Node { + "name": "ref", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "name": "ref", + "type": "Identifier", + }, + "type": "JSXExpressionContainer", + }, + }, + Node { + "name": Node { + "name": "style", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "properties": Array [ + Node { + "computed": false, + "key": Node { + "name": "backgroundColor", + "type": "Identifier", + }, + "method": false, + "shorthand": false, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "object": Node { + "name": "props", + "type": "Identifier", + }, + "property": Node { + "name": "color", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + }, + ], + "type": "ObjectExpression", + }, + "type": "JSXExpressionContainer", + }, + }, + ], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [ + Node { + "name": "props", + "type": "Identifier", + }, + Node { + "name": "ref", + "type": "Identifier", + }, + ], + "type": "ArrowFunctionExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; forwardRef components supports imported components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "extra": Object { + "parenStart": 87, + "parenthesized": true, + }, + "openingElement": Node { + "attributes": Array [ + Node { + "name": Node { + "name": "ref", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "name": "ref", + "type": "Identifier", + }, + "type": "JSXExpressionContainer", + }, + }, + Node { + "name": Node { + "name": "style", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "properties": Array [ + Node { + "computed": false, + "key": Node { + "name": "backgroundColor", + "type": "Identifier", + }, + "method": false, + "shorthand": false, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "object": Node { + "name": "props", + "type": "Identifier", + }, + "property": Node { + "name": "color", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + }, + ], + "type": "ObjectExpression", + }, + "type": "JSXExpressionContainer", + }, + }, + ], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [ + Node { + "name": "props", + "type": "Identifier", + }, + Node { + "name": "ref", + "type": "Identifier", + }, + ], + "type": "ArrowFunctionExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; stateless components finds exported components only once 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; stateless components finds exported specifiers 1 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "body": Array [ + Node { + "argument": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "type": "ReturnStatement", + }, + ], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "params": Array [], + "type": "FunctionDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; stateless components finds exported specifiers 2 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; stateless components finds exported specifiers 3 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "body": Array [ + Node { + "argument": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "type": "ReturnStatement", + }, + ], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "FunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; stateless components finds multiple components 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, + Node { + "async": false, + "body": Node { + "body": Array [ + Node { + "argument": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "type": "ReturnStatement", + }, + ], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "params": Array [], + "type": "FunctionDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; stateless components finds only exported components 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export {}; stateless components supports imported components 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, + Node { + "async": false, + "body": Node { + "arguments": Array [ + Node { + "extra": Object { + "raw": "'div'", + "rawValue": "div", + }, + "type": "StringLiteral", + "value": "div", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "createElement", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; React.createClass finds default export 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; React.createClass finds multiple exported components with export var 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; React.createClass finds multiple exported components with named export 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; React.createClass finds only exported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; React.createClass finds reassigned default export 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; React.createClass supports imported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; class definition finds default export 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; class definition finds default export inline 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; class definition finds multiple exported components with export var 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; class definition finds multiple exported components with named export 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; class definition finds only exported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "ComponentB", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; class definition supports imported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; forwardRef components finds forwardRef components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "extra": Object { + "parenStart": 217, + "parenthesized": true, + }, + "openingElement": Node { + "attributes": Array [ + Node { + "name": Node { + "name": "ref", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "name": "ref", + "type": "Identifier", + }, + "type": "JSXExpressionContainer", + }, + }, + Node { + "name": Node { + "name": "style", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "properties": Array [ + Node { + "computed": false, + "key": Node { + "name": "backgroundColor", + "type": "Identifier", + }, + "method": false, + "shorthand": false, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "object": Node { + "name": "props", + "type": "Identifier", + }, + "property": Node { + "name": "color", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + }, + ], + "type": "ObjectExpression", + }, + "type": "JSXExpressionContainer", + }, + }, + ], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [ + Node { + "name": "props", + "type": "Identifier", + }, + Node { + "name": "ref", + "type": "Identifier", + }, + ], + "type": "ArrowFunctionExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; forwardRef components finds none inline forwardRef components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "name": "ColoredView", + "type": "Identifier", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export default ; forwardRef components supports imported components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "extra": Object { + "parenStart": 87, + "parenthesized": true, + }, + "openingElement": Node { + "attributes": Array [ + Node { + "name": Node { + "name": "ref", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "name": "ref", + "type": "Identifier", + }, + "type": "JSXExpressionContainer", + }, + }, + Node { + "name": Node { + "name": "style", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "properties": Array [ + Node { + "computed": false, + "key": Node { + "name": "backgroundColor", + "type": "Identifier", + }, + "method": false, + "shorthand": false, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "object": Node { + "name": "props", + "type": "Identifier", + }, + "property": Node { + "name": "color", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + }, + ], + "type": "ObjectExpression", + }, + "type": "JSXExpressionContainer", + }, + }, + ], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [ + Node { + "name": "props", + "type": "Identifier", + }, + Node { + "name": "ref", + "type": "Identifier", + }, + ], + "type": "ArrowFunctionExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; React.createClass finds multiple components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; React.createClass finds multiple components with separate export statements 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; React.createClass finds named exports 1 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; React.createClass finds named exports 2 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; React.createClass finds named exports 3 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; React.createClass finds named exports 4 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; React.createClass finds only exported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; React.createClass supports imported components 1`] = ` +Array [ + Node { + "properties": Array [], + "type": "ObjectExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; class definition finds multiple components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; class definition finds multiple components with assigned component 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; class definition finds named exports 1 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; class definition finds named exports 2 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; class definition finds named exports 3 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; class definition finds named exports 4 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; class definition finds only exported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": null, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; class definition supports imported components 1`] = ` +Array [ + Node { + "body": Node { + "body": Array [], + "type": "ClassBody", + }, + "id": Node { + "name": "Component", + "type": "Identifier", + }, + "superClass": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "Component", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "ClassDeclaration", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; forwardRef components finds forwardRef components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "extra": Object { + "parenStart": 237, + "parenthesized": true, + }, + "openingElement": Node { + "attributes": Array [ + Node { + "name": Node { + "name": "ref", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "name": "ref", + "type": "Identifier", + }, + "type": "JSXExpressionContainer", + }, + }, + Node { + "name": Node { + "name": "style", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "properties": Array [ + Node { + "computed": false, + "key": Node { + "name": "backgroundColor", + "type": "Identifier", + }, + "method": false, + "shorthand": false, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "object": Node { + "name": "props", + "type": "Identifier", + }, + "property": Node { + "name": "color", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + }, + ], + "type": "ObjectExpression", + }, + "type": "JSXExpressionContainer", + }, + }, + ], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [ + Node { + "name": "props", + "type": "Identifier", + }, + Node { + "name": "ref", + "type": "Identifier", + }, + ], + "type": "ArrowFunctionExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; forwardRef components supports imported components 1`] = ` +Array [ + Node { + "arguments": Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "extra": Object { + "parenStart": 87, + "parenthesized": true, + }, + "openingElement": Node { + "attributes": Array [ + Node { + "name": Node { + "name": "ref", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "name": "ref", + "type": "Identifier", + }, + "type": "JSXExpressionContainer", + }, + }, + Node { + "name": Node { + "name": "style", + "type": "JSXIdentifier", + }, + "type": "JSXAttribute", + "value": Node { + "expression": Node { + "properties": Array [ + Node { + "computed": false, + "key": Node { + "name": "backgroundColor", + "type": "Identifier", + }, + "method": false, + "shorthand": false, + "type": "ObjectProperty", + "value": Node { + "computed": false, + "object": Node { + "name": "props", + "type": "Identifier", + }, + "property": Node { + "name": "color", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + }, + ], + "type": "ObjectExpression", + }, + "type": "JSXExpressionContainer", + }, + }, + ], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [ + Node { + "name": "props", + "type": "Identifier", + }, + Node { + "name": "ref", + "type": "Identifier", + }, + ], + "type": "ArrowFunctionExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "forwardRef", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; stateless components finds multiple components 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; stateless components finds multiple components with named export 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; stateless components finds named exports 1 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; stateless components finds only exported components 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "body": Array [ + Node { + "argument": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "type": "ReturnStatement", + }, + ], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "FunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; stateless components supports imported components 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, + Node { + "async": false, + "body": Node { + "arguments": Array [ + Node { + "extra": Object { + "raw": "'div'", + "rawValue": "div", + }, + "type": "StringLiteral", + "value": "div", + }, + Node { + "properties": Array [], + "type": "ObjectExpression", + }, + ], + "callee": Node { + "computed": false, + "object": Node { + "name": "React", + "type": "Identifier", + }, + "property": Node { + "name": "createElement", + "type": "Identifier", + }, + "type": "MemberExpression", + }, + "type": "CallExpression", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; stateless components supports imported components 2 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; stateless components supports imported components 3 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; + +exports[`findAllExportedComponentDefinitions ES6 export declarations export var foo = , ...; stateless components supports imported components 4 1`] = ` +Array [ + Node { + "async": false, + "body": Node { + "children": Array [], + "closingElement": null, + "openingElement": Node { + "attributes": Array [], + "name": Node { + "name": "div", + "type": "JSXIdentifier", + }, + "selfClosing": true, + "type": "JSXOpeningElement", + }, + "type": "JSXElement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, +] +`; diff --git a/src/resolver/__tests__/findAllComponentDefinitions-test.ts b/src/resolver/__tests__/findAllComponentDefinitions-test.ts index a2eeaf4baff..22c74f0850d 100644 --- a/src/resolver/__tests__/findAllComponentDefinitions-test.ts +++ b/src/resolver/__tests__/findAllComponentDefinitions-test.ts @@ -1,60 +1,47 @@ -import { NodePath as NodePathConstructor } from 'ast-types'; -import { NodePath } from 'ast-types/lib/node-path'; -import { - getParser, - parse as parseSource, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; -import { Importer } from '../../parse'; +import { NodePath } from '@babel/traverse'; +import { parse, makeMockImporter, noopImporter } from '../../../tests/utils'; import findAllComponentDefinitions from '../findAllComponentDefinitions'; describe('findAllComponentDefinitions', () => { - function parse( + function findComponentsInSource( source: string, - importer: Importer = noopImporter, + importer = noopImporter, ): NodePath[] { - return findAllComponentDefinitions( - parseSource(source).node, - getParser(), - importer, - ); + return findAllComponentDefinitions(parse(source, {}, importer, true)); } const mockImporter = makeMockImporter({ - obj: statement(` - export default {}; - `).get('declaration'), + obj: stmtLast => stmtLast(`export default {};`).get('declaration'), - reactComponent: statement(` - export default React.Component; + reactComponent: stmtLast => + stmtLast(` import React from 'react'; + export default React.Component; `).get('declaration'), - reactPureComponent: statement(` - export default React.PureComponent; + reactPureComponent: stmtLast => + stmtLast(` import React from 'react'; + export default React.PureComponent; `).get('declaration'), - jsxDiv: statement(` - export default
; - `).get('declaration'), + jsxDiv: stmtLast => stmtLast(`export default
;`).get('declaration'), - createElement: statement(` - export default React.createElement('div', null); + createElement: stmtLast => + stmtLast(` import React from 'react'; + export default React.createElement('div', null); `).get('declaration'), - arrowJsx: statement(` - export default (props) =>
{props.children}
; - `).get('declaration'), + arrowJsx: stmtLast => + stmtLast(`export default (props) =>
{props.children}
;`).get( + 'declaration', + ), - coloredView: statement(` - export default function ColoredView(props, ref) { + coloredView: stmtLast => + stmtLast(`export default function ColoredView(props, ref) { return
- }; - `).get('declaration'), + };`).get('declaration'), }); describe('React.createClass', () => { @@ -65,10 +52,10 @@ describe('findAllComponentDefinitions', () => { module.exports = Component; `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); - expect(result[0] instanceof NodePathConstructor).toBe(true); + expect(result[0] instanceof NodePath).toBe(true); expect(result[0].node.type).toBe('ObjectExpression'); }); @@ -80,10 +67,10 @@ describe('findAllComponentDefinitions', () => { module.exports = Component; `; - const result = parse(source, mockImporter); + const result = findComponentsInSource(source, mockImporter); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); - expect(result[0] instanceof NodePathConstructor).toBe(true); + expect(result[0] instanceof NodePath).toBe(true); expect(result[0].node.type).toBe('ObjectExpression'); }); @@ -94,7 +81,7 @@ describe('findAllComponentDefinitions', () => { module.exports = Component; `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); }); @@ -106,7 +93,7 @@ describe('findAllComponentDefinitions', () => { module.exports = Component; `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(0); }); @@ -119,7 +106,7 @@ describe('findAllComponentDefinitions', () => { exports.Component = Component; `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); }); @@ -132,7 +119,7 @@ describe('findAllComponentDefinitions', () => { exports.ComponentB = ComponentB; `; - let result = parse(source); + let result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(2); @@ -143,7 +130,7 @@ describe('findAllComponentDefinitions', () => { module.exports = ComponentB; `; - result = parse(source); + result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(2); }); @@ -160,7 +147,7 @@ describe('findAllComponentDefinitions', () => { class NotAComponent {} `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(4); }); @@ -173,7 +160,7 @@ describe('findAllComponentDefinitions', () => { var ComponentC = class extends PureComponent {} `; - const result = parse(source, mockImporter); + const result = findComponentsInSource(source, mockImporter); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(2); }); @@ -184,7 +171,7 @@ describe('findAllComponentDefinitions', () => { class Component extends R.Component {}; `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); }); @@ -195,7 +182,7 @@ describe('findAllComponentDefinitions', () => { class Component extends R.Component {}; `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(0); }); @@ -227,7 +214,7 @@ describe('findAllComponentDefinitions', () => { }; `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(7); }); @@ -242,7 +229,7 @@ describe('findAllComponentDefinitions', () => { const ComponentC = function(props) { return arrowJsx(props); }; `; - const result = parse(source, mockImporter); + const result = findComponentsInSource(source, mockImporter); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(3); }); @@ -254,7 +241,7 @@ describe('findAllComponentDefinitions', () => { function ComponentB () { return 7; } `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); }); @@ -265,7 +252,7 @@ describe('findAllComponentDefinitions', () => { const ComponentA = () => R.createElement('div', null); `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(0); }); @@ -285,10 +272,10 @@ describe('findAllComponentDefinitions', () => { extendStyles(ColoredView); `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); - expect(result[0].value.type).toEqual('CallExpression'); + expect(result[0].node.type).toEqual('CallExpression'); }); it('finds none inline forwardRef components', () => { @@ -304,10 +291,10 @@ describe('findAllComponentDefinitions', () => { const ForwardedColoredView = React.forwardRef(ColoredView); `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); - expect(result[0].value.type).toEqual('CallExpression'); + expect(result[0].node.type).toEqual('CallExpression'); }); it('resolves imported component wrapped with forwardRef', () => { @@ -317,10 +304,10 @@ describe('findAllComponentDefinitions', () => { const ForwardedColoredView = React.forwardRef(ColoredView); `; - const result = parse(source, mockImporter); + const result = findComponentsInSource(source, mockImporter); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); - expect(result[0].value.type).toEqual('CallExpression'); + expect(result[0].node.type).toEqual('CallExpression'); }); }); @@ -343,10 +330,10 @@ describe('findAllComponentDefinitions', () => { export default TetraAdminTabs; `; - const result = parse(source); + const result = findComponentsInSource(source); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); - expect(result[0].value.type).toEqual('ArrowFunctionExpression'); + expect(result[0].node.type).toEqual('ArrowFunctionExpression'); }); }); }); diff --git a/src/resolver/__tests__/findAllExportedComponentDefinitions-test.ts b/src/resolver/__tests__/findAllExportedComponentDefinitions-test.ts index 28fe915eefe..7f300894669 100644 --- a/src/resolver/__tests__/findAllExportedComponentDefinitions-test.ts +++ b/src/resolver/__tests__/findAllExportedComponentDefinitions-test.ts @@ -1,234 +1,218 @@ -import { NodePath } from 'ast-types/lib/node-path'; -import { - getParser, - parse, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; -import { Importer } from '../../parse'; +import type { NodePath } from '@babel/traverse'; +import { parse, noopImporter, makeMockImporter } from '../../../tests/utils'; import findAllExportedComponentDefinitions from '../findAllExportedComponentDefinitions'; describe('findAllExportedComponentDefinitions', () => { - function findComponents( - path: NodePath, - importer: Importer = noopImporter, + function findComponentsInSource( + source: string, + importer = noopImporter, ): NodePath[] { return findAllExportedComponentDefinitions( - path.node, - getParser(), - importer, + parse(source, {}, importer, true), ); } const mockImporter = makeMockImporter({ - createClass: statement(` - export default React.createClass({}); - import React from 'react'; + createClass: stmtLast => + stmtLast(` + import React from 'react' + export default React.createClass({}) `).get('declaration'), - classDec: statement(` - export default class Component extends React.Component {}; - import React from 'react'; + classDec: stmtLast => + stmtLast(` + import React from 'react' + export default class Component extends React.Component {} `).get('declaration'), - classExpr: statement(` - export default Component; - var Component = class extends React.Component {}; - import React from 'react'; + classExpr: stmtLast => + stmtLast(` + import React from 'react' + var Component = class extends React.Component {} + export default Component `).get('declaration'), - statelessJsx: statement(` - export default () =>
; + statelessJsx: stmtLast => + stmtLast(` + export default () =>
`).get('declaration'), - statelessCreateElement: statement(` - export default () => React.createElement('div', {}); - import React from 'react'; + statelessCreateElement: stmtLast => + stmtLast(` + import React from 'react' + export default () => React.createElement('div', {}) `).get('declaration'), - forwardRef: statement(` + forwardRef: stmtLast => + stmtLast(` + import React from 'react' export default React.forwardRef((props, ref) => (
- )); - import React from 'react'; + )) `).get('declaration'), }); describe('CommonJS module exports', () => { describe('React.createClass', () => { it('finds React.createClass', () => { - const parsed = parse(` + const result = findComponentsInSource(` var React = require("React"); var Component = React.createClass({}); module.exports = Component; `); - const actual = findComponents(parsed); - const expected = parsed.get( - 'body', - 1, - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); }); it('finds React.createClass, independent of the var name', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var Component = R.createClass({}); module.exports = Component; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('does not process X.createClass of other modules', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("NoReact"); var Component = R.createClass({}); module.exports = Component; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(0); + expect(result).toMatchSnapshot(); }); it('resolves an imported variable to React.createClass', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'createClass'; module.exports = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('class definitions', () => { it('finds class declarations', () => { - const parsed = parse(` + const result = findComponentsInSource(` var React = require("React"); class Component extends React.Component {} module.exports = Component; `); - const actual = findComponents(parsed); - const expected = parsed.get('body', 1); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); }); it('finds class expression', () => { - const parsed = parse(` + const result = findComponentsInSource(` var React = require("React"); var Component = class extends React.Component {} module.exports = Component; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('finds class definition, independent of the var name', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); class Component extends R.Component {} module.exports = Component; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('resolves an imported variable to class declaration', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'classDec'; module.exports = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('resolves an imported variable to class expression', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'classExpr'; module.exports = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('stateless components', () => { it('finds stateless component with JSX', () => { - const parsed = parse(` + const result = findComponentsInSource(` var React = require("React"); var Component = () =>
; module.exports = Component; `); - const actual = findComponents(parsed); - const expected = parsed.get('body', 1, 'declarations', 0, 'init'); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); }); it('finds stateless components with React.createElement, independent of the var name', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var Component = () => R.createElement('div', {}); module.exports = Component; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('does not process X.createElement of other modules', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("NoReact"); var Component = () => R.createElement({}); module.exports = Component; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(0); + expect(result).toMatchSnapshot(); }); it('resolves an imported stateless component with JSX', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'statelessJsx'; module.exports = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('resolves an imported stateless component with React.createElement', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'statelessCreateElement'; module.exports = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('forwardRef components', () => { it('finds forwardRef components', () => { - const source = ` + const result = findComponentsInSource(` import React from 'react'; import PropTypes from 'prop-types'; import extendStyles from 'enhancers/extendStyles'; @@ -238,17 +222,13 @@ describe('findAllExportedComponentDefinitions', () => { )); module.exports = extendStyles(ColoredView); - `; - - const parsed = parse(source); - const actual = findComponents(parsed); + `); - expect(actual.length).toBe(1); - expect(actual[0].value.type).toEqual('CallExpression'); + expect(result).toMatchSnapshot(); }); it('finds none inline forwardRef components', () => { - const source = ` + const result = findComponentsInSource(` import React from 'react'; import PropTypes from 'prop-types'; import extendStyles from 'enhancers/extendStyles'; @@ -260,238 +240,176 @@ describe('findAllExportedComponentDefinitions', () => { const ForwardedColoredView = React.forwardRef(ColoredView); module.exports = ForwardedColoredView - `; - - const parsed = parse(source); - const actual = findComponents(parsed); + `); - expect(actual.length).toBe(1); - expect(actual[0].value.type).toEqual('CallExpression'); + expect(result).toMatchSnapshot(); }); it('resolves an imported forwardRef component', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'forwardRef'; module.exports = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); - expect(actual[0].value.type).toEqual('CallExpression'); + expect(result).toMatchSnapshot(); }); }); describe('module.exports = ; / exports.foo = ;', () => { describe('React.createClass', () => { it('finds assignments to exports', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var Component = R.createClass({}); exports.foo = 42; exports.Component = Component; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('finds multiple exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); exports.ComponentA = ComponentA; exports.ComponentB = ComponentB; `); - const actual = findComponents(parsed); - const expectedA = parsed.get( - 'body', - 1, - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - const expectedB = parsed.get( - 'body', - 2, - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - expect(actual.length).toBe(2); - expect(actual[0].node).toBe(expectedA.node); - expect(actual[1].node).toBe(expectedB.node); + expect(result).toMatchSnapshot(); }); it('finds multiple exported components with hocs', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); exports.ComponentA = hoc(ComponentA); exports.ComponentB = hoc(ComponentB); `); - const actual = findComponents(parsed); - const expectedA = parsed.get( - 'body', - 1, - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - const expectedB = parsed.get( - 'body', - 2, - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - expect(actual.length).toBe(2); - expect(actual[0].node).toBe(expectedA.node); - expect(actual[1].node).toBe(expectedB.node); + expect(result).toMatchSnapshot(); }); - it('finds only exported components', () => { - let parsed = parse(` + it('finds only exported components on export', () => { + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); exports.ComponentB = ComponentB; `); - let actual = findComponents(parsed); - const expected = parsed.get( - 'body', - 2, - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds only exported components', () => { + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); module.exports = ComponentB; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('finds exported components only once', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); exports.ComponentA = ComponentA; exports.ComponentB = ComponentA; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'createClass'; exports.ComponentA = Component; exports.ComponentB = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('class definition', () => { it('finds assignments to exports', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); class Component extends R.Component {} exports.foo = 42; exports.Component = Component; `); - const actual = findComponents(parsed); - const expected = parsed.get('body', 1); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); }); it('finds multiple exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); class ComponentA extends R.Component {} class ComponentB extends R.Component {} exports.ComponentA = ComponentA; exports.ComponentB = ComponentB; `); - const actual = findComponents(parsed); - const expectedA = parsed.get('body', 1); - const expectedB = parsed.get('body', 2); - expect(actual.length).toBe(2); - expect(actual[0].node).toBe(expectedA.node); - expect(actual[1].node).toBe(expectedB.node); + expect(result).toMatchSnapshot(); }); - it('finds only exported components', () => { - let parsed = parse(` + it('finds only exported components on export', () => { + const result = findComponentsInSource(` var R = require("React"); class ComponentA extends R.Component {} class ComponentB extends R.Component {} exports.ComponentB = ComponentB; `); - let actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds only exported components', () => { + const result = findComponentsInSource(` var R = require("React"); class ComponentA extends R.Component {} class ComponentB extends R.Component {} module.exports = ComponentB; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('finds exported components only once', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); class ComponentA extends R.Component {} exports.ComponentA = ComponentA; exports.ComponentB = ComponentA; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'classDec'; exports.ComponentA = Component; exports.ComponentB = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); }); @@ -500,176 +418,132 @@ describe('findAllExportedComponentDefinitions', () => { describe('ES6 export declarations', () => { describe('export default ;', () => { describe('React.createClass', () => { - it('finds default export', () => { - let parsed = parse(` + it('finds reassigned default export', () => { + const result = findComponentsInSource(` var React = require("React"); var Component = React.createClass({}); export default Component `); - let actual = findComponents(parsed); - const expected = parsed.get( - 'body', - 1, - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds default export', () => { + const result = findComponentsInSource(` var React = require("React"); export default React.createClass({}); `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); - it('finds multiple exported components', () => { - let parsed = parse(` + it('finds multiple exported components with export var', () => { + const result = findComponentsInSource(` import React, { createElement } from "React" export var Component = React.createClass({}); export default React.createClass({}); `); - let actual = findComponents(parsed); - const expectedA = parsed.get( - 'body', - 1, - 'declaration', - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - const expectedB = parsed.get( - 'body', - 2, - 'declaration', - 'arguments', - 0, - ); - expect(actual.length).toBe(2); - expect(actual[0].node).toBe(expectedA.node); - expect(actual[1].node).toBe(expectedB.node); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds multiple exported components with named export', () => { + const result = findComponentsInSource(` import React, { createElement } from "React" var Component = React.createClass({}) export {Component}; export default React.createClass({}); `); - actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React, { createElement } from "React" var Component = React.createClass({}) export default React.createClass({}); `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` - import Component from 'createClass'; - export default Component; - `); - const actual = findComponents(parsed, mockImporter); + const result = findComponentsInSource( + `import Component from 'createClass'; + export default Component;`, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('class definition', () => { it('finds default export', () => { - let parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; class Component extends React.Component {} export default Component; `); - let actual = findComponents(parsed); - const expected = parsed.get('body', 1); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds default export inline', () => { + const result = findComponentsInSource(` import React from 'React'; export default class Component extends React.Component {}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); - it('finds multiple exported components', () => { - let parsed = parse(` + it('finds multiple exported components with export var', () => { + const result = findComponentsInSource(` import React from 'React'; export var Component = class extends React.Component {}; export default class ComponentB extends React.Component{}; `); - let actual = findComponents(parsed); - const expectedA = parsed.get( - 'body', - 1, - 'declaration', - 'declarations', - 0, - 'init', - ); - const expectedB = parsed.get('body', 2, 'declaration'); - expect(actual.length).toBe(2); - expect(actual[0].node).toBe(expectedA.node); - expect(actual[1].node).toBe(expectedB.node); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds multiple exported components with named export', () => { + const result = findComponentsInSource(` import React from 'React'; var Component = class extends React.Component {}; export {Component}; export default class ComponentB extends React.Component{}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var Component = class extends React.Component {}; export default class ComponentB extends React.Component{}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` - import Component from 'classDec'; - export default Component; - `); - const actual = findComponents(parsed, mockImporter); + const result = findComponentsInSource( + `import Component from 'classDec'; + export default Component;`, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('forwardRef components', () => { it('finds forwardRef components', () => { - const source = ` + const result = findComponentsInSource(` import React from 'react'; import PropTypes from 'prop-types'; import extendStyles from 'enhancers/extendStyles'; @@ -679,17 +553,13 @@ describe('findAllExportedComponentDefinitions', () => { )); export default extendStyles(ColoredView); - `; - - const parsed = parse(source); - const actual = findComponents(parsed); + `); - expect(actual.length).toBe(1); - expect(actual[0].value.type).toEqual('CallExpression'); + expect(result).toMatchSnapshot(); }); it('finds none inline forwardRef components', () => { - const source = ` + const result = findComponentsInSource(` import React from 'react'; import PropTypes from 'prop-types'; import extendStyles from 'enhancers/extendStyles'; @@ -701,310 +571,282 @@ describe('findAllExportedComponentDefinitions', () => { const ForwardedColoredView = React.forwardRef(ColoredView); export default ForwardedColoredView - `; - - const parsed = parse(source); - const actual = findComponents(parsed); + `); - expect(actual.length).toBe(1); - expect(actual[0].value.type).toEqual('CallExpression'); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` - import Component from 'forwardRef'; - export default Component; - `); - const actual = findComponents(parsed, mockImporter); + const result = findComponentsInSource( + `import Component from 'forwardRef'; + export default Component;`, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); }); describe('export var foo = , ...;', () => { describe('React.createClass', () => { - it('finds named exports', () => { - let parsed = parse(` + it('finds named exports 1', () => { + const result = findComponentsInSource(` var React = require("React"); export var somethingElse = 42, Component = React.createClass({}); `); - let actual = findComponents(parsed); - const expected = parsed.get( - 'body', - 1, - 'declaration', - 'declarations', - 1, - 'init', - 'arguments', - 0, - ); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds named exports 2', () => { + const result = findComponentsInSource(` var React = require("React"); export let Component = React.createClass({}), somethingElse = 42; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds named exports 3', () => { + const result = findComponentsInSource(` var React = require("React"); export const something = 21, Component = React.createClass({}), somethingElse = 42; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds named exports 4', () => { + const result = findComponentsInSource(` var React = require("React"); export var somethingElse = function() {}; export let Component = React.createClass({}); `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('finds multiple components', () => { - let parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); export var ComponentA = R.createClass({}), ComponentB = R.createClass({}); `); - let actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds multiple components with separate export statements', () => { + const result = findComponentsInSource(` var R = require("React"); export var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); export {ComponentB}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); export let ComponentB = R.createClass({}); `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` - import Component from 'createClass'; - export let ComponentA = Component; - export let ComponentB = Component; - `); - const actual = findComponents(parsed, mockImporter); + const result = findComponentsInSource( + `import Component from 'createClass'; + export let ComponentA = Component; + export let ComponentB = Component;`, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('class definition', () => { - it('finds named exports', () => { - let parsed = parse(` + it('finds named exports 1', () => { + const result = findComponentsInSource(` import React from 'React'; export var somethingElse = 42, Component = class extends React.Component {}; `); - let actual = findComponents(parsed); - const expected = parsed.get( - 'body', - 1, - 'declaration', - 'declarations', - 1, - 'init', - ); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds named exports 2', () => { + const result = findComponentsInSource(` import React from 'React'; export let Component = class extends React.Component {}, somethingElse = 42; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds named exports 3', () => { + const result = findComponentsInSource(` import React from 'React'; export const something = 21, Component = class extends React.Component {}, somethingElse = 42; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds named exports 4', () => { + const result = findComponentsInSource(` import React from 'React'; export var somethingElse = function() {}; export let Component = class extends React.Component {}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); }); it('finds multiple components', () => { - let parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; export var ComponentA = class extends React.Component {}; export var ComponentB = class extends React.Component {}; `); - let actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds multiple components with assigned component', () => { + const result = findComponentsInSource(` import React from 'React'; export var ComponentA = class extends React.Component {}; var ComponentB = class extends React.Component {}; export {ComponentB}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var ComponentA = class extends React.Component {} export var ComponentB = class extends React.Component {}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'classDec'; export let ComponentA = Component; export let ComponentB = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('stateless components', () => { - it('finds named exports', () => { - let parsed = parse(` + it('finds named exports 1', () => { + const result = findComponentsInSource(` import React from 'React'; export var somethingElse = 42, Component = () =>
; `); - let actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ArrowFunctionExpression'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('supports imported components 2', () => { + const result = findComponentsInSource(` import React from 'React'; export let Component = () =>
, somethingElse = 42; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ArrowFunctionExpression'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('supports imported components 3', () => { + const result = findComponentsInSource(` import React from 'React'; export const something = 21, Component = () =>
, somethingElse = 42; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ArrowFunctionExpression'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('supports imported components 4', () => { + const result = findComponentsInSource(` import React from 'React'; export var somethingElse = function() {}; export let Component = () =>
`); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ArrowFunctionExpression'); + expect(result).toMatchSnapshot(); }); it('finds multiple components', () => { - let parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; export var ComponentA = () =>
export var ComponentB = () =>
`); - let actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds multiple components with named export', () => { + const result = findComponentsInSource(` import React from 'React'; export var ComponentA = () =>
var ComponentB = () =>
export {ComponentB}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var ComponentA = class extends React.Component {} export var ComponentB = function() { return
; }; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('FunctionExpression'); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` - import Component1 from 'statelessJsx'; - import Component2 from 'statelessCreateElement'; - export var ComponentA = Component1, ComponentB = Component2; - `); - const actual = findComponents(parsed, mockImporter); + const result = findComponentsInSource( + `import Component1 from 'statelessJsx'; + import Component2 from 'statelessCreateElement'; + export var ComponentA = Component1, ComponentB = Component2;`, + mockImporter, + ); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); }); describe('forwardRef components', () => { it('finds forwardRef components', () => { - const source = ` + const result = findComponentsInSource(` import React from 'react'; import PropTypes from 'prop-types'; import extendStyles from 'enhancers/extendStyles'; @@ -1012,24 +854,22 @@ describe('findAllExportedComponentDefinitions', () => { export const ColoredView = extendStyles(React.forwardRef((props, ref) => (
))); - `; - - const parsed = parse(source); - const actual = findComponents(parsed); + `); - expect(actual.length).toBe(1); - expect(actual[0].value.type).toEqual('CallExpression'); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'forwardRef'; export let ComponentA = Component; export let ComponentB = Component; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); }); @@ -1037,157 +877,141 @@ describe('findAllExportedComponentDefinitions', () => { describe('export {};', () => { describe('React.createClass', () => { it('finds exported specifiers', () => { - let parsed = parse(` + const result = findComponentsInSource(` var React = require("React"); var foo = 42; var Component = React.createClass({}); export {foo, Component} `); - let actual = findComponents(parsed); - const expected = parsed.get( - 'body', - 2, - 'declarations', - 0, - 'init', - 'arguments', - 0, - ); - expect(actual.length).toBe(1); - expect(actual[0].node).toBe(expected.node); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds exported specifiers 2', () => { + const result = findComponentsInSource(` import React from "React" var foo = 42; var Component = React.createClass({}); export {Component, foo} `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds exported specifiers 3', () => { + const result = findComponentsInSource(` import React, { createElement } from "React" var foo = 42; var baz = 21; var Component = React.createClass({}); export {foo, Component as bar, baz} `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('finds multiple components', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); export {ComponentA as foo, ComponentB}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds multiple components with hocs', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var ComponentA = hoc(R.createClass({})); var ComponentB = hoc(R.createClass({})); export {ComponentA as foo, ComponentB}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); export {ComponentA} `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('finds exported components only once', () => { - const parsed = parse(` + const result = findComponentsInSource(` var R = require("React"); var ComponentA = R.createClass({}); export {ComponentA as foo, ComponentA as bar}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` - import Component from 'createClass'; - export { Component, Component as ComponentB }; - `); - const actual = findComponents(parsed, mockImporter); + const result = findComponentsInSource( + `import Component from 'createClass'; + export { Component, Component as ComponentB };`, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('class definition', () => { - it('finds exported specifiers', () => { - let parsed = parse(` + it('finds exported specifiers 1', () => { + const result = findComponentsInSource(` import React from 'React'; var foo = 42; var Component = class extends React.Component {}; export {foo, Component}; `); - let actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds exported specifiers 2', () => { + const result = findComponentsInSource(` import React from 'React'; var foo = 42; var Component = class extends React.Component {}; export {Component, foo}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds exported specifiers 3', () => { + const result = findComponentsInSource(` import React from 'React'; var foo = 42; var baz = 21; var Component = class extends React.Component {}; export {foo, Component as bar, baz}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); }); it('finds multiple components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var ComponentA = class extends React.Component {}; var ComponentB = class extends React.Component {}; export {ComponentA as foo, ComponentB}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds multiple components with hocs', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; class ComponentA extends React.Component {}; class ComponentB extends React.Component {}; @@ -1195,138 +1019,130 @@ describe('findAllExportedComponentDefinitions', () => { var WrappedB = hoc(ComponentB); export {WrappedA, WrappedB}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var ComponentA = class extends React.Component {}; var ComponentB = class extends React.Component {}; export {ComponentA}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); }); it('finds exported components only once', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var ComponentA = class extends React.Component {}; var ComponentB = class extends React.Component {}; export {ComponentA as foo, ComponentA as bar}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassExpression'); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'classDec'; export { Component, Component as ComponentB }; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); describe('stateless components', () => { - it('finds exported specifiers', () => { - let parsed = parse(` + it('finds exported specifiers 1', () => { + const result = findComponentsInSource(` import React from 'React'; var foo = 42; function Component() { return
; } export {foo, Component}; `); - let actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('FunctionDeclaration'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds exported specifiers 2', () => { + const result = findComponentsInSource(` import React from 'React'; var foo = 42; var Component = () =>
; export {Component, foo}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ArrowFunctionExpression'); + expect(result).toMatchSnapshot(); + }); - parsed = parse(` + it('finds exported specifiers 3', () => { + const result = findComponentsInSource(` import React from 'React'; var foo = 42; var baz = 21; var Component = function () { return
; } export {foo, Component as bar, baz}; `); - actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('FunctionExpression'); + expect(result).toMatchSnapshot(); }); it('finds multiple components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var ComponentA = () =>
; function ComponentB() { return
; } export {ComponentA as foo, ComponentB}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var ComponentA = () =>
; var ComponentB = () =>
; export {ComponentA}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ArrowFunctionExpression'); + expect(result).toMatchSnapshot(); }); it('finds exported components only once', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; var ComponentA = () =>
; var ComponentB = () =>
; export {ComponentA as foo, ComponentA as bar}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ArrowFunctionExpression'); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import ComponentA from 'statelessJsx'; import ComponentB from 'statelessCreateElement'; export { ComponentA, ComponentB }; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); }); describe('forwardRef components', () => { it('finds forwardRef components', () => { - const source = ` + const result = findComponentsInSource(` import React from 'react'; import PropTypes from 'prop-types'; import extendStyles from 'enhancers/extendStyles'; @@ -1336,23 +1152,21 @@ describe('findAllExportedComponentDefinitions', () => { ))); export { ColoredView } - `; - - const parsed = parse(source); - const actual = findComponents(parsed); + `); - expect(actual.length).toBe(1); - expect(actual[0].value.type).toEqual('CallExpression'); + expect(result).toMatchSnapshot(); }); it('supports imported components', () => { - const parsed = parse(` + const result = findComponentsInSource( + ` import Component from 'forwardRef'; export { Component, Component as ComponentB }; - `); - const actual = findComponents(parsed, mockImporter); + `, + mockImporter, + ); - expect(actual.length).toBe(1); + expect(result).toMatchSnapshot(); }); }); }); @@ -1360,75 +1174,65 @@ describe('findAllExportedComponentDefinitions', () => { describe('export ;', () => { describe('class definition', () => { it('finds named exports', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; export var foo = 42; export class Component extends React.Component {}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassDeclaration'); + expect(result).toMatchSnapshot(); }); it('finds multiple components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; export class ComponentA extends React.Component {}; export class ComponentB extends React.Component {}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; class ComponentA extends React.Component {}; export class ComponentB extends React.Component {}; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('ClassDeclaration'); + expect(result).toMatchSnapshot(); }); }); describe('function declaration', () => { it('finds named exports', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; export var foo = 42; export function Component() { return
; }; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('FunctionDeclaration'); + expect(result).toMatchSnapshot(); }); it('finds multiple components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; export function ComponentA() { return
; }; export function ComponentB() { return
; }; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(2); + expect(result).toMatchSnapshot(); }); it('finds only exported components', () => { - const parsed = parse(` + const result = findComponentsInSource(` import React from 'React'; function ComponentA() { return
; } export function ComponentB() { return
; }; `); - const actual = findComponents(parsed); - expect(actual.length).toBe(1); - expect(actual[0].node.type).toBe('FunctionDeclaration'); + expect(result).toMatchSnapshot(); }); }); }); diff --git a/src/resolver/__tests__/findExportedComponentDefinition-test.ts b/src/resolver/__tests__/findExportedComponentDefinition-test.ts index 09adf8bf8bc..5ebb4e5cee4 100644 --- a/src/resolver/__tests__/findExportedComponentDefinition-test.ts +++ b/src/resolver/__tests__/findExportedComponentDefinition-test.ts @@ -1,54 +1,50 @@ -import { NodePath } from 'ast-types/lib/node-path'; -import { - getParser, - parse as parseSource, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; -import { Importer } from '../../parse'; +import type { NodePath } from '@babel/traverse'; +import { noopImporter, makeMockImporter, parse } from '../../../tests/utils'; import findExportedComponentDefinition from '../findExportedComponentDefinition'; describe('findExportedComponentDefinition', () => { - function parse(source: string, importer: Importer = noopImporter): NodePath { - return findExportedComponentDefinition( - parseSource(source).node, - getParser(), - importer, - ) as NodePath; + function findComponentsInSource( + source: string, + importer = noopImporter, + ): NodePath[] { + return findExportedComponentDefinition(parse(source, {}, importer, true)); } const mockImporter = makeMockImporter({ - createClass: statement(` - export default React.createClass({}); - import React from 'react'; + createClass: stmtLast => + stmtLast(` + import React from 'react' + export default React.createClass({}) `).get('declaration'), - classDec: statement(` - export default class Component extends React.Component {}; - import React from 'react'; + classDec: stmtLast => + stmtLast(` + import React from 'react' + export default class Component extends React.Component {} `).get('declaration'), - classExpr: statement(` - export default Component; - var Component = class extends React.Component {}; - import React from 'react'; + classExpr: stmtLast => + stmtLast(` + import React from 'react' + var Component = class extends React.Component {} + export default Component `).get('declaration'), - statelessJsx: statement(` - export default () =>
; - `).get('declaration'), + statelessJsx: stmtLast => + stmtLast(`export default () =>
`).get('declaration'), - statelessCreateElement: statement(` - export default () => React.createElement('div', {}); - import React from 'react'; + statelessCreateElement: stmtLast => + stmtLast(` + import React from 'react' + export default () => React.createElement('div', {}) `).get('declaration'), - forwardRef: statement(` + forwardRef: stmtLast => + stmtLast(` + import React from 'react' export default React.forwardRef((props, ref) => (
- )); - import React from 'react'; + )) `).get('declaration'), }); @@ -61,7 +57,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('finds React.createClass with hoc', () => { @@ -71,7 +69,9 @@ describe('findExportedComponentDefinition', () => { module.exports = hoc(Component); `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('finds React.createClass with hoc and args', () => { @@ -81,7 +81,9 @@ describe('findExportedComponentDefinition', () => { module.exports = hoc(arg1, arg2)(Component); `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('finds React.createClass with two hocs', () => { @@ -93,7 +95,9 @@ describe('findExportedComponentDefinition', () => { ); `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('finds React.createClass with three hocs', () => { @@ -107,7 +111,9 @@ describe('findExportedComponentDefinition', () => { ); `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('finds React.createClass, independent of the var name', () => { @@ -117,7 +123,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('does not process X.createClass of other modules', () => { @@ -127,7 +135,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source)).toBeNull(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(0); }); it('resolves an imported variable to React.createClass', () => { @@ -136,7 +146,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source, mockImporter)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(0); }); }); @@ -148,9 +160,10 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('finds class expression', () => { @@ -160,9 +173,10 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); }); it('finds class definition, independent of the var name', () => { @@ -172,9 +186,10 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('resolves an imported variable to class declaration', () => { @@ -183,9 +198,10 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - const result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('resolves an imported variable to class expression', () => { @@ -194,9 +210,10 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - const result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); }); }); @@ -208,7 +225,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('finds stateless components with React.createElement, independent of the var name', () => { @@ -218,7 +237,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('does not process X.createElement of other modules', () => { @@ -228,7 +249,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source)).toBeNull(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(0); }); it('resolves an imported stateless component with JSX', () => { @@ -237,7 +260,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source, mockImporter)).toBeDefined(); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('resolves an imported stateless component with React.createElement', () => { @@ -246,7 +271,9 @@ describe('findExportedComponentDefinition', () => { module.exports = Component; `; - expect(parse(source, mockImporter)).toBeDefined(); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); }); @@ -260,7 +287,9 @@ describe('findExportedComponentDefinition', () => { exports.Component = Component; `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('errors if multiple components are exported', () => { @@ -272,27 +301,33 @@ describe('findExportedComponentDefinition', () => { exports.ComponentB = ComponentB; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); - it('accepts multiple definitions if only one is exported', () => { - let source = ` + it('accepts multiple definitions if only one is exported on exports', () => { + const source = ` var R = require("React"); var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); exports.ComponentB = ComponentB; `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + }); - source = ` + it('accepts multiple definitions if only one is exported', () => { + const source = ` var R = require("React"); var ComponentA = R.createClass({}); var ComponentB = R.createClass({}); module.exports = ComponentB; `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('supports imported components', () => { @@ -301,7 +336,9 @@ describe('findExportedComponentDefinition', () => { exports.ComponentB = Component; `; - expect(parse(source, mockImporter)).toBeDefined(); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); }); @@ -314,9 +351,10 @@ describe('findExportedComponentDefinition', () => { exports.Component = Component; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('errors if multiple components are exported', () => { @@ -328,7 +366,7 @@ describe('findExportedComponentDefinition', () => { exports.ComponentB = ComponentB; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -339,9 +377,10 @@ describe('findExportedComponentDefinition', () => { exports.ComponentB = ComponentB; `; - let result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); source = ` var R = require("React"); @@ -350,9 +389,10 @@ describe('findExportedComponentDefinition', () => { module.exports = ComponentB; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('supports imported components', () => { @@ -361,9 +401,10 @@ describe('findExportedComponentDefinition', () => { exports.ComponentB = Component; `; - const result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); }); }); @@ -373,37 +414,45 @@ describe('findExportedComponentDefinition', () => { describe('export default ;', () => { describe('React.createClass', () => { it('finds default export', () => { - let source = ` + const source = ` var React = require("React"); var Component = React.createClass({}); export default Component `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + }); - source = ` + it('finds default export inline', () => { + const source = ` var React = require("React"); export default React.createClass({}); `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('errors if multiple components are exported', () => { - let source = ` + const source = ` import React, { createElement } from "React" export var Component = React.createClass({}) export default React.createClass({}); `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); + }); - source = ` + it('errors if multiple components are exported with named export', () => { + const source = ` import React, { createElement } from "React" var Component = React.createClass({}) export {Component}; export default React.createClass({}); `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -413,7 +462,9 @@ describe('findExportedComponentDefinition', () => { export default React.createClass({}); `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('supports imported components', () => { @@ -422,7 +473,9 @@ describe('findExportedComponentDefinition', () => { export default Component; `; - expect(parse(source, mockImporter)).toBeDefined(); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); }); @@ -434,18 +487,20 @@ describe('findExportedComponentDefinition', () => { export default Component; `; - let result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); source = ` import React from 'React'; export default class Component extends React.Component {}; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('finds default export with hoc', () => { @@ -455,9 +510,10 @@ describe('findExportedComponentDefinition', () => { export default hoc(Component); `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('finds default export with hoc and args', () => { @@ -467,9 +523,10 @@ describe('findExportedComponentDefinition', () => { export default hoc(arg1, arg2)(Component); `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('finds default export with two hocs', () => { @@ -481,9 +538,10 @@ describe('findExportedComponentDefinition', () => { ); `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('errors if multiple components are exported', () => { @@ -492,7 +550,7 @@ describe('findExportedComponentDefinition', () => { export var Component = class extends React.Component {}; export default class ComponentB extends React.Component{}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); source = ` import React from 'React'; @@ -500,7 +558,7 @@ describe('findExportedComponentDefinition', () => { export {Component}; export default class ComponentB extends React.Component{}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -510,9 +568,10 @@ describe('findExportedComponentDefinition', () => { export default class ComponentB extends React.Component{}; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('supports imported components', () => { @@ -521,42 +580,61 @@ describe('findExportedComponentDefinition', () => { export default Component; `; - const result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); }); }); describe('export var foo = , ...;', () => { describe('React.createClass', () => { - it('finds named exports', () => { - let source = ` + it('finds named exports with export var', () => { + const source = ` var React = require("React"); export var somethingElse = 42, Component = React.createClass({}); `; - expect(parse(source)).toBeDefined(); - source = ` + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + }); + + it('finds named exports with export let', () => { + const source = ` var React = require("React"); export let Component = React.createClass({}), somethingElse = 42; `; - expect(parse(source)).toBeDefined(); - source = ` + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + }); + + it('finds named exports with export const', () => { + const source = ` var React = require("React"); export const something = 21, Component = React.createClass({}), somethingElse = 42; `; - expect(parse(source)).toBeDefined(); - source = ` + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + }); + + it('finds named exports with export let and additional export', () => { + const source = ` var React = require("React"); export var somethingElse = function() {}; export let Component = React.createClass({}); `; - expect(parse(source)).toBeDefined(); + + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('errors if multiple components are exported', () => { @@ -566,7 +644,7 @@ describe('findExportedComponentDefinition', () => { ComponentB = R.createClass({}); `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); source = ` var R = require("React"); @@ -575,7 +653,7 @@ describe('findExportedComponentDefinition', () => { export {ComponentB}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -585,7 +663,9 @@ describe('findExportedComponentDefinition', () => { export let ComponentB = R.createClass({}); `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('supports imported components', () => { @@ -594,7 +674,9 @@ describe('findExportedComponentDefinition', () => { export let ComponentB = Component; `; - expect(parse(source, mockImporter)).toBeDefined(); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); }); @@ -605,18 +687,20 @@ describe('findExportedComponentDefinition', () => { export var somethingElse = 42, Component = class extends React.Component {}; `; - let result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); source = ` import React from 'React'; export let Component = class extends React.Component {}, somethingElse = 42; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); source = ` import React from 'React'; @@ -624,18 +708,20 @@ describe('findExportedComponentDefinition', () => { Component = class extends React.Component {}, somethingElse = 42; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); source = ` import React from 'React'; export var somethingElse = function() {}; export let Component = class extends React.Component {}; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); }); it('errors if multiple components are exported', () => { @@ -644,7 +730,7 @@ describe('findExportedComponentDefinition', () => { export var ComponentA = class extends React.Component {}; export var ComponentB = class extends React.Component {}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); source = ` import React from 'React'; @@ -652,7 +738,7 @@ describe('findExportedComponentDefinition', () => { var ComponentB = class extends React.Component {}; export {ComponentB}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -661,9 +747,10 @@ describe('findExportedComponentDefinition', () => { var ComponentA = class extends React.Component {} export var ComponentB = class extends React.Component {}; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); }); it('supports imported components', () => { @@ -672,9 +759,10 @@ describe('findExportedComponentDefinition', () => { export let ComponentB = Component; `; - const result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); }); @@ -685,18 +773,20 @@ describe('findExportedComponentDefinition', () => { export var somethingElse = 42, Component = () =>
; `; - let result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); source = ` import React from 'React'; export let Component = () =>
, somethingElse = 42; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); source = ` import React from 'React'; @@ -704,18 +794,20 @@ describe('findExportedComponentDefinition', () => { Component = () =>
, somethingElse = 42; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); source = ` import React from 'React'; export var somethingElse = function() {}; export let Component = () =>
`; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); }); it('errors if multiple components are exported', () => { @@ -724,7 +816,7 @@ describe('findExportedComponentDefinition', () => { export var ComponentA = () =>
export var ComponentB = () =>
`; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); source = ` import React from 'React'; @@ -732,7 +824,7 @@ describe('findExportedComponentDefinition', () => { var ComponentB = () =>
export {ComponentB}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -741,9 +833,10 @@ describe('findExportedComponentDefinition', () => { var ComponentA = class extends React.Component {} export var ComponentB = function() { return
; }; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('FunctionExpression'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('FunctionExpression'); }); it('supports imported components', () => { @@ -752,49 +845,63 @@ describe('findExportedComponentDefinition', () => { export var ComponentA = Component; `; - let result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + let result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); source = ` import Component from 'statelessCreateElement'; export var ComponentB = Component; `; - result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); }); }); }); describe('export {};', () => { describe('React.createClass', () => { - it('finds exported specifiers', () => { - let source = ` + it('finds exported specifiers 1', () => { + const source = ` var React = require("React"); var foo = 42; var Component = React.createClass({}); export {foo, Component} `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + }); - source = ` + it('finds exported specifiers 2', () => { + const source = ` import React from "React" var foo = 42; var Component = React.createClass({}); export {Component, foo} `; - expect(parse(source)).toBeDefined(); - source = ` + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + }); + + it('finds exported specifiers 3', () => { + const source = ` import React, { createElement } from "React" var foo = 42; var baz = 21; var Component = React.createClass({}); export {foo, Component as bar, baz} `; - expect(parse(source)).toBeDefined(); + + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('errors if multiple components are exported', () => { @@ -805,7 +912,7 @@ describe('findExportedComponentDefinition', () => { export {ComponentA as foo, ComponentB}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -816,7 +923,9 @@ describe('findExportedComponentDefinition', () => { export {ComponentA} `; - expect(parse(source)).toBeDefined(); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); it('supports imported components', () => { @@ -825,7 +934,9 @@ describe('findExportedComponentDefinition', () => { export { Component }; `; - expect(parse(source, mockImporter)).toBeDefined(); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); }); }); @@ -837,9 +948,10 @@ describe('findExportedComponentDefinition', () => { var Component = class extends React.Component {}; export {foo, Component}; `; - let result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); source = ` import React from 'React'; @@ -847,9 +959,10 @@ describe('findExportedComponentDefinition', () => { var Component = class extends React.Component {}; export {Component, foo}; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); source = ` import React from 'React'; @@ -858,9 +971,10 @@ describe('findExportedComponentDefinition', () => { var Component = class extends React.Component {}; export {foo, Component as bar, baz}; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); }); it('errors if multiple components are exported', () => { @@ -871,7 +985,7 @@ describe('findExportedComponentDefinition', () => { export {ComponentA as foo, ComponentB}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -881,9 +995,10 @@ describe('findExportedComponentDefinition', () => { var ComponentB = class extends React.Component {}; export {ComponentA}; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassExpression'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassExpression'); }); it('supports imported components', () => { @@ -892,9 +1007,10 @@ describe('findExportedComponentDefinition', () => { export { Component }; `; - const result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); }); @@ -906,9 +1022,10 @@ describe('findExportedComponentDefinition', () => { function Component() { return
; } export {foo, Component}; `; - let result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('FunctionDeclaration'); + let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('FunctionDeclaration'); source = ` import React from 'React'; @@ -916,9 +1033,10 @@ describe('findExportedComponentDefinition', () => { var Component = () =>
; export {Component, foo}; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); source = ` import React from 'React'; @@ -927,9 +1045,10 @@ describe('findExportedComponentDefinition', () => { var Component = function () { return
; } export {foo, Component as bar, baz}; `; - result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('FunctionExpression'); + result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('FunctionExpression'); }); it('errors if multiple components are exported', () => { @@ -940,7 +1059,7 @@ describe('findExportedComponentDefinition', () => { export {ComponentA as foo, ComponentB}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -950,9 +1069,10 @@ describe('findExportedComponentDefinition', () => { var ComponentB = () =>
; export {ComponentA}; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); }); it('supports imported components', () => { @@ -961,18 +1081,20 @@ describe('findExportedComponentDefinition', () => { export { Component as ComponentA }; `; - let result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + let result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); source = ` import Component from 'statelessCreateElement'; export { Component as ComponentB }; `; - result = parse(source, mockImporter); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ArrowFunctionExpression'); + result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ArrowFunctionExpression'); }); }); }); @@ -985,9 +1107,10 @@ describe('findExportedComponentDefinition', () => { export var foo = 42; export class Component extends React.Component {}; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); it('errors if multiple components are exported', () => { @@ -997,7 +1120,7 @@ describe('findExportedComponentDefinition', () => { export class ComponentB extends React.Component {}; `; - expect(() => parse(source)).toThrow(); + expect(() => findComponentsInSource(source)).toThrow(); }); it('accepts multiple definitions if only one is exported', () => { @@ -1006,9 +1129,10 @@ describe('findExportedComponentDefinition', () => { class ComponentA extends React.Component {}; export class ComponentB extends React.Component {}; `; - const result = parse(source); - expect(result).toBeDefined(); - expect(result.node.type).toBe('ClassDeclaration'); + const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); + expect(result).toHaveLength(1); + expect(result[0].node.type).toBe('ClassDeclaration'); }); }); }); diff --git a/src/resolver/findAllComponentDefinitions.ts b/src/resolver/findAllComponentDefinitions.ts index 5abb009d379..70eed20f414 100644 --- a/src/resolver/findAllComponentDefinitions.ts +++ b/src/resolver/findAllComponentDefinitions.ts @@ -1,27 +1,24 @@ -import { ASTNode, namedTypes as t, visit } from 'ast-types'; import isReactComponentClass from '../utils/isReactComponentClass'; import isReactCreateClassCall from '../utils/isReactCreateClassCall'; import isReactForwardRefCall from '../utils/isReactForwardRefCall'; import isStatelessComponent from '../utils/isStatelessComponent'; import normalizeClassDefinition from '../utils/normalizeClassDefinition'; import resolveToValue from '../utils/resolveToValue'; -import type { Parser } from '../babelParser'; -import type { Importer } from '../parse'; -import { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type FileState from '../FileState'; +import type { Resolver } from '.'; /** * Given an AST, this function tries to find all object expressions that are * passed to `React.createClass` calls, by resolving all references properly. */ -export default function findAllComponentDefinitions( - ast: ASTNode, - _parser: Parser, - importer: Importer, +const findAllComponentDefinitions: Resolver = function ( + file: FileState, ): NodePath[] { const definitions = new Set(); function classVisitor(path) { - if (isReactComponentClass(path, importer)) { + if (isReactComponentClass(path)) { normalizeClassDefinition(path); definitions.add(path); } @@ -29,45 +26,42 @@ export default function findAllComponentDefinitions( } function statelessVisitor(path) { - if (isStatelessComponent(path, importer)) { + if (isStatelessComponent(path)) { definitions.add(path); } return false; } - visit(ast, { - visitFunctionDeclaration: statelessVisitor, - visitFunctionExpression: statelessVisitor, - visitArrowFunctionExpression: statelessVisitor, - visitClassExpression: classVisitor, - visitClassDeclaration: classVisitor, - visitCallExpression: function (path): boolean | null | undefined { - if (isReactForwardRefCall(path, importer)) { + file.traverse({ + FunctionDeclaration: statelessVisitor, + FunctionExpression: statelessVisitor, + ObjectMethod: statelessVisitor, + ArrowFunctionExpression: statelessVisitor, + ClassExpression: classVisitor, + ClassDeclaration: classVisitor, + CallExpression: function (path): void { + if (isReactForwardRefCall(path)) { // If the the inner function was previously identified as a component // replace it with the parent node - const inner = resolveToValue(path.get('arguments', 0), importer); + const inner = resolveToValue(path.get('arguments')[0]); definitions.delete(inner); definitions.add(path); // Do not traverse into arguments - return false; - } else if (isReactCreateClassCall(path, importer)) { - const resolvedPath = resolveToValue(path.get('arguments', 0), importer); - if (t.ObjectExpression.check(resolvedPath.node)) { + return path.skip(); + } else if (isReactCreateClassCall(path)) { + const resolvedPath = resolveToValue(path.get('arguments')[0]); + if (resolvedPath.isObjectExpression()) { definitions.add(resolvedPath); } // Do not traverse into arguments - return false; + return path.skip(); } - - // If it is neither of the above cases we need to traverse further - // as this call expression could be a HOC - this.traverse(path); - - return; }, }); return Array.from(definitions); -} +}; + +export default findAllComponentDefinitions; diff --git a/src/resolver/findAllExportedComponentDefinitions.ts b/src/resolver/findAllExportedComponentDefinitions.ts index 7e2c7e504f6..f561626c853 100644 --- a/src/resolver/findAllExportedComponentDefinitions.ts +++ b/src/resolver/findAllExportedComponentDefinitions.ts @@ -1,4 +1,3 @@ -import { ASTNode, namedTypes as t, visit } from 'ast-types'; import isExportsOrModuleAssignment from '../utils/isExportsOrModuleAssignment'; import isReactComponentClass from '../utils/isReactComponentClass'; import isReactCreateClassCall from '../utils/isReactCreateClassCall'; @@ -8,42 +7,38 @@ import normalizeClassDefinition from '../utils/normalizeClassDefinition'; import resolveExportDeclaration from '../utils/resolveExportDeclaration'; import resolveToValue from '../utils/resolveToValue'; import resolveHOC from '../utils/resolveHOC'; -import type { Parser } from '../babelParser'; -import type { Importer } from '../parse'; -import { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import { ignore } from '../utils/traverse'; +import type { + ExportDefaultDeclaration, + ExportNamedDeclaration, +} from '@babel/types'; +import type FileState from '../FileState'; +import type { Resolver } from '.'; -function ignore(): false { - return false; -} - -function isComponentDefinition(path: NodePath, importer: Importer): boolean { +function isComponentDefinition(path: NodePath): boolean { return ( - isReactCreateClassCall(path, importer) || - isReactComponentClass(path, importer) || - isStatelessComponent(path, importer) || - isReactForwardRefCall(path, importer) + isReactCreateClassCall(path) || + isReactComponentClass(path) || + isStatelessComponent(path) || + isReactForwardRefCall(path) ); } -function resolveDefinition( - definition: NodePath, - importer: Importer, -): NodePath | null { - if (isReactCreateClassCall(definition, importer)) { +// TODO duplicate code +function resolveDefinition(definition: NodePath): NodePath | null { + if (isReactCreateClassCall(definition)) { // return argument - const resolvedPath = resolveToValue( - definition.get('arguments', 0), - importer, - ); - if (t.ObjectExpression.check(resolvedPath.node)) { + const resolvedPath = resolveToValue(definition.get('arguments')[0]); + if (resolvedPath.isObjectExpression()) { return resolvedPath; } - } else if (isReactComponentClass(definition, importer)) { + } else if (isReactComponentClass(definition)) { normalizeClassDefinition(definition); return definition; } else if ( - isStatelessComponent(definition, importer) || - isReactForwardRefCall(definition, importer) + isStatelessComponent(definition) || + isReactForwardRefCall(definition) ) { return definition; } @@ -65,88 +60,83 @@ function resolveDefinition( * export default Definition; * export var Definition = ...; */ -export default function findExportedComponentDefinitions( - ast: ASTNode, - _parser: Parser, - importer: Importer, +const findExportedComponentDefinitions: Resolver = function ( + file: FileState, ): NodePath[] { const components: NodePath[] = []; - function exportDeclaration(path: NodePath): boolean | null | undefined { - const definitions: Array = resolveExportDeclaration( - path, - importer, - ) + function exportDeclaration( + path: NodePath, + ): void { + const definitions = resolveExportDeclaration(path) .reduce((acc, definition) => { - if (isComponentDefinition(definition, importer)) { + if (isComponentDefinition(definition)) { acc.push(definition); } else { - const resolved = resolveToValue( - resolveHOC(definition, importer), - importer, - ); - if (isComponentDefinition(resolved, importer)) { + const resolved = resolveToValue(resolveHOC(definition)); + if (isComponentDefinition(resolved)) { acc.push(resolved); } } return acc; }, [] as NodePath[]) - .map(definition => resolveDefinition(definition, importer)); + .map(definition => resolveDefinition(definition)); if (definitions.length === 0) { - return false; + return path.skip(); } definitions.forEach(definition => { if (definition && components.indexOf(definition) === -1) { components.push(definition); } }); - return false; + return path.skip(); } - visit(ast, { - visitFunctionDeclaration: ignore, - visitFunctionExpression: ignore, - visitClassDeclaration: ignore, - visitClassExpression: ignore, - visitIfStatement: ignore, - visitWithStatement: ignore, - visitSwitchStatement: ignore, - // @ts-ignore TODO test implications, write test and then fix - visitCatchCause: ignore, - visitWhileStatement: ignore, - visitDoWhileStatement: ignore, - visitForStatement: ignore, - visitForInStatement: ignore, + file.traverse({ + FunctionDeclaration: ignore, + FunctionExpression: ignore, + ClassDeclaration: ignore, + ClassExpression: ignore, + IfStatement: ignore, + WithStatement: ignore, + SwitchStatement: ignore, + // @ts-ignore TODO TYPO test implications, write test and then fix + //CatchCause: ignore, + WhileStatement: ignore, + DoWhileStatement: ignore, + ForStatement: ignore, + ForInStatement: ignore, - visitExportDeclaration: exportDeclaration, - visitExportNamedDeclaration: exportDeclaration, - visitExportDefaultDeclaration: exportDeclaration, + // TODO Check if this was necessary + //ExportDeclaration: exportDeclaration, + ExportNamedDeclaration: exportDeclaration, + ExportDefaultDeclaration: exportDeclaration, - visitAssignmentExpression: function ( - path: NodePath, - ): boolean | undefined | null { + AssignmentExpression: function (path): void { // Ignore anything that is not `exports.X = ...;` or // `module.exports = ...;` - if (!isExportsOrModuleAssignment(path, importer)) { - return false; + if (!isExportsOrModuleAssignment(path)) { + return path.skip(); } // Resolve the value of the right hand side. It should resolve to a call // expression, something like React.createClass - path = resolveToValue(path.get('right'), importer); - if (!isComponentDefinition(path, importer)) { - path = resolveToValue(resolveHOC(path, importer), importer); - if (!isComponentDefinition(path, importer)) { - return false; + let resolvedPath = resolveToValue(path.get('right')); + if (!isComponentDefinition(resolvedPath)) { + resolvedPath = resolveToValue(resolveHOC(resolvedPath)); + if (!isComponentDefinition(resolvedPath)) { + return path.skip(); } } - const definition = resolveDefinition(path, importer); + const definition = resolveDefinition(resolvedPath); if (definition && components.indexOf(definition) === -1) { components.push(definition); } - return false; + return path.skip(); }, }); return components; -} +}; + +export default findExportedComponentDefinitions; diff --git a/src/resolver/findExportedComponentDefinition.ts b/src/resolver/findExportedComponentDefinition.ts index bc35054c45f..cc8ae8b73c2 100644 --- a/src/resolver/findExportedComponentDefinition.ts +++ b/src/resolver/findExportedComponentDefinition.ts @@ -1,4 +1,3 @@ -import { namedTypes as t, visit } from 'ast-types'; import isExportsOrModuleAssignment from '../utils/isExportsOrModuleAssignment'; import isReactComponentClass from '../utils/isReactComponentClass'; import isReactCreateClassCall from '../utils/isReactCreateClassCall'; @@ -8,45 +7,41 @@ import normalizeClassDefinition from '../utils/normalizeClassDefinition'; import resolveExportDeclaration from '../utils/resolveExportDeclaration'; import resolveToValue from '../utils/resolveToValue'; import resolveHOC from '../utils/resolveHOC'; -import type { FileNodeWithOptions, Parser } from '../babelParser'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import { ignore } from '../utils/traverse'; +import type { + ExportDefaultDeclaration, + ExportNamedDeclaration, +} from '@babel/types'; +import type { Resolver } from '.'; +import type FileState from '../FileState'; const ERROR_MULTIPLE_DEFINITIONS = 'Multiple exported component definitions found.'; -function ignore(): false { - return false; -} - -function isComponentDefinition(path: NodePath, importer: Importer): boolean { +function isComponentDefinition(path: NodePath): boolean { return ( - isReactCreateClassCall(path, importer) || - isReactComponentClass(path, importer) || - isStatelessComponent(path, importer) || - isReactForwardRefCall(path, importer) + isReactCreateClassCall(path) || + isReactComponentClass(path) || + isStatelessComponent(path) || + isReactForwardRefCall(path) ); } -function resolveDefinition( - definition: NodePath, - importer: Importer, -): NodePath | null { - if (isReactCreateClassCall(definition, importer)) { +// TODO duplicate code +function resolveDefinition(definition: NodePath): NodePath | null { + if (isReactCreateClassCall(definition)) { // return argument - const resolvedPath = resolveToValue( - definition.get('arguments', 0), - importer, - ); - if (t.ObjectExpression.check(resolvedPath.node)) { + const resolvedPath = resolveToValue(definition.get('arguments')[0]); + if (resolvedPath.isObjectExpression()) { return resolvedPath; } - } else if (isReactComponentClass(definition, importer)) { + } else if (isReactComponentClass(definition)) { normalizeClassDefinition(definition); return definition; } else if ( - isStatelessComponent(definition, importer) || - isReactForwardRefCall(definition, importer) + isStatelessComponent(definition) || + isReactForwardRefCall(definition) ) { return definition; } @@ -68,24 +63,21 @@ function resolveDefinition( * export default Definition; * export var Definition = ...; */ -export default function findExportedComponentDefinition( - ast: FileNodeWithOptions, - _parser: Parser, - importer: Importer, -): NodePath | null { - let foundDefinition: NodePath | null = null; +const findExportedComponentDefinition: Resolver = function ( + file: FileState, +): NodePath[] { + const foundDefinition: NodePath[] = []; - function exportDeclaration(path: NodePath): false { - const definitions = resolveExportDeclaration(path, importer).reduce( + function exportDeclaration( + path: NodePath, + ): void { + const definitions = resolveExportDeclaration(path).reduce( (acc: NodePath[], definition: NodePath) => { - if (isComponentDefinition(definition, importer)) { + if (isComponentDefinition(definition)) { acc.push(definition); } else { - const resolved = resolveToValue( - resolveHOC(definition, importer), - importer, - ); - if (isComponentDefinition(resolved, importer)) { + const resolved = resolveToValue(resolveHOC(definition)); + if (isComponentDefinition(resolved)) { acc.push(resolved); } } @@ -95,59 +87,65 @@ export default function findExportedComponentDefinition( ); if (definitions.length === 0) { - return false; + return path.skip(); } - if (definitions.length > 1 || foundDefinition) { + if (definitions.length > 1 || foundDefinition.length === 1) { // If a file exports multiple components, ... complain! throw new Error(ERROR_MULTIPLE_DEFINITIONS); } - foundDefinition = resolveDefinition(definitions[0], importer); - return false; + const definition = resolveDefinition(definitions[0]); + if (definition) { + foundDefinition.push(definition); + } + return path.skip(); } - visit(ast, { - visitFunctionDeclaration: ignore, - visitFunctionExpression: ignore, - visitClassDeclaration: ignore, - visitClassExpression: ignore, - visitIfStatement: ignore, - visitWithStatement: ignore, - visitSwitchStatement: ignore, - visitWhileStatement: ignore, - visitDoWhileStatement: ignore, - visitForStatement: ignore, - visitForInStatement: ignore, - visitForOfStatement: ignore, - visitImportDeclaration: ignore, + file.traverse({ + FunctionDeclaration: ignore, + FunctionExpression: ignore, + ClassDeclaration: ignore, + ClassExpression: ignore, + IfStatement: ignore, + WithStatement: ignore, + SwitchStatement: ignore, + WhileStatement: ignore, + DoWhileStatement: ignore, + ForStatement: ignore, + ForInStatement: ignore, + ForOfStatement: ignore, + ImportDeclaration: ignore, - visitExportNamedDeclaration: exportDeclaration, - visitExportDefaultDeclaration: exportDeclaration, + ExportNamedDeclaration: exportDeclaration, + ExportDefaultDeclaration: exportDeclaration, - visitAssignmentExpression: function ( - path: NodePath, - ): false { + AssignmentExpression: function (path): void { // Ignore anything that is not `exports.X = ...;` or // `module.exports = ...;` - if (!isExportsOrModuleAssignment(path, importer)) { - return false; + if (!isExportsOrModuleAssignment(path)) { + return path.skip(); } // Resolve the value of the right hand side. It should resolve to a call // expression, something like React.createClass - path = resolveToValue(path.get('right'), importer); - if (!isComponentDefinition(path, importer)) { - path = resolveToValue(resolveHOC(path, importer), importer); - if (!isComponentDefinition(path, importer)) { - return false; + let resolvedPath = resolveToValue(path.get('right')); + if (!isComponentDefinition(resolvedPath)) { + resolvedPath = resolveToValue(resolveHOC(resolvedPath)); + if (!isComponentDefinition(resolvedPath)) { + return path.skip(); } } - if (foundDefinition) { + if (foundDefinition.length === 1) { // If a file exports multiple components, ... complain! throw new Error(ERROR_MULTIPLE_DEFINITIONS); } - foundDefinition = resolveDefinition(path, importer); - return false; + const definition = resolveDefinition(resolvedPath); + if (definition) { + foundDefinition.push(definition); + } + return path.skip(); }, }); return foundDefinition; -} +}; + +export default findExportedComponentDefinition; diff --git a/src/resolver/index.ts b/src/resolver/index.ts index 3339aabd0f6..628c26efbc2 100644 --- a/src/resolver/index.ts +++ b/src/resolver/index.ts @@ -1,9 +1,12 @@ import findAllComponentDefinitions from './findAllComponentDefinitions'; -import findExportedComponentDefinition from './findExportedComponentDefinition'; import findAllExportedComponentDefinitions from './findAllExportedComponentDefinitions'; +import findExportedComponentDefinition from './findExportedComponentDefinition'; +import type { NodePath } from '@babel/traverse'; +import type FileState from '../FileState'; export { findAllComponentDefinitions, - findExportedComponentDefinition, findAllExportedComponentDefinitions, + findExportedComponentDefinition, }; +export type Resolver = (file: FileState) => NodePath[]; diff --git a/src/utils/__tests__/__snapshots__/getClassMemberValuePath-test.ts.snap b/src/utils/__tests__/__snapshots__/getClassMemberValuePath-test.ts.snap new file mode 100644 index 00000000000..6267e945533 --- /dev/null +++ b/src/utils/__tests__/__snapshots__/getClassMemberValuePath-test.ts.snap @@ -0,0 +1,93 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getClassMemberValuePath ClassDeclaration Getters and Setters finds getters 1`] = ` +Node { + "async": false, + "body": Node { + "body": Array [], + "directives": Array [], + "type": "BlockStatement", + }, + "computed": false, + "generator": false, + "id": null, + "key": Node { + "name": "foo", + "type": "Identifier", + }, + "kind": "get", + "params": Array [], + "static": false, + "type": "ClassMethod", +} +`; + +exports[`getClassMemberValuePath ClassDeclaration MethodDefinitions finds "normal" method definitions 1`] = ` +Node { + "async": false, + "body": Node { + "body": Array [], + "directives": Array [], + "type": "BlockStatement", + }, + "computed": false, + "generator": false, + "id": null, + "key": Node { + "name": "render", + "type": "Identifier", + }, + "kind": "method", + "params": Array [], + "static": false, + "type": "ClassMethod", +} +`; + +exports[`getClassMemberValuePath ClassDeclaration MethodDefinitions finds computed method definitions with literal keys 1`] = ` +Node { + "async": false, + "body": Node { + "body": Array [], + "directives": Array [], + "type": "BlockStatement", + }, + "computed": true, + "generator": false, + "id": null, + "key": Node { + "extra": Object { + "raw": "'render'", + "rawValue": "render", + }, + "type": "StringLiteral", + "value": "render", + }, + "kind": "method", + "params": Array [], + "static": false, + "type": "ClassMethod", +} +`; + +exports[`getClassMemberValuePath ClassExpression finds "normal" method definitions 1`] = ` +Node { + "async": false, + "body": Node { + "body": Array [], + "directives": Array [], + "type": "BlockStatement", + }, + "computed": false, + "generator": false, + "id": null, + "key": Node { + "name": "render", + "type": "Identifier", + }, + "kind": "method", + "params": Array [], + "static": false, + "type": "ClassMethod", +} +`; diff --git a/src/utils/__tests__/__snapshots__/getMembers-test.ts.snap b/src/utils/__tests__/__snapshots__/getMembers-test.ts.snap index 38786eec4a2..fd26a66c182 100644 --- a/src/utils/__tests__/__snapshots__/getMembers-test.ts.snap +++ b/src/utils/__tests__/__snapshots__/getMembers-test.ts.snap @@ -3,177 +3,43 @@ exports[`getMembers does work with custom expressions in arguments 1`] = ` Array [ Object { - "argumentsPath": Node { - "arguments": Array [ - Node { - "end": 18, - "left": Node { - "end": 12, - "loc": SourceLocation { - "end": Position { - "column": 12, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 9, - "line": 1, - }, - }, + "argumentPaths": Array [ + Node { + "left": Node { + "extra": Object { "raw": "123", - "start": 9, - "type": "Literal", - "value": 123, + "rawValue": 123, }, - "loc": SourceLocation { - "end": Position { - "column": 18, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 9, - "line": 1, - }, - }, - "operator": "+", - "right": Node { - "end": 18, - "loc": SourceLocation { - "end": Position { - "column": 18, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 15, - "line": 1, - }, - }, - "raw": "123", - "start": 15, - "type": "Literal", - "value": 123, - }, - "start": 9, - "type": "BinaryExpression", - }, - ], - "callee": Node { - "computed": false, - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 1, - "line": 1, - }, - }, - "object": Node { - "end": 4, - "loc": SourceLocation { - "end": Position { - "column": 4, - "line": 1, - }, - "filename": undefined, - "identifierName": "foo", - "start": Position { - "column": 1, - "line": 1, - }, - }, - "name": "foo", - "start": 1, - "type": "Identifier", + "type": "NumericLiteral", + "value": 123, }, - "optional": false, - "property": Node { - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": "bar", - "start": Position { - "column": 5, - "line": 1, - }, + "operator": "+", + "right": Node { + "extra": Object { + "raw": "123", + "rawValue": 123, }, - "name": "bar", - "start": 5, - "type": "Identifier", - }, - "start": 1, - "type": "MemberExpression", - }, - "end": 19, - "loc": SourceLocation { - "end": Position { - "column": 19, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 1, - "line": 1, + "type": "NumericLiteral", + "value": 123, }, + "type": "BinaryExpression", }, - "optional": false, - "start": 1, - "type": "CallExpression", - }, + ], "computed": false, "path": Node { - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": "bar", - "start": Position { - "column": 5, - "line": 1, - }, - }, "name": "bar", - "start": 5, "type": "Identifier", }, }, Object { - "argumentsPath": null, + "argumentPaths": Array [], "computed": true, "path": Node { - "end": 25, - "loc": SourceLocation { - "end": Position { - "column": 25, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 20, - "line": 1, - }, + "extra": Object { + "raw": "\\"baz\\"", + "rawValue": "baz", }, - "raw": "\\"baz\\"", - "start": 20, - "type": "Literal", + "type": "StringLiteral", "value": "baz", }, }, @@ -183,177 +49,43 @@ Array [ exports[`getMembers does work with custom expressions in chain 1`] = ` Array [ Object { - "argumentsPath": Node { - "arguments": Array [ - Node { - "end": 12, - "loc": SourceLocation { - "end": Position { - "column": 12, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 9, - "line": 1, - }, - }, + "argumentPaths": Array [ + Node { + "extra": Object { "raw": "123", - "start": 9, - "type": "Literal", - "value": 123, + "rawValue": 123, }, - ], - "callee": Node { - "computed": false, - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 1, - "line": 1, - }, - }, - "object": Node { - "end": 4, - "loc": SourceLocation { - "end": Position { - "column": 4, - "line": 1, - }, - "filename": undefined, - "identifierName": "foo", - "start": Position { - "column": 1, - "line": 1, - }, - }, - "name": "foo", - "start": 1, - "type": "Identifier", - }, - "optional": false, - "property": Node { - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": "bar", - "start": Position { - "column": 5, - "line": 1, - }, - }, - "name": "bar", - "start": 5, - "type": "Identifier", - }, - "start": 1, - "type": "MemberExpression", + "type": "NumericLiteral", + "value": 123, }, - "end": 13, - "loc": SourceLocation { - "end": Position { - "column": 13, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 1, - "line": 1, - }, - }, - "optional": false, - "start": 1, - "type": "CallExpression", - }, + ], "computed": false, "path": Node { - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": "bar", - "start": Position { - "column": 5, - "line": 1, - }, - }, "name": "bar", - "start": 5, "type": "Identifier", }, }, Object { - "argumentsPath": null, + "argumentPaths": Array [], "computed": true, "path": Node { - "end": 21, "left": Node { - "end": 16, - "loc": SourceLocation { - "end": Position { - "column": 16, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 14, - "line": 1, - }, + "extra": Object { + "raw": "\\"\\"", + "rawValue": "", }, - "raw": "\\"\\"", - "start": 14, - "type": "Literal", + "type": "StringLiteral", "value": "", }, - "loc": SourceLocation { - "end": Position { - "column": 21, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 14, - "line": 1, - }, - }, "operator": "+", "right": Node { - "end": 21, - "loc": SourceLocation { - "end": Position { - "column": 21, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 19, - "line": 1, - }, + "extra": Object { + "raw": "\\"\\"", + "rawValue": "", }, - "raw": "\\"\\"", - "start": 19, - "type": "Literal", + "type": "StringLiteral", "value": "", }, - "start": 14, "type": "BinaryExpression", }, }, @@ -363,162 +95,39 @@ Array [ exports[`getMembers finds all "members" "inside" a MemberExpression 1`] = ` Array [ Object { - "argumentsPath": Node { - "arguments": Array [ - Node { - "end": 12, - "loc": SourceLocation { - "end": Position { - "column": 12, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 9, - "line": 1, - }, - }, + "argumentPaths": Array [ + Node { + "extra": Object { "raw": "123", - "start": 9, - "type": "Literal", - "value": 123, - }, - ], - "callee": Node { - "computed": false, - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 1, - "line": 1, - }, - }, - "object": Node { - "end": 4, - "loc": SourceLocation { - "end": Position { - "column": 4, - "line": 1, - }, - "filename": undefined, - "identifierName": "foo", - "start": Position { - "column": 1, - "line": 1, - }, - }, - "name": "foo", - "start": 1, - "type": "Identifier", - }, - "optional": false, - "property": Node { - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": "bar", - "start": Position { - "column": 5, - "line": 1, - }, - }, - "name": "bar", - "start": 5, - "type": "Identifier", - }, - "start": 1, - "type": "MemberExpression", - }, - "end": 13, - "loc": SourceLocation { - "end": Position { - "column": 13, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 1, - "line": 1, + "rawValue": 123, }, + "type": "NumericLiteral", + "value": 123, }, - "optional": false, - "start": 1, - "type": "CallExpression", - }, + ], "computed": false, "path": Node { - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": "bar", - "start": Position { - "column": 5, - "line": 1, - }, - }, "name": "bar", - "start": 5, "type": "Identifier", }, }, Object { - "argumentsPath": null, + "argumentPaths": Array [], "computed": true, "path": Node { - "end": 22, - "loc": SourceLocation { - "end": Position { - "column": 22, - "line": 1, - }, - "filename": undefined, - "identifierName": "baz", - "start": Position { - "column": 19, - "line": 1, - }, - }, "name": "baz", - "start": 19, "type": "Identifier", }, }, Object { - "argumentsPath": null, + "argumentPaths": Array [], "computed": true, "path": Node { - "end": 26, - "loc": SourceLocation { - "end": Position { - "column": 26, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 24, - "line": 1, - }, + "extra": Object { + "raw": "42", + "rawValue": 42, }, - "raw": "42", - "start": 24, - "type": "Literal", + "type": "NumericLiteral", "value": 42, }, }, @@ -528,161 +137,35 @@ Array [ exports[`getMembers includes the root if option set to true 1`] = ` Array [ Object { - "argumentsPath": null, + "argumentPaths": Array [], "computed": false, "path": Node { - "end": 4, - "loc": SourceLocation { - "end": Position { - "column": 4, - "line": 1, - }, - "filename": undefined, - "identifierName": "foo", - "start": Position { - "column": 1, - "line": 1, - }, - }, "name": "foo", - "start": 1, "type": "Identifier", }, }, Object { - "argumentsPath": Node { - "arguments": Array [ - Node { - "end": 12, - "loc": SourceLocation { - "end": Position { - "column": 12, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 9, - "line": 1, - }, - }, + "argumentPaths": Array [ + Node { + "extra": Object { "raw": "123", - "start": 9, - "type": "Literal", - "value": 123, - }, - ], - "callee": Node { - "computed": false, - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 1, - "line": 1, - }, - }, - "object": Node { - "end": 4, - "loc": SourceLocation { - "end": Position { - "column": 4, - "line": 1, - }, - "filename": undefined, - "identifierName": "foo", - "start": Position { - "column": 1, - "line": 1, - }, - }, - "name": "foo", - "start": 1, - "type": "Identifier", - }, - "optional": false, - "property": Node { - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": "bar", - "start": Position { - "column": 5, - "line": 1, - }, - }, - "name": "bar", - "start": 5, - "type": "Identifier", + "rawValue": 123, }, - "start": 1, - "type": "MemberExpression", + "type": "NumericLiteral", + "value": 123, }, - "end": 13, - "loc": SourceLocation { - "end": Position { - "column": 13, - "line": 1, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 1, - "line": 1, - }, - }, - "optional": false, - "start": 1, - "type": "CallExpression", - }, + ], "computed": false, "path": Node { - "end": 8, - "loc": SourceLocation { - "end": Position { - "column": 8, - "line": 1, - }, - "filename": undefined, - "identifierName": "bar", - "start": Position { - "column": 5, - "line": 1, - }, - }, "name": "bar", - "start": 5, "type": "Identifier", }, }, Object { - "argumentsPath": null, + "argumentPaths": Array [], "computed": true, "path": Node { - "end": 17, - "loc": SourceLocation { - "end": Position { - "column": 17, - "line": 1, - }, - "filename": undefined, - "identifierName": "baz", - "start": Position { - "column": 14, - "line": 1, - }, - }, "name": "baz", - "start": 14, "type": "Identifier", }, }, diff --git a/src/utils/__tests__/__snapshots__/getMethodDocumentation-test.ts.snap b/src/utils/__tests__/__snapshots__/getMethodDocumentation-test.ts.snap index 9be2c893644..a9f7e2ae3d4 100644 --- a/src/utils/__tests__/__snapshots__/getMethodDocumentation-test.ts.snap +++ b/src/utils/__tests__/__snapshots__/getMethodDocumentation-test.ts.snap @@ -12,4 +12,103 @@ Object { exports[`getMethodDocumentation name ignores complex computed method name 1`] = `null`; +exports[`getMethodDocumentation parameters does not add type parameters to alias 1`] = ` +Object { + "docblock": null, + "modifiers": Array [], + "name": "foo", + "params": Array [ + Object { + "name": "bar", + "optional": false, + "type": Object { + "alias": "Foo", + "elements": Array [ + Object { + "name": "T", + }, + ], + "name": "Foo", + "raw": "Foo", + }, + }, + ], + "returns": null, +} +`; + +exports[`getMethodDocumentation parameters extracts flow type info 1`] = ` +Object { + "docblock": null, + "modifiers": Array [], + "name": "foo", + "params": Array [ + Object { + "name": "bar", + "optional": false, + "type": Object { + "name": "number", + }, + }, + ], + "returns": null, +} +`; + +exports[`getMethodDocumentation parameters extracts flow type info 2`] = ` +Object { + "docblock": null, + "modifiers": Array [], + "name": "foo", + "params": Array [ + Object { + "name": "bar", + "optional": false, + "type": Object { + "name": "number", + }, + }, + ], + "returns": null, +} +`; + +exports[`getMethodDocumentation parameters extracts flow type info on function assignment 1`] = ` +Object { + "docblock": null, + "modifiers": Array [], + "name": "foo", + "params": Array [ + Object { + "name": "bar", + "optional": false, + "type": Object { + "name": "number", + }, + }, + ], + "returns": null, +} +`; + +exports[`getMethodDocumentation parameters private ignores private methods 1`] = `null`; + exports[`getMethodDocumentation parameters private ignores private typescript methods 1`] = `null`; + +exports[`getMethodDocumentation parameters resolves flow type info on imported functions 1`] = ` +Object { + "docblock": null, + "modifiers": Array [], + "name": "foo", + "params": Array [ + Object { + "name": "bar", + "optional": false, + "type": Object { + "name": "number", + }, + }, + ], + "returns": null, +} +`; diff --git a/src/utils/__tests__/__snapshots__/getNameOrValue-test.ts.snap b/src/utils/__tests__/__snapshots__/getNameOrValue-test.ts.snap new file mode 100644 index 00000000000..150e0ee7820 --- /dev/null +++ b/src/utils/__tests__/__snapshots__/getNameOrValue-test.ts.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getNameOrValue gets Identifier name 1`] = `"foo"`; + +exports[`getNameOrValue gets boolean literal value 1`] = `true`; + +exports[`getNameOrValue gets null RegExp pattern 1`] = `"abc?"`; + +exports[`getNameOrValue gets null literal value 1`] = `null`; + +exports[`getNameOrValue gets numeric literal value 1`] = `1`; + +exports[`getNameOrValue gets string literal value 1`] = `"foo"`; diff --git a/src/utils/__tests__/__snapshots__/resolveGenericTypeAnnotations-test.ts.snap b/src/utils/__tests__/__snapshots__/resolveGenericTypeAnnotations-test.ts.snap index 49f80e5323b..4c50b96fd0f 100644 --- a/src/utils/__tests__/__snapshots__/resolveGenericTypeAnnotations-test.ts.snap +++ b/src/utils/__tests__/__snapshots__/resolveGenericTypeAnnotations-test.ts.snap @@ -3,84 +3,28 @@ exports[`resolveGenericTypeAnnotation resolves type 1`] = ` Node { "callProperties": Array [], - "end": 57, "exact": false, "indexers": Array [], "inexact": false, "internalSlots": Array [], - "loc": SourceLocation { - "end": Position { - "column": 34, - "line": 3, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 21, - "line": 3, - }, - }, "properties": Array [ Node { - "end": 55, "key": Node { - "end": 47, - "loc": SourceLocation { - "end": Position { - "column": 24, - "line": 3, - }, - "filename": undefined, - "identifierName": "x", - "start": Position { - "column": 23, - "line": 3, - }, - }, "name": "x", - "start": 46, "type": "Identifier", }, "kind": "init", - "loc": SourceLocation { - "end": Position { - "column": 32, - "line": 3, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 23, - "line": 3, - }, - }, "method": false, "optional": false, "proto": false, - "start": 46, "static": false, "type": "ObjectTypeProperty", "value": Node { - "end": 55, - "loc": SourceLocation { - "end": Position { - "column": 32, - "line": 3, - }, - "filename": undefined, - "identifierName": undefined, - "start": Position { - "column": 26, - "line": 3, - }, - }, - "start": 49, "type": "StringTypeAnnotation", }, "variance": null, }, ], - "start": 44, "type": "ObjectTypeAnnotation", } `; diff --git a/src/utils/__tests__/docblock-test.ts b/src/utils/__tests__/docblock-test.ts index df8bd626c00..e6cc2825423 100644 --- a/src/utils/__tests__/docblock-test.ts +++ b/src/utils/__tests__/docblock-test.ts @@ -1,4 +1,4 @@ -import { statement } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; import { getDoclets, getDocblock } from '../docblock'; describe('docblock', () => { @@ -37,7 +37,7 @@ describe('docblock', () => { ]; it('gets the closest docblock of the given node', () => { - const node = statement(source.join('\n')); + const node = parse.statement(source.join('\n')); expect(getDocblock(node)).toEqual(comment.join('\n')); }); @@ -50,13 +50,13 @@ describe('docblock', () => { ]; terminators.forEach(t => { it('can handle ' + escape(t) + ' as line terminator', () => { - const node = statement(source.join(t)); + const node = parse.statement(source.join(t)); expect(getDocblock(node)).toEqual(comment.join(t)); }); }); it('supports "short" docblocks', () => { - const node = statement('/** bar */\nfoo;'); + const node = parse.statement('/** bar */\nfoo;'); expect(getDocblock(node)).toEqual('bar'); }); }); diff --git a/src/utils/__tests__/expressionTo-test.ts b/src/utils/__tests__/expressionTo-test.ts index 44b5a142e23..c31ddac8288 100644 --- a/src/utils/__tests__/expressionTo-test.ts +++ b/src/utils/__tests__/expressionTo-test.ts @@ -1,53 +1,55 @@ -import { expression, noopImporter } from '../../../tests/utils'; +import { parse, parseTypescript } from '../../../tests/utils'; import { Array as expressionToArray } from '../expressionTo'; describe('expressionTo', () => { describe('MemberExpression', () => { it('with only identifiers', () => { - expect( - expressionToArray(expression('foo.bar.baz'), noopImporter), - ).toEqual(['foo', 'bar', 'baz']); + expect(expressionToArray(parse.expression('foo.bar.baz'))).toEqual([ + 'foo', + 'bar', + 'baz', + ]); }); it('with one computed literal', () => { - expect( - expressionToArray(expression('foo["bar"].baz'), noopImporter), - ).toEqual(['foo', '"bar"', 'baz']); + expect(expressionToArray(parse.expression('foo["bar"].baz'))).toEqual([ + 'foo', + '"bar"', + 'baz', + ]); }); it('with one computed identifier', () => { - expect( - expressionToArray(expression('foo[bar].baz'), noopImporter), - ).toEqual(['foo', 'bar', 'baz']); + expect(expressionToArray(parse.expression('foo[bar].baz'))).toEqual([ + 'foo', + 'bar', + 'baz', + ]); }); it('with one computed object', () => { expect( - expressionToArray(expression('foo[{ a: "true"}].baz'), noopImporter), + expressionToArray(parse.expression('foo[{ a: "true"}].baz')), ).toEqual(['foo', '{a: "true"}', 'baz']); }); it('with one computed object with spread', () => { - expect( - expressionToArray(expression('foo[{ ...a }].baz'), noopImporter), - ).toEqual(['foo', '{...a}', 'baz']); + expect(expressionToArray(parse.expression('foo[{ ...a }].baz'))).toEqual([ + 'foo', + '{...a}', + 'baz', + ]); }); it('with one computed object with method', () => { - expect( - expressionToArray(expression('foo[{ a(){} }].baz'), noopImporter), - ).toEqual(['foo', '{a: }', 'baz']); + expect(expressionToArray(parse.expression('foo[{ a(){} }].baz'))).toEqual( + ['foo', '{a: }', 'baz'], + ); }); it('with TSAsExpression', () => { expect( - expressionToArray( - expression('(baz as X).prop', { - filename: 'file.ts', - parserOptions: { plugins: ['typescript'] }, - }), - noopImporter, - ), + expressionToArray(parseTypescript.expression('(baz as X).prop')), ).toEqual(['baz', 'prop']); }); }); diff --git a/src/utils/__tests__/flowUtilityTypes-test.ts b/src/utils/__tests__/flowUtilityTypes-test.ts index 15c4c2a4def..5c4f1937911 100644 --- a/src/utils/__tests__/flowUtilityTypes-test.ts +++ b/src/utils/__tests__/flowUtilityTypes-test.ts @@ -1,73 +1,90 @@ import { unwrapUtilityType, isSupportedUtilityType } from '../flowUtilityTypes'; -import { statement } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import type { GenericTypeAnnotation, TypeAlias } from '@babel/types'; describe('flowTypeUtilities', () => { describe('unwrapUtilityType', () => { it('correctly unwraps', () => { - const def = statement(` + const def = parse.statement(` type A = $ReadOnly<{ foo: string }> `); expect(unwrapUtilityType(def.get('right'))).toBe( - def.get('right', 'typeParameters', 'params', 0), + (def.get('right') as NodePath) + .get('typeParameters') + .get('params')[0], ); }); it('correctly unwraps double', () => { - const def = statement(` + const def = parse.statement(` type A = $ReadOnly<$ReadOnly<{ foo: string }>> `); expect(unwrapUtilityType(def.get('right'))).toBe( - def.get( - 'right', - 'typeParameters', - 'params', - 0, - 'typeParameters', - 'params', - 0, - ), + ( + (def.get('right') as NodePath) + .get('typeParameters') + .get('params')[0] as NodePath + ) + .get('typeParameters') + .get('params')[0], ); }); it('correctly unwraps triple', () => { - const def = statement(` + const def = parse.statement(` type A = $ReadOnly<$ReadOnly<$ReadOnly<{ foo: string }>>> `); expect(unwrapUtilityType(def.get('right'))).toBe( - def.get( - 'right', - 'typeParameters', - 'params', - 0, - 'typeParameters', - 'params', - 0, - 'typeParameters', - 'params', - 0, - ), + ( + ( + (def.get('right') as NodePath) + .get('typeParameters') + .get('params')[0] as NodePath + ) + .get('typeParameters') + .get('params')[0] as NodePath + ) + .get('typeParameters') + .get('params')[0], ); }); }); describe('isSupportedUtilityType', () => { - it('correctly returns true for valid type', () => { - const def = statement(` + it('correctly returns true for $Exact', () => { + const def = parse.statement(` type A = $Exact<{ foo: string }> `); expect(isSupportedUtilityType(def.get('right'))).toBe(true); }); + it('correctly returns true for $ReadOnly', () => { + const def = parse.statement(` + type A = $ReadOnly<{ foo: string }> + `); + + expect(isSupportedUtilityType(def.get('right'))).toBe(true); + }); + it('correctly returns false for invalid type', () => { - const def = statement(` + const def = parse.statement(` type A = $Homer<{ foo: string }> `); expect(isSupportedUtilityType(def.get('right'))).toBe(false); }); + + it('correctly returns false for QualifiedTypeIdentifier', () => { + const def = parse.statement(` + type A = $Homer.Marge<{ foo: string }> + `); + + expect(isSupportedUtilityType(def.get('right'))).toBe(false); + }); }); }); diff --git a/src/utils/__tests__/getClassMemberValuePath-test.ts b/src/utils/__tests__/getClassMemberValuePath-test.ts index 8b7afba4a62..31f4aa86da3 100644 --- a/src/utils/__tests__/getClassMemberValuePath-test.ts +++ b/src/utils/__tests__/getClassMemberValuePath-test.ts @@ -1,103 +1,122 @@ import getClassMemberValuePath from '../getClassMemberValuePath'; -import { statement } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; +import type { ClassDeclaration, ClassExpression } from '@babel/types'; describe('getClassMemberValuePath', () => { - describe('MethodDefinitions', () => { - it('finds "normal" method definitions', () => { - const def = statement(` + describe('ClassDeclaration', () => { + describe('MethodDefinitions', () => { + it('finds "normal" method definitions', () => { + const def = parse.statement(` class Foo { render() {} } `); - expect(getClassMemberValuePath(def, 'render')).toBe( - def.get('body', 'body', 0, 'value'), - ); - }); + expect(getClassMemberValuePath(def, 'render')).toMatchSnapshot(); + }); - it('finds computed method definitions with literal keys', () => { - const def = statement(` + it('finds computed method definitions with literal keys', () => { + const def = parse.statement(` class Foo { ['render']() {} } `); - expect(getClassMemberValuePath(def, 'render')).toBe( - def.get('body', 'body', 0, 'value'), - ); - }); + expect(getClassMemberValuePath(def, 'render')).toMatchSnapshot(); + }); - it('ignores computed method definitions with expression', () => { - const def = statement(` + it('ignores computed method definitions with expression', () => { + const def = parse.statement(` class Foo { [render]() {} } `); - expect(getClassMemberValuePath(def, 'render')).not.toBeDefined(); + expect(getClassMemberValuePath(def, 'render')).toBeNull(); + }); }); - }); - describe('Getters and Setters', () => { - it('finds getters', () => { - const def = statement(` + describe('Getters and Setters', () => { + it('finds getters', () => { + const def = parse.statement(` class Foo { get foo() {} } `); - expect(getClassMemberValuePath(def, 'foo')).toBe( - def.get('body', 'body', 0, 'value'), - ); - }); + expect(getClassMemberValuePath(def, 'foo')).toMatchSnapshot(); + }); - it('ignores setters', () => { - const def = statement(` + it('ignores setters', () => { + const def = parse.statement(` class Foo { set foo(val) {} } `); - expect(getClassMemberValuePath(def, 'foo')).not.toBeDefined(); + expect(getClassMemberValuePath(def, 'foo')).toBeNull(); + }); }); - }); - describe('ClassProperty', () => { - it('finds "normal" class properties', () => { - const def = statement(` + describe('ClassProperty', () => { + it('finds "normal" class properties', () => { + const def = parse.statement(` class Foo { foo = 42; } `); - expect(getClassMemberValuePath(def, 'foo')).toBe( - def.get('body', 'body', 0, 'value'), - ); + expect(getClassMemberValuePath(def, 'foo')).toEqual( + def.get('body').get('body')[0].get('value'), + ); + }); }); - }); - describe('PrivateClassProperty', () => { - it('ignores private class properties', () => { - const def = statement(` + describe('private', () => { + it('ignores private class properties', () => { + const def = parse.statement(` class Foo { #foo = 42; } `); - expect(getClassMemberValuePath(def, 'foo')).toBe(undefined); - }); + expect(getClassMemberValuePath(def, 'foo')).toBeNull(); + }); + + it('ignores private class methods', () => { + const def = parse.statement(` + class Foo { + #foo() {} + } + `); - it('finds "normal" class properties with private present', () => { - const def = statement(` + expect(getClassMemberValuePath(def, 'foo')).toBeNull(); + }); + + it('finds "normal" class properties with private present', () => { + const def = parse.statement(` class Foo { #private = 54; foo = 42; } `); - expect(getClassMemberValuePath(def, 'foo')).toBe( - def.get('body', 'body', 1, 'value'), - ); + expect(getClassMemberValuePath(def, 'foo')).toBe( + def.get('body').get('body')[1].get('value'), + ); + }); + }); + }); + + describe('ClassExpression', () => { + it('finds "normal" method definitions', () => { + const def = parse.expression(` + class Foo { + render() {} + } + `); + + expect(getClassMemberValuePath(def, 'render')).toMatchSnapshot(); }); }); }); diff --git a/src/utils/__tests__/getFlowType-test.ts b/src/utils/__tests__/getFlowType-test.ts index 040619b59da..78ccda78d7d 100644 --- a/src/utils/__tests__/getFlowType-test.ts +++ b/src/utils/__tests__/getFlowType-test.ts @@ -1,57 +1,72 @@ import getFlowType from '../getFlowType'; -import { - expression, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; +import type { + ExportNamedDeclaration, + ExpressionStatement, + FlowType, + Identifier, + TypeAlias, + TypeCastExpression, + VariableDeclaration, +} from '@babel/types'; +import type { NodePath } from '@babel/traverse'; describe('getFlowType', () => { const mockImporter = makeMockImporter({ - abc: statement(` + abc: stmt => + stmt(` export type abc = number; - `).get('declaration'), + `).get('declaration') as NodePath, - def: statement(` + def: stmt => + stmt(` export type def = boolean; - `).get('declaration'), + `).get('declaration') as NodePath, - xyz: statement(` + xyz: stmt => + stmt(` export type xyz = string; - `).get('declaration'), + `).get('declaration') as NodePath, - maybe: statement(` + maybe: stmt => + stmt(` export type maybe = ?string; - `).get('declaration'), + `).get('declaration') as NodePath, - barbaz: statement(` + barbaz: stmt => + stmt(` export type barbaz = "bar" | "baz"; - `).get('declaration'), + `).get('declaration') as NodePath, - recTup: statement(` - export type recTup = [abc, xyz]; + recTup: stmt => + stmt(` import type { abc } from 'abc'; import type { xyz } from 'xyz'; - `).get('declaration'), + export type recTup = [abc, xyz]; + `).get('declaration') as NodePath, - MyType: statement(` + MyType: stmt => + stmt(` export type MyType = { a: string, b: ?notImported }; - `).get('declaration'), + `).get('declaration') as NodePath, - MyGenericType: statement(` + MyGenericType: stmt => + stmt(` export type MyType = { a: T, b: Array }; - `).get('declaration'), + `).get('declaration') as NodePath, - fruits: statement(` + fruits: stmt => + stmt(` export default { 'apple': '🍎', 'banana': '🍌', }; `).get('declaration'), - otherFruits: statement(` + otherFruits: stmt => + stmt(` export type OtherFruits = { orange: string }; - `).get('declaration'), + `).get('declaration') as NodePath, }); it('detects simple types', () => { @@ -72,10 +87,11 @@ describe('getFlowType', () => { ]; simplePropTypes.forEach(type => { - const typePath = expression('x: ' + type) + const typePath = parse + .expression('x: ' + type) .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ name: type }); + expect(getFlowType(typePath)).toEqual({ name: type }); }); }); @@ -83,10 +99,11 @@ describe('getFlowType', () => { const literalTypes = ['"foo"', 1234, true]; literalTypes.forEach(value => { - const typePath = expression(`x: ${value}`) + const typePath = parse + .expression(`x: ${value}`) .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'literal', value: `${value}`, }); @@ -94,48 +111,69 @@ describe('getFlowType', () => { }); it('detects external type', () => { - const typePath = expression('x: xyz') + const typePath = parse + .expression('x: xyz') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ name: 'xyz' }); + expect(getFlowType(typePath)).toEqual({ name: 'xyz' }); }); it('resolves an imported type', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: xyz); import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'string', }); }); it('detects external nullable type', () => { - const typePath = expression('x: ?xyz') + const typePath = parse + .expression('x: ?xyz') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'xyz', nullable: true, }); }); it('resolves an imported nullable type', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: ?xyz); import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'string', nullable: true, }); }); it('detects array type shorthand optional', () => { - const typePath = expression('x: ?number[]') + const typePath = parse + .expression('x: ?number[]') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], raw: 'number[]', @@ -144,10 +182,11 @@ describe('getFlowType', () => { }); it('detects array type shorthand optional type', () => { - const typePath = expression('x: (?number)[]') + const typePath = parse + .expression('x: (?number)[]') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number', nullable: true }], raw: '(?number)[]', @@ -155,10 +194,11 @@ describe('getFlowType', () => { }); it('detects array type shorthand', () => { - const typePath = expression('x: number[]') + const typePath = parse + .expression('x: number[]') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], raw: 'number[]', @@ -166,10 +206,11 @@ describe('getFlowType', () => { }); it('detects array type', () => { - const typePath = expression('x: Array') + const typePath = parse + .expression('x: Array') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], raw: 'Array', @@ -177,42 +218,78 @@ describe('getFlowType', () => { }); it('resolves imported types used for arrays', () => { - let typePath = statement(` + let typePath = ( + parse + .statement( + ` (x: Array); import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'string' }], raw: 'Array', }); - typePath = statement(` + typePath = ( + parse + .statement( + ` (x: xyz[]); import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'string' }], raw: 'xyz[]', }); - typePath = statement(` + typePath = ( + parse + .statement( + ` (x: ?xyz[]); import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'string' }], raw: 'xyz[]', nullable: true, }); - typePath = statement(` + typePath = ( + parse + .statement( + ` (x: (?xyz)[]); import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'string', nullable: true }], raw: '(?xyz)[]', @@ -220,10 +297,11 @@ describe('getFlowType', () => { }); it('detects array type with multiple types', () => { - const typePath = expression('x: Array') + const typePath = parse + .expression('x: Array') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }, { name: 'xyz' }], raw: 'Array', @@ -231,12 +309,21 @@ describe('getFlowType', () => { }); it('resolves array type with multiple imported types', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: Array); import type { abc } from 'abc'; import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }, { name: 'string' }], raw: 'Array', @@ -244,10 +331,11 @@ describe('getFlowType', () => { }); it('detects class type', () => { - const typePath = expression('x: Class') + const typePath = parse + .expression('x: Class') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'Class', elements: [{ name: 'Boolean' }], raw: 'Class', @@ -255,11 +343,20 @@ describe('getFlowType', () => { }); it('resolves imported subtype for class type', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: Class); import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Class', elements: [{ name: 'string' }], raw: 'Class', @@ -267,10 +364,11 @@ describe('getFlowType', () => { }); it('detects function type with subtype', () => { - const typePath = expression('x: Function') + const typePath = parse + .expression('x: Function') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'Function', elements: [{ name: 'xyz' }], raw: 'Function', @@ -278,11 +376,20 @@ describe('getFlowType', () => { }); it('resolves imported subtype for function type', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: Function); import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Function', elements: [{ name: 'string' }], raw: 'Function', @@ -290,10 +397,11 @@ describe('getFlowType', () => { }); it('detects object types', () => { - const typePath = expression('x: { a: string, b?: xyz }') + const typePath = parse + .expression('x: { a: string, b?: xyz }') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -307,10 +415,11 @@ describe('getFlowType', () => { }); it('detects object types with maybe type', () => { - const typePath = expression('x: { a: string, b: ?xyz }') + const typePath = parse + .expression('x: { a: string, b: ?xyz }') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -324,13 +433,22 @@ describe('getFlowType', () => { }); it('resolves imported types used for objects', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: { a: abc, b: ?xyz, c?: xyz, d: maybe, e?: maybe }); import type { abc } from 'abc'; import type { xyz } from 'xyz'; import type { maybe } from 'maybe'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -359,10 +477,11 @@ describe('getFlowType', () => { }); it('detects union type', () => { - const typePath = expression('x: string | xyz | "foo" | void') + const typePath = parse + .expression('x: string | xyz | "foo" | void') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'string' }, @@ -375,11 +494,20 @@ describe('getFlowType', () => { }); it('resolves imported types within union type', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: string | barbaz | "foo" | void); import type { barbaz } from 'barbaz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'string' }, @@ -399,10 +527,11 @@ describe('getFlowType', () => { }); it('detects intersection type', () => { - const typePath = expression('x: string & xyz & "foo" & void') + const typePath = parse + .expression('x: string & xyz & "foo" & void') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'intersection', elements: [ { name: 'string' }, @@ -415,11 +544,20 @@ describe('getFlowType', () => { }); it('resolves imported types within intersection type', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: string & barbaz & "foo" & void); import type { barbaz } from 'barbaz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'intersection', elements: [ { name: 'string' }, @@ -439,12 +577,13 @@ describe('getFlowType', () => { }); it('detects function signature type', () => { - const typePath = expression( - 'x: (p1: number, p2: ?string, ...rest: Array) => boolean', - ) + const typePath = parse + .expression( + 'x: (p1: number, p2: ?string, ...rest: Array) => boolean', + ) .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -468,10 +607,11 @@ describe('getFlowType', () => { }); it('detects function signature types without parameter names', () => { - const typePath = expression('x: (number, ?string) => boolean') + const typePath = parse + .expression('x: (number, ?string) => boolean') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -486,10 +626,11 @@ describe('getFlowType', () => { }); it('detects function signature type with single parmeter without name', () => { - const typePath = expression('x: string => boolean') + const typePath = parse + .expression('x: string => boolean') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -501,10 +642,13 @@ describe('getFlowType', () => { }); it('detects callable signature type', () => { - const typePath = expression('x: { (str: string): string, token: string }') + const typePath = parse + .expression( + 'x: { (str: string): string, token: string }', + ) .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -526,14 +670,23 @@ describe('getFlowType', () => { }); it('resolves function signature types with imported types', () => { - let typePath = statement(` + let typePath = ( + parse + .statement( + ` (x: (p1: abc, p2: ?xyz, ...rest: Array) => def); import type { abc } from 'abc'; import type { def } from 'def'; import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -555,14 +708,23 @@ describe('getFlowType', () => { raw: '(p1: abc, p2: ?xyz, ...rest: Array) => def', }); - typePath = statement(` + typePath = ( + parse + .statement( + ` (x: (abc, ?xyz) => def); import type { abc } from 'abc'; import type { def } from 'def'; import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -575,13 +737,22 @@ describe('getFlowType', () => { raw: '(abc, ?xyz) => def', }); - typePath = statement(` + typePath = ( + parse + .statement( + ` (x: xyz => def); import type { def } from 'def'; import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -591,14 +762,23 @@ describe('getFlowType', () => { raw: 'xyz => def', }); - typePath = statement(` + typePath = ( + parse + .statement( + ` (x: { (str: xyz): abc, token: def }); import type { abc } from 'abc'; import type { def } from 'def'; import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -620,12 +800,13 @@ describe('getFlowType', () => { }); it('detects map signature', () => { - const typePath = expression( - 'x: { [key: string]: number, [key: "xl"]: string, token: "a" | "b" }', - ) + const typePath = parse + .expression( + 'x: { [key: string]: number, [key: "xl"]: string, token: "a" | "b" }', + ) .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -657,14 +838,23 @@ describe('getFlowType', () => { }); it('resolves imported types in map signature', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` (x: { [key: xyz]: abc, [key: "xl"]: def, token: barbaz }); import type { abc } from 'abc'; import type { def } from 'def'; import type { xyz } from 'xyz'; import type { barbaz } from 'barbaz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -696,10 +886,11 @@ describe('getFlowType', () => { }); it('detects tuple signature', () => { - const typePath = expression('x: [string, number]') + const typePath = parse + .expression('x: [string, number]') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'tuple', elements: [{ name: 'string' }, { name: 'number' }], raw: '[string, number]', @@ -707,10 +898,11 @@ describe('getFlowType', () => { }); it('detects tuple in union signature', () => { - const typePath = expression('x: [string, number] | [number, string]') + const typePath = parse + .expression('x: [string, number] | [number, string]') .get('typeAnnotation') .get('typeAnnotation'); - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { @@ -729,26 +921,44 @@ describe('getFlowType', () => { }); it('resolves imported types used in tuple signature', () => { - let typePath = statement(` + let typePath = ( + parse + .statement( + ` (x: [xyz, abc]); import type { abc } from 'abc'; import type { xyz } from 'xyz'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'tuple', elements: [{ name: 'string' }, { name: 'number' }], raw: '[xyz, abc]', }); - typePath = statement(` + typePath = ( + parse + .statement( + ` (x: [xyz, abc] | recTup); import type { abc } from 'abc'; import type { xyz } from 'xyz'; import type { recTup } from 'recTup'; - `).get('expression', 'typeAnnotation', 'typeAnnotation'); + `, + mockImporter, + ) + .get('expression') as NodePath + ) + .get('typeAnnotation') + .get('typeAnnotation'); - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { @@ -767,33 +977,43 @@ describe('getFlowType', () => { }); it('resolves types in scope', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: MyType = 2; type MyType = string; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'string', }); }); it('handles typeof types', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: typeof MyType = {}; type MyType = { a: string, b: ?xyz }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -807,16 +1027,22 @@ describe('getFlowType', () => { }); it('resolves typeof of imported types', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: typeof MyType = {}; import type { MyType } from 'MyType'; - `) - .get('declarations', 0) - .get('id') + `, + mockImporter, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -833,33 +1059,43 @@ describe('getFlowType', () => { }); it('handles qualified type identifiers', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: MyType.x = {}; type MyType = { a: string, b: ?xyz }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'MyType.x', }); }); it('handles qualified type identifiers with params', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: MyType.x = {}; type MyType = { a: string, b: ?xyz }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'MyType.x', raw: 'MyType.x', elements: [ @@ -871,17 +1107,22 @@ describe('getFlowType', () => { }); it('handles generic types', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: MyType = {}; type MyType = { a: T, b: Array }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', raw: '{ a: T, b: Array }', @@ -909,16 +1150,22 @@ describe('getFlowType', () => { }); it('resolves imported types that need subtypes', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: MyGenericType = {}; import type { MyGenericType } from 'MyGenericType'; - `) - .get('declarations', 0) - .get('id') + `, + mockImporter, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', raw: '{ a: T, b: Array }', @@ -947,17 +1194,22 @@ describe('getFlowType', () => { describe('React types', () => { function test(type, expected) { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: ${type} = 2; type Props = { x: string }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ ...expected, name: type.replace('.', '').replace(/<.+>/, ''), raw: type, @@ -998,19 +1250,24 @@ describe('getFlowType', () => { }); it('resolves $Keys to union', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: $Keys = 2; const CONTENTS = { 'apple': '🍎', 'banana': '🍌', }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: "'apple'" }, @@ -1021,19 +1278,24 @@ describe('getFlowType', () => { }); it('resolves $Keys without typeof to union', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: $Keys = 2; const CONTENTS = { 'apple': '🍎', 'banana': '🍌', }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: "'apple'" }, @@ -1044,15 +1306,20 @@ describe('getFlowType', () => { }); it('resolves $Keys with an ObjectTypeAnnotation typeParameter to union', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: $Keys<{| apple: string, banana: string |}> = 2; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: 'apple' }, @@ -1063,16 +1330,21 @@ describe('getFlowType', () => { }); it('resolves $Keys with an ObjectTypeAnnotation typeParameter to union with an ObjectTypeSpreadProperty', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: $Keys<{| apple: string, banana: string, ...OtherFruits |}> = 2; type OtherFruits = { orange: string } - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: 'apple' }, @@ -1084,16 +1356,22 @@ describe('getFlowType', () => { }); it('resolves $Keys to imported types', () => { - let typePath = statement(` + let typePath = ( + parse + .statement( + ` var x: $Keys = 2; import CONTENTS from 'fruits'; - `) - .get('declarations', 0) - .get('id') + `, + mockImporter, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: "'apple'" }, @@ -1102,16 +1380,22 @@ describe('getFlowType', () => { raw: '$Keys', }); - typePath = statement(` + typePath = ( + parse + .statement( + ` var x: $Keys = 2; import CONTENTS from 'fruits'; - `) - .get('declarations', 0) - .get('id') + `, + mockImporter, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: "'apple'" }, @@ -1120,16 +1404,22 @@ describe('getFlowType', () => { raw: '$Keys', }); - typePath = statement(` + typePath = ( + parse + .statement( + ` var x: $Keys<{| apple: string, banana: string, ...OtherFruits |}> = 2; import type { OtherFruits } from 'otherFruits'; - `) - .get('declarations', 0) - .get('id') + `, + mockImporter, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, mockImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: 'apple' }, @@ -1141,16 +1431,21 @@ describe('getFlowType', () => { }); it('handles multiple references to one type', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` let action: { a: Action, b: Action }; type Action = {}; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -1182,16 +1477,21 @@ describe('getFlowType', () => { }); it('handles self-referencing type cycles', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` let action: Action; type Action = { subAction: Action }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -1204,19 +1504,24 @@ describe('getFlowType', () => { }); it('handles long type cycles', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` let action: Action; type Action = { subAction: SubAction }; type SubAction = { subAction: SubSubAction }; type SubSubAction = { subAction: SubSubSubAction }; type SubSubSubAction = { rootAction: Action }; - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toEqual({ + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -1271,54 +1576,75 @@ describe('getFlowType', () => { }); it('handles ObjectTypeSpreadProperty', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: {| apple: string, banana: string, ...OtherFruits |} = 2; type OtherFruits = { orange: string } - `) - .get('declarations', 0) - .get('id') + `, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, noopImporter)).toMatchSnapshot(); + expect(getFlowType(typePath)).toMatchSnapshot(); }); it('handles ObjectTypeSpreadProperty from imported types', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: {| apple: string, banana: string, ...MyType |} = 2; import type { MyType } from 'MyType'; - `) - .get('declarations', 0) - .get('id') + `, + mockImporter, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, mockImporter)).toMatchSnapshot(); + expect(getFlowType(typePath)).toMatchSnapshot(); }); it('handles unresolved ObjectTypeSpreadProperty', () => { - const typePath = statement(` - var x: {| apple: string, banana: string, ...MyType |} = 2; - `) - .get('declarations', 0) - .get('id') + const typePath = ( + parse + .statement( + `var x: {| apple: string, banana: string, ...MyType |} = 2;`, + mockImporter, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, mockImporter)).toMatchSnapshot(); + expect(getFlowType(typePath)).toMatchSnapshot(); }); it('handles nested ObjectTypeSpreadProperty', () => { - const typePath = statement(` + const typePath = ( + parse + .statement( + ` var x: {| apple: string, banana: string, ...BreakfastFruits |} = 2; type BreakfastFruits = { mango: string, ...CitrusFruits }; type CitrusFruits = { orange: string, lemon: string }; - `) - .get('declarations', 0) - .get('id') + `, + mockImporter, + ) + .get('declarations')[0] + .get('id') as NodePath + ) .get('typeAnnotation') - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - expect(getFlowType(typePath, null, mockImporter)).toMatchSnapshot(); + expect(getFlowType(typePath)).toMatchSnapshot(); }); }); diff --git a/src/utils/__tests__/getMemberExpressionRoot-test.ts b/src/utils/__tests__/getMemberExpressionRoot-test.ts index 22e8a9d31fb..6c3a50e0d4e 100644 --- a/src/utils/__tests__/getMemberExpressionRoot-test.ts +++ b/src/utils/__tests__/getMemberExpressionRoot-test.ts @@ -1,9 +1,22 @@ -import { expression } from '../../../tests/utils'; +import type { MemberExpression } from '@babel/types'; +import { parse } from '../../../tests/utils'; import getMemberExpressionRoot from '../getMemberExpressionRoot'; describe('getMemberExpressionRoot', () => { it('returns the root of a member expression', () => { - const root = getMemberExpressionRoot(expression('foo.bar.baz')); - expect(root).toEqualASTNode(expression('foo')); + const root = getMemberExpressionRoot(parse.expression('foo.bar.baz')); + expect(root).toEqualASTNode(parse.expression('foo')); + }); + + it('returns the same path if identifier', () => { + const id = parse.expression('foo'); + const root = getMemberExpressionRoot(id); + expect(root).toEqualASTNode(id); + }); + + it('returns the same path if literal', () => { + const literal = parse.expression('1'); + const root = getMemberExpressionRoot(literal); + expect(root).toEqualASTNode(literal); }); }); diff --git a/src/utils/__tests__/getMemberExpressionValuePath-test.ts b/src/utils/__tests__/getMemberExpressionValuePath-test.ts index 2b610087b4a..30dc25ab650 100644 --- a/src/utils/__tests__/getMemberExpressionValuePath-test.ts +++ b/src/utils/__tests__/getMemberExpressionValuePath-test.ts @@ -1,75 +1,75 @@ -import { statement, noopImporter } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; import getMemberExpressionValuePath from '../getMemberExpressionValuePath'; describe('getMemberExpressionValuePath', () => { describe('MethodExpression', () => { it('finds "normal" property definitions', () => { - const def = statement(` + const def = parse.statement(` var Foo = () => {}; Foo.propTypes = {}; `); - expect(getMemberExpressionValuePath(def, 'propTypes', noopImporter)).toBe( - def.parent.get('body', 1, 'expression', 'right'), + expect(getMemberExpressionValuePath(def, 'propTypes')).toBe( + def.parentPath.get('body')[1].get('expression').get('right'), ); }); it('takes the correct property definitions', () => { - const def = statement(` + const def = parse.statement(` var Foo = () => {}; Foo.propTypes = {}; Bar.propTypes = { unrelated: true }; `); - expect(getMemberExpressionValuePath(def, 'propTypes', noopImporter)).toBe( - def.parent.get('body', 1, 'expression', 'right'), + expect(getMemberExpressionValuePath(def, 'propTypes')).toBe( + def.parentPath.get('body')[1].get('expression').get('right'), ); }); it('finds computed property definitions with literal keys', () => { - const def = statement(` + const def = parse.statement(` function Foo () {} Foo['render'] = () => {}; `); - expect(getMemberExpressionValuePath(def, 'render', noopImporter)).toBe( - def.parent.get('body', 1, 'expression', 'right'), + expect(getMemberExpressionValuePath(def, 'render')).toBe( + def.parentPath.get('body')[1].get('expression').get('right'), ); }); it('ignores computed property definitions with expression', () => { - const def = statement(` + const def = parse.statement(` var Foo = function Bar() {}; Foo[imComputed] = () => {}; `); - expect( - getMemberExpressionValuePath(def, 'imComputed', noopImporter), - ).not.toBeDefined(); + expect(getMemberExpressionValuePath(def, 'imComputed')).toBeNull(); }); }); describe('TaggedTemplateLiteral', () => { it('finds "normal" property definitions', () => { - const def = statement(` + const def = parse.statement(` var Foo = foo\`bar\` Foo.propTypes = {}; `); - expect(getMemberExpressionValuePath(def, 'propTypes', noopImporter)).toBe( - def.parent.get('body', 1, 'expression', 'right'), + expect(getMemberExpressionValuePath(def, 'propTypes')).toBe( + def.parentPath.get('body')[1].get('expression').get('right'), ); }); }); describe('CallExpression', () => { it('finds "normal" property definitions', () => { - const def = statement(` + const def = parse.statement(` const Foo = system({is: "button"}, "space"); Foo.propTypes = {}; `); - expect(getMemberExpressionValuePath(def, 'propTypes', noopImporter)).toBe( - def.parent.get('body', 1, 'expression', 'right'), + expect(getMemberExpressionValuePath(def, 'propTypes')).toBe( + def.parentPath.get('body')[1].get('expression').get('right'), ); }); }); + + //TODO test arrow assigned to destructuring }); diff --git a/src/utils/__tests__/getMemberValuePath-test.ts b/src/utils/__tests__/getMemberValuePath-test.ts index 49c032d5740..295c85cdabe 100644 --- a/src/utils/__tests__/getMemberValuePath-test.ts +++ b/src/utils/__tests__/getMemberValuePath-test.ts @@ -1,9 +1,8 @@ -import { expression, statement, noopImporter } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; import getPropertyValuePath from '../getPropertyValuePath'; import getClassMemberValuePath from '../getClassMemberValuePath'; import getMemberValuePath from '../getMemberValuePath'; import getMemberExpressionValuePath from '../getMemberExpressionValuePath'; -import { NodePath } from 'ast-types'; jest.mock('../getPropertyValuePath'); jest.mock('../getClassMemberValuePath'); @@ -11,93 +10,69 @@ jest.mock('../getMemberExpressionValuePath'); describe('getMemberValuePath', () => { it('handles ObjectExpressions', () => { - const path = expression('{}'); + const path = parse.expression('{}'); - getMemberValuePath(path, 'foo', noopImporter); - expect(getPropertyValuePath).toBeCalledWith(path, 'foo', noopImporter); + getMemberValuePath(path, 'foo'); + expect(getPropertyValuePath).toBeCalledWith(path, 'foo'); }); it('handles ClassDeclarations', () => { - const path = statement('class Foo {}'); + const path = parse.statement('class Foo {}'); - getMemberValuePath(path, 'foo', noopImporter); - expect(getClassMemberValuePath).toBeCalledWith(path, 'foo', noopImporter); + getMemberValuePath(path, 'foo'); + expect(getClassMemberValuePath).toBeCalledWith(path, 'foo'); }); it('handles TaggedTemplateLiterals', () => { - const path = expression('foo``'); - - getMemberValuePath(path, 'foo', noopImporter); - expect(getMemberExpressionValuePath).toBeCalledWith( - path, - 'foo', - noopImporter, - ); + const path = parse.expression('foo``'); + + getMemberValuePath(path, 'foo'); + expect(getMemberExpressionValuePath).toBeCalledWith(path, 'foo'); }); it('handles ClassExpressions', () => { - const path = expression('class {}'); + const path = parse.expression('class {}'); - getMemberValuePath(path, 'foo', noopImporter); - expect(getClassMemberValuePath).toBeCalledWith(path, 'foo', noopImporter); + getMemberValuePath(path, 'foo'); + expect(getClassMemberValuePath).toBeCalledWith(path, 'foo'); }); it('handles CallExpressions', () => { - const path = expression('system({is: "button"}, "space")'); - - getMemberValuePath(path, 'foo', noopImporter); - expect(getMemberExpressionValuePath).toBeCalledWith( - path, - 'foo', - noopImporter, - ); + const path = parse.expression('system({is: "button"}, "space")'); + + getMemberValuePath(path, 'foo'); + expect(getMemberExpressionValuePath).toBeCalledWith(path, 'foo'); }); - it('tries synonyms', () => { - let path = expression('{}'); - - getMemberValuePath(path, 'defaultProps', noopImporter); - expect(getPropertyValuePath).toBeCalledWith( - path, - 'defaultProps', - noopImporter, - ); - expect(getPropertyValuePath).toBeCalledWith( - path, - 'getDefaultProps', - noopImporter, - ); - - path = statement('class Foo {}'); - - getMemberValuePath(path, 'defaultProps', noopImporter); - expect(getClassMemberValuePath).toBeCalledWith( - path, - 'defaultProps', - noopImporter, - ); - expect(getClassMemberValuePath).toBeCalledWith( - path, - 'getDefaultProps', - noopImporter, - ); + describe('tries defaultProps synonyms', () => { + it('with object', () => { + const path = parse.expression('{}'); + + getMemberValuePath(path, 'defaultProps'); + expect(getPropertyValuePath).toBeCalledWith(path, 'defaultProps'); + expect(getPropertyValuePath).toBeCalledWith(path, 'getDefaultProps'); + }); + + it('with class', () => { + const path = parse.statement('class Foo {}'); + + getMemberValuePath(path, 'defaultProps'); + expect(getClassMemberValuePath).toBeCalledWith(path, 'defaultProps'); + expect(getClassMemberValuePath).toBeCalledWith(path, 'getDefaultProps'); + }); }); it('returns the result of getPropertyValuePath and getClassMemberValuePath', () => { - const mockPath = new NodePath(42); - const mockPath2 = new NodePath(21); + const mockPath = parse.expression('42'); + const mockPath2 = parse.expression('21'); jest.mocked(getPropertyValuePath).mockReturnValue(mockPath); jest.mocked(getClassMemberValuePath).mockReturnValue(mockPath2); - let path = expression('{}'); + let path = parse.expression('{}'); - expect(getMemberValuePath(path, 'defaultProps', noopImporter)).toBe( - mockPath, - ); + expect(getMemberValuePath(path, 'defaultProps')).toBe(mockPath); - path = statement('class Foo {}'); + path = parse.statement('class Foo {}'); - expect(getMemberValuePath(path, 'defaultProps', noopImporter)).toBe( - mockPath2, - ); + expect(getMemberValuePath(path, 'defaultProps')).toBe(mockPath2); }); }); diff --git a/src/utils/__tests__/getMembers-test.ts b/src/utils/__tests__/getMembers-test.ts index 41093de8ddc..9ba6ad8e809 100644 --- a/src/utils/__tests__/getMembers-test.ts +++ b/src/utils/__tests__/getMembers-test.ts @@ -1,27 +1,27 @@ -import { expression } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; import getMembers from '../getMembers'; describe('getMembers', () => { it('finds all "members" "inside" a MemberExpression', () => { - const members = getMembers(expression('foo.bar(123)(456)[baz][42]')); + const members = getMembers(parse.expression('foo.bar(123)(456)[baz][42]')); expect(members).toMatchSnapshot(); }); it('includes the root if option set to true', () => { - const members = getMembers(expression('foo.bar(123)[baz]'), true); + const members = getMembers(parse.expression('foo.bar(123)[baz]'), true); expect(members).toMatchSnapshot(); }); it('does work with custom expressions in chain', () => { - const members = getMembers(expression('foo.bar(123)["" + ""]')); + const members = getMembers(parse.expression('foo.bar(123)["" + ""]')); expect(members).toMatchSnapshot(); }); it('does work with custom expressions in arguments', () => { - const members = getMembers(expression('foo.bar(123 + 123)["baz"]')); + const members = getMembers(parse.expression('foo.bar(123 + 123)["baz"]')); expect(members).toMatchSnapshot(); }); diff --git a/src/utils/__tests__/getMethodDocumentation-test.ts b/src/utils/__tests__/getMethodDocumentation-test.ts index ac84935db8b..f4277534b6b 100644 --- a/src/utils/__tests__/getMethodDocumentation-test.ts +++ b/src/utils/__tests__/getMethodDocumentation-test.ts @@ -1,34 +1,42 @@ -import { - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import type { + ClassDeclaration, + ClassMethod, + ClassPrivateMethod, + ClassProperty, + ObjectExpression, + ObjectMethod, +} from '@babel/types'; +import { parse, makeMockImporter, parseTypescript } from '../../../tests/utils'; import getMethodDocumentation from '../getMethodDocumentation'; describe('getMethodDocumentation', () => { const mockImporter = makeMockImporter({ - hello: statement(` + hello: stmt => + stmt(` export default () => {}; `).get('declaration'), - bar: statement(` + bar: stmt => + stmt(` export default (bar: number) => {}; `).get('declaration'), - baz: statement(` + baz: stmt => + stmt(` export default (): number => {}; `).get('declaration'), }); describe('name', () => { it('extracts the method name', () => { - const def = statement(` + const def = parse.statement(` class Foo { hello() {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual({ + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'hello', docblock: null, modifiers: [], @@ -38,13 +46,13 @@ describe('getMethodDocumentation', () => { }); it('handles function assignment', () => { - const def = statement(` + const def = parse.statement(` class Foo { hello = () => {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual({ + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'hello', docblock: null, modifiers: [], @@ -54,34 +62,37 @@ describe('getMethodDocumentation', () => { }); it('handles computed method name', () => { - const def = statement(` + const def = parse.statement(` class Foo { [foo]() {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toMatchSnapshot(); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); it('ignores complex computed method name', () => { - const def = statement(` + const def = parse.statement(` class Foo { [() => {}]() {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toMatchSnapshot(); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); it('resolves assignment of imported function', () => { - const def = statement(` + const def = parse.statement( + ` class Foo { hello = hello; } import hello from 'hello'; - `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, mockImporter)).toEqual({ + `, + mockImporter, + ); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'hello', docblock: null, modifiers: [], @@ -93,7 +104,7 @@ describe('getMethodDocumentation', () => { describe('docblock', () => { it('extracts the method docblock', () => { - const def = statement(` + const def = parse.statement(` class Foo { /** * Don't use this! @@ -101,8 +112,8 @@ describe('getMethodDocumentation', () => { foo() {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual({ + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'foo', docblock: "Don't use this!", modifiers: [], @@ -112,7 +123,7 @@ describe('getMethodDocumentation', () => { }); it('extracts docblock on function assignment', () => { - const def = statement(` + const def = parse.statement(` class Foo { /** * Don't use this! @@ -120,8 +131,8 @@ describe('getMethodDocumentation', () => { foo = () => {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual({ + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'foo', docblock: "Don't use this!", modifiers: [], @@ -132,66 +143,58 @@ describe('getMethodDocumentation', () => { }); describe('parameters', () => { - function methodParametersDoc(params) { - return { - name: 'foo', - docblock: null, - modifiers: [], - returns: null, - params, - }; - } + it('extracts flow type info', () => { + const def = parse.statement(` + class Foo { + foo(bar: number) {} + } + `); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); + }); it('extracts flow type info', () => { - const def = statement(` + const def = parseTypescript.statement(` class Foo { foo(bar: number) {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( - methodParametersDoc([ - { - name: 'bar', - type: { name: 'number' }, - }, - ]), - ); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); + }); + + it('does not add type parameters to alias', () => { + const def = parseTypescript.statement(` + class Foo { + foo(bar: Foo) {} + } + `); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); it('extracts flow type info on function assignment', () => { - const def = statement(` + const def = parse.statement(` class Foo { foo = (bar: number) => {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( - methodParametersDoc([ - { - name: 'bar', - type: { name: 'number' }, - }, - ]), - ); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); it('resolves flow type info on imported functions', () => { - const def = statement(` + const def = parse.statement( + ` class Foo { foo = bar } import bar from 'bar'; - `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, mockImporter)).toEqual( - methodParametersDoc([ - { - name: 'bar', - type: { name: 'number' }, - }, - ]), + `, + mockImporter, ); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); describe('modifiers', () => { @@ -206,61 +209,67 @@ describe('getMethodDocumentation', () => { } it('detects no modifiers', () => { - const def = statement(` + const def = parse.statement(` class Foo { foo() {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( - methodModifiersDoc([]), - ); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual(methodModifiersDoc([])); }); it('detects static functions', () => { - const def = statement(` + const def = parse.statement(` class Foo { static foo() {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( + methodModifiersDoc(['static']), + ); + }); + + it('detects manually set static functions', () => { + const def = parse.expression(`{ foo() {} }`); + const method = def.get('properties')[0] as NodePath; + expect(getMethodDocumentation(method, { isStatic: true })).toEqual( methodModifiersDoc(['static']), ); }); it('detects generators', () => { - const def = statement(` + const def = parse.statement(` class Foo { *foo () {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodModifiersDoc(['generator']), ); }); it('detects async functions', () => { - const def = statement(` + const def = parse.statement(` class Foo { async foo () {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodModifiersDoc(['async']), ); }); it('detects static async functions', () => { - const def = statement(` + const def = parse.statement(` class Foo { static async foo () {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodModifiersDoc(['static', 'async']), ); }); @@ -278,25 +287,23 @@ describe('getMethodDocumentation', () => { } it('returns null if return is not documented', () => { - const def = statement(` + const def = parse.statement(` class Foo { foo () {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( - methodReturnDoc(null), - ); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual(methodReturnDoc(null)); }); it('extracts flow types', () => { - const def = statement(` + const def = parse.statement(` class Foo { foo (): number {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodReturnDoc({ type: { name: 'number' }, }), @@ -304,13 +311,15 @@ describe('getMethodDocumentation', () => { }); it('extracts flow types on function assignment', () => { - const def = statement(` + const def = parse.statement(` class Foo { foo = (): number => {} } `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toEqual( + const method = def + .get('body') + .get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodReturnDoc({ type: { name: 'number' }, }), @@ -318,14 +327,19 @@ describe('getMethodDocumentation', () => { }); it('resolves flow types on imported functions', () => { - const def = statement(` + const def = parse.statement( + ` class Foo { foo = baz } import baz from 'baz'; - `); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, mockImporter)).toEqual( + `, + mockImporter, + ); + const method = def + .get('body') + .get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodReturnDoc({ type: { name: 'number' }, }), @@ -335,30 +349,28 @@ describe('getMethodDocumentation', () => { describe('private', () => { it('ignores private typescript methods', () => { - const def = statement( + const def = parseTypescript.statement( ` class Foo { private foo() {} } `, - { parserOptions: { plugins: ['typescript'] } }, ); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toMatchSnapshot(); + const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); - // TOD add support - it.skip('ignores private methods', () => { - const def = statement( - ` - class Foo { + it('ignores private methods', () => { + const def = parse.statement( + `class Foo { #foo() {} - } - `, + }`, { parserOptions: { plugins: ['classPrivateMethods'] } }, ); - const method = def.get('body', 'body', 0); - expect(getMethodDocumentation(method, noopImporter)).toMatchSnapshot(); + const method = def + .get('body') + .get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); }); }); diff --git a/src/utils/__tests__/getNameOrValue-test.ts b/src/utils/__tests__/getNameOrValue-test.ts new file mode 100644 index 00000000000..488b609e605 --- /dev/null +++ b/src/utils/__tests__/getNameOrValue-test.ts @@ -0,0 +1,28 @@ +import { parse } from '../../../tests/utils'; +import getNameOrValue from '../getNameOrValue'; + +describe('getNameOrValue', () => { + it('gets Identifier name', () => { + expect(getNameOrValue(parse.expression('foo'))).toMatchSnapshot(); + }); + + it('gets string literal value', () => { + expect(getNameOrValue(parse.expression('"foo"'))).toMatchSnapshot(); + }); + + it('gets numeric literal value', () => { + expect(getNameOrValue(parse.expression('1'))).toMatchSnapshot(); + }); + + it('gets boolean literal value', () => { + expect(getNameOrValue(parse.expression('true'))).toMatchSnapshot(); + }); + + it('gets null RegExp pattern', () => { + expect(getNameOrValue(parse.expression('/abc?/'))).toMatchSnapshot(); + }); + + it('gets null literal value', () => { + expect(getNameOrValue(parse.expression('null'))).toMatchSnapshot(); + }); +}); diff --git a/src/utils/__tests__/getParameterName-test.ts b/src/utils/__tests__/getParameterName-test.ts index ebde85559a4..714c98b12b0 100644 --- a/src/utils/__tests__/getParameterName-test.ts +++ b/src/utils/__tests__/getParameterName-test.ts @@ -1,40 +1,50 @@ -import { expression } from '../../../tests/utils'; +import type { ClassDeclaration, FunctionExpression } from '@babel/types'; +import { parse } from '../../../tests/utils'; import getParameterName from '../getParameterName'; describe('getParameterName', () => { it('returns the name for a normal parameter', () => { - const def = expression('function(a) {}'); - const param = def.get('params', 0); + const def = parse.expression('function(a) {}'); + const param = def.get('params')[0]; expect(getParameterName(param)).toEqual('a'); }); it('returns the name for a rest parameter', () => { - const def = expression('function(...a) {}'); - const param = def.get('params', 0); + const def = parse.expression('function(...a) {}'); + const param = def.get('params')[0]; expect(getParameterName(param)).toEqual('...a'); }); it('returns the name for a parameter with a default value', () => { - const def = expression('function(a = 0) {}'); - const param = def.get('params', 0); + const def = parse.expression('function(a = 0) {}'); + const param = def.get('params')[0]; expect(getParameterName(param)).toEqual('a'); }); it('returns the raw representation for a parameter with object destructuring', () => { - const def = expression('function({a}) {}'); - const param = def.get('params', 0); + const def = parse.expression('function({a}) {}'); + const param = def.get('params')[0]; expect(getParameterName(param)).toEqual('{a}'); }); it('returns the raw representation for a parameter with array destructuring', () => { - const def = expression('function([a]) {}'); - const param = def.get('params', 0); + const def = parse.expression('function([a]) {}'); + const param = def.get('params')[0]; expect(getParameterName(param)).toEqual('[a]'); }); it('throws when passed an invalid path', () => { - const def = expression('function() {}'); + const def = parse.expression('function() {}'); const param = def; - expect(() => getParameterName(param)).toThrow(); + expect(() => getParameterName(param as any)).toThrow(); + }); + + it('handles typescript param property correctly', () => { + const def = parse.expression( + 'class A { constructor(readonly a: any) {}}', + { filename: 'file.ts' }, + ); + const param = def.get('body').get('body')[0].get('params')[0]; + expect(getParameterName(param)).toEqual('a'); }); }); diff --git a/src/utils/__tests__/getPropType-test.ts b/src/utils/__tests__/getPropType-test.ts index 06a6df2d9a2..66c2cf21c15 100644 --- a/src/utils/__tests__/getPropType-test.ts +++ b/src/utils/__tests__/getPropType-test.ts @@ -1,9 +1,5 @@ -import { - expression, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import type { ExpressionStatement } from '@babel/types'; +import { parse, makeMockImporter } from '../../../tests/utils'; import getPropType from '../getPropType'; describe('getPropType', () => { @@ -23,34 +19,28 @@ describe('getPropType', () => { ]; simplePropTypes.forEach(type => - expect( - getPropType(expression('React.PropTypes.' + type), noopImporter), - ).toEqual({ + expect(getPropType(parse.expression('React.PropTypes.' + type))).toEqual({ name: type, }), ); // It doesn't actually matter what the MemberExpression is simplePropTypes.forEach(type => - expect( - getPropType(expression('Foo.' + type + '.bar'), noopImporter), - ).toEqual({ + expect(getPropType(parse.expression('Foo.' + type + '.bar'))).toEqual({ name: type, }), ); // Doesn't even have to be a MemberExpression simplePropTypes.forEach(type => - expect(getPropType(expression(type), noopImporter)).toEqual({ + expect(getPropType(parse.expression(type))).toEqual({ name: type, }), ); }); it('detects complex prop types', () => { - expect( - getPropType(expression('oneOf(["foo", "bar"])'), noopImporter), - ).toEqual({ + expect(getPropType(parse.expression('oneOf(["foo", "bar"])'))).toEqual({ name: 'enum', value: [ { value: '"foo"', computed: false }, @@ -60,7 +50,7 @@ describe('getPropType', () => { // line comments are ignored expect( - getPropType(expression('oneOf(["foo", // baz\n"bar"])'), noopImporter), + getPropType(parse.expression('oneOf(["foo", // baz\n"bar"])')), ).toEqual({ name: 'enum', value: [ @@ -69,36 +59,34 @@ describe('getPropType', () => { ], }); - expect( - getPropType(expression('oneOfType([number, bool])'), noopImporter), - ).toEqual({ + expect(getPropType(parse.expression('oneOfType([number, bool])'))).toEqual({ name: 'union', value: [{ name: 'number' }, { name: 'bool' }], }); // custom type - expect(getPropType(expression('oneOfType([foo])'), noopImporter)).toEqual({ + expect(getPropType(parse.expression('oneOfType([foo])'))).toEqual({ name: 'union', value: [{ name: 'custom', raw: 'foo' }], }); - expect(getPropType(expression('instanceOf(Foo)'), noopImporter)).toEqual({ + expect(getPropType(parse.expression('instanceOf(Foo)'))).toEqual({ name: 'instanceOf', value: 'Foo', }); - expect(getPropType(expression('arrayOf(string)'), noopImporter)).toEqual({ + expect(getPropType(parse.expression('arrayOf(string)'))).toEqual({ name: 'arrayOf', value: { name: 'string' }, }); - expect(getPropType(expression('objectOf(string)'), noopImporter)).toEqual({ + expect(getPropType(parse.expression('objectOf(string)'))).toEqual({ name: 'objectOf', value: { name: 'string' }, }); expect( - getPropType(expression('shape({foo: string, bar: bool})'), noopImporter), + getPropType(parse.expression('shape({foo: string, bar: bool})')), ).toEqual({ name: 'shape', value: { @@ -114,7 +102,7 @@ describe('getPropType', () => { }); expect( - getPropType(expression('exact({foo: string, bar: bool})'), noopImporter), + getPropType(parse.expression('exact({foo: string, bar: bool})')), ).toEqual({ name: 'exact', value: { @@ -130,7 +118,7 @@ describe('getPropType', () => { }); // custom - expect(getPropType(expression('shape({foo: xyz})'), noopImporter)).toEqual({ + expect(getPropType(parse.expression('shape({foo: xyz})'))).toEqual({ name: 'shape', value: { foo: { @@ -142,7 +130,7 @@ describe('getPropType', () => { }); // custom - expect(getPropType(expression('exact({foo: xyz})'), noopImporter)).toEqual({ + expect(getPropType(parse.expression('exact({foo: xyz})'))).toEqual({ name: 'exact', value: { foo: { @@ -154,18 +142,14 @@ describe('getPropType', () => { }); // computed - expect( - getPropType(expression('shape(Child.propTypes)'), noopImporter), - ).toEqual({ + expect(getPropType(parse.expression('shape(Child.propTypes)'))).toEqual({ name: 'shape', value: 'Child.propTypes', computed: true, }); // computed - expect( - getPropType(expression('exact(Child.propTypes)'), noopImporter), - ).toEqual({ + expect(getPropType(parse.expression('exact(Child.propTypes)'))).toEqual({ name: 'exact', value: 'Child.propTypes', computed: true, @@ -174,213 +158,285 @@ describe('getPropType', () => { describe('resolve identifier to their values', () => { const mockImporter = makeMockImporter({ - shape: statement(` + shape: stmt => + stmt(` export default {bar: PropTypes.string}; `).get('declaration'), - types: statement(` + types: stmt => + stmt(` export default ["foo", "bar"]; `).get('declaration'), - foo: statement(` + foo: stmt => + stmt(` export default "foo"; `).get('declaration'), - bar: statement(` + bar: stmt => + stmt(` export default "bar"; `).get('declaration'), - obj: statement(` + obj: stmt => + stmt(` export default { FOO: "foo", BAR: "bar" }; `).get('declaration'), - arr: statement(` + arr: stmt => + stmt(` export default ["foo", "bar"]; `).get('declaration'), - keys: statement(` - export default Object.keys(obj); + keys: stmt => + stmt(` import obj from 'obj'; + export default Object.keys(obj); `).get('declaration'), - values: statement(` - export default Object.values(obj); + values: stmt => + stmt(` import obj from 'obj'; + export default Object.values(obj); `).get('declaration'), }); it('resolves variables to their values', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.shape(shape); var shape = {bar: PropTypes.string}; - `).get('expression'); + `, + ) + .get('expression'); - expect(getPropType(propTypeExpression, noopImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('resolves imported variables to their values', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.shape(shape); import shape from 'shape'; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(getPropType(propTypeExpression, mockImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('resolves simple identifier to their initialization value', () => { - const propTypeIdentifier = statement(` + const propTypeIdentifier = parse + .statement( + ` PropTypes.oneOf(TYPES); var TYPES = ["foo", "bar"]; - `).get('expression'); + `, + ) + .get('expression'); - expect(getPropType(propTypeIdentifier, noopImporter)).toMatchSnapshot(); + expect(getPropType(propTypeIdentifier)).toMatchSnapshot(); }); it('resolves importer identifier to initialization value', () => { - const propTypeIdentifier = statement(` + const propTypeIdentifier = parse + .statement( + ` PropTypes.oneOf(TYPES); import TYPES from 'types'; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(getPropType(propTypeIdentifier, mockImporter)).toMatchSnapshot(); + expect(getPropType(propTypeIdentifier)).toMatchSnapshot(); }); it('resolves simple identifier to their initialization value in array', () => { - const identifierInsideArray = statement(` + const identifierInsideArray = parse + .statement( + ` PropTypes.oneOf([FOO, BAR]); var FOO = "foo"; var BAR = "bar"; - `).get('expression'); + `, + ) + .get('expression'); - expect( - getPropType(identifierInsideArray, noopImporter), - ).toMatchSnapshot(); + expect(getPropType(identifierInsideArray)).toMatchSnapshot(); }); it('resolves imported identifier to their initialization value in array', () => { - const identifierInsideArray = statement(` + const identifierInsideArray = parse + .statement( + ` PropTypes.oneOf([FOO, BAR]); import FOO from 'foo'; import BAR from 'bar'; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect( - getPropType(identifierInsideArray, mockImporter), - ).toMatchSnapshot(); + expect(getPropType(identifierInsideArray)).toMatchSnapshot(); }); it('resolves memberExpressions', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf([TYPES.FOO, TYPES.BAR]); var TYPES = { FOO: "foo", BAR: "bar" }; - `).get('expression'); + `, + ) + .get('expression'); - expect(getPropType(propTypeExpression, noopImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('resolves memberExpressions from imported objects', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf([TYPES.FOO, TYPES.BAR]); import TYPES from 'obj'; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(getPropType(propTypeExpression, mockImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('correctly resolves SpreadElements in arrays', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf([...TYPES]); var TYPES = ["foo", "bar"]; - `).get('expression'); + `, + ) + .get('expression'); - expect(getPropType(propTypeExpression, noopImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('correctly resolves SpreadElements in arrays from imported values', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf([...TYPES]); import TYPES from 'arr'; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(getPropType(propTypeExpression, mockImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('correctly resolves nested SpreadElements in arrays', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf([...TYPES]); var TYPES = ["foo", ...TYPES2]; var TYPES2 = ["bar"]; - `).get('expression'); + `, + ) + .get('expression'); - expect(getPropType(propTypeExpression, noopImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('does resolve object keys values', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf(Object.keys(TYPES)); var TYPES = { FOO: "foo", BAR: "bar" }; - `).get('expression'); + `, + ) + .get('expression'); - expect(getPropType(propTypeExpression, noopImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('resolves values from imported Object.keys call', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf(keys); import keys from 'keys'; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(getPropType(propTypeExpression, mockImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('does resolve object values', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf(Object.values(TYPES)); var TYPES = { FOO: "foo", BAR: "bar" }; - `).get('expression'); + `, + ) + .get('expression'); - expect(getPropType(propTypeExpression, noopImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('resolves values from imported Object.values call', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf(values); import values from 'values'; - `).get('expression'); + `, + mockImporter, + ) + .get('expression'); - expect(getPropType(propTypeExpression, mockImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); it('does not resolve external values without proper importer', () => { - const propTypeExpression = statement(` + const propTypeExpression = parse + .statement( + ` PropTypes.oneOf(TYPES); import { TYPES } from './foo'; - `).get('expression'); + `, + ) + .get('expression'); - expect(getPropType(propTypeExpression, noopImporter)).toMatchSnapshot(); + expect(getPropType(propTypeExpression)).toMatchSnapshot(); }); }); it('detects custom validation functions for function', () => { - expect( - getPropType(expression('(function() {})'), noopImporter), - ).toMatchSnapshot(); + expect(getPropType(parse.expression('(function() {})'))).toMatchSnapshot(); }); it('detects custom validation functions for arrow function', () => { - expect(getPropType(expression('() => {}'), noopImporter)).toMatchSnapshot(); + expect(getPropType(parse.expression('() => {}'))).toMatchSnapshot(); }); it('detects descriptions on nested types in arrayOf', () => { expect( getPropType( - expression(`arrayOf( + parse.expression(`arrayOf( /** * test2 */ string )`), - noopImporter, ), ).toMatchSnapshot(); }); @@ -388,13 +444,12 @@ describe('getPropType', () => { it('detects descriptions on nested types in objectOf', () => { expect( getPropType( - expression(`objectOf( + parse.expression(`objectOf( /** * test2 */ string )`), - noopImporter, ), ).toMatchSnapshot(); }); @@ -402,7 +457,7 @@ describe('getPropType', () => { it('detects descriptions on nested types in shapes', () => { expect( getPropType( - expression(`shape({ + parse.expression(`shape({ /** * test1 */ @@ -412,7 +467,6 @@ describe('getPropType', () => { */ bar: bool })`), - noopImporter, ), ).toMatchSnapshot(); }); @@ -420,11 +474,10 @@ describe('getPropType', () => { it('detects required notations of nested types in shapes', () => { expect( getPropType( - expression(`shape({ + parse.expression(`shape({ foo: string.isRequired, bar: bool })`), - noopImporter, ), ).toMatchSnapshot(); }); @@ -432,7 +485,7 @@ describe('getPropType', () => { it('detects descriptions on nested types in exacts', () => { expect( getPropType( - expression(`exact({ + parse.expression(`exact({ /** * test1 */ @@ -442,7 +495,6 @@ describe('getPropType', () => { */ bar: bool })`), - noopImporter, ), ).toMatchSnapshot(); }); @@ -450,11 +502,10 @@ describe('getPropType', () => { it('detects required notations of nested types in exacts', () => { expect( getPropType( - expression(`exact({ + parse.expression(`exact({ foo: string.isRequired, bar: bool })`), - noopImporter, ), ).toMatchSnapshot(); }); @@ -462,11 +513,10 @@ describe('getPropType', () => { it('handles computed properties', () => { expect( getPropType( - expression(`exact({ + parse.expression(`exact({ [foo]: string.isRequired, bar: bool })`), - noopImporter, ), ).toMatchSnapshot(); }); @@ -474,11 +524,10 @@ describe('getPropType', () => { it('ignores complex computed properties', () => { expect( getPropType( - expression(`exact({ + parse.expression(`exact({ [() => {}]: string.isRequired, bar: bool })`), - noopImporter, ), ).toMatchSnapshot(); }); diff --git a/src/utils/__tests__/getPropertyName-test.ts b/src/utils/__tests__/getPropertyName-test.ts index 2933602d2fe..839db0f3cd7 100644 --- a/src/utils/__tests__/getPropertyName-test.ts +++ b/src/utils/__tests__/getPropertyName-test.ts @@ -1,113 +1,119 @@ -import { - statement, - expression, - noopImporter, - makeMockImporter, - expressionLast, -} from '../../../tests/utils'; +import type { ObjectExpression, TypeCastExpression } from '@babel/types'; +import { parse, makeMockImporter } from '../../../tests/utils'; import getPropertyName from '../getPropertyName'; describe('getPropertyName', () => { const mockImporter = makeMockImporter({ - foo: statement(` + foo: stmtLast => + stmtLast(` export default "name"; `).get('declaration'), - bar: statement(` + bar: stmtLast => + stmtLast(` export default { baz: "name" }; `).get('declaration'), }); it('returns the name for a normal property', () => { - const def = expression('{ foo: 1 }'); - const param = def.get('properties', 0); + const def = parse.expression('{ foo: 1 }'); + const param = def.get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe('foo'); + expect(getPropertyName(param)).toBe('foo'); }); it('returns the name of a object type spread property', () => { - const def = expression('(a: { ...foo })'); - const param = def.get('typeAnnotation', 'typeAnnotation', 'properties', 0); + const def = parse.expression('(a: { ...foo })'); + const param = def + .get('typeAnnotation') + .get('typeAnnotation') + .get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe('foo'); + expect(getPropertyName(param)).toBe('foo'); }); it('creates name for computed properties', () => { - const def = expression('{ [foo]: 21 }'); - const param = def.get('properties', 0); + const def = parse.expression('{ [foo]: 21 }'); + const param = def.get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe('@computed#foo'); + expect(getPropertyName(param)).toBe('@computed#foo'); }); it('creates name for computed properties from string', () => { - const def = expression('{ ["foo"]: 21 }'); - const param = def.get('properties', 0); + const def = parse.expression('{ ["foo"]: 21 }'); + const param = def.get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe('foo'); + expect(getPropertyName(param)).toBe('foo'); }); it('creates name for computed properties from int', () => { - const def = expression('{ [31]: 21 }'); - const param = def.get('properties', 0); + const def = parse.expression('{ [31]: 21 }'); + const param = def.get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe('31'); + expect(getPropertyName(param)).toBe('31'); }); it('returns null for computed properties from regex', () => { - const def = expression('{ [/31/]: 21 }'); - const param = def.get('properties', 0); + const def = parse.expression('{ [/31/]: 21 }'); + const param = def.get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe(null); + expect(getPropertyName(param)).toBe(null); }); it('returns null for to complex computed properties', () => { - const def = expression('{ [() => {}]: 21 }'); - const param = def.get('properties', 0); + const def = parse.expression('{ [() => {}]: 21 }'); + const param = def.get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe(null); + expect(getPropertyName(param)).toBe(null); }); it('resolves simple variables', () => { - const def = expressionLast(` + const def = parse.expressionLast(` const foo = "name"; ({ [foo]: 21 }); `); - const param = def.get('properties', 0); + const param = def.get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe('name'); + expect(getPropertyName(param)).toBe('name'); }); it('resolves imported variables', () => { - const def = expressionLast(` + const def = parse.expressionLast( + ` import foo from 'foo'; ({ [foo]: 21 }); - `); - const param = def.get('properties', 0); + `, + mockImporter, + ); + const param = def.get('properties')[0]; - expect(getPropertyName(param, mockImporter)).toBe('name'); + expect(getPropertyName(param)).toBe('name'); }); it('resolves simple member expressions', () => { - const def = expressionLast(` + const def = parse.expressionLast(` const a = { foo: "name" }; ({ [a.foo]: 21 }); `); - const param = def.get('properties', 0); + const param = def.get('properties')[0]; - expect(getPropertyName(param, noopImporter)).toBe('name'); + expect(getPropertyName(param)).toBe('name'); }); it('resolves imported member expressions', () => { - const def = expressionLast(` + const def = parse.expressionLast( + ` import bar from 'bar'; ({ [bar.baz]: 21 }); - `); - const param = def.get('properties', 0); + `, + mockImporter, + ); + const param = def.get('properties')[0]; - expect(getPropertyName(param, mockImporter)).toBe('name'); + expect(getPropertyName(param)).toBe('name'); }); }); diff --git a/src/utils/__tests__/getPropertyValuePath-test.ts b/src/utils/__tests__/getPropertyValuePath-test.ts index 2873b9d05b2..1422344f8fe 100644 --- a/src/utils/__tests__/getPropertyValuePath-test.ts +++ b/src/utils/__tests__/getPropertyValuePath-test.ts @@ -1,50 +1,64 @@ -import { - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import type { ExpressionStatement, ObjectExpression } from '@babel/types'; +import { parse, makeMockImporter } from '../../../tests/utils'; import getPropertyValuePath from '../getPropertyValuePath'; describe('getPropertyValuePath', () => { const mockImporter = makeMockImporter({ - bar: statement(`export default 'bar';`).get('declaration'), + bar: stmt => stmt(`export default 'bar';`).get('declaration'), }); it('returns the value path if the property exists', () => { - const objectExpressionPath = statement('({foo: 21, bar: 42})').get( - 'expression', + const objectExpressionPath = parse + .statement('({foo: 21, bar: 42})') + .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'bar')).toBe( + objectExpressionPath.get('properties')[1].get('value'), ); - expect( - getPropertyValuePath(objectExpressionPath, 'bar', noopImporter), - ).toBe(objectExpressionPath.get('properties', 1).get('value')); }); it('returns the value path for a computed property in scope', () => { - const objectExpressionPath = statement(` + const objectExpressionPath = parse + .statement( + ` ({foo: 21, [a]: 42}); var a = 'bar'; - `).get('expression'); - expect( - getPropertyValuePath(objectExpressionPath, 'bar', noopImporter), - ).toBe(objectExpressionPath.get('properties', 1).get('value')); + `, + ) + .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'bar')).toBe( + objectExpressionPath.get('properties')[1].get('value'), + ); }); it('returns undefined if the property does not exist', () => { - const objectExpressionPath = statement('({foo: 21, bar: 42})').get( - 'expression', - ); - expect( - getPropertyValuePath(objectExpressionPath, 'baz', noopImporter), - ).toBeUndefined(); + const objectExpressionPath = parse + .statement('({foo: 21, bar: 42})') + .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'baz')).toBeNull(); }); it('returns the value path for a computed property that was imported', () => { - const objectExpressionPath = statement(` + const objectExpressionPath = parse + .statement( + ` ({foo: 21, [a]: 42}); import a from 'bar'; - `).get('expression'); - expect( - getPropertyValuePath(objectExpressionPath, 'bar', mockImporter), - ).toBe(objectExpressionPath.get('properties', 1).get('value')); + `, + mockImporter, + ) + .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'bar')).toBe( + objectExpressionPath.get('properties')[1].get('value'), + ); + }); + + it('returns ObjectMethod directly', () => { + const objectExpressionPath = parse + .statement('({ foo(){} })') + .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'foo')).toBe( + objectExpressionPath.get('properties')[0], + ); }); }); diff --git a/src/utils/__tests__/getTSType-test.ts b/src/utils/__tests__/getTSType-test.ts index 887e0cc397f..63e95d23b22 100644 --- a/src/utils/__tests__/getTSType-test.ts +++ b/src/utils/__tests__/getTSType-test.ts @@ -1,60 +1,89 @@ -import { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { + Declaration, + ExportNamedDeclaration, + TSInterfaceDeclaration, + TSTypeAnnotation, + TypeScript, + VariableDeclaration, +} from '@babel/types'; import { - statement as stmt, - noopImporter, + parseTypescript, makeMockImporter, + noopImporter, } from '../../../tests/utils'; +import type { Importer } from '../../importer'; import getTSType from '../getTSType'; -function statement(src: string): NodePath { - return stmt(src, { - filename: 'test.ts', - babelrc: false, - }); +function typeAlias( + stmt: string, + importer: Importer = noopImporter, +): NodePath { + return parseTypescript + .statement(stmt, importer) + .get( + 'declarations.0.id.typeAnnotation.typeAnnotation', + ) as NodePath; } const mockImporter = makeMockImporter({ - abc: statement(` - export type abc = number; - `).get('declaration'), - - def: statement(` - export type def = boolean; - `).get('declaration'), - - xyz: statement(` - export type xyz = string; - `).get('declaration'), - - barbaz: statement(` - export type barbaz = "bar" | "baz"; - `).get('declaration'), - - recTup: statement(` - export type recTup = [abc, xyz]; - import { abc } from 'abc'; - import { xyz } from 'xyz'; - `).get('declaration'), - - obj: statement(` - export type A = { x: string }; - `).get('declaration'), - - MyType: statement(` - export type MyType = { a: number, b: xyz }; - import { xyz } from 'xyz'; - `).get('declaration'), - - MyGenericType: statement(` - export type MyGenericType = { a: T, b: Array }; - `).get('declaration'), - - fruits: statement(` + abc: stmtLast => + stmtLast(`export type abc = number;`, true).get( + 'declaration', + ) as NodePath, + + def: stmtLast => + stmtLast(`export type def = boolean;`, true).get( + 'declaration', + ) as NodePath, + + xyz: stmtLast => + stmtLast(`export type xyz = string;`, true).get( + 'declaration', + ) as NodePath, + + barbaz: stmtLast => + stmtLast( + `export type barbaz = "bar" | "baz";`, + true, + ).get('declaration') as NodePath, + + recTup: stmtLast => + stmtLast( + `import { abc } from 'abc'; + import { xyz } from 'xyz'; + export type recTup = [abc, xyz];`, + true, + ).get('declaration') as NodePath, + + obj: stmtLast => + stmtLast( + `export type A = { x: string };`, + true, + ).get('declaration') as NodePath, + + MyType: stmtLast => + stmtLast( + `import { xyz } from 'xyz'; + export type MyType = { a: number, b: xyz };`, + true, + ).get('declaration') as NodePath, + + MyGenericType: stmtLast => + stmtLast( + `export type MyGenericType = { a: T, b: Array };`, + true, + ).get('declaration') as NodePath, + + fruits: stmtLast => + stmtLast( + ` export default { 'apple': '🍎', 'banana': '🍌', }; - `).get('declaration'), + `, + ).get('declaration'), }); describe('getTSType', () => { @@ -78,12 +107,8 @@ describe('getTSType', () => { ]; simplePropTypes.forEach(type => { - const typePath = statement(`let x: ${type};`) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ name: type }); + const typePath = typeAlias(`let x: ${type};`); + expect(getTSType(typePath)).toEqual({ name: type }); }); }); @@ -91,12 +116,8 @@ describe('getTSType', () => { const literalTypes = ['"foo"', 1234, true]; literalTypes.forEach(value => { - const typePath = statement(`let x: ${value};`) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias(`let x: ${value};`); + expect(getTSType(typePath)).toEqual({ name: 'literal', value: `${value}`, }); @@ -104,33 +125,24 @@ describe('getTSType', () => { }); it('detects external type', () => { - const typePath = statement('let x: xyz;') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ name: 'xyz' }); + const typePath = typeAlias('let x: xyz;'); + expect(getTSType(typePath)).toEqual({ name: 'xyz' }); }); it('resolves external type', () => { - const typePath = statement(` + const typePath = typeAlias( + ` let x: xyz; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ name: 'string' }); + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'string' }); }); it('detects array type shorthand', () => { - const typePath = statement('let x: number[];') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: number[];'); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], raw: 'number[]', @@ -138,12 +150,8 @@ describe('getTSType', () => { }); it('detects array type', () => { - const typePath = statement('let x: Array;') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: Array;'); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], raw: 'Array', @@ -151,12 +159,8 @@ describe('getTSType', () => { }); it('detects array type with multiple types', () => { - const typePath = statement('let x: Array;') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: Array;'); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }, { name: 'xyz' }], raw: 'Array', @@ -164,43 +168,40 @@ describe('getTSType', () => { }); it('resolves imported types used for arrays', () => { - let typePath = statement(` + let typePath = typeAlias( + ` let x: xyz[]; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'string' }], raw: 'xyz[]', }); - typePath = statement(` + typePath = typeAlias( + ` let x: Array; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'string' }], raw: 'Array', }); - typePath = statement(` + typePath = typeAlias( + ` let x: Array; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }, { name: 'string' }], raw: 'Array', @@ -208,12 +209,8 @@ describe('getTSType', () => { }); it('detects class type', () => { - const typePath = statement('let x: Class;') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: Class;'); + expect(getTSType(typePath)).toEqual({ name: 'Class', elements: [{ name: 'Boolean' }], raw: 'Class', @@ -221,15 +218,14 @@ describe('getTSType', () => { }); it('resolves imported subtype for class type', () => { - const typePath = statement(` + const typePath = typeAlias( + ` let x: Class; import { xyz } from 'xyz' - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'Class', elements: [{ name: 'string' }], raw: 'Class', @@ -237,12 +233,8 @@ describe('getTSType', () => { }); it('detects function type with subtype', () => { - const typePath = statement('let x: Function;') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: Function;'); + expect(getTSType(typePath)).toEqual({ name: 'Function', elements: [{ name: 'xyz' }], raw: 'Function', @@ -250,15 +242,14 @@ describe('getTSType', () => { }); it('resolves imported subtype for function type', () => { - const typePath = statement(` + const typePath = typeAlias( + ` let x: Function; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'Function', elements: [{ name: 'string' }], raw: 'Function', @@ -266,12 +257,8 @@ describe('getTSType', () => { }); it('detects object types', () => { - const typePath = statement('let x: { a: string, b?: xyz };') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: { a: string, b?: xyz };'); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -285,15 +272,14 @@ describe('getTSType', () => { }); it('resolves imported types for object property types', () => { - const typePath = statement(` + const typePath = typeAlias( + ` let x: { a: number, b?: xyz }; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -307,12 +293,8 @@ describe('getTSType', () => { }); it('detects union type', () => { - const typePath = statement('let x: string | xyz | "foo" | void;') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: string | xyz | "foo" | void;'); + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ { name: 'string' }, @@ -325,15 +307,14 @@ describe('getTSType', () => { }); it('resolves imported types within union type', () => { - const typePath = statement(` + const typePath = typeAlias( + ` let x: string | barbaz | "foo" | void; import { barbaz } from 'barbaz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ { name: 'string' }, @@ -353,12 +334,8 @@ describe('getTSType', () => { }); it('detects intersection type', () => { - const typePath = statement('let x: string & xyz & "foo" & void;') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: string & xyz & "foo" & void;'); + expect(getTSType(typePath)).toEqual({ name: 'intersection', elements: [ { name: 'string' }, @@ -371,15 +348,14 @@ describe('getTSType', () => { }); it('resolves imported types within intersection type', () => { - const typePath = statement(` + const typePath = typeAlias( + ` let x: string & barbaz & "foo" & void; import { barbaz } from 'barbaz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'intersection', elements: [ { name: 'string' }, @@ -399,14 +375,10 @@ describe('getTSType', () => { }); it('detects function signature type', () => { - const typePath = statement( + const typePath = typeAlias( 'let x: (p1: number, p2: string, ...rest: Array) => boolean;', - ) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -430,12 +402,8 @@ describe('getTSType', () => { }); it('detects function signature type with `this` parameter', () => { - const typePath = statement('let x: (this: Foo, p1: number) => boolean;') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: (this: Foo, p1: number) => boolean;'); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -448,14 +416,10 @@ describe('getTSType', () => { }); it('detects callable signature type', () => { - const typePath = statement( + const typePath = typeAlias( 'let x: { (str: string): string, token: string };', - ) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -477,17 +441,16 @@ describe('getTSType', () => { }); it('resolves function signature types with imported types', () => { - let typePath = statement(` + let typePath = typeAlias( + ` let x: (p1: abc, p2: xyz, ...rest: Array) => def; import { abc } from 'abc'; import { def } from 'def'; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -509,15 +472,14 @@ describe('getTSType', () => { raw: '(p1: abc, p2: xyz, ...rest: Array) => def', }); - typePath = statement(` + typePath = typeAlias( + ` let x: (this: xyz, p1: number) => boolean; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'function', signature: { @@ -528,17 +490,16 @@ describe('getTSType', () => { raw: '(this: xyz, p1: number) => boolean', }); - typePath = statement(` + typePath = typeAlias( + ` let x: { (str: xyz): abc, token: def }; import { abc } from 'abc'; import { def } from 'def'; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -560,14 +521,10 @@ describe('getTSType', () => { }); it('detects map signature', () => { - const typePath = statement( + const typePath = typeAlias( 'let x: { [key: string]: number, [key: "xl"]: string, token: "a" | "b" };', - ) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -599,17 +556,16 @@ describe('getTSType', () => { }); it('resolves imported types in map signature', () => { - const typePath = statement(` + const typePath = typeAlias( + ` let x: { [key: xyz]: abc, [key: "xl"]: xyz, token: barbaz }; import { abc } from 'abc'; import { xyz } from 'xyz'; import { barbaz } from 'barbaz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -641,12 +597,8 @@ describe('getTSType', () => { }); it('detects tuple signature', () => { - const typePath = statement('let x: [string, number];') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: [string, number];'); + expect(getTSType(typePath)).toEqual({ name: 'tuple', elements: [{ name: 'string' }, { name: 'number' }], raw: '[string, number]', @@ -654,12 +606,8 @@ describe('getTSType', () => { }); it('detects tuple in union signature', () => { - const typePath = statement('let x: [string, number] | [number, string];') - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + const typePath = typeAlias('let x: [string, number] | [number, string];'); + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ { @@ -678,32 +626,30 @@ describe('getTSType', () => { }); it('resolves imported types in tuple signatures', () => { - let typePath = statement(` + let typePath = typeAlias( + ` let x: [xyz, abc]; import { abc } from 'abc'; import { xyz } from 'xyz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'tuple', elements: [{ name: 'string' }, { name: 'number' }], raw: '[xyz, abc]', }); - typePath = statement(` + typePath = typeAlias( + ` let x: [xyz, abc] | recTup; import { abc } from 'abc'; import { xyz } from 'xyz'; import { recTup } from 'recTup'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ { @@ -722,39 +668,33 @@ describe('getTSType', () => { }); it('detects indexed access', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: A["x"] = 2; interface A { x: string }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + `); + expect(getTSType(typePath)).toEqual({ name: 'A["x"]', raw: 'A["x"]', }); }); it('resolves indexed access', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: A["x"] = 2; type A = { x: string }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + `); + expect(getTSType(typePath)).toEqual({ name: 'string', raw: 'A["x"]', }); }); it('resolves indexed access of array', () => { - const typePath = statement(` + const typePath = parseTypescript + .statement( + ` var x: typeof STRING_VALS[number]; const STRING_VALS = [ @@ -762,58 +702,50 @@ describe('getTSType', () => { 'two', 'three' ]; - `) - .get('declarations', 0) + `, + ) + .get('declarations')[0] .get('id') .get('typeAnnotation') .get('typeAnnotation'); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'STRING_VALS[number]', raw: 'typeof STRING_VALS[number]', }); }); it('can resolve indexed access to imported type', () => { - const typePath = statement(` + const typePath = typeAlias( + ` var x: A["x"] = 2; import { A } from 'obj'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + `, + mockImporter, + ); + expect(getTSType(typePath)).toEqual({ name: 'string', raw: 'A["x"]', }); }); it('resolves types in scope', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: MyType = 2; type MyType = string; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ name: 'string' }); + expect(getTSType(typePath)).toEqual({ name: 'string' }); }); it('handles typeof types', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: typeof MyType = {}; type MyType = { a: string, b: xyz }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -827,16 +759,15 @@ describe('getTSType', () => { }); it('resolves typeof of imported types', () => { - const typePath = statement(` + const typePath = typeAlias( + ` var x: typeof MyType = {}; import { MyType } from 'MyType'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `, + mockImporter, + ); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -850,33 +781,25 @@ describe('getTSType', () => { }); it('handles qualified type identifiers', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: MyType.x = {}; type MyType = { a: string, b: xyz }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'MyType.x', }); }); it('handles qualified type identifiers with params', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: MyType.x = {}; type MyType = { a: string, b: xyz }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'MyType.x', raw: 'MyType.x', elements: [ @@ -888,17 +811,13 @@ describe('getTSType', () => { }); it('handles generic types', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: MyType = {}; type MyType = { a: T, b: Array }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', raw: '{ a: T, b: Array }', @@ -926,16 +845,15 @@ describe('getTSType', () => { }); it('resolves imported types that need subtypes', () => { - const typePath = statement(` + const typePath = typeAlias( + ` var x: MyGenericType = {}; import { MyGenericType } from 'MyGenericType'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `, + mockImporter, + ); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', raw: '{ a: T, b: Array }', @@ -963,15 +881,11 @@ describe('getTSType', () => { }); it('handles mapped types', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: { [key in 'x' | 'y']: boolean}; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', raw: "{ [key in 'x' | 'y']: boolean}", @@ -1003,16 +917,15 @@ describe('getTSType', () => { }); it('resolves imported types applied to mapped types', () => { - const typePath = statement(` + const typePath = typeAlias( + ` var x: { [key in barbaz]: boolean}; import { barbaz } from 'barbaz'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `, + mockImporter, + ); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', raw: '{ [key in barbaz]: boolean}', @@ -1045,17 +958,13 @@ describe('getTSType', () => { describe('React types', () => { function test(type, expected) { - const typePath = statement(` + const typePath = typeAlias(` var x: ${type} = 2; type Props = { x: string }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ ...expected, name: type.replace('.', '').replace(/<.+>/, ''), raw: type, @@ -1096,19 +1005,15 @@ describe('getTSType', () => { }); it('resolves keyof to union', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: keyof typeof CONTENTS = 2; const CONTENTS = { 'apple': '🍎', 'banana': '🍌', }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: "'apple'" }, @@ -1119,16 +1024,15 @@ describe('getTSType', () => { }); it('resolves keyof with imported types', () => { - const typePath = statement(` + const typePath = typeAlias( + ` var x: keyof typeof CONTENTS = 2; import CONTENTS from 'fruits'; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `, + mockImporter, + ); - expect(getTSType(typePath, null, mockImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: "'apple'" }, @@ -1139,15 +1043,11 @@ describe('getTSType', () => { }); it('resolves keyof with inline object to union', () => { - const typePath = statement(` + const typePath = typeAlias(` var x: keyof { apple: string, banana: string } = 2; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ { name: 'literal', value: 'apple' }, @@ -1158,16 +1058,12 @@ describe('getTSType', () => { }); it('handles multiple references to one type', () => { - const typePath = statement(` + const typePath = typeAlias(` let action: { a: Action, b: Action }; type Action = {}; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -1199,32 +1095,30 @@ describe('getTSType', () => { }); it('handles generics of the same Name', () => { - const typePath = statement(` + const typePath = parseTypescript + .statement( + ` interface Props { baz: Foo } type Foo = Bar - - `) + `, + ) .get('body') - .get('body', 0) + .get('body')[0] .get('typeAnnotation'); - getTSType(typePath, null, noopImporter); + getTSType(typePath as NodePath, null); }); it('handles self-referencing type cycles', () => { - const typePath = statement(` + const typePath = typeAlias(` let action: Action; type Action = { subAction: Action }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { @@ -1237,19 +1131,15 @@ describe('getTSType', () => { }); it('handles long type cycles', () => { - const typePath = statement(` + const typePath = typeAlias(` let action: Action; type Action = { subAction: SubAction }; type SubAction = { subAction: SubSubAction }; type SubSubAction = { subAction: SubSubSubAction }; type SubSubSubAction = { rootAction: Action }; - `) - .get('declarations', 0) - .get('id') - .get('typeAnnotation') - .get('typeAnnotation'); + `); - expect(getTSType(typePath, null, noopImporter)).toEqual({ + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', signature: { diff --git a/src/utils/__tests__/getTypeAnnotation-test.ts b/src/utils/__tests__/getTypeAnnotation-test.ts index b78eebc15f0..b52cafd4feb 100644 --- a/src/utils/__tests__/getTypeAnnotation-test.ts +++ b/src/utils/__tests__/getTypeAnnotation-test.ts @@ -1,9 +1,10 @@ -import { expression } from '../../../tests/utils'; +import type { TypeCastExpression } from '@babel/types'; +import { parse } from '../../../tests/utils'; import getTypeAnnotation from '../getTypeAnnotation'; describe('getTypeAnnotation', () => { it('detects simple type', () => { - const path = expression('x: xyz'); + const path = parse.expression('x: xyz'); expect(getTypeAnnotation(path)).toEqual( path.get('typeAnnotation').get('typeAnnotation'), @@ -11,13 +12,13 @@ describe('getTypeAnnotation', () => { }); it('does not fail if no type', () => { - const path = expression('x = 0'); + const path = parse.expression('x = 0'); expect(getTypeAnnotation(path)).toEqual(null); }); it('stops at first nested type', () => { - const path = expression('x: ?xyz'); + const path = parse.expression('x: ?xyz'); expect(getTypeAnnotation(path)).toEqual( path.get('typeAnnotation').get('typeAnnotation'), diff --git a/src/utils/__tests__/isDestructuringAssignment-test.ts b/src/utils/__tests__/isDestructuringAssignment-test.ts index d6de528e775..d39d15dff31 100644 --- a/src/utils/__tests__/isDestructuringAssignment-test.ts +++ b/src/utils/__tests__/isDestructuringAssignment-test.ts @@ -1,3 +1,5 @@ +import type { NodePath } from '@babel/traverse'; +import type { Node } from '@babel/types'; import { parse } from '../../../tests/utils'; import isDestructuringAssignment from '../isDestructuringAssignment'; @@ -5,7 +7,7 @@ describe('isDestructuringAssignment', () => { it('detects destructuring', () => { const def = parse(` var { Component } = require('react'); - `).get('body', 0, 'declarations', 0, 'id', 'properties', 0, 'key'); + `).get('body.0.declarations.0.id.properties.0') as NodePath; expect(isDestructuringAssignment(def, 'Component')).toBe(true); }); @@ -13,7 +15,7 @@ describe('isDestructuringAssignment', () => { it('fails if name does not match', () => { const def = parse(` var { Component } = require('react'); - `).get('body', 0, 'declarations', 0, 'id', 'properties', 0, 'key'); + `).get('body.0.declarations.0.id.properties.0') as NodePath; expect(isDestructuringAssignment(def, 'Component2')).toBe(false); }); @@ -21,7 +23,7 @@ describe('isDestructuringAssignment', () => { it('detects destructuring with alias', () => { const def = parse(` var { Component: C } = require('react'); - `).get('body', 0, 'declarations', 0, 'id', 'properties', 0, 'value'); + `).get('body.0.declarations.0.id.properties.0') as NodePath; expect(isDestructuringAssignment(def, 'Component')).toBe(true); }); @@ -29,7 +31,7 @@ describe('isDestructuringAssignment', () => { it('fails if name does not match with alias', () => { const def = parse(` var { Component: C } = require('react'); - `).get('body', 0, 'declarations', 0, 'id', 'properties', 0, 'value'); + `).get('body.0.declarations.0.id.properties.0') as NodePath; expect(isDestructuringAssignment(def, 'Component2')).toBe(false); }); diff --git a/src/utils/__tests__/isExportsOrModuleAssignment-test.ts b/src/utils/__tests__/isExportsOrModuleAssignment-test.ts index 3208c8f1135..a80453db807 100644 --- a/src/utils/__tests__/isExportsOrModuleAssignment-test.ts +++ b/src/utils/__tests__/isExportsOrModuleAssignment-test.ts @@ -1,29 +1,23 @@ -import { statement, noopImporter } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; import isExportsOrModuleAssignment from '../isExportsOrModuleAssignment'; describe('isExportsOrModuleAssignment', () => { it('detects "module.exports = ...;"', () => { expect( - isExportsOrModuleAssignment( - statement('module.exports = foo;'), - noopImporter, - ), + isExportsOrModuleAssignment(parse.statement('module.exports = foo;')), ).toBe(true); }); it('detects "exports.foo = ..."', () => { expect( - isExportsOrModuleAssignment( - statement('exports.foo = foo;'), - noopImporter, - ), + isExportsOrModuleAssignment(parse.statement('exports.foo = foo;')), ).toBe(true); }); it('does not accept "exports = foo;"', () => { // That doesn't actually export anything - expect( - isExportsOrModuleAssignment(statement('exports = foo;'), noopImporter), - ).toBe(false); + expect(isExportsOrModuleAssignment(parse.statement('exports = foo;'))).toBe( + false, + ); }); }); diff --git a/src/utils/__tests__/isReactCloneElementCall-test.ts b/src/utils/__tests__/isReactCloneElementCall-test.ts index b9e85e0377f..8822b290ad7 100644 --- a/src/utils/__tests__/isReactCloneElementCall-test.ts +++ b/src/utils/__tests__/isReactCloneElementCall-test.ts @@ -1,90 +1,89 @@ -import { - statement, - noopImporter, - makeMockImporter, - expressionLast, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import isReactCloneElementCall from '../isReactCloneElementCall'; describe('isReactCloneElementCall', () => { const mockImporter = makeMockImporter({ - foo: statement(` - export default React.cloneElement; + foo: stmtLast => + stmtLast(` import React from 'react'; + export default React.cloneElement; `).get('declaration'), }); describe('built in React.createClass', () => { it('accepts cloneElement called on React', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("React"); React.cloneElement({}); `); - expect(isReactCloneElementCall(def, noopImporter)).toBe(true); + expect(isReactCloneElementCall(def)).toBe(true); }); it('accepts cloneElement called on aliased React', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var other = require("React"); other.cloneElement({}); `); - expect(isReactCloneElementCall(def, noopImporter)).toBe(true); + expect(isReactCloneElementCall(def)).toBe(true); }); it('ignores other React calls', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("React"); React.isValidElement({}); `); - expect(isReactCloneElementCall(def, noopImporter)).toBe(false); + expect(isReactCloneElementCall(def)).toBe(false); }); it('ignores non React calls to cloneElement', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("bob"); React.cloneElement({}); `); - expect(isReactCloneElementCall(def, noopImporter)).toBe(false); + expect(isReactCloneElementCall(def)).toBe(false); }); it('accepts cloneElement called on destructed value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var { cloneElement } = require("react"); cloneElement({}); `); - expect(isReactCloneElementCall(def, noopImporter)).toBe(true); + expect(isReactCloneElementCall(def)).toBe(true); }); it('accepts cloneElement called on destructed aliased value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var { cloneElement: foo } = require("react"); foo({}); `); - expect(isReactCloneElementCall(def, noopImporter)).toBe(true); + expect(isReactCloneElementCall(def)).toBe(true); }); it('accepts cloneElement called on imported value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { cloneElement } from "react"; cloneElement({}); `); - expect(isReactCloneElementCall(def, noopImporter)).toBe(true); + expect(isReactCloneElementCall(def)).toBe(true); }); it('accepts cloneElement called on imported aliased value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { cloneElement as foo } from "react"; foo({}); `); - expect(isReactCloneElementCall(def, noopImporter)).toBe(true); + expect(isReactCloneElementCall(def)).toBe(true); }); it('can resolve cloneElement imported from an intermediate module', () => { - const def = expressionLast(` + const def = parse.expressionLast( + ` import foo from "foo"; foo({}); - `); - expect(isReactCloneElementCall(def, mockImporter)).toBe(true); + `, + mockImporter, + ); + expect(isReactCloneElementCall(def)).toBe(true); }); }); }); diff --git a/src/utils/__tests__/isReactComponentClass-test.ts b/src/utils/__tests__/isReactComponentClass-test.ts index cd3c38bce6d..24f0899dce0 100644 --- a/src/utils/__tests__/isReactComponentClass-test.ts +++ b/src/utils/__tests__/isReactComponentClass-test.ts @@ -1,190 +1,201 @@ -import { - expression, - statement, - parse, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import isReactComponentClass from '../isReactComponentClass'; describe('isReactComponentClass', () => { const mockImporter = makeMockImporter({ - component: statement(` - export default React.Component; + component: stmtLast => + stmtLast(` import React from 'react'; + export default React.Component; `).get('declaration'), - pureComponent: statement(` - export default React.PureComponent; + pureComponent: stmtLast => + stmtLast(` import React from 'react'; + export default React.PureComponent; `).get('declaration'), }); describe('render method', () => { it('ignores class declarations with a render method without superclass', () => { - const def = statement('class Foo { render() {}}'); - expect(isReactComponentClass(def, noopImporter)).toBe(false); + const def = parse.statement('class Foo { render() {}}'); + expect(isReactComponentClass(def)).toBe(false); }); it('ignores class expression with a render method without superclass', () => { - const def = expression('class { render() {}}'); - expect(isReactComponentClass(def, noopImporter)).toBe(false); + const def = parse.expression('class { render() {}}'); + expect(isReactComponentClass(def)).toBe(false); }); it('ignores static render methods', () => { - const def = statement('class Foo { static render() {}}'); - expect(isReactComponentClass(def, noopImporter)).toBe(false); + const def = parse.statement('class Foo { static render() {}}'); + expect(isReactComponentClass(def)).toBe(false); }); it('ignores dynamic render methods', () => { - const def = statement('class Foo { static [render]() {}}'); - expect(isReactComponentClass(def, noopImporter)).toBe(false); + const def = parse.statement('class Foo { static [render]() {}}'); + expect(isReactComponentClass(def)).toBe(false); }); it('ignores getter or setter render methods', () => { - let def = statement('class Foo { get render() {}}'); - expect(isReactComponentClass(def, noopImporter)).toBe(false); + let def = parse.statement('class Foo { get render() {}}'); + expect(isReactComponentClass(def)).toBe(false); - def = statement('class Foo { set render(value) {}}'); - expect(isReactComponentClass(def, noopImporter)).toBe(false); + def = parse.statement('class Foo { set render(value) {}}'); + expect(isReactComponentClass(def)).toBe(false); }); }); describe('JSDoc @extends React.Component', () => { it('accepts class declarations declaring `@extends React.Component` in JSDoc', () => { - const def = parse(` + const def = parse.statementLast(` var React = require('react'); /** * @class Foo * @extends React.Component */ class Foo extends Bar {} - `).get('body', 1); + `); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); }); describe('React.Component inheritance', () => { it('accepts class declarations extending React.Component', () => { - const def = parse(` + const def = parse.statementLast(` var React = require('react'); class Foo extends React.Component {} - `).get('body', 1); + `); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('accepts class expressions extending React.Component', () => { - const def = parse(` + const def = parse + .statementLast( + ` var React = require('react'); var Foo = class extends React.Component {} - `).get('body', 1, 'declarations', 0, 'init'); + `, + ) + .get('declarations')[0] + .get('init'); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('resolves the super class reference', () => { - const def = parse(` + const def = parse.statementLast(` var { Component } = require('react'); var C = Component; class Foo extends C {} - `).get('body', 2); + `); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('resolves the super class reference with alias', () => { - const def = parse(` + const def = parse.statementLast(` var { Component: C } = require('react'); class Foo extends C {} - `).get('body', 1); + `); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('does not accept references to other modules', () => { - const def = parse(` + const def = parse.statementLast( + ` var { Component } = require('FakeReact'); class Foo extends Component {} - `).get('body', 1); + `, + ); - expect(isReactComponentClass(def, noopImporter)).toBe(false); + expect(isReactComponentClass(def)).toBe(false); }); it('does not consider super class if render method is present', () => { - const def = parse(` + const def = parse.statementLast( + ` var {Component} = require('FakeReact'); class Foo extends Component { render() {} } - `).get('body', 1); + `, + ); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('can resolve Component from an intermediate module', () => { - const def = parse(` - import RC from 'component'; - class Foo extends RC {} - `).get('body', 1); + const def = parse.statementLast( + `import RC from 'component'; + class Foo extends RC {}`, + mockImporter, + ); - expect(isReactComponentClass(def, mockImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); }); describe('React.PureComponent inheritance', () => { it('accepts class declarations extending React.PureComponent', () => { - const def = parse(` - var React = require('react'); - class Foo extends React.PureComponent {} - `).get('body', 1); + const def = parse.statementLast( + `var React = require('react'); + class Foo extends React.PureComponent {}`, + ); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('accepts class expressions extending React.PureComponent', () => { - const def = parse(` - var React = require('react'); - var Foo = class extends React.PureComponent {} - `).get('body', 1, 'declarations', 0, 'init'); + const def = parse + .statementLast( + `var React = require('react'); + var Foo = class extends React.PureComponent {}`, + ) + .get('declarations')[0] + .get('init'); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('resolves the super class reference', () => { - const def = parse(` - var {PureComponent} = require('react'); - var C = PureComponent; - class Foo extends C {} - `).get('body', 2); + const def = parse.statementLast( + `var {PureComponent} = require('react'); + var C = PureComponent; + class Foo extends C {}`, + ); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('does not accept references to other modules', () => { - const def = parse(` - var {PureComponent} = require('FakeReact'); - class Foo extends PureComponent {} - `).get('body', 1); - - expect(isReactComponentClass(def, noopImporter)).toBe(false); + const def = parse.statementLast( + `var {PureComponent} = require('FakeReact'); + class Foo extends PureComponent {}`, + ); + expect(isReactComponentClass(def)).toBe(false); }); it('does not consider super class if render method is present', () => { - const def = parse(` + const def = parse.statementLast(` var {PureComponent} = require('FakeReact'); class Foo extends PureComponent { render() {} } - `).get('body', 1); + `); - expect(isReactComponentClass(def, noopImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); it('can resolve PureComponent from an intermediate module', () => { - const def = parse(` + const def = parse.statementLast( + ` import PC from 'pureComponent'; class Foo extends PC {} - `).get('body', 1); + `, + mockImporter, + ); - expect(isReactComponentClass(def, mockImporter)).toBe(true); + expect(isReactComponentClass(def)).toBe(true); }); }); }); diff --git a/src/utils/__tests__/isReactComponentMethod-test.ts b/src/utils/__tests__/isReactComponentMethod-test.ts index bc77b8481ab..b63d9967e51 100644 --- a/src/utils/__tests__/isReactComponentMethod-test.ts +++ b/src/utils/__tests__/isReactComponentMethod-test.ts @@ -1,53 +1,53 @@ -import { - expression, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import type { ClassDeclaration, ObjectExpression } from '@babel/types'; +import { parse, makeMockImporter } from '../../../tests/utils'; import isReactComponentMethod from '../isReactComponentMethod'; describe('isReactComponentMethod', () => { const mockImporter = makeMockImporter({ - foo: statement(` + foo: stmtLast => + stmtLast(` export default 'render'; `).get('declaration'), }); it('returns true if the method is a component class method', () => { - const def = statement('class Foo { render() {}}'); - const method = def.get('body', 'body', 0); - expect(isReactComponentMethod(method, noopImporter)).toBe(true); + const def = parse.statement('class Foo { render() {}}'); + const method = def.get('body').get('body')[0]; + expect(isReactComponentMethod(method)).toBe(true); }); it('returns true if the method is a component `createClass` object method', () => { - const def = expression('{ render() {}}'); - const method = def.get('properties', 0); - expect(isReactComponentMethod(method, noopImporter)).toBe(true); + const def = parse.expression('{ render() {}}'); + const method = def.get('properties')[0]; + expect(isReactComponentMethod(method)).toBe(true); }); it('returns false if the method is not a component class method', () => { - const def = statement('class Foo { bar() {}}'); - const method = def.get('body', 'body', 0); - expect(isReactComponentMethod(method, noopImporter)).toBe(false); + const def = parse.statement('class Foo { bar() {}}'); + const method = def.get('body').get('body')[0]; + expect(isReactComponentMethod(method)).toBe(false); }); it('returns false if the method is not a component `createClass` object method', () => { - const def = expression('{ bar() {}}'); - const method = def.get('properties', 0); - expect(isReactComponentMethod(method, noopImporter)).toBe(false); + const def = parse.expression('{ bar() {}}'); + const method = def.get('properties')[0]; + expect(isReactComponentMethod(method)).toBe(false); }); it('returns false if the path is not a method or object property', () => { - const def = statement('let foo = "bar";'); - expect(isReactComponentMethod(def, noopImporter)).toBe(false); + const def = parse.statement('let foo = "bar";'); + expect(isReactComponentMethod(def)).toBe(false); }); it('resolves imported value of computed property', () => { - const def = statement(` + const def = parse.statement( + ` class Foo { [foo]() {}} import foo from 'foo'; - `); - const method = def.get('body', 'body', 0); - expect(isReactComponentMethod(method, mockImporter)).toBe(true); + `, + mockImporter, + ); + const method = def.get('body').get('body')[0]; + expect(isReactComponentMethod(method)).toBe(true); }); }); diff --git a/src/utils/__tests__/isReactCreateClassCall-test.ts b/src/utils/__tests__/isReactCreateClassCall-test.ts index 3cdab33c470..cec88bf54ed 100644 --- a/src/utils/__tests__/isReactCreateClassCall-test.ts +++ b/src/utils/__tests__/isReactCreateClassCall-test.ts @@ -1,141 +1,144 @@ -import { - expressionLast, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import isReactCreateClassCall from '../isReactCreateClassCall'; describe('isReactCreateClassCall', () => { const mockImporter = makeMockImporter({ - foo: statement(` - export default React.createClass; + foo: stmtLast => + stmtLast(` import React from 'react'; + export default React.createClass; `).get('declaration'), - bar: statement(` - export default makeClass; + bar: stmtLast => + stmtLast(` import makeClass from "create-react-class"; + export default makeClass; `).get('declaration'), }); describe('built in React.createClass', () => { it('accepts createClass called on React', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("React"); React.createClass({ render() {} }); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(true); + expect(isReactCreateClassCall(def)).toBe(true); }); it('accepts createClass called on aliased React', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var other = require("React"); other.createClass({ render() {} }); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(true); + expect(isReactCreateClassCall(def)).toBe(true); }); it('ignores other React calls', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("React"); React.isValidElement({}); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(false); + expect(isReactCreateClassCall(def)).toBe(false); }); it('ignores non React calls to createClass', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("bob"); React.createClass({ render() {} }); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(false); + expect(isReactCreateClassCall(def)).toBe(false); }); it('accepts createClass called on destructed value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var { createClass } = require("react"); createClass({}); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(true); + expect(isReactCreateClassCall(def)).toBe(true); }); it('accepts createClass called on destructed aliased value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var { createClass: foo } = require("react"); foo({}); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(true); + expect(isReactCreateClassCall(def)).toBe(true); }); it('accepts createClass called on imported value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { createClass } from "react"; createClass({}); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(true); + expect(isReactCreateClassCall(def)).toBe(true); }); it('accepts createClass called on imported aliased value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { createClass as foo } from "react"; foo({}); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(true); + expect(isReactCreateClassCall(def)).toBe(true); }); it('resolves createClass imported from intermediate module', () => { - const def = expressionLast(` + const def = parse.expressionLast( + ` import foo from "foo"; foo({}); - `); - expect(isReactCreateClassCall(def, mockImporter)).toBe(true); + `, + mockImporter, + ); + expect(isReactCreateClassCall(def)).toBe(true); }); }); describe('modular in create-react-class', () => { it('accepts create-react-class', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var createReactClass = require("create-react-class"); createReactClass({ render() {} }); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(true); + expect(isReactCreateClassCall(def)).toBe(true); }); it('accepts create-react-class calls on another name', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var makeClass = require("create-react-class"); makeClass({ render() {} }); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(true); + expect(isReactCreateClassCall(def)).toBe(true); }); it('ignores non create-react-class calls to createReactClass', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var createReactClass = require("bob"); createReactClass({ render() {} }); `); - expect(isReactCreateClassCall(def, noopImporter)).toBe(false); + expect(isReactCreateClassCall(def)).toBe(false); }); it('resolves create-react-class imported from intermediate module', () => { - const def = expressionLast(` + const def = parse.expressionLast( + ` import bar from "bar"; bar({}); - `); - expect(isReactCreateClassCall(def, mockImporter)).toBe(true); + `, + mockImporter, + ); + expect(isReactCreateClassCall(def)).toBe(true); }); }); }); diff --git a/src/utils/__tests__/isReactCreateElementCall-test.ts b/src/utils/__tests__/isReactCreateElementCall-test.ts index c932b524778..fbb651f315d 100644 --- a/src/utils/__tests__/isReactCreateElementCall-test.ts +++ b/src/utils/__tests__/isReactCreateElementCall-test.ts @@ -1,96 +1,93 @@ -import { - expressionLast, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import isReactCreateElementCall from '../isReactCreateElementCall'; describe('isReactCreateElementCall', () => { const mockImporter = makeMockImporter({ - foo: statement(` - export default React.createElement; + foo: stmtLast => + stmtLast(` import React from 'react'; + export default React.createElement; `).get('declaration'), }); describe('built in React.createElement', () => { it('accepts createElement called on React', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("React"); React.createElement({ render() {} }); `); - expect(isReactCreateElementCall(def, noopImporter)).toBe(true); + expect(isReactCreateElementCall(def)).toBe(true); }); it('accepts createElement called on aliased React', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var other = require("React"); other.createElement({ render() {} }); `); - expect(isReactCreateElementCall(def, noopImporter)).toBe(true); + expect(isReactCreateElementCall(def)).toBe(true); }); it('ignores other React calls', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("React"); React.isValidElement({}); `); - expect(isReactCreateElementCall(def, noopImporter)).toBe(false); + expect(isReactCreateElementCall(def)).toBe(false); }); it('ignores non React calls to createElement', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("bob"); React.createElement({ render() {} }); `); - expect(isReactCreateElementCall(def, noopImporter)).toBe(false); + expect(isReactCreateElementCall(def)).toBe(false); }); it('accepts createElement called on destructed value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var { createElement } = require("react"); createElement({}); `); - expect(isReactCreateElementCall(def, noopImporter)).toBe(true); + expect(isReactCreateElementCall(def)).toBe(true); }); it('accepts createElement called on destructed aliased value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var { createElement: foo } = require("react"); foo({}); `); - expect(isReactCreateElementCall(def, noopImporter)).toBe(true); + expect(isReactCreateElementCall(def)).toBe(true); }); it('accepts createElement called on imported value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { createElement } from "react"; createElement({}); `); - expect(isReactCreateElementCall(def, noopImporter)).toBe(true); + expect(isReactCreateElementCall(def)).toBe(true); }); it('accepts createElement called on imported aliased value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { createElement as foo } from "react"; foo({}); `); - expect(isReactCreateElementCall(def, noopImporter)).toBe(true); + expect(isReactCreateElementCall(def)).toBe(true); }); it('can resolve createElement imported from an intermediate module', () => { - const def = expressionLast(` - import foo from "foo"; - foo({}); - `); - expect(isReactCreateElementCall(def, mockImporter)).toBe(true); + const def = parse.expressionLast( + `import foo from "foo"; + foo({});`, + mockImporter, + ); + expect(isReactCreateElementCall(def)).toBe(true); }); }); }); diff --git a/src/utils/__tests__/isReactForwardRefCall-test.ts b/src/utils/__tests__/isReactForwardRefCall-test.ts index 7cb34525424..8da0dd84b28 100644 --- a/src/utils/__tests__/isReactForwardRefCall-test.ts +++ b/src/utils/__tests__/isReactForwardRefCall-test.ts @@ -1,104 +1,103 @@ -import { - statement, - noopImporter, - makeMockImporter, - expressionLast, -} from '../../../tests/utils'; +import { makeMockImporter, parse } from '../../../tests/utils'; import isReactForwardRefCall from '../isReactForwardRefCall'; describe('isReactForwardRefCall', () => { const mockImporter = makeMockImporter({ - foo: statement(` - export default React.forwardRef; + foo: stmtLast => + stmtLast(` import React from 'react'; + export default React.forwardRef; `).get('declaration'), }); describe('built in React.forwardRef', () => { it('accepts forwardRef called on React', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("React"); React.forwardRef({ render() {} }); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(true); + expect(isReactForwardRefCall(def)).toBe(true); }); it('accepts forwardRef called on aliased React', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var other = require("React"); other.forwardRef({ render() {} }); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(true); + expect(isReactForwardRefCall(def)).toBe(true); }); it('ignores other React calls', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("React"); React.isValidElement({}); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(false); + expect(isReactForwardRefCall(def)).toBe(false); }); it('ignores non React calls to forwardRef', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var React = require("bob"); React.forwardRef({ render() {} }); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(false); + expect(isReactForwardRefCall(def)).toBe(false); }); it('accepts forwardRef called on destructed value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var { forwardRef } = require("react"); forwardRef({}); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(true); + expect(isReactForwardRefCall(def)).toBe(true); }); it('accepts forwardRef called on destructed aliased value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` var { forwardRef: foo } = require("react"); foo({}); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(true); + expect(isReactForwardRefCall(def)).toBe(true); }); it('accepts forwardRef called on imported value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { forwardRef } from "react"; forwardRef({}); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(true); + expect(isReactForwardRefCall(def)).toBe(true); }); it('does not accept forwardRef if not outer call', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { forwardRef, memo } from "react"; memo(forwardRef({})); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(false); + expect(isReactForwardRefCall(def)).toBe(false); }); it('accepts forwardRef called on imported aliased value', () => { - const def = expressionLast(` + const def = parse.expressionLast(` import { forwardRef as foo } from "react"; foo({}); `); - expect(isReactForwardRefCall(def, noopImporter)).toBe(true); + expect(isReactForwardRefCall(def)).toBe(true); }); it('can resolve forwardRef imported from an intermediate module', () => { - const def = expressionLast(` + const def = parse.expressionLast( + ` import foo from "foo"; foo({}); - `); - expect(isReactForwardRefCall(def, mockImporter)).toBe(true); + `, + mockImporter, + ); + expect(isReactForwardRefCall(def)).toBe(true); }); }); }); diff --git a/src/utils/__tests__/isRequiredPropType-test.ts b/src/utils/__tests__/isRequiredPropType-test.ts index 03c6c0ca61c..bc305584ffd 100644 --- a/src/utils/__tests__/isRequiredPropType-test.ts +++ b/src/utils/__tests__/isRequiredPropType-test.ts @@ -1,23 +1,27 @@ -import { expression } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; import isRequiredPropType from '../isRequiredPropType'; describe('isRequiredPropType', () => { it('considers isRequired', () => { - expect(isRequiredPropType(expression('foo.bar.isRequired'))).toEqual(true); - expect(isRequiredPropType(expression('foo.isRequired.bar'))).toEqual(true); - }); - - it('considers ["isRequired"]', () => { - expect(isRequiredPropType(expression('foo.bar["isRequired"]'))).toEqual( + expect(isRequiredPropType(parse.expression('foo.bar.isRequired'))).toEqual( true, ); - expect(isRequiredPropType(expression('foo["isRequired"].bar'))).toEqual( + expect(isRequiredPropType(parse.expression('foo.isRequired.bar'))).toEqual( true, ); }); + it('considers ["isRequired"]', () => { + expect( + isRequiredPropType(parse.expression('foo.bar["isRequired"]')), + ).toEqual(true); + expect( + isRequiredPropType(parse.expression('foo["isRequired"].bar')), + ).toEqual(true); + }); + it('ignores variables', () => { - expect(isRequiredPropType(expression('foo.bar[isRequired]'))).toEqual( + expect(isRequiredPropType(parse.expression('foo.bar[isRequired]'))).toEqual( false, ); }); diff --git a/src/utils/__tests__/isStatelessComponent-test.ts b/src/utils/__tests__/isStatelessComponent-test.ts index 308870b932f..66387a8d594 100644 --- a/src/utils/__tests__/isStatelessComponent-test.ts +++ b/src/utils/__tests__/isStatelessComponent-test.ts @@ -1,10 +1,6 @@ -import { - parse, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; -import { Importer } from '../../parse'; +import type { NodePath } from '@babel/traverse'; +import { parse, makeMockImporter, noopImporter } from '../../../tests/utils'; +import type { Importer } from '../../importer'; import isStatelessComponent from '../isStatelessComponent'; describe('isStatelessComponent', () => { @@ -19,22 +15,22 @@ describe('isStatelessComponent', () => { const componentStyle = { ArrowExpression: [ (name: string, expr: string): string => `var ${name} = () => (${expr});`, - ['declarations', 0, 'init'], + 'declarations.0.init', ], ArrowBlock: [ (name: string, expr: string): string => `var ${name} = () => { return (${expr}); };`, - ['declarations', 0, 'init'], + 'declarations.0.init', ], FunctionExpression: [ (name: string, expr: string): string => `var ${name} = function () { return (${expr}); }`, - ['declarations', 0, 'init'], + 'declarations.0.init', ], FunctionDeclaration: [ (name: string, expr: string): string => `function ${name} () { return (${expr}); }`, - [], + '', ], }; @@ -54,7 +50,7 @@ describe('isStatelessComponent', () => { var React = require('react'); ${componentFactory('Foo', expr)} `, - ['body', 1], + 'body.1', ], 'with Identifier reference': [ (expr: string, componentFactory: ComponentFactory): string => ` @@ -62,7 +58,7 @@ describe('isStatelessComponent', () => { var jsx = (${expr}); ${componentFactory('Foo', 'jsx')} `, - ['body', 2], + 'body.2', ], }; @@ -73,15 +69,15 @@ describe('isStatelessComponent', () => { ${componentStyle[name][0]('jsx', expr)} ${componentFactory('Foo', 'jsx()')} `, - ['body', 2], + 'body.2', ]; }); const negativeModifiers = { - 'nested ArrowExpression': (expr: string): string => `() => ${expr}`, - 'nested ArrowBlock': (expr: string): string => `() => { return ${expr} }`, - 'nested FunctionExpression': (expr: string): string => - `function () { return ${expr} }`, + //'nested ArrowExpression': (expr: string): string => `() => ${expr}`, + //'nested ArrowBlock': (expr: string): string => `() => { return ${expr} }`, + //'nested FunctionExpression': (expr: string): string => + // `function () { return ${expr} }`, }; Object.keys(cases).forEach(name => { @@ -103,11 +99,12 @@ describe('isStatelessComponent', () => { modifierFactory(returnExpr), componentFactory, ); - const def = parse(code).get( - ...caseSelector, - ...componentSelector, - ); - expect(isStatelessComponent(def, noopImporter)).toBe(true); + + const def: NodePath = parse(code).get( + `${caseSelector}.${componentSelector}`.replace(/\.$/, ''), + ) as NodePath; + + expect(isStatelessComponent(def)).toBe(true); }); }); @@ -119,11 +116,12 @@ describe('isStatelessComponent', () => { modifierFactory(returnExpr), componentFactory, ); - const def = parse(code).get( - ...caseSelector, - ...componentSelector, - ); - expect(isStatelessComponent(def, noopImporter)).toBe(false); + + const def: NodePath = parse(code).get( + `${caseSelector}.${componentSelector}`.replace(/\.$/, ''), + ) as NodePath; + + expect(isStatelessComponent(def)).toBe(false); }); }); }); @@ -139,11 +137,11 @@ describe('isStatelessComponent', () => { var AlphaBetters = require('react'); var Foo = () => AlphaBetters.createElement("div", null); `) - .get('body', 1) - .get('declarations', [0]) + .get('body')[1] + .get('declarations')[0] .get('init'); - expect(isStatelessComponent(def, noopImporter)).toBe(true); + expect(isStatelessComponent(def)).toBe(true); }); }); @@ -159,34 +157,34 @@ describe('isStatelessComponent', () => { world: function({ children }) { return React.cloneElement(children, {}); }, } `) - .get('body', 1) - .get('declarations', 0) + .get('body')[1] + .get('declarations')[0] .get('init'); - const bar = def.get('properties', 0); - const baz = def.get('properties', 1); - const hello = def.get('properties', 2); - const render = def.get('properties', 3); - const world = def.get('properties', 4); - - expect(isStatelessComponent(bar, noopImporter)).toBe(true); - expect(isStatelessComponent(baz, noopImporter)).toBe(true); - expect(isStatelessComponent(hello, noopImporter)).toBe(true); - expect(isStatelessComponent(render, noopImporter)).toBe(false); - expect(isStatelessComponent(world, noopImporter)).toBe(true); + const bar = def.get('properties')[0]; + const baz = def.get('properties')[1]; + const hello = def.get('properties')[2]; + const render = def.get('properties')[3]; + const world = def.get('properties')[4]; + + expect(isStatelessComponent(bar)).toBe(true); + expect(isStatelessComponent(baz)).toBe(true); + expect(isStatelessComponent(hello)).toBe(true); + expect(isStatelessComponent(render)).toBe(false); + expect(isStatelessComponent(world)).toBe(true); }); }); describe('is not overzealous', () => { it('does not accept declarations with a render method', () => { - const def = statement(` + const def = parse.statement(` class Foo { render() { return
; } } `); - expect(isStatelessComponent(def, noopImporter)).toBe(false); + expect(isStatelessComponent(def)).toBe(false); }); it('does not accept React.Component classes', () => { @@ -197,13 +195,13 @@ describe('isStatelessComponent', () => { return
; } } - `).get('body', 1); + `).get('body')[1]; - expect(isStatelessComponent(def, noopImporter)).toBe(false); + expect(isStatelessComponent(def)).toBe(false); }); it('does not accept React.createClass calls', () => { - const def = statement(` + const def = parse.statement(` React.createClass({ render() { return
; @@ -211,7 +209,7 @@ describe('isStatelessComponent', () => { }); `); - expect(isStatelessComponent(def, noopImporter)).toBe(false); + expect(isStatelessComponent(def)).toBe(false); }); }); @@ -222,20 +220,23 @@ describe('isStatelessComponent', () => { importer: Importer = noopImporter, ) { it(desc, () => { - const def = parse(src).get('body', 1); + const def = parse(src, importer).get('body')[1]; - expect(isStatelessComponent(def, importer)).toBe(true); + expect(isStatelessComponent(def)).toBe(true); }); } const mockImporter = makeMockImporter({ - bar: statement(` + bar: stmtLast => + stmtLast( + ` export default
; - `).get('declaration'), + `, + ).get('declaration'), }); it('does not see ifs as separate block', () => { - const def = statement(` + const def = parse.statement(` function Foo (props) { if (x) { return
; @@ -243,17 +244,17 @@ describe('isStatelessComponent', () => { } `); - expect(isStatelessComponent(def, noopImporter)).toBe(true); + expect(isStatelessComponent(def)).toBe(true); }); it('handles recursive function calls', () => { - const def = statement(` + const def = parse.statement(` function Foo (props) { return props && Foo(props); } `); - expect(isStatelessComponent(def, noopImporter)).toBe(false); + expect(isStatelessComponent(def)).toBe(false); }); test( diff --git a/src/utils/__tests__/isUnreachableFlowType-test.ts b/src/utils/__tests__/isUnreachableFlowType-test.ts index 6edd0df1e45..012c5f226b4 100644 --- a/src/utils/__tests__/isUnreachableFlowType-test.ts +++ b/src/utils/__tests__/isUnreachableFlowType-test.ts @@ -1,20 +1,22 @@ -import { expression, statement } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; import isUnreachableFlowType from '../isUnreachableFlowType'; describe('isUnreachableFlowType', () => { it('considers Identifier as unreachable', () => { - expect(isUnreachableFlowType(expression('foo'))).toBe(true); + expect(isUnreachableFlowType(parse.expression('foo'))).toBe(true); }); it('considers ImportDeclaration as unreachable', () => { - expect(isUnreachableFlowType(statement('import x from "";'))).toBe(true); + expect(isUnreachableFlowType(parse.statement('import x from "";'))).toBe( + true, + ); }); it('considers CallExpression as unreachable', () => { - expect(isUnreachableFlowType(expression('foo()'))).toBe(true); + expect(isUnreachableFlowType(parse.expression('foo()'))).toBe(true); }); it('considers VariableDeclaration not as unreachable', () => { - expect(isUnreachableFlowType(statement('const x = 1;'))).toBe(false); + expect(isUnreachableFlowType(parse.statement('const x = 1;'))).toBe(false); }); }); diff --git a/src/utils/__tests__/match-test.ts b/src/utils/__tests__/match-test.ts index d3e364d4be2..6c3fd1fcde2 100644 --- a/src/utils/__tests__/match-test.ts +++ b/src/utils/__tests__/match-test.ts @@ -1,8 +1,8 @@ -import { ASTNode } from 'ast-types'; +import type { Node } from '@babel/types'; import match from '../match'; describe('match', () => { - const toASTNode = (obj: Record): ASTNode => { + const toASTNode = (obj: Record): Node => { // eslint-disable-next-line @typescript-eslint/no-explicit-any return obj as any; }; diff --git a/src/utils/__tests__/normalizeClassDefinition-test.ts b/src/utils/__tests__/normalizeClassDefinition-test.ts index b62c96106e6..19a315845a3 100644 --- a/src/utils/__tests__/normalizeClassDefinition-test.ts +++ b/src/utils/__tests__/normalizeClassDefinition-test.ts @@ -1,100 +1,111 @@ -import { statement, parse } from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import type { + AssignmentExpression, + ClassDeclaration, + ClassExpression, + ClassProperty, + ExportDefaultDeclaration, + ExpressionStatement, + Identifier, + NumericLiteral, + VariableDeclaration, +} from '@babel/types'; +import { parse } from '../../../tests/utils'; import normalizeClassDefinition from '../normalizeClassDefinition'; describe('normalizeClassDefinition', () => { it('finds assignments to class declarations', () => { - const classDefinition = statement(` + const classDefinition = parse.statement(` class Foo {} Foo.propTypes = 42; `); normalizeClassDefinition(classDefinition); - const { - node: { - body: { - body: [classProperty], - }, - }, - } = classDefinition; + const classProperty = classDefinition.node.body.body[0] as ClassProperty; + expect(classProperty).toBeDefined(); - expect(classProperty.key.name).toBe('propTypes'); - expect(classProperty.value.value).toBe(42); + expect((classProperty.key as Identifier).name).toBe('propTypes'); + expect((classProperty.value as NumericLiteral).value).toBe(42); expect(classProperty.static).toBe(true); }); it('should not fail on classes without ids', () => { - const classDefinition = statement(` + const classDefinition = parse + .statement( + ` export default class extends React.Component { static propTypes = 42; } - `).get('declaration'); + `, + ) + .get('declaration') as NodePath; normalizeClassDefinition(classDefinition); - const { - node: { - body: { - body: [classProperty], - }, - }, - } = classDefinition; + const classProperty = classDefinition.node.body.body[0] as ClassProperty; + expect(classProperty).toBeDefined(); - expect(classProperty.key.name).toBe('propTypes'); - expect(classProperty.value.value).toBe(42); - expect(classProperty.static).toBe(true); }); - it('finds assignments to class expressions', () => { - let classDefinition = statement(` + it('finds assignments to class expressions with variable declaration', () => { + const classDefinition = parse + .statement( + ` var Foo = class {}; Foo.propTypes = 42; - `).get('declarations', 0, 'init'); + `, + ) + .get('declarations')[0] + .get('init') as NodePath; normalizeClassDefinition(classDefinition); - let { - node: { - body: { - body: [classProperty], - }, - }, - } = classDefinition; + const classProperty = classDefinition.node.body.body[0] as ClassProperty; + expect(classProperty).toBeDefined(); - expect(classProperty.key.name).toBe('propTypes'); - expect(classProperty.value.value).toBe(42); + expect((classProperty.key as Identifier).name).toBe('propTypes'); + expect((classProperty.value as NumericLiteral).value).toBe(42); expect(classProperty.static).toBe(true); + }); - classDefinition = parse(` - var Foo; - Foo = class {}; - Foo.propTypes = 42; - `).get('body', 1, 'expression', 'right'); + it('finds assignments to class expressions with assignment', () => { + const classDefinition = ( + parse + .statement( + `var Foo; + Foo = class {}; + Foo.propTypes = 42;`, + 1, + ) + .get('expression') as NodePath + ).get('right') as NodePath; normalizeClassDefinition(classDefinition); - ({ - node: { - body: { - body: [classProperty], - }, - }, - } = classDefinition); + const classProperty = classDefinition.node.body.body[0] as ClassProperty; + expect(classProperty).toBeDefined(); + expect((classProperty.key as Identifier).name).toBe('propTypes'); + expect((classProperty.value as NumericLiteral).value).toBe(42); + expect(classProperty.static).toBe(true); }); it('ignores assignments further up the tree', () => { - const classDefinition = statement(` + const classDefinition = parse + .statement( + ` var Foo = function() { (class {}); }; Foo.bar = 42; - `).get('declarations', 0, 'init', 'body', 'body', '0', 'expression'); + `, + ) + .get('declarations')[0] + .get('init') + .get('body') + .get('body')[0] + .get('expression'); normalizeClassDefinition(classDefinition); - const { - node: { - body: { - body: [classProperty], - }, - }, - } = classDefinition; + const classProperty = classDefinition.node.body.body[0] as ClassProperty; + expect(classProperty).not.toBeDefined(); }); }); diff --git a/src/utils/__tests__/printValue-test.ts b/src/utils/__tests__/printValue-test.ts index 37c353cf698..7767abd7707 100644 --- a/src/utils/__tests__/printValue-test.ts +++ b/src/utils/__tests__/printValue-test.ts @@ -1,10 +1,11 @@ -import { builders, NodePath } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { ExpressionStatement } from '@babel/types'; import { parse } from '../../../tests/utils'; import printValue from '../printValue'; describe('printValue', () => { - function pathFromSource(source) { - return parse(source).get('body', 0, 'expression'); + function pathFromSource(source: string): NodePath { + return parse.statement(source).get('expression'); } it('does not print leading comments', () => { @@ -14,32 +15,4 @@ describe('printValue', () => { it('does not print trailing comments', () => { expect(printValue(pathFromSource('bar//foo'))).toEqual('bar'); }); - - it('handles arbitrary generated nodes', () => { - expect( - printValue( - new NodePath( - builders.arrayExpression([ - builders.literal('bar'), - builders.literal('foo'), - builders.literal(1), - builders.literal(2), - builders.literal(3), - builders.literal(null), - builders.memberExpression( - builders.identifier('foo'), - builders.identifier('bar'), - ), - builders.jsxElement( - builders.jsxOpeningElement( - builders.jsxIdentifier('Baz'), - [], - true, - ), - ), - ]), - ), - ), - ).toEqual('["bar", "foo", 1, 2, 3, null, foo.bar, ]'); - }); }); diff --git a/src/utils/__tests__/resolveExportDeclaration-test.ts b/src/utils/__tests__/resolveExportDeclaration-test.ts index 34bc69a9c27..b7f2572236a 100644 --- a/src/utils/__tests__/resolveExportDeclaration-test.ts +++ b/src/utils/__tests__/resolveExportDeclaration-test.ts @@ -1,6 +1,10 @@ -import { statement, noopImporter } from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import type { + ExportDefaultDeclaration, + ExportNamedDeclaration, +} from '@babel/types'; +import { parse } from '../../../tests/utils'; import resolveExportDeclaration from '../resolveExportDeclaration'; -import { NodePath } from 'ast-types/lib/node-path'; jest.mock('../resolveToValue', () => { return (path: NodePath) => path; @@ -8,55 +12,63 @@ jest.mock('../resolveToValue', () => { describe('resolveExportDeclaration', () => { it('resolves default exports', () => { - const exp = statement('export default 42;'); - const resolved = resolveExportDeclaration(exp, noopImporter); + const exp = parse.statement('export default 42;'); + const resolved = resolveExportDeclaration(exp); expect(resolved).toEqual([exp.get('declaration')]); }); it('resolves named variable exports', () => { - const exp = statement('export var foo = 42, bar = 21;'); - const resolved = resolveExportDeclaration(exp, noopImporter); + const exp = parse.statement( + 'export var foo = 42, bar = 21;', + ); + const resolved = resolveExportDeclaration(exp); - const declarations = exp.get('declaration', 'declarations'); - expect(resolved).toEqual([declarations.get(0), declarations.get(1)]); + const declarations = exp.get('declaration').get('declarations'); + expect(resolved).toEqual([declarations[0], declarations[1]]); }); it('resolves named function exports', () => { - const exp = statement('export function foo(){}'); - const resolved = resolveExportDeclaration(exp, noopImporter); + const exp = parse.statement( + 'export function foo(){}', + ); + const resolved = resolveExportDeclaration(exp); expect(resolved).toEqual([exp.get('declaration')]); }); it('resolves named class exports', () => { - const exp = statement('export class Foo {}'); - const resolved = resolveExportDeclaration(exp, noopImporter); + const exp = parse.statement('export class Foo {}'); + const resolved = resolveExportDeclaration(exp); expect(resolved).toEqual([exp.get('declaration')]); }); it('resolves named exports', () => { - const exp = statement('export {foo, bar, baz}; var foo, bar, baz;'); - const resolved = resolveExportDeclaration(exp, noopImporter); + const exp = parse.statement( + 'export {foo, bar, baz}; var foo, bar, baz;', + ); + const resolved = resolveExportDeclaration(exp); const specifiers = exp.get('specifiers'); expect(resolved).toEqual([ - specifiers.get(0, 'local'), - specifiers.get(1, 'local'), - specifiers.get(2, 'local'), + specifiers[0].get('local'), + specifiers[1].get('local'), + specifiers[2].get('local'), ]); }); it('resolves named exports from', () => { - const exp = statement('export {foo, bar, baz} from "";'); - const resolved = resolveExportDeclaration(exp, noopImporter); + const exp = parse.statement( + 'export {foo, bar, baz} from "";', + ); + const resolved = resolveExportDeclaration(exp); const specifiers = exp.get('specifiers'); expect(resolved).toEqual([ - specifiers.get(0, 'local'), - specifiers.get(1, 'local'), - specifiers.get(2, 'local'), + specifiers[0].get('local'), + specifiers[1].get('local'), + specifiers[2].get('local'), ]); }); }); diff --git a/src/utils/__tests__/resolveGenericTypeAnnotations-test.ts b/src/utils/__tests__/resolveGenericTypeAnnotations-test.ts index 94fe5874455..a2510ce0a81 100644 --- a/src/utils/__tests__/resolveGenericTypeAnnotations-test.ts +++ b/src/utils/__tests__/resolveGenericTypeAnnotations-test.ts @@ -1,4 +1,4 @@ -import { statement, noopImporter } from '../../../tests/utils'; +import { parse } from '../../../tests/utils'; import resolveGenericTypeAnnotation from '../resolveGenericTypeAnnotation'; describe('resolveGenericTypeAnnotation', () => { @@ -9,14 +9,12 @@ describe('resolveGenericTypeAnnotation', () => { `; expect( resolveGenericTypeAnnotation( - statement(code).get( - 'declarations', - 0, - 'id', - 'typeAnnotation', - 'typeAnnotation', - ), - noopImporter, + parse + .statement(code) + .get('declarations')[0] + .get('id') + .get('typeAnnotation') + .get('typeAnnotation'), ), ).toMatchSnapshot(); }); diff --git a/src/utils/__tests__/resolveHOC-test.ts b/src/utils/__tests__/resolveHOC-test.ts index ed80b5c03d7..33167eeefde 100644 --- a/src/utils/__tests__/resolveHOC-test.ts +++ b/src/utils/__tests__/resolveHOC-test.ts @@ -1,133 +1,115 @@ -import { builders } from 'ast-types'; -import { - expressionLast, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { identifier, numericLiteral } from '@babel/types'; +import { makeMockImporter, parse } from '../../../tests/utils'; import resolveHOC from '../resolveHOC'; describe('resolveHOC', () => { const mockImporter = makeMockImporter({ - component: statement(` + component: stmtLast => + stmtLast(` export default Component; `).get('declaration'), - hoc: statement(` - export default hoc1(foo); + hoc: stmtLast => + stmtLast(` import foo from 'component'; + export default hoc1(foo); `).get('declaration'), }); it('resolves simple hoc', () => { - const path = expressionLast(['hoc(Component);'].join('\n')); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), - ); + const path = parse.expressionLast(['hoc(Component);'].join('\n')); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves simple hoc w/ multiple args', () => { - const path = expressionLast(['hoc1(arg1a, arg1b)(Component);'].join('\n')); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), + const path = parse.expressionLast( + ['hoc1(arg1a, arg1b)(Component);'].join('\n'), ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves nested hocs', () => { - const path = expressionLast( + const path = parse.expressionLast( `hoc2(arg2b, arg2b)( hoc1(arg1a, arg2a)(Component) );`, ); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), - ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves really nested hocs', () => { - const path = expressionLast( + const path = parse.expressionLast( `hoc3(arg3a, arg3b)( hoc2(arg2b, arg2b)( hoc1(arg1a, arg2a)(Component) ) );`, ); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), - ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC with additional params', () => { - const path = expressionLast(`hoc3(Component, {})`); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), - ); + const path = parse.expressionLast(`hoc3(Component, {})`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC as last element if first is literal', () => { - const path = expressionLast(`hoc3(41, Component)`); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), - ); + const path = parse.expressionLast(`hoc3(41, Component)`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC as last element if first is array', () => { - const path = expressionLast(`hoc3([], Component)`); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), - ); + const path = parse.expressionLast(`hoc3([], Component)`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC as last element if first is object', () => { - const path = expressionLast(`hoc3({}, Component)`); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), - ); + const path = parse.expressionLast(`hoc3({}, Component)`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC as last element if first is spread', () => { - const path = expressionLast(`hoc3(...params, Component)`); - expect(resolveHOC(path, noopImporter)).toEqualASTNode( - builders.identifier('Component'), - ); + const path = parse.expressionLast(`hoc3(...params, Component)`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves intermediate hocs', () => { - const path = expressionLast( + const path = parse.expressionLast( ['const Component = React.memo(42);', 'hoc()(Component);'].join('\n'), ); - expect(resolveHOC(path, noopImporter)).toEqualASTNode(builders.literal(42)); + expect(resolveHOC(path)).toEqualASTNode(numericLiteral(42)); }); it('can resolve an imported component passed to hoc', () => { - const path = expressionLast(` + const path = parse.expressionLast( + ` import foo from 'component'; hoc(foo); - `); - expect(resolveHOC(path, mockImporter)).toEqualASTNode( - builders.identifier('Component'), + `, + mockImporter, ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('can resolve an imported component passed to nested hoc', () => { - const path = expressionLast(` + const path = parse.expressionLast( + ` import foo from 'component'; hoc2(arg2b, arg2b)( hoc1(arg1a, arg2a)(foo) ); - `); - expect(resolveHOC(path, mockImporter)).toEqualASTNode( - builders.identifier('Component'), + `, + mockImporter, ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('can resolve an hocs inside imported component passed to hoc', () => { - const path = expressionLast(` - import bar from 'hoc'; - hoc(bar); - `); - expect(resolveHOC(path, mockImporter)).toEqualASTNode( - builders.identifier('Component'), + const path = parse.expressionLast( + `import bar from 'hoc'; + hoc(bar);`, + mockImporter, ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); }); diff --git a/src/utils/__tests__/resolveObjectKeysToArray-test.ts b/src/utils/__tests__/resolveObjectKeysToArray-test.ts index ff427d89a6d..5121bbdae82 100644 --- a/src/utils/__tests__/resolveObjectKeysToArray-test.ts +++ b/src/utils/__tests__/resolveObjectKeysToArray-test.ts @@ -1,14 +1,10 @@ -import { - statement, - noopImporter, - makeMockImporter, - expressionLast, -} from '../../../tests/utils'; +import { makeMockImporter, parse } from '../../../tests/utils'; import resolveObjectKeysToArray from '../resolveObjectKeysToArray'; describe('resolveObjectKeysToArray', () => { const mockImporter = makeMockImporter({ - foo: statement(` + foo: stmtLast => + stmtLast(` export default { bar: "bar", "foo": "foo", @@ -19,7 +15,8 @@ describe('resolveObjectKeysToArray', () => { }; `).get('declaration'), - bar: statement(` + bar: stmtLast => + stmtLast(` export default { bar: 'bar', }; @@ -27,31 +24,31 @@ describe('resolveObjectKeysToArray', () => { }); it('resolves Object.keys with identifiers', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { bar: 1, foo: 2 };', 'Object.keys(foo);'].join('\n'), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('resolves Object.keys with literals', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { "bar": 1, 5: 2 };', 'Object.keys(foo);'].join('\n'), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('resolves Object.keys with literals as computed key', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { ["bar"]: 1, [5]: 2};', 'Object.keys(foo);'].join('\n'), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('resolves Object.keys when using resolvable spread', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'var bar = { doo: 4 }', 'var foo = { boo: 1, foo: 2, ...bar };', @@ -59,32 +56,32 @@ describe('resolveObjectKeysToArray', () => { ].join('\n'), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('resolves Object.keys when using getters', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { boo: 1, foo: 2, get bar() {} };', 'Object.keys(foo);'].join( '\n', ), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('resolves Object.keys when using setters', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'var foo = { boo: 1, foo: 2, set bar(e) {} };', 'Object.keys(foo);', ].join('\n'), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('resolves Object.keys but ignores duplicates', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'var bar = { doo: 4, doo: 5 }', 'var foo = { boo: 1, foo: 2, doo: 1, ...bar };', @@ -92,51 +89,53 @@ describe('resolveObjectKeysToArray', () => { ].join('\n'), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('resolves Object.keys but ignores duplicates with getter and setter', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { get x() {}, set x(a) {} };', 'Object.keys(foo);'].join( '\n', ), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('does not resolve Object.keys when using unresolvable spread', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { bar: 1, foo: 2, ...bar };', 'Object.keys(foo);'].join('\n'), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toBeNull(); + expect(resolveObjectKeysToArray(path)).toBeNull(); }); it('does not resolve Object.keys when using computed keys', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { [bar]: 1, foo: 2 };', 'Object.keys(foo);'].join('\n'), ); - expect(resolveObjectKeysToArray(path, noopImporter)).toBeNull(); + expect(resolveObjectKeysToArray(path)).toBeNull(); }); it('can resolve imported objects passed to Object.keys', () => { - const path = expressionLast(` - import foo from 'foo'; - Object.keys(foo); - `); + const path = parse.expressionLast( + `import foo from 'foo'; + Object.keys(foo);`, + mockImporter, + ); - expect(resolveObjectKeysToArray(path, mockImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); it('can resolve spreads from imported objects', () => { - const path = expressionLast(` - import bar from 'bar'; - var abc = { foo: 'foo', baz: 'baz', ...bar }; - Object.keys(abc); - `); + const path = parse.expressionLast( + `import bar from 'bar'; + var abc = { foo: 'foo', baz: 'baz', ...bar }; + Object.keys(abc);`, + mockImporter, + ); - expect(resolveObjectKeysToArray(path, mockImporter)).toMatchSnapshot(); + expect(resolveObjectKeysToArray(path)).toMatchSnapshot(); }); }); diff --git a/src/utils/__tests__/resolveObjectValuesToArray-test.ts b/src/utils/__tests__/resolveObjectValuesToArray-test.ts index 07f8f91f1f5..db8f9d0764a 100644 --- a/src/utils/__tests__/resolveObjectValuesToArray-test.ts +++ b/src/utils/__tests__/resolveObjectValuesToArray-test.ts @@ -1,14 +1,10 @@ -import { - statement, - noopImporter, - makeMockImporter, - expressionLast, -} from '../../../tests/utils'; +import { makeMockImporter, parse } from '../../../tests/utils'; import resolveObjectValuesToArray from '../resolveObjectValuesToArray'; describe('resolveObjectValuesToArray', () => { const mockImporter = makeMockImporter({ - foo: statement(` + foo: stmtLast => + stmtLast(` export default { 1: "bar", 2: "foo", @@ -21,7 +17,8 @@ describe('resolveObjectValuesToArray', () => { }; `).get('declaration'), - bar: statement(` + bar: stmtLast => + stmtLast(` export default { bar: 'bar', }; @@ -29,49 +26,49 @@ describe('resolveObjectValuesToArray', () => { }); it('resolves Object.values with strings', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { 1: "bar", 2: "foo" };', 'Object.values(foo);'].join('\n'), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('resolves Object.values with numbers', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { 1: 0, 2: 5 };', 'Object.values(foo);'].join('\n'), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('resolves Object.values with undefined or null', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { 1: null, 2: undefined };', 'Object.values(foo);'].join( '\n', ), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('resolves Object.values with literals as computed key', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { ["bar"]: 1, [5]: 2};', 'Object.values(foo);'].join('\n'), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('does not resolve Object.values with complex computed key', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { [()=>{}]: 1, [5]: 2};', 'Object.values(foo);'].join('\n'), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toBeNull(); + expect(resolveObjectValuesToArray(path)).toBeNull(); }); it('resolves Object.values when using resolvable spread', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'var bar = { doo: 4 }', 'var foo = { boo: 1, foo: 2, ...bar };', @@ -79,43 +76,43 @@ describe('resolveObjectValuesToArray', () => { ].join('\n'), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('resolves Object.values when using getters', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'var foo = { boo: 1, foo: 2, get bar() {} };', 'Object.values(foo);', ].join('\n'), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('resolves Object.values when using setters', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'var foo = { boo: 1, foo: 2, set bar(e) {} };', 'Object.values(foo);', ].join('\n'), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('resolves Object.values when using methods', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { boo: 1, foo: 2, bar(e) {} };', 'Object.values(foo);'].join( '\n', ), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('resolves Object.values but ignores duplicates', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'var bar = { doo: 4, doo: 5 }', 'var foo = { boo: 1, foo: 2, doo: 1, ...bar };', @@ -123,45 +120,47 @@ describe('resolveObjectValuesToArray', () => { ].join('\n'), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('resolves Object.values but ignores duplicates with getter and setter', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { get x() {}, set x(a) {} };', 'Object.values(foo);'].join( '\n', ), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('does not resolve Object.values when using unresolvable spread', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { bar: 1, foo: 2, ...bar };', 'Object.values(foo);'].join( '\n', ), ); - expect(resolveObjectValuesToArray(path, noopImporter)).toBeNull(); + expect(resolveObjectValuesToArray(path)).toBeNull(); }); it('can resolve imported objects passed to Object.values', () => { - const path = expressionLast(` - import foo from 'foo'; - Object.values(foo); - `); + const path = parse.expressionLast( + `import foo from 'foo'; + Object.values(foo);`, + mockImporter, + ); - expect(resolveObjectValuesToArray(path, mockImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); it('can resolve spreads from imported objects', () => { - const path = expressionLast(` - import bar from 'bar'; - var abc = { foo: 'foo', baz: 'baz', ...bar }; - Object.values(abc); - `); + const path = parse.expressionLast( + `import bar from 'bar'; + var abc = { foo: 'foo', baz: 'baz', ...bar }; + Object.values(abc);`, + mockImporter, + ); - expect(resolveObjectValuesToArray(path, mockImporter)).toMatchSnapshot(); + expect(resolveObjectValuesToArray(path)).toMatchSnapshot(); }); }); diff --git a/src/utils/__tests__/resolveToModule-test.ts b/src/utils/__tests__/resolveToModule-test.ts index bfe336f1818..f4831718661 100644 --- a/src/utils/__tests__/resolveToModule-test.ts +++ b/src/utils/__tests__/resolveToModule-test.ts @@ -1,101 +1,101 @@ -import { - statement, - noopImporter, - makeMockImporter, - expressionLast, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import resolveToModule from '../resolveToModule'; describe('resolveToModule', () => { const mockImporter = makeMockImporter({ - Foo: statement(` - export default bar; - import bar from 'Bar'; - `).get('declaration'), + Foo: stmtLast => + stmtLast(` + import bar from 'Bar'; + export default bar; + `).get('declaration'), - Bar: statement(` - export default baz; - import baz from 'Baz'; - `).get('declaration'), + Bar: stmtLast => + stmtLast(` + import baz from 'Baz'; + export default baz; + `).get('declaration'), }); it('resolves identifiers', () => { - const path = expressionLast(` + const path = parse.expressionLast(` var foo = require("Foo"); foo; `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); }); it('resolves function calls', () => { - const path = expressionLast(` + const path = parse.expressionLast(` var foo = require("Foo"); foo(); `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); }); it('resolves member expressions', () => { - const path = expressionLast(` + const path = parse.expressionLast(` var foo = require("Foo"); foo.bar().baz; `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); }); it('understands destructuring', () => { - const path = expressionLast(` + const path = parse.expressionLast(` var {foo} = require("Foo"); foo; `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); }); describe('ES6 import declarations', () => { it('resolves ImportDefaultSpecifier', () => { - let path = expressionLast(` + let path = parse.expressionLast(` import foo from "Foo"; foo; `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); - path = expressionLast(` + path = parse.expressionLast(` import foo, {createElement} from "Foo"; foo; `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); }); it('resolves ImportSpecifier', () => { - const path = expressionLast(` + const path = parse.expressionLast(` import {foo, bar} from "Foo"; bar; `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); }); it('resolves aliased ImportSpecifier', () => { - const path = expressionLast(` + const path = parse.expressionLast(` import {foo, bar as baz} from "Foo"; baz; `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); }); it('resolves ImportNamespaceSpecifier', () => { - const path = expressionLast(` + const path = parse.expressionLast(` import * as foo from "Foo"; foo; `); - expect(resolveToModule(path, noopImporter)).toBe('Foo'); + expect(resolveToModule(path)).toBe('Foo'); }); it('can resolve imports until one not expanded', () => { - const path = expressionLast(` + const path = parse.expressionLast( + ` import foo from "Foo"; foo; - `); - expect(resolveToModule(path, mockImporter)).toBe('Baz'); + `, + mockImporter, + ); + expect(resolveToModule(path)).toBe('Baz'); }); }); }); diff --git a/src/utils/__tests__/resolveToValue-test.ts b/src/utils/__tests__/resolveToValue-test.ts index 6eeb1f29a11..cecbafec813 100644 --- a/src/utils/__tests__/resolveToValue-test.ts +++ b/src/utils/__tests__/resolveToValue-test.ts @@ -1,198 +1,213 @@ -import { builders } from 'ast-types'; -import { parse, noopImporter, expressionLast } from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import { + identifier, + memberExpression, + numericLiteral, + objectProperty, + restElement, +} from '@babel/types'; +import type { + AssignmentExpression, + CallExpression, + Identifier, +} from '@babel/types'; +import { parse, parseTypescript } from '../../../tests/utils'; import resolveToValue from '../resolveToValue'; describe('resolveToValue', () => { it('resolves simple variable declarations', () => { - const path = expressionLast(['var foo = 42;', 'foo;'].join('\n')); - expect(resolveToValue(path, noopImporter)).toEqualASTNode( - builders.literal(42), - ); + const path = parse.expressionLast(['var foo = 42;', 'foo;'].join('\n')); + expect(resolveToValue(path)).toEqualASTNode(numericLiteral(42)); }); it('resolves object destructuring', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var {foo: {bar: baz}} = bar;', 'baz;'].join('\n'), ); - // Resolves to identifier in destructuring - expect(resolveToValue(path, noopImporter)).toEqualASTNode( - builders.identifier('baz'), + const expected = objectProperty( + identifier('bar'), + identifier('baz'), + undefined, + undefined, + undefined, ); + expected.decorators = undefined; + // @ts-ignore BABEL types bug + expected.method = false; + // Resolves to identifier in destructuring + expect(resolveToValue(path)).toEqualASTNode(expected); }); - it('handles SpreadElements properly', () => { - const path = expressionLast( + it('handles RestElements properly', () => { + const path = parse.expressionLast( ['var {foo: {bar}, ...baz} = bar;', 'baz;'].join('\n'), ); - expect(resolveToValue(path, noopImporter)).toEqualASTNode(path); + expect(resolveToValue(path)).toEqualASTNode(restElement(identifier('baz'))); }); it('returns the original path if it cannot be resolved', () => { - const path = expressionLast(['function foo() {}', 'foo()'].join('\n')); + const path = parse.expressionLast( + ['function foo() {}', 'foo()'].join('\n'), + ); - expect(resolveToValue(path, noopImporter)).toEqualASTNode(path); + expect(resolveToValue(path)).toEqualASTNode(path); }); it('resolves variable declarators to their init value', () => { - const path = parse('var foo = 42;').get('body', 0, 'declarations', 0); + const path = parse.statement('var foo = 42;').get('declarations')[0]; - expect(resolveToValue(path, noopImporter)).toEqualASTNode( - builders.literal(42), - ); + expect(resolveToValue(path)).toEqualASTNode(numericLiteral(42)); }); it('resolves to class declarations', () => { - const path = expressionLast(` + const path = parse.expressionLast(` class Foo {} Foo; `); - expect(resolveToValue(path, noopImporter).node.type).toBe( - 'ClassDeclaration', - ); + expect(resolveToValue(path).node.type).toBe('ClassDeclaration'); }); it('resolves to class function declaration', () => { - const path = expressionLast(` + const path = parse.expressionLast(` function foo() {} foo; `); - expect(resolveToValue(path, noopImporter).node.type).toBe( - 'FunctionDeclaration', - ); + expect(resolveToValue(path).node.type).toBe('FunctionDeclaration'); }); describe('flow', () => { it('resolves type cast expressions', () => { - const path = expressionLast(` + const path = parse.expressionLast(` function foo() {} (foo: any); `); - expect(resolveToValue(path, noopImporter).node.type).toBe( - 'FunctionDeclaration', - ); + expect(resolveToValue(path).node.type).toBe('FunctionDeclaration'); }); }); describe('typescript', () => { - const parseTypescript = src => - expressionLast(src, { parserOptions: { plugins: ['typescript'] } }); - it('resolves type as expressions', () => { - const path = parseTypescript(` + const path = parseTypescript.expressionLast(` function foo() {} (foo as any); `); - expect(resolveToValue(path, noopImporter).node.type).toBe( - 'FunctionDeclaration', - ); + expect(resolveToValue(path).node.type).toBe('FunctionDeclaration'); }); it('resolves type assertions', () => { - const path = parseTypescript(` + const path = parseTypescript.expressionLast(` function foo() {} ( foo); `); - expect(resolveToValue(path, noopImporter).node.type).toBe( - 'FunctionDeclaration', + expect(resolveToValue(path).node.type).toBe('FunctionDeclaration'); + }); + + it('resolves type alias', () => { + const path = parseTypescript.statement( + `let action: Action; + type Action = {};`, ); + expect( + resolveToValue( + path.get( + 'declarations.0.id.typeAnnotation.typeAnnotation.typeName', + ) as NodePath, + ).node.type, + ).toBe('TSTypeAliasDeclaration'); }); }); describe('assignments', () => { it('resolves to assigned values', () => { - const path = expressionLast(['var foo;', 'foo = 42;', 'foo;'].join('\n')); - - expect(resolveToValue(path, noopImporter)).toEqualASTNode( - builders.literal(42), + const path = parse.expressionLast( + ['var foo;', 'foo = 42;', 'foo;'].join('\n'), ); + + expect(resolveToValue(path)).toEqualASTNode(numericLiteral(42)); }); it('resolves to other assigned value if ref is in an assignment lhs', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo;', 'foo = 42;', 'foo = wrap(foo);'].join('\n'), ); - expect(resolveToValue(path.get('left'), noopImporter)).toEqualASTNode( - builders.literal(42), + expect(resolveToValue(path.get('left'))).toEqualASTNode( + numericLiteral(42), ); }); it('resolves to other assigned value if ref is in an assignment rhs', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo;', 'foo = 42;', 'foo = wrap(foo);'].join('\n'), ); expect( - resolveToValue(path.get('right', 'arguments', 0), noopImporter), - ).toEqualASTNode(builders.literal(42)); + resolveToValue( + (path.get('right') as NodePath).get('arguments')[0], + ), + ).toEqualASTNode(numericLiteral(42)); }); }); describe('ImportDeclaration', () => { it('resolves default import references to the import declaration', () => { - const path = expressionLast(['import foo from "Foo"', 'foo;'].join('\n')); - const value = resolveToValue(path, noopImporter); + const path = parse.expressionLast( + ['import foo from "Foo"', 'foo;'].join('\n'), + ); + const value = resolveToValue(path); - expect(Array.isArray(value.value)).toBe(false); expect(value.node.type).toBe('ImportDeclaration'); }); it('resolves named import references to the import declaration', () => { - const path = expressionLast( + const path = parse.expressionLast( ['import {foo} from "Foo"', 'foo;'].join('\n'), ); - const value = resolveToValue(path, noopImporter); + const value = resolveToValue(path); - expect(Array.isArray(value.value)).toBe(false); expect(value.node.type).toBe('ImportDeclaration'); }); it('resolves aliased import references to the import declaration', () => { - const path = expressionLast( + const path = parse.expressionLast( ['import {foo as bar} from "Foo"', 'bar;'].join('\n'), ); - const value = resolveToValue(path, noopImporter); + const value = resolveToValue(path); - expect(Array.isArray(value.value)).toBe(false); expect(value.node.type).toBe('ImportDeclaration'); }); it('resolves namespace import references to the import declaration', () => { - const path = expressionLast( + const path = parse.expressionLast( ['import * as bar from "Foo"', 'bar;'].join('\n'), ); - const value = resolveToValue(path, noopImporter); + const value = resolveToValue(path); - expect(Array.isArray(value.value)).toBe(false); expect(value.node.type).toBe('ImportDeclaration'); }); }); describe('MemberExpression', () => { it("resolves a MemberExpression to it's init value", () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = { bar: 1 };', 'foo.bar;'].join('\n'), ); - expect(resolveToValue(path, noopImporter)).toEqualASTNode( - builders.literal(1), - ); + expect(resolveToValue(path)).toEqualASTNode(numericLiteral(1)); }); it('resolves a MemberExpression in the scope chain', () => { - const path = expressionLast( + const path = parse.expressionLast( ['var foo = 1;', 'var bar = { baz: foo };', 'bar.baz;'].join('\n'), ); - expect(resolveToValue(path, noopImporter)).toEqualASTNode( - builders.literal(1), - ); + expect(resolveToValue(path)).toEqualASTNode(numericLiteral(1)); }); it('resolves a nested MemberExpression in the scope chain', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'var foo = { bar: 1 };', 'var bar = { baz: foo.bar };', @@ -200,13 +215,11 @@ describe('resolveToValue', () => { ].join('\n'), ); - expect(resolveToValue(path, noopImporter)).toEqualASTNode( - builders.literal(1), - ); + expect(resolveToValue(path)).toEqualASTNode(numericLiteral(1)); }); it('returns the last resolvable MemberExpression', () => { - const path = expressionLast( + const path = parse.expressionLast( [ 'import foo from "bar";', 'var bar = { baz: foo.bar };', @@ -214,20 +227,19 @@ describe('resolveToValue', () => { ].join('\n'), ); - expect(resolveToValue(path, noopImporter)).toEqualASTNode( - builders.memberExpression( - builders.identifier('foo'), - builders.identifier('bar'), - ), + expect(resolveToValue(path)).toEqualASTNode( + memberExpression(identifier('foo'), identifier('bar'), false, false), ); }); it('returns the path itself if it can not resolve it any further', () => { - const path = expressionLast( - ['var foo = {};', 'foo.bar = 1;', 'foo.bar;'].join('\n'), + const path = parse.expressionLast( + `var foo = {}; + foo.bar = 1; + foo.bar;`, ); - expect(resolveToValue(path, noopImporter)).toEqualASTNode(path); + expect(resolveToValue(path)).toEqualASTNode(path); }); }); }); diff --git a/src/utils/__tests__/setPropDescription-test.ts b/src/utils/__tests__/setPropDescription-test.ts index 7fdb8d0d1ee..60a334eb421 100644 --- a/src/utils/__tests__/setPropDescription-test.ts +++ b/src/utils/__tests__/setPropDescription-test.ts @@ -1,12 +1,8 @@ -import { - expression, - statement, - noopImporter, - makeMockImporter, -} from '../../../tests/utils'; +import { parse, makeMockImporter } from '../../../tests/utils'; import setPropDescription from '../setPropDescription'; import Documentation from '../../Documentation'; import type { default as DocumentationMock } from '../../__mocks__/Documentation'; +import type { ExpressionStatement } from '@babel/types'; jest.mock('../../Documentation'); @@ -19,13 +15,13 @@ describe('setPropDescription', () => { }); const mockImporter = makeMockImporter({ - foo: statement(`export default 'foo';`).get('declaration'), + foo: stmtLast => stmtLast(`export default 'foo';`).get('declaration'), }); function getDescriptors(src: string, documentation = defaultDocumentation) { - const node = expression(src).get('properties', 0); + const node = parse.expression(src).get('properties')[0]; - setPropDescription(documentation, node, noopImporter); + setPropDescription(documentation, node); return documentation.descriptors; } @@ -87,9 +83,12 @@ describe('setPropDescription', () => { }); import a from 'foo'; `; - const node = statement(src).get('expression', 'properties', 0); + const node = parse + .statement(src, mockImporter) + .get('expression') + .get('properties')[0]; - setPropDescription(defaultDocumentation, node, mockImporter); + setPropDescription(defaultDocumentation, node); expect(defaultDocumentation.descriptors).toEqual({ foo: { diff --git a/src/utils/docblock.ts b/src/utils/docblock.ts index 662e35669dc..5fe14f8e745 100644 --- a/src/utils/docblock.ts +++ b/src/utils/docblock.ts @@ -2,8 +2,8 @@ * Helper functions to work with docblock comments. */ -import { CommentKind } from 'ast-types/gen/kinds'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { CommentBlock, CommentLine } from '@babel/types'; const DOCLET_PATTERN = /^@(\w+)(?:$|\s((?:[^](?!^@\w))*))/gim; @@ -20,7 +20,7 @@ const DOCBLOCK_HEADER = /^\*\s/; * exists. */ export function getDocblock(path: NodePath, trailing = false): string | null { - let comments: CommentKind[] = []; + let comments: Array = []; if (trailing && path.node.trailingComments) { comments = path.node.trailingComments.filter( comment => @@ -31,13 +31,6 @@ export function getDocblock(path: NodePath, trailing = false): string | null { comment => comment.type === 'CommentBlock' && DOCBLOCK_HEADER.test(comment.value), ); - } else if (path.node.comments) { - comments = path.node.comments.filter( - comment => - comment.leading && - comment.type === 'CommentBlock' && - DOCBLOCK_HEADER.test(comment.value), - ); } if (comments.length > 0) { @@ -50,11 +43,11 @@ export function getDocblock(path: NodePath, trailing = false): string | null { * Given a string, this functions returns an object with doclet names as keys * and their "content" as values. */ -export function getDoclets(str: string): Record { +export function getDoclets(str: string): Record { const doclets = Object.create(null); - let match = DOCLET_PATTERN.exec(str); + let match: RegExpExecArray | null; - for (; match; match = DOCLET_PATTERN.exec(str)) { + while ((match = DOCLET_PATTERN.exec(str))) { doclets[match[1]] = match[2] || true; } diff --git a/src/utils/expressionTo.ts b/src/utils/expressionTo.ts index 24d0069e9f9..92b15e27373 100644 --- a/src/utils/expressionTo.ts +++ b/src/utils/expressionTo.ts @@ -1,77 +1,78 @@ /*eslint no-loop-func: 0, no-use-before-define: 0*/ -import { namedTypes as t } from 'ast-types'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { Node, NodePath } from '@babel/traverse'; /** * Splits a MemberExpression or CallExpression into parts. * E.g. foo.bar.baz becomes ['foo', 'bar', 'baz'] */ -function toArray(path: NodePath, importer: Importer): string[] { +function toArray(path: NodePath): string[] { const parts = [path]; let result: string[] = []; while (parts.length > 0) { path = parts.shift() as NodePath; - const node = path.node; - if (t.CallExpression.check(node)) { + if (path.isCallExpression()) { parts.push(path.get('callee')); continue; - } else if (t.MemberExpression.check(node)) { + } else if (path.isMemberExpression()) { parts.push(path.get('object')); - if (node.computed) { - const resolvedPath = resolveToValue(path.get('property'), importer); + const property = path.get('property'); + if (path.node.computed) { + const resolvedPath = resolveToValue(property); if (resolvedPath !== undefined) { - result = result.concat(toArray(resolvedPath, importer)); + result = result.concat(toArray(resolvedPath)); } else { result.push(''); } - } else { - // @ts-ignore - result.push(node.property.name); + } else if (property.isIdentifier()) { + result.push(property.node.name); + } else if (property.isPrivateName()) { + // new test + result.push(`#${property.get('id').node.name}`); } continue; - } else if (t.Identifier.check(node)) { - result.push(node.name); + } else if (path.isIdentifier()) { + result.push(path.node.name); continue; - } else if (t.TSAsExpression.check(node)) { - if (t.Identifier.check(node.expression)) { - result.push(node.expression.name); + } else if (path.isTSAsExpression()) { + const expression = path.get('expression'); + if (expression.isIdentifier()) { + result.push(expression.node.name); } continue; - } else if (t.Literal.check(node)) { - // @ts-ignore - result.push(node.raw); + } else if (path.isLiteral() && path.node.extra?.raw) { + result.push(path.node.extra.raw as string); continue; - } else if (t.FunctionExpression.check(node)) { - result.push(''); - continue; - } else if (t.ThisExpression.check(node)) { + } else if (path.isThisExpression()) { result.push('this'); continue; - } else if (t.ObjectExpression.check(node)) { + } else if (path.isObjectExpression()) { const properties = path.get('properties').map(function (property) { - if (t.SpreadElement.check(property.node)) { - return `...${toString(property.get('argument'), importer)}`; - } else { + if (property.isSpreadElement()) { + return `...${toString(property.get('argument'))}`; + } else if (property.isObjectProperty()) { return ( - toString(property.get('key'), importer) + + toString(property.get('key')) + ': ' + - toString(property.get('value'), importer) + toString(property.get('value')) ); + } else if (property.isObjectMethod()) { + return toString(property.get('key')) + ': '; + } else { + throw new Error('Unrecognized object property type'); } }); result.push('{' + properties.join(', ') + '}'); continue; - } else if (t.ArrayExpression.check(node)) { + } else if (path.isArrayExpression()) { result.push( '[' + path .get('elements') .map(function (el) { - return toString(el, importer); + return toString(el); }) .join(', ') + ']', @@ -86,8 +87,8 @@ function toArray(path: NodePath, importer: Importer): string[] { /** * Creates a string representation of a member expression. */ -function toString(path: NodePath, importer: Importer): string { - return toArray(path, importer).join('.'); +function toString(path: NodePath): string { + return toArray(path).join('.'); } export { toString as String, toArray as Array }; diff --git a/src/utils/flowUtilityTypes.ts b/src/utils/flowUtilityTypes.ts index 08758640872..09b8d16d601 100644 --- a/src/utils/flowUtilityTypes.ts +++ b/src/utils/flowUtilityTypes.ts @@ -1,17 +1,22 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; - -const supportedUtilityTypes = new Set(['$Exact', '$ReadOnly']); +import type { NodePath } from '@babel/traverse'; +import type { GenericTypeAnnotation } from '@babel/types'; /** * See `supportedUtilityTypes` for which types are supported and * https://flow.org/en/docs/types/utilities/ for which types are available. */ -export function isSupportedUtilityType(path: NodePath): boolean { - if (t.GenericTypeAnnotation.check(path.node)) { +export function isSupportedUtilityType( + path: NodePath, +): path is NodePath { + if (path.isGenericTypeAnnotation()) { const idPath = path.get('id'); - return !!idPath && supportedUtilityTypes.has(idPath.node.name); + if (idPath.isIdentifier()) { + const name = idPath.node.name; + + return name === '$Exact' || name === '$ReadOnly'; + } } + return false; } @@ -22,7 +27,7 @@ export function isSupportedUtilityType(path: NodePath): boolean { */ export function unwrapUtilityType(path: NodePath): NodePath { while (isSupportedUtilityType(path)) { - path = path.get('typeParameters', 'params', 0); + path = path.get('typeParameters').get('params')[0]; } return path; diff --git a/src/utils/getClassMemberValuePath.ts b/src/utils/getClassMemberValuePath.ts index 56677def0e1..be5c471e0a6 100644 --- a/src/utils/getClassMemberValuePath.ts +++ b/src/utils/getClassMemberValuePath.ts @@ -1,22 +1,44 @@ -import type { NodePath } from 'ast-types/lib/node-path'; -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { + ClassDeclaration, + ClassExpression, + ClassMethod, + ClassProperty, + Expression, +} from '@babel/types'; import getNameOrValue from './getNameOrValue'; export default function getClassMemberValuePath( - classDefinition: NodePath, + classDefinition: NodePath, memberName: string, -): NodePath | null { +): NodePath | null { // Fortunately it seems like that all members of a class body, be it - // ClassProperty or MethodDefinition, have the same structure: They have a + // ClassProperty or ClassMethod, have the same structure: They have a // "key" and a "value" - return classDefinition - .get('body', 'body') - .filter( - (memberPath: NodePath) => - (!memberPath.node.computed || t.Literal.check(memberPath.node.key)) && - !t.PrivateName.check(memberPath.node.key) && - getNameOrValue(memberPath.get('key')) === memberName && - memberPath.node.kind !== 'set', - ) - .map((memberPath: NodePath) => memberPath.get('value'))[0]; + return ( + classDefinition + .get('body') + .get('body') + .filter(memberPath => { + if ( + (memberPath.isClassMethod() && memberPath.node.kind !== 'set') || + memberPath.isClassProperty() + ) { + const key = (memberPath as NodePath).get( + 'key', + ); + return ( + (!memberPath.node.computed || key.isLiteral()) && + getNameOrValue(key) === memberName + ); + } + + return false; + }) //TODO ClassMethod does not have value + .map(memberPath => + memberPath.isClassMethod() + ? memberPath + : (memberPath.get('value') as NodePath), + )[0] || null + ); } diff --git a/src/utils/getFlowType.ts b/src/utils/getFlowType.ts index 4c8aea3c986..ab6ca539165 100644 --- a/src/utils/getFlowType.ts +++ b/src/utils/getFlowType.ts @@ -1,11 +1,10 @@ -import { namedTypes as t } from 'ast-types'; import getPropertyName from './getPropertyName'; import printValue from './printValue'; import getTypeAnnotation from '../utils/getTypeAnnotation'; import resolveToValue from '../utils/resolveToValue'; import { resolveObjectToNameArray } from '../utils/resolveObjectKeysToArray'; -import getTypeParameters, { TypeParameters } from '../utils/getTypeParameters'; -import type { Importer } from '../parse'; +import type { TypeParameters } from '../utils/getTypeParameters'; +import getTypeParameters from '../utils/getTypeParameters'; import type { ElementsType, FunctionSignatureType, @@ -13,7 +12,25 @@ import type { SimpleType, TypeDescriptor, } from '../Documentation'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { + ArrayTypeAnnotation, + BooleanLiteralTypeAnnotation, + FlowType, + FunctionTypeAnnotation, + GenericTypeAnnotation, + Identifier, + InterfaceDeclaration, + IntersectionTypeAnnotation, + NullableTypeAnnotation, + NumberLiteralTypeAnnotation, + ObjectTypeAnnotation, + StringLiteralTypeAnnotation, + TupleTypeAnnotation, + TypeofTypeAnnotation, + TypeParameterDeclaration, + UnionTypeAnnotation, +} from '@babel/types'; const flowTypes = { AnyTypeAnnotation: 'any', @@ -46,34 +63,32 @@ const namedTypes = { }; function getFlowTypeWithRequirements( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor { - const type = getFlowTypeWithResolvedTypes(path, typeParams, importer); + const type = getFlowTypeWithResolvedTypes(path, typeParams); - type.required = !path.parentPath.node.optional; + type.required = + 'optional' in path.parentPath.node ? !path.parentPath.node.optional : true; return type; } function handleKeysHelper( - path: NodePath, - importer: Importer, + path: NodePath, ): ElementsType | null { - let value = path.get('typeParameters', 'params', 0); - if (t.TypeofTypeAnnotation.check(value.node)) { - value = value.get('argument', 'id'); - } else if (!t.ObjectTypeAnnotation.check(value.node)) { + let value = path.get('typeParameters').get('params')[0]; + if (value.isTypeofTypeAnnotation()) { + value = value.get('argument').get('id'); + } else if (!value.isObjectTypeAnnotation()) { value = value.get('id'); } - const resolvedPath = resolveToValue(value, importer); + const resolvedPath = resolveToValue(value); if ( resolvedPath && - (t.ObjectExpression.check(resolvedPath.node) || - t.ObjectTypeAnnotation.check(resolvedPath.node)) + (resolvedPath.isObjectExpression() || resolvedPath.isObjectTypeAnnotation()) ) { - const keys = resolveObjectToNameArray(resolvedPath, importer, true); + const keys = resolveObjectToNameArray(resolvedPath, true); if (keys) { return { @@ -88,87 +103,85 @@ function handleKeysHelper( } function handleArrayTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ElementsType { return { name: 'Array', elements: [ - getFlowTypeWithResolvedTypes( - path.get('elementType'), - typeParams, - importer, - ), + getFlowTypeWithResolvedTypes(path.get('elementType'), typeParams), ], raw: printValue(path), }; } function handleGenericTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor | null { - if (path.node.id.name === '$Keys' && path.node.typeParameters) { - return handleKeysHelper(path, importer); + const id = path.get('id'); + const typeParameters = path.get('typeParameters'); + if ( + id.isIdentifier() && + id.node.name === '$Keys' && + typeParameters.hasNode() + ) { + return handleKeysHelper(path); } let type: TypeDescriptor; - if (t.QualifiedTypeIdentifier.check(path.node.id)) { - const id = path.get('id'); - - if (id.node.qualification.name === 'React') { + if (id.isQualifiedTypeIdentifier()) { + const qualification = id.get('qualification'); + if (qualification.isIdentifier() && qualification.node.name === 'React') { type = { - name: `${id.node.qualification.name}${id.node.id.name}`, + name: `${qualification.node.name}${id.node.id.name}`, raw: printValue(id), }; } else { type = { name: printValue(id).replace(/<.*>$/, '') }; } } else { - type = { name: path.node.id.name }; + type = { name: (id as NodePath).node.name }; } const resolvedPath = - (typeParams && typeParams[type.name]) || - resolveToValue(path.get('id'), importer); + (typeParams && typeParams[type.name]) || resolveToValue(path.get('id')); - if (path.node.typeParameters && resolvedPath.node.typeParameters) { + if (typeParameters.hasNode() && resolvedPath.has('typeParameters')) { typeParams = getTypeParameters( - resolvedPath.get('typeParameters'), - path.get('typeParameters'), + resolvedPath.get('typeParameters') as NodePath, + typeParameters, typeParams, - importer, ); } if ( typeParams && typeParams[type.name] && - // @ts-ignore - typeParams[type.name].value.type === t.GenericTypeAnnotation.name + typeParams[type.name].isGenericTypeAnnotation() ) { return type; } if (typeParams && typeParams[type.name]) { - type = getFlowTypeWithResolvedTypes(resolvedPath, typeParams, importer); + type = getFlowTypeWithResolvedTypes( + resolvedPath as NodePath, + typeParams, + ); } - if (resolvedPath && resolvedPath.node.right) { + if (resolvedPath && resolvedPath.has('right')) { type = getFlowTypeWithResolvedTypes( - resolvedPath.get('right'), + resolvedPath.get('right') as NodePath, typeParams, - importer, ); - } else if (path.node.typeParameters) { - const params = path.get('typeParameters').get('params'); + } else if (typeParameters.hasNode()) { + const params = typeParameters.get('params'); type = { ...(type as SimpleType), - elements: params.map((param: NodePath) => - getFlowTypeWithResolvedTypes(param, typeParams, importer), + elements: params.map(param => + getFlowTypeWithResolvedTypes(param, typeParams), ), raw: printValue(path), }; @@ -178,9 +191,8 @@ function handleGenericTypeAnnotation( } function handleObjectTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor { const type: ObjectSignatureType = { name: 'signature', @@ -189,50 +201,49 @@ function handleObjectTypeAnnotation( signature: { properties: [] }, }; - path.get('callProperties').each(param => { - type.signature.constructor = getFlowTypeWithResolvedTypes( - param.get('value'), - typeParams, - importer, - ); - }); - - path.get('indexers').each(param => { - type.signature.properties.push({ - key: getFlowTypeWithResolvedTypes(param.get('key'), typeParams, importer), - value: getFlowTypeWithRequirements( + const callProperties = path.get('callProperties'); + if (Array.isArray(callProperties)) { + callProperties.forEach(param => { + type.signature.constructor = getFlowTypeWithResolvedTypes( param.get('value'), typeParams, - importer, - ), + ); }); - }); + } + + const indexers = path.get('indexers'); + if (Array.isArray(indexers)) { + indexers.forEach(param => { + type.signature.properties.push({ + key: getFlowTypeWithResolvedTypes(param.get('key'), typeParams), + value: getFlowTypeWithRequirements(param.get('value'), typeParams), + }); + }); + } - path.get('properties').each(param => { - if (t.ObjectTypeProperty.check(param.node)) { + path.get('properties').forEach(param => { + if (param.isObjectTypeProperty()) { type.signature.properties.push({ // For ObjectTypeProperties `getPropertyName` always returns string - key: getPropertyName(param, importer) as string, - value: getFlowTypeWithRequirements( - param.get('value'), - typeParams, - importer, - ), + key: getPropertyName(param) as string, + value: getFlowTypeWithRequirements(param.get('value'), typeParams), }); - } else if (t.ObjectTypeSpreadProperty.check(param.node)) { - let spreadObject = resolveToValue(param.get('argument'), importer); - if (t.GenericTypeAnnotation.check(spreadObject.node)) { - const typeAlias = resolveToValue(spreadObject.get('id'), importer); - if (t.ObjectTypeAnnotation.check(typeAlias.get('right').node)) { - spreadObject = resolveToValue(typeAlias.get('right'), importer); + } else if (param.isObjectTypeSpreadProperty()) { + let spreadObject = resolveToValue(param.get('argument')); + if (spreadObject.isGenericTypeAnnotation()) { + const typeAlias = resolveToValue(spreadObject.get('id')); + if ( + typeAlias.isTypeAlias() && + typeAlias.get('right').isObjectTypeAnnotation() + ) { + spreadObject = resolveToValue(typeAlias.get('right')); } } - if (t.ObjectTypeAnnotation.check(spreadObject.node)) { + if (spreadObject.isObjectTypeAnnotation()) { const props = handleObjectTypeAnnotation( spreadObject, typeParams, - importer, ) as ObjectSignatureType; type.signature.properties.push(...props.signature.properties); } @@ -242,7 +253,9 @@ function handleObjectTypeAnnotation( return type; } -function handleInterfaceDeclaration(path: NodePath): SimpleType { +function handleInterfaceDeclaration( + path: NodePath, +): SimpleType { // Interfaces are handled like references which would be documented separately, // rather than inlined like type aliases. return { @@ -251,60 +264,48 @@ function handleInterfaceDeclaration(path: NodePath): SimpleType { } function handleUnionTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ElementsType { return { name: 'union', raw: printValue(path), elements: path .get('types') - .map(subType => - getFlowTypeWithResolvedTypes(subType, typeParams, importer), - ), + .map(subType => getFlowTypeWithResolvedTypes(subType, typeParams)), }; } function handleIntersectionTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ElementsType { return { name: 'intersection', raw: printValue(path), elements: path .get('types') - .map(subType => - getFlowTypeWithResolvedTypes(subType, typeParams, importer), - ), + .map(subType => getFlowTypeWithResolvedTypes(subType, typeParams)), }; } function handleNullableTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor | null { const typeAnnotation = getTypeAnnotation(path); if (!typeAnnotation) return null; - const type = getFlowTypeWithResolvedTypes( - typeAnnotation, - typeParams, - importer, - ); + const type = getFlowTypeWithResolvedTypes(typeAnnotation, typeParams); type.nullable = true; return type; } function handleFunctionTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): FunctionSignatureType { const type: FunctionSignatureType = { name: 'signature', @@ -312,33 +313,29 @@ function handleFunctionTypeAnnotation( raw: printValue(path), signature: { arguments: [], - return: getFlowTypeWithResolvedTypes( - path.get('returnType'), - typeParams, - importer, - ), + return: getFlowTypeWithResolvedTypes(path.get('returnType'), typeParams), }, }; - path.get('params').each(param => { + path.get('params').forEach(param => { const typeAnnotation = getTypeAnnotation(param); type.signature.arguments.push({ name: param.node.name ? param.node.name.name : '', type: typeAnnotation - ? getFlowTypeWithResolvedTypes(typeAnnotation, typeParams, importer) + ? getFlowTypeWithResolvedTypes(typeAnnotation, typeParams) : undefined, }); }); - if (path.node.rest) { - const rest = path.get('rest'); + const rest = path.get('rest'); + if (rest.hasNode()) { const typeAnnotation = getTypeAnnotation(rest); type.signature.arguments.push({ name: rest.node.name ? rest.node.name.name : '', type: typeAnnotation - ? getFlowTypeWithResolvedTypes(typeAnnotation, typeParams, importer) + ? getFlowTypeWithResolvedTypes(typeAnnotation, typeParams) : undefined, rest: true, }); @@ -348,9 +345,8 @@ function handleFunctionTypeAnnotation( } function handleTupleTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ElementsType { const type: ElementsType = { name: 'tuple', @@ -358,59 +354,64 @@ function handleTupleTypeAnnotation( elements: [], }; - path.get('types').each(param => { - type.elements.push( - getFlowTypeWithResolvedTypes(param, typeParams, importer), - ); + path.get('types').forEach(param => { + type.elements.push(getFlowTypeWithResolvedTypes(param, typeParams)); }); return type; } function handleTypeofTypeAnnotation( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor { - return getFlowTypeWithResolvedTypes( - path.get('argument'), - typeParams, - importer, - ); + return getFlowTypeWithResolvedTypes(path.get('argument'), typeParams); } let visitedTypes = {}; function getFlowTypeWithResolvedTypes( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor { - const node = path.node; let type: TypeDescriptor | null = null; + const parent = path.parentPath; - const isTypeAlias = t.TypeAlias.check(path.parentPath.node); + const isTypeAlias = parent.isTypeAlias(); // When we see a typealias mark it as visited so that the next // call of this function does not run into an endless loop if (isTypeAlias) { - if (visitedTypes[path.parentPath.node.id.name] === true) { + if (visitedTypes[parent.node.id.name] === true) { // if we are currently visiting this node then just return the name // as we are starting to endless loop - return { name: path.parentPath.node.id.name }; - } else if (typeof visitedTypes[path.parentPath.node.id.name] === 'object') { + return { name: parent.node.id.name }; + } else if (typeof visitedTypes[parent.node.id.name] === 'object') { // if we already resolved the type simple return it - return visitedTypes[path.parentPath.node.id.name]; + return visitedTypes[parent.node.id.name]; } // mark the type as visited - visitedTypes[path.parentPath.node.id.name] = true; + visitedTypes[parent.node.id.name] = true; } - if (node.type in flowTypes) { - type = { name: flowTypes[node.type] }; - } else if (node.type in flowLiteralTypes) { - type = { name: 'literal', value: node.raw || `${node.value}` }; - } else if (node.type in namedTypes) { - type = namedTypes[node.type](path, typeParams, importer); + if (path.node.type in flowTypes) { + type = { name: flowTypes[path.node.type] }; + } else if (path.node.type in flowLiteralTypes) { + type = { + name: 'literal', + value: + (path.node.extra?.raw as string) || + `${ + ( + path as NodePath< + | BooleanLiteralTypeAnnotation + | NumberLiteralTypeAnnotation + | StringLiteralTypeAnnotation + > + ).node.value + }`, + }; + } else if (path.node.type in namedTypes) { + type = namedTypes[path.node.type](path, typeParams); } if (!type) { @@ -419,7 +420,7 @@ function getFlowTypeWithResolvedTypes( if (isTypeAlias) { // mark the type as unvisited so that further calls can resolve the type again - visitedTypes[path.parentPath.node.id.name] = type; + visitedTypes[parent.node.id.name] = type; } return type; @@ -433,15 +434,14 @@ function getFlowTypeWithResolvedTypes( * If there is no match, "unknown" is returned. */ export default function getFlowType( - path: NodePath, - typeParams: TypeParameters | null, - importer: Importer, + path: NodePath, + typeParams: TypeParameters | null = null, ): TypeDescriptor { // Empty visited types before an after run // Before: in case the detection threw and we rerun again // After: cleanup memory after we are done here visitedTypes = {}; - const type = getFlowTypeWithResolvedTypes(path, typeParams, importer); + const type = getFlowTypeWithResolvedTypes(path, typeParams); visitedTypes = {}; return type; diff --git a/src/utils/getFlowTypeFromReactComponent.ts b/src/utils/getFlowTypeFromReactComponent.ts deleted file mode 100644 index 27364a501cc..00000000000 --- a/src/utils/getFlowTypeFromReactComponent.ts +++ /dev/null @@ -1,154 +0,0 @@ -import type Documentation from '../Documentation'; -import getMemberValuePath from './getMemberValuePath'; -import getTypeAnnotation from './getTypeAnnotation'; -import getTypeParameters, { TypeParameters } from './getTypeParameters'; -import isReactComponentClass from './isReactComponentClass'; -import isReactForwardRefCall from './isReactForwardRefCall'; -import resolveGenericTypeAnnotation from './resolveGenericTypeAnnotation'; -import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; - -function getStatelessPropsPath( - componentDefinition: NodePath, - importer: Importer, -): NodePath { - const value = resolveToValue(componentDefinition, importer); - if (isReactForwardRefCall(value, importer)) { - const inner = resolveToValue(value.get('arguments', 0), importer); - return inner.get('params', 0); - } - return value.get('params', 0); -} - -/** - * Given an React component (stateless or class) tries to find the - * flow type for the props. If not found or not one of the supported - * component types returns null. - */ -export default (path: NodePath, importer: Importer): NodePath | null => { - let typePath: NodePath | null = null; - - if (isReactComponentClass(path, importer)) { - const superTypes = path.get('superTypeParameters'); - - if (superTypes.value) { - const params = superTypes.get('params'); - if (params.value.length === 3) { - typePath = params.get(1); - } else { - typePath = params.get(0); - } - } else { - const propsMemberPath = getMemberValuePath(path, 'props', importer); - if (!propsMemberPath) { - return null; - } - - typePath = getTypeAnnotation(propsMemberPath.parentPath); - } - - return typePath; - } - - const propsParam = getStatelessPropsPath(path, importer); - - if (propsParam) { - typePath = getTypeAnnotation(propsParam); - } - - return typePath; -}; - -export function applyToFlowTypeProperties( - documentation: Documentation, - path: NodePath, - callback: (propertyPath: NodePath, params: TypeParameters | null) => void, - typeParams: TypeParameters | null, - importer: Importer, -): void { - if (path.node.properties) { - path - .get('properties') - .each(propertyPath => callback(propertyPath, typeParams)); - } else if (path.node.members) { - path - .get('members') - .each(propertyPath => callback(propertyPath, typeParams)); - } else if (path.node.type === 'InterfaceDeclaration') { - if (path.node.extends) { - applyExtends(documentation, path, callback, typeParams, importer); - } - - path - .get('body', 'properties') - .each(propertyPath => callback(propertyPath, typeParams)); - } else if (path.node.type === 'TSInterfaceDeclaration') { - if (path.node.extends) { - applyExtends(documentation, path, callback, typeParams, importer); - } - - path - .get('body', 'body') - .each(propertyPath => callback(propertyPath, typeParams)); - } else if ( - path.node.type === 'IntersectionTypeAnnotation' || - path.node.type === 'TSIntersectionType' - ) { - path - .get('types') - .each(typesPath => - applyToFlowTypeProperties( - documentation, - typesPath, - callback, - typeParams, - importer, - ), - ); - } else if (path.node.type !== 'UnionTypeAnnotation') { - // The react-docgen output format does not currently allow - // for the expression of union types - const typePath = resolveGenericTypeAnnotation(path, importer); - if (typePath) { - applyToFlowTypeProperties( - documentation, - typePath, - callback, - typeParams, - importer, - ); - } - } -} - -function applyExtends(documentation, path, callback, typeParams, importer) { - path.get('extends').each((extendsPath: NodePath) => { - const resolvedPath = resolveGenericTypeAnnotation(extendsPath, importer); - if (resolvedPath) { - if (resolvedPath.node.typeParameters && extendsPath.node.typeParameters) { - typeParams = getTypeParameters( - resolvedPath.get('typeParameters'), - extendsPath.get('typeParameters'), - typeParams, - importer, - ); - } - applyToFlowTypeProperties( - documentation, - resolvedPath, - callback, - typeParams, - importer, - ); - } else { - const id = - extendsPath.node.id || - extendsPath.node.typeName || - extendsPath.node.expression; - if (id && id.type === 'Identifier') { - documentation.addComposes(id.name); - } - } - }); -} diff --git a/src/utils/getMemberExpressionRoot.ts b/src/utils/getMemberExpressionRoot.ts index ef8ea337aa5..c61601fb22d 100644 --- a/src/utils/getMemberExpressionRoot.ts +++ b/src/utils/getMemberExpressionRoot.ts @@ -1,5 +1,5 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { Expression, MemberExpression } from '@babel/types'; /** * Returns the path to the first part of the MemberExpression. I.e. given a @@ -10,10 +10,12 @@ import type { NodePath } from 'ast-types/lib/node-path'; * it returns the path of/to `foo`. */ export default function getMemberExpressionRoot( - memberExpressionPath: NodePath, -): NodePath { - do { - memberExpressionPath = memberExpressionPath.get('object'); - } while (t.MemberExpression.check(memberExpressionPath.node)); - return memberExpressionPath; + memberExpressionPath: NodePath, +): NodePath { + let path: NodePath = memberExpressionPath; + while (path.isMemberExpression()) { + path = path.get('object'); + } + + return path; } diff --git a/src/utils/getMemberExpressionValuePath.ts b/src/utils/getMemberExpressionValuePath.ts index 528a33776db..d87c1682b38 100644 --- a/src/utils/getMemberExpressionValuePath.ts +++ b/src/utils/getMemberExpressionValuePath.ts @@ -1,97 +1,98 @@ -import { namedTypes as t, visit } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { Expression } from '@babel/types'; import getNameOrValue from './getNameOrValue'; import { String as toString } from './expressionTo'; import isReactForwardRefCall from './isReactForwardRefCall'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; -function resolveName(path: NodePath, importer: Importer): string | undefined { - if (t.VariableDeclaration.check(path.node)) { +function resolveName(path: NodePath): string | undefined { + if (path.isVariableDeclaration()) { const declarations = path.get('declarations'); - if (declarations.value.length && declarations.value.length !== 1) { + if (declarations.length > 1) { throw new TypeError( 'Got unsupported VariableDeclaration. VariableDeclaration must only ' + 'have a single VariableDeclarator. Got ' + - declarations.value.length + + declarations.length + ' declarations.', ); } - const value = declarations.get(0, 'id', 'name').value; - return value; + const id = declarations[0].get('id'); + if (id.isIdentifier()) { + return id.node.name; + } + + return; } - if (t.FunctionDeclaration.check(path.node)) { - return path.get('id', 'name').value; + if (path.isFunctionDeclaration()) { + const id = path.get('id'); + if (id.isIdentifier()) { + return id.node.name; + } + + return; } if ( - t.FunctionExpression.check(path.node) || - t.ArrowFunctionExpression.check(path.node) || - t.TaggedTemplateExpression.check(path.node) || - t.CallExpression.check(path.node) || - isReactForwardRefCall(path, importer) + path.isFunctionExpression() || + path.isArrowFunctionExpression() || + path.isTaggedTemplateExpression() || + path.isCallExpression() || + isReactForwardRefCall(path) ) { - let currentPath = path; - while (currentPath.parent) { - if (t.VariableDeclarator.check(currentPath.parent.node)) { - return currentPath.parent.get('id', 'name').value; + let currentPath: NodePath = path; + while (currentPath.parentPath) { + if (currentPath.parentPath.isVariableDeclarator()) { + const id = currentPath.parentPath.get('id'); + if (id.isIdentifier()) { + return id.node.name; + } + return; } - currentPath = currentPath.parent; + currentPath = currentPath.parentPath; } return; } throw new TypeError( - 'Attempted to resolveName for an unsupported path. resolveName accepts a ' + - 'VariableDeclaration, FunctionDeclaration, FunctionExpression or CallExpression. Got "' + + 'Attempted to resolveName for an unsupported path. resolveName does not accept ' + path.node.type + '".', ); } -function getRoot(node) { - let root = node.parent; - while (root.parent) { - root = root.parent; - } - return root; -} - export default function getMemberExpressionValuePath( variableDefinition: NodePath, memberName: string, - importer: Importer, -): NodePath | null { - const localName = resolveName(variableDefinition, importer); - const program = getRoot(variableDefinition); +): NodePath | null { + const localName = resolveName(variableDefinition); + const program = variableDefinition.findParent(path => path.isProgram()); - if (!localName) { + if (!localName || !program) { // likely an immediately exported and therefore nameless/anonymous node // passed in return null; } - let result; - visit(program, { - visitAssignmentExpression(path) { + let result: NodePath | null = null; + program.traverse({ + AssignmentExpression(path) { const memberPath = path.get('left'); - if (!t.MemberExpression.check(memberPath.node)) { - return this.traverse(path); + if (!memberPath.isMemberExpression()) { + return; } + const property = memberPath.get('property'); if ( - (!memberPath.node.computed || - t.Literal.check(memberPath.node.property)) && - getNameOrValue(memberPath.get('property')) === memberName && - toString(memberPath.get('object'), importer) === localName + (!memberPath.node.computed || property.isLiteral()) && + getNameOrValue(property) === memberName && + toString(memberPath.get('object')) === localName ) { result = path.get('right'); - return false; + path.skip(); + return; } - - this.traverse(memberPath); }, }); diff --git a/src/utils/getMemberValuePath.ts b/src/utils/getMemberValuePath.ts index 563d954db5a..1e1418da1a2 100644 --- a/src/utils/getMemberValuePath.ts +++ b/src/utils/getMemberValuePath.ts @@ -1,75 +1,51 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; import getClassMemberValuePath from './getClassMemberValuePath'; import getMemberExpressionValuePath from './getMemberExpressionValuePath'; import getPropertyValuePath from './getPropertyValuePath'; import resolveFunctionDefinitionToReturnValue from '../utils/resolveFunctionDefinitionToReturnValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { ClassMethod, Expression, ObjectMethod } from '@babel/types'; -const SYNONYMS = { - getDefaultProps: 'defaultProps', - defaultProps: 'getDefaultProps', -}; - -const postprocessPropTypes = (path, importer) => - t.Function.check(path.node) - ? resolveFunctionDefinitionToReturnValue(path, importer) - : path; +const postprocessPropTypes = ( + path: NodePath, +) => (path.isFunction() ? resolveFunctionDefinitionToReturnValue(path) : path); const POSTPROCESS_MEMBERS = new Map([['propTypes', postprocessPropTypes]]); -const LOOKUP_METHOD = new Map([ - // @ts-ignore - [t.ArrowFunctionExpression.name, getMemberExpressionValuePath], - // @ts-ignore - [t.CallExpression.name, getMemberExpressionValuePath], - // @ts-ignore - [t.FunctionExpression.name, getMemberExpressionValuePath], - // @ts-ignore - [t.FunctionDeclaration.name, getMemberExpressionValuePath], - // @ts-ignore - [t.VariableDeclaration.name, getMemberExpressionValuePath], - // @ts-ignore - [t.ObjectExpression.name, getPropertyValuePath], - // @ts-ignore - [t.ClassDeclaration.name, getClassMemberValuePath], - // @ts-ignore - [t.ClassExpression.name, getClassMemberValuePath], -]); +const SUPPORTED_DEFINITION_TYPES = [ + 'ObjectExpression', + 'ClassDeclaration', + 'ClassExpression', + /** + * Adds support for libraries such as + * [styled components]{@link https://github.com/styled-components} that use + * TaggedTemplateExpression's to generate components. + * + * While react-docgen's built-in resolvers do not support resolving + * TaggedTemplateExpression definitions, third-party resolvers (such as + * https://github.com/Jmeyering/react-docgen-annotation-resolver) could be + * used to add these definitions. + */ + 'TaggedTemplateExpression', + // potential stateless function component + 'VariableDeclaration', + 'ArrowFunctionExpression', + 'FunctionDeclaration', + 'FunctionExpression', + /** + * Adds support for libraries such as + * [system-components]{@link https://jxnblk.com/styled-system/system-components} that use + * CallExpressions to generate components. + * + * While react-docgen's built-in resolvers do not support resolving + * CallExpressions definitions, third-party resolvers (such as + * https://github.com/Jmeyering/react-docgen-annotation-resolver) could be + * used to add these definitions. + */ + 'CallExpression', +]; -export function isSupportedDefinitionType({ node }: NodePath): boolean { - return ( - t.ObjectExpression.check(node) || - t.ClassDeclaration.check(node) || - t.ClassExpression.check(node) || - /** - * Adds support for libraries such as - * [styled components]{@link https://github.com/styled-components} that use - * TaggedTemplateExpression's to generate components. - * - * While react-docgen's built-in resolvers do not support resolving - * TaggedTemplateExpression definitions, third-party resolvers (such as - * https://github.com/Jmeyering/react-docgen-annotation-resolver) could be - * used to add these definitions. - */ - t.TaggedTemplateExpression.check(node) || - // potential stateless function component - t.VariableDeclaration.check(node) || - t.ArrowFunctionExpression.check(node) || - t.FunctionDeclaration.check(node) || - t.FunctionExpression.check(node) || - /** - * Adds support for libraries such as - * [system-components]{@link https://jxnblk.com/styled-system/system-components} that use - * CallExpressions to generate components. - * - * While react-docgen's built-in resolvers do not support resolving - * CallExpressions definitions, third-party resolvers (such as - * https://github.com/Jmeyering/react-docgen-annotation-resolver) could be - * used to add these definitions. - */ - t.CallExpression.check(node) - ); +export function isSupportedDefinitionType(path: NodePath): boolean { + return SUPPORTED_DEFINITION_TYPES.includes(path.node.type); } /** @@ -88,29 +64,43 @@ export function isSupportedDefinitionType({ node }: NodePath): boolean { export default function getMemberValuePath( componentDefinition: NodePath, memberName: string, - importer: Importer, -): NodePath | null { +): NodePath | null { + // TODO test error message if (!isSupportedDefinitionType(componentDefinition)) { throw new TypeError( - 'Got unsupported definition type. Definition must be one of ' + - 'ObjectExpression, ClassDeclaration, ClassExpression,' + - 'VariableDeclaration, ArrowFunctionExpression, FunctionExpression, ' + - 'TaggedTemplateExpression, FunctionDeclaration or CallExpression. Got "' + - componentDefinition.node.type + - '" instead.', + `Got unsupported definition type. Definition must be one of ${SUPPORTED_DEFINITION_TYPES.join( + ', ', + )}. Got "${componentDefinition.node.type}" instead.`, ); } - const lookupMethod = - LOOKUP_METHOD.get(componentDefinition.node.type) || - getMemberExpressionValuePath; - let result = lookupMethod(componentDefinition, memberName, importer); - if (!result && SYNONYMS[memberName]) { - result = lookupMethod(componentDefinition, SYNONYMS[memberName], importer); + let result: NodePath | null; + if (componentDefinition.isObjectExpression()) { + result = getPropertyValuePath(componentDefinition, memberName); + if (!result && memberName === 'defaultProps') { + result = getPropertyValuePath(componentDefinition, 'getDefaultProps'); + } + } else if ( + componentDefinition.isClassDeclaration() || + componentDefinition.isClassExpression() + ) { + result = getClassMemberValuePath(componentDefinition, memberName); + if (!result && memberName === 'defaultProps') { + result = getClassMemberValuePath(componentDefinition, 'getDefaultProps'); + } + } else { + result = getMemberExpressionValuePath(componentDefinition, memberName); + if (!result && memberName === 'defaultProps') { + result = getMemberExpressionValuePath( + componentDefinition, + 'getDefaultProps', + ); + } } + const postprocessMethod = POSTPROCESS_MEMBERS.get(memberName); if (result && postprocessMethod) { - result = postprocessMethod(result, importer); + result = postprocessMethod(result); } return result; diff --git a/src/utils/getMembers.ts b/src/utils/getMembers.ts index a7120c94ead..35ccb0c1c82 100644 --- a/src/utils/getMembers.ts +++ b/src/utils/getMembers.ts @@ -1,10 +1,10 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { Expression, PrivateName } from '@babel/types'; interface MemberDescriptor { - path: NodePath; + path: NodePath; computed: boolean; - argumentsPath: NodePath | null; + argumentPaths: NodePath[]; } /** @@ -24,32 +24,37 @@ export default function getMembers( includeRoot = false, ): MemberDescriptor[] { const result: MemberDescriptor[] = []; - let argumentsPath = null; + let argumentPaths: NodePath[] = []; + let resultPath: MemberDescriptor['path'] = path as NodePath; + // eslint-disable-next-line no-constant-condition - loop: while (true) { - switch (true) { - case t.MemberExpression.check(path.node): - result.push({ - path: path.get('property'), - computed: path.node.computed, - argumentsPath: argumentsPath, - }); - argumentsPath = null; - path = path.get('object'); - break; - case t.CallExpression.check(path.node): - argumentsPath = path.get('arguments'); - path = path.get('callee'); + while (true) { + if (resultPath.isMemberExpression()) { + const property = resultPath.get('property'); + result.push({ + path: property, + computed: resultPath.node.computed, + argumentPaths, + }); + argumentPaths = []; + resultPath = resultPath.get('object'); + } else if (resultPath.isCallExpression()) { + const callee = resultPath.get('callee'); + if (callee.isExpression()) { + argumentPaths = resultPath.get('arguments'); + resultPath = callee; + } else { break; - default: - break loop; + } + } else { + break; } } if (includeRoot && result.length > 0) { result.push({ - path, + path: resultPath, computed: false, - argumentsPath, + argumentPaths, }); } return result.reverse(); diff --git a/src/utils/getMethodDocumentation.ts b/src/utils/getMethodDocumentation.ts index 05c07ae911b..f8255420bb4 100644 --- a/src/utils/getMethodDocumentation.ts +++ b/src/utils/getMethodDocumentation.ts @@ -1,89 +1,133 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { + AssignmentExpression, + ClassMethod, + ClassPrivateMethod, + ClassProperty, + FlowType, + Function as FunctionType, + ObjectMethod, + ObjectProperty, + TSType, +} from '@babel/types'; import { getDocblock } from './docblock'; import getFlowType from './getFlowType'; import getTSType from './getTSType'; import getParameterName from './getParameterName'; import getPropertyName from './getPropertyName'; import getTypeAnnotation from './getTypeAnnotation'; -import type { Importer } from '../parse'; import resolveToValue from './resolveToValue'; -import { +import printValue from './printValue'; +import type { MethodDescriptor, MethodModifier, MethodParameter, MethodReturn, TypeDescriptor, } from '../Documentation'; -import type { NodePath } from 'ast-types/lib/node-path'; + +export type MethodNodePath = + | NodePath + | NodePath + | NodePath + | NodePath + | NodePath + | NodePath; function getMethodFunctionExpression( - methodPath: NodePath, - importer: Importer, -): NodePath { - const exprPath = t.AssignmentExpression.check(methodPath.node) + methodPath: MethodNodePath, +): NodePath | null { + if (methodPath.isClassMethod() || methodPath.isObjectMethod()) { + return methodPath; + } + + const potentialFunctionExpression = methodPath.isAssignmentExpression() ? methodPath.get('right') - : methodPath.get('value'); - return resolveToValue(exprPath, importer); + : (methodPath.get('value') as NodePath); + + const functionExpression = resolveToValue(potentialFunctionExpression); + + if (functionExpression.isFunction()) { + return functionExpression; + } + + return null; } -function getMethodParamsDoc( - methodPath: NodePath, - importer: Importer, -): MethodParameter[] { +function getMethodParamOptional( + path: NodePath, +): boolean { + let identifier: NodePath = path; + if (identifier.isTSParameterProperty()) { + identifier = identifier.get('parameter'); + } + if (identifier.isAssignmentPattern()) { + // A default value always makes the param optional + return true; + } + + return identifier.isIdentifier() ? Boolean(identifier.node.optional) : false; +} + +function getMethodParamsDoc(methodPath: MethodNodePath): MethodParameter[] { const params: MethodParameter[] = []; - const functionExpression = getMethodFunctionExpression(methodPath, importer); - - // Extract param flow types. - functionExpression.get('params').each((paramPath: NodePath) => { - let type: TypeDescriptor | null = null; - const typePath = getTypeAnnotation(paramPath); - if (typePath && t.Flow.check(typePath.node)) { - type = getFlowType(typePath, null, importer); - if (t.GenericTypeAnnotation.check(typePath.node)) { - // @ts-ignore - type.alias = typePath.node.id.name; + const functionExpression = getMethodFunctionExpression(methodPath); + + if (functionExpression) { + // Extract param types. + functionExpression.get('params').forEach(paramPath => { + let type: TypeDescriptor | null = null; + const typePath = getTypeAnnotation(paramPath); + if (typePath) { + if (typePath.isFlowType()) { + type = getFlowType(typePath, null); + if (typePath.isGenericTypeAnnotation()) { + type.alias = printValue(typePath.get('id')); + } + } else if (typePath.isTSType()) { + type = getTSType(typePath, null); + if (typePath.isTSTypeReference()) { + type.alias = printValue(typePath.get('typeName')); + } + } } - } else if (typePath) { - type = getTSType(typePath, null, importer); - if (t.TSTypeReference.check(typePath.node)) { - // @ts-ignore - type.alias = typePath.node.typeName.name; - } - } - const param = { - name: getParameterName(paramPath), - optional: paramPath.node.optional, - type, - }; + const param = { + name: getParameterName(paramPath), + optional: getMethodParamOptional(paramPath), + type, + }; - params.push(param); - }); + params.push(param); + }); + } return params; } // Extract flow return type. -function getMethodReturnDoc( - methodPath: NodePath, - importer: Importer, -): MethodReturn | null { - const functionExpression = getMethodFunctionExpression(methodPath, importer); - - if (functionExpression.node.returnType) { - const returnType = getTypeAnnotation(functionExpression.get('returnType')); - if (returnType && t.Flow.check(returnType.node)) { - return { type: getFlowType(returnType, null, importer) }; +function getMethodReturnDoc(methodPath: MethodNodePath): MethodReturn | null { + const functionExpression = getMethodFunctionExpression(methodPath); + + if (functionExpression && functionExpression.node.returnType) { + const returnType = getTypeAnnotation( + functionExpression.get('returnType') as NodePath, + ); + if (returnType && returnType.isFlowType()) { + return { type: getFlowType(returnType, null) }; } else if (returnType) { - return { type: getTSType(returnType, null, importer) }; + return { type: getTSType(returnType, null) }; } } return null; } -function getMethodModifiers(methodPath: NodePath): MethodModifier[] { - if (t.AssignmentExpression.check(methodPath.node)) { +function getMethodModifiers( + methodPath: MethodNodePath, + options: { isStatic?: boolean }, +): MethodModifier[] { + if (methodPath.isAssignmentExpression()) { return ['static']; } @@ -91,64 +135,79 @@ function getMethodModifiers(methodPath: NodePath): MethodModifier[] { const modifiers: MethodModifier[] = []; - if (methodPath.node.static) { + if ( + // TODO add test for options + options.isStatic === true || + ((methodPath.isClassProperty() || methodPath.isClassMethod()) && + methodPath.node.static) + ) { modifiers.push('static'); } - if (methodPath.node.kind === 'get' || methodPath.node.kind === 'set') { - modifiers.push(methodPath.node.kind); - } + const functionExpression = getMethodFunctionExpression(methodPath); + if (functionExpression) { + if ( + functionExpression.isClassMethod() || + functionExpression.isObjectMethod() + ) { + if ( + functionExpression.node.kind === 'get' || + functionExpression.node.kind === 'set' + ) { + modifiers.push(functionExpression.node.kind); + } + } - const functionExpression = methodPath.get('value').node; - if (functionExpression.generator) { - modifiers.push('generator'); - } - if (functionExpression.async) { - modifiers.push('async'); + if (functionExpression.node.generator) { + modifiers.push('generator'); + } + if (functionExpression.node.async) { + modifiers.push('async'); + } } return modifiers; } function getMethodName( - methodPath: NodePath, - importer: Importer, + methodPath: Exclude>, ): string | null { - if ( - t.AssignmentExpression.check(methodPath.node) && - t.MemberExpression.check(methodPath.node.left) - ) { - const left = methodPath.node.left; - const property = left.property; - if (!left.computed) { - // @ts-ignore - return property.name; - } - if (t.Literal.check(property)) { - return String(property.value); + if (methodPath.isAssignmentExpression()) { + const left = methodPath.get('left'); + if (left.isMemberExpression()) { + const property = left.get('property'); + if (!left.node.computed && property.isIdentifier()) { + return property.node.name; + } + if (property.isStringLiteral() || property.isNumericLiteral()) { + return String(property.node.value); + } } + return null; } - return getPropertyName(methodPath, importer); + + return getPropertyName(methodPath); } function getMethodAccessibility( - methodPath: NodePath, -): null | 'public' | 'private' | 'protected' { - if (t.AssignmentExpression.check(methodPath.node)) { - return null; + methodPath: MethodNodePath, +): 'private' | 'protected' | 'public' | null { + if (methodPath.isClassMethod() || methodPath.isClassProperty()) { + return methodPath.node.accessibility || null; } - // Otherwise this is a method/property node - return methodPath.node.accessibility; + // Otherwise this is a object method/property or assignment expression + return null; } -function getMethodDocblock(methodPath: NodePath): string | null { - if (t.AssignmentExpression.check(methodPath.node)) { - let path = methodPath; +function getMethodDocblock(methodPath: MethodNodePath): string | null { + if (methodPath.isAssignmentExpression()) { + let path: NodePath | null = methodPath; do { - path = path.parent; - } while (path && !t.ExpressionStatement.check(path.node)); + path = path.parentPath; + } while (path && !path.isExpressionStatement()); + if (path) { return getDocblock(path); } @@ -161,23 +220,26 @@ function getMethodDocblock(methodPath: NodePath): string | null { // Gets the documentation object for a component method. // Component methods may be represented as class/object method/property nodes -// or as assignment expresions of the form `Component.foo = function() {}` +// or as assignment expression of the form `Component.foo = function() {}` export default function getMethodDocumentation( - methodPath: NodePath, - importer: Importer, + methodPath: MethodNodePath, + options: { isStatic?: boolean } = {}, ): MethodDescriptor | null { - if (getMethodAccessibility(methodPath) === 'private') { + if ( + getMethodAccessibility(methodPath) === 'private' || + methodPath.isClassPrivateMethod() + ) { return null; } - const name = getMethodName(methodPath, importer); + const name = getMethodName(methodPath); if (!name) return null; return { name, docblock: getMethodDocblock(methodPath), - modifiers: getMethodModifiers(methodPath), - params: getMethodParamsDoc(methodPath, importer), - returns: getMethodReturnDoc(methodPath, importer), + modifiers: getMethodModifiers(methodPath, options), + params: getMethodParamsDoc(methodPath), + returns: getMethodReturnDoc(methodPath), }; } diff --git a/src/utils/getNameOrValue.ts b/src/utils/getNameOrValue.ts index 23fbbb33f68..351360ee79f 100644 --- a/src/utils/getNameOrValue.ts +++ b/src/utils/getNameOrValue.ts @@ -1,18 +1,24 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; /** * If node is an Identifier, it returns its name. If it is a literal, it returns * its value. */ -export default function getNameOrValue(path: NodePath, raw = false): string { - const node = path.node; - - if (t.Identifier.check(node)) { - return node.name; - } else if (t.Literal.check(node)) { - //@ts-ignore - return raw ? node.raw : node.value; +export default function getNameOrValue( + path: NodePath, +): boolean | number | string | null { + if (path.isIdentifier()) { + return path.node.name; + } else if ( + path.isStringLiteral() || + path.isNumericLiteral() || + path.isBooleanLiteral() + ) { + return path.node.value; + } else if (path.isRegExpLiteral()) { + return path.node.pattern; + } else if (path.isNullLiteral()) { + return null; } throw new TypeError('Argument must be an Identifier or a Literal'); diff --git a/src/utils/getParameterName.ts b/src/utils/getParameterName.ts index b5c18d021af..e42434b4a42 100644 --- a/src/utils/getParameterName.ts +++ b/src/utils/getParameterName.ts @@ -1,26 +1,45 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { + ArrayPattern, + AssignmentPattern, + Identifier, + ObjectPattern, + RestElement, + TSParameterProperty, +} from '@babel/types'; import printValue from './printValue'; -export default function getParameterName(parameterPath: NodePath): string { - switch (parameterPath.node.type) { - // @ts-ignore - case t.Identifier.name: - return parameterPath.node.name; - // @ts-ignore - case t.AssignmentPattern.name: - return getParameterName(parameterPath.get('left')); - // @ts-ignore - case t.ObjectPattern.name: // @ts-ignore - case t.ArrayPattern.name: - return printValue(parameterPath); - // @ts-ignore - case t.RestElement.name: - return '...' + getParameterName(parameterPath.get('argument')); - default: - throw new TypeError( - 'Parameter name must be an Identifier, an AssignmentPattern an ' + - `ObjectPattern or a RestElement, got ${parameterPath.node.type}`, - ); +type ParameterNodePath = NodePath< + | ArrayPattern + | AssignmentPattern + | Identifier + | ObjectPattern + | RestElement + | TSParameterProperty +>; + +export default function getParameterName( + parameterPath: ParameterNodePath, +): string { + if (parameterPath.isIdentifier()) { + return parameterPath.node.name; + } else if (parameterPath.isAssignmentPattern()) { + return getParameterName(parameterPath.get('left') as ParameterNodePath); + } else if ( + parameterPath.isObjectPattern() || + parameterPath.isArrayPattern() + ) { + return printValue(parameterPath); + } else if (parameterPath.isRestElement()) { + return `...${getParameterName( + parameterPath.get('argument') as ParameterNodePath, + )}`; + } else if (parameterPath.isTSParameterProperty()) { + return getParameterName(parameterPath.get('parameter')); } + + throw new TypeError( + 'Parameter name must be one of Identifier, AssignmentPattern, ArrayPattern, ' + + `ObjectPattern or RestElement, instead got ${parameterPath.node.type}`, + ); } diff --git a/src/utils/getPropType.ts b/src/utils/getPropType.ts index 5bf219c1649..8fd4bec702b 100644 --- a/src/utils/getPropType.ts +++ b/src/utils/getPropType.ts @@ -1,6 +1,5 @@ /*eslint no-use-before-define: 0*/ - -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; import { getDocblock } from '../utils/docblock'; import getMembers from './getMembers'; import getPropertyName from './getPropertyName'; @@ -9,53 +8,57 @@ import printValue from './printValue'; import resolveToValue from './resolveToValue'; import resolveObjectKeysToArray from './resolveObjectKeysToArray'; import resolveObjectValuesToArray from './resolveObjectValuesToArray'; -import type { Importer } from '../parse'; import type { PropTypeDescriptor, PropDescriptor } from '../Documentation'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { + ArrayExpression, + Expression, + ObjectProperty, + SpreadElement, +} from '@babel/types'; -function getEnumValues( - path: NodePath, - importer: Importer, +function getEnumValuesFromArrayExpression( + path: NodePath, ): Array> { const values: Array> = []; - path.get('elements').each(function (elementPath) { - if (t.SpreadElement.check(elementPath.node)) { - const value = resolveToValue(elementPath.get('argument'), importer); + path.get('elements').forEach(elementPath => { + // Array holes TODO test + if (elementPath.node == null) return; + + if (elementPath.isSpreadElement()) { + const value = resolveToValue(elementPath.get('argument')); - if (t.ArrayExpression.check(value.node)) { + if (value.isArrayExpression()) { // if the SpreadElement resolved to an Array, add all their elements too - return values.push(...getEnumValues(value, importer)); + return values.push(...getEnumValuesFromArrayExpression(value)); } else { // otherwise we'll just print the SpreadElement itself return values.push({ value: printValue(elementPath), - computed: !t.Literal.check(elementPath.node), + computed: !elementPath.isLiteral(), }); } } // try to resolve the array element to it's value - const value = resolveToValue(elementPath, importer); + const value = resolveToValue(elementPath as NodePath); return values.push({ value: printValue(value), - computed: !t.Literal.check(value.node), + computed: !value.isLiteral(), }); }); return values; } -function getPropTypeOneOf( - argumentPath: NodePath, - importer: Importer, -): PropTypeDescriptor { +// TODO +function getPropTypeOneOf(argumentPath: NodePath): PropTypeDescriptor { const type: PropTypeDescriptor = { name: 'enum' }; - const value: NodePath | null = resolveToValue(argumentPath, importer); - if (!t.ArrayExpression.check(value.node)) { + const value: NodePath = resolveToValue(argumentPath); + if (!value.isArrayExpression()) { const objectValues = - resolveObjectKeysToArray(value, importer) || - resolveObjectValuesToArray(value, importer); + resolveObjectKeysToArray(value) || //TODO return array of names and not ArrayExpression anymore + resolveObjectValuesToArray(value); if (objectValues) { type.value = objectValues.map(objectValue => ({ value: objectValue, @@ -67,23 +70,24 @@ function getPropTypeOneOf( type.value = printValue(argumentPath); } } else { - type.value = getEnumValues(value, importer); + type.value = getEnumValuesFromArrayExpression(value); } return type; } -function getPropTypeOneOfType( - argumentPath: NodePath, - importer: Importer, -): PropTypeDescriptor { +function getPropTypeOneOfType(argumentPath: NodePath): PropTypeDescriptor { const type: PropTypeDescriptor = { name: 'union' }; - if (!t.ArrayExpression.check(argumentPath.node)) { + if (!argumentPath.isArrayExpression()) { type.computed = true; type.value = printValue(argumentPath); } else { - type.value = argumentPath.get('elements').map(function (itemPath) { - const descriptor: PropTypeDescriptor = getPropType(itemPath, importer); - const docs = getDocblock(itemPath); + type.value = argumentPath.get('elements').map(elementPath => { + // Array holes TODO test + if (!elementPath.hasNode()) return; + const descriptor: PropTypeDescriptor = getPropType(elementPath); + const docs = getDocblock( + elementPath as NodePath, + ); if (docs) { descriptor.description = docs; } @@ -93,7 +97,7 @@ function getPropTypeOneOfType( return type; } -function getPropTypeArrayOf(argumentPath: NodePath, importer: Importer) { +function getPropTypeArrayOf(argumentPath: NodePath) { const type: PropTypeDescriptor = { name: 'arrayOf' }; const docs = getDocblock(argumentPath); @@ -101,7 +105,7 @@ function getPropTypeArrayOf(argumentPath: NodePath, importer: Importer) { type.description = docs; } - const subType = getPropType(argumentPath, importer); + const subType = getPropType(argumentPath); // @ts-ignore if (subType.name === 'unknown') { @@ -113,7 +117,7 @@ function getPropTypeArrayOf(argumentPath: NodePath, importer: Importer) { return type; } -function getPropTypeObjectOf(argumentPath: NodePath, importer: Importer) { +function getPropTypeObjectOf(argumentPath: NodePath) { const type: PropTypeDescriptor = { name: 'objectOf' }; const docs = getDocblock(argumentPath); @@ -121,7 +125,7 @@ function getPropTypeObjectOf(argumentPath: NodePath, importer: Importer) { type.description = docs; } - const subType = getPropType(argumentPath, importer); + const subType = getPropType(argumentPath); // @ts-ignore if (subType.name === 'unknown') { @@ -136,36 +140,32 @@ function getPropTypeObjectOf(argumentPath: NodePath, importer: Importer) { /** * Handles shape and exact prop types */ -function getPropTypeShapish( - name: 'shape' | 'exact', - argumentPath: NodePath, - importer: Importer, -) { +function getPropTypeShapish(name: 'exact' | 'shape', argumentPath: NodePath) { const type: PropTypeDescriptor = { name }; - if (!t.ObjectExpression.check(argumentPath.node)) { - argumentPath = resolveToValue(argumentPath, importer); + if (!argumentPath.isObjectExpression()) { + argumentPath = resolveToValue(argumentPath); } - if (t.ObjectExpression.check(argumentPath.node)) { + if (argumentPath.isObjectExpression()) { const value = {}; - argumentPath.get('properties').each(function (propertyPath) { - // @ts-ignore - if (propertyPath.get('type').value === t.SpreadElement.name) { + argumentPath.get('properties').forEach(propertyPath => { + if (propertyPath.isSpreadElement() || propertyPath.isObjectMethod()) { // It is impossible to resolve a name for a spread element return; } - const propertyName = getPropertyName(propertyPath, importer); + const propertyName = getPropertyName(propertyPath); if (!propertyName) return; - const descriptor: PropDescriptor | PropTypeDescriptor = getPropType( - propertyPath.get('value'), - importer, - ); + + const valuePath = (propertyPath as NodePath).get('value'); + + const descriptor: PropDescriptor | PropTypeDescriptor = + getPropType(valuePath); const docs = getDocblock(propertyPath); if (docs) { descriptor.description = docs; } - descriptor.required = isRequiredPropType(propertyPath.get('value')); + descriptor.required = isRequiredPropType(valuePath); value[propertyName] = descriptor; }); type.value = value; @@ -179,11 +179,7 @@ function getPropTypeShapish( return type; } -function getPropTypeInstanceOf( - argumentPath: NodePath, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _importer: Importer, -): PropTypeDescriptor { +function getPropTypeInstanceOf(argumentPath: NodePath): PropTypeDescriptor { return { name: 'instanceOf', value: printValue(argumentPath), @@ -204,10 +200,13 @@ const simplePropTypes = [ 'elementType', ] as const; -const propTypes = new Map< - string, - (path: NodePath, importer: Importer) => PropTypeDescriptor ->([ +function isSimplePropType( + name: string, +): name is typeof simplePropTypes[number] { + return simplePropTypes.includes(name as typeof simplePropTypes[number]); +} + +const propTypes = new Map PropTypeDescriptor>([ ['oneOf', getPropTypeOneOf], ['oneOfType', getPropTypeOneOfType], ['instanceOf', getPropTypeInstanceOf], @@ -225,49 +224,42 @@ const propTypes = new Map< * * If there is no match, "custom" is returned. */ -export default function getPropType( - path: NodePath, - importer: Importer, -): PropTypeDescriptor { +export default function getPropType(path: NodePath): PropTypeDescriptor { let descriptor: PropTypeDescriptor | null = null; getMembers(path, true).some(member => { - const node = member.path.node; + const memberPath = member.path; let name: string | null = null; - if (t.Literal.check(node)) { - name = node.value as string; - } else if (t.Identifier.check(node) && !member.computed) { - name = node.name; + if (memberPath.isStringLiteral()) { + name = memberPath.node.value; + } else if (memberPath.isIdentifier() && !member.computed) { + name = memberPath.node.name; } if (name) { - if (simplePropTypes.includes(name as typeof simplePropTypes[number])) { - descriptor = { name: name as typeof simplePropTypes[number] }; + if (isSimplePropType(name)) { + descriptor = { name }; return true; - } else if (propTypes.has(name) && member.argumentsPath) { - // @ts-ignore - descriptor = propTypes.get(name)(member.argumentsPath.get(0), importer); + } else if (propTypes.has(name) && member.argumentPaths.length) { + descriptor = propTypes.get(name)!(member.argumentPaths[0]); return true; } } return; }); - if (!descriptor) { - const node = path.node; - if ( - t.Identifier.check(node) && - simplePropTypes.includes(node.name as typeof simplePropTypes[number]) - ) { - descriptor = { name: node.name as typeof simplePropTypes[number] }; - } else if ( - t.CallExpression.check(node) && - t.Identifier.check(node.callee) && - propTypes.has(node.callee.name) - ) { - // @ts-ignore - descriptor = propTypes.get(node.callee.name)(path.get('arguments', 0)); - } else { - descriptor = { name: 'custom', raw: printValue(path) }; + + if (descriptor) { + return descriptor; + } + + if (path.isIdentifier() && isSimplePropType(path.node.name)) { + return { name: path.node.name }; + } else if (path.isCallExpression()) { + const callee = path.get('callee'); + + if (callee.isIdentifier() && propTypes.has(callee.node.name)) { + return propTypes.get(callee.node.name)!(path.get('arguments')[0]); } } - return descriptor; + + return { name: 'custom', raw: printValue(path) }; } diff --git a/src/utils/getPropertyName.ts b/src/utils/getPropertyName.ts index 0ee1cd0f70c..ae00363ce2f 100644 --- a/src/utils/getPropertyName.ts +++ b/src/utils/getPropertyName.ts @@ -1,8 +1,18 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { + ClassMethod, + ClassProperty, + Expression, + ObjectMethod, + ObjectProperty, + ObjectTypeProperty, + ObjectTypeSpreadProperty, + SpreadElement, + TSMethodSignature, + TSPropertySignature, +} from '@babel/types'; import getNameOrValue from './getNameOrValue'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; export const COMPUTED_PREFIX = '@computed#'; @@ -12,40 +22,48 @@ export const COMPUTED_PREFIX = '@computed#'; * returns the value of the literal or name of the identifier. */ export default function getPropertyName( - propertyPath: NodePath, - importer: Importer, + propertyPath: NodePath< + | ClassMethod + | ClassProperty + | ObjectMethod + | ObjectProperty + | ObjectTypeProperty + | ObjectTypeSpreadProperty + | SpreadElement + | TSMethodSignature + | TSPropertySignature + >, ): string | null { - if (t.ObjectTypeSpreadProperty.check(propertyPath.node)) { - return getNameOrValue(propertyPath.get('argument').get('id'), false); - } else if (propertyPath.node.computed) { - const key = propertyPath.get('key'); + if (propertyPath.isObjectTypeSpreadProperty()) { + const argument = propertyPath.get('argument'); + if (argument.isGenericTypeAnnotation()) { + // TODO test qualified type identifier + return getNameOrValue(argument.get('id')) as string; + } + return null; + } else if (propertyPath.has('computed')) { + const key = propertyPath.get('key') as NodePath; // Try to resolve variables and member expressions - if (t.Identifier.check(key.node) || t.MemberExpression.check(key.node)) { - const value = resolveToValue(key, importer).node; - - if ( - t.Literal.check(value) && - (typeof value.value === 'string' || typeof value.value === 'number') - ) { - return `${value.value}`; + if (key.isIdentifier() || key.isMemberExpression()) { + const valuePath = resolveToValue(key); + + if (valuePath.isStringLiteral() || valuePath.isNumericLiteral()) { + return `${valuePath.node.value}`; } } // generate name for identifier - if (t.Identifier.check(key.node)) { + if (key.isIdentifier()) { return `${COMPUTED_PREFIX}${key.node.name}`; } - if ( - t.Literal.check(key.node) && - (typeof key.node.value === 'string' || typeof key.node.value === 'number') - ) { + if (key.isStringLiteral() || key.isNumericLiteral()) { return `${key.node.value}`; } return null; } - return getNameOrValue(propertyPath.get('key'), false); + return `${getNameOrValue(propertyPath.get('key') as NodePath)}`; } diff --git a/src/utils/getPropertyValuePath.ts b/src/utils/getPropertyValuePath.ts index d3d342c9f7c..ab085c24512 100644 --- a/src/utils/getPropertyValuePath.ts +++ b/src/utils/getPropertyValuePath.ts @@ -1,24 +1,27 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { Expression, ObjectExpression, ObjectMethod } from '@babel/types'; import getPropertyName from './getPropertyName'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; /** * Given an ObjectExpression, this function returns the path of the value of * the property with name `propertyName`. */ export default function getPropertyValuePath( - path: NodePath, + path: NodePath, propertyName: string, - importer: Importer, -): NodePath | null { - t.ObjectExpression.assert(path.node); +): NodePath | null { + path.assertObjectExpression(); - return path - .get('properties') - .filter( - (propertyPath: NodePath) => - getPropertyName(propertyPath, importer) === propertyName, - ) - .map((propertyPath: NodePath) => propertyPath.get('value'))[0]; + return ( + path + .get('properties') + .filter(propertyPath => getPropertyName(propertyPath) === propertyName) + .map(propertyPath => + propertyPath.isObjectMethod() + ? propertyPath + : propertyPath.isObjectProperty() + ? (propertyPath.get('value') as NodePath) + : null, + )[0] || null + ); } diff --git a/src/utils/getTSType.ts b/src/utils/getTSType.ts index d3856661782..0e0a131fc0b 100644 --- a/src/utils/getTSType.ts +++ b/src/utils/getTSType.ts @@ -1,11 +1,10 @@ -import { namedTypes as t } from 'ast-types'; import getPropertyName from './getPropertyName'; import printValue from './printValue'; import getTypeAnnotation from '../utils/getTypeAnnotation'; import resolveToValue from '../utils/resolveToValue'; import { resolveObjectToNameArray } from '../utils/resolveObjectKeysToArray'; -import getTypeParameters, { TypeParameters } from '../utils/getTypeParameters'; -import type { Importer } from '../parse'; +import type { TypeParameters } from '../utils/getTypeParameters'; +import getTypeParameters from '../utils/getTypeParameters'; import type { ElementsType, @@ -16,7 +15,28 @@ import type { TypeDescriptor, TSFunctionSignatureType, } from '../Documentation'; -import { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { + TSUnionType, + TSFunctionType, + TSIntersectionType, + TSMappedType, + TSTupleType, + TSInterfaceDeclaration, + TSTypeLiteral, + TSTypeReference, + TSArrayType, + TSCallSignatureDeclaration, + TSIndexedAccessType, + TSTypeQuery, + TSType, + TSTypeAnnotation, + TSTypeOperator, + Identifier, + TSTypeParameterDeclaration, + RestElement, + TypeScript, +} from '@babel/types'; const tsTypes = { TSAnyKeyword: 'any', @@ -49,71 +69,77 @@ const namedTypes = { }; function handleTSArrayType( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ElementsType { return { name: 'Array', - elements: [ - getTSTypeWithResolvedTypes(path.get('elementType'), typeParams, importer), - ], + elements: [getTSTypeWithResolvedTypes(path.get('elementType'), typeParams)], raw: printValue(path), }; } function handleTSTypeReference( - path: NodePath, + path: NodePath, typeParams: TypeParameters, - importer: Importer, ): TypeDescriptor | null { let type: TypeDescriptor; - if (t.TSQualifiedName.check(path.node.typeName)) { - const typeName = path.get('typeName'); - - if (typeName.node.left.name === 'React') { + const typeName = path.get('typeName'); + if (typeName.isTSQualifiedName()) { + const left = typeName.get('left'); + const right = typeName.get('right'); + if ( + left.isIdentifier() && + left.node.name === 'React' && + right.isIdentifier() + ) { type = { - name: `${typeName.node.left.name}${typeName.node.right.name}`, + name: `${left.node.name}${right.node.name}`, raw: printValue(typeName), }; } else { type = { name: printValue(typeName).replace(/<.*>$/, '') }; } } else { - type = { name: path.node.typeName.name }; + type = { name: (typeName as NodePath).node.name }; } const resolvedPath = (typeParams && typeParams[type.name]) || - resolveToValue(path.get('typeName'), importer); + resolveToValue(path.get('typeName')); - if (path.node.typeParameters && resolvedPath.node.typeParameters) { + const typeParameters = path.get('typeParameters'); + const resolvedTypeParameters = resolvedPath.get('typeParameters') as NodePath< + TSTypeParameterDeclaration | null | undefined + >; + if (typeParameters.hasNode() && resolvedTypeParameters.hasNode()) { typeParams = getTypeParameters( - resolvedPath.get('typeParameters'), - path.get('typeParameters'), + resolvedTypeParameters, + typeParameters, typeParams, - importer, ); } if (typeParams && typeParams[type.name]) { // Open question: Why is this `null` instead of `typeParams` - type = getTSTypeWithResolvedTypes(resolvedPath, null, importer); - } - - if (resolvedPath && resolvedPath.node.typeAnnotation) { type = getTSTypeWithResolvedTypes( - resolvedPath.get('typeAnnotation'), - typeParams, - importer, + resolvedPath as NodePath, + null, ); - } else if (path.node.typeParameters) { - const params = path.get('typeParameters').get('params'); + } + + const resolvedTypeAnnotation = resolvedPath.get('typeAnnotation') as NodePath< + TSType | TSTypeAnnotation | null | undefined + >; + if (resolvedTypeAnnotation.hasNode()) { + type = getTSTypeWithResolvedTypes(resolvedTypeAnnotation, typeParams); + } else if (typeParameters.hasNode()) { + const params = typeParameters.get('params'); type = { ...(type as SimpleType), - elements: params.map((param: NodePath) => - getTSTypeWithResolvedTypes(param, typeParams, importer), + elements: params.map(param => + getTSTypeWithResolvedTypes(param, typeParams), ), raw: printValue(path), }; @@ -123,19 +149,18 @@ function handleTSTypeReference( } function getTSTypeWithRequirements( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor { - const type = getTSTypeWithResolvedTypes(path, typeParams, importer); - type.required = !path.parentPath.node.optional; + const type = getTSTypeWithResolvedTypes(path, typeParams); + type.required = + !('optional' in path.parentPath.node) || !path.parentPath.node.optional; return type; } function handleTSTypeLiteral( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ObjectSignatureType { const type: ObjectSignatureType = { name: 'signature', @@ -144,49 +169,44 @@ function handleTSTypeLiteral( signature: { properties: [] }, }; - path.get('members').each(param => { + path.get('members').forEach(param => { + const typeAnnotation = param.get('typeAnnotation') as NodePath< + TSTypeAnnotation | null | undefined + >; if ( - t.TSPropertySignature.check(param.node) || - t.TSMethodSignature.check(param.node) + (param.isTSPropertySignature() || param.isTSMethodSignature()) && + typeAnnotation.hasNode() ) { - const propName = getPropertyName(param, importer); + const propName = getPropertyName(param); if (!propName) { return; } type.signature.properties.push({ key: propName, - value: getTSTypeWithRequirements( - param.get('typeAnnotation'), - typeParams, - importer, - ), - }); - } else if (t.TSCallSignatureDeclaration.check(param.node)) { - type.signature.constructor = handleTSFunctionType( - param, - typeParams, - importer, - ); - } else if (t.TSIndexSignature.check(param.node)) { - type.signature.properties.push({ - key: getTSTypeWithResolvedTypes( - param.get('parameters').get(0).get('typeAnnotation'), - typeParams, - importer, - ), - value: getTSTypeWithRequirements( - param.get('typeAnnotation'), - typeParams, - importer, - ), + value: getTSTypeWithRequirements(typeAnnotation, typeParams), }); + } else if (param.isTSCallSignatureDeclaration()) { + type.signature.constructor = handleTSFunctionType(param, typeParams); + } else if (param.isTSIndexSignature() && typeAnnotation.hasNode()) { + const idTypeAnnotation = param + .get('parameters')[0] + .get('typeAnnotation') as NodePath; + + if (idTypeAnnotation.hasNode()) { + type.signature.properties.push({ + key: getTSTypeWithResolvedTypes(idTypeAnnotation, typeParams), + value: getTSTypeWithRequirements(typeAnnotation, typeParams), + }); + } } }); return type; } -function handleTSInterfaceDeclaration(path: NodePath): SimpleType { +function handleTSInterfaceDeclaration( + path: NodePath, +): SimpleType { // Interfaces are handled like references which would be documented separately, // rather than inlined like type aliases. return { @@ -195,49 +215,54 @@ function handleTSInterfaceDeclaration(path: NodePath): SimpleType { } function handleTSUnionType( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ElementsType { return { name: 'union', raw: printValue(path), elements: path .get('types') - .map(subType => - getTSTypeWithResolvedTypes(subType, typeParams, importer), - ), + .map(subType => getTSTypeWithResolvedTypes(subType, typeParams)), }; } function handleTSIntersectionType( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ElementsType { return { name: 'intersection', raw: printValue(path), elements: path .get('types') - .map(subType => - getTSTypeWithResolvedTypes(subType, typeParams, importer), - ), + .map(subType => getTSTypeWithResolvedTypes(subType, typeParams)), }; } function handleTSMappedType( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ObjectSignatureType { const key = getTSTypeWithResolvedTypes( - path.get('typeParameter').get('constraint'), + path.get('typeParameter').get('constraint') as NodePath, typeParams, - importer, ); key.required = !path.node.optional; + const typeAnnotation = path.get('typeAnnotation'); + let value: TypeDescriptor; + if (typeAnnotation.hasNode()) { + value = getTSTypeWithResolvedTypes(typeAnnotation, typeParams); + } else { + value = { name: 'any' }; //TODO test + /** + type OptionsFlags = { + [Property in keyof Type]; +}; + */ + } + return { name: 'signature', type: 'object', @@ -246,11 +271,7 @@ function handleTSMappedType( properties: [ { key, - value: getTSTypeWithResolvedTypes( - path.get('typeAnnotation'), - typeParams, - importer, - ), + value, }, ], }, @@ -258,40 +279,50 @@ function handleTSMappedType( } function handleTSFunctionType( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TSFunctionSignatureType { + let returnType: TypeDescriptor | undefined; + + const annotation = path.get('typeAnnotation'); + if (annotation.hasNode()) { + returnType = getTSTypeWithResolvedTypes(annotation, typeParams); + } + const type: TSFunctionSignatureType = { name: 'signature', type: 'function', raw: printValue(path), signature: { arguments: [], - return: getTSTypeWithResolvedTypes( - path.get('typeAnnotation'), - typeParams, - importer, - ), + return: returnType, }, }; - path.get('parameters').each(param => { - const typeAnnotation = getTypeAnnotation(param); + path.get('parameters').forEach(param => { + const typeAnnotation = getTypeAnnotation(param); + const arg: FunctionArgumentType = { - name: param.node.name || '', type: typeAnnotation - ? getTSTypeWithResolvedTypes(typeAnnotation, typeParams, importer) + ? getTSTypeWithResolvedTypes(typeAnnotation, typeParams) : undefined, + name: '', }; - if (param.node.name === 'this') { - type.signature.this = arg.type; - return; - } + if (param.isIdentifier()) { + arg.name = param.node.name; - if (param.node.type === 'RestElement') { - arg.name = param.node.argument.name; + if (param.node.name === 'this') { + type.signature.this = arg.type; + return; + } + } else { + const restArgument = (param as NodePath).get('argument'); + if (restArgument.isIdentifier()) { + arg.name = restArgument.node.name; + } else { + arg.name = printValue(restArgument); + } arg.rest = true; } @@ -302,9 +333,8 @@ function handleTSFunctionType( } function handleTSTupleType( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): ElementsType { const type: ElementsType = { name: 'tuple', @@ -312,53 +342,48 @@ function handleTSTupleType( elements: [], }; - path.get('elementTypes').each(param => { - type.elements.push(getTSTypeWithResolvedTypes(param, typeParams, importer)); + path.get('elementTypes').forEach(param => { + type.elements.push(getTSTypeWithResolvedTypes(param, typeParams)); }); return type; } function handleTSTypeQuery( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor { - const resolvedPath = resolveToValue(path.get('exprName'), importer); - if (resolvedPath && resolvedPath.node.typeAnnotation) { + const resolvedPath = resolveToValue(path.get('exprName')); + if ('typeAnnotation' in resolvedPath.node) { return getTSTypeWithResolvedTypes( - resolvedPath.get('typeAnnotation'), + resolvedPath.get('typeAnnotation') as NodePath, typeParams, - importer, ); } - + // @ts-ignore Do we need to handle TsQualifiedName here TODO return { name: path.node.exprName.name }; } function handleTSTypeOperator( - path: NodePath, - _typeParams: TypeParameters | null, - importer: Importer, + path: NodePath, ): TypeDescriptor | null { if (path.node.operator !== 'keyof') { return null; } - let value = path.get('typeAnnotation'); - if (t.TSTypeQuery.check(value.node)) { + let value: NodePath = path.get('typeAnnotation'); + if (value.isTSTypeQuery()) { value = value.get('exprName'); - } else if (value.node.id) { - value = value.get('id'); + } else if ('id' in value.node) { + value = value.get('id') as NodePath; } - const resolvedPath = resolveToValue(value, importer); + const resolvedPath = resolveToValue(value); if ( resolvedPath && - (t.ObjectExpression.check(resolvedPath.node) || - t.TSTypeLiteral.check(resolvedPath.node)) + (resolvedPath.isObjectExpression() || resolvedPath.isTSTypeLiteral()) ) { - const keys = resolveObjectToNameArray(resolvedPath, importer, true); + const keys = resolveObjectToNameArray(resolvedPath, true); if (keys) { return { @@ -373,19 +398,16 @@ function handleTSTypeOperator( } function handleTSIndexedAccessType( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): SimpleType { const objectType = getTSTypeWithResolvedTypes( path.get('objectType'), typeParams, - importer, ) as ObjectSignatureType; const indexType = getTSTypeWithResolvedTypes( path.get('indexType'), typeParams, - importer, ) as LiteralType; // We only get the signature if the objectType is a type (vs interface) @@ -409,53 +431,61 @@ function handleTSIndexedAccessType( }; } -let visitedTypes = {}; +let visitedTypes: Record< + string, + TypeDescriptor | true +> = {}; function getTSTypeWithResolvedTypes( - path: NodePath, + path: NodePath, typeParams: TypeParameters | null, - importer: Importer, ): TypeDescriptor { - if (t.TSTypeAnnotation.check(path.node)) { + if (path.isTSTypeAnnotation()) { path = path.get('typeAnnotation'); } const node = path.node; let type: TypeDescriptor; - const isTypeAlias = t.TSTypeAliasDeclaration.check(path.parentPath.node); + let typeAliasName: string | null = null; + if (path.parentPath.isTSTypeAliasDeclaration()) { + typeAliasName = path.parentPath.node.id.name; + } // When we see a typealias mark it as visited so that the next // call of this function does not run into an endless loop - if (isTypeAlias) { - if (visitedTypes[path.parentPath.node.id.name] === true) { + if (typeAliasName) { + if (visitedTypes[typeAliasName] === true) { // if we are currently visiting this node then just return the name // as we are starting to endless loop - return { name: path.parentPath.node.id.name }; - } else if (typeof visitedTypes[path.parentPath.node.id.name] === 'object') { + return { name: typeAliasName }; + } else if (typeof visitedTypes[typeAliasName] === 'object') { // if we already resolved the type simple return it - return visitedTypes[path.parentPath.node.id.name]; + return visitedTypes[ + typeAliasName + ] as TypeDescriptor; } // mark the type as visited - visitedTypes[path.parentPath.node.id.name] = true; + visitedTypes[typeAliasName] = true; } if (node.type in tsTypes) { type = { name: tsTypes[node.type] }; - } else if (t.TSLiteralType.check(node)) { + } else if (path.isTSLiteralType()) { + const literal = path.get('literal'); type = { name: 'literal', - // @ts-ignore - value: node.literal.raw || `${node.literal.value}`, + // @ts-ignore TODO create test for UnaryExpression (eg. -2 as literal) + value: (literal.node.extra?.raw as string) || `${literal.node.value}`, }; } else if (node.type in namedTypes) { - type = namedTypes[node.type](path, typeParams, importer); + type = namedTypes[node.type](path, typeParams); } else { type = { name: 'unknown' }; } - if (isTypeAlias) { + if (typeAliasName) { // mark the type as unvisited so that further calls can resolve the type again - visitedTypes[path.parentPath.node.id.name] = type; + visitedTypes[typeAliasName] = type; } return type; @@ -469,15 +499,14 @@ function getTSTypeWithResolvedTypes( * If there is no match, "unknown" is returned. */ export default function getTSType( - path: NodePath, - typeParamMap: TypeParameters | null, - importer: Importer, + path: NodePath, + typeParamMap: TypeParameters | null = null, ): TypeDescriptor { // Empty visited types before an after run // Before: in case the detection threw and we rerun again // After: cleanup memory after we are done here visitedTypes = {}; - const type = getTSTypeWithResolvedTypes(path, typeParamMap, importer); + const type = getTSTypeWithResolvedTypes(path, typeParamMap); visitedTypes = {}; return type; diff --git a/src/utils/getTypeAnnotation.ts b/src/utils/getTypeAnnotation.ts index ff1d999c915..bd8a178e9e9 100644 --- a/src/utils/getTypeAnnotation.ts +++ b/src/utils/getTypeAnnotation.ts @@ -1,25 +1,24 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; - -function hasTypeAnnotation(path: NodePath): boolean { - return !!path.node.typeAnnotation; -} +import type { NodePath } from '@babel/traverse'; +import type { FlowType } from '@babel/types'; /** * Gets the most inner valuable TypeAnnotation from path. If no TypeAnnotation * can be found null is returned */ -export default function getTypeAnnotation(path: NodePath): NodePath | null { - if (!hasTypeAnnotation(path)) return null; +export default function getTypeAnnotation( + path: NodePath, +): NodePath | null { + if (!path.has('typeAnnotation')) return null; - let resultPath: NodePath = path; + let resultPath = path; do { - resultPath = resultPath.get('typeAnnotation'); + resultPath = resultPath.get('typeAnnotation') as NodePath; } while ( - hasTypeAnnotation(resultPath) && - !t.FlowType.check(resultPath.node) && - !t.TSType.check(resultPath.node) + resultPath.has('typeAnnotation') && + !resultPath.isFlowType() && + !resultPath.isTSType() ); + // @ts-ignore return resultPath; } diff --git a/src/utils/getTypeFromReactComponent.ts b/src/utils/getTypeFromReactComponent.ts new file mode 100644 index 00000000000..e72812cfc64 --- /dev/null +++ b/src/utils/getTypeFromReactComponent.ts @@ -0,0 +1,160 @@ +import type { NodePath } from '@babel/traverse'; +import type Documentation from '../Documentation'; +import getMemberValuePath from './getMemberValuePath'; +import getTypeAnnotation from './getTypeAnnotation'; +import getTypeParameters from './getTypeParameters'; +import isReactComponentClass from './isReactComponentClass'; +import isReactForwardRefCall from './isReactForwardRefCall'; +import resolveGenericTypeAnnotation from './resolveGenericTypeAnnotation'; +import resolveToValue from './resolveToValue'; +import type { TypeParameters } from './getTypeParameters'; +import type { + FlowType, + InterfaceDeclaration, + InterfaceExtends, + TSExpressionWithTypeArguments, + TSInterfaceDeclaration, + TSType, + TSTypeParameterDeclaration, + TSTypeParameterInstantiation, + TypeParameterDeclaration, + TypeParameterInstantiation, +} from '@babel/types'; +import getTypeIdentifier from './getTypeIdentifier'; + +// TODO TESTME + +function getStatelessPropsPath(componentDefinition: NodePath): NodePath { + const value = resolveToValue(componentDefinition); + if (isReactForwardRefCall(value)) { + const inner = resolveToValue(value.get('arguments')[0]); + return inner.get('params')[0]; + } + return value.get('params')[0]; +} + +/** + * Given an React component (stateless or class) tries to find the + * flow type for the props. If not found or not one of the supported + * component types returns null. + */ +export default (path: NodePath): NodePath | null => { + let typePath: NodePath | null = null; + + if (isReactComponentClass(path)) { + const superTypes = path.get('superTypeParameters'); + + if (superTypes.node) { + const params = ( + superTypes as NodePath< + TSTypeParameterInstantiation | TypeParameterInstantiation + > + ).get('params'); + typePath = params[params.length === 3 ? 1 : 0]; + } else { + const propsMemberPath = getMemberValuePath(path, 'props'); + if (!propsMemberPath) { + return null; + } + + typePath = getTypeAnnotation(propsMemberPath.parentPath); + } + + return typePath; + } + + const propsParam = getStatelessPropsPath(path); + + if (propsParam) { + typePath = getTypeAnnotation(propsParam); + } + + return typePath; +}; + +export function applyToTypeProperties( + documentation: Documentation, + path: NodePath, + callback: (propertyPath: NodePath, params: TypeParameters | null) => void, + typeParams: TypeParameters | null, +): void { + if (path.isObjectTypeAnnotation()) { + path + .get('properties') + .forEach(propertyPath => callback(propertyPath, typeParams)); + } else if (path.isTSTypeLiteral()) { + path + .get('members') + .forEach(propertyPath => callback(propertyPath, typeParams)); + } else if (path.isInterfaceDeclaration()) { + if (path.node.extends) { + applyExtends(documentation, path, callback, typeParams); + } + + path + .get('body') + .get('properties') + .forEach(propertyPath => callback(propertyPath, typeParams)); + } else if (path.isTSInterfaceDeclaration()) { + if (path.node.extends) { + applyExtends(documentation, path, callback, typeParams); + } + + path + .get('body') + .get('body') + .forEach(propertyPath => callback(propertyPath, typeParams)); + } else if ( + path.isIntersectionTypeAnnotation() || + path.isTSIntersectionType() + ) { + (path.get('types') as Array>).forEach( + typesPath => + applyToTypeProperties(documentation, typesPath, callback, typeParams), + ); + } else if (!path.isUnionTypeAnnotation()) { + // The react-docgen output format does not currently allow + // for the expression of union types + const typePath = resolveGenericTypeAnnotation(path); + if (typePath) { + applyToTypeProperties(documentation, typePath, callback, typeParams); + } + } +} + +function applyExtends( + documentation: Documentation, + path: NodePath, + callback: (propertyPath: NodePath, params: TypeParameters | null) => void, + typeParams: TypeParameters | null, +) { + ( + path.get('extends') as Array< + NodePath + > + ).forEach(extendsPath => { + const resolvedPath = resolveGenericTypeAnnotation(extendsPath); + if (resolvedPath) { + if ( + resolvedPath.has('typeParameters') && + extendsPath.node.typeParameters + ) { + typeParams = getTypeParameters( + resolvedPath.get('typeParameters') as NodePath< + TSTypeParameterDeclaration | TypeParameterDeclaration + >, + extendsPath.get('typeParameters') as NodePath< + TSTypeParameterInstantiation | TypeParameterInstantiation + >, + typeParams, + ); + } + applyToTypeProperties(documentation, resolvedPath, callback, typeParams); + } else { + const idPath = getTypeIdentifier(extendsPath); + if (idPath && idPath.isIdentifier()) { + documentation.addComposes(idPath.node.name); + } + } + }); +} diff --git a/src/utils/getTypeIdentifier.ts b/src/utils/getTypeIdentifier.ts new file mode 100644 index 00000000000..99e3f1c154f --- /dev/null +++ b/src/utils/getTypeIdentifier.ts @@ -0,0 +1,13 @@ +import type { NodePath } from '@babel/traverse'; + +export default function getTypeIdentifier(path: NodePath): NodePath | null { + if (path.has('id')) { + return path.get('id') as NodePath; + } else if (path.isTSTypeReference()) { + return path.get('typeName'); + } else if (path.isTSExpressionWithTypeArguments()) { + return path.get('expression'); + } + + return null; +} diff --git a/src/utils/getTypeParameters.ts b/src/utils/getTypeParameters.ts index 929c1011535..23fefb6e5fe 100644 --- a/src/utils/getTypeParameters.ts +++ b/src/utils/getTypeParameters.ts @@ -1,36 +1,61 @@ import resolveGenericTypeAnnotation from '../utils/resolveGenericTypeAnnotation'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { + FlowType, + Identifier, + QualifiedTypeIdentifier, + TSQualifiedName, + TSTypeParameterDeclaration, + TSTypeParameterInstantiation, + TypeParameterDeclaration, + TypeParameterInstantiation, +} from '@babel/types'; + +// TODO needs tests TS && flow export type TypeParameters = Record; export default function getTypeParameters( - declaration: NodePath, - instantiation: NodePath, + declaration: NodePath, + instantiation: NodePath< + TSTypeParameterInstantiation | TypeParameterInstantiation + >, inputParams: TypeParameters | null | undefined, - importer: Importer, ): TypeParameters { - const params = {}; + const params: TypeParameters = {}; const numInstantiationParams = instantiation.node.params.length; let i = 0; - declaration.get('params').each((paramPath: NodePath) => { + declaration.get('params').forEach(paramPath => { const key = paramPath.node.name; const defaultTypePath = paramPath.node.default - ? paramPath.get('default') + ? (paramPath.get('default') as NodePath) : null; const typePath = i < numInstantiationParams - ? instantiation.get('params', i++) + ? instantiation.get('params')[i++] : defaultTypePath; if (typePath) { - let resolvedTypePath = - resolveGenericTypeAnnotation(typePath, importer) || typePath; - const typeName = - resolvedTypePath.node.typeName || resolvedTypePath.node.id; - if (typeName && inputParams && inputParams[typeName.name]) { - resolvedTypePath = inputParams[typeName.name]; + let resolvedTypePath: NodePath = + resolveGenericTypeAnnotation(typePath) || typePath; + let typeName: + | NodePath + | undefined; + + if (resolvedTypePath.isTSTypeReference()) { + typeName = resolvedTypePath.get('typeName'); + } else if (resolvedTypePath.isGenericTypeAnnotation()) { + typeName = resolvedTypePath.get('id'); + } + + if ( + typeName && + inputParams && + typeName.isIdentifier() && + inputParams[typeName.node.name] + ) { + resolvedTypePath = inputParams[typeName.node.name]; } params[key] = resolvedTypePath; diff --git a/src/utils/index.ts b/src/utils/index.ts index 609305842da..d4feccddcfa 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,30 +1,66 @@ import * as docblock from './docblock'; +import * as expressionTo from './expressionTo'; +import * as flowUtilityTypes from './flowUtilityTypes'; +import * as traverse from './traverse'; -export { docblock }; +export { docblock, expressionTo, flowUtilityTypes, traverse }; export { default as getClassMemberValuePath } from './getClassMemberValuePath'; export { default as getFlowType } from './getFlowType'; -export { default as getFlowTypeFromReactComponent } from './getFlowTypeFromReactComponent'; export { default as getMemberExpressionRoot } from './getMemberExpressionRoot'; +export { default as getMemberExpressionValuePath } from './getMemberExpressionValuePath'; export { default as getMembers } from './getMembers'; -export { default as getMemberValuePath } from './getMemberValuePath'; +export { + default as getMemberValuePath, + isSupportedDefinitionType, +} from './getMemberValuePath'; export { default as getMethodDocumentation } from './getMethodDocumentation'; +export type { MethodNodePath } from './getMethodDocumentation'; export { default as getNameOrValue } from './getNameOrValue'; export { default as getParameterName } from './getParameterName'; -export { default as getPropertyName } from './getPropertyName'; +export { default as getPropertyName, COMPUTED_PREFIX } from './getPropertyName'; export { default as getPropertyValuePath } from './getPropertyValuePath'; export { default as getPropType } from './getPropType'; +export { default as getTSType } from './getTSType'; export { default as getTypeAnnotation } from './getTypeAnnotation'; +export { + default as getTypeFromReactComponent, + applyToTypeProperties, +} from './getTypeFromReactComponent'; +export { default as getTypeIdentifier } from './getTypeIdentifier'; +export { default as getTypeParameters } from './getTypeParameters'; +export type { TypeParameters } from './getTypeParameters'; +export { default as isDestructuringAssignment } from './isDestructuringAssignment'; export { default as isExportsOrModuleAssignment } from './isExportsOrModuleAssignment'; +export { default as isReactBuiltinCall } from './isReactBuiltinCall'; +export { default as isReactChildrenElementCall } from './isReactChildrenElementCall'; +export { default as isReactCloneElementCall } from './isReactCloneElementCall'; export { default as isReactComponentClass } from './isReactComponentClass'; export { default as isReactComponentMethod } from './isReactComponentMethod'; export { default as isReactCreateClassCall } from './isReactCreateClassCall'; +export { default as isReactCreateElementCall } from './isReactCreateElementCall'; export { default as isReactForwardRefCall } from './isReactForwardRefCall'; export { default as isReactModuleName } from './isReactModuleName'; +export { default as isRequiredPropType } from './isRequiredPropType'; export { default as isStatelessComponent } from './isStatelessComponent'; +export { default as isUnreachableFlowType } from './isUnreachableFlowType'; export { default as match } from './match'; export { default as normalizeClassDefinition } from './normalizeClassDefinition'; +export { default as parseJsDoc } from './parseJsDoc'; +export { default as postProcessDocumentation } from './postProcessDocumentation'; export { default as printValue } from './printValue'; export { default as resolveExportDeclaration } from './resolveExportDeclaration'; +export { default as resolveFunctionDefinitionToReturnValue } from './resolveFunctionDefinitionToReturnValue'; +export { default as resolveGenericTypeAnnotation } from './resolveGenericTypeAnnotation'; +export { default as resolveHOC } from './resolveHOC'; +export { + default as resolveObjectKeysToArray, + resolveObjectToNameArray, +} from './resolveObjectKeysToArray'; +export { + default as resolveObjectValuesToArray, + resolveObjectToPropMap, +} from './resolveObjectValuesToArray'; export { default as resolveToModule } from './resolveToModule'; export { default as resolveToValue } from './resolveToValue'; +export { default as setPropDescription } from './setPropDescription'; diff --git a/src/utils/isDestructuringAssignment.ts b/src/utils/isDestructuringAssignment.ts index 49035dd6c21..a7f9af53f6c 100644 --- a/src/utils/isDestructuringAssignment.ts +++ b/src/utils/isDestructuringAssignment.ts @@ -1,5 +1,4 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; /** * Checks if the input Identifier is part of a destructuring Assignment @@ -9,10 +8,15 @@ export default function isDestructuringAssignment( path: NodePath, name: string, ): boolean { + if (!path.isObjectProperty()) { + return false; + } + + const id = path.get('key'); + return ( - t.Identifier.check(path.node) && - t.Property.check(path.parentPath.node) && - path.parentPath.node.key.name === name && - t.ObjectPattern.check(path.parentPath.parentPath.node) + id.isIdentifier() && + id.node.name === name && + path.parentPath.isObjectPattern() ); } diff --git a/src/utils/isExportsOrModuleAssignment.ts b/src/utils/isExportsOrModuleAssignment.ts index bca8dd10fd2..30b84b07aa5 100644 --- a/src/utils/isExportsOrModuleAssignment.ts +++ b/src/utils/isExportsOrModuleAssignment.ts @@ -1,27 +1,22 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; import * as expressionTo from './expressionTo'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; /** * Returns true if the expression is of form `exports.foo = ...;` or * `modules.exports = ...;`. */ -export default function isExportsOrModuleAssignment( - path: NodePath, - importer: Importer, -): boolean { - if (t.ExpressionStatement.check(path.node)) { +export default function isExportsOrModuleAssignment(path: NodePath): boolean { + if (path.isExpressionStatement()) { path = path.get('expression'); } if ( - !t.AssignmentExpression.check(path.node) || - !t.MemberExpression.check(path.node.left) + !path.isAssignmentExpression() || + !path.get('left').isMemberExpression() ) { return false; } - const exprArr = expressionTo.Array(path.get('left'), importer); + const exprArr = expressionTo.Array(path.get('left')); return ( (exprArr[0] === 'module' && exprArr[1] === 'exports') || exprArr[0] === 'exports' diff --git a/src/utils/isReactBuiltinCall.ts b/src/utils/isReactBuiltinCall.ts index e6adee99213..294f50a2500 100644 --- a/src/utils/isReactBuiltinCall.ts +++ b/src/utils/isReactBuiltinCall.ts @@ -1,11 +1,44 @@ -import { namedTypes as t } from 'ast-types'; import isReactModuleName from './isReactModuleName'; import match from './match'; import resolveToModule from './resolveToModule'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; import isDestructuringAssignment from './isDestructuringAssignment'; +import type { NodePath } from '@babel/traverse'; +import type { CallExpression, MemberExpression } from '@babel/types'; + +function isNamedMemberExpression(value: NodePath, name: string): boolean { + if (!value.isMemberExpression()) { + return false; + } + + const property = value.get('property'); + + return property.isIdentifier() && property.node.name === name; +} + +function isNamedImportDeclaration( + value: NodePath, + callee: NodePath, + name: string, +): boolean { + if (!value.isImportDeclaration() || !callee.isIdentifier()) { + return false; + } + + return value.get('specifiers').some(specifier => { + if (!specifier.isImportSpecifier()) { + return false; + } + const imported = specifier.get('imported'); + const local = specifier.get('local'); + + return ( + ((imported.isIdentifier() && imported.node.name === name) || + (imported.isStringLiteral() && imported.node.value === name)) && + local.node.name === callee.node.name + ); + }); +} /** * Returns true if the expression is a function call of the form @@ -14,40 +47,34 @@ import isDestructuringAssignment from './isDestructuringAssignment'; export default function isReactBuiltinCall( path: NodePath, name: string, - importer: Importer, ): boolean { - if (t.ExpressionStatement.check(path.node)) { + if (path.isExpressionStatement()) { path = path.get('expression'); } - if (match(path.node, { callee: { property: { name } } })) { - const module = resolveToModule(path.get('callee', 'object'), importer); - return Boolean(module && isReactModuleName(module)); - } + if (path.isCallExpression()) { + if (match(path.node, { callee: { property: { name } } })) { + const module = resolveToModule( + (path.get('callee') as NodePath).get('object'), + ); - if (t.CallExpression.check(path.node)) { - const value = resolveToValue(path.get('callee'), importer); - if (value === path.get('callee')) return false; + return Boolean(module && isReactModuleName(module)); + } + + const value = resolveToValue(path.get('callee')); + if (value === path.get('callee')) { + return false; + } - // Check if this is a destructuring assignment - // const { x } = require('react') if ( + // const { x } = require('react') isDestructuringAssignment(value, name) || // `require('react').createElement` - (t.MemberExpression.check(value.node) && - t.Identifier.check(value.get('property').node) && - value.get('property').node.name === name) || + isNamedMemberExpression(value, name) || // `import { createElement } from 'react'` - (t.ImportDeclaration.check(value.node) && - value.node.specifiers && - value.node.specifiers.some( - specifier => - // @ts-ignore - specifier.imported?.name === name && - specifier.local?.name === path.node.callee.name, - )) + isNamedImportDeclaration(value, path.get('callee'), name) ) { - const module = resolveToModule(value, importer); + const module = resolveToModule(value); return Boolean(module && isReactModuleName(module)); } diff --git a/src/utils/isReactChildrenElementCall.ts b/src/utils/isReactChildrenElementCall.ts index 536613260dd..97d9a561875 100644 --- a/src/utils/isReactChildrenElementCall.ts +++ b/src/utils/isReactChildrenElementCall.ts @@ -1,19 +1,17 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { MemberExpression } from '@babel/types'; import isReactModuleName from './isReactModuleName'; import match from './match'; import resolveToModule from './resolveToModule'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; + +// TODO unit tests /** * Returns true if the expression is a function call of the form * `React.Children.only(...)`. */ -export default function isReactChildrenElementCall( - path: NodePath, - importer: Importer, -): boolean { - if (t.ExpressionStatement.check(path.node)) { +export default function isReactChildrenElementCall(path: NodePath): boolean { + if (path.isExpressionStatement()) { path = path.get('expression'); } @@ -21,12 +19,15 @@ export default function isReactChildrenElementCall( return false; } - const calleeObj = path.get('callee', 'object'); - const module = resolveToModule(calleeObj, importer); + const calleeObj = (path.get('callee') as NodePath).get( + 'object', + ); - if (!match(calleeObj, { value: { property: { name: 'Children' } } })) { + if (!match(calleeObj.node, { property: { name: 'Children' } })) { return false; } + const module = resolveToModule(calleeObj); + return Boolean(module && isReactModuleName(module)); } diff --git a/src/utils/isReactCloneElementCall.ts b/src/utils/isReactCloneElementCall.ts index cdfa5988423..ce4265cade1 100644 --- a/src/utils/isReactCloneElementCall.ts +++ b/src/utils/isReactCloneElementCall.ts @@ -1,14 +1,13 @@ +import type { NodePath } from '@babel/traverse'; +import type { Expression, ExpressionStatement } from '@babel/types'; import isReactBuiltinCall from './isReactBuiltinCall'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; /** * Returns true if the expression is a function call of the form * `React.cloneElement(...)`. */ export default function isReactCloneElementCall( - path: NodePath, - importer: Importer, + path: NodePath, ): boolean { - return isReactBuiltinCall(path, 'cloneElement', importer); + return isReactBuiltinCall(path, 'cloneElement'); } diff --git a/src/utils/isReactComponentClass.ts b/src/utils/isReactComponentClass.ts index 3069633f0d3..c999bf1bc89 100644 --- a/src/utils/isReactComponentClass.ts +++ b/src/utils/isReactComponentClass.ts @@ -1,25 +1,34 @@ -import { ASTNode, namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; +import type { + ClassBody, + ClassDeclaration, + ClassExpression, + ClassMethod, +} from '@babel/types'; import isReactModuleName from './isReactModuleName'; import match from './match'; import resolveToModule from './resolveToModule'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; import isDestructuringAssignment from './isDestructuringAssignment'; -function isRenderMethod(node: ASTNode): boolean { - const isProperty = node.type === 'ClassProperty'; - return Boolean( - (t.MethodDefinition.check(node) || isProperty) && - // @ts-ignore - !node.computed && - // @ts-ignore - !node.static && - // @ts-ignore - (node.kind === '' || node.kind === 'method' || isProperty) && - // @ts-ignore - node.key.name === 'render', - ); +function isRenderMethod(path: NodePath): boolean { + if ( + (!path.isClassMethod() || path.node.kind !== 'method') && + !path.isClassProperty() + ) { + return false; + } + + if (path.node.computed || path.node.static) { + return false; + } + + const key = path.get('key') as NodePath; + if (!key.isIdentifier() || key.node.name !== 'render') { + return false; + } + + return true; } /** @@ -28,54 +37,46 @@ function isRenderMethod(node: ASTNode): boolean { */ export default function isReactComponentClass( path: NodePath, - importer: Importer, -): boolean { - const node = path.node; - if (!t.ClassDeclaration.check(node) && !t.ClassExpression.check(node)) { +): path is NodePath { + if (!path.isClassDeclaration() && !path.isClassExpression()) { return false; } // extends something - if (!node.superClass) { + if (!path.node.superClass) { return false; } // React.Component or React.PureComponent - const superClass = resolveToValue(path.get('superClass'), importer); + const superClass = resolveToValue(path.get('superClass') as NodePath); + if ( match(superClass.node, { property: { name: 'Component' } }) || match(superClass.node, { property: { name: 'PureComponent' } }) || isDestructuringAssignment(superClass, 'Component') || isDestructuringAssignment(superClass, 'PureComponent') ) { - const module = resolveToModule(superClass, importer); + const module = resolveToModule(superClass); if (module && isReactModuleName(module)) { return true; } } // render method - if (node.body.body.some(isRenderMethod)) { + if ( + (path.get('body') as NodePath).get('body').some(isRenderMethod) + ) { return true; } // check for @extends React.Component in docblock - if (path.parentPath && path.parentPath.value) { - const classDeclaration = Array.isArray(path.parentPath.value) - ? path.parentPath.value.find(function (declaration) { - return declaration.type === 'ClassDeclaration'; - }) - : path.parentPath.value; - - if ( - classDeclaration && - classDeclaration.leadingComments && - classDeclaration.leadingComments.some(function (comment) { - return /@extends\s+React\.Component/.test(comment.value); - }) - ) { - return true; - } + if ( + path.node.leadingComments && + path.node.leadingComments.some(function (comment) { + return /@extends\s+React\.Component/.test(comment.value); + }) + ) { + return true; } return false; diff --git a/src/utils/isReactComponentMethod.ts b/src/utils/isReactComponentMethod.ts index c87e30dad86..823d06edea9 100644 --- a/src/utils/isReactComponentMethod.ts +++ b/src/utils/isReactComponentMethod.ts @@ -1,7 +1,5 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; import getPropertyName from './getPropertyName'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; const componentMethods = [ 'componentDidMount', @@ -28,14 +26,11 @@ const componentMethods = [ /** * Returns if the method path is a Component method. */ -export default function (methodPath: NodePath, importer: Importer): boolean { - if ( - !t.MethodDefinition.check(methodPath.node) && - !t.Property.check(methodPath.node) - ) { +export default function (methodPath: NodePath): boolean { + if (!methodPath.isClassMethod() && !methodPath.isObjectMethod()) { return false; } - const name = getPropertyName(methodPath, importer); - return !!name && componentMethods.indexOf(name) !== -1; + const name = getPropertyName(methodPath); + return Boolean(name && componentMethods.indexOf(name) !== -1); } diff --git a/src/utils/isReactCreateClassCall.ts b/src/utils/isReactCreateClassCall.ts index 38e5a4cb574..8aaf9f33781 100644 --- a/src/utils/isReactCreateClassCall.ts +++ b/src/utils/isReactCreateClassCall.ts @@ -1,8 +1,6 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; import resolveToModule from './resolveToModule'; import isReactBuiltinCall from './isReactBuiltinCall'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; /** * Returns true if the expression is a function call of the form @@ -11,18 +9,15 @@ import type { NodePath } from 'ast-types/lib/node-path'; * createReactClass(...); * ``` */ -function isReactCreateClassCallModular( - path: NodePath, - importer: Importer, -): boolean { - if (t.ExpressionStatement.check(path.node)) { +function isReactCreateClassCallModular(path: NodePath): boolean { + if (path.isExpressionStatement()) { path = path.get('expression'); } - if (!t.CallExpression.check(path.node)) { + if (!path.isCallExpression()) { return false; } - const module = resolveToModule(path, importer); + const module = resolveToModule(path); return Boolean(module && module === 'create-react-class'); } @@ -34,12 +29,9 @@ function isReactCreateClassCallModular( * createReactClass(...); * ``` */ -export default function isReactCreateClassCall( - path: NodePath, - importer: Importer, -): boolean { +export default function isReactCreateClassCall(path: NodePath): boolean { return ( - isReactBuiltinCall(path, 'createClass', importer) || - isReactCreateClassCallModular(path, importer) + isReactBuiltinCall(path, 'createClass') || + isReactCreateClassCallModular(path) ); } diff --git a/src/utils/isReactCreateElementCall.ts b/src/utils/isReactCreateElementCall.ts index fa38ce452b1..51cc90270bb 100644 --- a/src/utils/isReactCreateElementCall.ts +++ b/src/utils/isReactCreateElementCall.ts @@ -1,14 +1,13 @@ +import type { NodePath } from '@babel/traverse'; +import type { Expression, ExpressionStatement } from '@babel/types'; import isReactBuiltinCall from './isReactBuiltinCall'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; /** * Returns true if the expression is a function call of the form * `React.createElement(...)`. */ export default function isReactCreateElementCall( - path: NodePath, - importer: Importer, + path: NodePath, ): boolean { - return isReactBuiltinCall(path, 'createElement', importer); + return isReactBuiltinCall(path, 'createElement'); } diff --git a/src/utils/isReactForwardRefCall.ts b/src/utils/isReactForwardRefCall.ts index d07d41fbfca..c89e2284212 100644 --- a/src/utils/isReactForwardRefCall.ts +++ b/src/utils/isReactForwardRefCall.ts @@ -1,14 +1,10 @@ +import type { NodePath } from '@babel/traverse'; import isReactBuiltinCall from './isReactBuiltinCall'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; /** * Returns true if the expression is a function call of the form * `React.forwardRef(...)`. */ -export default function isReactForwardRefCall( - path: NodePath, - importer: Importer, -): boolean { - return isReactBuiltinCall(path, 'forwardRef', importer); +export default function isReactForwardRefCall(path: NodePath): boolean { + return isReactBuiltinCall(path, 'forwardRef'); } diff --git a/src/utils/isReactModuleName.ts b/src/utils/isReactModuleName.ts index a14f732a339..8705c1712b8 100644 --- a/src/utils/isReactModuleName.ts +++ b/src/utils/isReactModuleName.ts @@ -9,9 +9,9 @@ const reactModules = [ /** * Takes a module name (string) and returns true if it refers to a root react * module name. + * + * TODO TESTME */ export default function isReactModuleName(moduleName: string): boolean { - return reactModules.some(function (reactModuleName) { - return reactModuleName === moduleName.toLowerCase(); - }); + return reactModules.includes(moduleName.toLowerCase()); } diff --git a/src/utils/isRequiredPropType.ts b/src/utils/isRequiredPropType.ts index 52be3b37d5e..b5ac307a7a0 100644 --- a/src/utils/isRequiredPropType.ts +++ b/src/utils/isRequiredPropType.ts @@ -1,13 +1,15 @@ -import type { NodePath } from 'ast-types/lib/node-path'; +import type { Node, NodePath } from '@babel/traverse'; import getMembers from '../utils/getMembers'; /** * Returns true of the prop is required, according to its type definition */ -export default function isRequiredPropType(path: NodePath): boolean { +export default function isRequiredPropType(path: NodePath): boolean { return getMembers(path).some( - member => - (!member.computed && member.path.node.name === 'isRequired') || - (member.computed && member.path.node.value === 'isRequired'), + ({ computed, path: memberPath }) => + (!computed && + memberPath.isIdentifier() && + memberPath.node.name === 'isRequired') || + (memberPath.isStringLiteral() && memberPath.node.value === 'isRequired'), ); } diff --git a/src/utils/isStatelessComponent.ts b/src/utils/isStatelessComponent.ts index 262998c854d..54236419c80 100644 --- a/src/utils/isStatelessComponent.ts +++ b/src/utils/isStatelessComponent.ts @@ -1,37 +1,33 @@ -import { namedTypes as t, visit } from 'ast-types'; import getPropertyValuePath from './getPropertyValuePath'; -import isReactComponentClass from './isReactComponentClass'; import isReactCreateClassCall from './isReactCreateClassCall'; import isReactCreateElementCall from './isReactCreateElementCall'; import isReactCloneElementCall from './isReactCloneElementCall'; import isReactChildrenElementCall from './isReactChildrenElementCall'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { Expression, ObjectExpression } from '@babel/types'; const validPossibleStatelessComponentTypes = [ - 'Property', + 'ObjectMethod', + 'ObjectProperty', 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression', ]; -function isJSXElementOrReactCall(path: NodePath, importer: Importer): boolean { +function isJSXElementOrReactCall(path: NodePath): boolean { return ( - path.node.type === 'JSXElement' || - path.node.type === 'JSXFragment' || - (path.node.type === 'CallExpression' && - isReactCreateElementCall(path, importer)) || - (path.node.type === 'CallExpression' && - isReactCloneElementCall(path, importer)) || - (path.node.type === 'CallExpression' && - isReactChildrenElementCall(path, importer)) + path.isJSXElement() || + path.isJSXFragment() || + (path.isCallExpression() && + (isReactCreateElementCall(path) || + isReactCloneElementCall(path) || + isReactChildrenElementCall(path))) ); } function resolvesToJSXElementOrReactCall( path: NodePath, - importer: Importer, seen: WeakSet, ): boolean { // avoid returns with recursive function calls @@ -42,24 +38,24 @@ function resolvesToJSXElementOrReactCall( seen.add(path); // Is the path is already a JSX element or a call to one of the React.* functions - if (isJSXElementOrReactCall(path, importer)) { + if (isJSXElementOrReactCall(path)) { return true; } - const resolvedPath = resolveToValue(path, importer); + const resolvedPath = resolveToValue(path); // If the path points to a conditional expression, then we need to look only at // the two possible paths - if (resolvedPath.node.type === 'ConditionalExpression') { + if (resolvedPath.isConditionalExpression()) { return ( resolvesToJSXElementOrReactCall( resolvedPath.get('consequent'), - importer, + seen, ) || resolvesToJSXElementOrReactCall( resolvedPath.get('alternate'), - importer, + seen, ) ); @@ -67,74 +63,78 @@ function resolvesToJSXElementOrReactCall( // If the path points to a logical expression (AND, OR, ...), then we need to look only at // the two possible paths - if (resolvedPath.node.type === 'LogicalExpression') { + if (resolvedPath.isLogicalExpression()) { return ( resolvesToJSXElementOrReactCall( resolvedPath.get('left'), - importer, + seen, - ) || - resolvesToJSXElementOrReactCall(resolvedPath.get('right'), importer, seen) + ) || resolvesToJSXElementOrReactCall(resolvedPath.get('right'), seen) ); } // Is the resolved path is already a JSX element or a call to one of the React.* functions // Only do this if the resolvedPath actually resolved something as otherwise we did this check already - if ( - resolvedPath !== path && - isJSXElementOrReactCall(resolvedPath, importer) - ) { + if (resolvedPath !== path && isJSXElementOrReactCall(resolvedPath)) { return true; } // If we have a call expression, lets try to follow it - if (resolvedPath.node.type === 'CallExpression') { - let calleeValue = resolveToValue(resolvedPath.get('callee'), importer); + if (resolvedPath.isCallExpression()) { + let calleeValue = resolveToValue(resolvedPath.get('callee')); - if (returnsJSXElementOrReactCall(calleeValue, importer, seen)) { + if (returnsJSXElementOrReactCall(calleeValue, seen)) { return true; } - let resolvedValue; + if (calleeValue.isMemberExpression()) { + let resolvedValue: NodePath | undefined; + const namesToResolve: NodePath[] = []; - const namesToResolve = [calleeValue.get('property')]; - - if (calleeValue.node.type === 'MemberExpression') { - if (calleeValue.get('object').node.type === 'Identifier') { - resolvedValue = resolveToValue(calleeValue.get('object'), importer); - } else if (t.MemberExpression.check(calleeValue.node)) { + const calleeObj = calleeValue.get('object'); + if (calleeObj.isIdentifier()) { + namesToResolve.push(calleeValue.get('property')); + resolvedValue = resolveToValue(calleeObj); + } else { do { - calleeValue = calleeValue.get('object'); namesToResolve.unshift(calleeValue.get('property')); - } while (t.MemberExpression.check(calleeValue.node)); + calleeValue = calleeValue.get('object'); + } while (calleeValue.isMemberExpression()); - resolvedValue = resolveToValue(calleeValue.get('object'), importer); + resolvedValue = resolveToValue(calleeValue); } - } - - if (resolvedValue && t.ObjectExpression.check(resolvedValue.node)) { - const resolvedMemberExpression = namesToResolve.reduce( - (result, nodePath) => { - if (!nodePath) { - return result; - } - if (result) { - result = getPropertyValuePath(result, nodePath.node.name, importer); - if (result && t.Identifier.check(result.node)) { - return resolveToValue(result, importer); + if (resolvedValue && resolvedValue.isObjectExpression()) { + const resolvedMemberExpression = namesToResolve.reduce( + (result: NodePath | null, nodePath) => { + if (result) { + if ( + (!nodePath.isIdentifier() && !nodePath.isStringLiteral()) || + !result.isObjectExpression() + ) { + return null; + } + result = getPropertyValuePath( + result, + nodePath.isIdentifier() + ? nodePath.node.name + : nodePath.node.value, + ); + if (result && result.isIdentifier()) { + return resolveToValue(result); + } } - } - return result; - }, - resolvedValue, - ); - - if ( - !resolvedMemberExpression || - returnsJSXElementOrReactCall(resolvedMemberExpression, importer, seen) - ) { - return true; + return result; + }, + resolvedValue, + ); + + if ( + !resolvedMemberExpression || + returnsJSXElementOrReactCall(resolvedMemberExpression, seen) + ) { + return true; + } } } } @@ -144,46 +144,48 @@ function resolvesToJSXElementOrReactCall( function returnsJSXElementOrReactCall( path: NodePath, - importer: Importer, seen: WeakSet = new WeakSet(), ): boolean { let visited = false; + if (path.isObjectProperty()) { + path = path.get('value'); + } + + if (!path.isFunction()) { + return false; + } + // early exit for ArrowFunctionExpressions if ( - path.node.type === 'ArrowFunctionExpression' && - path.get('body').node.type !== 'BlockStatement' && - resolvesToJSXElementOrReactCall(path.get('body'), importer, seen) + path.isArrowFunctionExpression() && + !path.get('body').isBlockStatement() && + resolvesToJSXElementOrReactCall(path.get('body'), seen) ) { return true; } - let scope = path.scope; - // If we get a property we want the function scope it holds and not its outer scope - if (path.node.type === 'Property') { - scope = path.get('value').scope; - } + const scope = path.scope; - // @ts-ignore - visit(path, { - visitReturnStatement(returnPath): boolean | null | undefined { + path.traverse({ + ReturnStatement(returnPath) { // Only check return statements which are part of the checked function scope - if (returnPath.scope !== scope) return false; + if (returnPath.scope.getFunctionParent() !== scope) { + path.skip(); + return; + } if ( + returnPath.node.argument && resolvesToJSXElementOrReactCall( - returnPath.get('argument'), - importer, + returnPath.get('argument') as NodePath, + seen, ) ) { visited = true; - return false; + path.skip(); } - - this.traverse(returnPath); - - return; }, }); @@ -193,26 +195,23 @@ function returnsJSXElementOrReactCall( /** * Returns `true` if the path represents a function which returns a JSXElement */ -export default function isStatelessComponent( - path: NodePath, - importer: Importer, -): boolean { - const node = path.node; - - if (validPossibleStatelessComponentTypes.indexOf(node.type) === -1) { +export default function isStatelessComponent(path: NodePath): boolean { + if (!path.inType(...validPossibleStatelessComponentTypes)) { return false; } - if (node.type === 'Property') { + if (path.isObjectMethod()) { + // TODO check this, I think this does not work as expected, need to go up 2 parents + // Also property/ObjectMethod is not part of classes?!? if ( - isReactCreateClassCall(path.parent, importer) || - isReactComponentClass(path.parent, importer) + isReactCreateClassCall(path.parentPath as NodePath) //|| + //isReactComponentClass(path.parent) ) { return false; } } - if (returnsJSXElementOrReactCall(path, importer)) { + if (returnsJSXElementOrReactCall(path)) { return true; } diff --git a/src/utils/isUnreachableFlowType.ts b/src/utils/isUnreachableFlowType.ts index 765aad36d65..c25af72ae62 100644 --- a/src/utils/isUnreachableFlowType.ts +++ b/src/utils/isUnreachableFlowType.ts @@ -1,14 +1,13 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; /** * Returns true of the path is an unreachable TypePath */ export default (path: NodePath): boolean => { return ( - !path || - t.Identifier.check(path.node) || - t.ImportDeclaration.check(path.node) || - t.CallExpression.check(path.node) + !path || // TODO Remove if we are fully typed + path.isIdentifier() || + path.isImportDeclaration() || + path.isCallExpression() ); }; diff --git a/src/utils/match.ts b/src/utils/match.ts index 1ab44a9deee..e88957e3ea2 100644 --- a/src/utils/match.ts +++ b/src/utils/match.ts @@ -1,13 +1,13 @@ -import { ASTNode } from 'ast-types'; +import type { Node } from '@babel/traverse'; -type Pattern = { [key: string]: number | string | Pattern }; +type Pattern = { [key: string]: Pattern | number | string }; /** * This function takes an AST node and matches it against "pattern". Pattern * is simply a (nested) object literal and it is traversed to see whether node * contains those (nested) properties with the provided values. */ -export default function match(node: ASTNode, pattern: Pattern): boolean { +export default function match(node: Node, pattern: Pattern): boolean { if (!node) { return false; } @@ -16,8 +16,7 @@ export default function match(node: ASTNode, pattern: Pattern): boolean { return false; } if (pattern[prop] && typeof pattern[prop] === 'object') { - // @ts-ignore - if (!match(node[prop], pattern[prop])) { + if (!match(node[prop], pattern[prop] as Pattern)) { return false; } } else if (node[prop] !== pattern[prop]) { diff --git a/src/utils/normalizeClassDefinition.ts b/src/utils/normalizeClassDefinition.ts index 34e465e674a..8788665b76b 100644 --- a/src/utils/normalizeClassDefinition.ts +++ b/src/utils/normalizeClassDefinition.ts @@ -1,9 +1,14 @@ -import { builders, namedTypes as t, visit } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import { classProperty } from '@babel/types'; import getMemberExpressionRoot from '../utils/getMemberExpressionRoot'; import getMembers from '../utils/getMembers'; +import type { NodePath } from '@babel/traverse'; +import type { + ClassDeclaration, + ClassExpression, + Expression, +} from '@babel/types'; -const ignore = () => false; +const ignore = (path: NodePath) => path.skip(); /** * Given a class definition (i.e. `class` declaration or expression), this @@ -25,32 +30,33 @@ const ignore = () => false; * } */ export default function normalizeClassDefinition( - classDefinition: NodePath, + classDefinition: NodePath, ): void { let variableName; - if (t.ClassDeclaration.check(classDefinition.node)) { - // Class declarations don't have an id, e.g.: `export default class extends React.Component {}` + if (classDefinition.isClassDeclaration()) { + // Class declarations may not have an id, e.g.: `export default class extends React.Component {}` if (classDefinition.node.id) { variableName = classDefinition.node.id.name; } - } else if (t.ClassExpression.check(classDefinition.node)) { - let { parentPath } = classDefinition; + } else if (classDefinition.isClassExpression()) { + let parentPath: NodePath | null = classDefinition.parentPath; while ( - parentPath.node !== classDefinition.scope.node && - !t.BlockStatement.check(parentPath.node) + parentPath && + parentPath.node !== classDefinition.scope.block && + !parentPath.isBlockStatement() ) { - if ( - t.VariableDeclarator.check(parentPath.node) && - t.Identifier.check(parentPath.node.id) - ) { - variableName = parentPath.node.id.name; - break; - } else if ( - t.AssignmentExpression.check(parentPath.node) && - t.Identifier.check(parentPath.node.left) - ) { - variableName = parentPath.node.left.name; - break; + if (parentPath.isVariableDeclarator()) { + const idPath = parentPath.get('id'); + if (idPath.isIdentifier()) { + variableName = idPath.node.name; + break; + } + } else if (parentPath.isAssignmentExpression()) { + const leftPath = parentPath.get('left'); + if (leftPath.isIdentifier()) { + variableName = leftPath.node.name; + break; + } } parentPath = parentPath.parentPath; } @@ -60,38 +66,40 @@ export default function normalizeClassDefinition( return; } - const scopeRoot = classDefinition.scope; - visit(scopeRoot.node, { - visitFunction: ignore, - visitClassDeclaration: ignore, - visitClassExpression: ignore, - visitForInStatement: ignore, - visitForStatement: ignore, - visitAssignmentExpression: function (path) { - if (t.MemberExpression.check(path.node.left)) { - const first = getMemberExpressionRoot(path.get('left')); - if ( - t.Identifier.check(first.node) && - first.node.name === variableName - ) { - const [member] = getMembers(path.get('left')); - if (member && !member.path.node.computed) { - const classProperty = builders.classProperty( - member.path.node, + const scopeBlock = classDefinition.parentPath.scope.block; + classDefinition.parentPath.scope.traverse(scopeBlock, { + Function: ignore, + ClassDeclaration: ignore, + ClassExpression: ignore, + ForInStatement: ignore, + ForStatement: ignore, + AssignmentExpression(path) { + const left = path.get('left'); + if (left.isMemberExpression()) { + const first = getMemberExpressionRoot(left); + if (first.isIdentifier() && first.node.name === variableName) { + const [member] = getMembers(left); + if ( + member && + !member.path.has('computed') && + !member.path.isPrivateName() + ) { + const property = classProperty( + member.path.node as Expression, path.node.right, null, + null, + false, true, ); - classDefinition.get('body', 'body').value.push(classProperty); - return false; + classDefinition.get('body').unshiftContainer('body', property); + path.skip(); + path.remove(); } } - this.traverse(path); } else { - return false; + path.skip(); } - - return undefined; }, }); } diff --git a/src/utils/parseJsDoc.ts b/src/utils/parseJsDoc.ts index e49475b8d6a..c2d1caa8b86 100644 --- a/src/utils/parseJsDoc.ts +++ b/src/utils/parseJsDoc.ts @@ -1,7 +1,7 @@ -import doctrine, { Type } from 'doctrine'; -import type { Annotation, Tag } from 'doctrine'; +import doctrine from 'doctrine'; +import type { Type, Annotation, Tag } from 'doctrine'; -type ExcludesNullish = (x: T | null | undefined | false | 0) => x is T; +type ExcludesNullish = (x: T | 0 | false | null | undefined) => x is T; type JsDocType = JsDocBaseType | JsDocElementsType; interface JsDocBaseType { @@ -27,7 +27,7 @@ interface JsDoc { returns: JsDocProperty | null; } -function getType(tagType: Type | undefined | null): JsDocType | null { +function getType(tagType: Type | null | undefined): JsDocType | null { if (!tagType) { return null; } diff --git a/src/utils/postProcessDocumentation.ts b/src/utils/postProcessDocumentation.ts index 0f4b813cb70..25511c572db 100644 --- a/src/utils/postProcessDocumentation.ts +++ b/src/utils/postProcessDocumentation.ts @@ -1,25 +1,19 @@ import type { DocumentationObject } from '../Documentation'; -function postProcessProps( - props: NonNullable, -): void { - // props with default values should not be required - Object.keys(props).forEach(prop => { - const propInfo = props[prop]; - - if (propInfo.defaultValue) { - propInfo.required = false; - } - }); -} - export default function ( documentation: DocumentationObject, ): DocumentationObject { const props = documentation.props; if (props) { - postProcessProps(props); + // props with default values should not be required + Object.keys(props).forEach(prop => { + const propInfo = props[prop]; + + if (propInfo.defaultValue) { + propInfo.required = false; + } + }); } return documentation; diff --git a/src/utils/printValue.ts b/src/utils/printValue.ts index 3a9bd5f00ef..3ddfc22255e 100644 --- a/src/utils/printValue.ts +++ b/src/utils/printValue.ts @@ -1,8 +1,5 @@ -import type { NodePath } from 'ast-types/lib/node-path'; import strip from 'strip-indent'; -import toBabel from 'estree-to-babel'; -import generate from '@babel/generator'; -import { FileNodeWithOptions } from '../babelParser'; +import type { NodePath } from '@babel/traverse'; function deindent(code: string): string { const firstNewLine = code.indexOf('\n'); @@ -14,46 +11,9 @@ function deindent(code: string): string { ); } -function getSrcFromAst(path: NodePath): string { - do { - if (path.node.type === 'File') { - return (path.node as FileNodeWithOptions).__src; - } - path = path.parentPath; - } while (path != null); - - throw new Error('Could not find source attached to File node'); -} - /** * Prints the given path without leading or trailing comments. */ export default function printValue(path: NodePath): string { - if (path.node.start == null) { - try { - const nodeCopy = { - ...path.node, - }; - - // `estree-to-babel` expects the `comments` property to exist on the top-level node - if (!nodeCopy.comments) { - nodeCopy.comments = []; - } - - return generate(toBabel(nodeCopy), { - comments: false, - concise: true, - }).code; - } catch (err: any) { - throw new Error( - `Cannot print raw value for type '${path.node.type}'. Please report this with an example at https://github.com/reactjs/react-docgen/issues. - -Original error: -${err.stack}`, - ); - } - } - const src = getSrcFromAst(path); - - return deindent(src.slice(path.node.start, path.node.end)); + return deindent(path.getSource()); } diff --git a/src/utils/resolveExportDeclaration.ts b/src/utils/resolveExportDeclaration.ts index 0e51f241403..e074095691d 100644 --- a/src/utils/resolveExportDeclaration.ts +++ b/src/utils/resolveExportDeclaration.ts @@ -1,27 +1,33 @@ -import { namedTypes as t } from 'ast-types'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { + ExportDefaultDeclaration, + ExportNamedDeclaration, +} from '@babel/types'; +import type { NodePath } from '@babel/traverse'; export default function resolveExportDeclaration( - path: NodePath, - importer: Importer, + path: NodePath, ): NodePath[] { const definitions: NodePath[] = []; - if (path.node.default) { + if (path.isExportDefaultDeclaration()) { definitions.push(path.get('declaration')); - } else if (path.node.declaration) { - if (t.VariableDeclaration.check(path.node.declaration)) { + } else if (path.isExportNamedDeclaration()) { + if (path.has('declaration')) { + const declaration = path.get('declaration'); + if (declaration.isVariableDeclaration()) { + declaration + .get('declarations') + .forEach(declarator => definitions.push(declarator)); + } else if (declaration.isDeclaration()) { + definitions.push(declaration); + } + } else if (path.has('specifiers')) { path - .get('declaration', 'declarations') - .each(declarator => definitions.push(declarator)); - } else { - definitions.push(path.get('declaration')); + .get('specifiers') + .forEach(specifier => + definitions.push(specifier.get('local') as NodePath), + ); } - } else if (path.node.specifiers) { - path - .get('specifiers') - .each(specifier => definitions.push(specifier.get('local'))); } - return definitions.map(definition => resolveToValue(definition, importer)); + return definitions.map(definition => resolveToValue(definition)); } diff --git a/src/utils/resolveFunctionDefinitionToReturnValue.ts b/src/utils/resolveFunctionDefinitionToReturnValue.ts index 7c9fbd50b7e..e503d78d592 100644 --- a/src/utils/resolveFunctionDefinitionToReturnValue.ts +++ b/src/utils/resolveFunctionDefinitionToReturnValue.ts @@ -1,22 +1,30 @@ +import type { NodePath } from '@babel/traverse'; +import type { Expression, Function as BabelFunction } from '@babel/types'; import resolveToValue from './resolveToValue'; -import { traverseShallow } from './traverse'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; -import { ReturnStatement } from 'typescript'; +import { ignore, traverseShallow } from './traverse'; + +// TODO needs unit test export default function resolveFunctionDefinitionToReturnValue( - path: NodePath, - importer: Importer, -): NodePath | null { + path: NodePath, +): NodePath | null { let returnPath: NodePath | null = null; - traverseShallow(path.get('body'), { - visitFunction: () => false, - visitReturnStatement: (nodePath: NodePath): false => { - returnPath = resolveToValue(nodePath.get('argument'), importer); - return false; + const body = path.get('body'); + traverseShallow( + body.node, + { + Function: ignore, + ReturnStatement: nodePath => { + const argument = nodePath.get('argument'); + if (argument.hasNode()) { + returnPath = resolveToValue(argument); + } + nodePath.skip(); + }, }, - }); + body.scope, + ); return returnPath; } diff --git a/src/utils/resolveGenericTypeAnnotation.ts b/src/utils/resolveGenericTypeAnnotation.ts index d9a8eab41df..b94d43e2a10 100644 --- a/src/utils/resolveGenericTypeAnnotation.ts +++ b/src/utils/resolveGenericTypeAnnotation.ts @@ -1,38 +1,23 @@ -import { namedTypes as t } from 'ast-types'; +import type { NodePath } from '@babel/traverse'; import isUnreachableFlowType from '../utils/isUnreachableFlowType'; import resolveToValue from '../utils/resolveToValue'; import { unwrapUtilityType } from './flowUtilityTypes'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import getTypeIdentifier from './getTypeIdentifier'; -function tryResolveGenericTypeAnnotation( - path: NodePath, - importer: Importer, -): NodePath | undefined { +function tryResolveGenericTypeAnnotation(path: NodePath): NodePath | undefined { let typePath = unwrapUtilityType(path); - let idPath; - - if (typePath.node.id) { - idPath = typePath.get('id'); - } else if (t.TSTypeReference.check(typePath.node)) { - idPath = typePath.get('typeName'); - } else if (t.TSExpressionWithTypeArguments.check(typePath.node)) { - idPath = typePath.get('expression'); - } + const idPath = getTypeIdentifier(typePath); if (idPath) { - typePath = resolveToValue(idPath, importer); + typePath = resolveToValue(idPath); if (isUnreachableFlowType(typePath)) { return; } - if (t.TypeAlias.check(typePath.node)) { - return tryResolveGenericTypeAnnotation(typePath.get('right'), importer); - } else if (t.TSTypeAliasDeclaration.check(typePath.node)) { - return tryResolveGenericTypeAnnotation( - typePath.get('typeAnnotation'), - importer, - ); + if (typePath.isTypeAlias()) { + return tryResolveGenericTypeAnnotation(typePath.get('right')); + } else if (typePath.isTSTypeAliasDeclaration()) { + return tryResolveGenericTypeAnnotation(typePath.get('typeAnnotation')); } return typePath; @@ -43,16 +28,13 @@ function tryResolveGenericTypeAnnotation( /** * Given an React component (stateless or class) tries to find the - * flow type for the props. If not found or not one of the supported + * flow or ts type for the props. If not found or not one of the supported * component types returns undefined. */ export default function resolveGenericTypeAnnotation( path: NodePath, - importer: Importer, ): NodePath | undefined { - if (!path) return; - - const typePath = tryResolveGenericTypeAnnotation(path, importer); + const typePath = tryResolveGenericTypeAnnotation(path); if (!typePath || typePath === path) return; diff --git a/src/utils/resolveHOC.ts b/src/utils/resolveHOC.ts index 86385a19428..86e343a35b3 100644 --- a/src/utils/resolveHOC.ts +++ b/src/utils/resolveHOC.ts @@ -1,9 +1,7 @@ -import { namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; import isReactCreateClassCall from './isReactCreateClassCall'; import isReactForwardRefCall from './isReactForwardRefCall'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; /** * If the path is a call expression, it recursively resolves to the @@ -11,38 +9,31 @@ import type { Importer } from '../parse'; * * Else the path itself is returned. */ -export default function resolveHOC( - path: NodePath, - importer: Importer, -): NodePath { - const node = path.node; +export default function resolveHOC(path: NodePath): NodePath { if ( - t.CallExpression.check(node) && - !isReactCreateClassCall(path, importer) && - !isReactForwardRefCall(path, importer) + path.isCallExpression() && + !isReactCreateClassCall(path) && + !isReactForwardRefCall(path) ) { - if (node.arguments.length) { - const inner = path.get('arguments', 0); + const node = path.node; + const argumentLength = node.arguments.length; + if (argumentLength && argumentLength > 0) { + const args = path.get('arguments'); + const firstArg = args[0]; // If the first argument is one of these types then the component might be the last argument // If there are all identifiers then we cannot figure out exactly and have to assume it is the first if ( - node.arguments.length > 1 && - (t.Literal.check(inner.node) || - t.ObjectExpression.check(inner.node) || - t.ArrayExpression.check(inner.node) || - t.SpreadElement.check(inner.node)) + argumentLength > 1 && + (firstArg.isLiteral() || + firstArg.isObjectExpression() || + firstArg.isArrayExpression() || + firstArg.isSpreadElement()) ) { - return resolveHOC( - resolveToValue( - path.get('arguments', node.arguments.length - 1), - importer, - ), - importer, - ); + return resolveHOC(resolveToValue(args[argumentLength - 1])); } - return resolveHOC(resolveToValue(inner, importer), importer); + return resolveHOC(resolveToValue(firstArg)); } } diff --git a/src/utils/resolveObjectKeysToArray.ts b/src/utils/resolveObjectKeysToArray.ts index 4a63940138d..63458acd0be 100644 --- a/src/utils/resolveObjectKeysToArray.ts +++ b/src/utils/resolveObjectKeysToArray.ts @@ -1,83 +1,114 @@ -import { ASTNode, namedTypes as t } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; +import type { NodePath } from '@babel/traverse'; +import type { + CallExpression, + Identifier, + NumericLiteral, + StringLiteral, +} from '@babel/types'; + +function isObjectKeysCall(path: NodePath): path is NodePath { + if (!path.isCallExpression() || path.get('arguments').length !== 1) { + return false; + } + + const callee = path.get('callee'); + + if (!callee.isMemberExpression()) { + return false; + } + const object = callee.get('object'); + const property = callee.get('property'); -function isObjectKeysCall(node: ASTNode): boolean { return ( - t.CallExpression.check(node) && - node.arguments.length === 1 && - t.MemberExpression.check(node.callee) && - t.Identifier.check(node.callee.object) && - node.callee.object.name === 'Object' && - t.Identifier.check(node.callee.property) && - node.callee.property.name === 'keys' + object.isIdentifier() && + object.node.name === 'Object' && + property.isIdentifier() && + property.node.name === 'keys' ); } -function isWhitelistedObjectProperty(prop) { - return ( - (t.Property.check(prop) && - ((t.Identifier.check(prop.key) && !prop.computed) || - t.Literal.check(prop.key))) || - t.SpreadElement.check(prop) - ); +function isWhitelistedObjectProperty(path: NodePath): boolean { + if (path.isSpreadElement()) return true; + + if ( + path.isObjectProperty() || + (path.isObjectMethod() && + (path.node.kind === 'get' || path.node.kind === 'set')) + ) { + const key = path.get('key') as NodePath; + return ( + (key.isIdentifier() && !path.node.computed) || + key.isStringLiteral() || + key.isNumericLiteral() + ); + } + + return false; } -function isWhiteListedObjectTypeProperty(prop) { +function isWhiteListedObjectTypeProperty(path: NodePath): boolean { return ( - t.ObjectTypeProperty.check(prop) || - t.ObjectTypeSpreadProperty.check(prop) || - t.TSPropertySignature.check(prop) + path.isObjectTypeProperty() || + path.isObjectTypeSpreadProperty() || + path.isTSPropertySignature() ); } // Resolves an ObjectExpression or an ObjectTypeAnnotation export function resolveObjectToNameArray( - object: NodePath, - importer: Importer, + objectPath: NodePath, raw = false, ): string[] | null { if ( - (t.ObjectExpression.check(object.value) && - object.value.properties.every(isWhitelistedObjectProperty)) || - (t.ObjectTypeAnnotation.check(object.value) && - object.value.properties.every(isWhiteListedObjectTypeProperty)) || - (t.TSTypeLiteral.check(object.value) && - object.value.members.every(isWhiteListedObjectTypeProperty)) + (objectPath.isObjectExpression() && + objectPath.get('properties').every(isWhitelistedObjectProperty)) || + (objectPath.isObjectTypeAnnotation() && + objectPath.get('properties').every(isWhiteListedObjectTypeProperty)) || + (objectPath.isTSTypeLiteral() && + objectPath.get('members').every(isWhiteListedObjectTypeProperty)) ) { let values: string[] = []; let error = false; - const properties = t.TSTypeLiteral.check(object.value) - ? object.get('members') - : object.get('properties'); - properties.each((propPath: NodePath) => { + const properties = objectPath.isTSTypeLiteral() + ? objectPath.get('members') + : (objectPath.get('properties') as NodePath[]); + properties.forEach(propPath => { if (error) return; - const prop = propPath.value; if ( - t.Property.check(prop) || - t.ObjectTypeProperty.check(prop) || - t.TSPropertySignature.check(prop) + propPath.isObjectProperty() || + propPath.isObjectMethod() || + propPath.isObjectTypeProperty() || + propPath.isTSPropertySignature() ) { + const key = propPath.get('key') as + | NodePath + | NodePath + | NodePath; // Key is either Identifier or Literal - // @ts-ignore - const name = prop.key.name || (raw ? prop.key.raw : prop.key.value); + const name: string = key.isIdentifier() + ? key.node.name + : raw + ? (key.node.extra?.raw as string) + : `${key.node.value}`; values.push(name); } else if ( - t.SpreadElement.check(prop) || - t.ObjectTypeSpreadProperty.check(prop) + propPath.isSpreadElement() || + propPath.isObjectTypeSpreadProperty() ) { - let spreadObject = resolveToValue(propPath.get('argument'), importer); - if (t.GenericTypeAnnotation.check(spreadObject.value)) { - const typeAlias = resolveToValue(spreadObject.get('id'), importer); - if (t.ObjectTypeAnnotation.check(typeAlias.get('right').value)) { - spreadObject = resolveToValue(typeAlias.get('right'), importer); + let spreadObject = resolveToValue(propPath.get('argument') as NodePath); + if (spreadObject.isGenericTypeAnnotation()) { + const typeAliasRight = resolveToValue(spreadObject.get('id')).get( + 'right', + ) as NodePath; + if (typeAliasRight.isObjectTypeAnnotation()) { + spreadObject = resolveToValue(typeAliasRight); } } - const spreadValues = resolveObjectToNameArray(spreadObject, importer); + const spreadValues = resolveObjectToNameArray(spreadObject); if (!spreadValues) { error = true; return; @@ -105,19 +136,14 @@ export function resolveObjectToNameArray( */ export default function resolveObjectKeysToArray( path: NodePath, - importer: Importer, ): string[] | null { - const node = path.node; - - if (isObjectKeysCall(node)) { - const objectExpression = resolveToValue( - path.get('arguments').get(0), - importer, - ); - const values = resolveObjectToNameArray(objectExpression, importer); + if (isObjectKeysCall(path)) { + const objectExpression = resolveToValue(path.get('arguments')[0]); + const values = resolveObjectToNameArray(objectExpression); if (values) { const nodes = values + //filter duplicates .filter((value, index, array) => array.indexOf(value) === index) .map(value => `"${value}"`); diff --git a/src/utils/resolveObjectValuesToArray.ts b/src/utils/resolveObjectValuesToArray.ts index 40a7174e77d..3c84fc9f940 100644 --- a/src/utils/resolveObjectValuesToArray.ts +++ b/src/utils/resolveObjectValuesToArray.ts @@ -1,100 +1,148 @@ -import { ASTNode, namedTypes as t } from 'ast-types'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; +import type { + CallExpression, + Identifier, + NumericLiteral, + ObjectMethod, + ObjectProperty, + ObjectTypeProperty, + ObjectTypeSpreadProperty, + SpreadElement, + StringLiteral, + TSPropertySignature, +} from '@babel/types'; interface ObjectPropMap { properties: string[]; values: Record; } -function isObjectValuesCall(node: ASTNode): boolean { +function isObjectValuesCall(path: NodePath): path is NodePath { + if (!path.isCallExpression() || path.node.arguments.length !== 1) { + return false; + } + + const callee = path.get('callee'); + if (!callee.isMemberExpression()) { + return false; + } + const object = callee.get('object'); + const property = callee.get('property'); + return ( - t.CallExpression.check(node) && - node.arguments.length === 1 && - t.MemberExpression.check(node.callee) && - t.Identifier.check(node.callee.object) && - node.callee.object.name === 'Object' && - t.Identifier.check(node.callee.property) && - node.callee.property.name === 'values' + object.isIdentifier() && + object.node.name === 'Object' && + property.isIdentifier() && + property.node.name === 'values' ); } -function isWhitelistedObjectProperty(prop) { +function isWhitelistedObjectProperty(prop: NodePath): boolean { return ( - (t.Property.check(prop) && - ((t.Identifier.check(prop.key) && !prop.computed) || - t.Literal.check(prop.key))) || - t.SpreadElement.check(prop) + (prop.isObjectProperty() && + ((prop.get('key').isIdentifier() && !prop.node.computed) || + prop.get('key').isStringLiteral() || + prop.get('key').isNumericLiteral())) || + (prop.isObjectMethod() && + ((prop.get('key').isIdentifier() && !prop.node.computed) || + prop.get('key').isStringLiteral() || + prop.get('key').isNumericLiteral())) || + prop.isSpreadElement() ); } -function isWhiteListedObjectTypeProperty(prop) { +function isWhiteListedObjectTypeProperty(prop: NodePath): boolean { return ( - t.ObjectTypeProperty.check(prop) || - t.ObjectTypeSpreadProperty.check(prop) || - t.TSPropertySignature.check(prop) + prop.isObjectTypeProperty() || + prop.isObjectTypeSpreadProperty() || + prop.isTSPropertySignature() ); } // Resolves an ObjectExpression or an ObjectTypeAnnotation export function resolveObjectToPropMap( object: NodePath, - importer: Importer, raw = false, ): ObjectPropMap | null { if ( - (t.ObjectExpression.check(object.value) && - object.value.properties.every(isWhitelistedObjectProperty)) || - (t.ObjectTypeAnnotation.check(object.value) && - object.value.properties.every(isWhiteListedObjectTypeProperty)) || - (t.TSTypeLiteral.check(object.value) && - object.value.members.every(isWhiteListedObjectTypeProperty)) + (object.isObjectExpression() && + object.get('properties').every(isWhitelistedObjectProperty)) || + (object.isObjectTypeAnnotation() && + object.get('properties').every(isWhiteListedObjectTypeProperty)) || + (object.isTSTypeLiteral() && + object.get('members').every(isWhiteListedObjectTypeProperty)) ) { const properties: string[] = []; let values = {}; let error = false; - const members = t.TSTypeLiteral.check(object.value) - ? object.get('members') - : object.get('properties'); - members.each(propPath => { - if (error) return; - const prop = propPath.value; - - if (prop.kind === 'get' || prop.kind === 'set' || prop.method === true) { - return; - } + const members: Array< + NodePath< + | ObjectMethod + | ObjectProperty + | ObjectTypeProperty + | ObjectTypeSpreadProperty + | SpreadElement + | TSPropertySignature + > + > = object.isTSTypeLiteral() + ? (object.get('members') as Array>) + : (object.get('properties') as Array< + NodePath< + | ObjectMethod + | ObjectProperty + | ObjectTypeProperty + | ObjectTypeSpreadProperty + | SpreadElement + > + >); + members.forEach(propPath => { + if (error || propPath.isObjectMethod()) return; if ( - t.Property.check(prop) || - t.ObjectTypeProperty.check(prop) || - t.TSPropertySignature.check(prop) + propPath.isObjectProperty() || + propPath.isObjectTypeProperty() || + propPath.isTSPropertySignature() ) { + const key = propPath.get('key') as NodePath< + Identifier | NumericLiteral | StringLiteral + >; // Key is either Identifier or Literal - // @ts-ignore - const name = prop.key.name || (raw ? prop.key.raw : prop.key.value); - const propValue = propPath.get(name).parentPath.value; + // TODO check this also for TSPropertySignature and ObjectTypeProperty + // TODO reimplement, this has so many issues + // Identifiers as values are not followed at all + // TSPropertySignature is not handled correctly here + const name: string = key.isIdentifier() + ? key.node.name + : raw + ? (key.node.extra?.raw as string) + : `${(key as NodePath).node.value}`; const value = - propValue.value.value || - (raw ? propValue.value.raw : propValue.value.value); + // @ts-ignore + propPath.node.value.value || + // @ts-ignore + (raw ? propPath.node.value.raw : propPath.node.value.value); if (properties.indexOf(name) === -1) { properties.push(name); } values[name] = value; } else if ( - t.SpreadElement.check(prop) || - t.ObjectTypeSpreadProperty.check(prop) + propPath.isSpreadElement() || + propPath.isObjectTypeSpreadProperty() ) { - let spreadObject = resolveToValue(propPath.get('argument'), importer); - if (t.GenericTypeAnnotation.check(spreadObject.value)) { - const typeAlias = resolveToValue(spreadObject.get('id'), importer); - if (t.ObjectTypeAnnotation.check(typeAlias.get('right').value)) { - spreadObject = resolveToValue(typeAlias.get('right'), importer); + let spreadObject = resolveToValue(propPath.get('argument') as NodePath); + if (spreadObject.isGenericTypeAnnotation()) { + const typeAlias = resolveToValue(spreadObject.get('id')); + if ( + typeAlias.isTypeAlias() && + typeAlias.get('right').isObjectTypeAnnotation() + ) { + spreadObject = resolveToValue(typeAlias.get('right')); } } - const spreadValues = resolveObjectToPropMap(spreadObject, importer); + const spreadValues = resolveObjectToPropMap(spreadObject); if (!spreadValues) { error = true; return; @@ -127,16 +175,10 @@ export function resolveObjectToPropMap( */ export default function resolveObjectValuesToArray( path: NodePath, - importer: Importer, ): string[] | null { - const node = path.node; - - if (isObjectValuesCall(node)) { - const objectExpression = resolveToValue( - path.get('arguments').get(0), - importer, - ); - const propMap = resolveObjectToPropMap(objectExpression, importer); + if (isObjectValuesCall(path)) { + const objectExpression = resolveToValue(path.get('arguments')[0]); + const propMap = resolveObjectToPropMap(objectExpression); if (propMap) { const nodes = propMap.properties.map(prop => { diff --git a/src/utils/resolveToModule.ts b/src/utils/resolveToModule.ts index a08ecf7e29c..24b8c6be423 100644 --- a/src/utils/resolveToModule.ts +++ b/src/utils/resolveToModule.ts @@ -1,63 +1,41 @@ -import { namedTypes as t } from 'ast-types'; -import match from './match'; +import type { NodePath } from '@babel/traverse'; +import type { Expression, StringLiteral } from '@babel/types'; +import getMemberExpressionRoot from './getMemberExpressionRoot'; import resolveToValue from './resolveToValue'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; /** * Given a path (e.g. call expression, member expression or identifier), * this function tries to find the name of module from which the "root value" * was imported. */ -export default function resolveToModule( - path: NodePath, - importer: Importer, -): string | null { - const node = path.node; - switch (node.type) { - // @ts-ignore - case t.VariableDeclarator.name: - if (node.init) { - return resolveToModule(path.get('init'), importer); - } - break; - - // @ts-ignore - case t.CallExpression.name: - // @ts-ignore - if (match(node.callee, { type: t.Identifier.name, name: 'require' })) { - return node.arguments[0].value; - } - return resolveToModule(path.get('callee'), importer); - - // @ts-ignore - case t.Identifier.name: // @ts-ignore - case t.JSXIdentifier.name: { - const valuePath = resolveToValue(path, importer); - if (valuePath !== path) { - return resolveToModule(valuePath, importer); - } - if (!t.Property.check(path.parentPath.node)) { - break; - } +export default function resolveToModule(path: NodePath): string | null { + if (path.isVariableDeclarator()) { + if (path.node.init) { + return resolveToModule(path.get('init') as NodePath); + } + } else if (path.isCallExpression()) { + const callee = path.get('callee'); + if (callee.isIdentifier() && callee.node.name === 'require') { + return (path.node.arguments[0] as StringLiteral).value; } - // @ts-ignore // fall through - case t.Property.name: // @ts-ignore - case t.ObjectPattern.name: - return resolveToModule(path.parentPath, importer); - // @ts-ignore - case t.ImportDeclaration.name: - return node.source.value; + return resolveToModule(callee); + } else if (path.isIdentifier() || path.isJSXIdentifier()) { + const valuePath = resolveToValue(path); + if (valuePath !== path) { + return resolveToModule(valuePath); + } + if (path.parentPath.isObjectProperty()) { + return resolveToModule(path.parentPath); + } + } else if (path.isObjectProperty() || path.isObjectPattern()) { + return resolveToModule(path.parentPath); + } else if (path.isImportDeclaration()) { + return path.node.source.value; + } else if (path.isMemberExpression()) { + path = getMemberExpressionRoot(path); - // @ts-ignore - case t.MemberExpression.name: - while (path && t.MemberExpression.check(path.node)) { - path = path.get('object'); - } - if (path) { - return resolveToModule(path, importer); - } + return resolveToModule(path); } return null; diff --git a/src/utils/resolveToValue.ts b/src/utils/resolveToValue.ts index 0dc9e8fe072..3d376229064 100644 --- a/src/utils/resolveToValue.ts +++ b/src/utils/resolveToValue.ts @@ -1,4 +1,11 @@ -import { namedTypes as t } from 'ast-types'; +import { Scope } from '@babel/traverse'; +import type { NodePath } from '@babel/traverse'; +import type { + Expression, + Identifier, + ImportDeclaration, + MemberExpression, +} from '@babel/types'; import getMemberExpressionRoot from './getMemberExpressionRoot'; import getPropertyValuePath from './getPropertyValuePath'; import { Array as toArray } from './expressionTo'; @@ -6,56 +13,46 @@ import { traverseShallow } from './traverse'; import getMemberValuePath, { isSupportedDefinitionType, } from './getMemberValuePath'; -import type { Importer } from '../parse'; -import type { NodePath } from 'ast-types/lib/node-path'; -import { Scope } from 'ast-types/lib/scope'; -import { Context } from 'ast-types/lib/path-visitor'; +import initialize from './ts-types'; function findScopePath( - paths: NodePath[], - path: NodePath, - importer: Importer, + bindingIdentifiers: Array>, ): NodePath | null { - if (paths.length < 1) { - return null; - } - let resultPath = paths[0]; - const parentPath = resultPath.parent; + if (bindingIdentifiers && bindingIdentifiers.length >= 1) { + const resolvedParentPath = bindingIdentifiers[0].parentPath; + if ( + resolvedParentPath.isImportDefaultSpecifier() || + resolvedParentPath.isImportSpecifier() + ) { + // TODO TESTME + let exportName: string | undefined; + if (resolvedParentPath.isImportDefaultSpecifier()) { + exportName = 'default'; + } else { + const imported = resolvedParentPath.get('imported'); - // Namespace imports are handled separately, at the site of a member expression access - if ( - t.ImportDefaultSpecifier.check(parentPath.node) || - t.ImportSpecifier.check(parentPath.node) - ) { - let exportName; - if (t.ImportDefaultSpecifier.check(parentPath.node)) { - exportName = 'default'; - } else { - exportName = parentPath.node.imported.name; - } + if (imported.isStringLiteral()) { + exportName = imported.node.value; + } else if (imported.isIdentifier()) { + exportName = imported.node.name; + } + } - const resolvedPath = importer(parentPath.parentPath, exportName); + if (!exportName) { + throw new Error('Could not detect export name'); + } - if (resolvedPath) { - return resolveToValue(resolvedPath, importer); - } - } + const importedPath = resolvedParentPath.hub.import( + resolvedParentPath.parentPath as NodePath, + exportName, + ); - if ( - t.ImportDefaultSpecifier.check(parentPath.node) || - t.ImportSpecifier.check(parentPath.node) || - t.ImportNamespaceSpecifier.check(parentPath.node) || - t.VariableDeclarator.check(parentPath.node) || - t.TypeAlias.check(parentPath.node) || - t.InterfaceDeclaration.check(parentPath.node) || - t.TSTypeAliasDeclaration.check(parentPath.node) || - t.TSInterfaceDeclaration.check(parentPath.node) - ) { - resultPath = parentPath; - } + if (importedPath) { + return resolveToValue(importedPath); + } + } - if (resultPath.node !== path.node) { - return resolveToValue(resultPath, importer); + return resolveToValue(resolvedParentPath); } return null; @@ -67,47 +64,52 @@ function findScopePath( */ function findLastAssignedValue( scope: Scope, - idPath: NodePath, - importer: Importer, + idPath: NodePath, ): NodePath | null { const results: NodePath[] = []; const name = idPath.node.name; - traverseShallow(scope.path, { - visitAssignmentExpression: function ( - this: Context, - path: NodePath, - ): boolean | undefined { - const node = path.node; - // Skip anything that is not an assignment to a variable with the - // passed name. - // Ensure the LHS isn't the reference we're trying to resolve. - if ( - !t.Identifier.check(node.left) || - node.left === idPath.node || - node.left.name !== name || - node.operator !== '=' - ) { - return this.traverse(path); - } - // Ensure the RHS doesn't contain the reference we're trying to resolve. - const candidatePath = path.get('right'); - for (let p = idPath; p && p.node != null; p = p.parent) { - if (p.node === candidatePath.node) { - return this.traverse(path); + traverseShallow( + scope.path.node, + { + AssignmentExpression(path) { + const node = path.node; + const left = path.get('left'); + // Skip anything that is not an assignment to a variable with the + // passed name. + // Ensure the LHS isn't the reference we're trying to resolve. + if ( + !left.isIdentifier() || + left.node === idPath.node || + left.node.name !== name || + node.operator !== '=' + ) { + return; } - } - results.push(candidatePath); - return false; + // Ensure the RHS doesn't contain the reference we're trying to resolve. + const candidatePath = path.get('right'); + for ( + let p: NodePath | null = idPath; + p && p.node != null; + p = p.parentPath + ) { + if (p.node === candidatePath.node) { + return; + } + } + results.push(candidatePath); + return path.skip(); + }, }, - }); + scope, + ); const resultPath = results.pop(); if (resultPath == null) { return null; } - return resolveToValue(resultPath, importer); + return resolveToValue(resultPath); } /** @@ -117,109 +119,105 @@ function findLastAssignedValue( * * Else the path itself is returned. */ -export default function resolveToValue( - path: NodePath, - importer: Importer, -): NodePath { - const node = path.node; - if (t.VariableDeclarator.check(node)) { - if (node.init) { - return resolveToValue(path.get('init'), importer); +export default function resolveToValue(path: NodePath): NodePath { + if (path.isVariableDeclarator()) { + if (path.node.init) { + return resolveToValue(path.get('init') as NodePath); } - } else if (t.MemberExpression.check(node)) { + } else if (path.isMemberExpression()) { const root = getMemberExpressionRoot(path); - const resolved = resolveToValue(root, importer); - if (t.ObjectExpression.check(resolved.node)) { + const resolved = resolveToValue(root); + if (resolved.isObjectExpression()) { let propertyPath: NodePath | null = resolved; - for (const propertyName of toArray(path, importer).slice(1)) { - if (propertyPath && t.ObjectExpression.check(propertyPath.node)) { - propertyPath = getPropertyValuePath( - propertyPath, - propertyName, - importer, - ); + for (const propertyName of toArray(path).slice(1)) { + if (propertyPath && propertyPath.isObjectExpression()) { + propertyPath = getPropertyValuePath(propertyPath, propertyName); } if (!propertyPath) { return path; } - propertyPath = resolveToValue(propertyPath, importer); + propertyPath = resolveToValue(propertyPath); } return propertyPath; } else if (isSupportedDefinitionType(resolved)) { - const memberPath = getMemberValuePath( - resolved, - path.node.property.name, - importer, - ); - if (memberPath) { - return resolveToValue(memberPath, importer); + const property = path.get('property'); + if (property.isIdentifier() || property.isStringLiteral()) { + const memberPath = getMemberValuePath( + resolved, + property.isIdentifier() ? property.node.name : property.node.value, // TODO TESTME + ); + if (memberPath) { + return resolveToValue(memberPath); + } } - } else if ( - t.ImportDeclaration.check(resolved.node) && - resolved.node.specifiers - ) { + } else if (resolved.isImportDeclaration() && resolved.node.specifiers) { // Handle references to namespace imports, e.g. import * as foo from 'bar'. // Try to find a specifier that matches the root of the member expression, and // find the export that matches the property name. - for (const specifier of resolved.node.specifiers) { + for (const specifier of resolved.get('specifiers')) { if ( - t.ImportNamespaceSpecifier.check(specifier) && - specifier.local && - specifier.local.name === root.node.name + specifier.isImportNamespaceSpecifier() && + specifier.node.local && + specifier.node.local.name === (root.node as Identifier).name // TODO TESTME could be not an identifier ) { - const resolvedPath = importer( + const resolvedPath = path.hub.import( resolved, - root.parentPath.node.property.name, + ((root.parentPath.node as MemberExpression).property as Identifier) + .name, // TODO TESTME Idk what that is ); if (resolvedPath) { - return resolveToValue(resolvedPath, importer); + return resolveToValue(resolvedPath); } } } } } else if ( - t.ImportDefaultSpecifier.check(node) || - t.ImportNamespaceSpecifier.check(node) || - t.ImportSpecifier.check(node) + path.isImportDefaultSpecifier() || + path.isImportNamespaceSpecifier() || + path.isImportSpecifier() ) { - // go up two levels as first level is only the array of specifiers - return path.parentPath.parentPath; - } else if (t.AssignmentExpression.check(node)) { - if (node.operator === '=') { - return resolveToValue(path.get('right'), importer); + // go up to the import declaration + return path.parentPath; + } else if (path.isAssignmentExpression()) { + if (path.node.operator === '=') { + return resolveToValue(path.get('right')); } } else if ( - t.TypeCastExpression.check(node) || - t.TSAsExpression.check(node) || - t.TSTypeAssertion.check(node) + path.isTypeCastExpression() || + path.isTSAsExpression() || + path.isTSTypeAssertion() ) { - return resolveToValue(path.get('expression'), importer); - } else if (t.Identifier.check(node)) { + return resolveToValue(path.get('expression') as NodePath); + } else if (path.isIdentifier()) { if ( - (t.ClassDeclaration.check(path.parentPath.node) || - t.ClassExpression.check(path.parentPath.node) || - t.Function.check(path.parentPath.node)) && + (path.parentPath.isClassDeclaration() || + path.parentPath.isClassExpression() || + path.parentPath.isFunction()) && path.parentPath.get('id') === path ) { return path.parentPath; } - let scope: Scope = path.scope.lookup(node.name); + const binding = path.scope.getBinding(path.node.name); let resolvedPath: NodePath | null = null; - if (scope) { + if (binding) { // The variable may be assigned a different value after initialization. // We are first trying to find all assignments to the variable in the // block where it is defined (i.e. we are not traversing into statements) - resolvedPath = findLastAssignedValue(scope, path, importer); + resolvedPath = findLastAssignedValue(binding.scope, path); if (!resolvedPath) { - const bindings = scope.getBindings()[node.name]; - resolvedPath = findScopePath(bindings, path, importer); + // @ts-ignore + const bindingMap = binding.path.getOuterBindingIdentifierPaths( + true, + ) as Record>>; + resolvedPath = findScopePath(bindingMap[path.node.name]); } } else { - scope = path.scope.lookupType(node.name); - if (scope) { - const typesInScope = scope.getTypes()[node.name]; - resolvedPath = findScopePath(typesInScope, path, importer); + // Initialize our monkey-patching of @babel/traverse 🙈 + initialize(Scope); + const typeBinding = path.scope.getTypeBinding(path.node.name); + if (typeBinding) { + resolvedPath = findScopePath([typeBinding.identifierPath]); } } return resolvedPath || path; diff --git a/src/utils/setPropDescription.ts b/src/utils/setPropDescription.ts index ade3606fc31..efae3639bad 100644 --- a/src/utils/setPropDescription.ts +++ b/src/utils/setPropDescription.ts @@ -1,15 +1,21 @@ -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath } from '@babel/traverse'; import type Documentation from '../Documentation'; import getPropertyName from './getPropertyName'; import { getDocblock } from './docblock'; -import type { Importer } from '../parse'; +import type { + ObjectMethod, + ObjectProperty, + ObjectTypeProperty, + TSPropertySignature, +} from '@babel/types'; export default function setPropDescription( documentation: Documentation, - propertyPath: NodePath, - importer: Importer, + propertyPath: NodePath< + ObjectMethod | ObjectProperty | ObjectTypeProperty | TSPropertySignature + >, ): void { - const propName = getPropertyName(propertyPath, importer); + const propName = getPropertyName(propertyPath); if (!propName) return; const propDescriptor = documentation.getPropDescriptor(propName); diff --git a/src/utils/traverse.ts b/src/utils/traverse.ts index 791cad4c07c..67c9634c830 100644 --- a/src/utils/traverse.ts +++ b/src/utils/traverse.ts @@ -1,35 +1,37 @@ -import { visit } from 'ast-types'; -import type { NodePath } from 'ast-types/lib/node-path'; +import type { NodePath, Scope, Visitor } from '@babel/traverse'; +import { default as babelTraverse } from '@babel/traverse'; +import type { Node } from '@babel/types'; -type Visitor = (path: NodePath) => unknown; +export function ignore(path: NodePath): void { + path.skip(); +} /** * A helper function that doesn't traverse into nested blocks / statements by * default. */ export function traverseShallow( - path: NodePath, - visitors: { [key: string]: Visitor }, + node: Node, + visitors: Visitor, + scope?: Scope | undefined, ): void { - // @ts-ignore - visit(path, { ...defaultVisitors, ...visitors }); + babelTraverse(node, { ...defaultVisitors, ...visitors }, scope); } -const ignore = () => false; const defaultVisitors = { - visitFunctionDeclaration: ignore, - visitFunctionExpression: ignore, - visitClassDeclaration: ignore, - visitClassExpression: ignore, - visitIfStatement: ignore, - visitWithStatement: ignore, - visitSwitchStatement: ignore, - visitWhileStatement: ignore, - visitDoWhileStatement: ignore, - visitForStatement: ignore, - visitForInStatement: ignore, - visitForOfStatement: ignore, - visitExportNamedDeclaration: ignore, - visitExportDefaultDeclaration: ignore, - visitConditionalExpression: ignore, + FunctionDeclaration: ignore, + FunctionExpression: ignore, + ClassDeclaration: ignore, + ClassExpression: ignore, + IfStatement: ignore, + WithStatement: ignore, + SwitchStatement: ignore, + WhileStatement: ignore, + DoWhileStatement: ignore, + ForStatement: ignore, + ForInStatement: ignore, + ForOfStatement: ignore, + ExportNamedDeclaration: ignore, + ExportDefaultDeclaration: ignore, + ConditionalExpression: ignore, }; diff --git a/src/utils/ts-types/index.ts b/src/utils/ts-types/index.ts new file mode 100644 index 00000000000..ee51ea5204c --- /dev/null +++ b/src/utils/ts-types/index.ts @@ -0,0 +1,176 @@ +import type { NodePath } from '@babel/traverse'; +import { Scope as BaseScope } from '@babel/traverse'; +import type { + Identifier, + TSEnumDeclaration, + TSInterfaceDeclaration, + TSTypeAliasDeclaration, +} from '@babel/types'; + +type BindingNode = + | TSEnumDeclaration + | TSInterfaceDeclaration + | TSTypeAliasDeclaration; + +type TypeKind = 'alias' | 'enum' | 'interface'; + +/** + * What the f... is this? + * Well, babel and in particular @babel/traverse have no scope tracking + * for typescript types. Flow types do work because they are part of the + * normal reference tracking and mix with non-type identifiers. + * This monkey-patching of @babel/traverse adds scope tracking for + * typescript types. It tries to do this without changing any babel behavior. + * + * This is not the best solution, but it allows to use @babel/traverse in react-docgen + * which needs to be able to do scope tracking of typescript types. + * + * see https://github.com/babel/babel/issues/14662 + */ + +declare module '@babel/traverse' { + export interface Scope { + typeBindings: Record; + getTypeBinding(name: string): TypeBinding | undefined; + getOwnTypeBinding(name: string): TypeBinding; + registerTypeBinding( + this: BaseScope, + typeKind: TypeKind, + path: NodePath, + bindingPath: NodePath, + ): void; + _realRegisterDeclaration: BaseScope['registerDeclaration']; + _realCrawl: BaseScope['crawl']; + } +} + +class TypeBinding { + identifier: Identifier; + identifierPath: NodePath; + path: NodePath; + scope: BaseScope; + typeKind: TypeKind; + + constructor(data: { + identifier: Identifier; + identifierPath: NodePath; + path: NodePath; + scope: BaseScope; + typeKind: TypeKind; + }) { + // TODO fix DT and remove existing from params + this.identifier = data.identifier; + this.identifierPath = data.identifierPath; + this.path = data.path; + this.scope = data.scope; + this.typeKind = data.typeKind; + } +} + +function registerTypeBinding( + this: BaseScope, + typeKind: TypeKind, + path: NodePath, + bindingPath: NodePath, +): void { + const ids = { [path.node.name]: [path.node] }; + // TODO remove loop as always one identifier? + for (const name of Object.keys(ids)) { + for (const id of ids[name]) { + const local = this.getOwnTypeBinding(name); + + if (local) { + if (local.identifier === id) continue; + + if ( + // : collide, <=>: not collide, merge + // enum interface + // enum alias + // interface alias + // alias alias + // interface <=> interface + // enum <=> enum + typeKind !== local.typeKind || + typeKind === 'alias' || + local.typeKind === 'alias' + ) { + throw this.hub.buildError( + id, + `Duplicate type declaration "${name}"`, + TypeError, + ); + } + // TODO fix in DT + // this.checkBlockScopedCollisions(local as any, 'let', name, id); + } + + if (local) { + // two interface with the same name + // @ts-expect-error TODO fix DT + local.reassign(path); + } else { + this.typeBindings[name] = new TypeBinding({ + identifier: id, + identifierPath: path, + path: bindingPath, + scope: this, + typeKind, + }); + } + } + } +} + +function getTypeBinding( + this: BaseScope, + name: string, +): TypeBinding | undefined { + // eslint-disable-next-line @typescript-eslint/no-this-alias + let scope = this; + + do { + const binding = scope.getOwnTypeBinding(name); + + if (binding) { + return binding; + } + } while ((scope = scope.parent)); + + return undefined; +} + +function getOwnTypeBinding(this: BaseScope, name: string): TypeBinding { + return this.typeBindings[name]; +} + +function registerDeclaration(this: BaseScope, path: NodePath): void { + if (path.isTSTypeAliasDeclaration()) { + this.registerTypeBinding('alias', path.get('id'), path); + } else if (path.isTSInterfaceDeclaration()) { + this.registerTypeBinding('interface', path.get('id'), path); + } else if (path.isTSEnumDeclaration()) { + this.registerTypeBinding('enum', path.get('id'), path); + } else { + this._realRegisterDeclaration(path); + } +} + +export default function initialize(scopeClass: typeof BaseScope): void { + // @ts-expect-error The typ does not allow undefined, only internally + if (scopeClass.prototype.getTypeBinding) { + return; + } + scopeClass.prototype.getTypeBinding = getTypeBinding; + scopeClass.prototype.registerTypeBinding = registerTypeBinding; + scopeClass.prototype.getOwnTypeBinding = getOwnTypeBinding; + scopeClass.prototype._realRegisterDeclaration = + scopeClass.prototype.registerDeclaration; + scopeClass.prototype.registerDeclaration = registerDeclaration; + scopeClass.prototype._realCrawl = scopeClass.prototype.crawl; + scopeClass.prototype.crawl = function (this: BaseScope) { + this.typeBindings = Object.create(null); + this._realCrawl(); + }; +} + +initialize(BaseScope); diff --git a/tests/NodePathSerializer.js b/tests/NodePathSerializer.js index 648d6b83ea6..544728d0f49 100644 --- a/tests/NodePathSerializer.js +++ b/tests/NodePathSerializer.js @@ -1,8 +1,21 @@ -const { NodePath } = require('ast-types'); +const { NodePath } = require('@babel/traverse'); +const { removePropertiesDeep } = require('@babel/types'); + +function removeUndefinedProperties(node) { + for (const key of Object.keys(node)) { + if (node[key] === undefined) { + delete node[key]; + } else if (node[key] === Object(node[key])) { + node[key] = removeUndefinedProperties(node[key]); + } + } + + return node; +} module.exports = { print(val, serialize) { - return serialize(val.node); + return serialize(removeUndefinedProperties(removePropertiesDeep(val.node))); }, test(val) { diff --git a/tests/setupTestFramework.ts b/tests/setupTestFramework.ts index 1f400be112e..77e66248927 100644 --- a/tests/setupTestFramework.ts +++ b/tests/setupTestFramework.ts @@ -1,16 +1,12 @@ /* eslint-env jest */ - -import { - NodePath as NodePathConstructor, - astNodesAreEquivalent, - ASTNode, -} from 'ast-types'; -import { NodePath } from 'ast-types/lib/node-path'; +import type { Node } from '@babel/traverse'; +import { NodePath } from '@babel/traverse'; +import { isNodesEquivalent, removePropertiesDeep } from '@babel/types'; import { diff } from 'jest-diff'; import { printExpected, printReceived } from 'jest-matcher-utils'; const matchers = { - toEqualASTNode: function (received: NodePath, expected: NodePath | ASTNode) { + toEqualASTNode: function (received: NodePath, expected: Node | NodePath) { if (!expected || typeof expected !== 'object') { throw new Error( 'Expected value must be an object representing an AST node.\n' + @@ -24,19 +20,28 @@ const matchers = { // Use value here instead of node, as node has some magic and always returns // the next Node it finds even if value is an array - const receivedNode = received.value; - let expectedNode = expected; - if (expected instanceof NodePathConstructor) { - expectedNode = expected.value; + const receivedNode = received.node; + let expectedNode: Node; + if (expected instanceof NodePath) { + expectedNode = expected.node; + } else { + expectedNode = expected; + } + if (expectedNode.type === 'MemberExpression') { + // Babel 7 always adds this optional field which is wrong + // Fixed in babel v8 + delete expectedNode.optional; } return { - pass: astNodesAreEquivalent(receivedNode, expectedNode), + pass: isNodesEquivalent(receivedNode, expectedNode), message: () => { + removePropertiesDeep(expectedNode); + removePropertiesDeep(receivedNode); const diffString = diff(expectedNode, receivedNode); return ( - 'Expected value to be (using ast-types):\n' + + 'Expected value to be:\n' + ` ${printExpected(expectedNode)}\n` + 'Received:\n' + ` ${printReceived(receivedNode)}` + diff --git a/tests/utils.ts b/tests/utils.ts index 2680a9a6b87..21bdc59fcb7 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,18 +1,25 @@ -/** - * Helper methods for tests. - */ - -import { ASTNode, NodePath as NodePathConstructor } from 'ast-types'; -import { NodePath } from 'ast-types/lib/node-path'; -import buildParser, { Options, Parser } from '../src/babelParser'; -import { Importer } from '../src/parse'; +import type { Node } from '@babel/core'; +import type { NodePath } from '@babel/traverse'; +import type { Options, Parser } from '../src/babelParser'; +import type { Importer, ImportPath } from '../src/importer'; +import FileState from '../src/FileState'; +import buildParser from '../src/babelParser'; +import type { + ExportDefaultDeclaration, + Expression, + ExpressionStatement, + Program, + Statement, +} from '@babel/types'; +// @ts-ignore TODO fix types in TD +//import { File } from '@babel/core'; declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace jest { // eslint-disable-next-line @typescript-eslint/no-unused-vars interface Matchers { - toEqualASTNode: (expected: NodePath | ASTNode) => CustomMatcherResult; + toEqualASTNode: (expected: Node | NodePath) => CustomMatcherResult; } } } @@ -20,72 +27,238 @@ declare global { export function getParser(options: Options = {}): Parser { return buildParser(options); } -/** - * Returns a NodePath to the program node of the passed node - */ -export function parse(src: string, options: Options = {}): NodePath { - const ast = getParser(options).parse(src); - ast.__src = src; - - return new NodePathConstructor(ast).get('program'); -} - -export function statement( - src: string, - options: Options = {}, - last = false, -): NodePath { - const root = parse(src, options); - return root.get('body', last ? root.node.body.length - 1 : 0); -} -export function expression(src: string, options: Options = {}): NodePath { - return statement(`(${src})`, options).get('expression'); +interface ParseCall { + (code: string, importer: Importer): NodePath; + (code: string, options: Options): NodePath; + ( + code: string, + options?: Options, + importer?: Importer, + returnFileState?: B, + ): B extends true ? FileState : NodePath; } -export function expressionLast(src: string, options: Options = {}): NodePath { - return statement(src, options, true).get('expression'); +interface Parse extends ParseCall { + expression(src: string, options?: Options): NodePath; + expression( + src: string, + importer: Importer, + options?: Options, + ): NodePath; + statement(src: string, index?: number): NodePath; + statement( + src: string, + importer: Importer, + index?: number, + ): NodePath; + statement( + src: string, + options: Options, + index?: number, + ): NodePath; + statement( + src: string, + importer: Importer, + options: Options, + index?: number, + ): NodePath; + expressionLast(src: string, options?: Options): NodePath; + expressionLast( + src: string, + importer: Importer, + options?: Options, + ): NodePath; + statementLast(src: string, options?: Options): NodePath; + statementLast( + src: string, + importer: Importer, + options?: Options, + ): NodePath; } /** - * Injects src into template by replacing the occurrence of %s. + * Returns a NodePath to the program path of the passed node + * Parses JS and Flow */ -export function parseWithTemplate(src: string, template: string): NodePath { - return parse(template.replace('%s', src)); -} +const parseDefault: ParseCall = function ( + code: string, + options: Importer | Options = {}, + importer: Importer = noopImporter, + returnFileState = false, +): typeof returnFileState extends true ? FileState : NodePath { + if (typeof options !== 'object') { + importer = options; + options = {}; + } + const opts = { + babelrc: false, + ...options, + }; + const parser = getParser(opts); + const ast = parser(code); + const fileState = new FileState(opts, { + ast, + code, + importer, + parser, + }); -/** - * Default template that simply defines React and PropTypes. - */ -export const REACT_TEMPLATE = [ - 'var React = require("React");', - 'var PropTypes = React.PropTypes;', - 'var {PropTypes: OtherPropTypes} = require("React");', - '%s;', -].join('\n'); - -export const MODULE_TEMPLATE = [ - 'var React = require("React");', - 'var PropTypes = React.PropTypes;', - 'var Component = React.createClass(%s);', - 'module.exports = Component', -].join('\n'); + if (returnFileState) { + return fileState as any; + } + + return fileState.path as any; +}; + +const parseTS: ParseCall = function ( + code: string, + options: Importer | Options = {}, + importer: Importer = noopImporter, +): NodePath { + if (typeof options !== 'object') { + importer = options; + options = {}; + } + + return parseDefault( + code, + { + filename: 'file.tsx', + parserOptions: { plugins: ['typescript'] }, + ...options, + }, + importer, + false, + ); +}; + +export const parse = buildTestParser(parseDefault as Parse); +export const parseTypescript = buildTestParser(parseTS as Parse); + +function buildTestParser(parseFunction: Parse): Parse { + parseFunction.statement = function ( + this: Parse, + src: string, + importer: Importer | Options | number = noopImporter, + options: Options | number = {}, + index = 0, + ): NodePath { + if (typeof options === 'number') { + index = options; + options = {}; + } + if (typeof importer === 'number') { + index = importer; + importer = noopImporter; + } else if (typeof importer === 'object') { + options = importer; + importer = noopImporter; + } + const root = this(src, options, importer, false); + + if (index < 0) { + index = root.node.body.length + index; + } + + return root.get('body')[index] as unknown as NodePath; + }; + + parseFunction.statementLast = function ( + this: Parse, + src: string, + importer: Importer | Options = noopImporter, + options: Options = {}, + ): NodePath { + if (typeof importer === 'object') { + options = importer; + importer = noopImporter; + } + return this.statement(src, importer, options, -1); + }; + + parseFunction.expression = function ( + this: Parse, + src: string, + importer: Importer | Options = noopImporter, + options: Options = {}, + ): NodePath { + if (typeof importer === 'object') { + options = importer; + importer = noopImporter; + } + return this.statement( + `(${src})`, + importer, + options, + ).get('expression') as unknown as NodePath; + }; + + parseFunction.expressionLast = function ( + this: Parse, + src: string, + importer: Importer | Options = noopImporter, + options: Options = {}, + ): NodePath { + if (typeof importer === 'object') { + options = importer; + importer = noopImporter; + } + return this.statement(src, importer, options, -1).get( + 'expression', + ) as unknown as NodePath; + }; + + return parseFunction; +} /** * Importer that doesn't resolve any values */ -export function noopImporter(): null { +export const noopImporter: Importer = (): null => { return null; -} - +}; /** * Builds an importer where the keys are import paths and the values are AST nodes */ export function makeMockImporter( - mocks: Record = {}, + mocks: Record< + string, + ( + stmtLast: ( + code: string, + isTs?: boolean, + index?: number, + ) => NodePath, + ) => NodePath + > = {}, ): Importer { - return (path: NodePath): NodePath => { - const source = path.node.source.value; - return mocks[source]; + const stmtLast = ( + code: string, + isTs = false, + index = -1, + ): NodePath => { + const parser = isTs ? parseTypescript : parse; + + return parser.statement(code, importer, index); + }; + let cache: Record = Object.create(null); + const importer: Importer = (path: ImportPath): NodePath | null => { + const source = path.node.source?.value; + + if (!source) { + throw new Error(`Cannot find mock source on ImportPath for ${path.type}`); + } + + if (cache[source] === undefined) { + cache[source] = mocks[source]?.(stmtLast); + } + + return cache[source]; }; + afterEach(() => { + cache = Object.create(null); + }); + + return importer; } diff --git a/tsconfig.json b/tsconfig.json index d06c7b1e410..1faa2d30c2e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,8 @@ "compilerOptions": { "jsx": "react", "declaration": true, - "target": "ES2018", + "lib": ["es2020"], + "target": "es2020", "module": "commonjs", "outDir": "./dist", "strict": true, @@ -14,7 +15,9 @@ "noUnusedLocals": true, "moduleResolution": "node", "esModuleInterop": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "inlineSourceMap": false, + "skipLibCheck": true }, "exclude": ["**/__tests__/**/*", "**/__mocks__/**/*"], "include": ["src/**/*"] diff --git a/yarn.lock b/yarn.lock index 28313f32993..a8f124316f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,28 +22,28 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.7.5": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8" - integrity sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw== +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.9.tgz#805461f967c77ff46c74ca0460ccf4fe933ddd59" + integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.18.10" + "@babel/generator" "^7.18.9" "@babel/helper-compilation-targets" "^7.18.9" "@babel/helper-module-transforms" "^7.18.9" "@babel/helpers" "^7.18.9" - "@babel/parser" "^7.18.10" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.18.10" - "@babel/types" "^7.18.10" + "@babel/parser" "^7.18.9" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.1" semver "^6.3.0" -"@babel/generator@^7.12.11", "@babel/generator@^7.18.10", "@babel/generator@^7.7.2": +"@babel/generator@^7.18.10": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.10.tgz#794f328bfabdcbaf0ebf9bf91b5b57b61fa77a2a" integrity sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA== @@ -52,6 +52,15 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" +"@babel/generator@^7.18.9", "@babel/generator@^7.7.2": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.9.tgz#68337e9ea8044d6ddc690fb29acae39359cca0a5" + integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug== + dependencies: + "@babel/types" "^7.18.9" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + "@babel/helper-compilation-targets@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" @@ -260,7 +269,7 @@ "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" -"@babel/traverse@^7.1.6", "@babel/traverse@^7.18.10", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.18.10": version "7.18.11" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.11.tgz#3d51f2afbd83ecf9912bcbb5c4d94e3d2ddaa16f" integrity sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ== @@ -276,7 +285,31 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": +"@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98" + integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.9" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.9" + "@babel/types" "^7.18.9" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f" + integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@babel/types@^7.18.10": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6" integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ== @@ -335,7 +368,7 @@ js-yaml "^3.13.1" resolve-from "^5.0.0" -"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": +"@istanbuljs/schema@^0.1.2": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== @@ -639,7 +672,7 @@ "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*", "@types/babel__traverse@7.17.1", "@types/babel__traverse@^7.0.6": version "7.17.1" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.17.1.tgz#1a0e73e8c28c7e832656db372b779bfd2ef37314" integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== @@ -720,6 +753,11 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.4.tgz#ad899dad022bab6b5a9f0a0fe67c2f7a4a8950ed" integrity sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw== +"@types/resolve@1.20.2": + version "1.20.2" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" + integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== + "@types/rimraf@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.2.tgz#a63d175b331748e5220ad48c901d7bbf1f44eef8" @@ -909,13 +947,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -ast-types@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.14.2.tgz#600b882df8583e3cd4f2df5fa20fa83759d4bdfd" - integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== - dependencies: - tslib "^2.0.1" - babel-jest@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" @@ -1025,24 +1056,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -c8@^7.6.0: - version "7.12.0" - resolved "https://registry.yarnpkg.com/c8/-/c8-7.12.0.tgz#402db1c1af4af5249153535d1c84ad70c5c96b14" - integrity sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@istanbuljs/schema" "^0.1.3" - find-up "^5.0.0" - foreground-child "^2.0.0" - istanbul-lib-coverage "^3.2.0" - istanbul-lib-report "^3.0.0" - istanbul-reports "^3.1.4" - rimraf "^3.0.2" - test-exclude "^6.0.0" - v8-to-istanbul "^9.0.0" - yargs "^16.2.0" - yargs-parser "^20.2.9" - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -1160,7 +1173,7 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" -cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@7.0.3, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1404,15 +1417,6 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-to-babel@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/estree-to-babel/-/estree-to-babel-3.2.1.tgz#82e78315275c3ca74475fdc8ac1a5103c8a75bf5" - integrity sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg== - dependencies: - "@babel/traverse" "^7.1.6" - "@babel/types" "^7.2.0" - c8 "^7.6.0" - esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -1537,14 +1541,6 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== -foreground-child@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" - integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^3.0.2" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1809,7 +1805,7 @@ istanbul-lib-source-maps@^4.0.0: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.1.3, istanbul-reports@^3.1.4: +istanbul-reports@^3.1.3: version "3.1.5" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== @@ -2338,12 +2334,12 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -neo-async@^2.6.1: +neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -node-dir@^0.1.10: +node-dir@^0.1.17: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" integrity sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg== @@ -2584,7 +2580,7 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== -resolve@^1.17.0, resolve@^1.20.0: +resolve@^1.20.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -2641,7 +2637,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -2835,11 +2831,6 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -2906,7 +2897,7 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^9.0.0, v8-to-istanbul@^9.0.1: +v8-to-istanbul@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== @@ -2966,29 +2957,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@^20.2.2, yargs-parser@^20.2.9: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - yargs-parser@^21.0.0, yargs-parser@^21.0.1: version "21.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.0.tgz#a11d06a3bf57f064e951aa3ef55fcf3a5705f876" integrity sha512-xzm2t63xTV/f7+bGMSRzLhUNk1ajv/tDoaD5OeGyC3cFo2fl7My9Z4hS3q2VdQ7JaLvTxErO8Jp5pRIFGMD/zg== -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yargs@^17.3.1: version "17.5.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" From 5ff929ee0e1d6551b915290c70a4eb02feb907fd Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 23 Jul 2022 20:49:30 +0200 Subject: [PATCH 02/44] chore: Do a benchmark for new version vs old --- benchmark/index.js | 24 +- benchmark/package.json | 5 +- benchmark/yarn.lock | 907 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 925 insertions(+), 11 deletions(-) diff --git a/benchmark/index.js b/benchmark/index.js index cd575efa48d..1067f0027d8 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -3,10 +3,12 @@ const path = require('path'); const Table = require('cli-table'); const Benchmark = require('benchmark'); const { parse } = require('..'); +const { parse: parse5 } = require('react-docgen5'); +const { parse: parse6old } = require('react-docgen6pre'); console.log(`Node: ${process.version}`); -const head = ['fixture', 'timing']; +const head = ['fixture', 'current', 'v6.0.0-alpha.3', 'v5.4.3']; const files = ['./fixtures/CircularProgress.js']; @@ -31,10 +33,17 @@ files.forEach(file => { const options = { filename: file, babelrc: false, configFile: false }; // warmup - parse(code, null, null, options); + parse(code, undefined, undefined, undefined, options); + parse5(code, undefined, undefined, options); global.gc(); - suite.add(0, () => { - parse(code, null, null, options); + suite.add('current', () => { + parse(code, undefined, undefined, undefined, options); + }); + suite.add('v6.0.0-alpha.3', () => { + parse6old(code, undefined, undefined, options); + }); + suite.add('v5.4.3', () => { + parse5(code, undefined, undefined, options); }); const result = [suite.name]; suite.on('cycle', function (event) { @@ -49,8 +58,13 @@ files.forEach(file => { } global.gc(); }); + suite.on('complete', function () { + process.stdout.write( + '-> Winner: ' + this.filter('fastest').map('name') + '\n', + ); + }); - console.log(`Running benchmark for ${suite.name} ...`); + process.stdout.write(`Running benchmark for ${suite.name} ... `); global.gc(); suite.run({ async: false }); global.gc(); // gc is disabled so ensure we run it diff --git a/benchmark/package.json b/benchmark/package.json index c6f90edb5ba..33248a9a259 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -8,6 +8,9 @@ "license": "MIT", "dependencies": { "benchmark": "2.1.4", - "cli-table": "0.3.11" + "cli-table": "0.3.11", + "microtime": "3.1.0", + "react-docgen5": "npm:react-docgen@5.4.3", + "react-docgen6pre": "npm:react-docgen@6.0.0-alpha.3" } } diff --git a/benchmark/yarn.lock b/benchmark/yarn.lock index 95f02c2f890..ae7f2183d93 100644 --- a/benchmark/yarn.lock +++ b/benchmark/yarn.lock @@ -2,32 +2,929 @@ # yarn lockfile v1 +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.18.8": + version "7.18.8" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== + +"@babel/core@^7.7.5": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz" + integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.9" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helpers" "^7.18.9" + "@babel/parser" "^7.18.9" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.12.11", "@babel/generator@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz" + integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug== + dependencies: + "@babel/types" "^7.18.9" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helpers@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.18.6", "@babel/parser@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz" + integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg== + +"@babel/runtime@^7.7.6": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz" + integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz" + integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/traverse@^7.1.6", "@babel/traverse@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz" + integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.9" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.9" + "@babel/types" "^7.18.9" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.2.0": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz" + integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ast-types@^0.14.2: + version "0.14.2" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz" + integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== + dependencies: + tslib "^2.0.1" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + benchmark@2.1.4: version "2.1.4" - resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629" + resolved "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz" integrity sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ== dependencies: lodash "^4.17.4" platform "^1.3.3" +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +browserslist@^4.20.2: + version "4.21.2" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz" + integrity sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA== + dependencies: + caniuse-lite "^1.0.30001366" + electron-to-chromium "^1.4.188" + node-releases "^2.0.6" + update-browserslist-db "^1.0.4" + +c8@^7.6.0: + version "7.12.0" + resolved "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz" + integrity sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@istanbuljs/schema" "^0.1.3" + find-up "^5.0.0" + foreground-child "^2.0.0" + istanbul-lib-coverage "^3.2.0" + istanbul-lib-report "^3.0.0" + istanbul-reports "^3.1.4" + rimraf "^3.0.2" + test-exclude "^6.0.0" + v8-to-istanbul "^9.0.0" + yargs "^16.2.0" + yargs-parser "^20.2.9" + +caniuse-lite@^1.0.30001366: + version "1.0.30001369" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz" + integrity sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + cli-table@0.3.11: version "0.3.11" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.11.tgz#ac69cdecbe81dccdba4889b9a18b7da312a9d3ee" + resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz" integrity sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ== dependencies: colors "1.0.3" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + colors@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== +commander@^2.19.0: + version "2.20.3" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +electron-to-chromium@^1.4.188: + version "1.4.199" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz" + integrity sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +estree-to-babel@^3.1.0: + version "3.2.1" + resolved "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz" + integrity sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg== + dependencies: + "@babel/traverse" "^7.1.6" + "@babel/types" "^7.2.0" + c8 "^7.6.0" + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +foreground-child@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz" + integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^3.0.2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-reports@^3.1.4: + version "3.1.5" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash@^4.17.4: version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +microtime@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/microtime/-/microtime-3.1.0.tgz#599a71250e3116c59f0fe5271dae4cc44321869c" + integrity sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ== + dependencies: + node-addon-api "^5.0.0" + node-gyp-build "^4.4.0" + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +neo-async@^2.6.1: + version "2.6.2" + resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-addon-api@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.0.0.tgz#7d7e6f9ef89043befdb20c1989c905ebde18c501" + integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA== + +node-dir@^0.1.10: + version "0.1.17" + resolved "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz" + integrity sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg== + dependencies: + minimatch "^3.0.2" + +node-gyp-build@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" + integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== + +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + platform@^1.3.3: version "1.3.6" - resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" + resolved "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz" integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== + +"react-docgen5@npm:react-docgen@5.4.3": + version "5.4.3" + resolved "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz" + integrity sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA== + dependencies: + "@babel/core" "^7.7.5" + "@babel/generator" "^7.12.11" + "@babel/runtime" "^7.7.6" + ast-types "^0.14.2" + commander "^2.19.0" + doctrine "^3.0.0" + estree-to-babel "^3.1.0" + neo-async "^2.6.1" + node-dir "^0.1.10" + strip-indent "^3.0.0" + +"react-docgen6pre@npm:react-docgen@6.0.0-alpha.3": + version "6.0.0-alpha.3" + resolved "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz" + integrity sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA== + dependencies: + "@babel/core" "^7.7.5" + "@babel/generator" "^7.12.11" + ast-types "^0.14.2" + commander "^2.19.0" + doctrine "^3.0.0" + estree-to-babel "^3.1.0" + neo-async "^2.6.1" + node-dir "^0.1.10" + resolve "^1.17.0" + strip-indent "^3.0.0" + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve@^1.17.0: + version "1.22.1" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +tslib@^2.0.1: + version "2.4.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +update-browserslist-db@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz" + integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +v8-to-istanbul@^9.0.0: + version "9.0.1" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 5d52f4a96f7e3307400ae277e1707b4f57455485 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 23 Jul 2022 21:11:50 +0200 Subject: [PATCH 03/44] chore: fix normalize --- src/utils/normalizeClassDefinition.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/normalizeClassDefinition.ts b/src/utils/normalizeClassDefinition.ts index 8788665b76b..53241d6a214 100644 --- a/src/utils/normalizeClassDefinition.ts +++ b/src/utils/normalizeClassDefinition.ts @@ -39,9 +39,8 @@ export default function normalizeClassDefinition( variableName = classDefinition.node.id.name; } } else if (classDefinition.isClassExpression()) { - let parentPath: NodePath | null = classDefinition.parentPath; + let parentPath: NodePath = classDefinition.parentPath; while ( - parentPath && parentPath.node !== classDefinition.scope.block && !parentPath.isBlockStatement() ) { From 0538d2320a2067069478a0d2cdb0d2dbb148ea75 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 23 Jul 2022 21:12:32 +0200 Subject: [PATCH 04/44] chore: remove node 12 from workflow --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c506042a301..0e976252631 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: tests: strategy: matrix: - node: ['12', '14', '16', '18'] + node: ['14', '16', '18'] name: Unit tests (Node v${{ matrix.node }}) runs-on: ubuntu-latest From dfef72ac520a2666927a8250bf5cddbb3a20dccc Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 23 Jul 2022 21:14:57 +0200 Subject: [PATCH 05/44] chore: revert --- src/utils/normalizeClassDefinition.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/normalizeClassDefinition.ts b/src/utils/normalizeClassDefinition.ts index 53241d6a214..8788665b76b 100644 --- a/src/utils/normalizeClassDefinition.ts +++ b/src/utils/normalizeClassDefinition.ts @@ -39,8 +39,9 @@ export default function normalizeClassDefinition( variableName = classDefinition.node.id.name; } } else if (classDefinition.isClassExpression()) { - let parentPath: NodePath = classDefinition.parentPath; + let parentPath: NodePath | null = classDefinition.parentPath; while ( + parentPath && parentPath.node !== classDefinition.scope.block && !parentPath.isBlockStatement() ) { From 40e10e2b95bdd4dd17a5373146191d94489c464c Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 00:17:34 +0200 Subject: [PATCH 06/44] fix: Add `.cts` and `.mts` support for typescript --- src/babelParser.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/babelParser.ts b/src/babelParser.ts index 4936de3a9f7..eafe2581a04 100644 --- a/src/babelParser.ts +++ b/src/babelParser.ts @@ -4,6 +4,8 @@ import type { File } from '@babel/types'; import path from 'path'; const TYPESCRIPT_EXTS = { + '.cts': true, + '.mts': true, '.ts': true, '.tsx': true, }; From 7d9b30533882f1272d003e3cce58ee0f05de1a66 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 00:18:01 +0200 Subject: [PATCH 07/44] fix: Update default babel options --- src/babelParser.ts | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/babelParser.ts b/src/babelParser.ts index eafe2581a04..38368626ff7 100644 --- a/src/babelParser.ts +++ b/src/babelParser.ts @@ -18,28 +18,21 @@ function getDefaultPlugins( TYPESCRIPT_EXTS[path.extname(options.filename || '')] ? 'typescript' : 'flow', - 'asyncGenerators', - 'bigInt', - 'classProperties', - 'classPrivateProperties', - 'classPrivateMethods', + 'asyncDoExpressions', + 'decimal', ['decorators', { decoratorsBeforeExport: false }], + 'decoratorAutoAccessors', + 'destructuringPrivate', 'doExpressions', - 'dynamicImport', 'exportDefaultFrom', - 'exportNamespaceFrom', 'functionBind', - 'functionSent', - 'importMeta', - 'logicalAssignment', - 'nullishCoalescingOperator', - 'numericSeparator', - 'objectRestSpread', - 'optionalCatchBinding', - 'optionalChaining', + 'importAssertions', + 'moduleBlocks', + 'partialApplication', ['pipelineOperator', { proposal: 'minimal' }], + ['recordAndTuple', { syntaxType: 'bar' }], + 'regexpUnicodeSets', 'throwExpressions', - 'topLevelAwait', ]; } @@ -84,6 +77,8 @@ function buildOptions( const plugins = buildPluginList(parserOptions, babelOptions); return { + sourceType: 'unambiguous', + tokens: false, ...(parserOptions || {}), plugins, }; From 3fdb7532d74d32f4eabea6032fe9886b6295cc2f Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 00:18:24 +0200 Subject: [PATCH 08/44] fix: Filter out estree plugin --- src/babelParser.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/babelParser.ts b/src/babelParser.ts index 38368626ff7..692ee1d0201 100644 --- a/src/babelParser.ts +++ b/src/babelParser.ts @@ -60,14 +60,8 @@ function buildPluginList( } // Ensure that the estree plugin is never active - if (plugins.includes('estree')) { - throw new Error( - //TODO not throw, just remove - 'The estree plugin is active for @babel/parser. As of version 6 react-docgen must have this plugin disabled.', - ); - } - - return plugins; + // TODO add test + return plugins.filter(plugin => plugin !== 'estree'); } function buildOptions( From 19b37ab7d8d596da05366513b20c9090040052f9 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 00:35:04 +0200 Subject: [PATCH 09/44] chore: cleanup code --- src/utils/__tests__/isStatelessComponent-test.ts | 8 ++++---- src/utils/isStatelessComponent.ts | 14 +------------- src/utils/isUnreachableFlowType.ts | 5 +---- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/utils/__tests__/isStatelessComponent-test.ts b/src/utils/__tests__/isStatelessComponent-test.ts index 66387a8d594..6d1fe5f695c 100644 --- a/src/utils/__tests__/isStatelessComponent-test.ts +++ b/src/utils/__tests__/isStatelessComponent-test.ts @@ -74,10 +74,10 @@ describe('isStatelessComponent', () => { }); const negativeModifiers = { - //'nested ArrowExpression': (expr: string): string => `() => ${expr}`, - //'nested ArrowBlock': (expr: string): string => `() => { return ${expr} }`, - //'nested FunctionExpression': (expr: string): string => - // `function () { return ${expr} }`, + 'nested ArrowExpression': (expr: string): string => `() => ${expr}`, + 'nested ArrowBlock': (expr: string): string => `() => { return ${expr} }`, + 'nested FunctionExpression': (expr: string): string => + `function () { return ${expr} }`, }; Object.keys(cases).forEach(name => { diff --git a/src/utils/isStatelessComponent.ts b/src/utils/isStatelessComponent.ts index 54236419c80..400318f6e68 100644 --- a/src/utils/isStatelessComponent.ts +++ b/src/utils/isStatelessComponent.ts @@ -1,11 +1,10 @@ import getPropertyValuePath from './getPropertyValuePath'; -import isReactCreateClassCall from './isReactCreateClassCall'; import isReactCreateElementCall from './isReactCreateElementCall'; import isReactCloneElementCall from './isReactCloneElementCall'; import isReactChildrenElementCall from './isReactChildrenElementCall'; import resolveToValue from './resolveToValue'; import type { NodePath } from '@babel/traverse'; -import type { Expression, ObjectExpression } from '@babel/types'; +import type { Expression } from '@babel/types'; const validPossibleStatelessComponentTypes = [ 'ObjectMethod', @@ -200,17 +199,6 @@ export default function isStatelessComponent(path: NodePath): boolean { return false; } - if (path.isObjectMethod()) { - // TODO check this, I think this does not work as expected, need to go up 2 parents - // Also property/ObjectMethod is not part of classes?!? - if ( - isReactCreateClassCall(path.parentPath as NodePath) //|| - //isReactComponentClass(path.parent) - ) { - return false; - } - } - if (returnsJSXElementOrReactCall(path)) { return true; } diff --git a/src/utils/isUnreachableFlowType.ts b/src/utils/isUnreachableFlowType.ts index c25af72ae62..61dc6d975d8 100644 --- a/src/utils/isUnreachableFlowType.ts +++ b/src/utils/isUnreachableFlowType.ts @@ -5,9 +5,6 @@ import type { NodePath } from '@babel/traverse'; */ export default (path: NodePath): boolean => { return ( - !path || // TODO Remove if we are fully typed - path.isIdentifier() || - path.isImportDeclaration() || - path.isCallExpression() + path.isIdentifier() || path.isImportDeclaration() || path.isCallExpression() ); }; From 3231443ad5586d8fdfed00a660e65163e4c0aa07 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 00:35:46 +0200 Subject: [PATCH 10/44] chore: more cleanup --- src/utils/isStatelessComponent.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/utils/isStatelessComponent.ts b/src/utils/isStatelessComponent.ts index 400318f6e68..ba018c4da69 100644 --- a/src/utils/isStatelessComponent.ts +++ b/src/utils/isStatelessComponent.ts @@ -199,9 +199,5 @@ export default function isStatelessComponent(path: NodePath): boolean { return false; } - if (returnsJSXElementOrReactCall(path)) { - return true; - } - - return false; + return returnsJSXElementOrReactCall(path); } From dd3804e835baec487254db5e0b3c0cd5087f0dcd Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 00:49:34 +0200 Subject: [PATCH 11/44] chore: improve code around traversal --- src/handlers/componentMethodsHandler.ts | 24 ++-- src/importer/makeFsImporter.ts | 130 +++++++++--------- .../resolveFunctionDefinitionToReturnValue.ts | 22 ++- src/utils/resolveToValue.ts | 63 ++++----- src/utils/traverse.ts | 14 +- 5 files changed, 117 insertions(+), 136 deletions(-) diff --git a/src/handlers/componentMethodsHandler.ts b/src/handlers/componentMethodsHandler.ts index 279d73c0b52..af0ae81a419 100644 --- a/src/handlers/componentMethodsHandler.ts +++ b/src/handlers/componentMethodsHandler.ts @@ -7,7 +7,7 @@ import type Documentation from '../Documentation'; import match from '../utils/match'; import { traverseShallow } from '../utils/traverse'; import resolveToValue from '../utils/resolveToValue'; -import type { NodePath, Scope } from '@babel/traverse'; +import type { NodePath } from '@babel/traverse'; import type { AssignmentExpression, Identifier } from '@babel/types'; /** @@ -35,7 +35,7 @@ function isMethod(path: NodePath): boolean { } function findAssignedMethods( - scope: Scope, + path: NodePath, idPath: NodePath, ): Array> { const results: Array> = []; @@ -47,19 +47,19 @@ function findAssignedMethods( const name = idPath.node.name; const idScope = idPath.scope.getBinding(idPath.node.name)?.scope; - traverseShallow(scope.path.node, { - AssignmentExpression(path) { - const node = path.node; + traverseShallow(path, { + AssignmentExpression(assignmentPath) { + const node = assignmentPath.node; if ( match(node.left, { type: 'MemberExpression', object: { type: 'Identifier', name }, }) && - path.scope.getBinding(name)?.scope === idScope && - resolveToValue(path.get('right')).isFunction() + assignmentPath.scope.getBinding(name)?.scope === idScope && + resolveToValue(assignmentPath.get('right')).isFunction() ) { - results.push(path); - path.skip(); + results.push(assignmentPath); + assignmentPath.skip(); } }, }); @@ -110,7 +110,7 @@ export default function componentMethodsHandler( path.parentPath.get('id').isIdentifier() ) { methodPaths = findAssignedMethods( - path.parentPath.scope, + path.parentPath.scope.path, path.parentPath.get('id') as NodePath, ).map(p => ({ path: p })); } else if ( @@ -120,12 +120,12 @@ export default function componentMethodsHandler( path.parentPath.get('left').isIdentifier() ) { methodPaths = findAssignedMethods( - path.parentPath.scope, + path.parentPath.scope.path, path.parentPath.get('left') as NodePath, ).map(p => ({ path: p })); } else if (path.isFunctionDeclaration()) { methodPaths = findAssignedMethods( - path.parentPath.scope, + path.parentPath.scope.path, path.get('id'), ).map(p => ({ path: p })); } diff --git a/src/importer/makeFsImporter.ts b/src/importer/makeFsImporter.ts index 643186e4f26..f4a00063245 100644 --- a/src/importer/makeFsImporter.ts +++ b/src/importer/makeFsImporter.ts @@ -75,78 +75,74 @@ export default function makeFsImporter( ): NodePath | null { let resultPath: NodePath | null = null; - traverseShallow( - state.ast, - { - ExportNamedDeclaration(path) { - const { declaration, specifiers, source } = path.node; - if ( - declaration && - 'id' in declaration && - declaration.id && - 'name' in declaration.id && - declaration.id.name === name - ) { - resultPath = path.get('declaration') as NodePath; - } else if ( - declaration && - 'declarations' in declaration && - declaration.declarations - ) { - (path.get('declaration') as NodePath) - .get('declarations') - .forEach(declPath => { - const id = declPath.get('id'); - // TODO: ArrayPattern and ObjectPattern - if ( - id.isIdentifier() && - id.node.name === name && - 'init' in declPath.node && - declPath.node.init - ) { - resultPath = declPath.get('init') as NodePath; - } - }); - } else if (specifiers) { - path.get('specifiers').forEach(specifierPath => { + traverseShallow(state.path, { + ExportNamedDeclaration(path) { + const { declaration, specifiers, source } = path.node; + if ( + declaration && + 'id' in declaration && + declaration.id && + 'name' in declaration.id && + declaration.id.name === name + ) { + resultPath = path.get('declaration') as NodePath; + } else if ( + declaration && + 'declarations' in declaration && + declaration.declarations + ) { + (path.get('declaration') as NodePath) + .get('declarations') + .forEach(declPath => { + const id = declPath.get('id'); + // TODO: ArrayPattern and ObjectPattern if ( - 'name' in specifierPath.node.exported && - specifierPath.node.exported.name === name + id.isIdentifier() && + id.node.name === name && + 'init' in declPath.node && + declPath.node.init ) { - // TODO TESTME with ExportDefaultSpecifier - if (source) { - const local = - 'local' in specifierPath.node - ? specifierPath.node.local.name - : 'default'; - resultPath = resolveImportedValue(path, local, state, seen); - } else if ('local' in specifierPath.node) { - resultPath = specifierPath.get('local') as NodePath; - } + resultPath = declPath.get('init') as NodePath; } }); - } - - return false; - }, - ExportDefaultDeclaration(path) { - if (name === 'default') { - resultPath = path.get('declaration'); - } - - return false; - }, - ExportAllDeclaration(path) { - const resolvedPath = resolveImportedValue(path, name, state, seen); - if (resolvedPath) { - resultPath = resolvedPath; - } - - return false; - }, + } else if (specifiers) { + path.get('specifiers').forEach(specifierPath => { + if ( + 'name' in specifierPath.node.exported && + specifierPath.node.exported.name === name + ) { + // TODO TESTME with ExportDefaultSpecifier + if (source) { + const local = + 'local' in specifierPath.node + ? specifierPath.node.local.name + : 'default'; + resultPath = resolveImportedValue(path, local, state, seen); + } else if ('local' in specifierPath.node) { + resultPath = specifierPath.get('local') as NodePath; + } + } + }); + } + + return false; + }, + ExportDefaultDeclaration(path) { + if (name === 'default') { + resultPath = path.get('declaration'); + } + + return false; + }, + ExportAllDeclaration(path) { + const resolvedPath = resolveImportedValue(path, name, state, seen); + if (resolvedPath) { + resultPath = resolvedPath; + } + + return false; }, - state.scope, - ); + }); return resultPath; } diff --git a/src/utils/resolveFunctionDefinitionToReturnValue.ts b/src/utils/resolveFunctionDefinitionToReturnValue.ts index e503d78d592..3733a2da179 100644 --- a/src/utils/resolveFunctionDefinitionToReturnValue.ts +++ b/src/utils/resolveFunctionDefinitionToReturnValue.ts @@ -11,20 +11,16 @@ export default function resolveFunctionDefinitionToReturnValue( let returnPath: NodePath | null = null; const body = path.get('body'); - traverseShallow( - body.node, - { - Function: ignore, - ReturnStatement: nodePath => { - const argument = nodePath.get('argument'); - if (argument.hasNode()) { - returnPath = resolveToValue(argument); - } - nodePath.skip(); - }, + traverseShallow(body, { + Function: ignore, + ReturnStatement: nodePath => { + const argument = nodePath.get('argument'); + if (argument.hasNode()) { + returnPath = resolveToValue(argument); + } + nodePath.skip(); }, - body.scope, - ); + }); return returnPath; } diff --git a/src/utils/resolveToValue.ts b/src/utils/resolveToValue.ts index 3d376229064..00f99ffc535 100644 --- a/src/utils/resolveToValue.ts +++ b/src/utils/resolveToValue.ts @@ -63,46 +63,41 @@ function findScopePath( * `scope`. We are not descending into any statements (blocks). */ function findLastAssignedValue( - scope: Scope, + path: NodePath, idPath: NodePath, ): NodePath | null { const results: NodePath[] = []; const name = idPath.node.name; - traverseShallow( - scope.path.node, - { - AssignmentExpression(path) { - const node = path.node; - const left = path.get('left'); - // Skip anything that is not an assignment to a variable with the - // passed name. - // Ensure the LHS isn't the reference we're trying to resolve. - if ( - !left.isIdentifier() || - left.node === idPath.node || - left.node.name !== name || - node.operator !== '=' - ) { + traverseShallow(path, { + AssignmentExpression(assignmentPath) { + const left = assignmentPath.get('left'); + // Skip anything that is not an assignment to a variable with the + // passed name. + // Ensure the LHS isn't the reference we're trying to resolve. + if ( + !left.isIdentifier() || + left.node === idPath.node || + left.node.name !== name || + assignmentPath.node.operator !== '=' + ) { + return; + } + // Ensure the RHS doesn't contain the reference we're trying to resolve. + const candidatePath = assignmentPath.get('right'); + for ( + let p: NodePath | null = idPath; + p && p.node != null; + p = p.parentPath + ) { + if (p.node === candidatePath.node) { return; } - // Ensure the RHS doesn't contain the reference we're trying to resolve. - const candidatePath = path.get('right'); - for ( - let p: NodePath | null = idPath; - p && p.node != null; - p = p.parentPath - ) { - if (p.node === candidatePath.node) { - return; - } - } - results.push(candidatePath); - return path.skip(); - }, + } + results.push(candidatePath); + return assignmentPath.skip(); }, - scope, - ); + }); const resultPath = results.pop(); @@ -204,9 +199,9 @@ export default function resolveToValue(path: NodePath): NodePath { // The variable may be assigned a different value after initialization. // We are first trying to find all assignments to the variable in the // block where it is defined (i.e. we are not traversing into statements) - resolvedPath = findLastAssignedValue(binding.scope, path); + resolvedPath = findLastAssignedValue(binding.scope.path, path); if (!resolvedPath) { - // @ts-ignore + // @ts-ignore TODO fix in DT const bindingMap = binding.path.getOuterBindingIdentifierPaths( true, ) as Record>>; diff --git a/src/utils/traverse.ts b/src/utils/traverse.ts index 67c9634c830..262461e287d 100644 --- a/src/utils/traverse.ts +++ b/src/utils/traverse.ts @@ -1,6 +1,4 @@ -import type { NodePath, Scope, Visitor } from '@babel/traverse'; -import { default as babelTraverse } from '@babel/traverse'; -import type { Node } from '@babel/types'; +import type { NodePath, Visitor } from '@babel/traverse'; export function ignore(path: NodePath): void { path.skip(); @@ -10,15 +8,11 @@ export function ignore(path: NodePath): void { * A helper function that doesn't traverse into nested blocks / statements by * default. */ -export function traverseShallow( - node: Node, - visitors: Visitor, - scope?: Scope | undefined, -): void { - babelTraverse(node, { ...defaultVisitors, ...visitors }, scope); +export function traverseShallow(path: NodePath, visitors: Visitor): void { + path.traverse({ ...shallowIgnoreVisitors, ...visitors }); } -const defaultVisitors = { +const shallowIgnoreVisitors = { FunctionDeclaration: ignore, FunctionExpression: ignore, ClassDeclaration: ignore, From af40b13768292d6de5a8a5f7ee602c61125eb0c1 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 11:47:32 +0200 Subject: [PATCH 12/44] fix: Support class and function declarations without identifier --- src/__tests__/__snapshots__/main-test.ts.snap | 18 +++++++++++++++ src/__tests__/fixtures/class-without-id.tsx | 11 ++++++++++ .../__tests__/displayNameHandler-test.ts | 22 +++++++++++++++---- src/handlers/displayNameHandler.ts | 13 ++++++----- 4 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 src/__tests__/fixtures/class-without-id.tsx diff --git a/src/__tests__/__snapshots__/main-test.ts.snap b/src/__tests__/__snapshots__/main-test.ts.snap index b3a55bf4443..e62b9ee6520 100644 --- a/src/__tests__/__snapshots__/main-test.ts.snap +++ b/src/__tests__/__snapshots__/main-test.ts.snap @@ -163,6 +163,24 @@ Array [ ] `; +exports[`main fixtures processes component "class-without-id.tsx" without errors 1`] = ` +Array [ + Object { + "description": "", + "methods": Array [], + "props": Object { + "value": Object { + "description": "", + "required": true, + "tsType": Object { + "name": "string", + }, + }, + }, + }, +] +`; + exports[`main fixtures processes component "component_1.js" without errors 1`] = ` Array [ Object { diff --git a/src/__tests__/fixtures/class-without-id.tsx b/src/__tests__/fixtures/class-without-id.tsx new file mode 100644 index 00000000000..6c62d1d27cf --- /dev/null +++ b/src/__tests__/fixtures/class-without-id.tsx @@ -0,0 +1,11 @@ +import * as React from 'react'; + +interface IProps { + value: string; +} + +export default class extends React.Component { + render() { + return
; + } +} diff --git a/src/handlers/__tests__/displayNameHandler-test.ts b/src/handlers/__tests__/displayNameHandler-test.ts index 9314247723c..0170123589a 100644 --- a/src/handlers/__tests__/displayNameHandler-test.ts +++ b/src/handlers/__tests__/displayNameHandler-test.ts @@ -4,6 +4,7 @@ import displayNameHandler from '../displayNameHandler'; import type DocumentationMock from '../../__mocks__/Documentation'; import type { ArrowFunctionExpression, + ExportDefaultDeclaration, ExpressionStatement, FunctionExpression, } from '@babel/types'; @@ -163,14 +164,19 @@ describe('defaultPropsHandler', () => { describe('ClassDeclaration', () => { it('considers the class name', () => { - const definition = parse.statement(` - class Foo { - } - `); + const definition = parse.statement(`class Foo {}`); expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); + it('does not crash if no name', () => { + const definition = parse + .statement(`export default class {}`) + .get('declaration'); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); + expect(documentation.displayName).toBeUndefined(); + }); + it('considers a static displayName class property', () => { const definition = parse.statement(` class Foo { @@ -244,6 +250,14 @@ describe('defaultPropsHandler', () => { expect(documentation.displayName).toBe('Foo'); }); + it('does not crash if no name', () => { + const definition = parse + .statement(`export default function () {}`) + .get('declaration'); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); + expect(documentation.displayName).toBeUndefined(); + }); + it('considers a static displayName object property', () => { const definition = parse.statement(` function Foo () {} diff --git a/src/handlers/displayNameHandler.ts b/src/handlers/displayNameHandler.ts index 10daec4c1b3..0e7e07497c5 100644 --- a/src/handlers/displayNameHandler.ts +++ b/src/handlers/displayNameHandler.ts @@ -4,24 +4,27 @@ import isReactForwardRefCall from '../utils/isReactForwardRefCall'; import resolveToValue from '../utils/resolveToValue'; import resolveFunctionDefinitionToReturnValue from '../utils/resolveFunctionDefinitionToReturnValue'; import type Documentation from '../Documentation'; -import type { Node, NodePath } from '@babel/traverse'; +import type { NodePath } from '@babel/traverse'; +import type { Identifier } from '@babel/types'; export default function displayNameHandler( documentation: Documentation, path: NodePath, ): void { - let displayNamePath: NodePath | null = getMemberValuePath( + let displayNamePath: NodePath | null = getMemberValuePath( path, 'displayName', ); if (!displayNamePath) { // Function and class declarations need special treatment. The name of the // function / class is the displayName - // TODO test class declaration without id - if (path.isClassDeclaration() || path.isFunctionDeclaration()) { + if ( + (path.isClassDeclaration() || path.isFunctionDeclaration()) && + path.has('id') + ) { documentation.set( 'displayName', - getNameOrValue(path.get('id') as NodePath), + getNameOrValue(path.get('id') as NodePath), ); } else if ( path.isArrowFunctionExpression() || From f87f8f02d1ea18fe06e77eef4c1035db7118ba08 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 12:18:45 +0200 Subject: [PATCH 13/44] fix: Support all possible kinds of functions in the `displayNameHandler` --- .../__tests__/displayNameHandler-test.ts | 184 ++++++++++-------- src/handlers/displayNameHandler.ts | 11 +- 2 files changed, 108 insertions(+), 87 deletions(-) diff --git a/src/handlers/__tests__/displayNameHandler-test.ts b/src/handlers/__tests__/displayNameHandler-test.ts index 0170123589a..79786e132d3 100644 --- a/src/handlers/__tests__/displayNameHandler-test.ts +++ b/src/handlers/__tests__/displayNameHandler-test.ts @@ -7,6 +7,7 @@ import type { ExportDefaultDeclaration, ExpressionStatement, FunctionExpression, + ObjectExpression, } from '@babel/types'; import type { NodePath } from '@babel/traverse'; @@ -37,37 +38,15 @@ describe('defaultPropsHandler', () => { }); it('extracts the displayName', () => { - let definition: NodePath = parse.expression('{displayName: "FooBar"}'); + const definition: NodePath = parse.expression('{displayName: "FooBar"}'); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBar'); + }); - definition = parse - .statement( - ` - ({displayName: foobarbaz}); - import foobarbaz from 'foobarbaz'; - `, - mockImporter, - ) - .get('expression'); - displayNameHandler(documentation, definition); - expect(documentation.displayName).toBe('FooBarBaz'); - - definition = parse.statement(` - class Foo { - static displayName = "BarFoo"; - } - `); - displayNameHandler(documentation, definition); - expect(documentation.displayName).toBe('BarFoo'); - - definition = parse.statement( - ` - class Foo { - static displayName = foobarbaz; - } - import foobarbaz from 'foobarbaz'; - `, + it('extracts the imported displayName', () => { + const definition = parse.expressionLast( + `import foobarbaz from 'foobarbaz'; + ({displayName: foobarbaz});`, mockImporter, ); displayNameHandler(documentation, definition); @@ -75,7 +54,7 @@ describe('defaultPropsHandler', () => { }); it('resolves identifiers', () => { - let definition: NodePath = parse + const definition = parse .statement( ` ({displayName: name}) @@ -85,8 +64,10 @@ describe('defaultPropsHandler', () => { .get('expression'); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('abc'); + }); - definition = parse + it('resolves imported identifiers', () => { + const definition = parse .statement( ` ({displayName: name}) @@ -98,46 +79,10 @@ describe('defaultPropsHandler', () => { .get('expression'); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); - - definition = parse.statement(` - class Foo { - static displayName = name; - } - var name = 'xyz'; - `); - displayNameHandler(documentation, definition); - expect(documentation.displayName).toBe('xyz'); - - definition = parse.statement( - ` - class Foo { - static displayName = name; - } - import foobarbaz from 'foobarbaz'; - var name = foobarbaz; - `, - mockImporter, - ); - displayNameHandler(documentation, definition); - expect(documentation.displayName).toBe('FooBarBaz'); - }); - - it('ignores non-literal names', () => { - let definition = parse.expression('{displayName: foo.bar}'); - expect(() => displayNameHandler(documentation, definition)).not.toThrow(); - expect(documentation.displayName).not.toBeDefined(); - - definition = parse.statement(` - class Foo { - static displayName = foo.bar; - } - `); - expect(() => displayNameHandler(documentation, definition)).not.toThrow(); - expect(documentation.displayName).not.toBeDefined(); }); it('can resolve non-literal names with appropriate importer', () => { - let definition = parse + const definition = parse .statement( ` ({displayName: foo.bar}); @@ -148,18 +93,6 @@ describe('defaultPropsHandler', () => { .get('expression'); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); - - definition = parse.statement( - ` - class Foo { - static displayName = bar.baz; - } - import bar from 'bar'; - `, - mockImporter, - ); - displayNameHandler(documentation, definition); - expect(documentation.displayName).toBe('foo'); }); describe('ClassDeclaration', () => { @@ -177,6 +110,74 @@ describe('defaultPropsHandler', () => { expect(documentation.displayName).toBeUndefined(); }); + it('resolves identifiers', () => { + const definition = parse.statement(` + class Foo { + static displayName = name; + } + var name = 'xyz'; + `); + displayNameHandler(documentation, definition); + expect(documentation.displayName).toBe('xyz'); + }); + + it('resolves imported identifiers', () => { + const definition = parse.statement( + ` + class Foo { + static displayName = name; + } + import foobarbaz from 'foobarbaz'; + var name = foobarbaz; + `, + mockImporter, + ); + displayNameHandler(documentation, definition); + expect(documentation.displayName).toBe('FooBarBaz'); + }); + + it('resolves imported displayName', () => { + const definition = parse.statement( + ` + class Foo { + static displayName = foobarbaz; + } + import foobarbaz from 'foobarbaz'; + `, + mockImporter, + ); + displayNameHandler(documentation, definition); + expect(documentation.displayName).toBe('FooBarBaz'); + }); + + it('ignores non-literal names', () => { + let definition = parse.expression('{displayName: foo.bar}'); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); + expect(documentation.displayName).not.toBeDefined(); + + definition = parse.statement(` + class Foo { + static displayName = foo.bar; + } + `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); + expect(documentation.displayName).toBeUndefined(); + }); + + it('can resolve non-literal names with appropriate importer', () => { + const definition = parse.statement( + ` + class Foo { + static displayName = bar.baz; + } + import bar from 'bar'; + `, + mockImporter, + ); + displayNameHandler(documentation, definition); + expect(documentation.displayName).toBe('foo'); + }); + it('considers a static displayName class property', () => { const definition = parse.statement(` class Foo { @@ -199,6 +200,31 @@ describe('defaultPropsHandler', () => { expect(documentation.displayName).toBe('foo'); }); + it('considers static displayName property with function expression', () => { + const definition = parse.statement(` + class Foo { + static displayName = function() { + return 'foo'; + } + } + `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); + expect(documentation.displayName).toBe('foo'); + }); + + it('considers static displayName property with function declaration', () => { + const definition = parse.statement(` + class Foo { + static displayName = displayName; + } + function displayName() { + return 'foo'; + } + `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); + expect(documentation.displayName).toBe('foo'); + }); + it('resolves variables in displayName getter', () => { const definition = parse.statement(` class Foo { diff --git a/src/handlers/displayNameHandler.ts b/src/handlers/displayNameHandler.ts index 0e7e07497c5..4c2ad85d2a3 100644 --- a/src/handlers/displayNameHandler.ts +++ b/src/handlers/displayNameHandler.ts @@ -53,14 +53,9 @@ export default function displayNameHandler( } displayNamePath = resolveToValue(displayNamePath); - // If display name is defined as a getter we get a function expression as - // value. In that case we try to determine the value from the return - // statement. - if ( - displayNamePath.isFunctionExpression() || - displayNamePath.isClassMethod() || - displayNamePath.isObjectMethod() // TODO test objectmethod? Do we need it? - ) { + // If display name is defined as function somehow (getter, property with function) + // we resolve the return value of the function + if (displayNamePath.isFunction()) { displayNamePath = resolveFunctionDefinitionToReturnValue(displayNamePath); } if ( From 3ea4b1993294039c565f2965f2f05112f3587442 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 12:47:13 +0200 Subject: [PATCH 14/44] chore: Refactor for readability and slight performance --- src/utils/getClassMemberValuePath.ts | 57 ++++++++++++++-------------- src/utils/getPropertyValuePath.ts | 26 ++++++------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/utils/getClassMemberValuePath.ts b/src/utils/getClassMemberValuePath.ts index be5c471e0a6..9868fd888ca 100644 --- a/src/utils/getClassMemberValuePath.ts +++ b/src/utils/getClassMemberValuePath.ts @@ -12,33 +12,34 @@ export default function getClassMemberValuePath( classDefinition: NodePath, memberName: string, ): NodePath | null { - // Fortunately it seems like that all members of a class body, be it - // ClassProperty or ClassMethod, have the same structure: They have a - // "key" and a "value" - return ( - classDefinition - .get('body') - .get('body') - .filter(memberPath => { - if ( - (memberPath.isClassMethod() && memberPath.node.kind !== 'set') || - memberPath.isClassProperty() - ) { - const key = (memberPath as NodePath).get( - 'key', - ); - return ( - (!memberPath.node.computed || key.isLiteral()) && - getNameOrValue(key) === memberName - ); - } + const classMember = classDefinition + .get('body') + .get('body') + .find(memberPath => { + if ( + (memberPath.isClassMethod() && memberPath.node.kind !== 'set') || + memberPath.isClassProperty() + ) { + const key = (memberPath as NodePath).get( + 'key', + ); - return false; - }) //TODO ClassMethod does not have value - .map(memberPath => - memberPath.isClassMethod() - ? memberPath - : (memberPath.get('value') as NodePath), - )[0] || null - ); + return ( + (!memberPath.node.computed || key.isLiteral()) && + getNameOrValue(key) === memberName + ); + } + + return false; + }); + + if (classMember) { + // For ClassProperty we return the value and for ClassMethod + // we return itself + return classMember.isClassMethod() + ? classMember + : (classMember.get('value') as NodePath); + } + + return null; } diff --git a/src/utils/getPropertyValuePath.ts b/src/utils/getPropertyValuePath.ts index ab085c24512..1568f8af7cc 100644 --- a/src/utils/getPropertyValuePath.ts +++ b/src/utils/getPropertyValuePath.ts @@ -10,18 +10,18 @@ export default function getPropertyValuePath( path: NodePath, propertyName: string, ): NodePath | null { - path.assertObjectExpression(); + const property = path + .get('properties') + .find( + propertyPath => + !propertyPath.isSpreadElement() && + getPropertyName(propertyPath) === propertyName, + ); - return ( - path - .get('properties') - .filter(propertyPath => getPropertyName(propertyPath) === propertyName) - .map(propertyPath => - propertyPath.isObjectMethod() - ? propertyPath - : propertyPath.isObjectProperty() - ? (propertyPath.get('value') as NodePath) - : null, - )[0] || null - ); + if (property) { + return property.isObjectMethod() + ? property + : (property.get('value') as NodePath); + } + return null; } From 06c6acc75874d810304a323292c70e982458ae56 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 12:55:27 +0200 Subject: [PATCH 15/44] chore: Add test for printValue deindentation --- .../__tests__/__snapshots__/printValue-test.ts.snap | 7 +++++++ src/utils/__tests__/printValue-test.ts | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/utils/__tests__/__snapshots__/printValue-test.ts.snap diff --git a/src/utils/__tests__/__snapshots__/printValue-test.ts.snap b/src/utils/__tests__/__snapshots__/printValue-test.ts.snap new file mode 100644 index 00000000000..9434d2c38e5 --- /dev/null +++ b/src/utils/__tests__/__snapshots__/printValue-test.ts.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`printValue deindents code 1`] = ` +"function () { + return x; +}" +`; diff --git a/src/utils/__tests__/printValue-test.ts b/src/utils/__tests__/printValue-test.ts index 7767abd7707..826611ac14f 100644 --- a/src/utils/__tests__/printValue-test.ts +++ b/src/utils/__tests__/printValue-test.ts @@ -15,4 +15,14 @@ describe('printValue', () => { it('does not print trailing comments', () => { expect(printValue(pathFromSource('bar//foo'))).toEqual('bar'); }); + + it('deindents code', () => { + expect( + printValue( + pathFromSource(` ( function () { + return x; + })`), + ), + ).toMatchSnapshot(); + }); }); From 690674d34d2e3b524ec8ed1d41fa94c6499bacf4 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 12:55:39 +0200 Subject: [PATCH 16/44] chore: Clarify comments --- src/utils/getPropertyValuePath.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/getPropertyValuePath.ts b/src/utils/getPropertyValuePath.ts index 1568f8af7cc..b1ef18be29a 100644 --- a/src/utils/getPropertyValuePath.ts +++ b/src/utils/getPropertyValuePath.ts @@ -4,7 +4,8 @@ import getPropertyName from './getPropertyName'; /** * Given an ObjectExpression, this function returns the path of the value of - * the property with name `propertyName`. + * the property with name `propertyName`. if the property is an ObjectMethod we + * return the ObjectMethod itself. */ export default function getPropertyValuePath( path: NodePath, From f45a21d135bf5f29a34be9a50c1c4438910d5b45 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 13:05:13 +0200 Subject: [PATCH 17/44] chore: unify the ignore visitors --- .../findAllExportedComponentDefinitions.ts | 18 ++---------------- .../findExportedComponentDefinition.ts | 16 ++-------------- src/utils/traverse.ts | 3 ++- 3 files changed, 6 insertions(+), 31 deletions(-) diff --git a/src/resolver/findAllExportedComponentDefinitions.ts b/src/resolver/findAllExportedComponentDefinitions.ts index f561626c853..de77b323b15 100644 --- a/src/resolver/findAllExportedComponentDefinitions.ts +++ b/src/resolver/findAllExportedComponentDefinitions.ts @@ -8,7 +8,7 @@ import resolveExportDeclaration from '../utils/resolveExportDeclaration'; import resolveToValue from '../utils/resolveToValue'; import resolveHOC from '../utils/resolveHOC'; import type { NodePath } from '@babel/traverse'; -import { ignore } from '../utils/traverse'; +import { shallowIgnoreVisitors } from '../utils/traverse'; import type { ExportDefaultDeclaration, ExportNamedDeclaration, @@ -94,22 +94,8 @@ const findExportedComponentDefinitions: Resolver = function ( } file.traverse({ - FunctionDeclaration: ignore, - FunctionExpression: ignore, - ClassDeclaration: ignore, - ClassExpression: ignore, - IfStatement: ignore, - WithStatement: ignore, - SwitchStatement: ignore, - // @ts-ignore TODO TYPO test implications, write test and then fix - //CatchCause: ignore, - WhileStatement: ignore, - DoWhileStatement: ignore, - ForStatement: ignore, - ForInStatement: ignore, + ...shallowIgnoreVisitors, - // TODO Check if this was necessary - //ExportDeclaration: exportDeclaration, ExportNamedDeclaration: exportDeclaration, ExportDefaultDeclaration: exportDeclaration, diff --git a/src/resolver/findExportedComponentDefinition.ts b/src/resolver/findExportedComponentDefinition.ts index cc8ae8b73c2..60d48266b91 100644 --- a/src/resolver/findExportedComponentDefinition.ts +++ b/src/resolver/findExportedComponentDefinition.ts @@ -8,7 +8,7 @@ import resolveExportDeclaration from '../utils/resolveExportDeclaration'; import resolveToValue from '../utils/resolveToValue'; import resolveHOC from '../utils/resolveHOC'; import type { NodePath } from '@babel/traverse'; -import { ignore } from '../utils/traverse'; +import { shallowIgnoreVisitors } from '../utils/traverse'; import type { ExportDefaultDeclaration, ExportNamedDeclaration, @@ -101,19 +101,7 @@ const findExportedComponentDefinition: Resolver = function ( } file.traverse({ - FunctionDeclaration: ignore, - FunctionExpression: ignore, - ClassDeclaration: ignore, - ClassExpression: ignore, - IfStatement: ignore, - WithStatement: ignore, - SwitchStatement: ignore, - WhileStatement: ignore, - DoWhileStatement: ignore, - ForStatement: ignore, - ForInStatement: ignore, - ForOfStatement: ignore, - ImportDeclaration: ignore, + ...shallowIgnoreVisitors, ExportNamedDeclaration: exportDeclaration, ExportDefaultDeclaration: exportDeclaration, diff --git a/src/utils/traverse.ts b/src/utils/traverse.ts index 262461e287d..ea8555f9280 100644 --- a/src/utils/traverse.ts +++ b/src/utils/traverse.ts @@ -12,7 +12,7 @@ export function traverseShallow(path: NodePath, visitors: Visitor): void { path.traverse({ ...shallowIgnoreVisitors, ...visitors }); } -const shallowIgnoreVisitors = { +export const shallowIgnoreVisitors = { FunctionDeclaration: ignore, FunctionExpression: ignore, ClassDeclaration: ignore, @@ -20,6 +20,7 @@ const shallowIgnoreVisitors = { IfStatement: ignore, WithStatement: ignore, SwitchStatement: ignore, + CatchClause: ignore, WhileStatement: ignore, DoWhileStatement: ignore, ForStatement: ignore, From 19b560f7c7dfae2033bd76ebbd0d9e0b32abc4ae Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 13:22:51 +0200 Subject: [PATCH 18/44] fix: support qualified type names --- .../__snapshots__/getNameOrValue-test.ts.snap | 6 +++ src/utils/__tests__/getNameOrValue-test.ts | 37 ++++++++++++++++++- src/utils/__tests__/getPropertyName-test.ts | 10 +++++ src/utils/getNameOrValue.ts | 7 +++- src/utils/getPropertyName.ts | 1 - 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/getNameOrValue-test.ts.snap b/src/utils/__tests__/__snapshots__/getNameOrValue-test.ts.snap index 150e0ee7820..ba485873a51 100644 --- a/src/utils/__tests__/__snapshots__/getNameOrValue-test.ts.snap +++ b/src/utils/__tests__/__snapshots__/getNameOrValue-test.ts.snap @@ -1,7 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`getNameOrValue errors on invalid path 1`] = `"Argument must be Identifier, Literal, QualifiedTypeIdentifier or TSQualifiedName. Received 'FunctionDeclaration'"`; + exports[`getNameOrValue gets Identifier name 1`] = `"foo"`; +exports[`getNameOrValue gets QualifiedTypeIdentifier 1`] = `"x.h"`; + +exports[`getNameOrValue gets TSQualifiedName 1`] = `"x.h"`; + exports[`getNameOrValue gets boolean literal value 1`] = `true`; exports[`getNameOrValue gets null RegExp pattern 1`] = `"abc?"`; diff --git a/src/utils/__tests__/getNameOrValue-test.ts b/src/utils/__tests__/getNameOrValue-test.ts index 488b609e605..6ad2ea07b90 100644 --- a/src/utils/__tests__/getNameOrValue-test.ts +++ b/src/utils/__tests__/getNameOrValue-test.ts @@ -1,4 +1,11 @@ -import { parse } from '../../../tests/utils'; +import type { NodePath } from '@babel/traverse'; +import type { + QualifiedTypeIdentifier, + TSAsExpression, + TSQualifiedName, + TypeCastExpression, +} from '@babel/types'; +import { parse, parseTypescript } from '../../../tests/utils'; import getNameOrValue from '../getNameOrValue'; describe('getNameOrValue', () => { @@ -25,4 +32,32 @@ describe('getNameOrValue', () => { it('gets null literal value', () => { expect(getNameOrValue(parse.expression('null'))).toMatchSnapshot(); }); + + it('gets TSQualifiedName', () => { + expect( + getNameOrValue( + parseTypescript + .expression('path as x.h') + .get('typeAnnotation.typeName') as NodePath, + ), + ).toMatchSnapshot(); + }); + + it('gets QualifiedTypeIdentifier', () => { + expect( + getNameOrValue( + parse + .expression('path: x.h') + .get( + 'typeAnnotation.typeAnnotation.id', + ) as NodePath, + ), + ).toMatchSnapshot(); + }); + + it('errors on invalid path', () => { + expect(() => + getNameOrValue(parse.statement('function foo(){}')), + ).toThrowErrorMatchingSnapshot(); + }); }); diff --git a/src/utils/__tests__/getPropertyName-test.ts b/src/utils/__tests__/getPropertyName-test.ts index 839db0f3cd7..2e842c5abc3 100644 --- a/src/utils/__tests__/getPropertyName-test.ts +++ b/src/utils/__tests__/getPropertyName-test.ts @@ -32,6 +32,16 @@ describe('getPropertyName', () => { expect(getPropertyName(param)).toBe('foo'); }); + it('returns the qualified name of a object type spread property', () => { + const def = parse.expression('(a: { ...foo.bub })'); + const param = def + .get('typeAnnotation') + .get('typeAnnotation') + .get('properties')[0]; + + expect(getPropertyName(param)).toBe('foo.bub'); + }); + it('creates name for computed properties', () => { const def = parse.expression('{ [foo]: 21 }'); const param = def.get('properties')[0]; diff --git a/src/utils/getNameOrValue.ts b/src/utils/getNameOrValue.ts index 351360ee79f..0b8449047ec 100644 --- a/src/utils/getNameOrValue.ts +++ b/src/utils/getNameOrValue.ts @@ -1,4 +1,5 @@ import type { NodePath } from '@babel/traverse'; +import printValue from './printValue'; /** * If node is an Identifier, it returns its name. If it is a literal, it returns @@ -9,6 +10,8 @@ export default function getNameOrValue( ): boolean | number | string | null { if (path.isIdentifier()) { return path.node.name; + } else if (path.isQualifiedTypeIdentifier() || path.isTSQualifiedName()) { + return printValue(path); } else if ( path.isStringLiteral() || path.isNumericLiteral() || @@ -21,5 +24,7 @@ export default function getNameOrValue( return null; } - throw new TypeError('Argument must be an Identifier or a Literal'); + throw new TypeError( + `Argument must be Identifier, Literal, QualifiedTypeIdentifier or TSQualifiedName. Received '${path.node.type}'`, + ); } diff --git a/src/utils/getPropertyName.ts b/src/utils/getPropertyName.ts index ae00363ce2f..424bc535c57 100644 --- a/src/utils/getPropertyName.ts +++ b/src/utils/getPropertyName.ts @@ -37,7 +37,6 @@ export default function getPropertyName( if (propertyPath.isObjectTypeSpreadProperty()) { const argument = propertyPath.get('argument'); if (argument.isGenericTypeAnnotation()) { - // TODO test qualified type identifier return getNameOrValue(argument.get('id')) as string; } return null; From 28288f5677135302e8fe6ad80711ed801a126ef8 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 24 Jul 2022 15:23:58 +0200 Subject: [PATCH 19/44] fix: Support all literal types in typescript --- src/utils/__tests__/getTSType-test.ts | 14 ++++++++------ src/utils/getTSType.ts | 3 +-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/utils/__tests__/getTSType-test.ts b/src/utils/__tests__/getTSType-test.ts index 63e95d23b22..034a14739a3 100644 --- a/src/utils/__tests__/getTSType-test.ts +++ b/src/utils/__tests__/getTSType-test.ts @@ -112,14 +112,16 @@ describe('getTSType', () => { }); }); - it('detects literal types', () => { - const literalTypes = ['"foo"', 1234, true]; + describe('literal types', () => { + const literalTypes = ['"foo"', 1234, true, -1, '`foo`']; literalTypes.forEach(value => { - const typePath = typeAlias(`let x: ${value};`); - expect(getTSType(typePath)).toEqual({ - name: 'literal', - value: `${value}`, + it(`detects ${value}`, () => { + const typePath = typeAlias(`let x: ${value};`); + expect(getTSType(typePath)).toEqual({ + name: 'literal', + value: `${value}`, + }); }); }); }); diff --git a/src/utils/getTSType.ts b/src/utils/getTSType.ts index 0e0a131fc0b..49ac9664122 100644 --- a/src/utils/getTSType.ts +++ b/src/utils/getTSType.ts @@ -474,8 +474,7 @@ function getTSTypeWithResolvedTypes( const literal = path.get('literal'); type = { name: 'literal', - // @ts-ignore TODO create test for UnaryExpression (eg. -2 as literal) - value: (literal.node.extra?.raw as string) || `${literal.node.value}`, + value: printValue(literal), }; } else if (node.type in namedTypes) { type = namedTypes[node.type](path, typeParams); From a80f4e2c6c5d369448f6a62d4d171750d4add085 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Mon, 25 Jul 2022 23:20:59 +0200 Subject: [PATCH 20/44] chore: Remove invalid TODOs --- src/utils/getPropType.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/utils/getPropType.ts b/src/utils/getPropType.ts index 8fd4bec702b..11d9223b614 100644 --- a/src/utils/getPropType.ts +++ b/src/utils/getPropType.ts @@ -51,14 +51,12 @@ function getEnumValuesFromArrayExpression( return values; } -// TODO function getPropTypeOneOf(argumentPath: NodePath): PropTypeDescriptor { const type: PropTypeDescriptor = { name: 'enum' }; const value: NodePath = resolveToValue(argumentPath); if (!value.isArrayExpression()) { const objectValues = - resolveObjectKeysToArray(value) || //TODO return array of names and not ArrayExpression anymore - resolveObjectValuesToArray(value); + resolveObjectKeysToArray(value) || resolveObjectValuesToArray(value); if (objectValues) { type.value = objectValues.map(objectValue => ({ value: objectValue, From d31aa41531cd65ea38f0cce8857d97bced3d55cb Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Mon, 25 Jul 2022 23:21:50 +0200 Subject: [PATCH 21/44] chore: Share code between resolvers --- .../findAllExportedComponentDefinitions.ts | 5 +-- .../findExportedComponentDefinition.ts | 38 ++----------------- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/src/resolver/findAllExportedComponentDefinitions.ts b/src/resolver/findAllExportedComponentDefinitions.ts index de77b323b15..40994758db3 100644 --- a/src/resolver/findAllExportedComponentDefinitions.ts +++ b/src/resolver/findAllExportedComponentDefinitions.ts @@ -16,7 +16,7 @@ import type { import type FileState from '../FileState'; import type { Resolver } from '.'; -function isComponentDefinition(path: NodePath): boolean { +export function isComponentDefinition(path: NodePath): boolean { return ( isReactCreateClassCall(path) || isReactComponentClass(path) || @@ -25,8 +25,7 @@ function isComponentDefinition(path: NodePath): boolean { ); } -// TODO duplicate code -function resolveDefinition(definition: NodePath): NodePath | null { +export function resolveDefinition(definition: NodePath): NodePath | null { if (isReactCreateClassCall(definition)) { // return argument const resolvedPath = resolveToValue(definition.get('arguments')[0]); diff --git a/src/resolver/findExportedComponentDefinition.ts b/src/resolver/findExportedComponentDefinition.ts index 60d48266b91..19cb481439c 100644 --- a/src/resolver/findExportedComponentDefinition.ts +++ b/src/resolver/findExportedComponentDefinition.ts @@ -1,9 +1,4 @@ import isExportsOrModuleAssignment from '../utils/isExportsOrModuleAssignment'; -import isReactComponentClass from '../utils/isReactComponentClass'; -import isReactCreateClassCall from '../utils/isReactCreateClassCall'; -import isReactForwardRefCall from '../utils/isReactForwardRefCall'; -import isStatelessComponent from '../utils/isStatelessComponent'; -import normalizeClassDefinition from '../utils/normalizeClassDefinition'; import resolveExportDeclaration from '../utils/resolveExportDeclaration'; import resolveToValue from '../utils/resolveToValue'; import resolveHOC from '../utils/resolveHOC'; @@ -15,39 +10,14 @@ import type { } from '@babel/types'; import type { Resolver } from '.'; import type FileState from '../FileState'; +import { + isComponentDefinition, + resolveDefinition, +} from './findAllExportedComponentDefinitions'; const ERROR_MULTIPLE_DEFINITIONS = 'Multiple exported component definitions found.'; -function isComponentDefinition(path: NodePath): boolean { - return ( - isReactCreateClassCall(path) || - isReactComponentClass(path) || - isStatelessComponent(path) || - isReactForwardRefCall(path) - ); -} - -// TODO duplicate code -function resolveDefinition(definition: NodePath): NodePath | null { - if (isReactCreateClassCall(definition)) { - // return argument - const resolvedPath = resolveToValue(definition.get('arguments')[0]); - if (resolvedPath.isObjectExpression()) { - return resolvedPath; - } - } else if (isReactComponentClass(definition)) { - normalizeClassDefinition(definition); - return definition; - } else if ( - isStatelessComponent(definition) || - isReactForwardRefCall(definition) - ) { - return definition; - } - return null; -} - /** * Given an AST, this function tries to find the exported component definition. * From 19fe0f2e16354036601ef816621932e76b246530 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Tue, 26 Jul 2022 23:16:32 +0200 Subject: [PATCH 22/44] chore: cleanup code --- src/__tests__/parse-test.ts | 3 +- .../componentDocblockHandler-test.ts | 91 ++++--- .../componentMethodsJsDocHandler-test.ts | 10 +- .../__tests__/defaultPropsHandler-test.ts | 95 +++++-- .../__tests__/displayNameHandler-test.ts | 241 +++++++++++------- .../__tests__/flowTypeHandler-test.ts | 203 +++++++-------- .../__tests__/propDocblockHandler-test.ts | 27 +- .../propTypeCompositionHandler-test.ts | 31 ++- .../__tests__/propTypeHandler-test.ts | 45 +++- src/handlers/componentDocblockHandler.ts | 24 +- src/handlers/componentMethodsHandler.ts | 50 ++-- src/handlers/componentMethodsJsDocHandler.ts | 7 +- src/handlers/defaultPropsHandler.ts | 18 +- src/handlers/displayNameHandler.ts | 27 +- src/handlers/flowTypeHandler.ts | 12 +- src/handlers/index.ts | 6 +- src/handlers/propDocBlockHandler.ts | 12 +- src/handlers/propTypeCompositionHandler.ts | 12 +- src/handlers/propTypeHandler.ts | 13 +- src/parse.ts | 6 +- src/resolver/findAllComponentDefinitions.ts | 10 +- .../findAllExportedComponentDefinitions.ts | 63 ++--- .../findExportedComponentDefinition.ts | 19 +- src/resolver/index.ts | 26 +- .../__tests__/getMemberValuePath-test.ts | 25 +- .../__tests__/isStatelessComponent-test.ts | 6 +- src/utils/getMemberValuePath.ts | 67 +++-- src/utils/getTypeFromReactComponent.ts | 8 +- src/utils/isStatelessComponent.ts | 5 +- src/utils/resolveComponentDefinition.ts | 42 +++ 30 files changed, 714 insertions(+), 490 deletions(-) create mode 100644 src/utils/resolveComponentDefinition.ts diff --git a/src/__tests__/parse-test.ts b/src/__tests__/parse-test.ts index 6dcfbe9efd4..114c2699a88 100644 --- a/src/__tests__/parse-test.ts +++ b/src/__tests__/parse-test.ts @@ -1,3 +1,4 @@ +import type { ObjectExpression } from '@babel/types'; import fs from 'fs'; import { directory as tempDirectory } from 'tempy'; import { parse as testParse, noopImporter } from '../../tests/utils'; @@ -5,7 +6,7 @@ import parse, { ERROR_MISSING_DEFINITION } from '../parse'; describe('parse', () => { it('allows custom component definition resolvers', () => { - const path = testParse.expression('{foo: "bar"}'); + const path = testParse.expression('{foo: "bar"}'); const resolver = jest.fn(() => [path]); const handler = jest.fn(); parse('//empty', resolver, [handler], noopImporter); diff --git a/src/handlers/__tests__/componentDocblockHandler-test.ts b/src/handlers/__tests__/componentDocblockHandler-test.ts index e62f40218bb..ded44012c65 100644 --- a/src/handlers/__tests__/componentDocblockHandler-test.ts +++ b/src/handlers/__tests__/componentDocblockHandler-test.ts @@ -5,15 +5,16 @@ import type DocumentationMock from '../../__mocks__/Documentation'; import type { NodePath } from '@babel/traverse'; import type { ArrowFunctionExpression, + CallExpression, + ClassDeclaration, ClassExpression, ExportDefaultDeclaration, - ExportNamedDeclaration, - ExpressionStatement, + FunctionDeclaration, FunctionExpression, - Node, ObjectExpression, VariableDeclaration, } from '@babel/types'; +import type { ComponentNode } from '../../resolver'; jest.mock('../../Documentation'); @@ -26,7 +27,7 @@ describe('componentDocblockHandler', () => { function test( definitionSrc: string, - parseFunc: (src: string) => NodePath, + parseFunc: (src: string) => NodePath, ) { it('finds docblocks for component definitions', () => { const definition = parseFunc(` @@ -36,7 +37,7 @@ describe('componentDocblockHandler', () => { * Component description */ ${definitionSrc} - `) as NodePath; + `); componentDocblockHandler(documentation, definition); expect(documentation.description).toBe('Component description'); @@ -50,7 +51,7 @@ describe('componentDocblockHandler', () => { * This is not a docblock', */ ${definitionSrc} - `) as NodePath; + `); componentDocblockHandler(documentation, definition); expect(documentation.description).toBe(''); @@ -58,7 +59,7 @@ describe('componentDocblockHandler', () => { definition = parseFunc(` // Inline comment' ${definitionSrc} - `) as NodePath; + `); componentDocblockHandler(documentation, definition); expect(documentation.description).toBe(''); @@ -73,7 +74,7 @@ describe('componentDocblockHandler', () => { */ var something_else = "foo"; ${definitionSrc} - `) as NodePath; + `); componentDocblockHandler(documentation, definition); expect(documentation.description).toBe(''); @@ -86,7 +87,7 @@ describe('componentDocblockHandler', () => { */ function testDecorators( classSrc: string, - parseFunc: (src: string) => NodePath, + parseFunc: (src: string) => NodePath, exportSrc = '', ) { describe('decorators', () => { @@ -100,7 +101,7 @@ describe('componentDocblockHandler', () => { @Decorator1 @Decorator2 ${classSrc} - `) as NodePath; + `); componentDocblockHandler(documentation, definition); expect(documentation.description).toBe('Component description'); @@ -120,7 +121,7 @@ describe('componentDocblockHandler', () => { * Component description */ ${classSrc} - `) as NodePath; + `); componentDocblockHandler(documentation, definition); expect(documentation.description).toBe('Component description'); @@ -158,12 +159,12 @@ describe('componentDocblockHandler', () => { describe('imports', () => { it('can use a custom importer to resolve docblocks on imported components', () => { const program = parse - .statementLast( + .statementLast( `import ${importDef} from 'test1'; export default ${importName};`, mockImporter, ) - .get('declaration'); + .get('declaration') as NodePath; componentDocblockHandler(documentation, program); expect(documentation.description).toBe('Component description'); @@ -172,12 +173,12 @@ describe('componentDocblockHandler', () => { it('traverses multiple imports', () => { const program = parse - .statementLast( + .statementLast( `import ${importDef} from 'test2'; export default ${importName};`, mockImporter, ) - .get('declaration'); + .get('declaration') as NodePath; componentDocblockHandler(documentation, program); expect(documentation.description).toBe('Component description'); @@ -221,32 +222,40 @@ describe('componentDocblockHandler', () => { testImports('export var Component = () => {}', 'Component'); }); - describe('ES6 default exports', () => { + describe('ESM default export', () => { describe('Default React.createClass export', () => { test('export default React.createClass({});', src => parse - .statementLast(src) + .statementLast(src) .get('declaration.arguments.0') as NodePath); }); describe('Default class declaration export', () => { test('export default class Component {}', src => - parse.statementLast(src).get('declaration')); + parse + .statementLast(src) + .get('declaration') as NodePath); testDecorators( 'class Component {}', src => - parse.statementLast(src).get('declaration'), + parse + .statementLast(src) + .get('declaration') as NodePath, 'export default', ); }); describe('Default class expression export', () => { test('export default class {}', src => - parse.statementLast(src).get('declaration')); + parse + .statementLast(src) + .get('declaration') as NodePath); testDecorators( 'class {}', src => - parse.statementLast(src).get('declaration'), + parse + .statementLast(src) + .get('declaration') as NodePath, 'export default', ); }); @@ -255,31 +264,31 @@ describe('componentDocblockHandler', () => { describe('named function', () => { test('export default function Component() {}', src => parse - .statementLast(src) - .get('declaration')); + .statementLast(src) + .get('declaration') as NodePath); }); describe('anonymous function', () => { test('export default function() {}', src => parse - .statementLast(src) - .get('declaration')); + .statementLast(src) + .get('declaration') as NodePath); }); describe('arrow function', () => { test('export default () => {}', src => parse .statementLast(src) - .get('declaration')); + .get('declaration') as NodePath); }); }); }); - describe('ES6 named exports', () => { + describe('ESM named export', () => { describe('Named React.createClass export', () => { test('export var Component = React.createClass({});', src => parse - .statementLast(src) + .statementLast(src) .get( 'declaration.declarations.0.init.arguments.0', ) as NodePath); @@ -287,11 +296,15 @@ describe('componentDocblockHandler', () => { describe('Named class declaration export', () => { test('export class Component {}', src => - parse.statementLast(src).get('declaration')); + parse + .statementLast(src) + .get('declaration') as NodePath); testDecorators( 'class Component {}', src => - parse.statementLast(src).get('declaration'), + parse + .statementLast(src) + .get('declaration') as NodePath, 'export', ); }); @@ -299,17 +312,23 @@ describe('componentDocblockHandler', () => { describe('Named stateless function', () => { describe('named function', () => { test('export function Component() {}', src => - parse.statementLast(src).get('declaration')); + parse + .statementLast(src) + .get('declaration') as NodePath); }); describe('anonymous function', () => { test('export var Component = function() {}', src => - parse.statementLast(src).get('declaration')); + parse + .statementLast(src) + .get('declaration') as NodePath); }); describe('arrow function', () => { test('export var Component = () => {}', src => - parse.statementLast(src).get('declaration')); + parse + .statementLast(src) + .get('declaration') as NodePath); }); }); }); @@ -321,7 +340,7 @@ describe('componentDocblockHandler', () => { test(` React.forwardRef((props, ref) => {}); import React from "react";`, src => - parse.statement(src, -2).get('expression')); + parse.statement(src, -2).get('expression') as NodePath); testImports( `import React from 'react'; @@ -336,7 +355,7 @@ describe('componentDocblockHandler', () => { React.memo(React.forwardRef((props, ref) => {})); import React from "react"; `, src => - parse.statement(src, -2).get('expression')); + parse.statement(src, -2).get('expression') as NodePath); testImports( ` @@ -354,7 +373,7 @@ describe('componentDocblockHandler', () => { React.forwardRef(Component); import React from "react"; `, src => - parse.statement(src, -2).get('expression')); + parse.statement(src, -2).get('expression') as NodePath); testImports( ` diff --git a/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts b/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts index e16a3ac9e7c..de68b2ff01c 100644 --- a/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts +++ b/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts @@ -1,4 +1,6 @@ +import type { NodePath } from '@babel/traverse'; import Documentation from '../../Documentation'; +import type { ComponentNode } from '../../resolver'; import type DocumentationMock from '../../__mocks__/Documentation'; import componentMethodsJsDocHandler from '../componentMethodsJsDocHandler'; @@ -25,7 +27,7 @@ describe('componentMethodsJsDocHandler', () => { }, ]; documentation.set('methods', methods); - componentMethodsJsDocHandler(documentation); + componentMethodsJsDocHandler(documentation, {} as NodePath); expect(documentation.get('methods')).toEqual(methods); }); @@ -47,7 +49,7 @@ describe('componentMethodsJsDocHandler', () => { ], }, ]); - componentMethodsJsDocHandler(documentation); + componentMethodsJsDocHandler(documentation, {} as NodePath); expect(documentation.get('methods')).toMatchSnapshot(); }); @@ -71,7 +73,7 @@ describe('componentMethodsJsDocHandler', () => { ], }, ]); - componentMethodsJsDocHandler(documentation); + componentMethodsJsDocHandler(documentation, {} as NodePath); expect(documentation.get('methods')).toMatchSnapshot(); }); @@ -94,7 +96,7 @@ describe('componentMethodsJsDocHandler', () => { ], }, ]); - componentMethodsJsDocHandler(documentation); + componentMethodsJsDocHandler(documentation, {} as NodePath); expect(documentation.get('methods')).toMatchSnapshot(); }); }); diff --git a/src/handlers/__tests__/defaultPropsHandler-test.ts b/src/handlers/__tests__/defaultPropsHandler-test.ts index 42f4ff03cce..73b9779bbe4 100644 --- a/src/handlers/__tests__/defaultPropsHandler-test.ts +++ b/src/handlers/__tests__/defaultPropsHandler-test.ts @@ -1,5 +1,12 @@ import type { NodePath } from '@babel/traverse'; -import type { ObjectExpression } from '@babel/types'; +import type { + ArrowFunctionExpression, + CallExpression, + ClassDeclaration, + ClassExpression, + ObjectExpression, + VariableDeclaration, +} from '@babel/types'; import { parse, makeMockImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; import type DocumentationMock from '../../__mocks__/Documentation'; @@ -126,18 +133,18 @@ describe('defaultPropsHandler', () => { it('handles computed properties', () => { const src = ` - ({ + { getDefaultProps: function() { return { foo: "bar", [bar]: 42, }; } - }) + } `; defaultPropsHandler( documentation, - parse(src).get('body.0.expression') as NodePath, + parse.expression(src), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -244,7 +251,10 @@ describe('defaultPropsHandler', () => { }; } `; - defaultPropsHandler(documentation, parse(src).get('body')[0]); + defaultPropsHandler( + documentation, + parse.statement(src), + ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -258,7 +268,10 @@ describe('defaultPropsHandler', () => { } } `; - defaultPropsHandler(documentation, parse(src).get('body')[0]); + defaultPropsHandler( + documentation, + parse.statement(src), + ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -353,7 +366,9 @@ describe('defaultPropsHandler', () => { }`; defaultPropsHandler( documentation, - parse.statement(src).get('declarations.0.init') as NodePath, + parse + .statement(src) + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -369,7 +384,7 @@ describe('defaultPropsHandler', () => { documentation, parse .statementLast(src, mockImporter) - .get('declarations.0.init') as NodePath, + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -386,7 +401,7 @@ describe('defaultPropsHandler', () => { } } `; - const definition = parse.expression(src); + const definition = parse.expression(src); expect(() => defaultPropsHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -403,7 +418,10 @@ describe('defaultPropsHandler', () => { } }) `; - const definition = parse.expressionLast(src, mockImporter); + const definition = parse.expressionLast( + src, + mockImporter, + ); expect(() => defaultPropsHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -448,7 +466,9 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse.statement(src).get('declarations.0.init') as NodePath, + parse + .statement(src) + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -465,7 +485,7 @@ describe('defaultPropsHandler', () => { documentation, parse .statement(src, mockImporter, 1) - .get('declarations.0.init') as NodePath, + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -478,7 +498,9 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse.statement(src, 1).get('declarations.0.init') as NodePath, + parse + .statement(src, 1) + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -493,7 +515,7 @@ describe('defaultPropsHandler', () => { documentation, parse .statement(src, mockImporter, 1) - .get('declarations.0.init') as NodePath, + .get('declarations.0.init') as NodePath, ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -507,7 +529,10 @@ describe('defaultPropsHandler', () => { abc: defg = {xyz: abc.def, 123: 42} }) =>
`; - defaultPropsHandler(documentation, parse.expressionLast(src)); + defaultPropsHandler( + documentation, + parse.expressionLast(src), + ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -520,7 +545,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse.expressionLast(src, mockImporter), + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -533,14 +558,20 @@ describe('defaultPropsHandler', () => { foo = ImportedComponent, }) =>
`; - defaultPropsHandler(documentation, parse.expressionLast(src)); + defaultPropsHandler( + documentation, + parse.expressionLast(src), + ); expect(documentation.descriptors).toMatchSnapshot(); }); it('should work with no defaults', () => { const src = `({ foo }) =>
`; - defaultPropsHandler(documentation, parse.expressionLast(src)); + defaultPropsHandler( + documentation, + parse.expressionLast(src), + ); expect(documentation.descriptors).toMatchSnapshot(); }); }); @@ -551,7 +582,10 @@ describe('defaultPropsHandler', () => { import React from 'react'; React.forwardRef(({ foo = 'bar' }, ref) =>
{foo}
); `; - defaultPropsHandler(documentation, parse.expressionLast(src)); + defaultPropsHandler( + documentation, + parse.expressionLast(src), + ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -563,7 +597,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse.expressionLast(src, mockImporter), + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -574,7 +608,12 @@ describe('defaultPropsHandler', () => { const Component = React.forwardRef(({ foo }, ref) =>
{foo}
); Component.defaultProps = { foo: 'baz' }; `; - defaultPropsHandler(documentation, parse.statement(src, 1)); + defaultPropsHandler( + documentation, + parse + .statement(src, 1) + .get('declarations.0.init') as NodePath, + ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -585,7 +624,12 @@ describe('defaultPropsHandler', () => { const Component = React.forwardRef(({ bar }, ref) =>
{bar}
); Component.defaultProps = other; `; - defaultPropsHandler(documentation, parse.statement(src, mockImporter, 2)); + defaultPropsHandler( + documentation, + parse + .statement(src, mockImporter, 2) + .get('declarations.0.init') as NodePath, + ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -595,7 +639,10 @@ describe('defaultPropsHandler', () => { const ComponentImpl = ({ foo = 'bar' }, ref) =>
{foo}
; React.forwardRef(ComponentImpl); `; - defaultPropsHandler(documentation, parse.expressionLast(src)); + defaultPropsHandler( + documentation, + parse.expressionLast(src), + ); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -608,7 +655,7 @@ describe('defaultPropsHandler', () => { `; defaultPropsHandler( documentation, - parse.expressionLast(src, mockImporter), + parse.expressionLast(src, mockImporter), ); expect(documentation.descriptors).toMatchSnapshot(); }); diff --git a/src/handlers/__tests__/displayNameHandler-test.ts b/src/handlers/__tests__/displayNameHandler-test.ts index 79786e132d3..88c2bb3850a 100644 --- a/src/handlers/__tests__/displayNameHandler-test.ts +++ b/src/handlers/__tests__/displayNameHandler-test.ts @@ -4,10 +4,12 @@ import displayNameHandler from '../displayNameHandler'; import type DocumentationMock from '../../__mocks__/Documentation'; import type { ArrowFunctionExpression, + ClassDeclaration, ExportDefaultDeclaration, - ExpressionStatement, + FunctionDeclaration, FunctionExpression, ObjectExpression, + VariableDeclaration, } from '@babel/types'; import type { NodePath } from '@babel/traverse'; @@ -38,7 +40,9 @@ describe('defaultPropsHandler', () => { }); it('extracts the displayName', () => { - const definition: NodePath = parse.expression('{displayName: "FooBar"}'); + const definition = parse.expression( + '{displayName: "FooBar"}', + ); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBar'); }); @@ -54,50 +58,46 @@ describe('defaultPropsHandler', () => { }); it('resolves identifiers', () => { - const definition = parse - .statement( - ` - ({displayName: name}) - var name = 'abc'; - `, - ) - .get('expression'); + const definition = parse.expressionLast( + `var name = 'abc'; + ({displayName: name})`, + ); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('abc'); }); it('resolves imported identifiers', () => { - const definition = parse - .statement( - ` - ({displayName: name}) - import foobarbaz from 'foobarbaz'; - var name = foobarbaz; - `, - mockImporter, - ) - .get('expression'); + const definition = parse.expressionLast( + `import foobarbaz from 'foobarbaz'; + var name = foobarbaz; + ({displayName: name})`, + mockImporter, + ); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); it('can resolve non-literal names with appropriate importer', () => { - const definition = parse - .statement( - ` - ({displayName: foo.bar}); - import foo from 'foo'; - `, - mockImporter, - ) - .get('expression'); + const definition = parse.expressionLast( + `import foo from 'foo'; + ({displayName: foo.bar});`, + mockImporter, + ); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); + it('ignores non-literal names', () => { + const definition = parse.expression( + '{displayName: foo.bar}', + ); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); + expect(documentation.displayName).not.toBeDefined(); + }); + describe('ClassDeclaration', () => { it('considers the class name', () => { - const definition = parse.statement(`class Foo {}`); + const definition = parse.statement(`class Foo {}`); expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -105,13 +105,13 @@ describe('defaultPropsHandler', () => { it('does not crash if no name', () => { const definition = parse .statement(`export default class {}`) - .get('declaration'); + .get('declaration') as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBeUndefined(); }); it('resolves identifiers', () => { - const definition = parse.statement(` + const definition = parse.statement(` class Foo { static displayName = name; } @@ -122,7 +122,7 @@ describe('defaultPropsHandler', () => { }); it('resolves imported identifiers', () => { - const definition = parse.statement( + const definition = parse.statement( ` class Foo { static displayName = name; @@ -137,7 +137,7 @@ describe('defaultPropsHandler', () => { }); it('resolves imported displayName', () => { - const definition = parse.statement( + const definition = parse.statement( ` class Foo { static displayName = foobarbaz; @@ -151,11 +151,7 @@ describe('defaultPropsHandler', () => { }); it('ignores non-literal names', () => { - let definition = parse.expression('{displayName: foo.bar}'); - expect(() => displayNameHandler(documentation, definition)).not.toThrow(); - expect(documentation.displayName).not.toBeDefined(); - - definition = parse.statement(` + const definition = parse.statement(` class Foo { static displayName = foo.bar; } @@ -165,7 +161,7 @@ describe('defaultPropsHandler', () => { }); it('can resolve non-literal names with appropriate importer', () => { - const definition = parse.statement( + const definition = parse.statement( ` class Foo { static displayName = bar.baz; @@ -179,7 +175,7 @@ describe('defaultPropsHandler', () => { }); it('considers a static displayName class property', () => { - const definition = parse.statement(` + const definition = parse.statement(` class Foo { static displayName = 'foo'; } @@ -189,7 +185,7 @@ describe('defaultPropsHandler', () => { }); it('considers static displayName getter', () => { - const definition = parse.statement(` + const definition = parse.statement(` class Foo { static get displayName() { return 'foo'; @@ -201,7 +197,7 @@ describe('defaultPropsHandler', () => { }); it('considers static displayName property with function expression', () => { - const definition = parse.statement(` + const definition = parse.statement(` class Foo { static displayName = function() { return 'foo'; @@ -213,7 +209,7 @@ describe('defaultPropsHandler', () => { }); it('considers static displayName property with function declaration', () => { - const definition = parse.statement(` + const definition = parse.statement(` class Foo { static displayName = displayName; } @@ -226,7 +222,7 @@ describe('defaultPropsHandler', () => { }); it('resolves variables in displayName getter', () => { - const definition = parse.statement(` + const definition = parse.statement(` class Foo { static get displayName() { return abc; @@ -238,8 +234,8 @@ describe('defaultPropsHandler', () => { expect(documentation.displayName).toBe('bar'); }); - it('resolves imported variables in displayName getter', () => { - let definition = parse.statement( + it('resolves imported Identifier in displayName getter', () => { + const definition = parse.statement( ` class Foo { static get displayName() { @@ -252,8 +248,10 @@ describe('defaultPropsHandler', () => { ); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); + }); - definition = parse.statement( + it('resolves imported MemberExpression in displayName getter', () => { + const definition = parse.statement( ` class Foo { static get displayName() { @@ -271,7 +269,8 @@ describe('defaultPropsHandler', () => { describe('FunctionDeclaration', () => { it('considers the function name', () => { - const definition = parse.statement('function Foo () {}'); + const definition = + parse.statement('function Foo () {}'); expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -279,13 +278,13 @@ describe('defaultPropsHandler', () => { it('does not crash if no name', () => { const definition = parse .statement(`export default function () {}`) - .get('declaration'); + .get('declaration') as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBeUndefined(); }); it('considers a static displayName object property', () => { - const definition = parse.statement(` + const definition = parse.statement(` function Foo () {} Foo.displayName = 'Bar'; `); @@ -294,7 +293,7 @@ describe('defaultPropsHandler', () => { }); it('resolves variable assigned to displayName object property', () => { - const definition = parse.statement(` + const definition = parse.statement(` function Foo () {} Foo.displayName = bar; var bar = 'Bar'; @@ -303,8 +302,8 @@ describe('defaultPropsHandler', () => { expect(documentation.displayName).toBe('Bar'); }); - it('resolves imported variable assigned to displayName object property', () => { - let definition = parse.statement( + it('resolves imported Identifier assigned to displayName object property', () => { + const definition = parse.statement( ` function Foo () {} import foobarbaz from 'foobarbaz'; @@ -314,8 +313,10 @@ describe('defaultPropsHandler', () => { ); displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); + }); - definition = parse.statement( + it('resolves imported MemberExpression assigned to displayName object property', () => { + const definition = parse.statement( ` function Foo () {} import foo from 'foo'; @@ -330,7 +331,7 @@ describe('defaultPropsHandler', () => { describe('FunctionExpression', () => { it('considers the variable name', () => { - const definition: NodePath = parse + const definition = parse .statement('var Foo = function () {};') .get('declarations.0.init') as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); @@ -346,44 +347,58 @@ describe('defaultPropsHandler', () => { }); it('considers a static displayName object property over variable name', () => { - const definition = parse.statement(` + const definition = parse + .statement( + ` var Foo = function () {}; Foo.displayName = 'Bar'; - `); + `, + ) + .get('declarations.0.init') as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves variable assigned to displayName object property over variable name', () => { - const definition = parse.statement(` + const definition = parse + .statement( + ` var Foo = function () {}; Foo.displayName = bar; var bar = 'Bar'; - `); + `, + ) + .get('declarations.0.init') as NodePath; displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('Bar'); }); - it('resolves imported variable assigned to displayName object property over variable name', () => { - let definition = parse.statement( - ` + it('resolves imported Identifier assigned to displayName object property over variable name', () => { + const definition = parse + .statement( + ` var Foo = function () {}; import foobarbaz from 'foobarbaz'; Foo.displayName = foobarbaz; `, - mockImporter, - ); + mockImporter, + ) + .get('declarations.0.init') as NodePath; displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); + }); - definition = parse.statement( - ` + it('resolves imported MemberExpression assigned to displayName object property over variable name', () => { + const definition = parse + .statement( + ` var Foo = function () {}; import foo from 'foo'; Foo.displayName = foo.bar; `, - mockImporter, - ); + mockImporter, + ) + .get('declarations.0.init') as NodePath; displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); @@ -453,87 +468,123 @@ describe('defaultPropsHandler', () => { }); it('considers a static displayName object property over variable name', () => { - const definition = parse.statement(` + const definition = parse + .statement( + ` var Foo = () => {}; Foo.displayName = 'Bar'; - `); + `, + ) + .get('declarations.0.init') as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves a variable assigned to displayName object property over variable name', () => { - const definition = parse.statement(` + const definition = parse + .statement( + ` var Foo = () => {}; Foo.displayName = bar; var bar = 'Bar'; - `); + `, + ) + .get('declarations.0.init') as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); - it('resolves imported variable assigned to displayName object property over variable name', () => { - let definition = parse.statement( - ` + it('resolves imported Identifier assigned to displayName object property over variable name', () => { + const definition = parse + .statement( + ` var Foo = () => {}; import foobarbaz from 'foobarbaz'; Foo.displayName = foobarbaz; `, - mockImporter, - ); + mockImporter, + ) + .get('declarations.0.init') as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('FooBarBaz'); + }); - definition = parse.statement( - ` + it('resolves imported MemberExpression assigned to displayName object property over variable name', () => { + const definition = parse + .statement( + ` var Foo = () => {}; import foo from 'foo'; Foo.displayName = foo.bar; `, - mockImporter, - ); + mockImporter, + ) + .get('declarations.0.init') as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('baz'); }); it('considers a static displayName object property over variable name even if wrapped', () => { - const definition = parse.statement(` + const definition = parse + .statement( + ` var Foo = React.forwardRef(() => {}); Foo.displayName = 'Bar'; - `); + `, + ) + .get( + 'declarations.0.init.arguments.0', + ) as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); it('resolves a variable assigned to displayName object property over variable name even if wrapped', () => { - const definition = parse.statement(` + const definition = parse + .statement( + ` var Foo = React.forwardRef(() => {}); Foo.displayName = bar; var bar = 'Bar'; - `); + `, + ) + .get( + 'declarations.0.init.arguments.0', + ) as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); - it('resolves imported variable assigned to displayName object property over variable name even if wrapped', () => { - let definition = parse.statement( - ` + it('resolves imported Identifier assigned to displayName object property over variable name even if wrapped', () => { + const definition = parse + .statement( + ` var Foo = React.forwardRef(() => {}); import foobarbaz from 'foobarbaz'; Foo.displayName = foobarbaz; `, - mockImporter, - ); + mockImporter, + ) + .get( + 'declarations.0.init.arguments.0', + ) as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('FooBarBaz'); + }); - definition = parse.statement( - ` + it('resolves imported MemberExpression assigned to displayName object property over variable name even if wrapped', () => { + const definition = parse + .statement( + ` var Foo = React.forwardRef(() => {}); import foo from 'foo'; Foo.displayName = foo.bar; `, - mockImporter, - ); + mockImporter, + ) + .get( + 'declarations.0.init.arguments.0', + ) as NodePath; expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('baz'); }); diff --git a/src/handlers/__tests__/flowTypeHandler-test.ts b/src/handlers/__tests__/flowTypeHandler-test.ts index f4c471eef6a..334c19e4c13 100644 --- a/src/handlers/__tests__/flowTypeHandler-test.ts +++ b/src/handlers/__tests__/flowTypeHandler-test.ts @@ -2,8 +2,15 @@ import { parse, makeMockImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; import flowTypeHandler from '../flowTypeHandler'; import type DocumentationMock from '../../__mocks__/Documentation'; -import type { ExportNamedDeclaration, ExpressionStatement } from '@babel/types'; +import type { + ArrowFunctionExpression, + CallExpression, + ClassDeclaration, + ExportNamedDeclaration, + ObjectExpression, +} from '@babel/types'; import type { NodePath } from '@babel/traverse'; +import type { ComponentNode } from '../../resolver'; jest.mock('../../Documentation'); jest.mock('../../utils/getFlowType', () => ({ @@ -43,7 +50,7 @@ describe('flowTypeHandler', () => { `; } - function test(getSrc: (src: string) => NodePath) { + function test(getSrc: (src: string) => NodePath) { it('detects types correctly', () => { const flowTypesSrc = ` { @@ -226,40 +233,47 @@ describe('flowTypeHandler', () => { }); describe('stateless component', () => { - test(propTypesSrc => - parse - .statement( - template('(props: Props) =>
;', propTypesSrc), - ) - .get('expression'), + test( + propTypesSrc => + parse + .statement(template('(props: Props) =>
;', propTypesSrc)) + .get('expression') as NodePath, ); }); }); - it('does not error if flowTypes cannot be found', () => { - let definition = parse.expression('{fooBar: 42}'); - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + describe('does not error if flowTypes cannot be found', () => { + it('ObjectExpression', () => { + const definition = parse.expression('{fooBar: 42}'); - definition = parse.statement('class Foo extends Component {}'); - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + }); - definition = parse.statement('() =>
'); - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + it('ClassDeclaration', () => { + const definition = parse.statement( + 'class Foo extends Component {}', + ); + + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + }); + + it('ArrowFunctionExpression', () => { + const definition = + parse.statement('() =>
'); + + expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + }); }); it('supports intersection proptypes', () => { const definition = parse - .statement( - ` - (props: Props) =>
; - - var React = require('React'); - import type Imported from 'something'; - - type Props = Imported & { foo: 'bar' }; - `, + .statement( + `(props: Props) =>
; + var React = require('React'); + import type Imported from 'something'; + type Props = Imported & { foo: 'bar' };`, ) - .get('expression'); + .get('expression') as NodePath; flowTypeHandler(documentation, definition); @@ -274,59 +288,43 @@ describe('flowTypeHandler', () => { it('does support utility types inline', () => { const definition = parse - .statement( - ` - (props: $ReadOnly) =>
; - - var React = require('React'); - - type Props = { foo: 'fooValue' }; - `, + .statement( + `(props: $ReadOnly) =>
; + var React = require('React'); + type Props = { foo: 'fooValue' };`, ) - .get('expression'); + .get('expression') as NodePath; expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); - expect(documentation.descriptors).toMatchSnapshot(); }); it('does not support union proptypes', () => { const definition = parse - .statement( - ` - (props: Props) =>
; - - var React = require('React'); - import type Imported from 'something'; - - type Other = { bar: 'barValue' }; - type Props = Imported | Other | { foo: 'fooValue' }; - `, + .statement( + `(props: Props) =>
; + var React = require('React'); + import type Imported from 'something'; + type Other = { bar: 'barValue' }; + type Props = Imported | Other | { foo: 'fooValue' };`, ) - .get('expression'); + .get('expression') as NodePath; expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); - expect(documentation.descriptors).toEqual({}); }); describe('imported prop types', () => { it('does not resolve type included by require', () => { const definition = parse - .statement( - ` - (props: Props) =>
; - var React = require('React'); - var Component = React.Component; - - var Props = require('something'); - `, + .statement( + `(props: Props) =>
; + var React = require('React'); + var Component = React.Component; + var Props = require('something');`, mockImporter, ) - .get('expression'); - - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); - expect(documentation.descriptors).toEqual({}); + .get('expression') as NodePath; expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); @@ -334,17 +332,14 @@ describe('flowTypeHandler', () => { it('imported', () => { const definition = parse - .statement( - ` - (props: Props) =>
; - var React = require('React'); - var Component = React.Component; - - import { Props } from 'something'; - `, + .statement( + `(props: Props) =>
; + var React = require('React'); + var Component = React.Component; + import { Props } from 'something';`, mockImporter, ) - .get('expression'); + .get('expression') as NodePath; expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); @@ -352,16 +347,13 @@ describe('flowTypeHandler', () => { it('type not imported', () => { const definition = parse - .statement( - ` - (props: Props) =>
; - var React = require('React'); - var Component = React.Component; - - import type { Props } from 'something'; - `, + .statement( + `(props: Props) =>
; + var React = require('React'); + var Component = React.Component; + import type { Props } from 'something';`, ) - .get('expression'); + .get('expression') as NodePath; expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); @@ -369,17 +361,14 @@ describe('flowTypeHandler', () => { it('type imported', () => { const definition = parse - .statement( - ` - (props: Props) =>
; - var React = require('React'); - var Component = React.Component; - - import type { Props } from 'something'; - `, + .statement( + `(props: Props) =>
; + var React = require('React'); + var Component = React.Component; + import type { Props } from 'something';`, mockImporter, ) - .get('expression'); + .get('expression') as NodePath; expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); @@ -387,18 +376,13 @@ describe('flowTypeHandler', () => { it('does not resolve types not in scope', () => { const definition = parse - .statement( - ` - (props: Props) =>
; - var React = require('React'); - var Component = React.Component; - `, + .statement( + `(props: Props) =>
; + var React = require('React'); + var Component = React.Component;`, mockImporter, ) - .get('expression'); - - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); - expect(documentation.descriptors).toEqual({}); + .get('expression') as NodePath; expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); @@ -406,18 +390,13 @@ describe('flowTypeHandler', () => { it('does not resolve types not in scope', () => { const definition = parse - .statement( - ` - (props: Props) =>
; - var React = require('React'); - var Component = React.Component; - `, + .statement( + `(props: Props) =>
; + var React = require('React'); + var Component = React.Component;`, mockImporter, ) - .get('expression'); - - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); - expect(documentation.descriptors).toEqual({}); + .get('expression') as NodePath; expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); @@ -431,10 +410,7 @@ describe('flowTypeHandler', () => { type Props = { foo: string }; React.forwardRef((props: Props, ref) =>
{props.foo}
); `; - flowTypeHandler( - documentation, - parse(src).get('body.2.expression') as NodePath, - ); + flowTypeHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toEqual({ foo: { flowType: {}, @@ -451,10 +427,7 @@ describe('flowTypeHandler', () => { const ComponentImpl = (props: Props, ref) =>
{props.foo}
; React.forwardRef(ComponentImpl); `; - flowTypeHandler( - documentation, - parse(src).get('body.3.expression') as NodePath, - ); + flowTypeHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toEqual({ foo: { flowType: {}, @@ -473,7 +446,7 @@ describe('flowTypeHandler', () => { `; flowTypeHandler( documentation, - parse(src).get('body.3.expression.right') as NodePath, + parse.expressionLast(src).get('right') as NodePath, ); expect(documentation.descriptors).toEqual({ foo: { diff --git a/src/handlers/__tests__/propDocblockHandler-test.ts b/src/handlers/__tests__/propDocblockHandler-test.ts index a06c7aad0d8..3449d1b0f4a 100644 --- a/src/handlers/__tests__/propDocblockHandler-test.ts +++ b/src/handlers/__tests__/propDocblockHandler-test.ts @@ -1,8 +1,9 @@ import type { NodePath } from '@babel/traverse'; -import type { ExpressionStatement } from '@babel/types'; +import type { ClassDeclaration, ObjectExpression } from '@babel/types'; import { parse, makeMockImporter, noopImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; import type { Importer } from '../../importer'; +import type { ComponentNode } from '../../resolver'; import type DocumentationMock from '../../__mocks__/Documentation'; import propDocBlockHandler from '../propDocBlockHandler'; @@ -29,7 +30,7 @@ describe('propDocBlockHandler', () => { function test( getSrc: (src: string) => string, - parseSrc: (src: string, importer?: Importer) => NodePath, + parseSrc: (src: string, importer?: Importer) => NodePath, ) { it('finds docblocks for prop types', () => { const definition = parseSrc( @@ -224,7 +225,9 @@ describe('propDocBlockHandler', () => { test( propTypesSrc => `({propTypes: ${propTypesSrc}})`, (src, importer = noopImporter) => - parse.statement(src, importer).get('expression'), + parse + .statement(src, importer) + .get('expression') as NodePath, ); }); @@ -254,11 +257,19 @@ describe('propDocBlockHandler', () => { }); }); - it('does not error if propTypes cannot be found', () => { - let definition = parse.expression('{fooBar: 42}'); - expect(() => propDocBlockHandler(documentation, definition)).not.toThrow(); + describe('does not error if propTypes cannot be found', () => { + it('ObjectExpression', () => { + const definition = parse.expression('{fooBar: 42}'); + expect(() => + propDocBlockHandler(documentation, definition), + ).not.toThrow(); + }); - definition = parse.statement('class Foo {}'); - expect(() => propDocBlockHandler(documentation, definition)).not.toThrow(); + it('ClassDeclaration', () => { + const definition = parse.statement('class Foo {}'); + expect(() => + propDocBlockHandler(documentation, definition), + ).not.toThrow(); + }); }); }); diff --git a/src/handlers/__tests__/propTypeCompositionHandler-test.ts b/src/handlers/__tests__/propTypeCompositionHandler-test.ts index e08a9d487a2..5b5c5202ef3 100644 --- a/src/handlers/__tests__/propTypeCompositionHandler-test.ts +++ b/src/handlers/__tests__/propTypeCompositionHandler-test.ts @@ -4,7 +4,8 @@ import Documentation from '../../Documentation'; import type DocumentationMock from '../../__mocks__/Documentation'; import type { NodePath } from '@babel/traverse'; import type { Importer } from '../../importer'; -import type { ExpressionStatement } from '@babel/types'; +import type { ClassDeclaration, ObjectExpression } from '@babel/types'; +import type { ComponentNode } from '../../resolver'; jest.mock('../../Documentation'); jest.mock('../../utils/getPropType', () => () => ({})); @@ -36,7 +37,7 @@ describe('propTypeCompositionHandler', () => { function test( getSrc: (src: string) => string, - parseSrc: (src: string, importer?: Importer) => NodePath, + parseSrc: (src: string, importer?: Importer) => NodePath, ) { it('understands assignment from module', () => { let definition = parseSrc(` @@ -119,7 +120,9 @@ describe('propTypeCompositionHandler', () => { test( propTypesSrc => `({propTypes: ${propTypesSrc}})`, (src, importer = noopImporter) => - parse.statement(src, importer).get('expression'), + parse + .statement(src, importer) + .get('expression') as NodePath, ); }); @@ -149,15 +152,19 @@ describe('propTypeCompositionHandler', () => { }); }); - it('does not error if propTypes cannot be found', () => { - let definition = parse.expression('{fooBar: 42}'); - expect(() => - propTypeCompositionHandler(documentation, definition), - ).not.toThrow(); + describe('does not error if propTypes cannot be found', () => { + it('ObjectExpression', () => { + const definition = parse.expression('{fooBar: 42}'); + expect(() => + propTypeCompositionHandler(documentation, definition), + ).not.toThrow(); + }); - definition = parse.statement('class Foo {}'); - expect(() => - propTypeCompositionHandler(documentation, definition), - ).not.toThrow(); + it('ClassDeclaration', () => { + const definition = parse.statement('class Foo {}'); + expect(() => + propTypeCompositionHandler(documentation, definition), + ).not.toThrow(); + }); }); }); diff --git a/src/handlers/__tests__/propTypeHandler-test.ts b/src/handlers/__tests__/propTypeHandler-test.ts index 7c86591a622..e568758b6d9 100644 --- a/src/handlers/__tests__/propTypeHandler-test.ts +++ b/src/handlers/__tests__/propTypeHandler-test.ts @@ -5,7 +5,13 @@ import { propTypeHandler } from '../propTypeHandler'; import getPropType from '../../utils/getPropType'; import type { NodePath } from '@babel/traverse'; import type { Importer } from '../../importer'; -import type { ExpressionStatement } from '@babel/types'; +import type { + ArrowFunctionExpression, + ClassDeclaration, + FunctionDeclaration, + ObjectExpression, +} from '@babel/types'; +import type { ComponentNode } from '../../resolver'; const getPropTypeMock = getPropType as jest.Mock; @@ -69,7 +75,7 @@ describe('propTypeHandler', () => { function test( getSrc: (src: string) => string, - parseSrc: (src: string, importer?: Importer) => NodePath, + parseSrc: (src: string, importer?: Importer) => NodePath, ) { it('passes the correct argument to getPropType', () => { const propTypesSrc = `{ @@ -278,7 +284,9 @@ describe('propTypeHandler', () => { test( propTypesSrc => template(`({propTypes: ${propTypesSrc}})`), (src, importer = noopImporter) => - parse.statement(src, importer).get('expression'), + parse + .statement(src, importer) + .get('expression') as NodePath, ); }); @@ -321,23 +329,34 @@ describe('propTypeHandler', () => { ); }); - it('does not error if propTypes cannot be found', () => { - let definition = parse.expression('{fooBar: 42}'); - expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + describe('does not error if propTypes cannot be found', () => { + it('ObjectExpression', () => { + const definition = parse.expression('{fooBar: 42}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + }); - definition = parse.statement('class Foo {}'); - expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + it('ClassDeclaration', () => { + const definition = parse.statement('class Foo {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + }); - definition = parse.statement('function Foo() {}'); - expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + it('FunctionDeclaration', () => { + const definition = + parse.statement('function Foo() {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + }); - definition = parse.expression('() => {}'); - expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + it('ArrowFunctionExpression', () => { + const definition = parse.expression('() => {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); + }); }); // This case is handled by propTypeCompositionHandler it('does not error if propTypes is a member expression', () => { - const definition = parse.expression('{propTypes: Foo.propTypes}'); + const definition = parse.expression( + '{propTypes: Foo.propTypes}', + ); expect(() => propTypeHandler(documentation, definition)).not.toThrow(); }); }); diff --git a/src/handlers/componentDocblockHandler.ts b/src/handlers/componentDocblockHandler.ts index 6be89acd77e..c3086e46519 100644 --- a/src/handlers/componentDocblockHandler.ts +++ b/src/handlers/componentDocblockHandler.ts @@ -3,18 +3,13 @@ import { getDocblock } from '../utils/docblock'; import isReactForwardRefCall from '../utils/isReactForwardRefCall'; import resolveToValue from '../utils/resolveToValue'; import type { NodePath, Node } from '@babel/traverse'; -import type { ClassDeclaration, ClassExpression } from '@babel/types'; - -function isClassDefinition( - path: NodePath, -): path is NodePath { - return path.isClassDeclaration() || path.isClassExpression(); -} +import type { ComponentNode } from '../resolver'; +import type { Handler } from '.'; function getDocblockFromComponent(path: NodePath): string | null { let description: string | null = null; - if (isClassDefinition(path)) { + if (path.isClassDeclaration() || path.isClassExpression()) { // If we have a class declaration or expression, then the comment might be // attached to the last decorator instead as trailing comment. if (path.node.decorators && path.node.decorators.length > 0) { @@ -56,9 +51,14 @@ function getDocblockFromComponent(path: NodePath): string | null { /** * Finds the nearest block comment before the component definition. */ -export default function componentDocblockHandler( +const componentDocblockHandler: Handler = function ( documentation: Documentation, - path: NodePath, + componentDefinition: NodePath, ): void { - documentation.set('description', getDocblockFromComponent(path) || ''); -} + documentation.set( + 'description', + getDocblockFromComponent(componentDefinition) || '', + ); +}; + +export default componentDocblockHandler; diff --git a/src/handlers/componentMethodsHandler.ts b/src/handlers/componentMethodsHandler.ts index af0ae81a419..3ec48d8e447 100644 --- a/src/handlers/componentMethodsHandler.ts +++ b/src/handlers/componentMethodsHandler.ts @@ -9,6 +9,8 @@ import { traverseShallow } from '../utils/traverse'; import resolveToValue from '../utils/resolveToValue'; import type { NodePath } from '@babel/traverse'; import type { AssignmentExpression, Identifier } from '@babel/types'; +import type { ComponentNode } from '../resolver'; +import type { Handler } from '.'; /** * The following values/constructs are considered methods: @@ -71,28 +73,28 @@ function findAssignedMethods( * Extract all flow types for the methods of a react component. Doesn't * return any react specific lifecycle methods. */ -export default function componentMethodsHandler( +const componentMethodsHandler: Handler = function ( documentation: Documentation, - path: NodePath, + componentDefinition: NodePath, ): void { // Extract all methods from the class or object. let methodPaths: Array<{ path: MethodNodePath; isStatic?: boolean }> = []; - if (isReactComponentClass(path)) { + if (isReactComponentClass(componentDefinition)) { methodPaths = ( - path + componentDefinition .get('body') .get('body') .filter(body => isMethod(body)) as MethodNodePath[] ).map(p => ({ path: p })); - } else if (path.isObjectExpression()) { + } else if (componentDefinition.isObjectExpression()) { methodPaths = ( - path + componentDefinition .get('properties') .filter(props => isMethod(props)) as MethodNodePath[] ).map(p => ({ path: p })); // Add the statics object properties. - const statics = getMemberValuePath(path, 'statics'); + const statics = getMemberValuePath(componentDefinition, 'statics'); if (statics && statics.isObjectExpression()) { statics.get('properties').forEach(property => { if (isMethod(property)) { @@ -104,29 +106,29 @@ export default function componentMethodsHandler( }); } } else if ( - path.parentPath && - path.parentPath.isVariableDeclarator() && - path.parentPath.node.init === path.node && - path.parentPath.get('id').isIdentifier() + componentDefinition.parentPath && + componentDefinition.parentPath.isVariableDeclarator() && + componentDefinition.parentPath.node.init === componentDefinition.node && + componentDefinition.parentPath.get('id').isIdentifier() ) { methodPaths = findAssignedMethods( - path.parentPath.scope.path, - path.parentPath.get('id') as NodePath, + componentDefinition.parentPath.scope.path, + componentDefinition.parentPath.get('id') as NodePath, ).map(p => ({ path: p })); } else if ( - path.parentPath && - path.parentPath.isAssignmentExpression() && - path.parentPath.node.right === path.node && - path.parentPath.get('left').isIdentifier() + componentDefinition.parentPath && + componentDefinition.parentPath.isAssignmentExpression() && + componentDefinition.parentPath.node.right === componentDefinition.node && + componentDefinition.parentPath.get('left').isIdentifier() ) { methodPaths = findAssignedMethods( - path.parentPath.scope.path, - path.parentPath.get('left') as NodePath, + componentDefinition.parentPath.scope.path, + componentDefinition.parentPath.get('left') as NodePath, ).map(p => ({ path: p })); - } else if (path.isFunctionDeclaration()) { + } else if (componentDefinition.isFunctionDeclaration()) { methodPaths = findAssignedMethods( - path.parentPath.scope.path, - path.get('id'), + componentDefinition.parentPath.scope.path, + componentDefinition.get('id'), ).map(p => ({ path: p })); } @@ -136,4 +138,6 @@ export default function componentMethodsHandler( .map(({ path: p, isStatic }) => getMethodDocumentation(p, { isStatic })) .filter(Boolean), ); -} +}; + +export default componentMethodsHandler; diff --git a/src/handlers/componentMethodsJsDocHandler.ts b/src/handlers/componentMethodsJsDocHandler.ts index 16dfc46010d..bf556ba17bc 100644 --- a/src/handlers/componentMethodsJsDocHandler.ts +++ b/src/handlers/componentMethodsJsDocHandler.ts @@ -3,6 +3,7 @@ import type { default as Documentation, MethodDescriptor, } from '../Documentation'; +import type { Handler } from '.'; // Merges two objects ignoring null/undefined. function merge(obj1: T, obj2: U): (T & U) | null { @@ -23,7 +24,7 @@ function merge(obj1: T, obj2: U): (T & U) | null { * Extract info from the methods jsdoc blocks. Must be run after * flowComponentMethodsHandler. */ -export default function componentMethodsJsDocHandler( +const componentMethodsJsDocHandler: Handler = function ( documentation: Documentation, ): void { let methods = documentation.get('methods') as MethodDescriptor[] | null; @@ -54,4 +55,6 @@ export default function componentMethodsJsDocHandler( }); documentation.set('methods', methods); -} +}; + +export default componentMethodsJsDocHandler; diff --git a/src/handlers/defaultPropsHandler.ts b/src/handlers/defaultPropsHandler.ts index a7a92fd5c77..97f5b747348 100644 --- a/src/handlers/defaultPropsHandler.ts +++ b/src/handlers/defaultPropsHandler.ts @@ -15,6 +15,8 @@ import type { RestElement, SpreadElement, } from '@babel/types'; +import type { ComponentNode } from '../resolver'; +import type { Handler } from '.'; function getDefaultValue(path: NodePath): DefaultValueDescriptor | null { let defaultValue: string | undefined; @@ -52,7 +54,9 @@ function getDefaultValue(path: NodePath): DefaultValueDescriptor | null { return null; } -function getStatelessPropsPath(componentDefinition: NodePath): NodePath { +function getStatelessPropsPath( + componentDefinition: NodePath, +): NodePath { let value = resolveToValue(componentDefinition); if (isReactForwardRefCall(value)) { @@ -62,7 +66,9 @@ function getStatelessPropsPath(componentDefinition: NodePath): NodePath { return value.get('params')[0]; } -function getDefaultPropsPath(componentDefinition: NodePath): NodePath | null { +function getDefaultPropsPath( + componentDefinition: NodePath, +): NodePath | null { let defaultPropsPath: NodePath | null = getMemberValuePath( componentDefinition, 'defaultProps', @@ -138,9 +144,9 @@ function getDefaultValuesFromProps( }); } -export default function defaultPropsHandler( +const defaultPropsHandler: Handler = function ( documentation: Documentation, - componentDefinition: NodePath, + componentDefinition: NodePath, ): void { let statelessProps: NodePath | null = null; const defaultPropsPath = getDefaultPropsPath(componentDefinition); @@ -166,4 +172,6 @@ export default function defaultPropsHandler( false, ); } -} +}; + +export default defaultPropsHandler; diff --git a/src/handlers/displayNameHandler.ts b/src/handlers/displayNameHandler.ts index 4c2ad85d2a3..c61901ef811 100644 --- a/src/handlers/displayNameHandler.ts +++ b/src/handlers/displayNameHandler.ts @@ -6,32 +6,35 @@ import resolveFunctionDefinitionToReturnValue from '../utils/resolveFunctionDefi import type Documentation from '../Documentation'; import type { NodePath } from '@babel/traverse'; import type { Identifier } from '@babel/types'; +import type { Handler } from '.'; +import type { ComponentNode } from '../resolver'; -export default function displayNameHandler( +const displayNameHandler: Handler = function ( documentation: Documentation, - path: NodePath, + componentDefinition: NodePath, ): void { let displayNamePath: NodePath | null = getMemberValuePath( - path, + componentDefinition, 'displayName', ); if (!displayNamePath) { // Function and class declarations need special treatment. The name of the // function / class is the displayName if ( - (path.isClassDeclaration() || path.isFunctionDeclaration()) && - path.has('id') + (componentDefinition.isClassDeclaration() || + componentDefinition.isFunctionDeclaration()) && + componentDefinition.has('id') ) { documentation.set( 'displayName', - getNameOrValue(path.get('id') as NodePath), + getNameOrValue(componentDefinition.get('id') as NodePath), ); } else if ( - path.isArrowFunctionExpression() || - path.isFunctionExpression() || - isReactForwardRefCall(path) + componentDefinition.isArrowFunctionExpression() || + componentDefinition.isFunctionExpression() || + isReactForwardRefCall(componentDefinition) ) { - let currentPath = path; + let currentPath: NodePath = componentDefinition; while (currentPath.parentPath) { if (currentPath.parentPath.isVariableDeclarator()) { documentation.set( @@ -65,4 +68,6 @@ export default function displayNameHandler( return; } documentation.set('displayName', displayNamePath.node.value); -} +}; + +export default displayNameHandler; diff --git a/src/handlers/flowTypeHandler.ts b/src/handlers/flowTypeHandler.ts index 9a76cd9ee9a..dbe6cc564ac 100644 --- a/src/handlers/flowTypeHandler.ts +++ b/src/handlers/flowTypeHandler.ts @@ -11,6 +11,8 @@ import resolveToValue from '../utils/resolveToValue'; import setPropDescription from '../utils/setPropDescription'; import type { NodePath } from '@babel/traverse'; import type { FlowType } from '@babel/types'; +import type { ComponentNode } from '../resolver'; +import type { Handler } from '.'; function setPropDescriptor( documentation: Documentation, @@ -95,11 +97,11 @@ function setPropDescriptor( * * TODO either rename this handler or split in flow vs ts */ -export default function flowTypeHandler( +const flowTypeHandler: Handler = function ( documentation: Documentation, - path: NodePath, + componentDefinition: NodePath, ): void { - const typesPath = getTypeFromReactComponent(path); + const typesPath = getTypeFromReactComponent(componentDefinition); if (!typesPath) { return; @@ -113,4 +115,6 @@ export default function flowTypeHandler( }, null, ); -} +}; + +export default flowTypeHandler; diff --git a/src/handlers/index.ts b/src/handlers/index.ts index 1481e385f27..a11c92b76f6 100644 --- a/src/handlers/index.ts +++ b/src/handlers/index.ts @@ -1,5 +1,6 @@ import type { NodePath } from '@babel/traverse'; import type Documentation from '../Documentation'; +import type { ComponentNode } from '../resolver'; export { default as componentDocblockHandler } from './componentDocblockHandler'; export { default as componentMethodsHandler } from './componentMethodsHandler'; @@ -15,4 +16,7 @@ export { childContextTypeHandler, } from './propTypeHandler'; -export type Handler = (documentation: Documentation, path: NodePath) => void; +export type Handler = ( + documentation: Documentation, + componentDefinition: NodePath, +) => void; diff --git a/src/handlers/propDocBlockHandler.ts b/src/handlers/propDocBlockHandler.ts index 5112f6bd89a..b6d219eff7f 100644 --- a/src/handlers/propDocBlockHandler.ts +++ b/src/handlers/propDocBlockHandler.ts @@ -4,6 +4,8 @@ import getMemberValuePath from '../utils/getMemberValuePath'; import resolveToValue from '../utils/resolveToValue'; import setPropDescription from '../utils/setPropDescription'; import type Documentation from '../Documentation'; +import type { ComponentNode } from '../resolver'; +import type { Handler } from '.'; function resolveDocumentation( documentation: Documentation, @@ -26,12 +28,12 @@ function resolveDocumentation( }); } -export default function propDocBlockHandler( +const propDocBlockHandler: Handler = function ( documentation: Documentation, - path: NodePath, + componentDefinition: NodePath, ): void { let propTypesPath: NodePath | null = getMemberValuePath( - path, + componentDefinition, 'propTypes', ); if (!propTypesPath) { @@ -43,4 +45,6 @@ export default function propDocBlockHandler( } resolveDocumentation(documentation, propTypesPath); -} +}; + +export default propDocBlockHandler; diff --git a/src/handlers/propTypeCompositionHandler.ts b/src/handlers/propTypeCompositionHandler.ts index 4bb85f5e036..aab6fc1404b 100644 --- a/src/handlers/propTypeCompositionHandler.ts +++ b/src/handlers/propTypeCompositionHandler.ts @@ -4,6 +4,8 @@ import resolveToValue from '../utils/resolveToValue'; import type Documentation from '../Documentation'; import type { NodePath } from '@babel/traverse'; import type { ObjectExpression, Node } from '@babel/types'; +import type { Handler } from '.'; +import type { ComponentNode } from '../resolver'; /** * It resolves the path to its module name and adds it to the "composes" entry @@ -30,12 +32,12 @@ function processObjectExpression( }); } -export default function propTypeCompositionHandler( +const propTypeCompositionHandler: Handler = function ( documentation: Documentation, - path: NodePath, + componentDefinition: NodePath, ): void { let propTypesPath: NodePath | null = getMemberValuePath( - path, + componentDefinition, 'propTypes', ); if (!propTypesPath) { @@ -52,4 +54,6 @@ export default function propTypeCompositionHandler( } amendComposes(documentation, propTypesPath); -} +}; + +export default propTypeCompositionHandler; diff --git a/src/handlers/propTypeHandler.ts b/src/handlers/propTypeHandler.ts index e8d67d60d0d..aacb0d10521 100644 --- a/src/handlers/propTypeHandler.ts +++ b/src/handlers/propTypeHandler.ts @@ -10,6 +10,8 @@ import type Documentation from '../Documentation'; import type { PropDescriptor, PropTypeDescriptor } from '../Documentation'; import type { NodePath } from '@babel/traverse'; import type { Node } from '@babel/types'; +import type { Handler } from '.'; +import type { ComponentNode } from '../resolver'; function isPropTypesExpression(path: NodePath): boolean { const moduleName = resolveToModule(path); @@ -54,12 +56,13 @@ function amendPropTypes( }); } -function getPropTypeHandler( - propName: string, -): (documentation: Documentation, path: NodePath) => void { - return function (documentation: Documentation, path: NodePath) { +function getPropTypeHandler(propName: string): Handler { + return function ( + documentation: Documentation, + componentDefinition: NodePath, + ): void { let propTypesPath: NodePath | null = getMemberValuePath( - path, + componentDefinition, propName, ); if (!propTypesPath) { diff --git a/src/parse.ts b/src/parse.ts index 15d5558492a..6a8c7c4e1b9 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -6,17 +6,17 @@ import type { Options } from './babelParser'; import type { NodePath } from '@babel/traverse'; import type { Handler } from './handlers'; import type { Importer } from './importer'; -import type { Resolver } from './resolver'; +import type { ComponentNode, Resolver } from './resolver'; import FileState from './FileState'; const ERROR_MISSING_DEFINITION = 'No suitable component definition found.'; function executeHandlers( handlers: Handler[], - componentDefinitions: NodePath[], + componentDefinitions: Array>, ): DocumentationObject[] { return componentDefinitions.map( - (componentDefinition: NodePath): DocumentationObject => { + (componentDefinition): DocumentationObject => { const documentation = new Documentation(); handlers.forEach(handler => handler(documentation, componentDefinition)); return postProcessDocumentation(documentation.toObject()); diff --git a/src/resolver/findAllComponentDefinitions.ts b/src/resolver/findAllComponentDefinitions.ts index 70eed20f414..b6c8d673784 100644 --- a/src/resolver/findAllComponentDefinitions.ts +++ b/src/resolver/findAllComponentDefinitions.ts @@ -6,7 +6,7 @@ import normalizeClassDefinition from '../utils/normalizeClassDefinition'; import resolveToValue from '../utils/resolveToValue'; import type { NodePath } from '@babel/traverse'; import type FileState from '../FileState'; -import type { Resolver } from '.'; +import type { ComponentNode, Resolver } from '.'; /** * Given an AST, this function tries to find all object expressions that are @@ -14,8 +14,8 @@ import type { Resolver } from '.'; */ const findAllComponentDefinitions: Resolver = function ( file: FileState, -): NodePath[] { - const definitions = new Set(); +): Array> { + const definitions = new Set>(); function classVisitor(path) { if (isReactComponentClass(path)) { @@ -43,7 +43,9 @@ const findAllComponentDefinitions: Resolver = function ( if (isReactForwardRefCall(path)) { // If the the inner function was previously identified as a component // replace it with the parent node - const inner = resolveToValue(path.get('arguments')[0]); + const inner = resolveToValue( + path.get('arguments')[0], + ) as NodePath; definitions.delete(inner); definitions.add(path); diff --git a/src/resolver/findAllExportedComponentDefinitions.ts b/src/resolver/findAllExportedComponentDefinitions.ts index 40994758db3..995ef2a72ac 100644 --- a/src/resolver/findAllExportedComponentDefinitions.ts +++ b/src/resolver/findAllExportedComponentDefinitions.ts @@ -1,9 +1,4 @@ import isExportsOrModuleAssignment from '../utils/isExportsOrModuleAssignment'; -import isReactComponentClass from '../utils/isReactComponentClass'; -import isReactCreateClassCall from '../utils/isReactCreateClassCall'; -import isReactForwardRefCall from '../utils/isReactForwardRefCall'; -import isStatelessComponent from '../utils/isStatelessComponent'; -import normalizeClassDefinition from '../utils/normalizeClassDefinition'; import resolveExportDeclaration from '../utils/resolveExportDeclaration'; import resolveToValue from '../utils/resolveToValue'; import resolveHOC from '../utils/resolveHOC'; @@ -14,35 +9,10 @@ import type { ExportNamedDeclaration, } from '@babel/types'; import type FileState from '../FileState'; -import type { Resolver } from '.'; - -export function isComponentDefinition(path: NodePath): boolean { - return ( - isReactCreateClassCall(path) || - isReactComponentClass(path) || - isStatelessComponent(path) || - isReactForwardRefCall(path) - ); -} - -export function resolveDefinition(definition: NodePath): NodePath | null { - if (isReactCreateClassCall(definition)) { - // return argument - const resolvedPath = resolveToValue(definition.get('arguments')[0]); - if (resolvedPath.isObjectExpression()) { - return resolvedPath; - } - } else if (isReactComponentClass(definition)) { - normalizeClassDefinition(definition); - return definition; - } else if ( - isStatelessComponent(definition) || - isReactForwardRefCall(definition) - ) { - return definition; - } - return null; -} +import type { ComponentNode, Resolver } from '.'; +import resolveComponentDefinition, { + isComponentDefinition, +} from '../utils/resolveComponentDefinition'; /** * Given an AST, this function tries to find the exported component definitions. @@ -61,13 +31,13 @@ export function resolveDefinition(definition: NodePath): NodePath | null { */ const findExportedComponentDefinitions: Resolver = function ( file: FileState, -): NodePath[] { - const components: NodePath[] = []; +): Array> { + const components: Array> = []; function exportDeclaration( path: NodePath, ): void { - const definitions = resolveExportDeclaration(path) + resolveExportDeclaration(path) .reduce((acc, definition) => { if (isComponentDefinition(definition)) { acc.push(definition); @@ -78,17 +48,14 @@ const findExportedComponentDefinitions: Resolver = function ( } } return acc; - }, [] as NodePath[]) - .map(definition => resolveDefinition(definition)); + }, [] as Array>) + .forEach(definition => { + const resolved = resolveComponentDefinition(definition); + if (resolved && components.indexOf(resolved) === -1) { + components.push(resolved); + } + }); - if (definitions.length === 0) { - return path.skip(); - } - definitions.forEach(definition => { - if (definition && components.indexOf(definition) === -1) { - components.push(definition); - } - }); return path.skip(); } @@ -113,7 +80,7 @@ const findExportedComponentDefinitions: Resolver = function ( return path.skip(); } } - const definition = resolveDefinition(resolvedPath); + const definition = resolveComponentDefinition(resolvedPath); if (definition && components.indexOf(definition) === -1) { components.push(definition); } diff --git a/src/resolver/findExportedComponentDefinition.ts b/src/resolver/findExportedComponentDefinition.ts index 19cb481439c..7bb79a24590 100644 --- a/src/resolver/findExportedComponentDefinition.ts +++ b/src/resolver/findExportedComponentDefinition.ts @@ -8,12 +8,11 @@ import type { ExportDefaultDeclaration, ExportNamedDeclaration, } from '@babel/types'; -import type { Resolver } from '.'; +import type { ComponentNode, Resolver } from '.'; import type FileState from '../FileState'; -import { +import resolveComponentDefinition, { isComponentDefinition, - resolveDefinition, -} from './findAllExportedComponentDefinitions'; +} from '../utils/resolveComponentDefinition'; const ERROR_MULTIPLE_DEFINITIONS = 'Multiple exported component definitions found.'; @@ -35,14 +34,14 @@ const ERROR_MULTIPLE_DEFINITIONS = */ const findExportedComponentDefinition: Resolver = function ( file: FileState, -): NodePath[] { - const foundDefinition: NodePath[] = []; +): Array> { + const foundDefinition: Array> = []; function exportDeclaration( path: NodePath, ): void { const definitions = resolveExportDeclaration(path).reduce( - (acc: NodePath[], definition: NodePath) => { + (acc, definition) => { if (isComponentDefinition(definition)) { acc.push(definition); } else { @@ -53,7 +52,7 @@ const findExportedComponentDefinition: Resolver = function ( } return acc; }, - [], + [] as Array>, ); if (definitions.length === 0) { @@ -63,7 +62,7 @@ const findExportedComponentDefinition: Resolver = function ( // If a file exports multiple components, ... complain! throw new Error(ERROR_MULTIPLE_DEFINITIONS); } - const definition = resolveDefinition(definitions[0]); + const definition = resolveComponentDefinition(definitions[0]); if (definition) { foundDefinition.push(definition); } @@ -95,7 +94,7 @@ const findExportedComponentDefinition: Resolver = function ( // If a file exports multiple components, ... complain! throw new Error(ERROR_MULTIPLE_DEFINITIONS); } - const definition = resolveDefinition(resolvedPath); + const definition = resolveComponentDefinition(resolvedPath); if (definition) { foundDefinition.push(definition); } diff --git a/src/resolver/index.ts b/src/resolver/index.ts index 628c26efbc2..9b92c2b46ac 100644 --- a/src/resolver/index.ts +++ b/src/resolver/index.ts @@ -3,10 +3,34 @@ import findAllExportedComponentDefinitions from './findAllExportedComponentDefin import findExportedComponentDefinition from './findExportedComponentDefinition'; import type { NodePath } from '@babel/traverse'; import type FileState from '../FileState'; +import type { + ArrowFunctionExpression, + CallExpression, + ClassDeclaration, + ClassExpression, + FunctionDeclaration, + FunctionExpression, + ObjectExpression, + ObjectMethod, +} from '@babel/types'; + +export type StatelessComponentNode = + | ArrowFunctionExpression + | FunctionDeclaration + | FunctionExpression + | ObjectMethod; + +export type ComponentNode = + | CallExpression + | ClassDeclaration + | ClassExpression + | ObjectExpression + | StatelessComponentNode; + +export type Resolver = (file: FileState) => Array>; export { findAllComponentDefinitions, findAllExportedComponentDefinitions, findExportedComponentDefinition, }; -export type Resolver = (file: FileState) => NodePath[]; diff --git a/src/utils/__tests__/getMemberValuePath-test.ts b/src/utils/__tests__/getMemberValuePath-test.ts index 295c85cdabe..86d67ff358c 100644 --- a/src/utils/__tests__/getMemberValuePath-test.ts +++ b/src/utils/__tests__/getMemberValuePath-test.ts @@ -3,6 +3,13 @@ import getPropertyValuePath from '../getPropertyValuePath'; import getClassMemberValuePath from '../getClassMemberValuePath'; import getMemberValuePath from '../getMemberValuePath'; import getMemberExpressionValuePath from '../getMemberExpressionValuePath'; +import type { + CallExpression, + ClassDeclaration, + ClassExpression, + ObjectExpression, + TaggedTemplateExpression, +} from '@babel/types'; jest.mock('../getPropertyValuePath'); jest.mock('../getClassMemberValuePath'); @@ -10,35 +17,37 @@ jest.mock('../getMemberExpressionValuePath'); describe('getMemberValuePath', () => { it('handles ObjectExpressions', () => { - const path = parse.expression('{}'); + const path = parse.expression('{}'); getMemberValuePath(path, 'foo'); expect(getPropertyValuePath).toBeCalledWith(path, 'foo'); }); it('handles ClassDeclarations', () => { - const path = parse.statement('class Foo {}'); + const path = parse.statement('class Foo {}'); getMemberValuePath(path, 'foo'); expect(getClassMemberValuePath).toBeCalledWith(path, 'foo'); }); it('handles TaggedTemplateLiterals', () => { - const path = parse.expression('foo``'); + const path = parse.expression('foo``'); getMemberValuePath(path, 'foo'); expect(getMemberExpressionValuePath).toBeCalledWith(path, 'foo'); }); it('handles ClassExpressions', () => { - const path = parse.expression('class {}'); + const path = parse.expression('class {}'); getMemberValuePath(path, 'foo'); expect(getClassMemberValuePath).toBeCalledWith(path, 'foo'); }); it('handles CallExpressions', () => { - const path = parse.expression('system({is: "button"}, "space")'); + const path = parse.expression( + 'system({is: "button"}, "space")', + ); getMemberValuePath(path, 'foo'); expect(getMemberExpressionValuePath).toBeCalledWith(path, 'foo'); @@ -46,7 +55,7 @@ describe('getMemberValuePath', () => { describe('tries defaultProps synonyms', () => { it('with object', () => { - const path = parse.expression('{}'); + const path = parse.expression('{}'); getMemberValuePath(path, 'defaultProps'); expect(getPropertyValuePath).toBeCalledWith(path, 'defaultProps'); @@ -54,7 +63,7 @@ describe('getMemberValuePath', () => { }); it('with class', () => { - const path = parse.statement('class Foo {}'); + const path = parse.statement('class Foo {}'); getMemberValuePath(path, 'defaultProps'); expect(getClassMemberValuePath).toBeCalledWith(path, 'defaultProps'); @@ -67,7 +76,7 @@ describe('getMemberValuePath', () => { const mockPath2 = parse.expression('21'); jest.mocked(getPropertyValuePath).mockReturnValue(mockPath); jest.mocked(getClassMemberValuePath).mockReturnValue(mockPath2); - let path = parse.expression('{}'); + let path = parse.expression('{}'); expect(getMemberValuePath(path, 'defaultProps')).toBe(mockPath); diff --git a/src/utils/__tests__/isStatelessComponent-test.ts b/src/utils/__tests__/isStatelessComponent-test.ts index 6d1fe5f695c..7d7b5254bfa 100644 --- a/src/utils/__tests__/isStatelessComponent-test.ts +++ b/src/utils/__tests__/isStatelessComponent-test.ts @@ -162,10 +162,10 @@ describe('isStatelessComponent', () => { .get('init'); const bar = def.get('properties')[0]; - const baz = def.get('properties')[1]; - const hello = def.get('properties')[2]; + const baz = def.get('properties')[1].get('value'); + const hello = def.get('properties')[2].get('value'); const render = def.get('properties')[3]; - const world = def.get('properties')[4]; + const world = def.get('properties')[4].get('value'); expect(isStatelessComponent(bar)).toBe(true); expect(isStatelessComponent(baz)).toBe(true); diff --git a/src/utils/getMemberValuePath.ts b/src/utils/getMemberValuePath.ts index 1e1418da1a2..c5a5303de31 100644 --- a/src/utils/getMemberValuePath.ts +++ b/src/utils/getMemberValuePath.ts @@ -3,7 +3,27 @@ import getClassMemberValuePath from './getClassMemberValuePath'; import getMemberExpressionValuePath from './getMemberExpressionValuePath'; import getPropertyValuePath from './getPropertyValuePath'; import resolveFunctionDefinitionToReturnValue from '../utils/resolveFunctionDefinitionToReturnValue'; -import type { ClassMethod, Expression, ObjectMethod } from '@babel/types'; +import type { + CallExpression, + ClassDeclaration, + ClassExpression, + ClassMethod, + Expression, + ObjectExpression, + ObjectMethod, + TaggedTemplateExpression, + VariableDeclaration, +} from '@babel/types'; +import type { StatelessComponentNode } from '../resolver'; + +type SupportedNodes = + | CallExpression + | ClassDeclaration + | ClassExpression + | ObjectExpression + | StatelessComponentNode + | TaggedTemplateExpression + | VariableDeclaration; const postprocessPropTypes = ( path: NodePath, @@ -12,39 +32,45 @@ const postprocessPropTypes = ( const POSTPROCESS_MEMBERS = new Map([['propTypes', postprocessPropTypes]]); const SUPPORTED_DEFINITION_TYPES = [ - 'ObjectExpression', - 'ClassDeclaration', - 'ClassExpression', + // potential stateless function component + 'ArrowFunctionExpression', /** * Adds support for libraries such as - * [styled components]{@link https://github.com/styled-components} that use - * TaggedTemplateExpression's to generate components. + * [system-components]{@link https://jxnblk.com/styled-system/system-components} that use + * CallExpressions to generate components. * * While react-docgen's built-in resolvers do not support resolving - * TaggedTemplateExpression definitions, third-party resolvers (such as + * CallExpressions definitions, third-party resolvers (such as * https://github.com/Jmeyering/react-docgen-annotation-resolver) could be * used to add these definitions. */ - 'TaggedTemplateExpression', + 'CallExpression', + 'ClassDeclaration', + 'ClassExpression', // potential stateless function component - 'VariableDeclaration', - 'ArrowFunctionExpression', 'FunctionDeclaration', + // potential stateless function component 'FunctionExpression', + 'ObjectExpression', + // potential stateless function component + 'ObjectMethod', /** * Adds support for libraries such as - * [system-components]{@link https://jxnblk.com/styled-system/system-components} that use - * CallExpressions to generate components. + * [styled components]{@link https://github.com/styled-components} that use + * TaggedTemplateExpression's to generate components. * * While react-docgen's built-in resolvers do not support resolving - * CallExpressions definitions, third-party resolvers (such as + * TaggedTemplateExpression definitions, third-party resolvers (such as * https://github.com/Jmeyering/react-docgen-annotation-resolver) could be * used to add these definitions. */ - 'CallExpression', + 'TaggedTemplateExpression', + 'VariableDeclaration', ]; -export function isSupportedDefinitionType(path: NodePath): boolean { +export function isSupportedDefinitionType( + path: NodePath, +): path is NodePath { return SUPPORTED_DEFINITION_TYPES.includes(path.node.type); } @@ -62,18 +88,9 @@ export function isSupportedDefinitionType(path: NodePath): boolean { * `getDefaultProps` can be used interchangeably. */ export default function getMemberValuePath( - componentDefinition: NodePath, + componentDefinition: NodePath, memberName: string, ): NodePath | null { - // TODO test error message - if (!isSupportedDefinitionType(componentDefinition)) { - throw new TypeError( - `Got unsupported definition type. Definition must be one of ${SUPPORTED_DEFINITION_TYPES.join( - ', ', - )}. Got "${componentDefinition.node.type}" instead.`, - ); - } - let result: NodePath | null; if (componentDefinition.isObjectExpression()) { result = getPropertyValuePath(componentDefinition, memberName); diff --git a/src/utils/getTypeFromReactComponent.ts b/src/utils/getTypeFromReactComponent.ts index e72812cfc64..a5227f0f398 100644 --- a/src/utils/getTypeFromReactComponent.ts +++ b/src/utils/getTypeFromReactComponent.ts @@ -44,12 +44,8 @@ export default (path: NodePath): NodePath | null => { if (isReactComponentClass(path)) { const superTypes = path.get('superTypeParameters'); - if (superTypes.node) { - const params = ( - superTypes as NodePath< - TSTypeParameterInstantiation | TypeParameterInstantiation - > - ).get('params'); + if (superTypes.hasNode()) { + const params = superTypes.get('params'); typePath = params[params.length === 3 ? 1 : 0]; } else { const propsMemberPath = getMemberValuePath(path, 'props'); diff --git a/src/utils/isStatelessComponent.ts b/src/utils/isStatelessComponent.ts index ba018c4da69..4345e84dc7a 100644 --- a/src/utils/isStatelessComponent.ts +++ b/src/utils/isStatelessComponent.ts @@ -7,11 +7,10 @@ import type { NodePath } from '@babel/traverse'; import type { Expression } from '@babel/types'; const validPossibleStatelessComponentTypes = [ - 'ObjectMethod', - 'ObjectProperty', + 'ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression', - 'ArrowFunctionExpression', + 'ObjectMethod', ]; function isJSXElementOrReactCall(path: NodePath): boolean { diff --git a/src/utils/resolveComponentDefinition.ts b/src/utils/resolveComponentDefinition.ts new file mode 100644 index 00000000000..03cbfc200d9 --- /dev/null +++ b/src/utils/resolveComponentDefinition.ts @@ -0,0 +1,42 @@ +import type { NodePath } from '@babel/traverse'; +import type { ComponentNode } from '../resolver'; +import isReactComponentClass from './isReactComponentClass'; +import isReactCreateClassCall from './isReactCreateClassCall'; +import isReactForwardRefCall from './isReactForwardRefCall'; +import isStatelessComponent from './isStatelessComponent'; +import normalizeClassDefinition from './normalizeClassDefinition'; +import resolveToValue from './resolveToValue'; + +export function isComponentDefinition( + path: NodePath, +): path is NodePath { + return ( + isReactCreateClassCall(path) || + isReactComponentClass(path) || + isStatelessComponent(path) || + isReactForwardRefCall(path) + ); +} + +export default function resolveComponentDefinition( + definition: NodePath, +): NodePath | null { + if (isReactCreateClassCall(definition)) { + // return argument + const resolvedPath = resolveToValue(definition.get('arguments')[0]); + if (resolvedPath.isObjectExpression()) { + return resolvedPath; + } + } else if (isReactComponentClass(definition)) { + normalizeClassDefinition(definition); + + return definition; + } else if ( + isStatelessComponent(definition) || + isReactForwardRefCall(definition) + ) { + return definition; + } + + return null; +} From 8f8d655867a8aad1c77c34675074872b30411fbf Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Tue, 26 Jul 2022 23:21:10 +0200 Subject: [PATCH 23/44] feat: rename flowTypeHandler to codeTypeHandler --- ...t.ts.snap => codeTypeHandler-test.ts.snap} | 16 +++---- ...andler-test.ts => codeTypeHandler-test.ts} | 46 +++++++++---------- ...{flowTypeHandler.ts => codeTypeHandler.ts} | 6 +-- src/handlers/index.ts | 2 +- src/main.ts | 2 +- 5 files changed, 35 insertions(+), 37 deletions(-) rename src/handlers/__tests__/__snapshots__/{flowTypeHandler-test.ts.snap => codeTypeHandler-test.ts.snap} (80%) rename src/handlers/__tests__/{flowTypeHandler-test.ts => codeTypeHandler-test.ts} (89%) rename src/handlers/{flowTypeHandler.ts => codeTypeHandler.ts} (96%) diff --git a/src/handlers/__tests__/__snapshots__/flowTypeHandler-test.ts.snap b/src/handlers/__tests__/__snapshots__/codeTypeHandler-test.ts.snap similarity index 80% rename from src/handlers/__tests__/__snapshots__/flowTypeHandler-test.ts.snap rename to src/handlers/__tests__/__snapshots__/codeTypeHandler-test.ts.snap index 83ae155a99d..f70870373bf 100644 --- a/src/handlers/__tests__/__snapshots__/flowTypeHandler-test.ts.snap +++ b/src/handlers/__tests__/__snapshots__/codeTypeHandler-test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`flowTypeHandler TypeAlias class definition for flow <0.53 ignores hash map entry 1`] = ` +exports[`codeTypeHandler TypeAlias class definition for flow <0.53 ignores hash map entry 1`] = ` Object { "bar": Object { "description": "", @@ -10,7 +10,7 @@ Object { } `; -exports[`flowTypeHandler TypeAlias class definition for flow >=0.53 with State ignores hash map entry 1`] = ` +exports[`codeTypeHandler TypeAlias class definition for flow >=0.53 with State ignores hash map entry 1`] = ` Object { "bar": Object { "description": "", @@ -20,7 +20,7 @@ Object { } `; -exports[`flowTypeHandler TypeAlias class definition for flow >=0.53 without State ignores hash map entry 1`] = ` +exports[`codeTypeHandler TypeAlias class definition for flow >=0.53 without State ignores hash map entry 1`] = ` Object { "bar": Object { "description": "", @@ -30,7 +30,7 @@ Object { } `; -exports[`flowTypeHandler TypeAlias class definition with inline props ignores hash map entry 1`] = ` +exports[`codeTypeHandler TypeAlias class definition with inline props ignores hash map entry 1`] = ` Object { "bar": Object { "description": "", @@ -40,7 +40,7 @@ Object { } `; -exports[`flowTypeHandler TypeAlias stateless component ignores hash map entry 1`] = ` +exports[`codeTypeHandler TypeAlias stateless component ignores hash map entry 1`] = ` Object { "bar": Object { "description": "", @@ -50,7 +50,7 @@ Object { } `; -exports[`flowTypeHandler does support utility types inline 1`] = ` +exports[`codeTypeHandler does support utility types inline 1`] = ` Object { "foo": Object { "description": "", @@ -60,7 +60,7 @@ Object { } `; -exports[`flowTypeHandler imported prop types imported 1`] = ` +exports[`codeTypeHandler imported prop types imported 1`] = ` Object { "abc": Object { "description": "", @@ -95,7 +95,7 @@ Object { } `; -exports[`flowTypeHandler imported prop types type imported 1`] = ` +exports[`codeTypeHandler imported prop types type imported 1`] = ` Object { "abc": Object { "description": "", diff --git a/src/handlers/__tests__/flowTypeHandler-test.ts b/src/handlers/__tests__/codeTypeHandler-test.ts similarity index 89% rename from src/handlers/__tests__/flowTypeHandler-test.ts rename to src/handlers/__tests__/codeTypeHandler-test.ts index 334c19e4c13..c666bbb0d17 100644 --- a/src/handlers/__tests__/flowTypeHandler-test.ts +++ b/src/handlers/__tests__/codeTypeHandler-test.ts @@ -1,6 +1,6 @@ import { parse, makeMockImporter } from '../../../tests/utils'; import Documentation from '../../Documentation'; -import flowTypeHandler from '../flowTypeHandler'; +import codeTypeHandler from '../codeTypeHandler'; import type DocumentationMock from '../../__mocks__/Documentation'; import type { ArrowFunctionExpression, @@ -18,7 +18,7 @@ jest.mock('../../utils/getFlowType', () => ({ __esModule: true, })); -describe('flowTypeHandler', () => { +describe('codeTypeHandler', () => { let documentation: Documentation & DocumentationMock; beforeEach(() => { @@ -61,7 +61,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition); + codeTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -91,7 +91,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition); + codeTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -116,7 +116,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition); + codeTypeHandler(documentation, definition); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -130,7 +130,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition); + codeTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -154,7 +154,7 @@ describe('flowTypeHandler', () => { `; const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition); + codeTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -176,7 +176,7 @@ describe('flowTypeHandler', () => { const definition = getSrc(flowTypesSrc); - flowTypeHandler(documentation, definition); + codeTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -246,7 +246,7 @@ describe('flowTypeHandler', () => { it('ObjectExpression', () => { const definition = parse.expression('{fooBar: 42}'); - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); }); it('ClassDeclaration', () => { @@ -254,14 +254,14 @@ describe('flowTypeHandler', () => { 'class Foo extends Component {}', ); - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); }); it('ArrowFunctionExpression', () => { const definition = parse.statement('() =>
'); - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); }); }); @@ -275,7 +275,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - flowTypeHandler(documentation, definition); + codeTypeHandler(documentation, definition); expect(documentation.descriptors).toEqual({ foo: { @@ -295,7 +295,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -310,7 +310,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); }); @@ -326,7 +326,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); }); @@ -341,7 +341,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -355,7 +355,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); }); @@ -370,7 +370,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -384,7 +384,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); }); @@ -398,7 +398,7 @@ describe('flowTypeHandler', () => { ) .get('expression') as NodePath; - expect(() => flowTypeHandler(documentation, definition)).not.toThrow(); + expect(() => codeTypeHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toEqual({}); }); }); @@ -410,7 +410,7 @@ describe('flowTypeHandler', () => { type Props = { foo: string }; React.forwardRef((props: Props, ref) =>
{props.foo}
); `; - flowTypeHandler(documentation, parse.expressionLast(src)); + codeTypeHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toEqual({ foo: { flowType: {}, @@ -427,7 +427,7 @@ describe('flowTypeHandler', () => { const ComponentImpl = (props: Props, ref) =>
{props.foo}
; React.forwardRef(ComponentImpl); `; - flowTypeHandler(documentation, parse.expressionLast(src)); + codeTypeHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toEqual({ foo: { flowType: {}, @@ -444,7 +444,7 @@ describe('flowTypeHandler', () => { let Component = (props: Props, ref) =>
{props.foo}
; Component = React.forwardRef(Component); `; - flowTypeHandler( + codeTypeHandler( documentation, parse.expressionLast(src).get('right') as NodePath, ); diff --git a/src/handlers/flowTypeHandler.ts b/src/handlers/codeTypeHandler.ts similarity index 96% rename from src/handlers/flowTypeHandler.ts rename to src/handlers/codeTypeHandler.ts index dbe6cc564ac..648e8e97136 100644 --- a/src/handlers/flowTypeHandler.ts +++ b/src/handlers/codeTypeHandler.ts @@ -94,10 +94,8 @@ function setPropDescriptor( * This handler tries to find flow Type annotated react components and extract * its types to the documentation. It also extracts docblock comments which are * inlined in the type definition. - * - * TODO either rename this handler or split in flow vs ts */ -const flowTypeHandler: Handler = function ( +const codeTypeHandler: Handler = function ( documentation: Documentation, componentDefinition: NodePath, ): void { @@ -117,4 +115,4 @@ const flowTypeHandler: Handler = function ( ); }; -export default flowTypeHandler; +export default codeTypeHandler; diff --git a/src/handlers/index.ts b/src/handlers/index.ts index a11c92b76f6..7f64d701389 100644 --- a/src/handlers/index.ts +++ b/src/handlers/index.ts @@ -7,7 +7,7 @@ export { default as componentMethodsHandler } from './componentMethodsHandler'; export { default as componentMethodsJsDocHandler } from './componentMethodsJsDocHandler'; export { default as defaultPropsHandler } from './defaultPropsHandler'; export { default as displayNameHandler } from './displayNameHandler'; -export { default as flowTypeHandler } from './flowTypeHandler'; +export { default as codeTypeHandler } from './codeTypeHandler'; export { default as propDocBlockHandler } from './propDocBlockHandler'; export { default as propTypeCompositionHandler } from './propTypeCompositionHandler'; export { diff --git a/src/main.ts b/src/main.ts index 0f09aa5fcff..c497f514586 100644 --- a/src/main.ts +++ b/src/main.ts @@ -17,7 +17,7 @@ const defaultHandlers: Handler[] = [ allHandlers.childContextTypeHandler, allHandlers.propTypeCompositionHandler, allHandlers.propDocBlockHandler, - allHandlers.flowTypeHandler, + allHandlers.codeTypeHandler, allHandlers.defaultPropsHandler, allHandlers.componentDocblockHandler, allHandlers.displayNameHandler, From 70882aecc07999ae9e60dc9a8498ce6574c2f9c6 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Tue, 26 Jul 2022 23:28:02 +0200 Subject: [PATCH 24/44] chore: add padding eslint rule --- .eslintrc.js | 17 +++++ benchmark/index.js | 2 + bin/__tests__/__fixtures__/customResolver.js | 1 + bin/__tests__/react-docgen-test.ts | 11 ++++ bin/react-docgen.js | 9 +++ src/Documentation.ts | 7 ++ src/FileState.ts | 2 + src/__tests__/main-test.ts | 4 ++ src/__tests__/parse-test.ts | 2 + .../__tests__/codeTypeHandler-test.ts | 3 + .../__tests__/componentMethodsHandler-test.ts | 1 + .../componentMethodsJsDocHandler-test.ts | 1 + .../__tests__/defaultPropsHandler-test.ts | 37 +++++++++++ .../__tests__/displayNameHandler-test.ts | 47 ++++++++++++++ .../__tests__/propDocblockHandler-test.ts | 2 + .../propTypeCompositionHandler-test.ts | 2 + .../__tests__/propTypeHandler-test.ts | 5 ++ src/handlers/codeTypeHandler.ts | 8 +++ src/handlers/componentDocblockHandler.ts | 3 + src/handlers/componentMethodsHandler.ts | 4 ++ src/handlers/componentMethodsJsDocHandler.ts | 4 ++ src/handlers/defaultPropsHandler.ts | 5 ++ src/handlers/displayNameHandler.ts | 6 ++ src/handlers/propDocBlockHandler.ts | 2 + src/handlers/propTypeCompositionHandler.ts | 3 + src/handlers/propTypeHandler.ts | 6 ++ src/importer/makeFsImporter.ts | 7 ++ src/parse.ts | 3 + .../findAllComponentDefinitions-test.ts | 18 +++++ ...indAllExportedComponentDefinitions-test.ts | 1 - .../findExportedComponentDefinition-test.ts | 65 +++++++++++++++++++ src/resolver/findAllComponentDefinitions.ts | 4 ++ .../findAllExportedComponentDefinitions.ts | 6 ++ .../findExportedComponentDefinition.ts | 7 ++ src/utils/__tests__/docblock-test.ts | 4 ++ src/utils/__tests__/getFlowType-test.ts | 32 +++++++++ .../__tests__/getMemberExpressionRoot-test.ts | 3 + .../__tests__/getMemberValuePath-test.ts | 1 + .../__tests__/getMethodDocumentation-test.ts | 24 +++++++ src/utils/__tests__/getParameterName-test.ts | 7 ++ .../__tests__/getPropertyValuePath-test.ts | 5 ++ src/utils/__tests__/getTSType-test.ts | 31 +++++++++ .../__tests__/isReactCloneElementCall-test.ts | 9 +++ .../__tests__/isReactComponentClass-test.ts | 6 ++ .../__tests__/isReactComponentMethod-test.ts | 6 ++ .../__tests__/isReactCreateClassCall-test.ts | 13 ++++ .../isReactCreateElementCall-test.ts | 9 +++ .../__tests__/isReactForwardRefCall-test.ts | 10 +++ .../__tests__/isStatelessComponent-test.ts | 3 + src/utils/__tests__/parseJsDoc-test.ts | 3 + .../resolveExportDeclaration-test.ts | 3 + .../resolveGenericTypeAnnotations-test.ts | 1 + src/utils/__tests__/resolveHOC-test.ts | 13 ++++ src/utils/__tests__/resolveToModule-test.ts | 9 +++ src/utils/__tests__/resolveToValue-test.ts | 8 +++ src/utils/docblock.ts | 2 + src/utils/expressionTo.ts | 4 ++ src/utils/flowUtilityTypes.ts | 1 + src/utils/getFlowType.ts | 14 ++++ src/utils/getMemberExpressionRoot.ts | 1 + src/utils/getMemberExpressionValuePath.ts | 9 +++ src/utils/getMemberValuePath.ts | 2 + src/utils/getMembers.ts | 3 + src/utils/getMethodDocumentation.ts | 9 +++ src/utils/getPropType.ts | 20 ++++++ src/utils/getPropertyName.ts | 2 + src/utils/getPropertyValuePath.ts | 1 + src/utils/getTSType.ts | 23 ++++++- src/utils/getTypeAnnotation.ts | 1 + src/utils/getTypeFromReactComponent.ts | 8 +++ src/utils/getTypeParameters.ts | 1 + src/utils/isExportsOrModuleAssignment.ts | 1 + src/utils/isReactBuiltinCall.ts | 1 + src/utils/isReactComponentClass.ts | 2 + src/utils/isReactComponentMethod.ts | 1 + src/utils/isReactCreateClassCall.ts | 1 + src/utils/isStatelessComponent.ts | 3 + src/utils/match.ts | 1 + src/utils/normalizeClassDefinition.ts | 9 +++ src/utils/parseJsDoc.ts | 4 ++ src/utils/resolveComponentDefinition.ts | 1 + src/utils/resolveExportDeclaration.ts | 3 + .../resolveFunctionDefinitionToReturnValue.ts | 2 + src/utils/resolveHOC.ts | 1 + src/utils/resolveObjectKeysToArray.ts | 6 ++ src/utils/resolveObjectValuesToArray.ts | 6 ++ src/utils/resolveToModule.ts | 2 + src/utils/resolveToValue.ts | 16 +++++ src/utils/setPropDescription.ts | 2 + src/utils/ts-types/index.ts | 1 + tests/setupTestFramework.ts | 1 + tests/utils.ts | 4 ++ website/src/components/App.js | 2 + website/src/components/CodeMirrorPanel.js | 2 +- 94 files changed, 675 insertions(+), 3 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 8af62029cbb..e5c65f38ca7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,6 +10,23 @@ module.exports = { rules: { 'no-shadow': 'error', 'no-var': 'error', + 'padding-line-between-statements': [ + 'error', + // Require newline before return + { blankLine: 'always', prev: '*', next: 'return' }, + // Require newline after a batch of variable declarations + { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + { + blankLine: 'never', + prev: ['import'], + next: ['import'], + }, + ], 'prefer-const': 'error', strict: ['error', 'never'], }, diff --git a/benchmark/index.js b/benchmark/index.js index 1067f0027d8..72c3f6fab36 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -46,6 +46,7 @@ files.forEach(file => { parse5(code, undefined, undefined, options); }); const result = [suite.name]; + suite.on('cycle', function (event) { { // separate scope so we can cleanup all this afterwards @@ -54,6 +55,7 @@ files.forEach(file => { const msg = `${Math.round(bench.hz * factor) / factor} ops/sec ±${ Math.round(bench.stats.rme * 100) / 100 }% (${Math.round(bench.stats.mean * 1000)}ms)`; + result.push(msg); } global.gc(); diff --git a/bin/__tests__/__fixtures__/customResolver.js b/bin/__tests__/__fixtures__/customResolver.js index 21d62823c19..c436ef1aa09 100644 --- a/bin/__tests__/__fixtures__/customResolver.js +++ b/bin/__tests__/__fixtures__/customResolver.js @@ -12,5 +12,6 @@ const { NodePath } = require('ast-types'); module.exports = function (ast, parser) { const path = new NodePath(parser.parse(code)); + return path.get('program', 'body', 0, 'expression'); }; diff --git a/bin/__tests__/react-docgen-test.ts b/bin/__tests__/react-docgen-test.ts index d2923e234d3..b46e0c64193 100644 --- a/bin/__tests__/react-docgen-test.ts +++ b/bin/__tests__/react-docgen-test.ts @@ -19,6 +19,7 @@ function run( const docgen = spawn(path.join(__dirname, '../react-docgen.js'), args); let stdout = ''; let stderr = ''; + docgen.stdout?.on('data', data => (stdout += data)); docgen.stderr?.on('data', data => (stderr += data)); docgen.on('close', () => resolve([stdout, stderr])); @@ -63,10 +64,12 @@ describe.skip('react-docgen CLI', () => { } const componentPath = path.join(dir, `Component.${extension}`); + await writeFile(componentPath, component, 'utf-8'); tempComponents.push(componentPath); const noComponentPath = path.join(dir, `NoComponent.${extension}`); + await writeFile(noComponentPath, '{}', 'utf-8'); tempNoComponents.push(noComponentPath); @@ -112,6 +115,7 @@ describe.skip('react-docgen CLI', () => { async () => { await createTempfiles(); const [stdout, stderr] = await run([tempDir]); + expect(stderr).toContain('NoComponent'); expect(stdout).toContain('Component'); }, @@ -148,6 +152,7 @@ describe.skip('react-docgen CLI', () => { '--extension=bar', tempDir, ]); + expect(stdout).toContain('Component.foo'); expect(stdout).toContain('Component.bar'); @@ -195,6 +200,7 @@ describe.skip('react-docgen CLI', () => { await createTempfiles(undefined, 'foo'); const [stdout, stderr] = await run(['--ignore=foo', tempDir]); + expect(stdout).toBe(''); expect(stderr).toBe(''); }, @@ -207,6 +213,7 @@ describe.skip('react-docgen CLI', () => { await createTempfiles(undefined, 'foo'); const [stdout, stderr] = await run(['-i', 'foo', tempDir]); + expect(stdout).toBe(''); expect(stderr).toBe(''); }, @@ -217,6 +224,7 @@ describe.skip('react-docgen CLI', () => { 'writes to stdout', async () => { const [stdout, stderr] = await run([], component); + expect(stdout.length > 0).toBe(true); expect(stderr.length).toBe(0); }, @@ -227,6 +235,7 @@ describe.skip('react-docgen CLI', () => { 'writes to stderr', async () => { const [stdout, stderr] = await run([], '{}'); + expect(stderr.length > 0).toBe(true); expect(stdout.length).toBe(0); }, @@ -237,6 +246,7 @@ describe.skip('react-docgen CLI', () => { 'writes to a file if provided', async () => { const outFile = tempFile(); + await createTempfiles(); const [stdout] = await run([`--out=${outFile}`, tempDir]); @@ -251,6 +261,7 @@ describe.skip('react-docgen CLI', () => { 'writes to a file if provided shortcut', async () => { const outFile = tempFile(); + await createTempfiles(); const [stdout] = await run(['-o', outFile, tempDir]); diff --git a/bin/react-docgen.js b/bin/react-docgen.js index 39122839776..cc13684a224 100755 --- a/bin/react-docgen.js +++ b/bin/react-docgen.js @@ -3,6 +3,7 @@ const argv = require('commander'); function collect(val, memo) { memo.push(val); + return memo; } @@ -61,12 +62,14 @@ let excludePatterns = argv.exclude; let resolver; let errorMessage; const regexRegex = /^\/(.*)\/([igymu]{0,5})$/; + if ( excludePatterns && excludePatterns.length === 1 && regexRegex.test(excludePatterns[0]) ) { const match = excludePatterns[0].match(regexRegex); + excludePatterns = new RegExp(match[1], match[2]); } @@ -79,6 +82,7 @@ if (argv.resolver) { throw error; } const resolverPath = path.resolve(process.cwd(), argv.resolver); + try { // Look for local resolver resolver = require(resolverPath); @@ -160,11 +164,13 @@ if (errorMessage) { * 2. No files passed, consume input stream */ let source = ''; + process.stdin.setEncoding('utf8'); process.stdin.resume(); const timer = setTimeout(function () { process.stderr.write('Still waiting for std input...'); }, 5000); + process.stdin.on('data', function (chunk) { clearTimeout(timer); source += chunk; @@ -181,6 +187,7 @@ if (errorMessage) { * 3. Paths are passed */ const result = Object.create(null); + async.eachSeries( paths, function (filePath, done) { @@ -188,6 +195,7 @@ if (errorMessage) { if (error) { writeError(error, filePath); done(); + return; } if (stats.isDirectory()) { @@ -210,6 +218,7 @@ if (errorMessage) { }, function () { const resultsPaths = Object.keys(result); + if (resultsPaths.length === 0) { // we must have gotten an error process.exitCode = 1; diff --git a/src/Documentation.ts b/src/Documentation.ts index c8bce1513e5..2fdd36ccc94 100644 --- a/src/Documentation.ts +++ b/src/Documentation.ts @@ -167,25 +167,31 @@ export default class Documentation { getPropDescriptor(propName: string): PropDescriptor { let propDescriptor = this.#props.get(propName); + if (!propDescriptor) { this.#props.set(propName, (propDescriptor = {})); } + return propDescriptor; } getContextDescriptor(propName: string): PropDescriptor { let propDescriptor = this.#context.get(propName); + if (!propDescriptor) { this.#context.set(propName, (propDescriptor = {})); } + return propDescriptor; } getChildContextDescriptor(propName: string): PropDescriptor { let propDescriptor = this.#childContext.get(propName); + if (!propDescriptor) { this.#childContext.set(propName, (propDescriptor = {})); } + return propDescriptor; } @@ -225,6 +231,7 @@ export default class Documentation { if (this.#composes.size > 0) { obj.composes = Array.from(this.#composes); } + return obj; } } diff --git a/src/FileState.ts b/src/FileState.ts index a306ec561f1..56696681b45 100644 --- a/src/FileState.ts +++ b/src/FileState.ts @@ -28,7 +28,9 @@ export default class FileState { Error: new (message?: string) => E, ): E & { node: Node } => { const err = new Error(msg); + (err as E & { node: Node }).node = node; + return err as E & { node: Node }; }, }; diff --git a/src/__tests__/main-test.ts b/src/__tests__/main-test.ts index c51f5691d8f..e3fcd17d4c9 100644 --- a/src/__tests__/main-test.ts +++ b/src/__tests__/main-test.ts @@ -7,6 +7,7 @@ describe('main', () => { function test(source: string) { it('parses with default resolver/handlers', () => { const docs = parse(source); + expect(docs).toMatchSnapshot(); }); @@ -14,6 +15,7 @@ describe('main', () => { const docs = parse(source, undefined, [ handlers.componentDocblockHandler, ]); + expect(docs).toMatchSnapshot(); }); } @@ -196,12 +198,14 @@ describe('main', () => { describe('fixtures', () => { const fixturePath = path.join(__dirname, 'fixtures'); const fileNames = fs.readdirSync(fixturePath); + for (let i = 0; i < fileNames.length; i++) { const filePath = path.join(fixturePath, fileNames[i]); const fileContent = fs.readFileSync(filePath, 'utf8'); it(`processes component "${fileNames[i]}" without errors`, () => { let result; + expect(() => { result = parse( fileContent, diff --git a/src/__tests__/parse-test.ts b/src/__tests__/parse-test.ts index 114c2699a88..8f6eafb7a92 100644 --- a/src/__tests__/parse-test.ts +++ b/src/__tests__/parse-test.ts @@ -9,6 +9,7 @@ describe('parse', () => { const path = testParse.expression('{foo: "bar"}'); const resolver = jest.fn(() => [path]); const handler = jest.fn(); + parse('//empty', resolver, [handler], noopImporter); expect(resolver).toBeCalled(); @@ -17,6 +18,7 @@ describe('parse', () => { it('errors if component definition is not found', () => { const resolver = jest.fn(() => []); + expect(() => parse('//empty', resolver, [], noopImporter)).toThrowError( ERROR_MISSING_DEFINITION, ); diff --git a/src/handlers/__tests__/codeTypeHandler-test.ts b/src/handlers/__tests__/codeTypeHandler-test.ts index c666bbb0d17..524151b5b91 100644 --- a/src/handlers/__tests__/codeTypeHandler-test.ts +++ b/src/handlers/__tests__/codeTypeHandler-test.ts @@ -410,6 +410,7 @@ describe('codeTypeHandler', () => { type Props = { foo: string }; React.forwardRef((props: Props, ref) =>
{props.foo}
); `; + codeTypeHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toEqual({ foo: { @@ -427,6 +428,7 @@ describe('codeTypeHandler', () => { const ComponentImpl = (props: Props, ref) =>
{props.foo}
; React.forwardRef(ComponentImpl); `; + codeTypeHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toEqual({ foo: { @@ -444,6 +446,7 @@ describe('codeTypeHandler', () => { let Component = (props: Props, ref) =>
{props.foo}
; Component = React.forwardRef(Component); `; + codeTypeHandler( documentation, parse.expressionLast(src).get('right') as NodePath, diff --git a/src/handlers/__tests__/componentMethodsHandler-test.ts b/src/handlers/__tests__/componentMethodsHandler-test.ts index a56994d6dfd..278be7b2fb9 100644 --- a/src/handlers/__tests__/componentMethodsHandler-test.ts +++ b/src/handlers/__tests__/componentMethodsHandler-test.ts @@ -311,6 +311,7 @@ describe('componentMethodsHandler', () => { const definition = parse .statement(src) .get('expression') as NodePath; + componentMethodsHandler(documentation, definition); expect(documentation.methods).toEqual([]); }); diff --git a/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts b/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts index de68b2ff01c..fd88d92f57d 100644 --- a/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts +++ b/src/handlers/__tests__/componentMethodsJsDocHandler-test.ts @@ -26,6 +26,7 @@ describe('componentMethodsJsDocHandler', () => { ], }, ]; + documentation.set('methods', methods); componentMethodsJsDocHandler(documentation, {} as NodePath); expect(documentation.get('methods')).toEqual(methods); diff --git a/src/handlers/__tests__/defaultPropsHandler-test.ts b/src/handlers/__tests__/defaultPropsHandler-test.ts index 73b9779bbe4..eab08866fd3 100644 --- a/src/handlers/__tests__/defaultPropsHandler-test.ts +++ b/src/handlers/__tests__/defaultPropsHandler-test.ts @@ -16,6 +16,7 @@ jest.mock('../../Documentation'); describe('defaultPropsHandler', () => { let documentation: Documentation & DocumentationMock; + beforeEach(() => { documentation = new Documentation() as Documentation & DocumentationMock; }); @@ -74,6 +75,7 @@ describe('defaultPropsHandler', () => { } } `; + defaultPropsHandler( documentation, parse.expression(src), @@ -91,6 +93,7 @@ describe('defaultPropsHandler', () => { } } `; + defaultPropsHandler( documentation, parse.expression(src), @@ -112,6 +115,7 @@ describe('defaultPropsHandler', () => { getDefaultProps: getDefaultProps }) `; + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -124,6 +128,7 @@ describe('defaultPropsHandler', () => { getDefaultProps: getDefaultProps }) `; + defaultPropsHandler( documentation, parse.expressionLast(src, mockImporter), @@ -142,6 +147,7 @@ describe('defaultPropsHandler', () => { } } `; + defaultPropsHandler( documentation, parse.expression(src), @@ -161,6 +167,7 @@ describe('defaultPropsHandler', () => { } }) `; + defaultPropsHandler( documentation, parse.expressionLast(src, mockImporter), @@ -179,6 +186,7 @@ describe('defaultPropsHandler', () => { } }) `; + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -195,6 +203,7 @@ describe('defaultPropsHandler', () => { } }) `; + defaultPropsHandler( documentation, parse.expressionLast(src, mockImporter), @@ -215,6 +224,7 @@ describe('defaultPropsHandler', () => { } }) `; + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -231,6 +241,7 @@ describe('defaultPropsHandler', () => { } }) `; + defaultPropsHandler( documentation, parse.expressionLast(src, mockImporter), @@ -251,6 +262,7 @@ describe('defaultPropsHandler', () => { }; } `; + defaultPropsHandler( documentation, parse.statement(src), @@ -268,6 +280,7 @@ describe('defaultPropsHandler', () => { } } `; + defaultPropsHandler( documentation, parse.statement(src), @@ -282,6 +295,7 @@ describe('defaultPropsHandler', () => { static defaultProps = defaultProps; } `; + defaultPropsHandler( documentation, parse.statementLast(src, mockImporter), @@ -300,6 +314,7 @@ describe('defaultPropsHandler', () => { }; } `; + defaultPropsHandler(documentation, parse.statementLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -314,6 +329,7 @@ describe('defaultPropsHandler', () => { }; } `; + defaultPropsHandler( documentation, parse.statementLast(src, mockImporter), @@ -331,6 +347,7 @@ describe('defaultPropsHandler', () => { }; } `; + defaultPropsHandler(documentation, parse.statementLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -345,6 +362,7 @@ describe('defaultPropsHandler', () => { }; } `; + defaultPropsHandler( documentation, parse.statementLast(src, mockImporter), @@ -364,6 +382,7 @@ describe('defaultPropsHandler', () => { abc: {xyz: abc.def, 123: 42} }; }`; + defaultPropsHandler( documentation, parse @@ -380,6 +399,7 @@ describe('defaultPropsHandler', () => { static defaultProps = defaultProps; } `; + defaultPropsHandler( documentation, parse @@ -402,6 +422,7 @@ describe('defaultPropsHandler', () => { } `; const definition = parse.expression(src); + expect(() => defaultPropsHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -422,6 +443,7 @@ describe('defaultPropsHandler', () => { src, mockImporter, ); + expect(() => defaultPropsHandler(documentation, definition)).not.toThrow(); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -436,6 +458,7 @@ describe('defaultPropsHandler', () => { abc = {xyz: abc.def, 123: 42} }) =>
`; + defaultPropsHandler(documentation, parse.expressionLast(src)); expect(documentation.descriptors).toMatchSnapshot(); }); @@ -447,6 +470,7 @@ describe('defaultPropsHandler', () => { bar = baz, }) =>
`; + defaultPropsHandler( documentation, parse.expressionLast(src, mockImporter), @@ -464,6 +488,7 @@ describe('defaultPropsHandler', () => { }) =>
Foo.defaultProps = { abc: {xyz: abc.def, 123: 42} }; `; + defaultPropsHandler( documentation, parse @@ -481,6 +506,7 @@ describe('defaultPropsHandler', () => { }) =>
Foo.defaultProps = other; `; + defaultPropsHandler( documentation, parse @@ -496,6 +522,7 @@ describe('defaultPropsHandler', () => { var Foo = (props) =>
Foo.defaultProps = { foo: "bar", ...other }; `; + defaultPropsHandler( documentation, parse @@ -511,6 +538,7 @@ describe('defaultPropsHandler', () => { var Foo = (props) =>
Foo.defaultProps = { foo: "bar", ...other }; `; + defaultPropsHandler( documentation, parse @@ -529,6 +557,7 @@ describe('defaultPropsHandler', () => { abc: defg = {xyz: abc.def, 123: 42} }) =>
`; + defaultPropsHandler( documentation, parse.expressionLast(src), @@ -543,6 +572,7 @@ describe('defaultPropsHandler', () => { foo: bar = baz, }) =>
`; + defaultPropsHandler( documentation, parse.expressionLast(src, mockImporter), @@ -558,6 +588,7 @@ describe('defaultPropsHandler', () => { foo = ImportedComponent, }) =>
`; + defaultPropsHandler( documentation, parse.expressionLast(src), @@ -582,6 +613,7 @@ describe('defaultPropsHandler', () => { import React from 'react'; React.forwardRef(({ foo = 'bar' }, ref) =>
{foo}
); `; + defaultPropsHandler( documentation, parse.expressionLast(src), @@ -595,6 +627,7 @@ describe('defaultPropsHandler', () => { import React from 'react'; React.forwardRef(({ bar = baz }, ref) =>
{bar}
); `; + defaultPropsHandler( documentation, parse.expressionLast(src, mockImporter), @@ -608,6 +641,7 @@ describe('defaultPropsHandler', () => { const Component = React.forwardRef(({ foo }, ref) =>
{foo}
); Component.defaultProps = { foo: 'baz' }; `; + defaultPropsHandler( documentation, parse @@ -624,6 +658,7 @@ describe('defaultPropsHandler', () => { const Component = React.forwardRef(({ bar }, ref) =>
{bar}
); Component.defaultProps = other; `; + defaultPropsHandler( documentation, parse @@ -639,6 +674,7 @@ describe('defaultPropsHandler', () => { const ComponentImpl = ({ foo = 'bar' }, ref) =>
{foo}
; React.forwardRef(ComponentImpl); `; + defaultPropsHandler( documentation, parse.expressionLast(src), @@ -653,6 +689,7 @@ describe('defaultPropsHandler', () => { const ComponentImpl = ({ bar = baz }, ref) =>
{bar}
; React.forwardRef(ComponentImpl); `; + defaultPropsHandler( documentation, parse.expressionLast(src, mockImporter), diff --git a/src/handlers/__tests__/displayNameHandler-test.ts b/src/handlers/__tests__/displayNameHandler-test.ts index 88c2bb3850a..d81394ca6ea 100644 --- a/src/handlers/__tests__/displayNameHandler-test.ts +++ b/src/handlers/__tests__/displayNameHandler-test.ts @@ -43,6 +43,7 @@ describe('defaultPropsHandler', () => { const definition = parse.expression( '{displayName: "FooBar"}', ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBar'); }); @@ -53,6 +54,7 @@ describe('defaultPropsHandler', () => { ({displayName: foobarbaz});`, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -62,6 +64,7 @@ describe('defaultPropsHandler', () => { `var name = 'abc'; ({displayName: name})`, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('abc'); }); @@ -73,6 +76,7 @@ describe('defaultPropsHandler', () => { ({displayName: name})`, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -83,6 +87,7 @@ describe('defaultPropsHandler', () => { ({displayName: foo.bar});`, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); @@ -91,6 +96,7 @@ describe('defaultPropsHandler', () => { const definition = parse.expression( '{displayName: foo.bar}', ); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).not.toBeDefined(); }); @@ -98,6 +104,7 @@ describe('defaultPropsHandler', () => { describe('ClassDeclaration', () => { it('considers the class name', () => { const definition = parse.statement(`class Foo {}`); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -106,6 +113,7 @@ describe('defaultPropsHandler', () => { const definition = parse .statement(`export default class {}`) .get('declaration') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBeUndefined(); }); @@ -117,6 +125,7 @@ describe('defaultPropsHandler', () => { } var name = 'xyz'; `); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('xyz'); }); @@ -132,6 +141,7 @@ describe('defaultPropsHandler', () => { `, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -146,6 +156,7 @@ describe('defaultPropsHandler', () => { `, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -156,6 +167,7 @@ describe('defaultPropsHandler', () => { static displayName = foo.bar; } `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBeUndefined(); }); @@ -170,6 +182,7 @@ describe('defaultPropsHandler', () => { `, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('foo'); }); @@ -180,6 +193,7 @@ describe('defaultPropsHandler', () => { static displayName = 'foo'; } `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('foo'); }); @@ -192,6 +206,7 @@ describe('defaultPropsHandler', () => { } } `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('foo'); }); @@ -204,6 +219,7 @@ describe('defaultPropsHandler', () => { } } `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('foo'); }); @@ -217,6 +233,7 @@ describe('defaultPropsHandler', () => { return 'foo'; } `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('foo'); }); @@ -230,6 +247,7 @@ describe('defaultPropsHandler', () => { } const abc = 'bar'; `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('bar'); }); @@ -246,6 +264,7 @@ describe('defaultPropsHandler', () => { `, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -262,6 +281,7 @@ describe('defaultPropsHandler', () => { `, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); @@ -271,6 +291,7 @@ describe('defaultPropsHandler', () => { it('considers the function name', () => { const definition = parse.statement('function Foo () {}'); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -279,6 +300,7 @@ describe('defaultPropsHandler', () => { const definition = parse .statement(`export default function () {}`) .get('declaration') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBeUndefined(); }); @@ -288,6 +310,7 @@ describe('defaultPropsHandler', () => { function Foo () {} Foo.displayName = 'Bar'; `); + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); @@ -298,6 +321,7 @@ describe('defaultPropsHandler', () => { Foo.displayName = bar; var bar = 'Bar'; `); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('Bar'); }); @@ -311,6 +335,7 @@ describe('defaultPropsHandler', () => { `, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -324,6 +349,7 @@ describe('defaultPropsHandler', () => { `, mockImporter, ); + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); @@ -334,6 +360,7 @@ describe('defaultPropsHandler', () => { const definition = parse .statement('var Foo = function () {};') .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -342,6 +369,7 @@ describe('defaultPropsHandler', () => { const definition = parse .statement('Foo = function () {};') .get('expression.right') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -355,6 +383,7 @@ describe('defaultPropsHandler', () => { `, ) .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); @@ -369,6 +398,7 @@ describe('defaultPropsHandler', () => { `, ) .get('declarations.0.init') as NodePath; + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('Bar'); }); @@ -384,6 +414,7 @@ describe('defaultPropsHandler', () => { mockImporter, ) .get('declarations.0.init') as NodePath; + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -399,6 +430,7 @@ describe('defaultPropsHandler', () => { mockImporter, ) .get('declarations.0.init') as NodePath; + displayNameHandler(documentation, definition); expect(documentation.displayName).toBe('baz'); }); @@ -409,6 +441,7 @@ describe('defaultPropsHandler', () => { const definition = parse .statement('var Foo = () => {};') .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -419,6 +452,7 @@ describe('defaultPropsHandler', () => { .get( 'declarations.0.init.arguments.0', ) as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -432,6 +466,7 @@ describe('defaultPropsHandler', () => { `, ) .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -440,6 +475,7 @@ describe('defaultPropsHandler', () => { const definition = parse .statement('Foo = () => {};') .get('expression.right') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -450,6 +486,7 @@ describe('defaultPropsHandler', () => { .get( 'expression.right.arguments.0', ) as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -463,6 +500,7 @@ describe('defaultPropsHandler', () => { `, ) .get('expression.right') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Foo'); }); @@ -476,6 +514,7 @@ describe('defaultPropsHandler', () => { `, ) .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); @@ -490,6 +529,7 @@ describe('defaultPropsHandler', () => { `, ) .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); @@ -505,6 +545,7 @@ describe('defaultPropsHandler', () => { mockImporter, ) .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -520,6 +561,7 @@ describe('defaultPropsHandler', () => { mockImporter, ) .get('declarations.0.init') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('baz'); }); @@ -535,6 +577,7 @@ describe('defaultPropsHandler', () => { .get( 'declarations.0.init.arguments.0', ) as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); @@ -551,6 +594,7 @@ describe('defaultPropsHandler', () => { .get( 'declarations.0.init.arguments.0', ) as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('Bar'); }); @@ -568,6 +612,7 @@ describe('defaultPropsHandler', () => { .get( 'declarations.0.init.arguments.0', ) as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('FooBarBaz'); }); @@ -585,6 +630,7 @@ describe('defaultPropsHandler', () => { .get( 'declarations.0.init.arguments.0', ) as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).toBe('baz'); }); @@ -593,6 +639,7 @@ describe('defaultPropsHandler', () => { const definition = parse .statement('Foo.Bar = () => {};') .get('expression.right') as NodePath; + expect(() => displayNameHandler(documentation, definition)).not.toThrow(); expect(documentation.displayName).not.toBeDefined(); }); diff --git a/src/handlers/__tests__/propDocblockHandler-test.ts b/src/handlers/__tests__/propDocblockHandler-test.ts index 3449d1b0f4a..8c8ad175834 100644 --- a/src/handlers/__tests__/propDocblockHandler-test.ts +++ b/src/handlers/__tests__/propDocblockHandler-test.ts @@ -260,6 +260,7 @@ describe('propDocBlockHandler', () => { describe('does not error if propTypes cannot be found', () => { it('ObjectExpression', () => { const definition = parse.expression('{fooBar: 42}'); + expect(() => propDocBlockHandler(documentation, definition), ).not.toThrow(); @@ -267,6 +268,7 @@ describe('propDocBlockHandler', () => { it('ClassDeclaration', () => { const definition = parse.statement('class Foo {}'); + expect(() => propDocBlockHandler(documentation, definition), ).not.toThrow(); diff --git a/src/handlers/__tests__/propTypeCompositionHandler-test.ts b/src/handlers/__tests__/propTypeCompositionHandler-test.ts index 5b5c5202ef3..80ad32a01be 100644 --- a/src/handlers/__tests__/propTypeCompositionHandler-test.ts +++ b/src/handlers/__tests__/propTypeCompositionHandler-test.ts @@ -155,6 +155,7 @@ describe('propTypeCompositionHandler', () => { describe('does not error if propTypes cannot be found', () => { it('ObjectExpression', () => { const definition = parse.expression('{fooBar: 42}'); + expect(() => propTypeCompositionHandler(documentation, definition), ).not.toThrow(); @@ -162,6 +163,7 @@ describe('propTypeCompositionHandler', () => { it('ClassDeclaration', () => { const definition = parse.statement('class Foo {}'); + expect(() => propTypeCompositionHandler(documentation, definition), ).not.toThrow(); diff --git a/src/handlers/__tests__/propTypeHandler-test.ts b/src/handlers/__tests__/propTypeHandler-test.ts index e568758b6d9..b4e41438fb6 100644 --- a/src/handlers/__tests__/propTypeHandler-test.ts +++ b/src/handlers/__tests__/propTypeHandler-test.ts @@ -332,22 +332,26 @@ describe('propTypeHandler', () => { describe('does not error if propTypes cannot be found', () => { it('ObjectExpression', () => { const definition = parse.expression('{fooBar: 42}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); }); it('ClassDeclaration', () => { const definition = parse.statement('class Foo {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); }); it('FunctionDeclaration', () => { const definition = parse.statement('function Foo() {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); }); it('ArrowFunctionExpression', () => { const definition = parse.expression('() => {}'); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); }); }); @@ -357,6 +361,7 @@ describe('propTypeHandler', () => { const definition = parse.expression( '{propTypes: Foo.propTypes}', ); + expect(() => propTypeHandler(documentation, definition)).not.toThrow(); }); }); diff --git a/src/handlers/codeTypeHandler.ts b/src/handlers/codeTypeHandler.ts index 648e8e97136..f59bd10ef07 100644 --- a/src/handlers/codeTypeHandler.ts +++ b/src/handlers/codeTypeHandler.ts @@ -33,11 +33,13 @@ function setPropDescriptor( }, typeParams, ); + return; } // TODO what about other types here const id = argument.get('id') as NodePath; + if (!id.hasNode() || !id.isIdentifier()) { return; } @@ -45,6 +47,7 @@ function setPropDescriptor( if (resolvedPath && resolvedPath.isTypeAlias()) { const right = resolvedPath.get('right'); + applyToTypeProperties( documentation, right, @@ -59,9 +62,11 @@ function setPropDescriptor( } else if (path.isObjectTypeProperty()) { const type = getFlowType(path.get('value'), typeParams); const propName = getPropertyName(path); + if (!propName) return; const propDescriptor = documentation.getPropDescriptor(propName); + propDescriptor.required = !path.node.optional; propDescriptor.flowType = type; @@ -71,15 +76,18 @@ function setPropDescriptor( setPropDescription(documentation, path); } else if (path.isTSPropertySignature()) { const typeAnnotation = path.get('typeAnnotation'); + if (!typeAnnotation.hasNode()) { return; } const type = getTSType(typeAnnotation, typeParams); const propName = getPropertyName(path); + if (!propName) return; const propDescriptor = documentation.getPropDescriptor(propName); + propDescriptor.required = !path.node.optional; propDescriptor.tsType = type; diff --git a/src/handlers/componentDocblockHandler.ts b/src/handlers/componentDocblockHandler.ts index c3086e46519..4d799162747 100644 --- a/src/handlers/componentDocblockHandler.ts +++ b/src/handlers/componentDocblockHandler.ts @@ -22,6 +22,7 @@ function getDocblockFromComponent(path: NodePath): string | null { if (description == null) { // Find parent statement (e.g. var Component = React.createClass();) let searchPath: NodePath | null = path; + while (searchPath && !searchPath.isStatement()) { searchPath = searchPath.parentPath; } @@ -41,10 +42,12 @@ function getDocblockFromComponent(path: NodePath): string | null { ? path.get('arguments')[0] : path; const inner = resolveToValue(searchPath); + if (inner.node !== path.node) { return getDocblockFromComponent(inner); } } + return description; } diff --git a/src/handlers/componentMethodsHandler.ts b/src/handlers/componentMethodsHandler.ts index 3ec48d8e447..b18fb85b1fa 100644 --- a/src/handlers/componentMethodsHandler.ts +++ b/src/handlers/componentMethodsHandler.ts @@ -30,6 +30,7 @@ function isMethod(path: NodePath): boolean { (path.isClassProperty() || path.isObjectProperty()) ) { const value = resolveToValue(path.get('value') as NodePath); + isProbablyMethod = value.isFunction(); } @@ -52,6 +53,7 @@ function findAssignedMethods( traverseShallow(path, { AssignmentExpression(assignmentPath) { const node = assignmentPath.node; + if ( match(node.left, { type: 'MemberExpression', @@ -79,6 +81,7 @@ const componentMethodsHandler: Handler = function ( ): void { // Extract all methods from the class or object. let methodPaths: Array<{ path: MethodNodePath; isStatic?: boolean }> = []; + if (isReactComponentClass(componentDefinition)) { methodPaths = ( componentDefinition @@ -95,6 +98,7 @@ const componentMethodsHandler: Handler = function ( // Add the statics object properties. const statics = getMemberValuePath(componentDefinition, 'statics'); + if (statics && statics.isObjectExpression()) { statics.get('properties').forEach(property => { if (isMethod(property)) { diff --git a/src/handlers/componentMethodsJsDocHandler.ts b/src/handlers/componentMethodsJsDocHandler.ts index bf556ba17bc..a1d672547cc 100644 --- a/src/handlers/componentMethodsJsDocHandler.ts +++ b/src/handlers/componentMethodsJsDocHandler.ts @@ -13,11 +13,13 @@ function merge(obj1: T, obj2: U): (T & U) | null { const merged: Record = { ...(obj1 as Record), }; + for (const prop in obj2 as Record) { if (obj2[prop] != null) { merged[prop] = obj2[prop]; } } + return merged as T & U; } /** @@ -28,6 +30,7 @@ const componentMethodsJsDocHandler: Handler = function ( documentation: Documentation, ): void { let methods = documentation.get('methods') as MethodDescriptor[] | null; + if (!methods) { return; } @@ -43,6 +46,7 @@ const componentMethodsJsDocHandler: Handler = function ( const returns = merge(jsDoc.returns, method.returns); const params = method.params.map(param => { const jsDocParam = jsDoc.params.find(p => p.name === param.name); + return merge(jsDocParam, param); }); diff --git a/src/handlers/defaultPropsHandler.ts b/src/handlers/defaultPropsHandler.ts index 97f5b747348..fa59ce2a4d3 100644 --- a/src/handlers/defaultPropsHandler.ts +++ b/src/handlers/defaultPropsHandler.ts @@ -22,6 +22,7 @@ function getDefaultValue(path: NodePath): DefaultValueDescriptor | null { let defaultValue: string | undefined; let resolvedPath = path; let valuePath = path; + if (path.isBooleanLiteral()) { defaultValue = `${path.node.value}`; } else if (path.isNullLiteral()) { @@ -73,6 +74,7 @@ function getDefaultPropsPath( componentDefinition, 'defaultProps', ); + if (!defaultPropsPath) { return null; } @@ -92,10 +94,12 @@ function getDefaultPropsPath( // an object literal. const returnValue = resolveFunctionDefinitionToReturnValue(defaultPropsPath); + if (returnValue && returnValue.isObjectExpression()) { defaultPropsPath = returnValue; } } + return defaultPropsPath; } @@ -150,6 +154,7 @@ const defaultPropsHandler: Handler = function ( ): void { let statelessProps: NodePath | null = null; const defaultPropsPath = getDefaultPropsPath(componentDefinition); + /** * function, lazy, memo, forwardRef etc components can resolve default props as well */ diff --git a/src/handlers/displayNameHandler.ts b/src/handlers/displayNameHandler.ts index c61901ef811..6f18572a722 100644 --- a/src/handlers/displayNameHandler.ts +++ b/src/handlers/displayNameHandler.ts @@ -17,6 +17,7 @@ const displayNameHandler: Handler = function ( componentDefinition, 'displayName', ); + if (!displayNamePath) { // Function and class declarations need special treatment. The name of the // function / class is the displayName @@ -35,23 +36,28 @@ const displayNameHandler: Handler = function ( isReactForwardRefCall(componentDefinition) ) { let currentPath: NodePath = componentDefinition; + while (currentPath.parentPath) { if (currentPath.parentPath.isVariableDeclarator()) { documentation.set( 'displayName', getNameOrValue(currentPath.parentPath.get('id')), ); + return; } else if (currentPath.parentPath.isAssignmentExpression()) { const leftPath = currentPath.parentPath.get('left'); + if (leftPath.isIdentifier() || leftPath.isLiteral()) { documentation.set('displayName', getNameOrValue(leftPath)); + return; } } currentPath = currentPath.parentPath; } } + return; } displayNamePath = resolveToValue(displayNamePath); diff --git a/src/handlers/propDocBlockHandler.ts b/src/handlers/propDocBlockHandler.ts index b6d219eff7f..05c8ac9b418 100644 --- a/src/handlers/propDocBlockHandler.ts +++ b/src/handlers/propDocBlockHandler.ts @@ -18,6 +18,7 @@ function resolveDocumentation( path.get('properties').forEach(propertyPath => { if (propertyPath.isSpreadElement()) { const resolvedValuePath = resolveToValue(propertyPath.get('argument')); + resolveDocumentation(documentation, resolvedValuePath); } else if ( propertyPath.isObjectProperty() || @@ -36,6 +37,7 @@ const propDocBlockHandler: Handler = function ( componentDefinition, 'propTypes', ); + if (!propTypesPath) { return; } diff --git a/src/handlers/propTypeCompositionHandler.ts b/src/handlers/propTypeCompositionHandler.ts index aab6fc1404b..7c5aeb20910 100644 --- a/src/handlers/propTypeCompositionHandler.ts +++ b/src/handlers/propTypeCompositionHandler.ts @@ -13,6 +13,7 @@ import type { ComponentNode } from '../resolver'; */ function amendComposes(documentation: Documentation, path: NodePath): void { const moduleName = resolveToModule(path); + if (moduleName) { documentation.addComposes(moduleName); } @@ -40,6 +41,7 @@ const propTypeCompositionHandler: Handler = function ( componentDefinition, 'propTypes', ); + if (!propTypesPath) { return; } @@ -50,6 +52,7 @@ const propTypeCompositionHandler: Handler = function ( if (propTypesPath.isObjectExpression()) { processObjectExpression(documentation, propTypesPath); + return; } diff --git a/src/handlers/propTypeHandler.ts b/src/handlers/propTypeHandler.ts index aacb0d10521..122189ab23f 100644 --- a/src/handlers/propTypeHandler.ts +++ b/src/handlers/propTypeHandler.ts @@ -15,9 +15,11 @@ import type { ComponentNode } from '../resolver'; function isPropTypesExpression(path: NodePath): boolean { const moduleName = resolveToModule(path); + if (moduleName) { return isReactModuleName(moduleName) || moduleName === 'ReactPropTypes'; } + return false; } @@ -32,6 +34,7 @@ function amendPropTypes( path.get('properties').forEach(propertyPath => { if (propertyPath.isObjectProperty()) { const propName = getPropertyName(propertyPath); + if (!propName) return; const propDescriptor = getDescriptor(propName); @@ -48,6 +51,7 @@ function amendPropTypes( } if (propertyPath.isSpreadElement()) { const resolvedValuePath = resolveToValue(propertyPath.get('argument')); + if (resolvedValuePath.isObjectExpression()) { // normal object literal amendPropTypes(getDescriptor, resolvedValuePath); @@ -65,6 +69,7 @@ function getPropTypeHandler(propName: string): Handler { componentDefinition, propName, ); + if (!propTypesPath) { return; } @@ -73,6 +78,7 @@ function getPropTypeHandler(propName: string): Handler { return; } let getDescriptor; + switch (propName) { case 'childContextTypes': getDescriptor = documentation.getChildContextDescriptor; diff --git a/src/importer/makeFsImporter.ts b/src/importer/makeFsImporter.ts index f4a00063245..eb33494aa53 100644 --- a/src/importer/makeFsImporter.ts +++ b/src/importer/makeFsImporter.ts @@ -34,6 +34,7 @@ export default function makeFsImporter( // Also never traverse into react itself. const source = path.node.source?.value; const options = state.opts; + if (!source || !options || !options.filename || source === 'react') { return null; } @@ -56,9 +57,11 @@ export default function makeFsImporter( seen.add(resolvedSource); let nextState = cache.get(resolvedSource); + if (!nextState) { // Read and parse the code const src = fs.readFileSync(resolvedSource, 'utf8'); + nextState = state.parse(src); cache.set(resolvedSource, nextState); @@ -78,6 +81,7 @@ export default function makeFsImporter( traverseShallow(state.path, { ExportNamedDeclaration(path) { const { declaration, specifiers, source } = path.node; + if ( declaration && 'id' in declaration && @@ -95,6 +99,7 @@ export default function makeFsImporter( .get('declarations') .forEach(declPath => { const id = declPath.get('id'); + // TODO: ArrayPattern and ObjectPattern if ( id.isIdentifier() && @@ -117,6 +122,7 @@ export default function makeFsImporter( 'local' in specifierPath.node ? specifierPath.node.local.name : 'default'; + resultPath = resolveImportedValue(path, local, state, seen); } else if ('local' in specifierPath.node) { resultPath = specifierPath.get('local') as NodePath; @@ -136,6 +142,7 @@ export default function makeFsImporter( }, ExportAllDeclaration(path) { const resolvedPath = resolveImportedValue(path, name, state, seen); + if (resolvedPath) { resultPath = resolvedPath; } diff --git a/src/parse.ts b/src/parse.ts index 6a8c7c4e1b9..760b3d72f48 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -18,7 +18,9 @@ function executeHandlers( return componentDefinitions.map( (componentDefinition): DocumentationObject => { const documentation = new Documentation(); + handlers.forEach(handler => handler(documentation, componentDefinition)); + return postProcessDocumentation(documentation.toObject()); }, ); @@ -63,6 +65,7 @@ export default function parse( if (componentDefinitions.length === 0) { throw new Error(ERROR_MISSING_DEFINITION); } + return executeHandlers(handlers, componentDefinitions); } diff --git a/src/resolver/__tests__/findAllComponentDefinitions-test.ts b/src/resolver/__tests__/findAllComponentDefinitions-test.ts index 22c74f0850d..0f966c9a727 100644 --- a/src/resolver/__tests__/findAllComponentDefinitions-test.ts +++ b/src/resolver/__tests__/findAllComponentDefinitions-test.ts @@ -53,6 +53,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); expect(result[0] instanceof NodePath).toBe(true); @@ -68,6 +69,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); expect(result[0] instanceof NodePath).toBe(true); @@ -82,6 +84,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); }); @@ -94,6 +97,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(0); }); @@ -107,6 +111,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); }); @@ -120,6 +125,7 @@ describe('findAllComponentDefinitions', () => { `; let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(2); @@ -148,6 +154,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(4); }); @@ -161,6 +168,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(2); }); @@ -172,6 +180,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); }); @@ -183,6 +192,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(0); }); @@ -215,6 +225,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(7); }); @@ -230,6 +241,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(3); }); @@ -242,6 +254,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); }); @@ -253,6 +266,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(0); }); @@ -273,6 +287,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); expect(result[0].node.type).toEqual('CallExpression'); @@ -292,6 +307,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); expect(result[0].node.type).toEqual('CallExpression'); @@ -305,6 +321,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); expect(result[0].node.type).toEqual('CallExpression'); @@ -331,6 +348,7 @@ describe('findAllComponentDefinitions', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(1); expect(result[0].node.type).toEqual('ArrowFunctionExpression'); diff --git a/src/resolver/__tests__/findAllExportedComponentDefinitions-test.ts b/src/resolver/__tests__/findAllExportedComponentDefinitions-test.ts index 7f300894669..d0a2e9de83b 100644 --- a/src/resolver/__tests__/findAllExportedComponentDefinitions-test.ts +++ b/src/resolver/__tests__/findAllExportedComponentDefinitions-test.ts @@ -1,6 +1,5 @@ import type { NodePath } from '@babel/traverse'; import { parse, noopImporter, makeMockImporter } from '../../../tests/utils'; - import findAllExportedComponentDefinitions from '../findAllExportedComponentDefinitions'; describe('findAllExportedComponentDefinitions', () => { diff --git a/src/resolver/__tests__/findExportedComponentDefinition-test.ts b/src/resolver/__tests__/findExportedComponentDefinition-test.ts index 5ebb4e5cee4..e9a3f865ce9 100644 --- a/src/resolver/__tests__/findExportedComponentDefinition-test.ts +++ b/src/resolver/__tests__/findExportedComponentDefinition-test.ts @@ -58,6 +58,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -70,6 +71,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -82,6 +84,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -96,6 +99,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -112,6 +116,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -124,6 +129,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -136,6 +142,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(0); }); @@ -147,6 +154,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(0); }); @@ -161,6 +169,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -174,6 +183,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassExpression'); @@ -187,6 +197,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -199,6 +210,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -211,6 +223,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassExpression'); @@ -226,6 +239,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -238,6 +252,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -250,6 +265,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(0); }); @@ -261,6 +277,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -272,6 +289,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -288,6 +306,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -313,6 +332,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -326,6 +346,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -337,6 +358,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -352,6 +374,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -378,6 +401,7 @@ describe('findExportedComponentDefinition', () => { `; let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -402,6 +426,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -421,6 +446,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -432,6 +458,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -442,6 +469,7 @@ describe('findExportedComponentDefinition', () => { export var Component = React.createClass({}) export default React.createClass({}); `; + expect(() => findComponentsInSource(source)).toThrow(); }); @@ -452,6 +480,7 @@ describe('findExportedComponentDefinition', () => { export {Component}; export default React.createClass({}); `; + expect(() => findComponentsInSource(source)).toThrow(); }); @@ -463,6 +492,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -474,6 +504,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -488,6 +519,7 @@ describe('findExportedComponentDefinition', () => { `; let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -511,6 +543,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -524,6 +557,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -539,6 +573,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -550,6 +585,7 @@ describe('findExportedComponentDefinition', () => { export var Component = class extends React.Component {}; export default class ComponentB extends React.Component{}; `; + expect(() => findComponentsInSource(source)).toThrow(); source = ` @@ -569,6 +605,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -581,6 +618,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -597,6 +635,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -608,6 +647,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -621,6 +661,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -633,6 +674,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -664,6 +706,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -675,6 +718,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -688,6 +732,7 @@ describe('findExportedComponentDefinition', () => { Component = class extends React.Component {}; `; let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassExpression'); @@ -730,6 +775,7 @@ describe('findExportedComponentDefinition', () => { export var ComponentA = class extends React.Component {}; export var ComponentB = class extends React.Component {}; `; + expect(() => findComponentsInSource(source)).toThrow(); source = ` @@ -748,6 +794,7 @@ describe('findExportedComponentDefinition', () => { export var ComponentB = class extends React.Component {}; `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassExpression'); @@ -760,6 +807,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -774,6 +822,7 @@ describe('findExportedComponentDefinition', () => { Component = () =>
; `; let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ArrowFunctionExpression'); @@ -816,6 +865,7 @@ describe('findExportedComponentDefinition', () => { export var ComponentA = () =>
export var ComponentB = () =>
`; + expect(() => findComponentsInSource(source)).toThrow(); source = ` @@ -834,6 +884,7 @@ describe('findExportedComponentDefinition', () => { export var ComponentB = function() { return
; }; `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('FunctionExpression'); @@ -846,6 +897,7 @@ describe('findExportedComponentDefinition', () => { `; let result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ArrowFunctionExpression'); @@ -873,6 +925,7 @@ describe('findExportedComponentDefinition', () => { export {foo, Component} `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -886,6 +939,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -900,6 +954,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -924,6 +979,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -935,6 +991,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); }); @@ -949,6 +1006,7 @@ describe('findExportedComponentDefinition', () => { export {foo, Component}; `; let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassExpression'); @@ -996,6 +1054,7 @@ describe('findExportedComponentDefinition', () => { export {ComponentA}; `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassExpression'); @@ -1008,6 +1067,7 @@ describe('findExportedComponentDefinition', () => { `; const result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -1023,6 +1083,7 @@ describe('findExportedComponentDefinition', () => { export {foo, Component}; `; let result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('FunctionDeclaration'); @@ -1070,6 +1131,7 @@ describe('findExportedComponentDefinition', () => { export {ComponentA}; `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ArrowFunctionExpression'); @@ -1082,6 +1144,7 @@ describe('findExportedComponentDefinition', () => { `; let result = findComponentsInSource(source, mockImporter); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ArrowFunctionExpression'); @@ -1108,6 +1171,7 @@ describe('findExportedComponentDefinition', () => { export class Component extends React.Component {}; `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); @@ -1130,6 +1194,7 @@ describe('findExportedComponentDefinition', () => { export class ComponentB extends React.Component {}; `; const result = findComponentsInSource(source); + expect(Array.isArray(result)).toBe(true); expect(result).toHaveLength(1); expect(result[0].node.type).toBe('ClassDeclaration'); diff --git a/src/resolver/findAllComponentDefinitions.ts b/src/resolver/findAllComponentDefinitions.ts index b6c8d673784..ddc1efb29d8 100644 --- a/src/resolver/findAllComponentDefinitions.ts +++ b/src/resolver/findAllComponentDefinitions.ts @@ -22,6 +22,7 @@ const findAllComponentDefinitions: Resolver = function ( normalizeClassDefinition(path); definitions.add(path); } + return false; } @@ -29,6 +30,7 @@ const findAllComponentDefinitions: Resolver = function ( if (isStatelessComponent(path)) { definitions.add(path); } + return false; } @@ -46,6 +48,7 @@ const findAllComponentDefinitions: Resolver = function ( const inner = resolveToValue( path.get('arguments')[0], ) as NodePath; + definitions.delete(inner); definitions.add(path); @@ -53,6 +56,7 @@ const findAllComponentDefinitions: Resolver = function ( return path.skip(); } else if (isReactCreateClassCall(path)) { const resolvedPath = resolveToValue(path.get('arguments')[0]); + if (resolvedPath.isObjectExpression()) { definitions.add(resolvedPath); } diff --git a/src/resolver/findAllExportedComponentDefinitions.ts b/src/resolver/findAllExportedComponentDefinitions.ts index 995ef2a72ac..9c6aa377f20 100644 --- a/src/resolver/findAllExportedComponentDefinitions.ts +++ b/src/resolver/findAllExportedComponentDefinitions.ts @@ -43,14 +43,17 @@ const findExportedComponentDefinitions: Resolver = function ( acc.push(definition); } else { const resolved = resolveToValue(resolveHOC(definition)); + if (isComponentDefinition(resolved)) { acc.push(resolved); } } + return acc; }, [] as Array>) .forEach(definition => { const resolved = resolveComponentDefinition(definition); + if (resolved && components.indexOf(resolved) === -1) { components.push(resolved); } @@ -74,6 +77,7 @@ const findExportedComponentDefinitions: Resolver = function ( // Resolve the value of the right hand side. It should resolve to a call // expression, something like React.createClass let resolvedPath = resolveToValue(path.get('right')); + if (!isComponentDefinition(resolvedPath)) { resolvedPath = resolveToValue(resolveHOC(resolvedPath)); if (!isComponentDefinition(resolvedPath)) { @@ -81,9 +85,11 @@ const findExportedComponentDefinitions: Resolver = function ( } } const definition = resolveComponentDefinition(resolvedPath); + if (definition && components.indexOf(definition) === -1) { components.push(definition); } + return path.skip(); }, }); diff --git a/src/resolver/findExportedComponentDefinition.ts b/src/resolver/findExportedComponentDefinition.ts index 7bb79a24590..fce13a15132 100644 --- a/src/resolver/findExportedComponentDefinition.ts +++ b/src/resolver/findExportedComponentDefinition.ts @@ -46,10 +46,12 @@ const findExportedComponentDefinition: Resolver = function ( acc.push(definition); } else { const resolved = resolveToValue(resolveHOC(definition)); + if (isComponentDefinition(resolved)) { acc.push(resolved); } } + return acc; }, [] as Array>, @@ -63,9 +65,11 @@ const findExportedComponentDefinition: Resolver = function ( throw new Error(ERROR_MULTIPLE_DEFINITIONS); } const definition = resolveComponentDefinition(definitions[0]); + if (definition) { foundDefinition.push(definition); } + return path.skip(); } @@ -84,6 +88,7 @@ const findExportedComponentDefinition: Resolver = function ( // Resolve the value of the right hand side. It should resolve to a call // expression, something like React.createClass let resolvedPath = resolveToValue(path.get('right')); + if (!isComponentDefinition(resolvedPath)) { resolvedPath = resolveToValue(resolveHOC(resolvedPath)); if (!isComponentDefinition(resolvedPath)) { @@ -95,9 +100,11 @@ const findExportedComponentDefinition: Resolver = function ( throw new Error(ERROR_MULTIPLE_DEFINITIONS); } const definition = resolveComponentDefinition(resolvedPath); + if (definition) { foundDefinition.push(definition); } + return path.skip(); }, }); diff --git a/src/utils/__tests__/docblock-test.ts b/src/utils/__tests__/docblock-test.ts index e6cc2825423..50be859793c 100644 --- a/src/utils/__tests__/docblock-test.ts +++ b/src/utils/__tests__/docblock-test.ts @@ -38,6 +38,7 @@ describe('docblock', () => { it('gets the closest docblock of the given node', () => { const node = parse.statement(source.join('\n')); + expect(getDocblock(node)).toEqual(comment.join('\n')); }); @@ -48,15 +49,18 @@ describe('docblock', () => { '\u2029', '\u000D\u000A', // \r\n ]; + terminators.forEach(t => { it('can handle ' + escape(t) + ' as line terminator', () => { const node = parse.statement(source.join(t)); + expect(getDocblock(node)).toEqual(comment.join(t)); }); }); it('supports "short" docblocks', () => { const node = parse.statement('/** bar */\nfoo;'); + expect(getDocblock(node)).toEqual('bar'); }); }); diff --git a/src/utils/__tests__/getFlowType-test.ts b/src/utils/__tests__/getFlowType-test.ts index 78ccda78d7d..ab8ee70e499 100644 --- a/src/utils/__tests__/getFlowType-test.ts +++ b/src/utils/__tests__/getFlowType-test.ts @@ -91,6 +91,7 @@ describe('getFlowType', () => { .expression('x: ' + type) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: type }); }); }); @@ -103,6 +104,7 @@ describe('getFlowType', () => { .expression(`x: ${value}`) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'literal', value: `${value}`, @@ -115,6 +117,7 @@ describe('getFlowType', () => { .expression('x: xyz') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'xyz' }); }); @@ -132,6 +135,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'string', }); @@ -142,6 +146,7 @@ describe('getFlowType', () => { .expression('x: ?xyz') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'xyz', nullable: true, @@ -162,6 +167,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'string', nullable: true, @@ -173,6 +179,7 @@ describe('getFlowType', () => { .expression('x: ?number[]') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], @@ -186,6 +193,7 @@ describe('getFlowType', () => { .expression('x: (?number)[]') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number', nullable: true }], @@ -198,6 +206,7 @@ describe('getFlowType', () => { .expression('x: number[]') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], @@ -210,6 +219,7 @@ describe('getFlowType', () => { .expression('x: Array') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], @@ -231,6 +241,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'string' }], @@ -301,6 +312,7 @@ describe('getFlowType', () => { .expression('x: Array') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }, { name: 'xyz' }], @@ -323,6 +335,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }, { name: 'string' }], @@ -335,6 +348,7 @@ describe('getFlowType', () => { .expression('x: Class') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Class', elements: [{ name: 'Boolean' }], @@ -356,6 +370,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Class', elements: [{ name: 'string' }], @@ -368,6 +383,7 @@ describe('getFlowType', () => { .expression('x: Function') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Function', elements: [{ name: 'xyz' }], @@ -389,6 +405,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'Function', elements: [{ name: 'string' }], @@ -401,6 +418,7 @@ describe('getFlowType', () => { .expression('x: { a: string, b?: xyz }') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -419,6 +437,7 @@ describe('getFlowType', () => { .expression('x: { a: string, b: ?xyz }') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -448,6 +467,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -481,6 +501,7 @@ describe('getFlowType', () => { .expression('x: string | xyz | "foo" | void') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ @@ -507,6 +528,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ @@ -531,6 +553,7 @@ describe('getFlowType', () => { .expression('x: string & xyz & "foo" & void') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'intersection', elements: [ @@ -557,6 +580,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'intersection', elements: [ @@ -583,6 +607,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', @@ -611,6 +636,7 @@ describe('getFlowType', () => { .expression('x: (number, ?string) => boolean') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', @@ -630,6 +656,7 @@ describe('getFlowType', () => { .expression('x: string => boolean') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'function', @@ -648,6 +675,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -806,6 +834,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -854,6 +883,7 @@ describe('getFlowType', () => { ) .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -890,6 +920,7 @@ describe('getFlowType', () => { .expression('x: [string, number]') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'tuple', elements: [{ name: 'string' }, { name: 'number' }], @@ -902,6 +933,7 @@ describe('getFlowType', () => { .expression('x: [string, number] | [number, string]') .get('typeAnnotation') .get('typeAnnotation'); + expect(getFlowType(typePath)).toEqual({ name: 'union', elements: [ diff --git a/src/utils/__tests__/getMemberExpressionRoot-test.ts b/src/utils/__tests__/getMemberExpressionRoot-test.ts index 6c3a50e0d4e..08409240752 100644 --- a/src/utils/__tests__/getMemberExpressionRoot-test.ts +++ b/src/utils/__tests__/getMemberExpressionRoot-test.ts @@ -5,18 +5,21 @@ import getMemberExpressionRoot from '../getMemberExpressionRoot'; describe('getMemberExpressionRoot', () => { it('returns the root of a member expression', () => { const root = getMemberExpressionRoot(parse.expression('foo.bar.baz')); + expect(root).toEqualASTNode(parse.expression('foo')); }); it('returns the same path if identifier', () => { const id = parse.expression('foo'); const root = getMemberExpressionRoot(id); + expect(root).toEqualASTNode(id); }); it('returns the same path if literal', () => { const literal = parse.expression('1'); const root = getMemberExpressionRoot(literal); + expect(root).toEqualASTNode(literal); }); }); diff --git a/src/utils/__tests__/getMemberValuePath-test.ts b/src/utils/__tests__/getMemberValuePath-test.ts index 86d67ff358c..39a1e410775 100644 --- a/src/utils/__tests__/getMemberValuePath-test.ts +++ b/src/utils/__tests__/getMemberValuePath-test.ts @@ -74,6 +74,7 @@ describe('getMemberValuePath', () => { it('returns the result of getPropertyValuePath and getClassMemberValuePath', () => { const mockPath = parse.expression('42'); const mockPath2 = parse.expression('21'); + jest.mocked(getPropertyValuePath).mockReturnValue(mockPath); jest.mocked(getClassMemberValuePath).mockReturnValue(mockPath2); let path = parse.expression('{}'); diff --git a/src/utils/__tests__/getMethodDocumentation-test.ts b/src/utils/__tests__/getMethodDocumentation-test.ts index f4277534b6b..5e2e29cd91a 100644 --- a/src/utils/__tests__/getMethodDocumentation-test.ts +++ b/src/utils/__tests__/getMethodDocumentation-test.ts @@ -36,6 +36,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'hello', docblock: null, @@ -52,6 +53,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'hello', docblock: null, @@ -68,6 +70,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); @@ -78,6 +81,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); @@ -92,6 +96,7 @@ describe('getMethodDocumentation', () => { mockImporter, ); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'hello', docblock: null, @@ -113,6 +118,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'foo', docblock: "Don't use this!", @@ -132,6 +138,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual({ name: 'foo', docblock: "Don't use this!", @@ -150,6 +157,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); @@ -160,6 +168,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); @@ -170,6 +179,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); @@ -180,6 +190,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); @@ -194,6 +205,7 @@ describe('getMethodDocumentation', () => { mockImporter, ); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); @@ -215,6 +227,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual(methodModifiersDoc([])); }); @@ -225,6 +238,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodModifiersDoc(['static']), ); @@ -233,6 +247,7 @@ describe('getMethodDocumentation', () => { it('detects manually set static functions', () => { const def = parse.expression(`{ foo() {} }`); const method = def.get('properties')[0] as NodePath; + expect(getMethodDocumentation(method, { isStatic: true })).toEqual( methodModifiersDoc(['static']), ); @@ -245,6 +260,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodModifiersDoc(['generator']), ); @@ -257,6 +273,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodModifiersDoc(['async']), ); @@ -269,6 +286,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodModifiersDoc(['static', 'async']), ); @@ -293,6 +311,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual(methodReturnDoc(null)); }); @@ -303,6 +322,7 @@ describe('getMethodDocumentation', () => { } `); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodReturnDoc({ type: { name: 'number' }, @@ -319,6 +339,7 @@ describe('getMethodDocumentation', () => { const method = def .get('body') .get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodReturnDoc({ type: { name: 'number' }, @@ -339,6 +360,7 @@ describe('getMethodDocumentation', () => { const method = def .get('body') .get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toEqual( methodReturnDoc({ type: { name: 'number' }, @@ -357,6 +379,7 @@ describe('getMethodDocumentation', () => { `, ); const method = def.get('body').get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); @@ -370,6 +393,7 @@ describe('getMethodDocumentation', () => { const method = def .get('body') .get('body')[0] as NodePath; + expect(getMethodDocumentation(method)).toMatchSnapshot(); }); }); diff --git a/src/utils/__tests__/getParameterName-test.ts b/src/utils/__tests__/getParameterName-test.ts index 714c98b12b0..aab6c2eb520 100644 --- a/src/utils/__tests__/getParameterName-test.ts +++ b/src/utils/__tests__/getParameterName-test.ts @@ -6,36 +6,42 @@ describe('getParameterName', () => { it('returns the name for a normal parameter', () => { const def = parse.expression('function(a) {}'); const param = def.get('params')[0]; + expect(getParameterName(param)).toEqual('a'); }); it('returns the name for a rest parameter', () => { const def = parse.expression('function(...a) {}'); const param = def.get('params')[0]; + expect(getParameterName(param)).toEqual('...a'); }); it('returns the name for a parameter with a default value', () => { const def = parse.expression('function(a = 0) {}'); const param = def.get('params')[0]; + expect(getParameterName(param)).toEqual('a'); }); it('returns the raw representation for a parameter with object destructuring', () => { const def = parse.expression('function({a}) {}'); const param = def.get('params')[0]; + expect(getParameterName(param)).toEqual('{a}'); }); it('returns the raw representation for a parameter with array destructuring', () => { const def = parse.expression('function([a]) {}'); const param = def.get('params')[0]; + expect(getParameterName(param)).toEqual('[a]'); }); it('throws when passed an invalid path', () => { const def = parse.expression('function() {}'); const param = def; + expect(() => getParameterName(param as any)).toThrow(); }); @@ -45,6 +51,7 @@ describe('getParameterName', () => { { filename: 'file.ts' }, ); const param = def.get('body').get('body')[0].get('params')[0]; + expect(getParameterName(param)).toEqual('a'); }); }); diff --git a/src/utils/__tests__/getPropertyValuePath-test.ts b/src/utils/__tests__/getPropertyValuePath-test.ts index 1422344f8fe..313dc548bf9 100644 --- a/src/utils/__tests__/getPropertyValuePath-test.ts +++ b/src/utils/__tests__/getPropertyValuePath-test.ts @@ -12,6 +12,7 @@ describe('getPropertyValuePath', () => { const objectExpressionPath = parse .statement('({foo: 21, bar: 42})') .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'bar')).toBe( objectExpressionPath.get('properties')[1].get('value'), ); @@ -26,6 +27,7 @@ describe('getPropertyValuePath', () => { `, ) .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'bar')).toBe( objectExpressionPath.get('properties')[1].get('value'), ); @@ -35,6 +37,7 @@ describe('getPropertyValuePath', () => { const objectExpressionPath = parse .statement('({foo: 21, bar: 42})') .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'baz')).toBeNull(); }); @@ -48,6 +51,7 @@ describe('getPropertyValuePath', () => { mockImporter, ) .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'bar')).toBe( objectExpressionPath.get('properties')[1].get('value'), ); @@ -57,6 +61,7 @@ describe('getPropertyValuePath', () => { const objectExpressionPath = parse .statement('({ foo(){} })') .get('expression') as NodePath; + expect(getPropertyValuePath(objectExpressionPath, 'foo')).toBe( objectExpressionPath.get('properties')[0], ); diff --git a/src/utils/__tests__/getTSType-test.ts b/src/utils/__tests__/getTSType-test.ts index 034a14739a3..657c22c2a2a 100644 --- a/src/utils/__tests__/getTSType-test.ts +++ b/src/utils/__tests__/getTSType-test.ts @@ -108,6 +108,7 @@ describe('getTSType', () => { simplePropTypes.forEach(type => { const typePath = typeAlias(`let x: ${type};`); + expect(getTSType(typePath)).toEqual({ name: type }); }); }); @@ -118,6 +119,7 @@ describe('getTSType', () => { literalTypes.forEach(value => { it(`detects ${value}`, () => { const typePath = typeAlias(`let x: ${value};`); + expect(getTSType(typePath)).toEqual({ name: 'literal', value: `${value}`, @@ -128,6 +130,7 @@ describe('getTSType', () => { it('detects external type', () => { const typePath = typeAlias('let x: xyz;'); + expect(getTSType(typePath)).toEqual({ name: 'xyz' }); }); @@ -139,11 +142,13 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'string' }); }); it('detects array type shorthand', () => { const typePath = typeAlias('let x: number[];'); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], @@ -153,6 +158,7 @@ describe('getTSType', () => { it('detects array type', () => { const typePath = typeAlias('let x: Array;'); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }], @@ -162,6 +168,7 @@ describe('getTSType', () => { it('detects array type with multiple types', () => { const typePath = typeAlias('let x: Array;'); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'number' }, { name: 'xyz' }], @@ -177,6 +184,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'Array', elements: [{ name: 'string' }], @@ -212,6 +220,7 @@ describe('getTSType', () => { it('detects class type', () => { const typePath = typeAlias('let x: Class;'); + expect(getTSType(typePath)).toEqual({ name: 'Class', elements: [{ name: 'Boolean' }], @@ -227,6 +236,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'Class', elements: [{ name: 'string' }], @@ -236,6 +246,7 @@ describe('getTSType', () => { it('detects function type with subtype', () => { const typePath = typeAlias('let x: Function;'); + expect(getTSType(typePath)).toEqual({ name: 'Function', elements: [{ name: 'xyz' }], @@ -251,6 +262,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'Function', elements: [{ name: 'string' }], @@ -260,6 +272,7 @@ describe('getTSType', () => { it('detects object types', () => { const typePath = typeAlias('let x: { a: string, b?: xyz };'); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -281,6 +294,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -296,6 +310,7 @@ describe('getTSType', () => { it('detects union type', () => { const typePath = typeAlias('let x: string | xyz | "foo" | void;'); + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ @@ -316,6 +331,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ @@ -337,6 +353,7 @@ describe('getTSType', () => { it('detects intersection type', () => { const typePath = typeAlias('let x: string & xyz & "foo" & void;'); + expect(getTSType(typePath)).toEqual({ name: 'intersection', elements: [ @@ -357,6 +374,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'intersection', elements: [ @@ -380,6 +398,7 @@ describe('getTSType', () => { const typePath = typeAlias( 'let x: (p1: number, p2: string, ...rest: Array) => boolean;', ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'function', @@ -405,6 +424,7 @@ describe('getTSType', () => { it('detects function signature type with `this` parameter', () => { const typePath = typeAlias('let x: (this: Foo, p1: number) => boolean;'); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'function', @@ -421,6 +441,7 @@ describe('getTSType', () => { const typePath = typeAlias( 'let x: { (str: string): string, token: string };', ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -452,6 +473,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'function', @@ -526,6 +548,7 @@ describe('getTSType', () => { const typePath = typeAlias( 'let x: { [key: string]: number, [key: "xl"]: string, token: "a" | "b" };', ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -567,6 +590,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'signature', type: 'object', @@ -600,6 +624,7 @@ describe('getTSType', () => { it('detects tuple signature', () => { const typePath = typeAlias('let x: [string, number];'); + expect(getTSType(typePath)).toEqual({ name: 'tuple', elements: [{ name: 'string' }, { name: 'number' }], @@ -609,6 +634,7 @@ describe('getTSType', () => { it('detects tuple in union signature', () => { const typePath = typeAlias('let x: [string, number] | [number, string];'); + expect(getTSType(typePath)).toEqual({ name: 'union', elements: [ @@ -636,6 +662,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'tuple', elements: [{ name: 'string' }, { name: 'number' }], @@ -675,6 +702,7 @@ describe('getTSType', () => { interface A { x: string }; `); + expect(getTSType(typePath)).toEqual({ name: 'A["x"]', raw: 'A["x"]', @@ -687,6 +715,7 @@ describe('getTSType', () => { type A = { x: string }; `); + expect(getTSType(typePath)).toEqual({ name: 'string', raw: 'A["x"]', @@ -710,6 +739,7 @@ describe('getTSType', () => { .get('id') .get('typeAnnotation') .get('typeAnnotation'); + expect(getTSType(typePath)).toEqual({ name: 'STRING_VALS[number]', raw: 'typeof STRING_VALS[number]', @@ -724,6 +754,7 @@ describe('getTSType', () => { `, mockImporter, ); + expect(getTSType(typePath)).toEqual({ name: 'string', raw: 'A["x"]', diff --git a/src/utils/__tests__/isReactCloneElementCall-test.ts b/src/utils/__tests__/isReactCloneElementCall-test.ts index 8822b290ad7..dfd0b5c0bcc 100644 --- a/src/utils/__tests__/isReactCloneElementCall-test.ts +++ b/src/utils/__tests__/isReactCloneElementCall-test.ts @@ -16,6 +16,7 @@ describe('isReactCloneElementCall', () => { var React = require("React"); React.cloneElement({}); `); + expect(isReactCloneElementCall(def)).toBe(true); }); @@ -24,6 +25,7 @@ describe('isReactCloneElementCall', () => { var other = require("React"); other.cloneElement({}); `); + expect(isReactCloneElementCall(def)).toBe(true); }); @@ -32,6 +34,7 @@ describe('isReactCloneElementCall', () => { var React = require("React"); React.isValidElement({}); `); + expect(isReactCloneElementCall(def)).toBe(false); }); @@ -40,6 +43,7 @@ describe('isReactCloneElementCall', () => { var React = require("bob"); React.cloneElement({}); `); + expect(isReactCloneElementCall(def)).toBe(false); }); @@ -48,6 +52,7 @@ describe('isReactCloneElementCall', () => { var { cloneElement } = require("react"); cloneElement({}); `); + expect(isReactCloneElementCall(def)).toBe(true); }); @@ -56,6 +61,7 @@ describe('isReactCloneElementCall', () => { var { cloneElement: foo } = require("react"); foo({}); `); + expect(isReactCloneElementCall(def)).toBe(true); }); @@ -64,6 +70,7 @@ describe('isReactCloneElementCall', () => { import { cloneElement } from "react"; cloneElement({}); `); + expect(isReactCloneElementCall(def)).toBe(true); }); @@ -72,6 +79,7 @@ describe('isReactCloneElementCall', () => { import { cloneElement as foo } from "react"; foo({}); `); + expect(isReactCloneElementCall(def)).toBe(true); }); @@ -83,6 +91,7 @@ describe('isReactCloneElementCall', () => { `, mockImporter, ); + expect(isReactCloneElementCall(def)).toBe(true); }); }); diff --git a/src/utils/__tests__/isReactComponentClass-test.ts b/src/utils/__tests__/isReactComponentClass-test.ts index 24f0899dce0..4d4e1e69655 100644 --- a/src/utils/__tests__/isReactComponentClass-test.ts +++ b/src/utils/__tests__/isReactComponentClass-test.ts @@ -19,26 +19,31 @@ describe('isReactComponentClass', () => { describe('render method', () => { it('ignores class declarations with a render method without superclass', () => { const def = parse.statement('class Foo { render() {}}'); + expect(isReactComponentClass(def)).toBe(false); }); it('ignores class expression with a render method without superclass', () => { const def = parse.expression('class { render() {}}'); + expect(isReactComponentClass(def)).toBe(false); }); it('ignores static render methods', () => { const def = parse.statement('class Foo { static render() {}}'); + expect(isReactComponentClass(def)).toBe(false); }); it('ignores dynamic render methods', () => { const def = parse.statement('class Foo { static [render]() {}}'); + expect(isReactComponentClass(def)).toBe(false); }); it('ignores getter or setter render methods', () => { let def = parse.statement('class Foo { get render() {}}'); + expect(isReactComponentClass(def)).toBe(false); def = parse.statement('class Foo { set render(value) {}}'); @@ -174,6 +179,7 @@ describe('isReactComponentClass', () => { `var {PureComponent} = require('FakeReact'); class Foo extends PureComponent {}`, ); + expect(isReactComponentClass(def)).toBe(false); }); diff --git a/src/utils/__tests__/isReactComponentMethod-test.ts b/src/utils/__tests__/isReactComponentMethod-test.ts index b63d9967e51..6a35cda8e79 100644 --- a/src/utils/__tests__/isReactComponentMethod-test.ts +++ b/src/utils/__tests__/isReactComponentMethod-test.ts @@ -13,29 +13,34 @@ describe('isReactComponentMethod', () => { it('returns true if the method is a component class method', () => { const def = parse.statement('class Foo { render() {}}'); const method = def.get('body').get('body')[0]; + expect(isReactComponentMethod(method)).toBe(true); }); it('returns true if the method is a component `createClass` object method', () => { const def = parse.expression('{ render() {}}'); const method = def.get('properties')[0]; + expect(isReactComponentMethod(method)).toBe(true); }); it('returns false if the method is not a component class method', () => { const def = parse.statement('class Foo { bar() {}}'); const method = def.get('body').get('body')[0]; + expect(isReactComponentMethod(method)).toBe(false); }); it('returns false if the method is not a component `createClass` object method', () => { const def = parse.expression('{ bar() {}}'); const method = def.get('properties')[0]; + expect(isReactComponentMethod(method)).toBe(false); }); it('returns false if the path is not a method or object property', () => { const def = parse.statement('let foo = "bar";'); + expect(isReactComponentMethod(def)).toBe(false); }); @@ -48,6 +53,7 @@ describe('isReactComponentMethod', () => { mockImporter, ); const method = def.get('body').get('body')[0]; + expect(isReactComponentMethod(method)).toBe(true); }); }); diff --git a/src/utils/__tests__/isReactCreateClassCall-test.ts b/src/utils/__tests__/isReactCreateClassCall-test.ts index cec88bf54ed..73566f5b1ef 100644 --- a/src/utils/__tests__/isReactCreateClassCall-test.ts +++ b/src/utils/__tests__/isReactCreateClassCall-test.ts @@ -24,6 +24,7 @@ describe('isReactCreateClassCall', () => { render() {} }); `); + expect(isReactCreateClassCall(def)).toBe(true); }); @@ -34,6 +35,7 @@ describe('isReactCreateClassCall', () => { render() {} }); `); + expect(isReactCreateClassCall(def)).toBe(true); }); @@ -42,6 +44,7 @@ describe('isReactCreateClassCall', () => { var React = require("React"); React.isValidElement({}); `); + expect(isReactCreateClassCall(def)).toBe(false); }); @@ -52,6 +55,7 @@ describe('isReactCreateClassCall', () => { render() {} }); `); + expect(isReactCreateClassCall(def)).toBe(false); }); @@ -60,6 +64,7 @@ describe('isReactCreateClassCall', () => { var { createClass } = require("react"); createClass({}); `); + expect(isReactCreateClassCall(def)).toBe(true); }); @@ -68,6 +73,7 @@ describe('isReactCreateClassCall', () => { var { createClass: foo } = require("react"); foo({}); `); + expect(isReactCreateClassCall(def)).toBe(true); }); @@ -76,6 +82,7 @@ describe('isReactCreateClassCall', () => { import { createClass } from "react"; createClass({}); `); + expect(isReactCreateClassCall(def)).toBe(true); }); @@ -84,6 +91,7 @@ describe('isReactCreateClassCall', () => { import { createClass as foo } from "react"; foo({}); `); + expect(isReactCreateClassCall(def)).toBe(true); }); @@ -95,6 +103,7 @@ describe('isReactCreateClassCall', () => { `, mockImporter, ); + expect(isReactCreateClassCall(def)).toBe(true); }); }); @@ -107,6 +116,7 @@ describe('isReactCreateClassCall', () => { render() {} }); `); + expect(isReactCreateClassCall(def)).toBe(true); }); @@ -117,6 +127,7 @@ describe('isReactCreateClassCall', () => { render() {} }); `); + expect(isReactCreateClassCall(def)).toBe(true); }); @@ -127,6 +138,7 @@ describe('isReactCreateClassCall', () => { render() {} }); `); + expect(isReactCreateClassCall(def)).toBe(false); }); @@ -138,6 +150,7 @@ describe('isReactCreateClassCall', () => { `, mockImporter, ); + expect(isReactCreateClassCall(def)).toBe(true); }); }); diff --git a/src/utils/__tests__/isReactCreateElementCall-test.ts b/src/utils/__tests__/isReactCreateElementCall-test.ts index fbb651f315d..5b3f46d67f4 100644 --- a/src/utils/__tests__/isReactCreateElementCall-test.ts +++ b/src/utils/__tests__/isReactCreateElementCall-test.ts @@ -18,6 +18,7 @@ describe('isReactCreateElementCall', () => { render() {} }); `); + expect(isReactCreateElementCall(def)).toBe(true); }); @@ -28,6 +29,7 @@ describe('isReactCreateElementCall', () => { render() {} }); `); + expect(isReactCreateElementCall(def)).toBe(true); }); @@ -36,6 +38,7 @@ describe('isReactCreateElementCall', () => { var React = require("React"); React.isValidElement({}); `); + expect(isReactCreateElementCall(def)).toBe(false); }); @@ -46,6 +49,7 @@ describe('isReactCreateElementCall', () => { render() {} }); `); + expect(isReactCreateElementCall(def)).toBe(false); }); @@ -54,6 +58,7 @@ describe('isReactCreateElementCall', () => { var { createElement } = require("react"); createElement({}); `); + expect(isReactCreateElementCall(def)).toBe(true); }); @@ -62,6 +67,7 @@ describe('isReactCreateElementCall', () => { var { createElement: foo } = require("react"); foo({}); `); + expect(isReactCreateElementCall(def)).toBe(true); }); @@ -70,6 +76,7 @@ describe('isReactCreateElementCall', () => { import { createElement } from "react"; createElement({}); `); + expect(isReactCreateElementCall(def)).toBe(true); }); @@ -78,6 +85,7 @@ describe('isReactCreateElementCall', () => { import { createElement as foo } from "react"; foo({}); `); + expect(isReactCreateElementCall(def)).toBe(true); }); @@ -87,6 +95,7 @@ describe('isReactCreateElementCall', () => { foo({});`, mockImporter, ); + expect(isReactCreateElementCall(def)).toBe(true); }); }); diff --git a/src/utils/__tests__/isReactForwardRefCall-test.ts b/src/utils/__tests__/isReactForwardRefCall-test.ts index 8da0dd84b28..63b201dcc44 100644 --- a/src/utils/__tests__/isReactForwardRefCall-test.ts +++ b/src/utils/__tests__/isReactForwardRefCall-test.ts @@ -18,6 +18,7 @@ describe('isReactForwardRefCall', () => { render() {} }); `); + expect(isReactForwardRefCall(def)).toBe(true); }); @@ -28,6 +29,7 @@ describe('isReactForwardRefCall', () => { render() {} }); `); + expect(isReactForwardRefCall(def)).toBe(true); }); @@ -36,6 +38,7 @@ describe('isReactForwardRefCall', () => { var React = require("React"); React.isValidElement({}); `); + expect(isReactForwardRefCall(def)).toBe(false); }); @@ -46,6 +49,7 @@ describe('isReactForwardRefCall', () => { render() {} }); `); + expect(isReactForwardRefCall(def)).toBe(false); }); @@ -54,6 +58,7 @@ describe('isReactForwardRefCall', () => { var { forwardRef } = require("react"); forwardRef({}); `); + expect(isReactForwardRefCall(def)).toBe(true); }); @@ -62,6 +67,7 @@ describe('isReactForwardRefCall', () => { var { forwardRef: foo } = require("react"); foo({}); `); + expect(isReactForwardRefCall(def)).toBe(true); }); @@ -70,6 +76,7 @@ describe('isReactForwardRefCall', () => { import { forwardRef } from "react"; forwardRef({}); `); + expect(isReactForwardRefCall(def)).toBe(true); }); @@ -78,6 +85,7 @@ describe('isReactForwardRefCall', () => { import { forwardRef, memo } from "react"; memo(forwardRef({})); `); + expect(isReactForwardRefCall(def)).toBe(false); }); @@ -86,6 +94,7 @@ describe('isReactForwardRefCall', () => { import { forwardRef as foo } from "react"; foo({}); `); + expect(isReactForwardRefCall(def)).toBe(true); }); @@ -97,6 +106,7 @@ describe('isReactForwardRefCall', () => { `, mockImporter, ); + expect(isReactForwardRefCall(def)).toBe(true); }); }); diff --git a/src/utils/__tests__/isStatelessComponent-test.ts b/src/utils/__tests__/isStatelessComponent-test.ts index 7d7b5254bfa..3c9a1e20736 100644 --- a/src/utils/__tests__/isStatelessComponent-test.ts +++ b/src/utils/__tests__/isStatelessComponent-test.ts @@ -86,10 +86,12 @@ describe('isStatelessComponent', () => { describe(name, () => { Object.keys(componentIdentifiers).forEach(componentIdentifierName => { const returnExpr = componentIdentifiers[componentIdentifierName]; + describe(componentIdentifierName, () => { Object.keys(componentStyle).forEach(componentName => { const [componentFactory, componentSelector] = componentStyle[componentName]; + describe(componentName, () => { Object.keys(modifiers).forEach(modifierName => { const modifierFactory = modifiers[modifierName]; @@ -184,6 +186,7 @@ describe('isStatelessComponent', () => { } } `); + expect(isStatelessComponent(def)).toBe(false); }); diff --git a/src/utils/__tests__/parseJsDoc-test.ts b/src/utils/__tests__/parseJsDoc-test.ts index 93e2dc998a9..f7449263ac2 100644 --- a/src/utils/__tests__/parseJsDoc-test.ts +++ b/src/utils/__tests__/parseJsDoc-test.ts @@ -6,6 +6,7 @@ describe('parseJsDoc', () => { const docblock = ` Don't use this! `; + expect(parseJsDoc(docblock)).toMatchSnapshot(); }); }); @@ -20,6 +21,7 @@ describe('parseJsDoc', () => { Object.keys(docBlocks).forEach(name => { const docBlock = docBlocks[name]; + it(name, () => { expect(parseJsDoc(docBlock)).toMatchSnapshot(); }); @@ -36,6 +38,7 @@ describe('parseJsDoc', () => { Object.keys(docBlocks).forEach(name => { const docBlock = docBlocks[name]; + it(name, () => { expect(parseJsDoc(docBlock)).toMatchSnapshot(); }); diff --git a/src/utils/__tests__/resolveExportDeclaration-test.ts b/src/utils/__tests__/resolveExportDeclaration-test.ts index b7f2572236a..5136b41b51c 100644 --- a/src/utils/__tests__/resolveExportDeclaration-test.ts +++ b/src/utils/__tests__/resolveExportDeclaration-test.ts @@ -25,6 +25,7 @@ describe('resolveExportDeclaration', () => { const resolved = resolveExportDeclaration(exp); const declarations = exp.get('declaration').get('declarations'); + expect(resolved).toEqual([declarations[0], declarations[1]]); }); @@ -51,6 +52,7 @@ describe('resolveExportDeclaration', () => { const resolved = resolveExportDeclaration(exp); const specifiers = exp.get('specifiers'); + expect(resolved).toEqual([ specifiers[0].get('local'), specifiers[1].get('local'), @@ -65,6 +67,7 @@ describe('resolveExportDeclaration', () => { const resolved = resolveExportDeclaration(exp); const specifiers = exp.get('specifiers'); + expect(resolved).toEqual([ specifiers[0].get('local'), specifiers[1].get('local'), diff --git a/src/utils/__tests__/resolveGenericTypeAnnotations-test.ts b/src/utils/__tests__/resolveGenericTypeAnnotations-test.ts index a2510ce0a81..75aab6b7941 100644 --- a/src/utils/__tests__/resolveGenericTypeAnnotations-test.ts +++ b/src/utils/__tests__/resolveGenericTypeAnnotations-test.ts @@ -7,6 +7,7 @@ describe('resolveGenericTypeAnnotation', () => { var x: Props; type Props = { x: string }; `; + expect( resolveGenericTypeAnnotation( parse diff --git a/src/utils/__tests__/resolveHOC-test.ts b/src/utils/__tests__/resolveHOC-test.ts index 33167eeefde..39f9405add2 100644 --- a/src/utils/__tests__/resolveHOC-test.ts +++ b/src/utils/__tests__/resolveHOC-test.ts @@ -18,6 +18,7 @@ describe('resolveHOC', () => { it('resolves simple hoc', () => { const path = parse.expressionLast(['hoc(Component);'].join('\n')); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); @@ -25,6 +26,7 @@ describe('resolveHOC', () => { const path = parse.expressionLast( ['hoc1(arg1a, arg1b)(Component);'].join('\n'), ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); @@ -34,6 +36,7 @@ describe('resolveHOC', () => { hoc1(arg1a, arg2a)(Component) );`, ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); @@ -45,31 +48,37 @@ describe('resolveHOC', () => { ) );`, ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC with additional params', () => { const path = parse.expressionLast(`hoc3(Component, {})`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC as last element if first is literal', () => { const path = parse.expressionLast(`hoc3(41, Component)`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC as last element if first is array', () => { const path = parse.expressionLast(`hoc3([], Component)`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC as last element if first is object', () => { const path = parse.expressionLast(`hoc3({}, Component)`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); it('resolves HOC as last element if first is spread', () => { const path = parse.expressionLast(`hoc3(...params, Component)`); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); @@ -77,6 +86,7 @@ describe('resolveHOC', () => { const path = parse.expressionLast( ['const Component = React.memo(42);', 'hoc()(Component);'].join('\n'), ); + expect(resolveHOC(path)).toEqualASTNode(numericLiteral(42)); }); @@ -88,6 +98,7 @@ describe('resolveHOC', () => { `, mockImporter, ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); @@ -101,6 +112,7 @@ describe('resolveHOC', () => { `, mockImporter, ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); @@ -110,6 +122,7 @@ describe('resolveHOC', () => { hoc(bar);`, mockImporter, ); + expect(resolveHOC(path)).toEqualASTNode(identifier('Component')); }); }); diff --git a/src/utils/__tests__/resolveToModule-test.ts b/src/utils/__tests__/resolveToModule-test.ts index f4831718661..fd1e10421e3 100644 --- a/src/utils/__tests__/resolveToModule-test.ts +++ b/src/utils/__tests__/resolveToModule-test.ts @@ -21,6 +21,7 @@ describe('resolveToModule', () => { var foo = require("Foo"); foo; `); + expect(resolveToModule(path)).toBe('Foo'); }); @@ -29,6 +30,7 @@ describe('resolveToModule', () => { var foo = require("Foo"); foo(); `); + expect(resolveToModule(path)).toBe('Foo'); }); @@ -37,6 +39,7 @@ describe('resolveToModule', () => { var foo = require("Foo"); foo.bar().baz; `); + expect(resolveToModule(path)).toBe('Foo'); }); @@ -45,6 +48,7 @@ describe('resolveToModule', () => { var {foo} = require("Foo"); foo; `); + expect(resolveToModule(path)).toBe('Foo'); }); @@ -54,6 +58,7 @@ describe('resolveToModule', () => { import foo from "Foo"; foo; `); + expect(resolveToModule(path)).toBe('Foo'); path = parse.expressionLast(` @@ -68,6 +73,7 @@ describe('resolveToModule', () => { import {foo, bar} from "Foo"; bar; `); + expect(resolveToModule(path)).toBe('Foo'); }); @@ -76,6 +82,7 @@ describe('resolveToModule', () => { import {foo, bar as baz} from "Foo"; baz; `); + expect(resolveToModule(path)).toBe('Foo'); }); @@ -84,6 +91,7 @@ describe('resolveToModule', () => { import * as foo from "Foo"; foo; `); + expect(resolveToModule(path)).toBe('Foo'); }); @@ -95,6 +103,7 @@ describe('resolveToModule', () => { `, mockImporter, ); + expect(resolveToModule(path)).toBe('Baz'); }); }); diff --git a/src/utils/__tests__/resolveToValue-test.ts b/src/utils/__tests__/resolveToValue-test.ts index cecbafec813..2755931189a 100644 --- a/src/utils/__tests__/resolveToValue-test.ts +++ b/src/utils/__tests__/resolveToValue-test.ts @@ -17,6 +17,7 @@ import resolveToValue from '../resolveToValue'; describe('resolveToValue', () => { it('resolves simple variable declarations', () => { const path = parse.expressionLast(['var foo = 42;', 'foo;'].join('\n')); + expect(resolveToValue(path)).toEqualASTNode(numericLiteral(42)); }); @@ -32,6 +33,7 @@ describe('resolveToValue', () => { undefined, undefined, ); + expected.decorators = undefined; // @ts-ignore BABEL types bug expected.method = false; @@ -66,6 +68,7 @@ describe('resolveToValue', () => { class Foo {} Foo; `); + expect(resolveToValue(path).node.type).toBe('ClassDeclaration'); }); @@ -74,6 +77,7 @@ describe('resolveToValue', () => { function foo() {} foo; `); + expect(resolveToValue(path).node.type).toBe('FunctionDeclaration'); }); @@ -83,6 +87,7 @@ describe('resolveToValue', () => { function foo() {} (foo: any); `); + expect(resolveToValue(path).node.type).toBe('FunctionDeclaration'); }); }); @@ -93,6 +98,7 @@ describe('resolveToValue', () => { function foo() {} (foo as any); `); + expect(resolveToValue(path).node.type).toBe('FunctionDeclaration'); }); @@ -101,6 +107,7 @@ describe('resolveToValue', () => { function foo() {} ( foo); `); + expect(resolveToValue(path).node.type).toBe('FunctionDeclaration'); }); @@ -109,6 +116,7 @@ describe('resolveToValue', () => { `let action: Action; type Action = {};`, ); + expect( resolveToValue( path.get( diff --git a/src/utils/docblock.ts b/src/utils/docblock.ts index 5fe14f8e745..7c328727d29 100644 --- a/src/utils/docblock.ts +++ b/src/utils/docblock.ts @@ -21,6 +21,7 @@ const DOCBLOCK_HEADER = /^\*\s/; */ export function getDocblock(path: NodePath, trailing = false): string | null { let comments: Array = []; + if (trailing && path.node.trailingComments) { comments = path.node.trailingComments.filter( comment => @@ -36,6 +37,7 @@ export function getDocblock(path: NodePath, trailing = false): string | null { if (comments.length > 0) { return parseDocblock(comments[comments.length - 1].value); } + return null; } diff --git a/src/utils/expressionTo.ts b/src/utils/expressionTo.ts index 92b15e27373..55b2fe1b3e5 100644 --- a/src/utils/expressionTo.ts +++ b/src/utils/expressionTo.ts @@ -19,8 +19,10 @@ function toArray(path: NodePath): string[] { } else if (path.isMemberExpression()) { parts.push(path.get('object')); const property = path.get('property'); + if (path.node.computed) { const resolvedPath = resolveToValue(property); + if (resolvedPath !== undefined) { result = result.concat(toArray(resolvedPath)); } else { @@ -38,6 +40,7 @@ function toArray(path: NodePath): string[] { continue; } else if (path.isTSAsExpression()) { const expression = path.get('expression'); + if (expression.isIdentifier()) { result.push(expression.node.name); } @@ -64,6 +67,7 @@ function toArray(path: NodePath): string[] { throw new Error('Unrecognized object property type'); } }); + result.push('{' + properties.join(', ') + '}'); continue; } else if (path.isArrayExpression()) { diff --git a/src/utils/flowUtilityTypes.ts b/src/utils/flowUtilityTypes.ts index 09b8d16d601..f86c62efd94 100644 --- a/src/utils/flowUtilityTypes.ts +++ b/src/utils/flowUtilityTypes.ts @@ -10,6 +10,7 @@ export function isSupportedUtilityType( ): path is NodePath { if (path.isGenericTypeAnnotation()) { const idPath = path.get('id'); + if (idPath.isIdentifier()) { const name = idPath.node.name; diff --git a/src/utils/getFlowType.ts b/src/utils/getFlowType.ts index ab6ca539165..95e552c13d0 100644 --- a/src/utils/getFlowType.ts +++ b/src/utils/getFlowType.ts @@ -78,12 +78,14 @@ function handleKeysHelper( path: NodePath, ): ElementsType | null { let value = path.get('typeParameters').get('params')[0]; + if (value.isTypeofTypeAnnotation()) { value = value.get('argument').get('id'); } else if (!value.isObjectTypeAnnotation()) { value = value.get('id'); } const resolvedPath = resolveToValue(value); + if ( resolvedPath && (resolvedPath.isObjectExpression() || resolvedPath.isObjectTypeAnnotation()) @@ -121,6 +123,7 @@ function handleGenericTypeAnnotation( ): TypeDescriptor | null { const id = path.get('id'); const typeParameters = path.get('typeParameters'); + if ( id.isIdentifier() && id.node.name === '$Keys' && @@ -130,8 +133,10 @@ function handleGenericTypeAnnotation( } let type: TypeDescriptor; + if (id.isQualifiedTypeIdentifier()) { const qualification = id.get('qualification'); + if (qualification.isIdentifier() && qualification.node.name === 'React') { type = { name: `${qualification.node.name}${id.node.id.name}`, @@ -202,6 +207,7 @@ function handleObjectTypeAnnotation( }; const callProperties = path.get('callProperties'); + if (Array.isArray(callProperties)) { callProperties.forEach(param => { type.signature.constructor = getFlowTypeWithResolvedTypes( @@ -212,6 +218,7 @@ function handleObjectTypeAnnotation( } const indexers = path.get('indexers'); + if (Array.isArray(indexers)) { indexers.forEach(param => { type.signature.properties.push({ @@ -230,8 +237,10 @@ function handleObjectTypeAnnotation( }); } else if (param.isObjectTypeSpreadProperty()) { let spreadObject = resolveToValue(param.get('argument')); + if (spreadObject.isGenericTypeAnnotation()) { const typeAlias = resolveToValue(spreadObject.get('id')); + if ( typeAlias.isTypeAlias() && typeAlias.get('right').isObjectTypeAnnotation() @@ -245,6 +254,7 @@ function handleObjectTypeAnnotation( spreadObject, typeParams, ) as ObjectSignatureType; + type.signature.properties.push(...props.signature.properties); } } @@ -298,6 +308,7 @@ function handleNullableTypeAnnotation( if (!typeAnnotation) return null; const type = getFlowTypeWithResolvedTypes(typeAnnotation, typeParams); + type.nullable = true; return type; @@ -329,6 +340,7 @@ function handleFunctionTypeAnnotation( }); const rest = path.get('rest'); + if (rest.hasNode()) { const typeAnnotation = getTypeAnnotation(rest); @@ -378,6 +390,7 @@ function getFlowTypeWithResolvedTypes( const parent = path.parentPath; const isTypeAlias = parent.isTypeAlias(); + // When we see a typealias mark it as visited so that the next // call of this function does not run into an endless loop if (isTypeAlias) { @@ -442,6 +455,7 @@ export default function getFlowType( // After: cleanup memory after we are done here visitedTypes = {}; const type = getFlowTypeWithResolvedTypes(path, typeParams); + visitedTypes = {}; return type; diff --git a/src/utils/getMemberExpressionRoot.ts b/src/utils/getMemberExpressionRoot.ts index c61601fb22d..4758b744e7c 100644 --- a/src/utils/getMemberExpressionRoot.ts +++ b/src/utils/getMemberExpressionRoot.ts @@ -13,6 +13,7 @@ export default function getMemberExpressionRoot( memberExpressionPath: NodePath, ): NodePath { let path: NodePath = memberExpressionPath; + while (path.isMemberExpression()) { path = path.get('object'); } diff --git a/src/utils/getMemberExpressionValuePath.ts b/src/utils/getMemberExpressionValuePath.ts index d87c1682b38..43fb299b245 100644 --- a/src/utils/getMemberExpressionValuePath.ts +++ b/src/utils/getMemberExpressionValuePath.ts @@ -7,6 +7,7 @@ import isReactForwardRefCall from './isReactForwardRefCall'; function resolveName(path: NodePath): string | undefined { if (path.isVariableDeclaration()) { const declarations = path.get('declarations'); + if (declarations.length > 1) { throw new TypeError( 'Got unsupported VariableDeclaration. VariableDeclaration must only ' + @@ -16,6 +17,7 @@ function resolveName(path: NodePath): string | undefined { ); } const id = declarations[0].get('id'); + if (id.isIdentifier()) { return id.node.name; } @@ -25,6 +27,7 @@ function resolveName(path: NodePath): string | undefined { if (path.isFunctionDeclaration()) { const id = path.get('id'); + if (id.isIdentifier()) { return id.node.name; } @@ -40,12 +43,15 @@ function resolveName(path: NodePath): string | undefined { isReactForwardRefCall(path) ) { let currentPath: NodePath = path; + while (currentPath.parentPath) { if (currentPath.parentPath.isVariableDeclarator()) { const id = currentPath.parentPath.get('id'); + if (id.isIdentifier()) { return id.node.name; } + return; } @@ -76,9 +82,11 @@ export default function getMemberExpressionValuePath( } let result: NodePath | null = null; + program.traverse({ AssignmentExpression(path) { const memberPath = path.get('left'); + if (!memberPath.isMemberExpression()) { return; } @@ -91,6 +99,7 @@ export default function getMemberExpressionValuePath( ) { result = path.get('right'); path.skip(); + return; } }, diff --git a/src/utils/getMemberValuePath.ts b/src/utils/getMemberValuePath.ts index c5a5303de31..dbde4835bdb 100644 --- a/src/utils/getMemberValuePath.ts +++ b/src/utils/getMemberValuePath.ts @@ -92,6 +92,7 @@ export default function getMemberValuePath( memberName: string, ): NodePath | null { let result: NodePath | null; + if (componentDefinition.isObjectExpression()) { result = getPropertyValuePath(componentDefinition, memberName); if (!result && memberName === 'defaultProps') { @@ -116,6 +117,7 @@ export default function getMemberValuePath( } const postprocessMethod = POSTPROCESS_MEMBERS.get(memberName); + if (result && postprocessMethod) { result = postprocessMethod(result); } diff --git a/src/utils/getMembers.ts b/src/utils/getMembers.ts index 35ccb0c1c82..a06b99a9362 100644 --- a/src/utils/getMembers.ts +++ b/src/utils/getMembers.ts @@ -31,6 +31,7 @@ export default function getMembers( while (true) { if (resultPath.isMemberExpression()) { const property = resultPath.get('property'); + result.push({ path: property, computed: resultPath.node.computed, @@ -40,6 +41,7 @@ export default function getMembers( resultPath = resultPath.get('object'); } else if (resultPath.isCallExpression()) { const callee = resultPath.get('callee'); + if (callee.isExpression()) { argumentPaths = resultPath.get('arguments'); resultPath = callee; @@ -57,5 +59,6 @@ export default function getMembers( argumentPaths, }); } + return result.reverse(); } diff --git a/src/utils/getMethodDocumentation.ts b/src/utils/getMethodDocumentation.ts index f8255420bb4..a1a77465b4e 100644 --- a/src/utils/getMethodDocumentation.ts +++ b/src/utils/getMethodDocumentation.ts @@ -58,6 +58,7 @@ function getMethodParamOptional( path: NodePath, ): boolean { let identifier: NodePath = path; + if (identifier.isTSParameterProperty()) { identifier = identifier.get('parameter'); } @@ -78,6 +79,7 @@ function getMethodParamsDoc(methodPath: MethodNodePath): MethodParameter[] { functionExpression.get('params').forEach(paramPath => { let type: TypeDescriptor | null = null; const typePath = getTypeAnnotation(paramPath); + if (typePath) { if (typePath.isFlowType()) { type = getFlowType(typePath, null); @@ -113,6 +115,7 @@ function getMethodReturnDoc(methodPath: MethodNodePath): MethodReturn | null { const returnType = getTypeAnnotation( functionExpression.get('returnType') as NodePath, ); + if (returnType && returnType.isFlowType()) { return { type: getFlowType(returnType, null) }; } else if (returnType) { @@ -145,6 +148,7 @@ function getMethodModifiers( } const functionExpression = getMethodFunctionExpression(methodPath); + if (functionExpression) { if ( functionExpression.isClassMethod() || @@ -174,8 +178,10 @@ function getMethodName( ): string | null { if (methodPath.isAssignmentExpression()) { const left = methodPath.get('left'); + if (left.isMemberExpression()) { const property = left.get('property'); + if (!left.node.computed && property.isIdentifier()) { return property.node.name; } @@ -204,6 +210,7 @@ function getMethodAccessibility( function getMethodDocblock(methodPath: MethodNodePath): string | null { if (methodPath.isAssignmentExpression()) { let path: NodePath | null = methodPath; + do { path = path.parentPath; } while (path && !path.isExpressionStatement()); @@ -211,6 +218,7 @@ function getMethodDocblock(methodPath: MethodNodePath): string | null { if (path) { return getDocblock(path); } + return null; } @@ -233,6 +241,7 @@ export default function getMethodDocumentation( } const name = getMethodName(methodPath); + if (!name) return null; return { diff --git a/src/utils/getPropType.ts b/src/utils/getPropType.ts index 11d9223b614..b6be8ddf628 100644 --- a/src/utils/getPropType.ts +++ b/src/utils/getPropType.ts @@ -42,6 +42,7 @@ function getEnumValuesFromArrayExpression( // try to resolve the array element to it's value const value = resolveToValue(elementPath as NodePath); + return values.push({ value: printValue(value), computed: !value.isLiteral(), @@ -54,9 +55,11 @@ function getEnumValuesFromArrayExpression( function getPropTypeOneOf(argumentPath: NodePath): PropTypeDescriptor { const type: PropTypeDescriptor = { name: 'enum' }; const value: NodePath = resolveToValue(argumentPath); + if (!value.isArrayExpression()) { const objectValues = resolveObjectKeysToArray(value) || resolveObjectValuesToArray(value); + if (objectValues) { type.value = objectValues.map(objectValue => ({ value: objectValue, @@ -70,11 +73,13 @@ function getPropTypeOneOf(argumentPath: NodePath): PropTypeDescriptor { } else { type.value = getEnumValuesFromArrayExpression(value); } + return type; } function getPropTypeOneOfType(argumentPath: NodePath): PropTypeDescriptor { const type: PropTypeDescriptor = { name: 'union' }; + if (!argumentPath.isArrayExpression()) { type.computed = true; type.value = printValue(argumentPath); @@ -86,12 +91,15 @@ function getPropTypeOneOfType(argumentPath: NodePath): PropTypeDescriptor { const docs = getDocblock( elementPath as NodePath, ); + if (docs) { descriptor.description = docs; } + return descriptor; }); } + return type; } @@ -99,6 +107,7 @@ function getPropTypeArrayOf(argumentPath: NodePath) { const type: PropTypeDescriptor = { name: 'arrayOf' }; const docs = getDocblock(argumentPath); + if (docs) { type.description = docs; } @@ -112,6 +121,7 @@ function getPropTypeArrayOf(argumentPath: NodePath) { } else { type.value = subType; } + return type; } @@ -119,6 +129,7 @@ function getPropTypeObjectOf(argumentPath: NodePath) { const type: PropTypeDescriptor = { name: 'objectOf' }; const docs = getDocblock(argumentPath); + if (docs) { type.description = docs; } @@ -132,6 +143,7 @@ function getPropTypeObjectOf(argumentPath: NodePath) { } else { type.value = subType; } + return type; } @@ -140,12 +152,14 @@ function getPropTypeObjectOf(argumentPath: NodePath) { */ function getPropTypeShapish(name: 'exact' | 'shape', argumentPath: NodePath) { const type: PropTypeDescriptor = { name }; + if (!argumentPath.isObjectExpression()) { argumentPath = resolveToValue(argumentPath); } if (argumentPath.isObjectExpression()) { const value = {}; + argumentPath.get('properties').forEach(propertyPath => { if (propertyPath.isSpreadElement() || propertyPath.isObjectMethod()) { // It is impossible to resolve a name for a spread element @@ -153,6 +167,7 @@ function getPropTypeShapish(name: 'exact' | 'shape', argumentPath: NodePath) { } const propertyName = getPropertyName(propertyPath); + if (!propertyName) return; const valuePath = (propertyPath as NodePath).get('value'); @@ -160,6 +175,7 @@ function getPropTypeShapish(name: 'exact' | 'shape', argumentPath: NodePath) { const descriptor: PropDescriptor | PropTypeDescriptor = getPropType(valuePath); const docs = getDocblock(propertyPath); + if (docs) { descriptor.description = docs; } @@ -224,9 +240,11 @@ const propTypes = new Map PropTypeDescriptor>([ */ export default function getPropType(path: NodePath): PropTypeDescriptor { let descriptor: PropTypeDescriptor | null = null; + getMembers(path, true).some(member => { const memberPath = member.path; let name: string | null = null; + if (memberPath.isStringLiteral()) { name = memberPath.node.value; } else if (memberPath.isIdentifier() && !member.computed) { @@ -235,9 +253,11 @@ export default function getPropType(path: NodePath): PropTypeDescriptor { if (name) { if (isSimplePropType(name)) { descriptor = { name }; + return true; } else if (propTypes.has(name) && member.argumentPaths.length) { descriptor = propTypes.get(name)!(member.argumentPaths[0]); + return true; } } diff --git a/src/utils/getPropertyName.ts b/src/utils/getPropertyName.ts index 424bc535c57..796d307daca 100644 --- a/src/utils/getPropertyName.ts +++ b/src/utils/getPropertyName.ts @@ -36,9 +36,11 @@ export default function getPropertyName( ): string | null { if (propertyPath.isObjectTypeSpreadProperty()) { const argument = propertyPath.get('argument'); + if (argument.isGenericTypeAnnotation()) { return getNameOrValue(argument.get('id')) as string; } + return null; } else if (propertyPath.has('computed')) { const key = propertyPath.get('key') as NodePath; diff --git a/src/utils/getPropertyValuePath.ts b/src/utils/getPropertyValuePath.ts index b1ef18be29a..ea5b2cea10c 100644 --- a/src/utils/getPropertyValuePath.ts +++ b/src/utils/getPropertyValuePath.ts @@ -24,5 +24,6 @@ export default function getPropertyValuePath( ? property : (property.get('value') as NodePath); } + return null; } diff --git a/src/utils/getTSType.ts b/src/utils/getTSType.ts index 49ac9664122..af12bc01350 100644 --- a/src/utils/getTSType.ts +++ b/src/utils/getTSType.ts @@ -5,7 +5,6 @@ import resolveToValue from '../utils/resolveToValue'; import { resolveObjectToNameArray } from '../utils/resolveObjectKeysToArray'; import type { TypeParameters } from '../utils/getTypeParameters'; import getTypeParameters from '../utils/getTypeParameters'; - import type { ElementsType, FunctionArgumentType, @@ -85,9 +84,11 @@ function handleTSTypeReference( ): TypeDescriptor | null { let type: TypeDescriptor; const typeName = path.get('typeName'); + if (typeName.isTSQualifiedName()) { const left = typeName.get('left'); const right = typeName.get('right'); + if ( left.isIdentifier() && left.node.name === 'React' && @@ -112,6 +113,7 @@ function handleTSTypeReference( const resolvedTypeParameters = resolvedPath.get('typeParameters') as NodePath< TSTypeParameterDeclaration | null | undefined >; + if (typeParameters.hasNode() && resolvedTypeParameters.hasNode()) { typeParams = getTypeParameters( resolvedTypeParameters, @@ -131,6 +133,7 @@ function handleTSTypeReference( const resolvedTypeAnnotation = resolvedPath.get('typeAnnotation') as NodePath< TSType | TSTypeAnnotation | null | undefined >; + if (resolvedTypeAnnotation.hasNode()) { type = getTSTypeWithResolvedTypes(resolvedTypeAnnotation, typeParams); } else if (typeParameters.hasNode()) { @@ -153,8 +156,10 @@ function getTSTypeWithRequirements( typeParams: TypeParameters | null, ): TypeDescriptor { const type = getTSTypeWithResolvedTypes(path, typeParams); + type.required = !('optional' in path.parentPath.node) || !path.parentPath.node.optional; + return type; } @@ -173,11 +178,13 @@ function handleTSTypeLiteral( const typeAnnotation = param.get('typeAnnotation') as NodePath< TSTypeAnnotation | null | undefined >; + if ( (param.isTSPropertySignature() || param.isTSMethodSignature()) && typeAnnotation.hasNode() ) { const propName = getPropertyName(param); + if (!propName) { return; } @@ -248,10 +255,12 @@ function handleTSMappedType( path.get('typeParameter').get('constraint') as NodePath, typeParams, ); + key.required = !path.node.optional; const typeAnnotation = path.get('typeAnnotation'); let value: TypeDescriptor; + if (typeAnnotation.hasNode()) { value = getTSTypeWithResolvedTypes(typeAnnotation, typeParams); } else { @@ -285,6 +294,7 @@ function handleTSFunctionType( let returnType: TypeDescriptor | undefined; const annotation = path.get('typeAnnotation'); + if (annotation.hasNode()) { returnType = getTSTypeWithResolvedTypes(annotation, typeParams); } @@ -314,10 +324,12 @@ function handleTSFunctionType( if (param.node.name === 'this') { type.signature.this = arg.type; + return; } } else { const restArgument = (param as NodePath).get('argument'); + if (restArgument.isIdentifier()) { arg.name = restArgument.node.name; } else { @@ -354,12 +366,14 @@ function handleTSTypeQuery( typeParams: TypeParameters | null, ): TypeDescriptor { const resolvedPath = resolveToValue(path.get('exprName')); + if ('typeAnnotation' in resolvedPath.node) { return getTSTypeWithResolvedTypes( resolvedPath.get('typeAnnotation') as NodePath, typeParams, ); } + // @ts-ignore Do we need to handle TsQualifiedName here TODO return { name: path.node.exprName.name }; } @@ -372,6 +386,7 @@ function handleTSTypeOperator( } let value: NodePath = path.get('typeAnnotation'); + if (value.isTSTypeQuery()) { value = value.get('exprName'); } else if ('id' in value.node) { @@ -379,6 +394,7 @@ function handleTSTypeOperator( } const resolvedPath = resolveToValue(value); + if ( resolvedPath && (resolvedPath.isObjectExpression() || resolvedPath.isTSTypeLiteral()) @@ -422,9 +438,11 @@ function handleTSIndexedAccessType( // indexType.value = "'foo'" return indexType.value && p.key === indexType.value.replace(/['"]+/g, ''); }); + if (!resolvedType) { return { name: 'unknown' }; } + return { name: resolvedType.value.name, raw: printValue(path), @@ -447,6 +465,7 @@ function getTSTypeWithResolvedTypes( const node = path.node; let type: TypeDescriptor; let typeAliasName: string | null = null; + if (path.parentPath.isTSTypeAliasDeclaration()) { typeAliasName = path.parentPath.node.id.name; } @@ -472,6 +491,7 @@ function getTSTypeWithResolvedTypes( type = { name: tsTypes[node.type] }; } else if (path.isTSLiteralType()) { const literal = path.get('literal'); + type = { name: 'literal', value: printValue(literal), @@ -506,6 +526,7 @@ export default function getTSType( // After: cleanup memory after we are done here visitedTypes = {}; const type = getTSTypeWithResolvedTypes(path, typeParamMap); + visitedTypes = {}; return type; diff --git a/src/utils/getTypeAnnotation.ts b/src/utils/getTypeAnnotation.ts index bd8a178e9e9..363bfc8f00b 100644 --- a/src/utils/getTypeAnnotation.ts +++ b/src/utils/getTypeAnnotation.ts @@ -11,6 +11,7 @@ export default function getTypeAnnotation( if (!path.has('typeAnnotation')) return null; let resultPath = path; + do { resultPath = resultPath.get('typeAnnotation') as NodePath; } while ( diff --git a/src/utils/getTypeFromReactComponent.ts b/src/utils/getTypeFromReactComponent.ts index a5227f0f398..cdf44c86324 100644 --- a/src/utils/getTypeFromReactComponent.ts +++ b/src/utils/getTypeFromReactComponent.ts @@ -26,10 +26,13 @@ import getTypeIdentifier from './getTypeIdentifier'; function getStatelessPropsPath(componentDefinition: NodePath): NodePath { const value = resolveToValue(componentDefinition); + if (isReactForwardRefCall(value)) { const inner = resolveToValue(value.get('arguments')[0]); + return inner.get('params')[0]; } + return value.get('params')[0]; } @@ -46,9 +49,11 @@ export default (path: NodePath): NodePath | null => { if (superTypes.hasNode()) { const params = superTypes.get('params'); + typePath = params[params.length === 3 ? 1 : 0]; } else { const propsMemberPath = getMemberValuePath(path, 'props'); + if (!propsMemberPath) { return null; } @@ -112,6 +117,7 @@ export function applyToTypeProperties( // The react-docgen output format does not currently allow // for the expression of union types const typePath = resolveGenericTypeAnnotation(path); + if (typePath) { applyToTypeProperties(documentation, typePath, callback, typeParams); } @@ -130,6 +136,7 @@ function applyExtends( > ).forEach(extendsPath => { const resolvedPath = resolveGenericTypeAnnotation(extendsPath); + if (resolvedPath) { if ( resolvedPath.has('typeParameters') && @@ -148,6 +155,7 @@ function applyExtends( applyToTypeProperties(documentation, resolvedPath, callback, typeParams); } else { const idPath = getTypeIdentifier(extendsPath); + if (idPath && idPath.isIdentifier()) { documentation.addComposes(idPath.node.name); } diff --git a/src/utils/getTypeParameters.ts b/src/utils/getTypeParameters.ts index 23fefb6e5fe..27e40a5cf28 100644 --- a/src/utils/getTypeParameters.ts +++ b/src/utils/getTypeParameters.ts @@ -26,6 +26,7 @@ export default function getTypeParameters( const numInstantiationParams = instantiation.node.params.length; let i = 0; + declaration.get('params').forEach(paramPath => { const key = paramPath.node.name; const defaultTypePath = paramPath.node.default diff --git a/src/utils/isExportsOrModuleAssignment.ts b/src/utils/isExportsOrModuleAssignment.ts index 30b84b07aa5..d879b5cf509 100644 --- a/src/utils/isExportsOrModuleAssignment.ts +++ b/src/utils/isExportsOrModuleAssignment.ts @@ -17,6 +17,7 @@ export default function isExportsOrModuleAssignment(path: NodePath): boolean { } const exprArr = expressionTo.Array(path.get('left')); + return ( (exprArr[0] === 'module' && exprArr[1] === 'exports') || exprArr[0] === 'exports' diff --git a/src/utils/isReactBuiltinCall.ts b/src/utils/isReactBuiltinCall.ts index 294f50a2500..0fc3cfde71a 100644 --- a/src/utils/isReactBuiltinCall.ts +++ b/src/utils/isReactBuiltinCall.ts @@ -62,6 +62,7 @@ export default function isReactBuiltinCall( } const value = resolveToValue(path.get('callee')); + if (value === path.get('callee')) { return false; } diff --git a/src/utils/isReactComponentClass.ts b/src/utils/isReactComponentClass.ts index c999bf1bc89..f099d610be7 100644 --- a/src/utils/isReactComponentClass.ts +++ b/src/utils/isReactComponentClass.ts @@ -24,6 +24,7 @@ function isRenderMethod(path: NodePath): boolean { } const key = path.get('key') as NodePath; + if (!key.isIdentifier() || key.node.name !== 'render') { return false; } @@ -57,6 +58,7 @@ export default function isReactComponentClass( isDestructuringAssignment(superClass, 'PureComponent') ) { const module = resolveToModule(superClass); + if (module && isReactModuleName(module)) { return true; } diff --git a/src/utils/isReactComponentMethod.ts b/src/utils/isReactComponentMethod.ts index 823d06edea9..baddb146df7 100644 --- a/src/utils/isReactComponentMethod.ts +++ b/src/utils/isReactComponentMethod.ts @@ -32,5 +32,6 @@ export default function (methodPath: NodePath): boolean { } const name = getPropertyName(methodPath); + return Boolean(name && componentMethods.indexOf(name) !== -1); } diff --git a/src/utils/isReactCreateClassCall.ts b/src/utils/isReactCreateClassCall.ts index 8aaf9f33781..944fdbf713e 100644 --- a/src/utils/isReactCreateClassCall.ts +++ b/src/utils/isReactCreateClassCall.ts @@ -18,6 +18,7 @@ function isReactCreateClassCallModular(path: NodePath): boolean { return false; } const module = resolveToModule(path); + return Boolean(module && module === 'create-react-class'); } diff --git a/src/utils/isStatelessComponent.ts b/src/utils/isStatelessComponent.ts index 4345e84dc7a..51461c7fdec 100644 --- a/src/utils/isStatelessComponent.ts +++ b/src/utils/isStatelessComponent.ts @@ -90,6 +90,7 @@ function resolvesToJSXElementOrReactCall( const namesToResolve: NodePath[] = []; const calleeObj = calleeValue.get('object'); + if (calleeObj.isIdentifier()) { namesToResolve.push(calleeValue.get('property')); resolvedValue = resolveToValue(calleeObj); @@ -122,6 +123,7 @@ function resolvesToJSXElementOrReactCall( return resolveToValue(result); } } + return result; }, resolvedValue, @@ -170,6 +172,7 @@ function returnsJSXElementOrReactCall( // Only check return statements which are part of the checked function scope if (returnPath.scope.getFunctionParent() !== scope) { path.skip(); + return; } diff --git a/src/utils/match.ts b/src/utils/match.ts index e88957e3ea2..9b9552065af 100644 --- a/src/utils/match.ts +++ b/src/utils/match.ts @@ -23,5 +23,6 @@ export default function match(node: Node, pattern: Pattern): boolean { return false; } } + return true; } diff --git a/src/utils/normalizeClassDefinition.ts b/src/utils/normalizeClassDefinition.ts index 8788665b76b..6745054ec4b 100644 --- a/src/utils/normalizeClassDefinition.ts +++ b/src/utils/normalizeClassDefinition.ts @@ -33,6 +33,7 @@ export default function normalizeClassDefinition( classDefinition: NodePath, ): void { let variableName; + if (classDefinition.isClassDeclaration()) { // Class declarations may not have an id, e.g.: `export default class extends React.Component {}` if (classDefinition.node.id) { @@ -40,6 +41,7 @@ export default function normalizeClassDefinition( } } else if (classDefinition.isClassExpression()) { let parentPath: NodePath | null = classDefinition.parentPath; + while ( parentPath && parentPath.node !== classDefinition.scope.block && @@ -47,12 +49,14 @@ export default function normalizeClassDefinition( ) { if (parentPath.isVariableDeclarator()) { const idPath = parentPath.get('id'); + if (idPath.isIdentifier()) { variableName = idPath.node.name; break; } } else if (parentPath.isAssignmentExpression()) { const leftPath = parentPath.get('left'); + if (leftPath.isIdentifier()) { variableName = leftPath.node.name; break; @@ -67,6 +71,7 @@ export default function normalizeClassDefinition( } const scopeBlock = classDefinition.parentPath.scope.block; + classDefinition.parentPath.scope.traverse(scopeBlock, { Function: ignore, ClassDeclaration: ignore, @@ -75,10 +80,13 @@ export default function normalizeClassDefinition( ForStatement: ignore, AssignmentExpression(path) { const left = path.get('left'); + if (left.isMemberExpression()) { const first = getMemberExpressionRoot(left); + if (first.isIdentifier() && first.node.name === variableName) { const [member] = getMembers(left); + if ( member && !member.path.has('computed') && @@ -92,6 +100,7 @@ export default function normalizeClassDefinition( false, true, ); + classDefinition.get('body').unshiftContainer('body', property); path.skip(); path.remove(); diff --git a/src/utils/parseJsDoc.ts b/src/utils/parseJsDoc.ts index c2d1caa8b86..2748588a032 100644 --- a/src/utils/parseJsDoc.ts +++ b/src/utils/parseJsDoc.ts @@ -72,6 +72,7 @@ function getType(tagType: Type | null | undefined): JsDocType | null { 'name' in tagType.expression ? tagType.expression.name : null; + if (typeName) { return { name: typeName }; } else { @@ -90,12 +91,14 @@ function getReturnsJsDoc(jsDoc: Annotation): JsDocProperty | null { const returnTag = jsDoc.tags.find( tag => tag.title === 'return' || tag.title === 'returns', ); + if (returnTag) { return { description: returnTag.description, type: getType(returnTag.type), }; } + return null; } @@ -104,6 +107,7 @@ function getParamsJsDoc(jsDoc: Annotation): JsDocParam[] { if (!jsDoc.tags) { return []; } + return jsDoc.tags .filter(tag => tag.title === 'param') .map(tag => { diff --git a/src/utils/resolveComponentDefinition.ts b/src/utils/resolveComponentDefinition.ts index 03cbfc200d9..22df7337e93 100644 --- a/src/utils/resolveComponentDefinition.ts +++ b/src/utils/resolveComponentDefinition.ts @@ -24,6 +24,7 @@ export default function resolveComponentDefinition( if (isReactCreateClassCall(definition)) { // return argument const resolvedPath = resolveToValue(definition.get('arguments')[0]); + if (resolvedPath.isObjectExpression()) { return resolvedPath; } diff --git a/src/utils/resolveExportDeclaration.ts b/src/utils/resolveExportDeclaration.ts index e074095691d..2973eb4ed65 100644 --- a/src/utils/resolveExportDeclaration.ts +++ b/src/utils/resolveExportDeclaration.ts @@ -9,11 +9,13 @@ export default function resolveExportDeclaration( path: NodePath, ): NodePath[] { const definitions: NodePath[] = []; + if (path.isExportDefaultDeclaration()) { definitions.push(path.get('declaration')); } else if (path.isExportNamedDeclaration()) { if (path.has('declaration')) { const declaration = path.get('declaration'); + if (declaration.isVariableDeclaration()) { declaration .get('declarations') @@ -29,5 +31,6 @@ export default function resolveExportDeclaration( ); } } + return definitions.map(definition => resolveToValue(definition)); } diff --git a/src/utils/resolveFunctionDefinitionToReturnValue.ts b/src/utils/resolveFunctionDefinitionToReturnValue.ts index 3733a2da179..3009a8a0ca2 100644 --- a/src/utils/resolveFunctionDefinitionToReturnValue.ts +++ b/src/utils/resolveFunctionDefinitionToReturnValue.ts @@ -11,10 +11,12 @@ export default function resolveFunctionDefinitionToReturnValue( let returnPath: NodePath | null = null; const body = path.get('body'); + traverseShallow(body, { Function: ignore, ReturnStatement: nodePath => { const argument = nodePath.get('argument'); + if (argument.hasNode()) { returnPath = resolveToValue(argument); } diff --git a/src/utils/resolveHOC.ts b/src/utils/resolveHOC.ts index 86e343a35b3..783a8dc267a 100644 --- a/src/utils/resolveHOC.ts +++ b/src/utils/resolveHOC.ts @@ -17,6 +17,7 @@ export default function resolveHOC(path: NodePath): NodePath { ) { const node = path.node; const argumentLength = node.arguments.length; + if (argumentLength && argumentLength > 0) { const args = path.get('arguments'); const firstArg = args[0]; diff --git a/src/utils/resolveObjectKeysToArray.ts b/src/utils/resolveObjectKeysToArray.ts index 63458acd0be..a72428e2a06 100644 --- a/src/utils/resolveObjectKeysToArray.ts +++ b/src/utils/resolveObjectKeysToArray.ts @@ -37,6 +37,7 @@ function isWhitelistedObjectProperty(path: NodePath): boolean { (path.node.kind === 'get' || path.node.kind === 'set')) ) { const key = path.get('key') as NodePath; + return ( (key.isIdentifier() && !path.node.computed) || key.isStringLiteral() || @@ -73,6 +74,7 @@ export function resolveObjectToNameArray( const properties = objectPath.isTSTypeLiteral() ? objectPath.get('members') : (objectPath.get('properties') as NodePath[]); + properties.forEach(propPath => { if (error) return; @@ -99,18 +101,22 @@ export function resolveObjectToNameArray( propPath.isObjectTypeSpreadProperty() ) { let spreadObject = resolveToValue(propPath.get('argument') as NodePath); + if (spreadObject.isGenericTypeAnnotation()) { const typeAliasRight = resolveToValue(spreadObject.get('id')).get( 'right', ) as NodePath; + if (typeAliasRight.isObjectTypeAnnotation()) { spreadObject = resolveToValue(typeAliasRight); } } const spreadValues = resolveObjectToNameArray(spreadObject); + if (!spreadValues) { error = true; + return; } values = [...values, ...spreadValues]; diff --git a/src/utils/resolveObjectValuesToArray.ts b/src/utils/resolveObjectValuesToArray.ts index 3c84fc9f940..dbcca0beaff 100644 --- a/src/utils/resolveObjectValuesToArray.ts +++ b/src/utils/resolveObjectValuesToArray.ts @@ -24,6 +24,7 @@ function isObjectValuesCall(path: NodePath): path is NodePath { } const callee = path.get('callee'); + if (!callee.isMemberExpression()) { return false; } @@ -96,6 +97,7 @@ export function resolveObjectToPropMap( | SpreadElement > >); + members.forEach(propPath => { if (error || propPath.isObjectMethod()) return; @@ -132,8 +134,10 @@ export function resolveObjectToPropMap( propPath.isObjectTypeSpreadProperty() ) { let spreadObject = resolveToValue(propPath.get('argument') as NodePath); + if (spreadObject.isGenericTypeAnnotation()) { const typeAlias = resolveToValue(spreadObject.get('id')); + if ( typeAlias.isTypeAlias() && typeAlias.get('right').isObjectTypeAnnotation() @@ -143,8 +147,10 @@ export function resolveObjectToPropMap( } const spreadValues = resolveObjectToPropMap(spreadObject); + if (!spreadValues) { error = true; + return; } spreadValues.properties.forEach(spreadProp => { diff --git a/src/utils/resolveToModule.ts b/src/utils/resolveToModule.ts index 24b8c6be423..1f2682a0530 100644 --- a/src/utils/resolveToModule.ts +++ b/src/utils/resolveToModule.ts @@ -15,6 +15,7 @@ export default function resolveToModule(path: NodePath): string | null { } } else if (path.isCallExpression()) { const callee = path.get('callee'); + if (callee.isIdentifier() && callee.node.name === 'require') { return (path.node.arguments[0] as StringLiteral).value; } @@ -22,6 +23,7 @@ export default function resolveToModule(path: NodePath): string | null { return resolveToModule(callee); } else if (path.isIdentifier() || path.isJSXIdentifier()) { const valuePath = resolveToValue(path); + if (valuePath !== path) { return resolveToModule(valuePath); } diff --git a/src/utils/resolveToValue.ts b/src/utils/resolveToValue.ts index 00f99ffc535..081d6750bd2 100644 --- a/src/utils/resolveToValue.ts +++ b/src/utils/resolveToValue.ts @@ -20,12 +20,14 @@ function findScopePath( ): NodePath | null { if (bindingIdentifiers && bindingIdentifiers.length >= 1) { const resolvedParentPath = bindingIdentifiers[0].parentPath; + if ( resolvedParentPath.isImportDefaultSpecifier() || resolvedParentPath.isImportSpecifier() ) { // TODO TESTME let exportName: string | undefined; + if (resolvedParentPath.isImportDefaultSpecifier()) { exportName = 'default'; } else { @@ -72,6 +74,7 @@ function findLastAssignedValue( traverseShallow(path, { AssignmentExpression(assignmentPath) { const left = assignmentPath.get('left'); + // Skip anything that is not an assignment to a variable with the // passed name. // Ensure the LHS isn't the reference we're trying to resolve. @@ -85,6 +88,7 @@ function findLastAssignedValue( } // Ensure the RHS doesn't contain the reference we're trying to resolve. const candidatePath = assignmentPath.get('right'); + for ( let p: NodePath | null = idPath; p && p.node != null; @@ -95,6 +99,7 @@ function findLastAssignedValue( } } results.push(candidatePath); + return assignmentPath.skip(); }, }); @@ -104,6 +109,7 @@ function findLastAssignedValue( if (resultPath == null) { return null; } + return resolveToValue(resultPath); } @@ -122,8 +128,10 @@ export default function resolveToValue(path: NodePath): NodePath { } else if (path.isMemberExpression()) { const root = getMemberExpressionRoot(path); const resolved = resolveToValue(root); + if (resolved.isObjectExpression()) { let propertyPath: NodePath | null = resolved; + for (const propertyName of toArray(path).slice(1)) { if (propertyPath && propertyPath.isObjectExpression()) { propertyPath = getPropertyValuePath(propertyPath, propertyName); @@ -133,14 +141,17 @@ export default function resolveToValue(path: NodePath): NodePath { } propertyPath = resolveToValue(propertyPath); } + return propertyPath; } else if (isSupportedDefinitionType(resolved)) { const property = path.get('property'); + if (property.isIdentifier() || property.isStringLiteral()) { const memberPath = getMemberValuePath( resolved, property.isIdentifier() ? property.node.name : property.node.value, // TODO TESTME ); + if (memberPath) { return resolveToValue(memberPath); } @@ -160,6 +171,7 @@ export default function resolveToValue(path: NodePath): NodePath { ((root.parentPath.node as MemberExpression).property as Identifier) .name, // TODO TESTME Idk what that is ); + if (resolvedPath) { return resolveToValue(resolvedPath); } @@ -195,6 +207,7 @@ export default function resolveToValue(path: NodePath): NodePath { const binding = path.scope.getBinding(path.node.name); let resolvedPath: NodePath | null = null; + if (binding) { // The variable may be assigned a different value after initialization. // We are first trying to find all assignments to the variable in the @@ -205,16 +218,19 @@ export default function resolveToValue(path: NodePath): NodePath { const bindingMap = binding.path.getOuterBindingIdentifierPaths( true, ) as Record>>; + resolvedPath = findScopePath(bindingMap[path.node.name]); } } else { // Initialize our monkey-patching of @babel/traverse 🙈 initialize(Scope); const typeBinding = path.scope.getTypeBinding(path.node.name); + if (typeBinding) { resolvedPath = findScopePath([typeBinding.identifierPath]); } } + return resolvedPath || path; } diff --git a/src/utils/setPropDescription.ts b/src/utils/setPropDescription.ts index efae3639bad..f54a30367e0 100644 --- a/src/utils/setPropDescription.ts +++ b/src/utils/setPropDescription.ts @@ -16,9 +16,11 @@ export default function setPropDescription( >, ): void { const propName = getPropertyName(propertyPath); + if (!propName) return; const propDescriptor = documentation.getPropDescriptor(propName); + if (propDescriptor.description) return; propDescriptor.description = getDocblock(propertyPath) || ''; diff --git a/src/utils/ts-types/index.ts b/src/utils/ts-types/index.ts index ee51ea5204c..6db5cd0ed76 100644 --- a/src/utils/ts-types/index.ts +++ b/src/utils/ts-types/index.ts @@ -74,6 +74,7 @@ function registerTypeBinding( bindingPath: NodePath, ): void { const ids = { [path.node.name]: [path.node] }; + // TODO remove loop as always one identifier? for (const name of Object.keys(ids)) { for (const id of ids[name]) { diff --git a/tests/setupTestFramework.ts b/tests/setupTestFramework.ts index 77e66248927..7f36e0b562b 100644 --- a/tests/setupTestFramework.ts +++ b/tests/setupTestFramework.ts @@ -22,6 +22,7 @@ const matchers = { // the next Node it finds even if value is an array const receivedNode = received.node; let expectedNode: Node; + if (expected instanceof NodePath) { expectedNode = expected.node; } else { diff --git a/tests/utils.ts b/tests/utils.ts index 21bdc59fcb7..3da908431dd 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -174,6 +174,7 @@ function buildTestParser(parseFunction: Parse): Parse { options = importer; importer = noopImporter; } + return this.statement(src, importer, options, -1); }; @@ -187,6 +188,7 @@ function buildTestParser(parseFunction: Parse): Parse { options = importer; importer = noopImporter; } + return this.statement( `(${src})`, importer, @@ -204,6 +206,7 @@ function buildTestParser(parseFunction: Parse): Parse { options = importer; importer = noopImporter; } + return this.statement(src, importer, options, -1).get( 'expression', ) as unknown as NodePath; @@ -256,6 +259,7 @@ export function makeMockImporter( return cache[source]; }; + afterEach(() => { cache = Object.create(null); }); diff --git a/website/src/components/App.js b/website/src/components/App.js index 843eeb8d8a8..50523c1b880 100644 --- a/website/src/components/App.js +++ b/website/src/components/App.js @@ -72,6 +72,7 @@ export default class App extends React.Component { this._jsonRef = React.createRef(); const options = this.buildOptions('js'); + this.state = { value: this.compile(codeSample, options), mode: 'application/json', @@ -107,6 +108,7 @@ export default class App extends React.Component { plugins: [...defaultPlugins], }, }; + switch (language) { case 'ts': options.parserOptions.plugins.push('typescript'); diff --git a/website/src/components/CodeMirrorPanel.js b/website/src/components/CodeMirrorPanel.js index 642d83a7274..363705318ae 100644 --- a/website/src/components/CodeMirrorPanel.js +++ b/website/src/components/CodeMirrorPanel.js @@ -2,7 +2,6 @@ import React from 'react'; import CodeMirror from 'codemirror'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/jsx/jsx'; - import 'codemirror/addon/fold/foldgutter'; import 'codemirror/addon/fold/brace-fold'; import 'codemirror/addon/fold/comment-fold'; @@ -35,6 +34,7 @@ export default class CodeMirrorPanel extends React.Component { }, this.props, ); + delete options.value; delete options.onChange; delete options.codeSample; From c178110ffe9995dd1244afb512429738163ddf58 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Fri, 29 Jul 2022 01:00:39 +0200 Subject: [PATCH 25/44] chore: Add test for isReactModuleName --- src/utils/__tests__/isReactModuleName-test.ts | 21 +++++++++++++++++++ src/utils/isReactModuleName.ts | 2 -- 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/utils/__tests__/isReactModuleName-test.ts diff --git a/src/utils/__tests__/isReactModuleName-test.ts b/src/utils/__tests__/isReactModuleName-test.ts new file mode 100644 index 00000000000..f755c44db11 --- /dev/null +++ b/src/utils/__tests__/isReactModuleName-test.ts @@ -0,0 +1,21 @@ +import isReactModuleName from '../isReactModuleName'; + +describe('isReactModuleName', () => { + const reactModules = [ + 'react', + 'react/addons', + 'react-native', + 'proptypes', + 'prop-types', + ]; + + reactModules.forEach(module => { + it(`returns true for ${module}`, () => { + expect(isReactModuleName(module)).toBe(true); + }); + }); + + it(`returns false by default`, () => { + expect(isReactModuleName('not-react')).toBe(false); + }); +}); diff --git a/src/utils/isReactModuleName.ts b/src/utils/isReactModuleName.ts index 8705c1712b8..6261737027c 100644 --- a/src/utils/isReactModuleName.ts +++ b/src/utils/isReactModuleName.ts @@ -9,8 +9,6 @@ const reactModules = [ /** * Takes a module name (string) and returns true if it refers to a root react * module name. - * - * TODO TESTME */ export default function isReactModuleName(moduleName: string): boolean { return reactModules.includes(moduleName.toLowerCase()); From a1d81f11a9c86c3087a0341e5bc21e1c655643fd Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Fri, 29 Jul 2022 01:02:34 +0200 Subject: [PATCH 26/44] fix: Simplify resolveObjectValuesToArray and remove type handling BREAKING CHANGE: The return values of `resolveObjectValuesToArray` are now in the order they are defined in the source code. --- .../__snapshots__/getPropType-test.ts.snap | 8 +- .../resolveObjectValuesToArray-test.ts.snap | 10 +- src/utils/index.ts | 5 +- src/utils/resolveObjectValuesToArray.ts | 164 ++++-------------- 4 files changed, 46 insertions(+), 141 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/getPropType-test.ts.snap b/src/utils/__tests__/__snapshots__/getPropType-test.ts.snap index 23477fa8d86..ce9c700ac8d 100644 --- a/src/utils/__tests__/__snapshots__/getPropType-test.ts.snap +++ b/src/utils/__tests__/__snapshots__/getPropType-test.ts.snap @@ -208,11 +208,11 @@ Object { "value": Array [ Object { "computed": false, - "value": "\\"bar\\"", + "value": "\\"foo\\"", }, Object { "computed": false, - "value": "\\"foo\\"", + "value": "\\"bar\\"", }, ], } @@ -348,11 +348,11 @@ Object { "value": Array [ Object { "computed": false, - "value": "\\"bar\\"", + "value": "\\"foo\\"", }, Object { "computed": false, - "value": "\\"foo\\"", + "value": "\\"bar\\"", }, ], } diff --git a/src/utils/__tests__/__snapshots__/resolveObjectValuesToArray-test.ts.snap b/src/utils/__tests__/__snapshots__/resolveObjectValuesToArray-test.ts.snap index 739978487a8..d9e4ffc5ba0 100644 --- a/src/utils/__tests__/__snapshots__/resolveObjectValuesToArray-test.ts.snap +++ b/src/utils/__tests__/__snapshots__/resolveObjectValuesToArray-test.ts.snap @@ -15,17 +15,17 @@ Array [ exports[`resolveObjectValuesToArray can resolve spreads from imported objects 1`] = ` Array [ - "\\"bar\\"", - "\\"baz\\"", "\\"foo\\"", + "\\"baz\\"", + "\\"bar\\"", ] `; exports[`resolveObjectValuesToArray resolves Object.values but ignores duplicates 1`] = ` Array [ "1", - "5", "2", + "5", ] `; @@ -48,8 +48,8 @@ Array [ exports[`resolveObjectValuesToArray resolves Object.values when using resolvable spread 1`] = ` Array [ "1", - "4", "2", + "4", ] `; @@ -62,8 +62,8 @@ Array [ exports[`resolveObjectValuesToArray resolves Object.values with literals as computed key 1`] = ` Array [ - "2", "1", + "2", ] `; diff --git a/src/utils/index.ts b/src/utils/index.ts index d4feccddcfa..41c48628719 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -57,10 +57,7 @@ export { default as resolveObjectKeysToArray, resolveObjectToNameArray, } from './resolveObjectKeysToArray'; -export { - default as resolveObjectValuesToArray, - resolveObjectToPropMap, -} from './resolveObjectValuesToArray'; +export { default as resolveObjectValuesToArray } from './resolveObjectValuesToArray'; export { default as resolveToModule } from './resolveToModule'; export { default as resolveToValue } from './resolveToValue'; export { default as setPropDescription } from './setPropDescription'; diff --git a/src/utils/resolveObjectValuesToArray.ts b/src/utils/resolveObjectValuesToArray.ts index dbcca0beaff..9a7b0f56dfa 100644 --- a/src/utils/resolveObjectValuesToArray.ts +++ b/src/utils/resolveObjectValuesToArray.ts @@ -4,20 +4,9 @@ import type { CallExpression, Identifier, NumericLiteral, - ObjectMethod, - ObjectProperty, - ObjectTypeProperty, - ObjectTypeSpreadProperty, - SpreadElement, StringLiteral, - TSPropertySignature, } from '@babel/types'; -interface ObjectPropMap { - properties: string[]; - values: Record; -} - function isObjectValuesCall(path: NodePath): path is NodePath { if (!path.isCallExpression() || path.node.arguments.length !== 1) { return false; @@ -39,113 +28,43 @@ function isObjectValuesCall(path: NodePath): path is NodePath { ); } -function isWhitelistedObjectProperty(prop: NodePath): boolean { - return ( - (prop.isObjectProperty() && - ((prop.get('key').isIdentifier() && !prop.node.computed) || - prop.get('key').isStringLiteral() || - prop.get('key').isNumericLiteral())) || - (prop.isObjectMethod() && - ((prop.get('key').isIdentifier() && !prop.node.computed) || - prop.get('key').isStringLiteral() || - prop.get('key').isNumericLiteral())) || - prop.isSpreadElement() - ); -} - -function isWhiteListedObjectTypeProperty(prop: NodePath): boolean { - return ( - prop.isObjectTypeProperty() || - prop.isObjectTypeSpreadProperty() || - prop.isTSPropertySignature() - ); -} - // Resolves an ObjectExpression or an ObjectTypeAnnotation -export function resolveObjectToPropMap( - object: NodePath, - raw = false, -): ObjectPropMap | null { - if ( - (object.isObjectExpression() && - object.get('properties').every(isWhitelistedObjectProperty)) || - (object.isObjectTypeAnnotation() && - object.get('properties').every(isWhiteListedObjectTypeProperty)) || - (object.isTSTypeLiteral() && - object.get('members').every(isWhiteListedObjectTypeProperty)) - ) { - const properties: string[] = []; - let values = {}; +function resolveObjectToPropMap(object: NodePath): Map | null { + if (object.isObjectExpression()) { + const values = new Map(); let error = false; - const members: Array< - NodePath< - | ObjectMethod - | ObjectProperty - | ObjectTypeProperty - | ObjectTypeSpreadProperty - | SpreadElement - | TSPropertySignature - > - > = object.isTSTypeLiteral() - ? (object.get('members') as Array>) - : (object.get('properties') as Array< - NodePath< - | ObjectMethod - | ObjectProperty - | ObjectTypeProperty - | ObjectTypeSpreadProperty - | SpreadElement - > - >); - - members.forEach(propPath => { + + object.get('properties').forEach(propPath => { if (error || propPath.isObjectMethod()) return; - if ( - propPath.isObjectProperty() || - propPath.isObjectTypeProperty() || - propPath.isTSPropertySignature() - ) { + if (propPath.isObjectProperty()) { const key = propPath.get('key') as NodePath< Identifier | NumericLiteral | StringLiteral >; + let name: string; + // Key is either Identifier or Literal - // TODO check this also for TSPropertySignature and ObjectTypeProperty - // TODO reimplement, this has so many issues - // Identifiers as values are not followed at all - // TSPropertySignature is not handled correctly here - const name: string = key.isIdentifier() - ? key.node.name - : raw - ? (key.node.extra?.raw as string) - : `${(key as NodePath).node.value}`; - const value = - // @ts-ignore - propPath.node.value.value || - // @ts-ignore - (raw ? propPath.node.value.raw : propPath.node.value.value); - - if (properties.indexOf(name) === -1) { - properties.push(name); - } - values[name] = value; - } else if ( - propPath.isSpreadElement() || - propPath.isObjectTypeSpreadProperty() - ) { - let spreadObject = resolveToValue(propPath.get('argument') as NodePath); - - if (spreadObject.isGenericTypeAnnotation()) { - const typeAlias = resolveToValue(spreadObject.get('id')); - - if ( - typeAlias.isTypeAlias() && - typeAlias.get('right').isObjectTypeAnnotation() - ) { - spreadObject = resolveToValue(typeAlias.get('right')); - } + if (key.isIdentifier()) { + name = key.node.name; + } else if (key.isNumericLiteral() || key.isStringLiteral()) { + name = `${key.node.value}`; + } else { + error = true; + + return; } + // Identifiers as values are not followed at all + const valuePath = propPath.get('value'); + const value = valuePath.isStringLiteral() + ? `"${valuePath.node.value}"` + : valuePath.isNumericLiteral() + ? `${valuePath.node.value}` + : 'null'; + + values.set(name, value); + } else if (propPath.isSpreadElement()) { + const spreadObject = resolveToValue(propPath.get('argument')); const spreadValues = resolveObjectToPropMap(spreadObject); if (!spreadValues) { @@ -153,17 +72,16 @@ export function resolveObjectToPropMap( return; } - spreadValues.properties.forEach(spreadProp => { - if (properties.indexOf(spreadProp) === -1) { - properties.push(spreadProp); - } - }); - values = { ...values, ...spreadValues.values }; + for (const entry of spreadValues.entries()) { + const [key, value] = entry; + + values.set(key, value); + } } }); if (!error) { - return { properties: properties.sort(), values }; + return values; } } @@ -184,20 +102,10 @@ export default function resolveObjectValuesToArray( ): string[] | null { if (isObjectValuesCall(path)) { const objectExpression = resolveToValue(path.get('arguments')[0]); - const propMap = resolveObjectToPropMap(objectExpression); - - if (propMap) { - const nodes = propMap.properties.map(prop => { - const value = propMap.values[prop]; - - return typeof value === 'undefined' - ? 'null' - : typeof value === 'string' - ? `"${value}"` - : `${value}`; - }); + const values = resolveObjectToPropMap(objectExpression); - return nodes; + if (values) { + return Array.from(values.values()); } } From a3f2072e6dd839e405d2bef64f93ba7c4b9c49e2 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 31 Jul 2022 00:27:53 +0200 Subject: [PATCH 27/44] feat: Add support for resolving destructuring in resolveToValue --- src/FileState.ts | 23 +-- src/__tests__/__snapshots__/main-test.ts.snap | 26 ++++ .../fixtures/support/other-exports.ts | 1 + .../fixtures/support/some-exports.ts | 5 + src/__tests__/fixtures/test-all-imports.tsx | 9 ++ src/__tests__/main-test.ts | 11 +- src/importer/makeFsImporter.ts | 131 +++++++++++------- ...eObjectPatternPropertyToValue-test.ts.snap | 23 +++ ...esolveObjectPatternPropertyToValue-test.ts | 93 +++++++++++++ src/utils/index.ts | 1 + .../resolveObjectPatternPropertyToValue.ts | 48 +++++++ src/utils/resolveToValue.ts | 81 ++++++----- 12 files changed, 350 insertions(+), 102 deletions(-) create mode 100644 src/__tests__/fixtures/support/other-exports.ts create mode 100644 src/__tests__/fixtures/support/some-exports.ts create mode 100644 src/__tests__/fixtures/test-all-imports.tsx create mode 100644 src/utils/__tests__/__snapshots__/resolveObjectPatternPropertyToValue-test.ts.snap create mode 100644 src/utils/__tests__/resolveObjectPatternPropertyToValue-test.ts create mode 100644 src/utils/resolveObjectPatternPropertyToValue.ts diff --git a/src/FileState.ts b/src/FileState.ts index 56696681b45..a04c077cb8e 100644 --- a/src/FileState.ts +++ b/src/FileState.ts @@ -61,22 +61,29 @@ export default class FileState { this.scope = this.path.scope; } + /** + * Try to resolve and import with the `name` + */ import(path: ImportPath, name: string): NodePath | null { return this.#importer(path, name, this); } /** - * Parse a new file + * Parse the content of a new file + * The filename is required so that potential imports inside the content can be correctly resolved */ - parse(code: string): FileState { + parse(code: string, filename: string): FileState { const ast = this.#parser(code); - return new FileState(this.opts, { - ast, - code, - importer: this.#importer, - parser: this.#parser, - }); + return new FileState( + { ...this.opts, filename }, + { + ast, + code, + importer: this.#importer, + parser: this.#parser, + }, + ); } /** diff --git a/src/__tests__/__snapshots__/main-test.ts.snap b/src/__tests__/__snapshots__/main-test.ts.snap index e62b9ee6520..6036ba114ef 100644 --- a/src/__tests__/__snapshots__/main-test.ts.snap +++ b/src/__tests__/__snapshots__/main-test.ts.snap @@ -2244,3 +2244,29 @@ Array [ }, ] `; + +exports[`main fixtures processes component "test-all-imports.tsx" without errors 1`] = ` +Array [ + Object { + "description": "This is a TS component with imported stuff", + "displayName": "ImportedExtendedComponent", + "methods": Array [], + "props": Object { + "x": Object { + "defaultValue": Object { + "computed": false, + "value": "\\"string\\"", + }, + "required": false, + }, + "y": Object { + "defaultValue": Object { + "computed": false, + "value": "'otherstring'", + }, + "required": false, + }, + }, + }, +] +`; diff --git a/src/__tests__/fixtures/support/other-exports.ts b/src/__tests__/fixtures/support/other-exports.ts new file mode 100644 index 00000000000..129c265f93d --- /dev/null +++ b/src/__tests__/fixtures/support/other-exports.ts @@ -0,0 +1 @@ +export default 'otherstring' diff --git a/src/__tests__/fixtures/support/some-exports.ts b/src/__tests__/fixtures/support/some-exports.ts new file mode 100644 index 00000000000..72133053ff2 --- /dev/null +++ b/src/__tests__/fixtures/support/some-exports.ts @@ -0,0 +1,5 @@ +const obj = { objDestruct: "string" }; + +export const { objDestruct } = obj; + +export defaultFrom from './other-exports'; diff --git a/src/__tests__/fixtures/test-all-imports.tsx b/src/__tests__/fixtures/test-all-imports.tsx new file mode 100644 index 00000000000..837cfb3dc95 --- /dev/null +++ b/src/__tests__/fixtures/test-all-imports.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { objDestruct, defaultFrom } from './support/some-exports'; + +/** + * This is a TS component with imported stuff + */ +export function ImportedExtendedComponent({ x = objDestruct, y = defaultFrom }) { + return

Hello world

; +} diff --git a/src/__tests__/main-test.ts b/src/__tests__/main-test.ts index e3fcd17d4c9..d0a4a806974 100644 --- a/src/__tests__/main-test.ts +++ b/src/__tests__/main-test.ts @@ -197,13 +197,18 @@ describe('main', () => { // even though it is not the default describe('fixtures', () => { const fixturePath = path.join(__dirname, 'fixtures'); - const fileNames = fs.readdirSync(fixturePath); + const fileNames = fs.readdirSync(fixturePath, { withFileTypes: true }); for (let i = 0; i < fileNames.length; i++) { - const filePath = path.join(fixturePath, fileNames[i]); + if (fileNames[i].isDirectory()) { + continue; + } + const name = fileNames[i].name; + + const filePath = path.join(fixturePath, name); const fileContent = fs.readFileSync(filePath, 'utf8'); - it(`processes component "${fileNames[i]}" without errors`, () => { + it(`processes component "${name}" without errors`, () => { let result; expect(() => { diff --git a/src/importer/makeFsImporter.ts b/src/importer/makeFsImporter.ts index eb33494aa53..f933dc7b7f2 100644 --- a/src/importer/makeFsImporter.ts +++ b/src/importer/makeFsImporter.ts @@ -3,9 +3,10 @@ import resolve from 'resolve'; import { dirname } from 'path'; import fs from 'fs'; import type { NodePath } from '@babel/traverse'; -import type { VariableDeclaration } from '@babel/types'; +import type { ExportSpecifier, Identifier, ObjectProperty } from '@babel/types'; import type { Importer, ImportPath } from '.'; import type FileState from '../FileState'; +import { resolveObjectPatternPropertyToValue } from '../utils'; function defaultLookupModule(filename: string, basedir: string): string { return resolve.sync(filename, { @@ -62,7 +63,7 @@ export default function makeFsImporter( // Read and parse the code const src = fs.readFileSync(resolvedSource, 'utf8'); - nextState = state.parse(src); + nextState = state.parse(src, resolvedSource); cache.set(resolvedSource, nextState); } @@ -76,81 +77,111 @@ export default function makeFsImporter( name: string, seen: Set, ): NodePath | null { - let resultPath: NodePath | null = null; + let resultPath: NodePath | null | undefined; traverseShallow(state.path, { ExportNamedDeclaration(path) { - const { declaration, specifiers, source } = path.node; - - if ( - declaration && - 'id' in declaration && - declaration.id && - 'name' in declaration.id && - declaration.id.name === name - ) { - resultPath = path.get('declaration') as NodePath; + const declaration = path.get('declaration'); + + // export const/var ... + if (declaration.hasNode() && declaration.isVariableDeclaration()) { + for (const declPath of declaration.get('declarations')) { + const id = declPath.get('id'); + const init = declPath.get('init'); + + if (id.isIdentifier() && id.node.name === name && init.hasNode()) { + // export const/var a = + + resultPath = init; + + break; + } else if (id.isObjectPattern()) { + // export const/var { a } = + + resultPath = id.get('properties').find(prop => { + if (prop.isObjectProperty()) { + const value = prop.get('value'); + + return value.isIdentifier() && value.node.name === name; + } + // We don't handle RestElement here yet as complicated + + return false; + }); + + if (resultPath) { + resultPath = resolveObjectPatternPropertyToValue( + resultPath as NodePath, + ); + + break; + } + } + // ArrayPattern not handled yet + } } else if ( - declaration && - 'declarations' in declaration && - declaration.declarations + declaration.hasNode() && + declaration.has('id') && + (declaration.get('id') as NodePath).isIdentifier() && + (declaration.get('id') as NodePath).node.name === name ) { - (path.get('declaration') as NodePath) - .get('declarations') - .forEach(declPath => { - const id = declPath.get('id'); - - // TODO: ArrayPattern and ObjectPattern - if ( - id.isIdentifier() && - id.node.name === name && - 'init' in declPath.node && - declPath.node.init - ) { - resultPath = declPath.get('init') as NodePath; - } - }); - } else if (specifiers) { - path.get('specifiers').forEach(specifierPath => { - if ( - 'name' in specifierPath.node.exported && - specifierPath.node.exported.name === name - ) { - // TODO TESTME with ExportDefaultSpecifier - if (source) { - const local = - 'local' in specifierPath.node - ? specifierPath.node.local.name - : 'default'; + // export function/class/type/interface/enum ... + + resultPath = declaration; + } else if (path.has('specifiers')) { + // export { ... } or export x from ... or export * as x from ... + + for (const specifierPath of path.get('specifiers')) { + if (specifierPath.isExportNamespaceSpecifier()) { + continue; + } + const exported = specifierPath.get('exported'); + + if (exported.isIdentifier() && exported.node.name === name) { + // export ... from '' + if (path.has('source')) { + const local = specifierPath.isExportSpecifier() + ? specifierPath.node.local.name + : 'default'; resultPath = resolveImportedValue(path, local, state, seen); - } else if ('local' in specifierPath.node) { - resultPath = specifierPath.get('local') as NodePath; + if (resultPath) { + break; + } + } else { + resultPath = (specifierPath as NodePath).get( + 'local', + ); + break; } } - }); + } } - return false; + resultPath ? path.stop() : path.skip(); }, ExportDefaultDeclaration(path) { if (name === 'default') { resultPath = path.get('declaration'); + + return path.stop(); } - return false; + path.skip(); }, ExportAllDeclaration(path) { const resolvedPath = resolveImportedValue(path, name, state, seen); if (resolvedPath) { resultPath = resolvedPath; + + return path.stop(); } - return false; + path.skip(); }, }); - return resultPath; + return resultPath || null; } } diff --git a/src/utils/__tests__/__snapshots__/resolveObjectPatternPropertyToValue-test.ts.snap b/src/utils/__tests__/__snapshots__/resolveObjectPatternPropertyToValue-test.ts.snap new file mode 100644 index 00000000000..64ed2389532 --- /dev/null +++ b/src/utils/__tests__/__snapshots__/resolveObjectPatternPropertyToValue-test.ts.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`resolveObjectPatternPropertyToValue AssignmentExpression resolved basic case 1`] = ` +Node { + "extra": Object { + "raw": "\\"string\\"", + "rawValue": "string", + }, + "type": "StringLiteral", + "value": "string", +} +`; + +exports[`resolveObjectPatternPropertyToValue VariableDeclarator resolved basic case 1`] = ` +Node { + "extra": Object { + "raw": "\\"string\\"", + "rawValue": "string", + }, + "type": "StringLiteral", + "value": "string", +} +`; diff --git a/src/utils/__tests__/resolveObjectPatternPropertyToValue-test.ts b/src/utils/__tests__/resolveObjectPatternPropertyToValue-test.ts new file mode 100644 index 00000000000..7a9e88ab980 --- /dev/null +++ b/src/utils/__tests__/resolveObjectPatternPropertyToValue-test.ts @@ -0,0 +1,93 @@ +import type { NodePath } from '@babel/traverse'; +import type { + AssignmentExpression, + ObjectExpression, + ObjectProperty, + VariableDeclaration, +} from '@babel/types'; +import { parse } from '../../../tests/utils'; +import resolveObjectPatternPropertyToValue from '../resolveObjectPatternPropertyToValue'; + +describe('resolveObjectPatternPropertyToValue', () => { + it('does not resolve if not in ObjectProperty', () => { + const path = parse + .expressionLast( + `const x = { a : "string" }; + ({ a })`, + ) + .get('properties.0') as NodePath; + + expect(resolveObjectPatternPropertyToValue(path)).toBeNull(); + }); + + it('does not resolve if not in VariableDeclarator or AssignmentExpression', () => { + const path = parse + .expression(`({ a }) => {}`) + .get('params.0.properties.0') as NodePath; + + expect(resolveObjectPatternPropertyToValue(path)).toBeNull(); + }); + + describe('VariableDeclarator', () => { + it('resolved basic case', () => { + const path = parse + .statementLast( + `const x = { a : "string" }; + const { a } = x;`, + ) + .get('declarations.0.id.properties.0') as NodePath; + + expect(resolveObjectPatternPropertyToValue(path)).toMatchSnapshot(); + }); + + it('does not resolve if property not found', () => { + const path = parse + .statementLast( + `const x = { b : "string" }; + const { a } = x;`, + ) + .get('declarations.0.id.properties.0') as NodePath; + + expect(resolveObjectPatternPropertyToValue(path)).toBeNull(); + }); + + it('does not resolve when init not resolvable', () => { + const path = parse + .statementLast(`const { a } = x;`) + .get('declarations.0.id.properties.0') as NodePath; + + expect(resolveObjectPatternPropertyToValue(path)).toBeNull(); + }); + }); + describe('AssignmentExpression', () => { + it('resolved basic case', () => { + const path = parse + .expressionLast( + `const x = { a : "string" }; + ({ a } = x)`, + ) + .get('left.properties.0') as NodePath; + + expect(resolveObjectPatternPropertyToValue(path)).toMatchSnapshot(); + }); + + it('does not resolve if property not found', () => { + const path = parse + .expressionLast( + `const x = { b : "string" }; + ({ a } = x)`, + ) + .get('left.properties.0') as NodePath; + + expect(resolveObjectPatternPropertyToValue(path)).toBeNull(); + }); + + it('does not resolve when init not resolvable', () => { + const path = parse + .expression(`{ a } = x`) + .get('left.properties.0') as NodePath; + + expect(resolveObjectPatternPropertyToValue(path)).toBeNull(); + }); + }); +}); diff --git a/src/utils/index.ts b/src/utils/index.ts index 41c48628719..f84339b8152 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -53,6 +53,7 @@ export { default as resolveExportDeclaration } from './resolveExportDeclaration' export { default as resolveFunctionDefinitionToReturnValue } from './resolveFunctionDefinitionToReturnValue'; export { default as resolveGenericTypeAnnotation } from './resolveGenericTypeAnnotation'; export { default as resolveHOC } from './resolveHOC'; +export { default as resolveObjectPatternPropertyToValue } from './resolveObjectPatternPropertyToValue'; export { default as resolveObjectKeysToArray, resolveObjectToNameArray, diff --git a/src/utils/resolveObjectPatternPropertyToValue.ts b/src/utils/resolveObjectPatternPropertyToValue.ts new file mode 100644 index 00000000000..7abaae3c55a --- /dev/null +++ b/src/utils/resolveObjectPatternPropertyToValue.ts @@ -0,0 +1,48 @@ +import type { NodePath } from '@babel/traverse'; +import type { Identifier, ObjectProperty } from '@babel/types'; +import getPropertyValuePath from './getPropertyValuePath'; +import resolveToValue from './resolveToValue'; + +function resolveToObjectExpression(path: NodePath): NodePath | null { + if (path.isVariableDeclarator()) { + const init = path.get('init'); + + if (init.hasNode()) { + return resolveToValue(init); + } + } else if (path.isAssignmentExpression()) { + if (path.node.operator === '=') { + return resolveToValue(path.get('right')); + } + } + + return null; +} + +/** + * Resolve and ObjectProperty inside an ObjectPattern to its value if possible + * If not found `null` is returned + */ +export default function resolveObjectPatternPropertyToValue( + path: NodePath, +): NodePath | null { + if (!path.parentPath.isObjectPattern()) { + return null; + } + + const resolved = resolveToObjectExpression(path.parentPath.parentPath); + + if (resolved && resolved.isObjectExpression()) { + const propertyPath = getPropertyValuePath( + resolved, + // Always id in ObjectPattern + (path.get('key') as NodePath).node.name, + ); + + if (propertyPath) { + return resolveToValue(propertyPath); + } + } + + return null; +} diff --git a/src/utils/resolveToValue.ts b/src/utils/resolveToValue.ts index 081d6750bd2..08b8367f435 100644 --- a/src/utils/resolveToValue.ts +++ b/src/utils/resolveToValue.ts @@ -1,7 +1,6 @@ import { Scope } from '@babel/traverse'; import type { NodePath } from '@babel/traverse'; import type { - Expression, Identifier, ImportDeclaration, MemberExpression, @@ -121,9 +120,46 @@ function findLastAssignedValue( * Else the path itself is returned. */ export default function resolveToValue(path: NodePath): NodePath { - if (path.isVariableDeclarator()) { - if (path.node.init) { - return resolveToValue(path.get('init') as NodePath); + if (path.isIdentifier()) { + if ( + (path.parentPath.isClass() || path.parentPath.isFunction()) && + path.parentPath.get('id') === path + ) { + return path.parentPath; + } + + const binding = path.scope.getBinding(path.node.name); + let resolvedPath: NodePath | null = null; + + if (binding) { + // The variable may be assigned a different value after initialization. + // We are first trying to find all assignments to the variable in the + // block where it is defined (i.e. we are not traversing into statements) + resolvedPath = findLastAssignedValue(binding.scope.path, path); + if (!resolvedPath) { + // @ts-ignore TODO fix in DT + const bindingMap = binding.path.getOuterBindingIdentifierPaths( + true, + ) as Record>>; + + resolvedPath = findScopePath(bindingMap[path.node.name]); + } + } else { + // Initialize our monkey-patching of @babel/traverse 🙈 + initialize(Scope); + const typeBinding = path.scope.getTypeBinding(path.node.name); + + if (typeBinding) { + resolvedPath = findScopePath([typeBinding.identifierPath]); + } + } + + return resolvedPath || path; + } else if (path.isVariableDeclarator()) { + const init = path.get('init'); + + if (init.hasNode()) { + return resolveToValue(init); } } else if (path.isMemberExpression()) { const root = getMemberExpressionRoot(path); @@ -195,43 +231,6 @@ export default function resolveToValue(path: NodePath): NodePath { path.isTSTypeAssertion() ) { return resolveToValue(path.get('expression') as NodePath); - } else if (path.isIdentifier()) { - if ( - (path.parentPath.isClassDeclaration() || - path.parentPath.isClassExpression() || - path.parentPath.isFunction()) && - path.parentPath.get('id') === path - ) { - return path.parentPath; - } - - const binding = path.scope.getBinding(path.node.name); - let resolvedPath: NodePath | null = null; - - if (binding) { - // The variable may be assigned a different value after initialization. - // We are first trying to find all assignments to the variable in the - // block where it is defined (i.e. we are not traversing into statements) - resolvedPath = findLastAssignedValue(binding.scope.path, path); - if (!resolvedPath) { - // @ts-ignore TODO fix in DT - const bindingMap = binding.path.getOuterBindingIdentifierPaths( - true, - ) as Record>>; - - resolvedPath = findScopePath(bindingMap[path.node.name]); - } - } else { - // Initialize our monkey-patching of @babel/traverse 🙈 - initialize(Scope); - const typeBinding = path.scope.getTypeBinding(path.node.name); - - if (typeBinding) { - resolvedPath = findScopePath([typeBinding.identifierPath]); - } - } - - return resolvedPath || path; } return path; From 1228c177dde7c595db31c6fd6c7a92eee8342e49 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 31 Jul 2022 16:58:05 +0200 Subject: [PATCH 28/44] chore: Cleanup code --- src/handlers/codeTypeHandler.ts | 2 +- src/utils/resolveToValue.ts | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/handlers/codeTypeHandler.ts b/src/handlers/codeTypeHandler.ts index f59bd10ef07..1f32f65b80b 100644 --- a/src/handlers/codeTypeHandler.ts +++ b/src/handlers/codeTypeHandler.ts @@ -45,7 +45,7 @@ function setPropDescriptor( } const resolvedPath = resolveToValue(id); - if (resolvedPath && resolvedPath.isTypeAlias()) { + if (resolvedPath.isTypeAlias()) { const right = resolvedPath.get('right'); applyToTypeProperties( diff --git a/src/utils/resolveToValue.ts b/src/utils/resolveToValue.ts index 08b8367f435..26bfbe104e6 100644 --- a/src/utils/resolveToValue.ts +++ b/src/utils/resolveToValue.ts @@ -88,15 +88,13 @@ function findLastAssignedValue( // Ensure the RHS doesn't contain the reference we're trying to resolve. const candidatePath = assignmentPath.get('right'); - for ( - let p: NodePath | null = idPath; - p && p.node != null; - p = p.parentPath + if ( + candidatePath.node === idPath.node || + idPath.findParent(parent => parent.node === candidatePath.node) ) { - if (p.node === candidatePath.node) { - return; - } + return; } + results.push(candidatePath); return assignmentPath.skip(); @@ -221,10 +219,6 @@ export default function resolveToValue(path: NodePath): NodePath { ) { // go up to the import declaration return path.parentPath; - } else if (path.isAssignmentExpression()) { - if (path.node.operator === '=') { - return resolveToValue(path.get('right')); - } } else if ( path.isTypeCastExpression() || path.isTSAsExpression() || From 8ddb4332dace691eb7629e4c15ccb0150fc04d3d Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 31 Jul 2022 22:18:08 +0200 Subject: [PATCH 29/44] feat: Improve performance drastically by changing traversing visitors are now pre-exploded and are cached in the module scope instead of creating them on every call. This change brought the benchmark from 170ops/s to 225ops/sec --- .github/workflows/release-please.yml | 7 +- benchmark/package.json | 3 +- package.json | 7 +- src/FileState.ts | 4 +- .../__tests__/componentMethodsHandler-test.ts | 6 +- src/handlers/componentMethodsHandler.ts | 71 ++++++---- src/importer/index.ts | 2 +- src/importer/makeFsImporter.ts | 109 +++++++++----- src/main.ts | 13 +- src/resolver/findAllComponentDefinitions.ts | 91 +++++++----- .../findAllExportedComponentDefinitions.ts | 114 ++++++++------- .../findExportedComponentDefinition.ts | 134 ++++++++++-------- ...nctionDefinitionToReturnValue-test.ts.snap | 23 +++ ...lveFunctionDefinitionToReturnValue-test.ts | 48 +++++++ .../resolveFunctionDefinitionToReturnValue.ts | 41 ++++-- src/utils/resolveToValue.ts | 59 ++++---- src/utils/traverse.ts | 42 +++--- 17 files changed, 482 insertions(+), 292 deletions(-) create mode 100644 src/utils/__tests__/__snapshots__/resolveFunctionDefinitionToReturnValue-test.ts.snap create mode 100644 src/utils/__tests__/resolveFunctionDefinitionToReturnValue-test.ts diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index daeee47a932..c632300127d 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -32,12 +32,11 @@ jobs: if: ${{ steps.release.outputs.release_created }} run: yarn install --frozen-lockfile --non-interactive - - name: Install website dependencies + - name: Build package if: ${{ steps.release.outputs.release_created }} - run: yarn install --frozen-lockfile --non-interactive - working-directory: ./website + run: yarn build - run: npm publish --tag=next env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - if: ${{ steps.release.outputs.release_created }} \ No newline at end of file + if: ${{ steps.release.outputs.release_created }} diff --git a/benchmark/package.json b/benchmark/package.json index 33248a9a259..7c3ef3a770e 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -3,7 +3,8 @@ "private": true, "description": "Generate benchmarks for react-docgen", "scripts": { - "start": "node --expose-gc ./index.js" + "start": "node --expose-gc ./index.js", + "debug": "node --inspect-brk --expose-gc ./index.js" }, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index e5522bc70e5..66b20725fc5 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,12 @@ "main": "dist/main.js", "typings": "dist/main.d.ts", "scripts": { - "build": "rimraf dist/ && yarn build:ts", - "build:ts": "tsc", + "build": "rimraf dist/ && tsc", "lint": "eslint . --ext .js,.ts --report-unused-disable-directives", "fix": "eslint . --ext .js,.ts --fix --report-unused-disable-directives", - "prepare": "yarn build", "start": "cd website && yarn && yarn start", - "test": "yarn build && jest" + "test": "yarn lint && yarn build && jest", + "test:ci": "yarn build && jest" }, "keywords": [ "react", diff --git a/src/FileState.ts b/src/FileState.ts index a04c077cb8e..ea73155bacf 100644 --- a/src/FileState.ts +++ b/src/FileState.ts @@ -86,10 +86,12 @@ export default class FileState { ); } + traverse(visitors: Visitor, state?: S): void; + traverse(visitors: Visitor): void; /** * Traverse the current file */ - traverse(visitors: Visitor, state?: unknown): void { + traverse(visitors: Visitor, state?: any): void { traverse(this.ast, visitors, this.scope, state); } } diff --git a/src/handlers/__tests__/componentMethodsHandler-test.ts b/src/handlers/__tests__/componentMethodsHandler-test.ts index 278be7b2fb9..995e46e02c9 100644 --- a/src/handlers/__tests__/componentMethodsHandler-test.ts +++ b/src/handlers/__tests__/componentMethodsHandler-test.ts @@ -351,6 +351,7 @@ describe('componentMethodsHandler', () => { it('finds static methods on a component in an assignment', () => { const src = ` + let Test; Test = (props) => {}; Test.doFoo = () => {}; Test.doBar = () => {}; @@ -360,7 +361,7 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, parse - .statement(src) + .statement(src, 1) .get('expression.right') as NodePath, ); expect(documentation.methods).toMatchSnapshot(); @@ -368,6 +369,7 @@ describe('componentMethodsHandler', () => { it('resolves imported methods assigned on a component in an assignment', () => { const src = ` + let Test; Test = (props) => {}; import doFoo from 'doFoo'; Test.doFoo = doFoo; @@ -376,7 +378,7 @@ describe('componentMethodsHandler', () => { componentMethodsHandler( documentation, parse - .statement(src, mockImporter) + .statement(src, mockImporter, 1) .get('expression.right') as NodePath, ); expect(documentation.methods).toMatchSnapshot(); diff --git a/src/handlers/componentMethodsHandler.ts b/src/handlers/componentMethodsHandler.ts index b18fb85b1fa..f21199deb99 100644 --- a/src/handlers/componentMethodsHandler.ts +++ b/src/handlers/componentMethodsHandler.ts @@ -4,10 +4,10 @@ import getMethodDocumentation from '../utils/getMethodDocumentation'; import isReactComponentClass from '../utils/isReactComponentClass'; import isReactComponentMethod from '../utils/isReactComponentMethod'; import type Documentation from '../Documentation'; -import match from '../utils/match'; -import { traverseShallow } from '../utils/traverse'; +import { shallowIgnoreVisitors } from '../utils/traverse'; import resolveToValue from '../utils/resolveToValue'; -import type { NodePath } from '@babel/traverse'; +import type { NodePath, Scope } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import type { AssignmentExpression, Identifier } from '@babel/types'; import type { ComponentNode } from '../resolver'; import type { Handler } from '.'; @@ -37,38 +37,61 @@ function isMethod(path: NodePath): boolean { return isProbablyMethod && !isReactComponentMethod(path); } +interface TraverseState { + readonly scope: Scope | undefined; + readonly name: string; + methods: Array>; +} + +const explodedVisitors = visitors.explode({ + ...shallowIgnoreVisitors, + + AssignmentExpression: { + enter: function (assignmentPath, state) { + const { name, scope } = state; + const left = assignmentPath.get('left'); + const binding = assignmentPath.scope.getBinding(name); + + if ( + left.isMemberExpression() && + left.get('object').isIdentifier() && + (left.node.object as Identifier).name === name && + binding && + binding.scope === scope && + resolveToValue(assignmentPath.get('right')).isFunction() + ) { + state.methods.push(assignmentPath); + } + assignmentPath.skip(); + }, + }, +}); + function findAssignedMethods( path: NodePath, idPath: NodePath, ): Array> { - const results: Array> = []; - if (!idPath.hasNode() || !idPath.isIdentifier()) { - return results; + return []; } const name = idPath.node.name; - const idScope = idPath.scope.getBinding(idPath.node.name)?.scope; + const binding = idPath.scope.getBinding(name); - traverseShallow(path, { - AssignmentExpression(assignmentPath) { - const node = assignmentPath.node; + if (!binding) { + return []; + } - if ( - match(node.left, { - type: 'MemberExpression', - object: { type: 'Identifier', name }, - }) && - assignmentPath.scope.getBinding(name)?.scope === idScope && - resolveToValue(assignmentPath.get('right')).isFunction() - ) { - results.push(assignmentPath); - assignmentPath.skip(); - } - }, - }); + const scope = binding.scope; + const state: TraverseState = { + scope, + name, + methods: [], + }; + + path.traverse(explodedVisitors, state); - return results; + return state.methods; } /** diff --git a/src/importer/index.ts b/src/importer/index.ts index 97434bbb0d8..e0c30f2bbb7 100644 --- a/src/importer/index.ts +++ b/src/importer/index.ts @@ -15,7 +15,7 @@ export type ImportPath = NodePath< export type Importer = ( path: ImportPath, name: string, - state: FileState, + file: FileState, ) => NodePath | null; export { ignoreImports, makeFsImporter }; diff --git a/src/importer/makeFsImporter.ts b/src/importer/makeFsImporter.ts index f933dc7b7f2..77b75473247 100644 --- a/src/importer/makeFsImporter.ts +++ b/src/importer/makeFsImporter.ts @@ -1,8 +1,9 @@ -import { traverseShallow } from '../utils/traverse'; +import { shallowIgnoreVisitors } from '../utils/traverse'; import resolve from 'resolve'; import { dirname } from 'path'; import fs from 'fs'; import type { NodePath } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import type { ExportSpecifier, Identifier, ObjectProperty } from '@babel/types'; import type { Importer, ImportPath } from '.'; import type FileState from '../FileState'; @@ -15,6 +16,13 @@ function defaultLookupModule(filename: string, basedir: string): string { }); } +interface TraverseState { + readonly name: string; + readonly file: FileState; + readonly seen: Set; + resultPath?: NodePath | null; +} + // Factory for the resolveImports importer export default function makeFsImporter( lookupModule: ( @@ -23,18 +31,16 @@ export default function makeFsImporter( ) => string = defaultLookupModule, cache: Map = new Map(), ): Importer { - return resolveImportedValue; - function resolveImportedValue( path: ImportPath, name: string, - state: FileState, + file: FileState, seen: Set = new Set(), ): NodePath | null { // Bail if no filename was provided for the current source file. // Also never traverse into react itself. const source = path.node.source?.value; - const options = state.opts; + const options = file.opts; if (!source || !options || !options.filename || source === 'react') { return null; @@ -57,30 +63,25 @@ export default function makeFsImporter( seen.add(resolvedSource); - let nextState = cache.get(resolvedSource); + let nextFile = cache.get(resolvedSource); - if (!nextState) { + if (!nextFile) { // Read and parse the code const src = fs.readFileSync(resolvedSource, 'utf8'); - nextState = state.parse(src, resolvedSource); + nextFile = file.parse(src, resolvedSource); - cache.set(resolvedSource, nextState); + cache.set(resolvedSource, nextFile); } - return findExportedValue(nextState, name, seen); + return findExportedValue(nextFile, name, seen); } - // Traverses the program looking for an export that matches the requested name - function findExportedValue( - state: FileState, - name: string, - seen: Set, - ): NodePath | null { - let resultPath: NodePath | null | undefined; - - traverseShallow(state.path, { - ExportNamedDeclaration(path) { + const explodedVisitors = visitors.explode({ + ...shallowIgnoreVisitors, + ExportNamedDeclaration: { + enter: function (path, state) { + const { file, name, seen } = state; const declaration = path.get('declaration'); // export const/var ... @@ -92,13 +93,13 @@ export default function makeFsImporter( if (id.isIdentifier() && id.node.name === name && init.hasNode()) { // export const/var a = - resultPath = init; + state.resultPath = init; break; } else if (id.isObjectPattern()) { // export const/var { a } = - resultPath = id.get('properties').find(prop => { + state.resultPath = id.get('properties').find(prop => { if (prop.isObjectProperty()) { const value = prop.get('value'); @@ -109,9 +110,9 @@ export default function makeFsImporter( return false; }); - if (resultPath) { - resultPath = resolveObjectPatternPropertyToValue( - resultPath as NodePath, + if (state.resultPath) { + state.resultPath = resolveObjectPatternPropertyToValue( + state.resultPath as NodePath, ); break; @@ -127,7 +128,7 @@ export default function makeFsImporter( ) { // export function/class/type/interface/enum ... - resultPath = declaration; + state.resultPath = declaration; } else if (path.has('specifiers')) { // export { ... } or export x from ... or export * as x from ... @@ -144,44 +145,74 @@ export default function makeFsImporter( ? specifierPath.node.local.name : 'default'; - resultPath = resolveImportedValue(path, local, state, seen); - if (resultPath) { + state.resultPath = resolveImportedValue( + path, + local, + file, + seen, + ); + if (state.resultPath) { break; } } else { - resultPath = (specifierPath as NodePath).get( - 'local', - ); + state.resultPath = ( + specifierPath as NodePath + ).get('local'); + break; } } } } - resultPath ? path.stop() : path.skip(); + state.resultPath ? path.stop() : path.skip(); }, - ExportDefaultDeclaration(path) { + }, + ExportDefaultDeclaration: { + enter: function (path, state) { + const { name } = state; + if (name === 'default') { - resultPath = path.get('declaration'); + state.resultPath = path.get('declaration'); return path.stop(); } path.skip(); }, - ExportAllDeclaration(path) { - const resolvedPath = resolveImportedValue(path, name, state, seen); + }, + ExportAllDeclaration: { + enter: function (path, state) { + const { name, file, seen } = state; + const resolvedPath = resolveImportedValue(path, name, file, seen); if (resolvedPath) { - resultPath = resolvedPath; + state.resultPath = resolvedPath; return path.stop(); } path.skip(); }, - }); + }, + }); + + // Traverses the program looking for an export that matches the requested name + function findExportedValue( + file: FileState, + name: string, + seen: Set, + ): NodePath | null { + const state: TraverseState = { + file, + name, + seen, + }; - return resultPath || null; + file.traverse(explodedVisitors, state); + + return state.resultPath || null; } + + return resolveImportedValue; } diff --git a/src/main.ts b/src/main.ts index c497f514586..01d4837fa8d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,7 @@ import * as allHandlers from './handlers'; import parse from './parse'; -import * as AllResolver from './resolver'; -import * as AllImporter from './importer'; +import * as allResolvers from './resolver'; +import * as allImporters from './importer'; import * as utils from './utils'; import type { Options } from './babelParser'; import type { DocumentationObject as Documentation } from './Documentation'; @@ -10,7 +10,7 @@ import type { Importer } from './importer'; import type { Handler } from './handlers'; import type FileState from './FileState'; -const defaultResolver: Resolver = AllResolver.findExportedComponentDefinition; +const defaultResolver: Resolver = allResolvers.findExportedComponentDefinition; const defaultHandlers: Handler[] = [ allHandlers.propTypeHandler, allHandlers.contextTypeHandler, @@ -24,7 +24,8 @@ const defaultHandlers: Handler[] = [ allHandlers.componentMethodsHandler, allHandlers.componentMethodsJsDocHandler, ]; -const defaultImporter: Importer = AllImporter.makeFsImporter(); + +const defaultImporter: Importer = allImporters.makeFsImporter(); declare module '@babel/traverse' { export interface HubInterface { @@ -67,8 +68,8 @@ export { defaultParse as parse, defaultHandlers, allHandlers as handlers, - AllResolver as resolver, - AllImporter as importers, + allResolvers as resolver, + allImporters as importers, utils, }; diff --git a/src/resolver/findAllComponentDefinitions.ts b/src/resolver/findAllComponentDefinitions.ts index ddc1efb29d8..47e1af82a30 100644 --- a/src/resolver/findAllComponentDefinitions.ts +++ b/src/resolver/findAllComponentDefinitions.ts @@ -5,43 +5,54 @@ import isStatelessComponent from '../utils/isStatelessComponent'; import normalizeClassDefinition from '../utils/normalizeClassDefinition'; import resolveToValue from '../utils/resolveToValue'; import type { NodePath } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import type FileState from '../FileState'; import type { ComponentNode, Resolver } from '.'; +import type { + ArrowFunctionExpression, + FunctionDeclaration, + FunctionExpression, + ObjectMethod, +} from '@babel/types'; -/** - * Given an AST, this function tries to find all object expressions that are - * passed to `React.createClass` calls, by resolving all references properly. - */ -const findAllComponentDefinitions: Resolver = function ( - file: FileState, -): Array> { - const definitions = new Set>(); +interface TraverseState { + foundDefinitions: Set>; +} - function classVisitor(path) { - if (isReactComponentClass(path)) { - normalizeClassDefinition(path); - definitions.add(path); - } - - return false; +function classVisitor(path: NodePath, state: TraverseState) { + if (isReactComponentClass(path)) { + normalizeClassDefinition(path); + state.foundDefinitions.add(path); } - function statelessVisitor(path) { - if (isStatelessComponent(path)) { - definitions.add(path); - } + path.skip(); +} - return false; +function statelessVisitor( + path: NodePath< + | ArrowFunctionExpression + | FunctionDeclaration + | FunctionExpression + | ObjectMethod + >, + state: TraverseState, +) { + if (isStatelessComponent(path)) { + state.foundDefinitions.add(path); } - file.traverse({ - FunctionDeclaration: statelessVisitor, - FunctionExpression: statelessVisitor, - ObjectMethod: statelessVisitor, - ArrowFunctionExpression: statelessVisitor, - ClassExpression: classVisitor, - ClassDeclaration: classVisitor, - CallExpression: function (path): void { + path.skip(); +} + +const explodedVisitors = visitors.explode({ + FunctionDeclaration: { enter: statelessVisitor }, + FunctionExpression: { enter: statelessVisitor }, + ObjectMethod: { enter: statelessVisitor }, + ArrowFunctionExpression: { enter: statelessVisitor }, + ClassExpression: { enter: classVisitor }, + ClassDeclaration: { enter: classVisitor }, + CallExpression: { + enter: function (path, state): void { if (isReactForwardRefCall(path)) { // If the the inner function was previously identified as a component // replace it with the parent node @@ -49,8 +60,8 @@ const findAllComponentDefinitions: Resolver = function ( path.get('arguments')[0], ) as NodePath; - definitions.delete(inner); - definitions.add(path); + state.foundDefinitions.delete(inner); + state.foundDefinitions.add(path); // Do not traverse into arguments return path.skip(); @@ -58,16 +69,30 @@ const findAllComponentDefinitions: Resolver = function ( const resolvedPath = resolveToValue(path.get('arguments')[0]); if (resolvedPath.isObjectExpression()) { - definitions.add(resolvedPath); + state.foundDefinitions.add(resolvedPath); } // Do not traverse into arguments return path.skip(); } }, - }); + }, +}); + +/** + * Given an AST, this function tries to find all object expressions that are + * passed to `React.createClass` calls, by resolving all references properly. + */ +const findAllComponentDefinitions: Resolver = function ( + file: FileState, +): Array> { + const state: TraverseState = { + foundDefinitions: new Set>(), + }; + + file.traverse(explodedVisitors, state); - return Array.from(definitions); + return Array.from(state.foundDefinitions); }; export default findAllComponentDefinitions; diff --git a/src/resolver/findAllExportedComponentDefinitions.ts b/src/resolver/findAllExportedComponentDefinitions.ts index 9c6aa377f20..1581e0cbdef 100644 --- a/src/resolver/findAllExportedComponentDefinitions.ts +++ b/src/resolver/findAllExportedComponentDefinitions.ts @@ -3,6 +3,7 @@ import resolveExportDeclaration from '../utils/resolveExportDeclaration'; import resolveToValue from '../utils/resolveToValue'; import resolveHOC from '../utils/resolveHOC'; import type { NodePath } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import { shallowIgnoreVisitors } from '../utils/traverse'; import type { ExportDefaultDeclaration, @@ -14,61 +15,47 @@ import resolveComponentDefinition, { isComponentDefinition, } from '../utils/resolveComponentDefinition'; -/** - * Given an AST, this function tries to find the exported component definitions. - * - * The component definitions are either the ObjectExpression passed to - * `React.createClass` or a `class` definition extending `React.Component` or - * having a `render()` method. - * - * If a definition is part of the following statements, it is considered to be - * exported: - * - * modules.exports = Definition; - * exports.foo = Definition; - * export default Definition; - * export var Definition = ...; - */ -const findExportedComponentDefinitions: Resolver = function ( - file: FileState, -): Array> { - const components: Array> = []; - - function exportDeclaration( - path: NodePath, - ): void { - resolveExportDeclaration(path) - .reduce((acc, definition) => { - if (isComponentDefinition(definition)) { - acc.push(definition); - } else { - const resolved = resolveToValue(resolveHOC(definition)); - - if (isComponentDefinition(resolved)) { - acc.push(resolved); - } - } +interface TraverseState { + foundDefinitions: Array>; +} - return acc; - }, [] as Array>) - .forEach(definition => { - const resolved = resolveComponentDefinition(definition); +function exportDeclaration( + path: NodePath, + state: TraverseState, +): void { + resolveExportDeclaration(path) + .reduce((acc, definition) => { + if (isComponentDefinition(definition)) { + acc.push(definition); + } else { + const resolved = resolveToValue(resolveHOC(definition)); - if (resolved && components.indexOf(resolved) === -1) { - components.push(resolved); + if (isComponentDefinition(resolved)) { + acc.push(resolved); } - }); + } - return path.skip(); - } + return acc; + }, [] as Array>) + .forEach(definition => { + const resolved = resolveComponentDefinition(definition); + + if (resolved && !state.foundDefinitions.includes(resolved)) { + state.foundDefinitions.push(resolved); + } + }); - file.traverse({ - ...shallowIgnoreVisitors, + return path.skip(); +} - ExportNamedDeclaration: exportDeclaration, - ExportDefaultDeclaration: exportDeclaration, +const explodedVisitors = visitors.explode({ + ...shallowIgnoreVisitors, - AssignmentExpression: function (path): void { + ExportNamedDeclaration: { enter: exportDeclaration }, + ExportDefaultDeclaration: { enter: exportDeclaration }, + + AssignmentExpression: { + enter: function (path, state): void { // Ignore anything that is not `exports.X = ...;` or // `module.exports = ...;` if (!isExportsOrModuleAssignment(path)) { @@ -86,15 +73,38 @@ const findExportedComponentDefinitions: Resolver = function ( } const definition = resolveComponentDefinition(resolvedPath); - if (definition && components.indexOf(definition) === -1) { - components.push(definition); + if (definition && state.foundDefinitions.indexOf(definition) === -1) { + state.foundDefinitions.push(definition); } return path.skip(); }, - }); + }, +}); + +/** + * Given an AST, this function tries to find the exported component definitions. + * + * The component definitions are either the ObjectExpression passed to + * `React.createClass` or a `class` definition extending `React.Component` or + * having a `render()` method. + * + * If a definition is part of the following statements, it is considered to be + * exported: + * + * modules.exports = Definition; + * exports.foo = Definition; + * export default Definition; + * export var Definition = ...; + */ +const findExportedComponentDefinitions: Resolver = function ( + file: FileState, +): Array> { + const state: TraverseState = { foundDefinitions: [] }; + + file.traverse(explodedVisitors, state); - return components; + return state.foundDefinitions; }; export default findExportedComponentDefinitions; diff --git a/src/resolver/findExportedComponentDefinition.ts b/src/resolver/findExportedComponentDefinition.ts index fce13a15132..24045565ac2 100644 --- a/src/resolver/findExportedComponentDefinition.ts +++ b/src/resolver/findExportedComponentDefinition.ts @@ -3,6 +3,7 @@ import resolveExportDeclaration from '../utils/resolveExportDeclaration'; import resolveToValue from '../utils/resolveToValue'; import resolveHOC from '../utils/resolveHOC'; import type { NodePath } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import { shallowIgnoreVisitors } from '../utils/traverse'; import type { ExportDefaultDeclaration, @@ -17,69 +18,55 @@ import resolveComponentDefinition, { const ERROR_MULTIPLE_DEFINITIONS = 'Multiple exported component definitions found.'; -/** - * Given an AST, this function tries to find the exported component definition. - * - * The component definition is either the ObjectExpression passed to - * `React.createClass` or a `class` definition extending `React.Component` or - * having a `render()` method. - * - * If a definition is part of the following statements, it is considered to be - * exported: - * - * modules.exports = Definition; - * exports.foo = Definition; - * export default Definition; - * export var Definition = ...; - */ -const findExportedComponentDefinition: Resolver = function ( - file: FileState, -): Array> { - const foundDefinition: Array> = []; - - function exportDeclaration( - path: NodePath, - ): void { - const definitions = resolveExportDeclaration(path).reduce( - (acc, definition) => { - if (isComponentDefinition(definition)) { - acc.push(definition); - } else { - const resolved = resolveToValue(resolveHOC(definition)); - - if (isComponentDefinition(resolved)) { - acc.push(resolved); - } +interface TraverseState { + foundDefinition: NodePath | null; +} + +function exportDeclaration( + path: NodePath, + state: TraverseState, +): void { + const definitions = resolveExportDeclaration(path).reduce( + (acc, definition) => { + if (isComponentDefinition(definition)) { + acc.push(definition); + } else { + const resolved = resolveToValue(resolveHOC(definition)); + + if (isComponentDefinition(resolved)) { + acc.push(resolved); } + } - return acc; - }, - [] as Array>, - ); - - if (definitions.length === 0) { - return path.skip(); - } - if (definitions.length > 1 || foundDefinition.length === 1) { - // If a file exports multiple components, ... complain! - throw new Error(ERROR_MULTIPLE_DEFINITIONS); - } - const definition = resolveComponentDefinition(definitions[0]); - - if (definition) { - foundDefinition.push(definition); - } + return acc; + }, + [] as Array>, + ); + if (definitions.length === 0) { return path.skip(); } + if (definitions.length > 1 || state.foundDefinition) { + // If a file exports multiple components, ... complain! + throw new Error(ERROR_MULTIPLE_DEFINITIONS); + } + const definition = resolveComponentDefinition(definitions[0]); - file.traverse({ - ...shallowIgnoreVisitors, + if (definition) { + state.foundDefinition = definition; + } - ExportNamedDeclaration: exportDeclaration, - ExportDefaultDeclaration: exportDeclaration, + return path.skip(); +} - AssignmentExpression: function (path): void { +const explodedVisitors = visitors.explode({ + ...shallowIgnoreVisitors, + + ExportNamedDeclaration: { enter: exportDeclaration }, + ExportDefaultDeclaration: { enter: exportDeclaration }, + + AssignmentExpression: { + enter: function (path, state): void { // Ignore anything that is not `exports.X = ...;` or // `module.exports = ...;` if (!isExportsOrModuleAssignment(path)) { @@ -95,21 +82,50 @@ const findExportedComponentDefinition: Resolver = function ( return path.skip(); } } - if (foundDefinition.length === 1) { + if (state.foundDefinition) { // If a file exports multiple components, ... complain! throw new Error(ERROR_MULTIPLE_DEFINITIONS); } const definition = resolveComponentDefinition(resolvedPath); if (definition) { - foundDefinition.push(definition); + state.foundDefinition = definition; } return path.skip(); }, - }); + }, +}); + +/** + * Given an AST, this function tries to find the exported component definition. + * + * The component definition is either the ObjectExpression passed to + * `React.createClass` or a `class` definition extending `React.Component` or + * having a `render()` method. + * + * If a definition is part of the following statements, it is considered to be + * exported: + * + * modules.exports = Definition; + * exports.foo = Definition; + * export default Definition; + * export var Definition = ...; + */ +const findExportedComponentDefinition: Resolver = function ( + file: FileState, +): Array> { + const state: TraverseState = { + foundDefinition: null, + }; + + file.traverse(explodedVisitors, state); + + if (state.foundDefinition) { + return [state.foundDefinition]; + } - return foundDefinition; + return []; }; export default findExportedComponentDefinition; diff --git a/src/utils/__tests__/__snapshots__/resolveFunctionDefinitionToReturnValue-test.ts.snap b/src/utils/__tests__/__snapshots__/resolveFunctionDefinitionToReturnValue-test.ts.snap new file mode 100644 index 00000000000..ef87469850b --- /dev/null +++ b/src/utils/__tests__/__snapshots__/resolveFunctionDefinitionToReturnValue-test.ts.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`resolveFunctionDefinitionToReturnValue can resolve easy return statement 1`] = ` +Node { + "extra": Object { + "raw": "\\"result\\"", + "rawValue": "result", + }, + "type": "StringLiteral", + "value": "result", +} +`; + +exports[`resolveFunctionDefinitionToReturnValue stops after first return 1`] = ` +Node { + "extra": Object { + "raw": "\\"first\\"", + "rawValue": "first", + }, + "type": "StringLiteral", + "value": "first", +} +`; diff --git a/src/utils/__tests__/resolveFunctionDefinitionToReturnValue-test.ts b/src/utils/__tests__/resolveFunctionDefinitionToReturnValue-test.ts new file mode 100644 index 00000000000..52a0e69adf8 --- /dev/null +++ b/src/utils/__tests__/resolveFunctionDefinitionToReturnValue-test.ts @@ -0,0 +1,48 @@ +import type { FunctionDeclaration } from '@babel/types'; +import { parse } from '../../../tests/utils'; +import resolveFunctionDefinitionToReturnValue from '../resolveFunctionDefinitionToReturnValue'; + +describe('resolveFunctionDefinitionToReturnValue', () => { + it('can resolve easy return statement', () => { + const path = parse.statement(` + function x () { return "result"; } + `); + + expect(resolveFunctionDefinitionToReturnValue(path)).toMatchSnapshot(); + }); + + it('stops after first return', () => { + const path = parse.statement(` + function x () { return "first"; return "second"; } + `); + + expect(resolveFunctionDefinitionToReturnValue(path)).toMatchSnapshot(); + }); + + it('ignores return values in other blocks', () => { + const path = parse.statement(` + function x () { + const a = function () { return "funcexpr"; } + const b = () => { return "arrow"; } + function c () { return "funcdecl"; } + const d = { + d() { return "objmthd"; } + } + + class A { + method() { + return "classmthd"; + } + } + + if (e) { + return "if"; + } else { + return "else"; + } + } + `); + + expect(resolveFunctionDefinitionToReturnValue(path)).toBeNull(); + }); +}); diff --git a/src/utils/resolveFunctionDefinitionToReturnValue.ts b/src/utils/resolveFunctionDefinitionToReturnValue.ts index 3009a8a0ca2..48864379104 100644 --- a/src/utils/resolveFunctionDefinitionToReturnValue.ts +++ b/src/utils/resolveFunctionDefinitionToReturnValue.ts @@ -1,28 +1,41 @@ import type { NodePath } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import type { Expression, Function as BabelFunction } from '@babel/types'; import resolveToValue from './resolveToValue'; -import { ignore, traverseShallow } from './traverse'; +import { ignore, shallowIgnoreVisitors } from './traverse'; -// TODO needs unit test - -export default function resolveFunctionDefinitionToReturnValue( - path: NodePath, -): NodePath | null { - let returnPath: NodePath | null = null; +interface TraverseState { + returnPath?: NodePath; +} - const body = path.get('body'); +const explodedVisitors = visitors.explode({ + ...shallowIgnoreVisitors, - traverseShallow(body, { - Function: ignore, - ReturnStatement: nodePath => { + Function: { enter: ignore }, + ReturnStatement: { + enter: function (nodePath, state) { const argument = nodePath.get('argument'); if (argument.hasNode()) { - returnPath = resolveToValue(argument); + state.returnPath = resolveToValue(argument) as NodePath; + + return nodePath.stop(); } + nodePath.skip(); }, - }); + }, +}); + +// TODO needs unit test + +export default function resolveFunctionDefinitionToReturnValue( + path: NodePath, +): NodePath | null { + const body = path.get('body'); + const state: TraverseState = {}; + + body.traverse(explodedVisitors, state); - return returnPath; + return state.returnPath || null; } diff --git a/src/utils/resolveToValue.ts b/src/utils/resolveToValue.ts index 26bfbe104e6..3d770d911f4 100644 --- a/src/utils/resolveToValue.ts +++ b/src/utils/resolveToValue.ts @@ -1,4 +1,4 @@ -import { Scope } from '@babel/traverse'; +import { Scope, visitors } from '@babel/traverse'; import type { NodePath } from '@babel/traverse'; import type { Identifier, @@ -8,7 +8,7 @@ import type { import getMemberExpressionRoot from './getMemberExpressionRoot'; import getPropertyValuePath from './getPropertyValuePath'; import { Array as toArray } from './expressionTo'; -import { traverseShallow } from './traverse'; +import { shallowIgnoreVisitors } from './traverse'; import getMemberValuePath, { isSupportedDefinitionType, } from './getMemberValuePath'; @@ -59,19 +59,17 @@ function findScopePath( return null; } -/** - * Tries to find the last value assigned to `name` in the scope created by - * `scope`. We are not descending into any statements (blocks). - */ -function findLastAssignedValue( - path: NodePath, - idPath: NodePath, -): NodePath | null { - const results: NodePath[] = []; - const name = idPath.node.name; +interface TraverseState { + readonly idPath: NodePath; + resultPath?: NodePath; +} + +const explodedVisitors = visitors.explode({ + ...shallowIgnoreVisitors, - traverseShallow(path, { - AssignmentExpression(assignmentPath) { + AssignmentExpression: { + enter: function (assignmentPath, state) { + const node = state.idPath.node; const left = assignmentPath.get('left'); // Skip anything that is not an assignment to a variable with the @@ -79,35 +77,42 @@ function findLastAssignedValue( // Ensure the LHS isn't the reference we're trying to resolve. if ( !left.isIdentifier() || - left.node === idPath.node || - left.node.name !== name || + left.node === node || + left.node.name !== node.name || assignmentPath.node.operator !== '=' ) { - return; + return assignmentPath.skip(); } // Ensure the RHS doesn't contain the reference we're trying to resolve. const candidatePath = assignmentPath.get('right'); if ( - candidatePath.node === idPath.node || - idPath.findParent(parent => parent.node === candidatePath.node) + candidatePath.node === node || + state.idPath.findParent(parent => parent.node === candidatePath.node) ) { - return; + return assignmentPath.skip(); } - results.push(candidatePath); + state.resultPath = candidatePath; return assignmentPath.skip(); }, - }); + }, +}); - const resultPath = results.pop(); +/** + * Tries to find the last value assigned to `name` in the scope created by + * `scope`. We are not descending into any statements (blocks). + */ +function findLastAssignedValue( + path: NodePath, + idPath: NodePath, +): NodePath | null { + const state: TraverseState = { idPath }; - if (resultPath == null) { - return null; - } + path.traverse(explodedVisitors, state); - return resolveToValue(resultPath); + return state.resultPath ? resolveToValue(state.resultPath) : null; } /** diff --git a/src/utils/traverse.ts b/src/utils/traverse.ts index ea8555f9280..355824fb264 100644 --- a/src/utils/traverse.ts +++ b/src/utils/traverse.ts @@ -1,32 +1,24 @@ -import type { NodePath, Visitor } from '@babel/traverse'; +import type { NodePath } from '@babel/traverse'; export function ignore(path: NodePath): void { path.skip(); } -/** - * A helper function that doesn't traverse into nested blocks / statements by - * default. - */ -export function traverseShallow(path: NodePath, visitors: Visitor): void { - path.traverse({ ...shallowIgnoreVisitors, ...visitors }); -} - export const shallowIgnoreVisitors = { - FunctionDeclaration: ignore, - FunctionExpression: ignore, - ClassDeclaration: ignore, - ClassExpression: ignore, - IfStatement: ignore, - WithStatement: ignore, - SwitchStatement: ignore, - CatchClause: ignore, - WhileStatement: ignore, - DoWhileStatement: ignore, - ForStatement: ignore, - ForInStatement: ignore, - ForOfStatement: ignore, - ExportNamedDeclaration: ignore, - ExportDefaultDeclaration: ignore, - ConditionalExpression: ignore, + FunctionDeclaration: { enter: ignore }, + FunctionExpression: { enter: ignore }, + ClassDeclaration: { enter: ignore }, + ClassExpression: { enter: ignore }, + IfStatement: { enter: ignore }, + WithStatement: { enter: ignore }, + SwitchStatement: { enter: ignore }, + CatchClause: { enter: ignore }, + WhileStatement: { enter: ignore }, + DoWhileStatement: { enter: ignore }, + ForStatement: { enter: ignore }, + ForInStatement: { enter: ignore }, + ForOfStatement: { enter: ignore }, + ExportNamedDeclaration: { enter: ignore }, + ExportDefaultDeclaration: { enter: ignore }, + ConditionalExpression: { enter: ignore }, }; From 602df2e9411e0eb3f4febbebf491370f55ed8363 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 31 Jul 2022 22:20:44 +0200 Subject: [PATCH 30/44] chore: fix workflow --- .github/workflows/build.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0e976252631..ad73388c7a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: run: yarn install --frozen-lockfile --non-interactive - name: Unit tests - run: yarn test --ci --coverage + run: yarn test:ci - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 diff --git a/package.json b/package.json index 66b20725fc5..5ed45b7a231 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "fix": "eslint . --ext .js,.ts --fix --report-unused-disable-directives", "start": "cd website && yarn && yarn start", "test": "yarn lint && yarn build && jest", - "test:ci": "yarn build && jest" + "test:ci": "yarn build && jest --ci --coverage" }, "keywords": [ "react", From 764ad2ed8e9a83e05fe369c74cd64e46f6a2ac72 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 31 Jul 2022 22:25:09 +0200 Subject: [PATCH 31/44] chore: add version 4 to benchmark --- benchmark/index.js | 8 +- benchmark/package-lock.json | 2684 +++++++++++++++++++++++++++++++++++ benchmark/package.json | 1 + benchmark/yarn.lock | 1550 ++++++++++---------- 4 files changed, 3492 insertions(+), 751 deletions(-) create mode 100644 benchmark/package-lock.json diff --git a/benchmark/index.js b/benchmark/index.js index 72c3f6fab36..218a1ec44ce 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -3,12 +3,13 @@ const path = require('path'); const Table = require('cli-table'); const Benchmark = require('benchmark'); const { parse } = require('..'); +const { parse: parse4 } = require('react-docgen4'); const { parse: parse5 } = require('react-docgen5'); const { parse: parse6old } = require('react-docgen6pre'); console.log(`Node: ${process.version}`); -const head = ['fixture', 'current', 'v6.0.0-alpha.3', 'v5.4.3']; +const head = ['fixture', 'current', 'v6.0.0-alpha.3', 'v5.4.3', 'v4.1.1']; const files = ['./fixtures/CircularProgress.js']; @@ -34,7 +35,9 @@ files.forEach(file => { // warmup parse(code, undefined, undefined, undefined, options); + parse6old(code, undefined, undefined, options); parse5(code, undefined, undefined, options); + parse4(code, undefined, undefined, options); global.gc(); suite.add('current', () => { parse(code, undefined, undefined, undefined, options); @@ -45,6 +48,9 @@ files.forEach(file => { suite.add('v5.4.3', () => { parse5(code, undefined, undefined, options); }); + suite.add('v4.1.1', () => { + parse4(code, undefined, undefined, options); + }); const result = [suite.name]; suite.on('cycle', function (event) { diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json new file mode 100644 index 00000000000..bf3cdadff84 --- /dev/null +++ b/benchmark/package-lock.json @@ -0,0 +1,2684 @@ +{ + "name": "react-docgen-benchmark", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "react-docgen-benchmark", + "license": "MIT", + "dependencies": { + "benchmark": "2.1.4", + "cli-table": "0.3.11", + "microtime": "3.1.0", + "react-docgen4": "npm:react-docgen@4.1.1", + "react-docgen5": "npm:react-docgen@5.4.3", + "react-docgen6pre": "npm:react-docgen@6.0.0-alpha.3" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", + "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", + "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz", + "integrity": "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.9", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", + "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", + "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", + "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", + "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", + "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", + "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz", + "integrity": "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.9", + "@babel/types": "^7.18.9", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", + "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "license": "MIT" + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", + "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001366", + "electron-to-chromium": "^1.4.188", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/c8": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", + "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001369", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz", + "integrity": "sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz", + "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==", + "dependencies": { + "colors": "1.0.3" + }, + "engines": { + "node": ">= 0.2.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.199", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz", + "integrity": "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-to-babel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz", + "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.2.0", + "c8": "^7.6.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "license": "MIT" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/microtime": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/microtime/-/microtime-3.1.0.tgz", + "integrity": "sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.4.0" + }, + "engines": { + "node": ">= 14.13.0" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==", + "license": "MIT" + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "license": "ISC" + }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "license": "MIT" + }, + "node_modules/private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react-docgen4": { + "name": "react-docgen", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-4.1.1.tgz", + "integrity": "sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==", + "dependencies": { + "@babel/core": "^7.0.0", + "@babel/runtime": "^7.0.0", + "async": "^2.1.4", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "node-dir": "^0.1.10", + "recast": "^0.17.3" + }, + "bin": { + "react-docgen": "bin/react-docgen.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/react-docgen5": { + "name": "react-docgen", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", + "integrity": "sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.7.5", + "@babel/generator": "^7.12.11", + "@babel/runtime": "^7.7.6", + "ast-types": "^0.14.2", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "estree-to-babel": "^3.1.0", + "neo-async": "^2.6.1", + "node-dir": "^0.1.10", + "strip-indent": "^3.0.0" + }, + "bin": { + "react-docgen": "bin/react-docgen.js" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/react-docgen6pre": { + "name": "react-docgen", + "version": "6.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz", + "integrity": "sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.7.5", + "@babel/generator": "^7.12.11", + "ast-types": "^0.14.2", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "estree-to-babel": "^3.1.0", + "neo-async": "^2.6.1", + "node-dir": "^0.1.10", + "resolve": "^1.17.0", + "strip-indent": "^3.0.0" + }, + "bin": { + "react-docgen": "bin/react-docgen.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/recast": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz", + "integrity": "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==", + "dependencies": { + "ast-types": "0.12.4", + "esprima": "~4.0.0", + "private": "^0.1.8", + "source-map": "~0.6.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/ast-types": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", + "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "license": "0BSD" + }, + "node_modules/update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", + "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==" + }, + "@babel/core": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", + "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz", + "integrity": "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==", + "requires": { + "@babel/types": "^7.18.9", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", + "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.20.2", + "semver": "^6.3.0" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + }, + "@babel/helper-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", + "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", + "requires": { + "@babel/template": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", + "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + }, + "@babel/helpers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", + "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", + "requires": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", + "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==" + }, + "@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", + "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/traverse": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz", + "integrity": "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.9", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.18.9", + "@babel/types": "^7.18.9", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", + "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "requires": { + "tslib": "^2.0.1" + } + }, + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "requires": { + "lodash": "^4.17.14" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", + "requires": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browserslist": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", + "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "requires": { + "caniuse-lite": "^1.0.30001366", + "electron-to-chromium": "^1.4.188", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.4" + } + }, + "c8": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", + "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + } + }, + "caniuse-lite": { + "version": "1.0.30001369", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz", + "integrity": "sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cli-table": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz", + "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==", + "requires": { + "colors": "1.0.3" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.4.199", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz", + "integrity": "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "estree-to-babel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz", + "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", + "requires": { + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.2.0", + "c8": "^7.6.0" + } + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "microtime": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/microtime/-/microtime-3.1.0.tgz", + "integrity": "sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ==", + "requires": { + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.4.0" + } + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "requires": { + "minimatch": "^3.0.2" + } + }, + "node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==" + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "react-docgen4": { + "version": "npm:react-docgen@4.1.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-4.1.1.tgz", + "integrity": "sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==", + "requires": { + "@babel/core": "^7.0.0", + "@babel/runtime": "^7.0.0", + "async": "^2.1.4", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "node-dir": "^0.1.10", + "recast": "^0.17.3" + } + }, + "react-docgen5": { + "version": "npm:react-docgen@5.4.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", + "integrity": "sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==", + "requires": { + "@babel/core": "^7.7.5", + "@babel/generator": "^7.12.11", + "@babel/runtime": "^7.7.6", + "ast-types": "^0.14.2", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "estree-to-babel": "^3.1.0", + "neo-async": "^2.6.1", + "node-dir": "^0.1.10", + "strip-indent": "^3.0.0" + } + }, + "react-docgen6pre": { + "version": "npm:react-docgen@6.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz", + "integrity": "sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA==", + "requires": { + "@babel/core": "^7.7.5", + "@babel/generator": "^7.12.11", + "ast-types": "^0.14.2", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "estree-to-babel": "^3.1.0", + "neo-async": "^2.6.1", + "node-dir": "^0.1.10", + "resolve": "^1.17.0", + "strip-indent": "^3.0.0" + } + }, + "recast": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz", + "integrity": "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==", + "requires": { + "ast-types": "0.12.4", + "esprima": "~4.0.0", + "private": "^0.1.8", + "source-map": "~0.6.1" + }, + "dependencies": { + "ast-types": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", + "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==" + } + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "requires": { + "min-indent": "^1.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} diff --git a/benchmark/package.json b/benchmark/package.json index 7c3ef3a770e..ef32abd59c8 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -11,6 +11,7 @@ "benchmark": "2.1.4", "cli-table": "0.3.11", "microtime": "3.1.0", + "react-docgen4": "npm:react-docgen@4.1.1", "react-docgen5": "npm:react-docgen@5.4.3", "react-docgen6pre": "npm:react-docgen@6.0.0-alpha.3" } diff --git a/benchmark/yarn.lock b/benchmark/yarn.lock index ae7f2183d93..61ebddb7ca5 100644 --- a/benchmark/yarn.lock +++ b/benchmark/yarn.lock @@ -3,29 +3,29 @@ "@ampproject/remapping@^2.1.0": - version "2.2.0" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + "integrity" "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==" + "resolved" "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" + "version" "2.2.0" dependencies: "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" "@babel/code-frame@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + "integrity" "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/highlight" "^7.18.6" "@babel/compat-data@^7.18.8": - version "7.18.8" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz" - integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== + "integrity" "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==" + "resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz" + "version" "7.18.8" -"@babel/core@^7.7.5": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz" - integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g== +"@babel/core@^7.0.0", "@babel/core@^7.7.5": + "integrity" "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==" + "resolved" "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz" + "version" "7.18.9" dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.18.6" @@ -37,62 +37,62 @@ "@babel/template" "^7.18.6" "@babel/traverse" "^7.18.9" "@babel/types" "^7.18.9" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.1" - semver "^6.3.0" + "convert-source-map" "^1.7.0" + "debug" "^4.1.0" + "gensync" "^1.0.0-beta.2" + "json5" "^2.2.1" + "semver" "^6.3.0" "@babel/generator@^7.12.11", "@babel/generator@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz" - integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug== + "integrity" "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==" + "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz" + "version" "7.18.9" dependencies: "@babel/types" "^7.18.9" "@jridgewell/gen-mapping" "^0.3.2" - jsesc "^2.5.1" + "jsesc" "^2.5.1" "@babel/helper-compilation-targets@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz" - integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== + "integrity" "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==" + "resolved" "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz" + "version" "7.18.9" dependencies: "@babel/compat-data" "^7.18.8" "@babel/helper-validator-option" "^7.18.6" - browserslist "^4.20.2" - semver "^6.3.0" + "browserslist" "^4.20.2" + "semver" "^6.3.0" "@babel/helper-environment-visitor@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" - integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + "integrity" "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" + "version" "7.18.9" "@babel/helper-function-name@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz" - integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + "integrity" "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==" + "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz" + "version" "7.18.9" dependencies: "@babel/template" "^7.18.6" "@babel/types" "^7.18.9" "@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + "integrity" "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==" + "resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/types" "^7.18.6" "@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + "integrity" "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/types" "^7.18.6" "@babel/helper-module-transforms@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz" - integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + "integrity" "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz" + "version" "7.18.9" dependencies: "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-module-imports" "^7.18.6" @@ -104,72 +104,72 @@ "@babel/types" "^7.18.9" "@babel/helper-simple-access@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz" - integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + "integrity" "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==" + "resolved" "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/types" "^7.18.6" "@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + "integrity" "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==" + "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/types" "^7.18.6" "@babel/helper-validator-identifier@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz" - integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + "integrity" "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz" + "version" "7.18.6" "@babel/helper-validator-option@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" - integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + "integrity" "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" + "version" "7.18.6" "@babel/helpers@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz" - integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== + "integrity" "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==" + "resolved" "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz" + "version" "7.18.9" dependencies: "@babel/template" "^7.18.6" "@babel/traverse" "^7.18.9" "@babel/types" "^7.18.9" "@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + "integrity" "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==" + "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" + "chalk" "^2.0.0" + "js-tokens" "^4.0.0" "@babel/parser@^7.18.6", "@babel/parser@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz" - integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg== + "integrity" "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==" + "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz" + "version" "7.18.9" -"@babel/runtime@^7.7.6": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz" - integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.7.6": + "integrity" "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==" + "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz" + "version" "7.18.9" dependencies: - regenerator-runtime "^0.13.4" + "regenerator-runtime" "^0.13.4" "@babel/template@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz" - integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== + "integrity" "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==" + "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz" + "version" "7.18.6" dependencies: "@babel/code-frame" "^7.18.6" "@babel/parser" "^7.18.6" "@babel/types" "^7.18.6" "@babel/traverse@^7.1.6", "@babel/traverse@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz" - integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg== + "integrity" "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==" + "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz" + "version" "7.18.9" dependencies: "@babel/code-frame" "^7.18.6" "@babel/generator" "^7.18.9" @@ -179,752 +179,802 @@ "@babel/helper-split-export-declaration" "^7.18.6" "@babel/parser" "^7.18.9" "@babel/types" "^7.18.9" - debug "^4.1.0" - globals "^11.1.0" + "debug" "^4.1.0" + "globals" "^11.1.0" "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.2.0": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz" - integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg== + "integrity" "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==" + "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz" + "version" "7.18.9" dependencies: "@babel/helper-validator-identifier" "^7.18.6" - to-fast-properties "^2.0.0" + "to-fast-properties" "^2.0.0" "@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "integrity" "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + "resolved" "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + "version" "0.2.3" "@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": - version "0.1.3" - resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + "integrity" "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" + "resolved" "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + "version" "0.1.3" "@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + "integrity" "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==" + "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" + "version" "0.1.1" dependencies: "@jridgewell/set-array" "^1.0.0" "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + "integrity" "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==" + "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + "version" "0.3.2" dependencies: "@jridgewell/set-array" "^1.0.1" "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + "integrity" "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + "resolved" "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + "version" "3.1.0" "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + "integrity" "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "resolved" "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + "version" "1.1.2" "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + "integrity" "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "resolved" "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + "version" "1.4.14" "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.14" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz" - integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + "integrity" "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==" + "resolved" "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz" + "version" "0.3.14" dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + "integrity" "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + "resolved" "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + "version" "2.0.4" -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +"ansi-regex@^5.0.1": + "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + "version" "5.0.1" -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== +"ansi-styles@^3.2.1": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" dependencies: - color-convert "^1.9.0" + "color-convert" "^1.9.0" -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== +"ansi-styles@^4.0.0": + "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + "version" "4.3.0" dependencies: - color-convert "^2.0.1" + "color-convert" "^2.0.1" -ast-types@^0.14.2: - version "0.14.2" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz" - integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== +"ast-types@^0.14.2": + "integrity" "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==" + "resolved" "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz" + "version" "0.14.2" dependencies: - tslib "^2.0.1" + "tslib" "^2.0.1" -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +"ast-types@0.12.4": + "integrity" "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==" + "resolved" "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz" + "version" "0.12.4" -benchmark@2.1.4: - version "2.1.4" - resolved "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz" - integrity sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ== +"async@^2.1.4": + "integrity" "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==" + "resolved" "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + "version" "2.6.4" dependencies: - lodash "^4.17.4" - platform "^1.3.3" + "lodash" "^4.17.14" -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +"balanced-match@^1.0.0": + "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + "version" "1.0.2" + +"benchmark@2.1.4": + "integrity" "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==" + "resolved" "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz" + "version" "2.1.4" + dependencies: + "lodash" "^4.17.4" + "platform" "^1.3.3" + +"brace-expansion@^1.1.7": + "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + "version" "1.1.11" dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" + "balanced-match" "^1.0.0" + "concat-map" "0.0.1" -browserslist@^4.20.2: - version "4.21.2" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz" - integrity sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA== +"browserslist@^4.20.2", "browserslist@>= 4.21.0": + "integrity" "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==" + "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz" + "version" "4.21.2" dependencies: - caniuse-lite "^1.0.30001366" - electron-to-chromium "^1.4.188" - node-releases "^2.0.6" - update-browserslist-db "^1.0.4" + "caniuse-lite" "^1.0.30001366" + "electron-to-chromium" "^1.4.188" + "node-releases" "^2.0.6" + "update-browserslist-db" "^1.0.4" -c8@^7.6.0: - version "7.12.0" - resolved "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz" - integrity sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A== +"c8@^7.6.0": + "integrity" "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==" + "resolved" "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz" + "version" "7.12.0" dependencies: "@bcoe/v8-coverage" "^0.2.3" "@istanbuljs/schema" "^0.1.3" - find-up "^5.0.0" - foreground-child "^2.0.0" - istanbul-lib-coverage "^3.2.0" - istanbul-lib-report "^3.0.0" - istanbul-reports "^3.1.4" - rimraf "^3.0.2" - test-exclude "^6.0.0" - v8-to-istanbul "^9.0.0" - yargs "^16.2.0" - yargs-parser "^20.2.9" - -caniuse-lite@^1.0.30001366: - version "1.0.30001369" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz" - integrity sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -cli-table@0.3.11: - version "0.3.11" - resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz" - integrity sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ== - dependencies: - colors "1.0.3" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colors@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" - integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== - -commander@^2.19.0: - version "2.20.3" - resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -cross-spawn@^7.0.0: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^4.1.0: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -electron-to-chromium@^1.4.188: - version "1.4.199" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz" - integrity sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + "find-up" "^5.0.0" + "foreground-child" "^2.0.0" + "istanbul-lib-coverage" "^3.2.0" + "istanbul-lib-report" "^3.0.0" + "istanbul-reports" "^3.1.4" + "rimraf" "^3.0.2" + "test-exclude" "^6.0.0" + "v8-to-istanbul" "^9.0.0" + "yargs" "^16.2.0" + "yargs-parser" "^20.2.9" + +"caniuse-lite@^1.0.30001366": + "integrity" "sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA==" + "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz" + "version" "1.0.30001369" + +"chalk@^2.0.0": + "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + "version" "2.4.2" + dependencies: + "ansi-styles" "^3.2.1" + "escape-string-regexp" "^1.0.5" + "supports-color" "^5.3.0" + +"cli-table@0.3.11": + "integrity" "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==" + "resolved" "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz" + "version" "0.3.11" + dependencies: + "colors" "1.0.3" + +"cliui@^7.0.2": + "integrity" "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==" + "resolved" "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + "version" "7.0.4" + dependencies: + "string-width" "^4.2.0" + "strip-ansi" "^6.0.0" + "wrap-ansi" "^7.0.0" + +"color-convert@^1.9.0": + "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + "version" "1.9.3" + dependencies: + "color-name" "1.1.3" + +"color-convert@^2.0.1": + "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "color-name" "~1.1.4" + +"color-name@~1.1.4": + "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + "version" "1.1.4" + +"color-name@1.1.3": + "integrity" "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + "version" "1.1.3" + +"colors@1.0.3": + "integrity" "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==" + "resolved" "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" + "version" "1.0.3" + +"commander@^2.19.0": + "integrity" "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "resolved" "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + "version" "2.20.3" + +"concat-map@0.0.1": + "integrity" "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "version" "0.0.1" + +"convert-source-map@^1.6.0", "convert-source-map@^1.7.0": + "integrity" "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==" + "resolved" "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" + "version" "1.8.0" + dependencies: + "safe-buffer" "~5.1.1" + +"cross-spawn@^7.0.0": + "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" + "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + "version" "7.0.3" + dependencies: + "path-key" "^3.1.0" + "shebang-command" "^2.0.0" + "which" "^2.0.1" + +"debug@^4.1.0": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" + dependencies: + "ms" "2.1.2" + +"doctrine@^3.0.0": + "integrity" "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==" + "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "esutils" "^2.0.2" + +"electron-to-chromium@^1.4.188": + "integrity" "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==" + "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz" + "version" "1.4.199" + +"emoji-regex@^8.0.0": + "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + "version" "8.0.0" + +"escalade@^3.1.1": + "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + "version" "3.1.1" + +"escape-string-regexp@^1.0.5": + "integrity" "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "version" "1.0.5" -estree-to-babel@^3.1.0: - version "3.2.1" - resolved "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz" - integrity sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg== +"esprima@~4.0.0": + "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + "version" "4.0.1" + +"estree-to-babel@^3.1.0": + "integrity" "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==" + "resolved" "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz" + "version" "3.2.1" dependencies: "@babel/traverse" "^7.1.6" "@babel/types" "^7.2.0" - c8 "^7.6.0" - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -foreground-child@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz" - integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^3.0.2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -glob@^7.1.3, glob@^7.1.4: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-core-module@^2.9.0: - version "2.9.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz" - integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== - dependencies: - has "^1.0.3" - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-reports@^3.1.4: - version "3.1.5" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" - integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json5@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash@^4.17.4: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -microtime@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/microtime/-/microtime-3.1.0.tgz#599a71250e3116c59f0fe5271dae4cc44321869c" - integrity sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ== - dependencies: - node-addon-api "^5.0.0" - node-gyp-build "^4.4.0" - -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - -minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -neo-async@^2.6.1: - version "2.6.2" - resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -node-addon-api@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.0.0.tgz#7d7e6f9ef89043befdb20c1989c905ebde18c501" - integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA== - -node-dir@^0.1.10: - version "0.1.17" - resolved "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz" - integrity sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg== - dependencies: - minimatch "^3.0.2" - -node-gyp-build@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" - integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== - -node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -platform@^1.3.3: - version "1.3.6" - resolved "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz" - integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== + "c8" "^7.6.0" + +"esutils@^2.0.2": + "integrity" "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "resolved" "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + "version" "2.0.3" + +"find-up@^5.0.0": + "integrity" "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "locate-path" "^6.0.0" + "path-exists" "^4.0.0" + +"foreground-child@^2.0.0": + "integrity" "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==" + "resolved" "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "cross-spawn" "^7.0.0" + "signal-exit" "^3.0.2" + +"fs.realpath@^1.0.0": + "integrity" "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "version" "1.0.0" + +"function-bind@^1.1.1": + "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + "version" "1.1.1" + +"gensync@^1.0.0-beta.2": + "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + "version" "1.0.0-beta.2" + +"get-caller-file@^2.0.5": + "integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + "version" "2.0.5" + +"glob@^7.1.3", "glob@^7.1.4": + "integrity" "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==" + "resolved" "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + "version" "7.2.3" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^3.1.1" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" + +"globals@^11.1.0": + "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + "version" "11.12.0" + +"has-flag@^3.0.0": + "integrity" "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + "version" "3.0.0" + +"has-flag@^4.0.0": + "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + "version" "4.0.0" + +"has@^1.0.3": + "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" + "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "function-bind" "^1.1.1" + +"html-escaper@^2.0.0": + "integrity" "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + "resolved" "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + "version" "2.0.2" + +"inflight@^1.0.4": + "integrity" "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==" + "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "once" "^1.3.0" + "wrappy" "1" + +"inherits@2": + "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + "version" "2.0.4" + +"is-core-module@^2.9.0": + "integrity" "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==" + "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz" + "version" "2.9.0" + dependencies: + "has" "^1.0.3" + +"is-fullwidth-code-point@^3.0.0": + "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + "version" "3.0.0" + +"isexe@^2.0.0": + "integrity" "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + "version" "2.0.0" + +"istanbul-lib-coverage@^3.0.0", "istanbul-lib-coverage@^3.2.0": + "integrity" "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" + "resolved" "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" + "version" "3.2.0" + +"istanbul-lib-report@^3.0.0": + "integrity" "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==" + "resolved" "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "istanbul-lib-coverage" "^3.0.0" + "make-dir" "^3.0.0" + "supports-color" "^7.1.0" + +"istanbul-reports@^3.1.4": + "integrity" "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==" + "resolved" "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" + "version" "3.1.5" + dependencies: + "html-escaper" "^2.0.0" + "istanbul-lib-report" "^3.0.0" + +"js-tokens@^4.0.0": + "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + "version" "4.0.0" + +"jsesc@^2.5.1": + "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + "version" "2.5.2" + +"json5@^2.2.1": + "integrity" "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" + "version" "2.2.1" + +"locate-path@^6.0.0": + "integrity" "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "p-locate" "^5.0.0" + +"lodash@^4.17.14", "lodash@^4.17.4": + "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + "version" "4.17.21" + +"make-dir@^3.0.0": + "integrity" "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==" + "resolved" "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "semver" "^6.0.0" + +"microtime@3.1.0": + "integrity" "sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ==" + "resolved" "https://registry.npmjs.org/microtime/-/microtime-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "node-addon-api" "^5.0.0" + "node-gyp-build" "^4.4.0" + +"min-indent@^1.0.0": + "integrity" "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" + "resolved" "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" + "version" "1.0.1" + +"minimatch@^3.0.2", "minimatch@^3.0.4", "minimatch@^3.1.1": + "integrity" "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + "version" "3.1.2" + dependencies: + "brace-expansion" "^1.1.7" + +"ms@2.1.2": + "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + "version" "2.1.2" + +"neo-async@^2.6.1": + "integrity" "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + "resolved" "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" + "version" "2.6.2" + +"node-addon-api@^5.0.0": + "integrity" "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + "resolved" "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz" + "version" "5.0.0" + +"node-dir@^0.1.10": + "integrity" "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==" + "resolved" "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz" + "version" "0.1.17" + dependencies: + "minimatch" "^3.0.2" + +"node-gyp-build@^4.4.0": + "integrity" "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==" + "resolved" "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz" + "version" "4.5.0" + +"node-releases@^2.0.6": + "integrity" "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" + "version" "2.0.6" + +"once@^1.3.0": + "integrity" "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" + "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "wrappy" "1" + +"p-limit@^3.0.2": + "integrity" "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "yocto-queue" "^0.1.0" + +"p-locate@^5.0.0": + "integrity" "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "p-limit" "^3.0.2" + +"path-exists@^4.0.0": + "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + "version" "4.0.0" + +"path-is-absolute@^1.0.0": + "integrity" "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "version" "1.0.1" + +"path-key@^3.1.0": + "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + "version" "3.1.1" + +"path-parse@^1.0.7": + "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + "version" "1.0.7" + +"picocolors@^1.0.0": + "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + "version" "1.0.0" + +"platform@^1.3.3": + "integrity" "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" + "resolved" "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz" + "version" "1.3.6" + +"private@^0.1.8": + "integrity" "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + "resolved" "https://registry.npmjs.org/private/-/private-0.1.8.tgz" + "version" "0.1.8" + +"react-docgen4@npm:react-docgen@4.1.1": + "integrity" "sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==" + "resolved" "https://registry.npmjs.org/react-docgen/-/react-docgen-4.1.1.tgz" + "version" "4.1.1" + dependencies: + "@babel/core" "^7.0.0" + "@babel/runtime" "^7.0.0" + "async" "^2.1.4" + "commander" "^2.19.0" + "doctrine" "^3.0.0" + "node-dir" "^0.1.10" + "recast" "^0.17.3" "react-docgen5@npm:react-docgen@5.4.3": - version "5.4.3" - resolved "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz" - integrity sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA== + "integrity" "sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==" + "resolved" "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz" + "version" "5.4.3" dependencies: "@babel/core" "^7.7.5" "@babel/generator" "^7.12.11" "@babel/runtime" "^7.7.6" - ast-types "^0.14.2" - commander "^2.19.0" - doctrine "^3.0.0" - estree-to-babel "^3.1.0" - neo-async "^2.6.1" - node-dir "^0.1.10" - strip-indent "^3.0.0" + "ast-types" "^0.14.2" + "commander" "^2.19.0" + "doctrine" "^3.0.0" + "estree-to-babel" "^3.1.0" + "neo-async" "^2.6.1" + "node-dir" "^0.1.10" + "strip-indent" "^3.0.0" "react-docgen6pre@npm:react-docgen@6.0.0-alpha.3": - version "6.0.0-alpha.3" - resolved "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz" - integrity sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA== + "integrity" "sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA==" + "resolved" "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz" + "version" "6.0.0-alpha.3" dependencies: "@babel/core" "^7.7.5" "@babel/generator" "^7.12.11" - ast-types "^0.14.2" - commander "^2.19.0" - doctrine "^3.0.0" - estree-to-babel "^3.1.0" - neo-async "^2.6.1" - node-dir "^0.1.10" - resolve "^1.17.0" - strip-indent "^3.0.0" - -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -resolve@^1.17.0: - version "1.22.1" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.2: - version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + "ast-types" "^0.14.2" + "commander" "^2.19.0" + "doctrine" "^3.0.0" + "estree-to-babel" "^3.1.0" + "neo-async" "^2.6.1" + "node-dir" "^0.1.10" + "resolve" "^1.17.0" + "strip-indent" "^3.0.0" + +"recast@^0.17.3": + "integrity" "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==" + "resolved" "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz" + "version" "0.17.6" + dependencies: + "ast-types" "0.12.4" + "esprima" "~4.0.0" + "private" "^0.1.8" + "source-map" "~0.6.1" + +"regenerator-runtime@^0.13.4": + "integrity" "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" + "version" "0.13.9" + +"require-directory@^2.1.1": + "integrity" "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + "resolved" "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + "version" "2.1.1" + +"resolve@^1.17.0": + "integrity" "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + "version" "1.22.1" + dependencies: + "is-core-module" "^2.9.0" + "path-parse" "^1.0.7" + "supports-preserve-symlinks-flag" "^1.0.0" + +"rimraf@^3.0.2": + "integrity" "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "glob" "^7.1.3" + +"safe-buffer@~5.1.1": + "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + "version" "5.1.2" + +"semver@^6.0.0", "semver@^6.3.0": + "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + "version" "6.3.0" + +"shebang-command@^2.0.0": + "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" + "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "shebang-regex" "^3.0.0" + +"shebang-regex@^3.0.0": + "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + "version" "3.0.0" + +"signal-exit@^3.0.2": + "integrity" "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + "version" "3.0.7" + +"source-map@~0.6.1": + "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + "version" "0.6.1" + +"string-width@^4.1.0", "string-width@^4.2.0": + "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + "version" "4.2.3" + dependencies: + "emoji-regex" "^8.0.0" + "is-fullwidth-code-point" "^3.0.0" + "strip-ansi" "^6.0.1" + +"strip-ansi@^6.0.0", "strip-ansi@^6.0.1": + "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "ansi-regex" "^5.0.1" + +"strip-indent@^3.0.0": + "integrity" "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==" + "resolved" "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "min-indent" "^1.0.0" + +"supports-color@^5.3.0": + "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + "version" "5.5.0" + dependencies: + "has-flag" "^3.0.0" + +"supports-color@^7.1.0": + "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + "version" "7.2.0" + dependencies: + "has-flag" "^4.0.0" + +"supports-preserve-symlinks-flag@^1.0.0": + "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + "version" "1.0.0" + +"test-exclude@^6.0.0": + "integrity" "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==" + "resolved" "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + "version" "6.0.0" dependencies: "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" + "glob" "^7.1.4" + "minimatch" "^3.0.4" -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== +"to-fast-properties@^2.0.0": + "integrity" "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + "version" "2.0.0" -tslib@^2.0.1: - version "2.4.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +"tslib@^2.0.1": + "integrity" "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" + "version" "2.4.0" -update-browserslist-db@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz" - integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== +"update-browserslist-db@^1.0.4": + "integrity" "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==" + "resolved" "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz" + "version" "1.0.5" dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + "escalade" "^3.1.1" + "picocolors" "^1.0.0" -v8-to-istanbul@^9.0.0: - version "9.0.1" - resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz" - integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== +"v8-to-istanbul@^9.0.0": + "integrity" "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==" + "resolved" "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz" + "version" "9.0.1" dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yargs-parser@^20.2.2, yargs-parser@^20.2.9: - version "20.2.9" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + "convert-source-map" "^1.6.0" + +"which@^2.0.1": + "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" + "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "isexe" "^2.0.0" + +"wrap-ansi@^7.0.0": + "integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" + "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + "version" "7.0.0" + dependencies: + "ansi-styles" "^4.0.0" + "string-width" "^4.1.0" + "strip-ansi" "^6.0.0" + +"wrappy@1": + "integrity" "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "version" "1.0.2" + +"y18n@^5.0.5": + "integrity" "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + "resolved" "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + "version" "5.0.8" + +"yargs-parser@^20.2.2", "yargs-parser@^20.2.9": + "integrity" "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + "version" "20.2.9" + +"yargs@^16.2.0": + "integrity" "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==" + "resolved" "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + "version" "16.2.0" + dependencies: + "cliui" "^7.0.2" + "escalade" "^3.1.1" + "get-caller-file" "^2.0.5" + "require-directory" "^2.1.1" + "string-width" "^4.2.0" + "y18n" "^5.0.5" + "yargs-parser" "^20.2.2" + +"yocto-queue@^0.1.0": + "integrity" "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + "resolved" "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + "version" "0.1.0" From 67def8b675457b1c05090340ca89fdca79e294fc Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Wed, 3 Aug 2022 23:05:20 +0200 Subject: [PATCH 32/44] chore: Remove TODOs that are solved in PR now --- package.json | 7 +-- src/FileState.ts | 4 +- src/utils/ts-types/index.ts | 85 +++++++++++++++++-------------------- tests/utils.ts | 2 - 4 files changed, 44 insertions(+), 54 deletions(-) diff --git a/package.json b/package.json index 5ed45b7a231..7e733d34e57 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,10 @@ "build": "rimraf dist/ && tsc", "lint": "eslint . --ext .js,.ts --report-unused-disable-directives", "fix": "eslint . --ext .js,.ts --fix --report-unused-disable-directives", - "start": "cd website && yarn && yarn start", - "test": "yarn lint && yarn build && jest", - "test:ci": "yarn build && jest --ci --coverage" + "test": "yarn website:install && yarn lint && yarn build && jest", + "test:ci": "yarn build && jest --ci --coverage", + "website:install": "cd website && yarn", + "website:start": "yarn website:install && cd website && yarn start" }, "keywords": [ "react", diff --git a/src/FileState.ts b/src/FileState.ts index ea73155bacf..b82ce8d52cc 100644 --- a/src/FileState.ts +++ b/src/FileState.ts @@ -56,7 +56,7 @@ export default class FileState { parent: this.ast, container: this.ast, key: 'program', - // @ts-expect-error TODO FIX DT https://github.com/babel/babel/blob/b58e35b6aa30a4c58da3147ae4a1fb5cef2073c9/packages/babel-traverse/src/path/context.ts#L158 + // @ts-expect-error TODO DONE wait for update to types }).setContext() as NodePath; this.scope = this.path.scope; } @@ -91,7 +91,7 @@ export default class FileState { /** * Traverse the current file */ - traverse(visitors: Visitor, state?: any): void { + traverse(visitors: Visitor, state?: unknown): void { traverse(this.ast, visitors, this.scope, state); } } diff --git a/src/utils/ts-types/index.ts b/src/utils/ts-types/index.ts index 6db5cd0ed76..93fc2d77bd1 100644 --- a/src/utils/ts-types/index.ts +++ b/src/utils/ts-types/index.ts @@ -58,7 +58,6 @@ class TypeBinding { scope: BaseScope; typeKind: TypeKind; }) { - // TODO fix DT and remove existing from params this.identifier = data.identifier; this.identifierPath = data.identifierPath; this.path = data.path; @@ -73,52 +72,41 @@ function registerTypeBinding( path: NodePath, bindingPath: NodePath, ): void { - const ids = { [path.node.name]: [path.node] }; - - // TODO remove loop as always one identifier? - for (const name of Object.keys(ids)) { - for (const id of ids[name]) { - const local = this.getOwnTypeBinding(name); - - if (local) { - if (local.identifier === id) continue; - - if ( - // : collide, <=>: not collide, merge - // enum interface - // enum alias - // interface alias - // alias alias - // interface <=> interface - // enum <=> enum - typeKind !== local.typeKind || - typeKind === 'alias' || - local.typeKind === 'alias' - ) { - throw this.hub.buildError( - id, - `Duplicate type declaration "${name}"`, - TypeError, - ); - } - // TODO fix in DT - // this.checkBlockScopedCollisions(local as any, 'let', name, id); - } - - if (local) { - // two interface with the same name - // @ts-expect-error TODO fix DT - local.reassign(path); - } else { - this.typeBindings[name] = new TypeBinding({ - identifier: id, - identifierPath: path, - path: bindingPath, - scope: this, - typeKind, - }); - } + const id = path.node; + const { name } = id; + const local = this.getOwnTypeBinding(name); + + if (local) { + if (local.identifier === id) return; + + if ( + // : does collide, + // <=>: does not collide (type merging) + // + // enum interface + // enum alias + // interface alias + // alias alias + // interface <=> interface + // enum <=> enum + typeKind !== local.typeKind || + typeKind === 'alias' || + local.typeKind === 'alias' + ) { + throw this.hub.buildError( + id, + `Duplicate type declaration "${name}"`, + TypeError, + ); } + } else { + this.typeBindings[name] = new TypeBinding({ + identifier: id, + identifierPath: path, + path: bindingPath, + scope: this, + typeKind, + }); } } @@ -157,16 +145,19 @@ function registerDeclaration(this: BaseScope, path: NodePath): void { } export default function initialize(scopeClass: typeof BaseScope): void { - // @ts-expect-error The typ does not allow undefined, only internally + // @ts-expect-error The typ assumes getTypeBinding is always set, + // but we know we have to do that once and that is here if (scopeClass.prototype.getTypeBinding) { return; } scopeClass.prototype.getTypeBinding = getTypeBinding; scopeClass.prototype.registerTypeBinding = registerTypeBinding; scopeClass.prototype.getOwnTypeBinding = getOwnTypeBinding; + scopeClass.prototype._realRegisterDeclaration = scopeClass.prototype.registerDeclaration; scopeClass.prototype.registerDeclaration = registerDeclaration; + scopeClass.prototype._realCrawl = scopeClass.prototype.crawl; scopeClass.prototype.crawl = function (this: BaseScope) { this.typeBindings = Object.create(null); diff --git a/tests/utils.ts b/tests/utils.ts index 3da908431dd..c834e0da564 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -11,8 +11,6 @@ import type { Program, Statement, } from '@babel/types'; -// @ts-ignore TODO fix types in TD -//import { File } from '@babel/core'; declare global { // eslint-disable-next-line @typescript-eslint/no-namespace From de98231c02f21cafdd25f7d9f16ec24aa2222df8 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Fri, 5 Aug 2022 13:44:09 +0200 Subject: [PATCH 33/44] chore: update external types --- package.json | 2 +- src/FileState.ts | 1 - src/utils/resolveToValue.ts | 1 - yarn.lock | 9 ++++++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 7e733d34e57..301ddd7f8aa 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "strip-indent": "^3.0.0" }, "devDependencies": { - "@types/babel__traverse": "7.17.1", + "@types/babel__traverse": "7.18.0", "@types/cross-spawn": "6.0.2", "@types/doctrine": "0.0.5", "@types/jest": "28.1.6", diff --git a/src/FileState.ts b/src/FileState.ts index b82ce8d52cc..6db65171a51 100644 --- a/src/FileState.ts +++ b/src/FileState.ts @@ -56,7 +56,6 @@ export default class FileState { parent: this.ast, container: this.ast, key: 'program', - // @ts-expect-error TODO DONE wait for update to types }).setContext() as NodePath; this.scope = this.path.scope; } diff --git a/src/utils/resolveToValue.ts b/src/utils/resolveToValue.ts index 3d770d911f4..1c1fb53f68a 100644 --- a/src/utils/resolveToValue.ts +++ b/src/utils/resolveToValue.ts @@ -140,7 +140,6 @@ export default function resolveToValue(path: NodePath): NodePath { // block where it is defined (i.e. we are not traversing into statements) resolvedPath = findLastAssignedValue(binding.scope.path, path); if (!resolvedPath) { - // @ts-ignore TODO fix in DT const bindingMap = binding.path.getOuterBindingIdentifierPaths( true, ) as Record>>; diff --git a/yarn.lock b/yarn.lock index a8f124316f3..0eead02614b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -672,13 +672,20 @@ "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@7.17.1", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": version "7.17.1" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.17.1.tgz#1a0e73e8c28c7e832656db372b779bfd2ef37314" integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== dependencies: "@babel/types" "^7.3.0" +"@types/babel__traverse@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.0.tgz#8134fd78cb39567465be65b9fdc16d378095f41f" + integrity sha512-v4Vwdko+pgymgS+A2UIaJru93zQd85vIGWObM5ekZNdXCKtDYqATlEYnWgfo86Q6I1Lh0oXnksDnMU1cwmlPDw== + dependencies: + "@babel/types" "^7.3.0" + "@types/cross-spawn@6.0.2": version "6.0.2" resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" From e20d2d040184930773a186cde895579052496862 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Fri, 5 Aug 2022 21:00:19 +0200 Subject: [PATCH 34/44] fix: remove trailing comma and semi from raw value --- .../__snapshots__/getTSType-test.ts.snap | 1349 +++++++++++++++++ .../__snapshots__/printValue-test.ts.snap | 20 + src/utils/__tests__/getTSType-test.ts | 725 +-------- src/utils/__tests__/printValue-test.ts | 50 +- src/utils/printValue.ts | 9 +- 5 files changed, 1500 insertions(+), 653 deletions(-) create mode 100644 src/utils/__tests__/__snapshots__/getTSType-test.ts.snap diff --git a/src/utils/__tests__/__snapshots__/getTSType-test.ts.snap b/src/utils/__tests__/__snapshots__/getTSType-test.ts.snap new file mode 100644 index 00000000000..6baa7294076 --- /dev/null +++ b/src/utils/__tests__/__snapshots__/getTSType-test.ts.snap @@ -0,0 +1,1349 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getTSType React types React.ChildrenArray 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "ReactChildrenArray", + "raw": "React.ChildrenArray", +} +`; + +exports[`getTSType React types React.ComponentType 1`] = ` +Object { + "elements": Array [ + Object { + "name": "signature", + "raw": "{ x: string }", + "signature": Object { + "properties": Array [ + Object { + "key": "x", + "value": Object { + "name": "string", + "required": true, + }, + }, + ], + }, + "type": "object", + }, + ], + "name": "ReactComponentType", + "raw": "React.ComponentType", +} +`; + +exports[`getTSType React types React.Element 1`] = ` +Object { + "elements": Array [ + Object { + "name": "any", + }, + ], + "name": "ReactElement", + "raw": "React.Element", +} +`; + +exports[`getTSType React types React.ElementProps 1`] = ` +Object { + "elements": Array [ + Object { + "name": "Component", + }, + ], + "name": "ReactElementProps", + "raw": "React.ElementProps", +} +`; + +exports[`getTSType React types React.ElementRef 1`] = ` +Object { + "elements": Array [ + Object { + "name": "Component", + }, + ], + "name": "ReactElementRef", + "raw": "React.ElementRef", +} +`; + +exports[`getTSType React types React.ElementType 1`] = ` +Object { + "name": "ReactElementType", + "raw": "React.ElementType", +} +`; + +exports[`getTSType React types React.Key 1`] = ` +Object { + "name": "ReactKey", + "raw": "React.Key", +} +`; + +exports[`getTSType React types React.Node 1`] = ` +Object { + "name": "ReactNode", + "raw": "React.Node", +} +`; + +exports[`getTSType React types React.Ref 1`] = ` +Object { + "elements": Array [ + Object { + "name": "Component", + }, + ], + "name": "ReactRef", + "raw": "React.Ref", +} +`; + +exports[`getTSType React types React.StatelessFunctionalComponent 1`] = ` +Object { + "elements": Array [ + Object { + "name": "Props2", + }, + ], + "name": "ReactStatelessFunctionalComponent", + "raw": "React.StatelessFunctionalComponent", +} +`; + +exports[`getTSType can resolve indexed access to imported type 1`] = ` +Object { + "name": "string", + "raw": "A[\\"x\\"]", +} +`; + +exports[`getTSType detects array type 1`] = ` +Object { + "elements": Array [ + Object { + "name": "number", + }, + ], + "name": "Array", + "raw": "Array", +} +`; + +exports[`getTSType detects array type shorthand 1`] = ` +Object { + "elements": Array [ + Object { + "name": "number", + }, + ], + "name": "Array", + "raw": "number[]", +} +`; + +exports[`getTSType detects array type with multiple types 1`] = ` +Object { + "elements": Array [ + Object { + "name": "number", + }, + Object { + "name": "xyz", + }, + ], + "name": "Array", + "raw": "Array", +} +`; + +exports[`getTSType detects callable signature type 1`] = ` +Object { + "name": "signature", + "raw": "{ (str: string): string, token: string }", + "signature": Object { + "constructor": Object { + "name": "signature", + "raw": "(str: string): string", + "signature": Object { + "arguments": Array [ + Object { + "name": "str", + "type": Object { + "name": "string", + }, + }, + ], + "return": Object { + "name": "string", + }, + }, + "type": "function", + }, + "properties": Array [ + Object { + "key": "token", + "value": Object { + "name": "string", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType detects class type 1`] = ` +Object { + "elements": Array [ + Object { + "name": "Boolean", + }, + ], + "name": "Class", + "raw": "Class", +} +`; + +exports[`getTSType detects external type 1`] = ` +Object { + "name": "xyz", +} +`; + +exports[`getTSType detects function signature type 1`] = ` +Object { + "name": "signature", + "raw": "(p1: number, p2: string, ...rest: Array) => boolean", + "signature": Object { + "arguments": Array [ + Object { + "name": "p1", + "type": Object { + "name": "number", + }, + }, + Object { + "name": "p2", + "type": Object { + "name": "string", + }, + }, + Object { + "name": "rest", + "rest": true, + "type": Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "Array", + "raw": "Array", + }, + }, + ], + "return": Object { + "name": "boolean", + }, + }, + "type": "function", +} +`; + +exports[`getTSType detects function signature type with \`this\` parameter 1`] = ` +Object { + "name": "signature", + "raw": "(this: Foo, p1: number) => boolean", + "signature": Object { + "arguments": Array [ + Object { + "name": "p1", + "type": Object { + "name": "number", + }, + }, + ], + "return": Object { + "name": "boolean", + }, + "this": Object { + "name": "Foo", + }, + }, + "type": "function", +} +`; + +exports[`getTSType detects function type with subtype 1`] = ` +Object { + "elements": Array [ + Object { + "name": "xyz", + }, + ], + "name": "Function", + "raw": "Function", +} +`; + +exports[`getTSType detects indexed access 1`] = ` +Object { + "name": "A[\\"x\\"]", + "raw": "A[\\"x\\"]", +} +`; + +exports[`getTSType detects intersection type 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + Object { + "name": "xyz", + }, + Object { + "name": "literal", + "value": "\\"foo\\"", + }, + Object { + "name": "void", + }, + ], + "name": "intersection", + "raw": "string & xyz & \\"foo\\" & void", +} +`; + +exports[`getTSType detects map signature 1`] = ` +Object { + "name": "signature", + "raw": "{ [key: string]: number, [key: \\"xl\\"]: string, token: \\"a\\" | \\"b\\" }", + "signature": Object { + "properties": Array [ + Object { + "key": Object { + "name": "string", + }, + "value": Object { + "name": "number", + "required": true, + }, + }, + Object { + "key": Object { + "name": "literal", + "value": "\\"xl\\"", + }, + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "token", + "value": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"a\\"", + }, + Object { + "name": "literal", + "value": "\\"b\\"", + }, + ], + "name": "union", + "raw": "\\"a\\" | \\"b\\"", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType detects object types 1`] = ` +Object { + "name": "signature", + "raw": "{ a: string, b?: xyz }", + "signature": Object { + "properties": Array [ + Object { + "key": "a", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "b", + "value": Object { + "name": "xyz", + "required": false, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType detects simple types 1`] = ` +Object { + "name": "string", +} +`; + +exports[`getTSType detects simple types 2`] = ` +Object { + "name": "number", +} +`; + +exports[`getTSType detects simple types 3`] = ` +Object { + "name": "boolean", +} +`; + +exports[`getTSType detects simple types 4`] = ` +Object { + "name": "symbol", +} +`; + +exports[`getTSType detects simple types 5`] = ` +Object { + "name": "object", +} +`; + +exports[`getTSType detects simple types 6`] = ` +Object { + "name": "any", +} +`; + +exports[`getTSType detects simple types 7`] = ` +Object { + "name": "unknown", +} +`; + +exports[`getTSType detects simple types 8`] = ` +Object { + "name": "null", +} +`; + +exports[`getTSType detects simple types 9`] = ` +Object { + "name": "undefined", +} +`; + +exports[`getTSType detects simple types 10`] = ` +Object { + "name": "void", +} +`; + +exports[`getTSType detects simple types 11`] = ` +Object { + "name": "Object", +} +`; + +exports[`getTSType detects simple types 12`] = ` +Object { + "name": "Function", +} +`; + +exports[`getTSType detects simple types 13`] = ` +Object { + "name": "Boolean", +} +`; + +exports[`getTSType detects simple types 14`] = ` +Object { + "name": "String", +} +`; + +exports[`getTSType detects simple types 15`] = ` +Object { + "name": "Number", +} +`; + +exports[`getTSType detects tuple in union signature 1`] = ` +Object { + "elements": Array [ + Object { + "elements": Array [ + Object { + "name": "string", + }, + Object { + "name": "number", + }, + ], + "name": "tuple", + "raw": "[string, number]", + }, + Object { + "elements": Array [ + Object { + "name": "number", + }, + Object { + "name": "string", + }, + ], + "name": "tuple", + "raw": "[number, string]", + }, + ], + "name": "union", + "raw": "[string, number] | [number, string]", +} +`; + +exports[`getTSType detects tuple signature 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + Object { + "name": "number", + }, + ], + "name": "tuple", + "raw": "[string, number]", +} +`; + +exports[`getTSType detects union type 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + Object { + "name": "xyz", + }, + Object { + "name": "literal", + "value": "\\"foo\\"", + }, + Object { + "name": "void", + }, + ], + "name": "union", + "raw": "string | xyz | \\"foo\\" | void", +} +`; + +exports[`getTSType handles generic types 1`] = ` +Object { + "name": "signature", + "raw": "{ a: T, b: Array }", + "signature": Object { + "properties": Array [ + Object { + "key": "a", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "b", + "value": Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "Array", + "raw": "Array", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType handles generics of the same Name 1`] = ` +Object { + "elements": Array [ + Object { + "name": "T", + }, + ], + "name": "Bar", + "raw": "Bar", +} +`; + +exports[`getTSType handles long type cycles 1`] = ` +Object { + "name": "signature", + "raw": "{ subAction: SubAction }", + "signature": Object { + "properties": Array [ + Object { + "key": "subAction", + "value": Object { + "name": "signature", + "raw": "{ subAction: SubSubAction }", + "required": true, + "signature": Object { + "properties": Array [ + Object { + "key": "subAction", + "value": Object { + "name": "signature", + "raw": "{ subAction: SubSubSubAction }", + "required": true, + "signature": Object { + "properties": Array [ + Object { + "key": "subAction", + "value": Object { + "name": "signature", + "raw": "{ rootAction: Action }", + "required": true, + "signature": Object { + "properties": Array [ + Object { + "key": "rootAction", + "value": Object { + "name": "Action", + "required": true, + }, + }, + ], + }, + "type": "object", + }, + }, + ], + }, + "type": "object", + }, + }, + ], + }, + "type": "object", + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType handles mapped types 1`] = ` +Object { + "name": "signature", + "raw": "{ [key in 'x' | 'y']: boolean}", + "signature": Object { + "properties": Array [ + Object { + "key": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "'x'", + }, + Object { + "name": "literal", + "value": "'y'", + }, + ], + "name": "union", + "raw": "'x' | 'y'", + "required": true, + }, + "value": Object { + "name": "boolean", + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType handles multiple references to one type 1`] = ` +Object { + "name": "signature", + "raw": "{ a: Action, b: Action }", + "signature": Object { + "properties": Array [ + Object { + "key": "a", + "value": Object { + "name": "signature", + "raw": "{}", + "required": true, + "signature": Object { + "properties": Array [], + }, + "type": "object", + }, + }, + Object { + "key": "b", + "value": Object { + "name": "signature", + "raw": "{}", + "required": true, + "signature": Object { + "properties": Array [], + }, + "type": "object", + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType handles qualified type identifiers 1`] = ` +Object { + "name": "MyType.x", +} +`; + +exports[`getTSType handles qualified type identifiers with params 1`] = ` +Object { + "elements": Array [ + Object { + "name": "any", + }, + ], + "name": "MyType.x", + "raw": "MyType.x", +} +`; + +exports[`getTSType handles self-referencing type cycles 1`] = ` +Object { + "name": "signature", + "raw": "{ subAction: Action }", + "signature": Object { + "properties": Array [ + Object { + "key": "subAction", + "value": Object { + "name": "Action", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType handles typeof types 1`] = ` +Object { + "name": "signature", + "raw": "{ a: string, b: xyz }", + "signature": Object { + "properties": Array [ + Object { + "key": "a", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "b", + "value": Object { + "name": "xyz", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType literal types detects "foo" 1`] = ` +Object { + "name": "literal", + "value": "\\"foo\\"", +} +`; + +exports[`getTSType literal types detects \`foo\` 1`] = ` +Object { + "name": "literal", + "value": "\`foo\`", +} +`; + +exports[`getTSType literal types detects -1 1`] = ` +Object { + "name": "literal", + "value": "-1", +} +`; + +exports[`getTSType literal types detects 1234 1`] = ` +Object { + "name": "literal", + "value": "1234", +} +`; + +exports[`getTSType literal types detects true 1`] = ` +Object { + "name": "literal", + "value": "true", +} +`; + +exports[`getTSType resolves external type 1`] = ` +Object { + "name": "string", +} +`; + +exports[`getTSType resolves function signature types with imported types 1`] = ` +Object { + "name": "signature", + "raw": "(p1: abc, p2: xyz, ...rest: Array) => def", + "signature": Object { + "arguments": Array [ + Object { + "name": "p1", + "type": Object { + "name": "number", + }, + }, + Object { + "name": "p2", + "type": Object { + "name": "string", + }, + }, + Object { + "name": "rest", + "rest": true, + "type": Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "Array", + "raw": "Array", + }, + }, + ], + "return": Object { + "name": "boolean", + }, + }, + "type": "function", +} +`; + +exports[`getTSType resolves function signature types with imported types 2`] = ` +Object { + "name": "signature", + "raw": "(this: xyz, p1: number) => boolean", + "signature": Object { + "arguments": Array [ + Object { + "name": "p1", + "type": Object { + "name": "number", + }, + }, + ], + "return": Object { + "name": "boolean", + }, + "this": Object { + "name": "string", + }, + }, + "type": "function", +} +`; + +exports[`getTSType resolves function signature types with imported types 3`] = ` +Object { + "name": "signature", + "raw": "{ (str: xyz): abc, token: def }", + "signature": Object { + "constructor": Object { + "name": "signature", + "raw": "(str: xyz): abc", + "signature": Object { + "arguments": Array [ + Object { + "name": "str", + "type": Object { + "name": "string", + }, + }, + ], + "return": Object { + "name": "number", + }, + }, + "type": "function", + }, + "properties": Array [ + Object { + "key": "token", + "value": Object { + "name": "boolean", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType resolves imported subtype for class type 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "Class", + "raw": "Class", +} +`; + +exports[`getTSType resolves imported subtype for function type 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "Function", + "raw": "Function", +} +`; + +exports[`getTSType resolves imported types applied to mapped types 1`] = ` +Object { + "name": "signature", + "raw": "{ [key in barbaz]: boolean}", + "signature": Object { + "properties": Array [ + Object { + "key": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"bar\\"", + }, + Object { + "name": "literal", + "value": "\\"baz\\"", + }, + ], + "name": "union", + "raw": "\\"bar\\" | \\"baz\\"", + "required": true, + }, + "value": Object { + "name": "boolean", + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType resolves imported types for object property types 1`] = ` +Object { + "name": "signature", + "raw": "{ a: number, b?: xyz }", + "signature": Object { + "properties": Array [ + Object { + "key": "a", + "value": Object { + "name": "number", + "required": true, + }, + }, + Object { + "key": "b", + "value": Object { + "name": "string", + "required": false, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType resolves imported types in map signature 1`] = ` +Object { + "name": "signature", + "raw": "{ [key: xyz]: abc, [key: \\"xl\\"]: xyz, token: barbaz }", + "signature": Object { + "properties": Array [ + Object { + "key": Object { + "name": "string", + "required": true, + }, + "value": Object { + "name": "number", + "required": true, + }, + }, + Object { + "key": Object { + "name": "literal", + "value": "\\"xl\\"", + }, + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "token", + "value": Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"bar\\"", + }, + Object { + "name": "literal", + "value": "\\"baz\\"", + }, + ], + "name": "union", + "raw": "\\"bar\\" | \\"baz\\"", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType resolves imported types in tuple signatures 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + Object { + "name": "number", + }, + ], + "name": "tuple", + "raw": "[xyz, abc]", +} +`; + +exports[`getTSType resolves imported types in tuple signatures 2`] = ` +Object { + "elements": Array [ + Object { + "elements": Array [ + Object { + "name": "string", + }, + Object { + "name": "number", + }, + ], + "name": "tuple", + "raw": "[xyz, abc]", + }, + Object { + "elements": Array [ + Object { + "name": "number", + }, + Object { + "name": "string", + }, + ], + "name": "tuple", + "raw": "[abc, xyz]", + }, + ], + "name": "union", + "raw": "[xyz, abc] | recTup", +} +`; + +exports[`getTSType resolves imported types that need subtypes 1`] = ` +Object { + "name": "signature", + "raw": "{ a: T, b: Array }", + "signature": Object { + "properties": Array [ + Object { + "key": "a", + "value": Object { + "name": "string", + "required": true, + }, + }, + Object { + "key": "b", + "value": Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "Array", + "raw": "Array", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType resolves imported types used for arrays 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "Array", + "raw": "xyz[]", +} +`; + +exports[`getTSType resolves imported types used for arrays 2`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + ], + "name": "Array", + "raw": "Array", +} +`; + +exports[`getTSType resolves imported types used for arrays 3`] = ` +Object { + "elements": Array [ + Object { + "name": "number", + }, + Object { + "name": "string", + }, + ], + "name": "Array", + "raw": "Array", +} +`; + +exports[`getTSType resolves imported types within intersection type 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"bar\\"", + }, + Object { + "name": "literal", + "value": "\\"baz\\"", + }, + ], + "name": "union", + "raw": "\\"bar\\" | \\"baz\\"", + }, + Object { + "name": "literal", + "value": "\\"foo\\"", + }, + Object { + "name": "void", + }, + ], + "name": "intersection", + "raw": "string & barbaz & \\"foo\\" & void", +} +`; + +exports[`getTSType resolves imported types within union type 1`] = ` +Object { + "elements": Array [ + Object { + "name": "string", + }, + Object { + "elements": Array [ + Object { + "name": "literal", + "value": "\\"bar\\"", + }, + Object { + "name": "literal", + "value": "\\"baz\\"", + }, + ], + "name": "union", + "raw": "\\"bar\\" | \\"baz\\"", + }, + Object { + "name": "literal", + "value": "\\"foo\\"", + }, + Object { + "name": "void", + }, + ], + "name": "union", + "raw": "string | barbaz | \\"foo\\" | void", +} +`; + +exports[`getTSType resolves indexed access 1`] = ` +Object { + "name": "string", + "raw": "A[\\"x\\"]", +} +`; + +exports[`getTSType resolves indexed access of array 1`] = ` +Object { + "name": "STRING_VALS[number]", + "raw": "typeof STRING_VALS[number]", +} +`; + +exports[`getTSType resolves keyof to union 1`] = ` +Object { + "elements": Array [ + Object { + "name": "literal", + "value": "'apple'", + }, + Object { + "name": "literal", + "value": "'banana'", + }, + ], + "name": "union", + "raw": "keyof typeof CONTENTS", +} +`; + +exports[`getTSType resolves keyof with imported types 1`] = ` +Object { + "elements": Array [ + Object { + "name": "literal", + "value": "'apple'", + }, + Object { + "name": "literal", + "value": "'banana'", + }, + ], + "name": "union", + "raw": "keyof typeof CONTENTS", +} +`; + +exports[`getTSType resolves keyof with inline object to union 1`] = ` +Object { + "elements": Array [ + Object { + "name": "literal", + "value": "apple", + }, + Object { + "name": "literal", + "value": "banana", + }, + ], + "name": "union", + "raw": "keyof { apple: string, banana: string }", +} +`; + +exports[`getTSType resolves typeof of imported types 1`] = ` +Object { + "name": "signature", + "raw": "{ a: number, b: xyz }", + "signature": Object { + "properties": Array [ + Object { + "key": "a", + "value": Object { + "name": "number", + "required": true, + }, + }, + Object { + "key": "b", + "value": Object { + "name": "string", + "required": true, + }, + }, + ], + }, + "type": "object", +} +`; + +exports[`getTSType resolves types in scope 1`] = ` +Object { + "name": "string", +} +`; diff --git a/src/utils/__tests__/__snapshots__/printValue-test.ts.snap b/src/utils/__tests__/__snapshots__/printValue-test.ts.snap index 9434d2c38e5..4534a0b3225 100644 --- a/src/utils/__tests__/__snapshots__/printValue-test.ts.snap +++ b/src/utils/__tests__/__snapshots__/printValue-test.ts.snap @@ -5,3 +5,23 @@ exports[`printValue deindents code 1`] = ` return x; }" `; + +exports[`printValue removes trailing , for TsCallSignatureDeclaration 1`] = `"(): number"`; + +exports[`printValue removes trailing , for TsConstructSignatureDeclaration 1`] = `"new (x:number)"`; + +exports[`printValue removes trailing , for TsIndexSignature 1`] = `"[x:string]: number"`; + +exports[`printValue removes trailing , for TsMethodSignature 1`] = `"x(): number"`; + +exports[`printValue removes trailing , for TsPropertySignature 1`] = `"x: number"`; + +exports[`printValue removes trailing ; for TsCallSignatureDeclaration 1`] = `"(): number"`; + +exports[`printValue removes trailing ; for TsConstructSignatureDeclaration 1`] = `"new (x:number)"`; + +exports[`printValue removes trailing ; for TsIndexSignature 1`] = `"[x:string]: number"`; + +exports[`printValue removes trailing ; for TsMethodSignature 1`] = `"x(): number"`; + +exports[`printValue removes trailing ; for TsPropertySignature 1`] = `"x: number"`; diff --git a/src/utils/__tests__/getTSType-test.ts b/src/utils/__tests__/getTSType-test.ts index 657c22c2a2a..3b4acf63c85 100644 --- a/src/utils/__tests__/getTSType-test.ts +++ b/src/utils/__tests__/getTSType-test.ts @@ -109,7 +109,7 @@ describe('getTSType', () => { simplePropTypes.forEach(type => { const typePath = typeAlias(`let x: ${type};`); - expect(getTSType(typePath)).toEqual({ name: type }); + expect(getTSType(typePath)).toMatchSnapshot(); }); }); @@ -120,10 +120,7 @@ describe('getTSType', () => { it(`detects ${value}`, () => { const typePath = typeAlias(`let x: ${value};`); - expect(getTSType(typePath)).toEqual({ - name: 'literal', - value: `${value}`, - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); }); }); @@ -131,7 +128,7 @@ describe('getTSType', () => { it('detects external type', () => { const typePath = typeAlias('let x: xyz;'); - expect(getTSType(typePath)).toEqual({ name: 'xyz' }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves external type', () => { @@ -143,37 +140,25 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ name: 'string' }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects array type shorthand', () => { const typePath = typeAlias('let x: number[];'); - expect(getTSType(typePath)).toEqual({ - name: 'Array', - elements: [{ name: 'number' }], - raw: 'number[]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects array type', () => { const typePath = typeAlias('let x: Array;'); - expect(getTSType(typePath)).toEqual({ - name: 'Array', - elements: [{ name: 'number' }], - raw: 'Array', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects array type with multiple types', () => { const typePath = typeAlias('let x: Array;'); - expect(getTSType(typePath)).toEqual({ - name: 'Array', - elements: [{ name: 'number' }, { name: 'xyz' }], - raw: 'Array', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported types used for arrays', () => { @@ -185,11 +170,7 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'Array', - elements: [{ name: 'string' }], - raw: 'xyz[]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); typePath = typeAlias( ` @@ -198,11 +179,7 @@ describe('getTSType', () => { `, mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'Array', - elements: [{ name: 'string' }], - raw: 'Array', - }); + expect(getTSType(typePath)).toMatchSnapshot(); typePath = typeAlias( ` @@ -211,21 +188,13 @@ describe('getTSType', () => { `, mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'Array', - elements: [{ name: 'number' }, { name: 'string' }], - raw: 'Array', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects class type', () => { const typePath = typeAlias('let x: Class;'); - expect(getTSType(typePath)).toEqual({ - name: 'Class', - elements: [{ name: 'Boolean' }], - raw: 'Class', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported subtype for class type', () => { @@ -237,21 +206,13 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'Class', - elements: [{ name: 'string' }], - raw: 'Class', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects function type with subtype', () => { const typePath = typeAlias('let x: Function;'); - expect(getTSType(typePath)).toEqual({ - name: 'Function', - elements: [{ name: 'xyz' }], - raw: 'Function', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported subtype for function type', () => { @@ -263,27 +224,13 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'Function', - elements: [{ name: 'string' }], - raw: 'Function', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects object types', () => { const typePath = typeAlias('let x: { a: string, b?: xyz };'); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { key: 'a', value: { name: 'string', required: true } }, - { key: 'b', value: { name: 'xyz', required: false } }, - ], - }, - raw: '{ a: string, b?: xyz }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported types for object property types', () => { @@ -295,32 +242,13 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { key: 'a', value: { name: 'number', required: true } }, - { key: 'b', value: { name: 'string', required: false } }, - ], - }, - raw: '{ a: number, b?: xyz }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects union type', () => { const typePath = typeAlias('let x: string | xyz | "foo" | void;'); - expect(getTSType(typePath)).toEqual({ - name: 'union', - elements: [ - { name: 'string' }, - { name: 'xyz' }, - { name: 'literal', value: '"foo"' }, - { name: 'void' }, - ], - raw: 'string | xyz | "foo" | void', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported types within union type', () => { @@ -332,38 +260,13 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'union', - elements: [ - { name: 'string' }, - { - name: 'union', - elements: [ - { name: 'literal', value: '"bar"' }, - { name: 'literal', value: '"baz"' }, - ], - raw: '"bar" | "baz"', - }, - { name: 'literal', value: '"foo"' }, - { name: 'void' }, - ], - raw: 'string | barbaz | "foo" | void', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects intersection type', () => { const typePath = typeAlias('let x: string & xyz & "foo" & void;'); - expect(getTSType(typePath)).toEqual({ - name: 'intersection', - elements: [ - { name: 'string' }, - { name: 'xyz' }, - { name: 'literal', value: '"foo"' }, - { name: 'void' }, - ], - raw: 'string & xyz & "foo" & void', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported types within intersection type', () => { @@ -375,23 +278,7 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'intersection', - elements: [ - { name: 'string' }, - { - name: 'union', - elements: [ - { name: 'literal', value: '"bar"' }, - { name: 'literal', value: '"baz"' }, - ], - raw: '"bar" | "baz"', - }, - { name: 'literal', value: '"foo"' }, - { name: 'void' }, - ], - raw: 'string & barbaz & "foo" & void', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects function signature type', () => { @@ -399,42 +286,13 @@ describe('getTSType', () => { 'let x: (p1: number, p2: string, ...rest: Array) => boolean;', ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'function', - signature: { - arguments: [ - { name: 'p1', type: { name: 'number' } }, - { name: 'p2', type: { name: 'string' } }, - { - name: 'rest', - rest: true, - type: { - name: 'Array', - elements: [{ name: 'string' }], - raw: 'Array', - }, - }, - ], - return: { name: 'boolean' }, - }, - raw: '(p1: number, p2: string, ...rest: Array) => boolean', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects function signature type with `this` parameter', () => { const typePath = typeAlias('let x: (this: Foo, p1: number) => boolean;'); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'function', - signature: { - arguments: [{ name: 'p1', type: { name: 'number' } }], - this: { name: 'Foo' }, - return: { name: 'boolean' }, - }, - raw: '(this: Foo, p1: number) => boolean', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects callable signature type', () => { @@ -442,25 +300,7 @@ describe('getTSType', () => { 'let x: { (str: string): string, token: string };', ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - constructor: { - name: 'signature', - type: 'function', - signature: { - arguments: [{ name: 'str', type: { name: 'string' } }], - return: { name: 'string' }, - }, - raw: '(str: string): string,', // TODO: why does it print a comma? - }, - properties: [ - { key: 'token', value: { name: 'string', required: true } }, - ], - }, - raw: '{ (str: string): string, token: string }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves function signature types with imported types', () => { @@ -474,27 +314,7 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'function', - signature: { - arguments: [ - { name: 'p1', type: { name: 'number' } }, - { name: 'p2', type: { name: 'string' } }, - { - name: 'rest', - rest: true, - type: { - name: 'Array', - elements: [{ name: 'string' }], - raw: 'Array', - }, - }, - ], - return: { name: 'boolean' }, - }, - raw: '(p1: abc, p2: xyz, ...rest: Array) => def', - }); + expect(getTSType(typePath)).toMatchSnapshot(); typePath = typeAlias( ` @@ -503,16 +323,8 @@ describe('getTSType', () => { `, mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'function', - signature: { - arguments: [{ name: 'p1', type: { name: 'number' } }], - this: { name: 'string' }, - return: { name: 'boolean' }, - }, - raw: '(this: xyz, p1: number) => boolean', - }); + + expect(getTSType(typePath)).toMatchSnapshot(); typePath = typeAlias( ` @@ -523,25 +335,8 @@ describe('getTSType', () => { `, mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - constructor: { - name: 'signature', - type: 'function', - signature: { - arguments: [{ name: 'str', type: { name: 'string' } }], - return: { name: 'number' }, - }, - raw: '(str: xyz): abc,', - }, - properties: [ - { key: 'token', value: { name: 'boolean', required: true } }, - ], - }, - raw: '{ (str: xyz): abc, token: def }', - }); + + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects map signature', () => { @@ -549,35 +344,7 @@ describe('getTSType', () => { 'let x: { [key: string]: number, [key: "xl"]: string, token: "a" | "b" };', ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { - key: { name: 'string' }, - value: { name: 'number', required: true }, - }, - { - key: { name: 'literal', value: '"xl"' }, - value: { name: 'string', required: true }, - }, - { - key: 'token', - value: { - name: 'union', - required: true, - raw: '"a" | "b"', - elements: [ - { name: 'literal', value: '"a"' }, - { name: 'literal', value: '"b"' }, - ], - }, - }, - ], - }, - raw: '{ [key: string]: number, [key: "xl"]: string, token: "a" | "b" }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported types in map signature', () => { @@ -591,66 +358,19 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { - key: { name: 'string', required: true }, - value: { name: 'number', required: true }, - }, - { - key: { name: 'literal', value: '"xl"' }, - value: { name: 'string', required: true }, - }, - { - key: 'token', - value: { - name: 'union', - required: true, - raw: '"bar" | "baz"', - elements: [ - { name: 'literal', value: '"bar"' }, - { name: 'literal', value: '"baz"' }, - ], - }, - }, - ], - }, - raw: '{ [key: xyz]: abc, [key: "xl"]: xyz, token: barbaz }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects tuple signature', () => { const typePath = typeAlias('let x: [string, number];'); - expect(getTSType(typePath)).toEqual({ - name: 'tuple', - elements: [{ name: 'string' }, { name: 'number' }], - raw: '[string, number]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects tuple in union signature', () => { const typePath = typeAlias('let x: [string, number] | [number, string];'); - expect(getTSType(typePath)).toEqual({ - name: 'union', - elements: [ - { - name: 'tuple', - elements: [{ name: 'string' }, { name: 'number' }], - raw: '[string, number]', - }, - { - name: 'tuple', - elements: [{ name: 'number' }, { name: 'string' }], - raw: '[number, string]', - }, - ], - raw: '[string, number] | [number, string]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported types in tuple signatures', () => { @@ -663,11 +383,7 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'tuple', - elements: [{ name: 'string' }, { name: 'number' }], - raw: '[xyz, abc]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); typePath = typeAlias( ` @@ -678,22 +394,7 @@ describe('getTSType', () => { `, mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'union', - elements: [ - { - name: 'tuple', - elements: [{ name: 'string' }, { name: 'number' }], - raw: '[xyz, abc]', - }, - { - name: 'tuple', - elements: [{ name: 'number' }, { name: 'string' }], - raw: '[abc, xyz]', - }, - ], - raw: '[xyz, abc] | recTup', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('detects indexed access', () => { @@ -703,10 +404,7 @@ describe('getTSType', () => { interface A { x: string }; `); - expect(getTSType(typePath)).toEqual({ - name: 'A["x"]', - raw: 'A["x"]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves indexed access', () => { @@ -716,10 +414,7 @@ describe('getTSType', () => { type A = { x: string }; `); - expect(getTSType(typePath)).toEqual({ - name: 'string', - raw: 'A["x"]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves indexed access of array', () => { @@ -740,10 +435,7 @@ describe('getTSType', () => { .get('typeAnnotation') .get('typeAnnotation'); - expect(getTSType(typePath)).toEqual({ - name: 'STRING_VALS[number]', - raw: 'typeof STRING_VALS[number]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('can resolve indexed access to imported type', () => { @@ -755,10 +447,7 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'string', - raw: 'A["x"]', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves types in scope', () => { @@ -768,7 +457,7 @@ describe('getTSType', () => { type MyType = string; `); - expect(getTSType(typePath)).toEqual({ name: 'string' }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles typeof types', () => { @@ -778,17 +467,7 @@ describe('getTSType', () => { type MyType = { a: string, b: xyz }; `); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { key: 'a', value: { name: 'string', required: true } }, - { key: 'b', value: { name: 'xyz', required: true } }, - ], - }, - raw: '{ a: string, b: xyz }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves typeof of imported types', () => { @@ -800,17 +479,7 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { key: 'a', value: { name: 'number', required: true } }, - { key: 'b', value: { name: 'string', required: true } }, - ], - }, - raw: '{ a: number, b: xyz }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles qualified type identifiers', () => { @@ -820,9 +489,7 @@ describe('getTSType', () => { type MyType = { a: string, b: xyz }; `); - expect(getTSType(typePath)).toEqual({ - name: 'MyType.x', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles qualified type identifiers with params', () => { @@ -832,15 +499,7 @@ describe('getTSType', () => { type MyType = { a: string, b: xyz }; `); - expect(getTSType(typePath)).toEqual({ - name: 'MyType.x', - raw: 'MyType.x', - elements: [ - { - name: 'any', - }, - ], - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles generic types', () => { @@ -850,31 +509,7 @@ describe('getTSType', () => { type MyType = { a: T, b: Array }; `); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - raw: '{ a: T, b: Array }', - signature: { - properties: [ - { - key: 'a', - value: { - name: 'string', - required: true, - }, - }, - { - key: 'b', - value: { - name: 'Array', - raw: 'Array', - required: true, - elements: [{ name: 'string' }], - }, - }, - ], - }, - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported types that need subtypes', () => { @@ -886,31 +521,7 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - raw: '{ a: T, b: Array }', - signature: { - properties: [ - { - key: 'a', - value: { - name: 'string', - required: true, - }, - }, - { - key: 'b', - value: { - name: 'Array', - raw: 'Array', - required: true, - elements: [{ name: 'string' }], - }, - }, - ], - }, - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles mapped types', () => { @@ -918,35 +529,7 @@ describe('getTSType', () => { var x: { [key in 'x' | 'y']: boolean}; `); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - raw: "{ [key in 'x' | 'y']: boolean}", - signature: { - properties: [ - { - key: { - elements: [ - { - name: 'literal', - value: "'x'", - }, - { - name: 'literal', - value: "'y'", - }, - ], - name: 'union', - raw: "'x' | 'y'", - required: true, - }, - value: { - name: 'boolean', - }, - }, - ], - }, - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves imported types applied to mapped types', () => { @@ -958,82 +541,33 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - raw: '{ [key in barbaz]: boolean}', - signature: { - properties: [ - { - key: { - elements: [ - { - name: 'literal', - value: '"bar"', - }, - { - name: 'literal', - value: '"baz"', - }, - ], - name: 'union', - raw: '"bar" | "baz"', - required: true, - }, - value: { - name: 'boolean', - }, - }, - ], - }, - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); describe('React types', () => { - function test(type, expected) { - const typePath = typeAlias(` - var x: ${type} = 2; + const types = [ + 'React.Node', + 'React.Key', + 'React.ElementType', + 'React.ChildrenArray', + 'React.Element', + 'React.Ref', + 'React.ElementProps', + 'React.ElementRef', + 'React.ComponentType', + 'React.StatelessFunctionalComponent', + ]; - type Props = { x: string }; - `); + types.forEach(type => { + it(type, () => { + const typePath = typeAlias(` + var x: ${type} = 2; - expect(getTSType(typePath)).toEqual({ - ...expected, - name: type.replace('.', '').replace(/<.+>/, ''), - raw: type, - }); - } - - const types = { - 'React.Node': {}, - 'React.Key': {}, - 'React.ElementType': {}, - 'React.ChildrenArray': { elements: [{ name: 'string' }] }, - 'React.Element': { elements: [{ name: 'any' }] }, - 'React.Ref': { elements: [{ name: 'Component' }] }, - 'React.ElementProps': { elements: [{ name: 'Component' }] }, - 'React.ElementRef': { elements: [{ name: 'Component' }] }, - 'React.ComponentType': { - elements: [ - { - name: 'signature', - raw: '{ x: string }', - signature: { - properties: [ - { key: 'x', value: { name: 'string', required: true } }, - ], - }, - type: 'object', - }, - ], - }, - 'React.StatelessFunctionalComponent': { - elements: [{ name: 'Props2' }], - }, - }; + type Props = { x: string }; + `); - Object.keys(types).forEach(type => { - it(type, () => test(type, types[type])); + expect(getTSType(typePath)).toMatchSnapshot(); + }); }); }); @@ -1046,14 +580,7 @@ describe('getTSType', () => { }; `); - expect(getTSType(typePath)).toEqual({ - name: 'union', - elements: [ - { name: 'literal', value: "'apple'" }, - { name: 'literal', value: "'banana'" }, - ], - raw: 'keyof typeof CONTENTS', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves keyof with imported types', () => { @@ -1065,14 +592,7 @@ describe('getTSType', () => { mockImporter, ); - expect(getTSType(typePath)).toEqual({ - name: 'union', - elements: [ - { name: 'literal', value: "'apple'" }, - { name: 'literal', value: "'banana'" }, - ], - raw: 'keyof typeof CONTENTS', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('resolves keyof with inline object to union', () => { @@ -1080,14 +600,7 @@ describe('getTSType', () => { var x: keyof { apple: string, banana: string } = 2; `); - expect(getTSType(typePath)).toEqual({ - name: 'union', - elements: [ - { name: 'literal', value: 'apple' }, - { name: 'literal', value: 'banana' }, - ], - raw: 'keyof { apple: string, banana: string }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles multiple references to one type', () => { @@ -1096,35 +609,7 @@ describe('getTSType', () => { type Action = {}; `); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { - key: 'a', - value: { - name: 'signature', - type: 'object', - required: true, - raw: '{}', - signature: { properties: [] }, - }, - }, - { - key: 'b', - value: { - name: 'signature', - type: 'object', - required: true, - raw: '{}', - signature: { properties: [] }, - }, - }, - ], - }, - raw: '{ a: Action, b: Action }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles generics of the same Name', () => { @@ -1140,9 +625,9 @@ describe('getTSType', () => { ) .get('body') .get('body')[0] - .get('typeAnnotation'); + .get('typeAnnotation') as NodePath; - getTSType(typePath as NodePath, null); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles self-referencing type cycles', () => { @@ -1151,16 +636,7 @@ describe('getTSType', () => { type Action = { subAction: Action }; `); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { key: 'subAction', value: { name: 'Action', required: true } }, - ], - }, - raw: '{ subAction: Action }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); it('handles long type cycles', () => { @@ -1172,57 +648,6 @@ describe('getTSType', () => { type SubSubSubAction = { rootAction: Action }; `); - expect(getTSType(typePath)).toEqual({ - name: 'signature', - type: 'object', - signature: { - properties: [ - { - key: 'subAction', - value: { - name: 'signature', - type: 'object', - required: true, - signature: { - properties: [ - { - key: 'subAction', - value: { - name: 'signature', - type: 'object', - required: true, - signature: { - properties: [ - { - key: 'subAction', - value: { - name: 'signature', - type: 'object', - required: true, - signature: { - properties: [ - { - key: 'rootAction', - value: { name: 'Action', required: true }, - }, - ], - }, - raw: '{ rootAction: Action }', - }, - }, - ], - }, - raw: '{ subAction: SubSubSubAction }', - }, - }, - ], - }, - raw: '{ subAction: SubSubAction }', - }, - }, - ], - }, - raw: '{ subAction: SubAction }', - }); + expect(getTSType(typePath)).toMatchSnapshot(); }); }); diff --git a/src/utils/__tests__/printValue-test.ts b/src/utils/__tests__/printValue-test.ts index 826611ac14f..29f40b580be 100644 --- a/src/utils/__tests__/printValue-test.ts +++ b/src/utils/__tests__/printValue-test.ts @@ -1,6 +1,6 @@ import type { NodePath } from '@babel/traverse'; -import type { ExpressionStatement } from '@babel/types'; -import { parse } from '../../../tests/utils'; +import type { ExpressionStatement, TSInterfaceDeclaration } from '@babel/types'; +import { parse, parseTypescript } from '../../../tests/utils'; import printValue from '../printValue'; describe('printValue', () => { @@ -25,4 +25,50 @@ describe('printValue', () => { ), ).toMatchSnapshot(); }); + + [',', ';'].forEach(char => { + it(`removes trailing ${char} for TsConstructSignatureDeclaration`, () => { + const path = parseTypescript + .statement( + `interface A { new (x:number)${char} }`, + ) + .get('body.body.0') as NodePath; + + expect(printValue(path)).toMatchSnapshot(); + }); + + it(`removes trailing ${char} for TsIndexSignature`, () => { + const path = parseTypescript + .statement( + `interface A { [x:string]: number${char} }`, + ) + .get('body.body.0') as NodePath; + + expect(printValue(path)).toMatchSnapshot(); + }); + + it(`removes trailing ${char} for TsCallSignatureDeclaration`, () => { + const path = parseTypescript + .statement(`interface A { (): number${char} }`) + .get('body.body.0') as NodePath; + + expect(printValue(path)).toMatchSnapshot(); + }); + + it(`removes trailing ${char} for TsPropertySignature`, () => { + const path = parseTypescript + .statement(`interface A { x: number${char} }`) + .get('body.body.0') as NodePath; + + expect(printValue(path)).toMatchSnapshot(); + }); + + it(`removes trailing ${char} for TsMethodSignature`, () => { + const path = parseTypescript + .statement(`interface A { x(): number${char} }`) + .get('body.body.0') as NodePath; + + expect(printValue(path)).toMatchSnapshot(); + }); + }); }); diff --git a/src/utils/printValue.ts b/src/utils/printValue.ts index 3ddfc22255e..5a524d8626d 100644 --- a/src/utils/printValue.ts +++ b/src/utils/printValue.ts @@ -15,5 +15,12 @@ function deindent(code: string): string { * Prints the given path without leading or trailing comments. */ export default function printValue(path: NodePath): string { - return deindent(path.getSource()); + let source = path.getSource(); + + // variable declarations and interface/type/class members might end with one of these + if (source.endsWith(',') || source.endsWith(';')) { + source = source.slice(0, -1); + } + + return deindent(source); } From 796713d84181fae692ec9bae717714ffb67ff077 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Fri, 5 Aug 2022 21:42:36 +0200 Subject: [PATCH 35/44] feat: Improve performance by creating all visitors only once --- benchmark/package-lock.json | 2684 --------------------- benchmark/yarn.lock | 1618 ++++++------- src/utils/getMemberExpressionValuePath.ts | 60 +- src/utils/isStatelessComponent.ts | 70 +- src/utils/normalizeClassDefinition.ts | 92 +- src/utils/traverse.ts | 9 +- 6 files changed, 943 insertions(+), 3590 deletions(-) delete mode 100644 benchmark/package-lock.json diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json deleted file mode 100644 index bf3cdadff84..00000000000 --- a/benchmark/package-lock.json +++ /dev/null @@ -1,2684 +0,0 @@ -{ - "name": "react-docgen-benchmark", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "react-docgen-benchmark", - "license": "MIT", - "dependencies": { - "benchmark": "2.1.4", - "cli-table": "0.3.11", - "microtime": "3.1.0", - "react-docgen4": "npm:react-docgen@4.1.1", - "react-docgen5": "npm:react-docgen@5.4.3", - "react-docgen6pre": "npm:react-docgen@6.0.0-alpha.3" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@ampproject/remapping/node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", - "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", - "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-module-transforms": "^7.18.9", - "@babel/helpers": "^7.18.9", - "@babel/parser": "^7.18.9", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz", - "integrity": "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.18.9", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", - "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.18.8", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", - "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", - "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", - "license": "MIT", - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", - "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", - "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", - "license": "MIT", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", - "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz", - "integrity": "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.9", - "@babel/types": "^7.18.9", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", - "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "license": "MIT" - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "license": "MIT" - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/benchmark": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", - "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", - "license": "MIT", - "dependencies": { - "lodash": "^4.17.4", - "platform": "^1.3.3" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", - "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001366", - "electron-to-chromium": "^1.4.188", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.4" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/c8": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", - "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", - "license": "ISC", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.3", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.4", - "rimraf": "^3.0.2", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.0.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9" - }, - "bin": { - "c8": "bin/c8.js" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001369", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz", - "integrity": "sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-table": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz", - "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==", - "dependencies": { - "colors": "1.0.3" - }, - "engines": { - "node": ">= 0.2.0" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==", - "license": "MIT", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.199", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz", - "integrity": "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==", - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estree-to-babel": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz", - "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.1.6", - "@babel/types": "^7.2.0", - "c8": "^7.6.0" - }, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "license": "MIT" - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "license": "MIT" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "license": "MIT", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/microtime": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/microtime/-/microtime-3.1.0.tgz", - "integrity": "sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^5.0.0", - "node-gyp-build": "^4.4.0" - }, - "engines": { - "node": ">= 14.13.0" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT" - }, - "node_modules/node-addon-api": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", - "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==", - "license": "MIT" - }, - "node_modules/node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "license": "MIT", - "dependencies": { - "minimatch": "^3.0.2" - }, - "engines": { - "node": ">= 0.10.5" - } - }, - "node_modules/node-gyp-build": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", - "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "license": "MIT" - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "license": "ISC" - }, - "node_modules/platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", - "license": "MIT" - }, - "node_modules/private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/react-docgen4": { - "name": "react-docgen", - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-4.1.1.tgz", - "integrity": "sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==", - "dependencies": { - "@babel/core": "^7.0.0", - "@babel/runtime": "^7.0.0", - "async": "^2.1.4", - "commander": "^2.19.0", - "doctrine": "^3.0.0", - "node-dir": "^0.1.10", - "recast": "^0.17.3" - }, - "bin": { - "react-docgen": "bin/react-docgen.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-docgen5": { - "name": "react-docgen", - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", - "integrity": "sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.7.5", - "@babel/generator": "^7.12.11", - "@babel/runtime": "^7.7.6", - "ast-types": "^0.14.2", - "commander": "^2.19.0", - "doctrine": "^3.0.0", - "estree-to-babel": "^3.1.0", - "neo-async": "^2.6.1", - "node-dir": "^0.1.10", - "strip-indent": "^3.0.0" - }, - "bin": { - "react-docgen": "bin/react-docgen.js" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/react-docgen6pre": { - "name": "react-docgen", - "version": "6.0.0-alpha.3", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz", - "integrity": "sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.7.5", - "@babel/generator": "^7.12.11", - "ast-types": "^0.14.2", - "commander": "^2.19.0", - "doctrine": "^3.0.0", - "estree-to-babel": "^3.1.0", - "neo-async": "^2.6.1", - "node-dir": "^0.1.10", - "resolve": "^1.17.0", - "strip-indent": "^3.0.0" - }, - "bin": { - "react-docgen": "bin/react-docgen.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/recast": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz", - "integrity": "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==", - "dependencies": { - "ast-types": "0.12.4", - "esprima": "~4.0.0", - "private": "^0.1.8", - "source-map": "~0.6.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/recast/node_modules/ast-types": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", - "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "license": "MIT" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "license": "MIT", - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "license": "0BSD" - }, - "node_modules/update-browserslist-db": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", - "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", - "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==" - }, - "@babel/core": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", - "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-module-transforms": "^7.18.9", - "@babel/helpers": "^7.18.9", - "@babel/parser": "^7.18.9", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz", - "integrity": "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==", - "requires": { - "@babel/types": "^7.18.9", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", - "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", - "requires": { - "@babel/compat-data": "^7.18.8", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" - }, - "@babel/helper-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", - "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", - "requires": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", - "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" - }, - "@babel/helpers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", - "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", - "requires": { - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", - "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==" - }, - "@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" - } - }, - "@babel/traverse": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz", - "integrity": "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.9", - "@babel/types": "^7.18.9", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", - "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" - }, - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", - "requires": { - "tslib": "^2.0.1" - } - }, - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "benchmark": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", - "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", - "requires": { - "lodash": "^4.17.4", - "platform": "^1.3.3" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browserslist": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", - "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", - "requires": { - "caniuse-lite": "^1.0.30001366", - "electron-to-chromium": "^1.4.188", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.4" - } - }, - "c8": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", - "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.3", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.4", - "rimraf": "^3.0.2", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.0.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9" - } - }, - "caniuse-lite": { - "version": "1.0.30001369", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz", - "integrity": "sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cli-table": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz", - "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==", - "requires": { - "colors": "1.0.3" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==" - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "requires": { - "esutils": "^2.0.2" - } - }, - "electron-to-chromium": { - "version": "1.4.199", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz", - "integrity": "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "estree-to-babel": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz", - "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", - "requires": { - "@babel/traverse": "^7.1.6", - "@babel/types": "^7.2.0", - "c8": "^7.6.0" - } - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "requires": { - "has": "^1.0.3" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - } - }, - "microtime": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/microtime/-/microtime-3.1.0.tgz", - "integrity": "sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ==", - "requires": { - "node-addon-api": "^5.0.0", - "node-gyp-build": "^4.4.0" - } - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "node-addon-api": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", - "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" - }, - "node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "requires": { - "minimatch": "^3.0.2" - } - }, - "node-gyp-build": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", - "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==" - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" - }, - "react-docgen4": { - "version": "npm:react-docgen@4.1.1", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-4.1.1.tgz", - "integrity": "sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==", - "requires": { - "@babel/core": "^7.0.0", - "@babel/runtime": "^7.0.0", - "async": "^2.1.4", - "commander": "^2.19.0", - "doctrine": "^3.0.0", - "node-dir": "^0.1.10", - "recast": "^0.17.3" - } - }, - "react-docgen5": { - "version": "npm:react-docgen@5.4.3", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", - "integrity": "sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==", - "requires": { - "@babel/core": "^7.7.5", - "@babel/generator": "^7.12.11", - "@babel/runtime": "^7.7.6", - "ast-types": "^0.14.2", - "commander": "^2.19.0", - "doctrine": "^3.0.0", - "estree-to-babel": "^3.1.0", - "neo-async": "^2.6.1", - "node-dir": "^0.1.10", - "strip-indent": "^3.0.0" - } - }, - "react-docgen6pre": { - "version": "npm:react-docgen@6.0.0-alpha.3", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz", - "integrity": "sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA==", - "requires": { - "@babel/core": "^7.7.5", - "@babel/generator": "^7.12.11", - "ast-types": "^0.14.2", - "commander": "^2.19.0", - "doctrine": "^3.0.0", - "estree-to-babel": "^3.1.0", - "neo-async": "^2.6.1", - "node-dir": "^0.1.10", - "resolve": "^1.17.0", - "strip-indent": "^3.0.0" - } - }, - "recast": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz", - "integrity": "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==", - "requires": { - "ast-types": "0.12.4", - "esprima": "~4.0.0", - "private": "^0.1.8", - "source-map": "~0.6.1" - }, - "dependencies": { - "ast-types": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", - "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==" - } - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "requires": { - "min-indent": "^1.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "update-browserslist-db": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", - "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - } - } -} diff --git a/benchmark/yarn.lock b/benchmark/yarn.lock index 61ebddb7ca5..8f351e794ae 100644 --- a/benchmark/yarn.lock +++ b/benchmark/yarn.lock @@ -3,96 +3,96 @@ "@ampproject/remapping@^2.1.0": - "integrity" "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==" - "resolved" "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" - "version" "2.2.0" + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== dependencies: "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" "@babel/code-frame@^7.18.6": - "integrity" "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==" - "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" - "version" "7.18.6" + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== dependencies: "@babel/highlight" "^7.18.6" "@babel/compat-data@^7.18.8": - "integrity" "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==" - "resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz" - "version" "7.18.8" + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== "@babel/core@^7.0.0", "@babel/core@^7.7.5": - "integrity" "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==" - "resolved" "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz" - "version" "7.18.9" + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8" + integrity sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.18.9" + "@babel/generator" "^7.18.10" "@babel/helper-compilation-targets" "^7.18.9" "@babel/helper-module-transforms" "^7.18.9" "@babel/helpers" "^7.18.9" - "@babel/parser" "^7.18.9" - "@babel/template" "^7.18.6" - "@babel/traverse" "^7.18.9" - "@babel/types" "^7.18.9" - "convert-source-map" "^1.7.0" - "debug" "^4.1.0" - "gensync" "^1.0.0-beta.2" - "json5" "^2.2.1" - "semver" "^6.3.0" - -"@babel/generator@^7.12.11", "@babel/generator@^7.18.9": - "integrity" "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==" - "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz" - "version" "7.18.9" - dependencies: - "@babel/types" "^7.18.9" + "@babel/parser" "^7.18.10" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.10" + "@babel/types" "^7.18.10" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.12.11", "@babel/generator@^7.18.10": + version "7.18.12" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.12.tgz#fa58daa303757bd6f5e4bbca91b342040463d9f4" + integrity sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg== + dependencies: + "@babel/types" "^7.18.10" "@jridgewell/gen-mapping" "^0.3.2" - "jsesc" "^2.5.1" + jsesc "^2.5.1" "@babel/helper-compilation-targets@^7.18.9": - "integrity" "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==" - "resolved" "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz" - "version" "7.18.9" + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== dependencies: "@babel/compat-data" "^7.18.8" "@babel/helper-validator-option" "^7.18.6" - "browserslist" "^4.20.2" - "semver" "^6.3.0" + browserslist "^4.20.2" + semver "^6.3.0" "@babel/helper-environment-visitor@^7.18.9": - "integrity" "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" - "resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" - "version" "7.18.9" + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== "@babel/helper-function-name@^7.18.9": - "integrity" "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==" - "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz" - "version" "7.18.9" + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== dependencies: "@babel/template" "^7.18.6" "@babel/types" "^7.18.9" "@babel/helper-hoist-variables@^7.18.6": - "integrity" "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==" - "resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" - "version" "7.18.6" + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== dependencies: "@babel/types" "^7.18.6" "@babel/helper-module-imports@^7.18.6": - "integrity" "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==" - "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" - "version" "7.18.6" + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== dependencies: "@babel/types" "^7.18.6" "@babel/helper-module-transforms@^7.18.9": - "integrity" "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==" - "resolved" "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz" - "version" "7.18.9" + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== dependencies: "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-module-imports" "^7.18.6" @@ -104,877 +104,883 @@ "@babel/types" "^7.18.9" "@babel/helper-simple-access@^7.18.6": - "integrity" "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==" - "resolved" "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz" - "version" "7.18.6" + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== dependencies: "@babel/types" "^7.18.6" "@babel/helper-split-export-declaration@^7.18.6": - "integrity" "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==" - "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" - "version" "7.18.6" + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== dependencies: "@babel/types" "^7.18.6" +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + "@babel/helper-validator-identifier@^7.18.6": - "integrity" "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" - "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz" - "version" "7.18.6" + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== "@babel/helper-validator-option@^7.18.6": - "integrity" "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" - "resolved" "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" - "version" "7.18.6" + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== "@babel/helpers@^7.18.9": - "integrity" "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==" - "resolved" "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz" - "version" "7.18.9" + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== dependencies: "@babel/template" "^7.18.6" "@babel/traverse" "^7.18.9" "@babel/types" "^7.18.9" "@babel/highlight@^7.18.6": - "integrity" "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==" - "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" - "version" "7.18.6" + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== dependencies: "@babel/helper-validator-identifier" "^7.18.6" - "chalk" "^2.0.0" - "js-tokens" "^4.0.0" + chalk "^2.0.0" + js-tokens "^4.0.0" -"@babel/parser@^7.18.6", "@babel/parser@^7.18.9": - "integrity" "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==" - "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz" - "version" "7.18.9" +"@babel/parser@^7.18.10", "@babel/parser@^7.18.11": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9" + integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ== "@babel/runtime@^7.0.0", "@babel/runtime@^7.7.6": - "integrity" "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==" - "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz" - "version" "7.18.9" + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" + integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== dependencies: - "regenerator-runtime" "^0.13.4" + regenerator-runtime "^0.13.4" -"@babel/template@^7.18.6": - "integrity" "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==" - "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz" - "version" "7.18.6" +"@babel/template@^7.18.10", "@babel/template@^7.18.6": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.18.6" - "@babel/types" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" -"@babel/traverse@^7.1.6", "@babel/traverse@^7.18.9": - "integrity" "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==" - "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz" - "version" "7.18.9" +"@babel/traverse@^7.1.6", "@babel/traverse@^7.18.10", "@babel/traverse@^7.18.9": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.11.tgz#3d51f2afbd83ecf9912bcbb5c4d94e3d2ddaa16f" + integrity sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.18.9" + "@babel/generator" "^7.18.10" "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-function-name" "^7.18.9" "@babel/helper-hoist-variables" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.18.9" - "@babel/types" "^7.18.9" - "debug" "^4.1.0" - "globals" "^11.1.0" + "@babel/parser" "^7.18.11" + "@babel/types" "^7.18.10" + debug "^4.1.0" + globals "^11.1.0" -"@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.2.0": - "integrity" "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==" - "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz" - "version" "7.18.9" +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.2.0": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6" + integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ== dependencies: + "@babel/helper-string-parser" "^7.18.10" "@babel/helper-validator-identifier" "^7.18.6" - "to-fast-properties" "^2.0.0" + to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": - "integrity" "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" - "resolved" "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" - "version" "0.2.3" + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== "@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": - "integrity" "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" - "resolved" "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" - "version" "0.1.3" + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== "@jridgewell/gen-mapping@^0.1.0": - "integrity" "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==" - "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" - "version" "0.1.1" + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== dependencies: "@jridgewell/set-array" "^1.0.0" "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/gen-mapping@^0.3.2": - "integrity" "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==" - "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" - "version" "0.3.2" + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== dependencies: "@jridgewell/set-array" "^1.0.1" "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/resolve-uri@^3.0.3": - "integrity" "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - "resolved" "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" - "version" "3.1.0" + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": - "integrity" "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - "resolved" "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" - "version" "1.1.2" + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== "@jridgewell/sourcemap-codec@^1.4.10": - "integrity" "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - "resolved" "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" - "version" "1.4.14" + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.9": - "integrity" "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==" - "resolved" "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz" - "version" "0.3.14" + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" "@types/istanbul-lib-coverage@^2.0.1": - "integrity" "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - "resolved" "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" - "version" "2.0.4" + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== -"ansi-regex@^5.0.1": - "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" - "version" "5.0.1" +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -"ansi-styles@^3.2.1": - "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" - "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - "version" "3.2.1" +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: - "color-convert" "^1.9.0" + color-convert "^1.9.0" -"ansi-styles@^4.0.0": - "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" - "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - "version" "4.3.0" +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: - "color-convert" "^2.0.1" + color-convert "^2.0.1" -"ast-types@^0.14.2": - "integrity" "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==" - "resolved" "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz" - "version" "0.14.2" - dependencies: - "tslib" "^2.0.1" +ast-types@0.12.4: + version "0.12.4" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.12.4.tgz#71ce6383800f24efc9a1a3308f3a6e420a0974d1" + integrity sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw== -"ast-types@0.12.4": - "integrity" "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==" - "resolved" "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz" - "version" "0.12.4" +ast-types@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.14.2.tgz#600b882df8583e3cd4f2df5fa20fa83759d4bdfd" + integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== + dependencies: + tslib "^2.0.1" -"async@^2.1.4": - "integrity" "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==" - "resolved" "https://registry.npmjs.org/async/-/async-2.6.4.tgz" - "version" "2.6.4" +async@^2.1.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== dependencies: - "lodash" "^4.17.14" + lodash "^4.17.14" -"balanced-match@^1.0.0": - "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - "version" "1.0.2" +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -"benchmark@2.1.4": - "integrity" "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==" - "resolved" "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz" - "version" "2.1.4" +benchmark@2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629" + integrity sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ== dependencies: - "lodash" "^4.17.4" - "platform" "^1.3.3" + lodash "^4.17.4" + platform "^1.3.3" -"brace-expansion@^1.1.7": - "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" - "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" - "version" "1.1.11" +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: - "balanced-match" "^1.0.0" - "concat-map" "0.0.1" + balanced-match "^1.0.0" + concat-map "0.0.1" -"browserslist@^4.20.2", "browserslist@>= 4.21.0": - "integrity" "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==" - "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz" - "version" "4.21.2" +browserslist@^4.20.2: + version "4.21.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== dependencies: - "caniuse-lite" "^1.0.30001366" - "electron-to-chromium" "^1.4.188" - "node-releases" "^2.0.6" - "update-browserslist-db" "^1.0.4" + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" -"c8@^7.6.0": - "integrity" "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==" - "resolved" "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz" - "version" "7.12.0" +c8@^7.6.0: + version "7.12.0" + resolved "https://registry.yarnpkg.com/c8/-/c8-7.12.0.tgz#402db1c1af4af5249153535d1c84ad70c5c96b14" + integrity sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A== dependencies: "@bcoe/v8-coverage" "^0.2.3" "@istanbuljs/schema" "^0.1.3" - "find-up" "^5.0.0" - "foreground-child" "^2.0.0" - "istanbul-lib-coverage" "^3.2.0" - "istanbul-lib-report" "^3.0.0" - "istanbul-reports" "^3.1.4" - "rimraf" "^3.0.2" - "test-exclude" "^6.0.0" - "v8-to-istanbul" "^9.0.0" - "yargs" "^16.2.0" - "yargs-parser" "^20.2.9" - -"caniuse-lite@^1.0.30001366": - "integrity" "sha512-OY1SBHaodJc4wflDIKnlkdqWzJZd1Ls/2zbVJHBSv3AT7vgOJ58yAhd2CN4d57l2kPJrgMb7P9+N1Mhy4tNSQA==" - "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001369.tgz" - "version" "1.0.30001369" - -"chalk@^2.0.0": - "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" - "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - "version" "2.4.2" - dependencies: - "ansi-styles" "^3.2.1" - "escape-string-regexp" "^1.0.5" - "supports-color" "^5.3.0" - -"cli-table@0.3.11": - "integrity" "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==" - "resolved" "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz" - "version" "0.3.11" - dependencies: - "colors" "1.0.3" - -"cliui@^7.0.2": - "integrity" "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==" - "resolved" "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" - "version" "7.0.4" - dependencies: - "string-width" "^4.2.0" - "strip-ansi" "^6.0.0" - "wrap-ansi" "^7.0.0" - -"color-convert@^1.9.0": - "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" - "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - "version" "1.9.3" - dependencies: - "color-name" "1.1.3" - -"color-convert@^2.0.1": - "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" - "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - "version" "2.0.1" - dependencies: - "color-name" "~1.1.4" - -"color-name@~1.1.4": - "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - "version" "1.1.4" - -"color-name@1.1.3": - "integrity" "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - "version" "1.1.3" - -"colors@1.0.3": - "integrity" "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==" - "resolved" "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" - "version" "1.0.3" - -"commander@^2.19.0": - "integrity" "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - "resolved" "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" - "version" "2.20.3" - -"concat-map@0.0.1": - "integrity" "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - "version" "0.0.1" - -"convert-source-map@^1.6.0", "convert-source-map@^1.7.0": - "integrity" "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==" - "resolved" "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" - "version" "1.8.0" - dependencies: - "safe-buffer" "~5.1.1" - -"cross-spawn@^7.0.0": - "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" - "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - "version" "7.0.3" - dependencies: - "path-key" "^3.1.0" - "shebang-command" "^2.0.0" - "which" "^2.0.1" - -"debug@^4.1.0": - "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" - "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - "version" "4.3.4" - dependencies: - "ms" "2.1.2" - -"doctrine@^3.0.0": - "integrity" "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==" - "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - "version" "3.0.0" - dependencies: - "esutils" "^2.0.2" - -"electron-to-chromium@^1.4.188": - "integrity" "sha512-WIGME0Cs7oob3mxsJwHbeWkH0tYkIE/sjkJ8ML2BYmuRcjhRl/q5kVDXG7W9LOOKwzPU5M0LBlXRq9rlSgnNlg==" - "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.199.tgz" - "version" "1.4.199" - -"emoji-regex@^8.0.0": - "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - "version" "8.0.0" - -"escalade@^3.1.1": - "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - "version" "3.1.1" - -"escape-string-regexp@^1.0.5": - "integrity" "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - "version" "1.0.5" + find-up "^5.0.0" + foreground-child "^2.0.0" + istanbul-lib-coverage "^3.2.0" + istanbul-lib-report "^3.0.0" + istanbul-reports "^3.1.4" + rimraf "^3.0.2" + test-exclude "^6.0.0" + v8-to-istanbul "^9.0.0" + yargs "^16.2.0" + yargs-parser "^20.2.9" + +caniuse-lite@^1.0.30001370: + version "1.0.30001374" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001374.tgz#3dab138e3f5485ba2e74bd13eca7fe1037ce6f57" + integrity sha512-mWvzatRx3w+j5wx/mpFN5v5twlPrabG8NqX2c6e45LCpymdoGqNvRkRutFUqpRTXKFQFNQJasvK0YT7suW6/Hw== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +cli-table@0.3.11: + version "0.3.11" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.11.tgz#ac69cdecbe81dccdba4889b9a18b7da312a9d3ee" + integrity sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ== + dependencies: + colors "1.0.3" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== + +commander@^2.19.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +electron-to-chromium@^1.4.202: + version "1.4.211" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz#afaa8b58313807501312d598d99b953568d60f91" + integrity sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== -"esprima@~4.0.0": - "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - "version" "4.0.1" - -"estree-to-babel@^3.1.0": - "integrity" "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==" - "resolved" "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz" - "version" "3.2.1" +esprima@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estree-to-babel@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/estree-to-babel/-/estree-to-babel-3.2.1.tgz#82e78315275c3ca74475fdc8ac1a5103c8a75bf5" + integrity sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg== dependencies: "@babel/traverse" "^7.1.6" "@babel/types" "^7.2.0" - "c8" "^7.6.0" - -"esutils@^2.0.2": - "integrity" "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - "resolved" "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" - "version" "2.0.3" - -"find-up@^5.0.0": - "integrity" "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==" - "resolved" "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - "version" "5.0.0" - dependencies: - "locate-path" "^6.0.0" - "path-exists" "^4.0.0" - -"foreground-child@^2.0.0": - "integrity" "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==" - "resolved" "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz" - "version" "2.0.0" - dependencies: - "cross-spawn" "^7.0.0" - "signal-exit" "^3.0.2" - -"fs.realpath@^1.0.0": - "integrity" "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - "version" "1.0.0" - -"function-bind@^1.1.1": - "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - "version" "1.1.1" - -"gensync@^1.0.0-beta.2": - "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" - "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" - "version" "1.0.0-beta.2" - -"get-caller-file@^2.0.5": - "integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" - "version" "2.0.5" - -"glob@^7.1.3", "glob@^7.1.4": - "integrity" "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==" - "resolved" "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - "version" "7.2.3" - dependencies: - "fs.realpath" "^1.0.0" - "inflight" "^1.0.4" - "inherits" "2" - "minimatch" "^3.1.1" - "once" "^1.3.0" - "path-is-absolute" "^1.0.0" - -"globals@^11.1.0": - "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - "version" "11.12.0" - -"has-flag@^3.0.0": - "integrity" "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - "version" "3.0.0" - -"has-flag@^4.0.0": - "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - "version" "4.0.0" - -"has@^1.0.3": - "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" - "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - "version" "1.0.3" - dependencies: - "function-bind" "^1.1.1" - -"html-escaper@^2.0.0": - "integrity" "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" - "resolved" "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" - "version" "2.0.2" - -"inflight@^1.0.4": - "integrity" "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==" - "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - "version" "1.0.6" - dependencies: - "once" "^1.3.0" - "wrappy" "1" - -"inherits@2": - "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - "version" "2.0.4" - -"is-core-module@^2.9.0": - "integrity" "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==" - "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz" - "version" "2.9.0" - dependencies: - "has" "^1.0.3" - -"is-fullwidth-code-point@^3.0.0": - "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - "version" "3.0.0" - -"isexe@^2.0.0": - "integrity" "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - "version" "2.0.0" - -"istanbul-lib-coverage@^3.0.0", "istanbul-lib-coverage@^3.2.0": - "integrity" "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" - "resolved" "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" - "version" "3.2.0" - -"istanbul-lib-report@^3.0.0": - "integrity" "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==" - "resolved" "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" - "version" "3.0.0" - dependencies: - "istanbul-lib-coverage" "^3.0.0" - "make-dir" "^3.0.0" - "supports-color" "^7.1.0" - -"istanbul-reports@^3.1.4": - "integrity" "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==" - "resolved" "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" - "version" "3.1.5" - dependencies: - "html-escaper" "^2.0.0" - "istanbul-lib-report" "^3.0.0" - -"js-tokens@^4.0.0": - "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - "version" "4.0.0" - -"jsesc@^2.5.1": - "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - "version" "2.5.2" - -"json5@^2.2.1": - "integrity" "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" - "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" - "version" "2.2.1" - -"locate-path@^6.0.0": - "integrity" "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==" - "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" - "version" "6.0.0" - dependencies: - "p-locate" "^5.0.0" - -"lodash@^4.17.14", "lodash@^4.17.4": - "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - "version" "4.17.21" - -"make-dir@^3.0.0": - "integrity" "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==" - "resolved" "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" - "version" "3.1.0" - dependencies: - "semver" "^6.0.0" - -"microtime@3.1.0": - "integrity" "sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ==" - "resolved" "https://registry.npmjs.org/microtime/-/microtime-3.1.0.tgz" - "version" "3.1.0" - dependencies: - "node-addon-api" "^5.0.0" - "node-gyp-build" "^4.4.0" - -"min-indent@^1.0.0": - "integrity" "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" - "resolved" "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" - "version" "1.0.1" - -"minimatch@^3.0.2", "minimatch@^3.0.4", "minimatch@^3.1.1": - "integrity" "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==" - "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - "version" "3.1.2" - dependencies: - "brace-expansion" "^1.1.7" - -"ms@2.1.2": - "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - "version" "2.1.2" - -"neo-async@^2.6.1": - "integrity" "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - "resolved" "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" - "version" "2.6.2" - -"node-addon-api@^5.0.0": - "integrity" "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" - "resolved" "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz" - "version" "5.0.0" - -"node-dir@^0.1.10": - "integrity" "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==" - "resolved" "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz" - "version" "0.1.17" - dependencies: - "minimatch" "^3.0.2" - -"node-gyp-build@^4.4.0": - "integrity" "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==" - "resolved" "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz" - "version" "4.5.0" - -"node-releases@^2.0.6": - "integrity" "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" - "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" - "version" "2.0.6" - -"once@^1.3.0": - "integrity" "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" - "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - "version" "1.4.0" - dependencies: - "wrappy" "1" - -"p-limit@^3.0.2": - "integrity" "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==" - "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - "version" "3.1.0" - dependencies: - "yocto-queue" "^0.1.0" - -"p-locate@^5.0.0": - "integrity" "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==" - "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" - "version" "5.0.0" - dependencies: - "p-limit" "^3.0.2" - -"path-exists@^4.0.0": - "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - "version" "4.0.0" - -"path-is-absolute@^1.0.0": - "integrity" "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - "version" "1.0.1" - -"path-key@^3.1.0": - "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - "version" "3.1.1" - -"path-parse@^1.0.7": - "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - "version" "1.0.7" - -"picocolors@^1.0.0": - "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - "version" "1.0.0" + c8 "^7.6.0" + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +foreground-child@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" + integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^3.0.2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-core-module@^2.9.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-reports@^3.1.4: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash@^4.17.14, lodash@^4.17.4: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +microtime@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/microtime/-/microtime-3.1.0.tgz#599a71250e3116c59f0fe5271dae4cc44321869c" + integrity sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ== + dependencies: + node-addon-api "^5.0.0" + node-gyp-build "^4.4.0" + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +neo-async@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-addon-api@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.0.0.tgz#7d7e6f9ef89043befdb20c1989c905ebde18c501" + integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA== + +node-dir@^0.1.10: + version "0.1.17" + resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" + integrity sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg== + dependencies: + minimatch "^3.0.2" + +node-gyp-build@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" + integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== + +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -"platform@^1.3.3": - "integrity" "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" - "resolved" "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz" - "version" "1.3.6" - -"private@^0.1.8": - "integrity" "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" - "resolved" "https://registry.npmjs.org/private/-/private-0.1.8.tgz" - "version" "0.1.8" +platform@^1.3.3: + version "1.3.6" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" + integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== + +private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== "react-docgen4@npm:react-docgen@4.1.1": - "integrity" "sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==" - "resolved" "https://registry.npmjs.org/react-docgen/-/react-docgen-4.1.1.tgz" - "version" "4.1.1" + version "4.1.1" + resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-4.1.1.tgz#8fef0212dbf14733e09edecef1de6b224d87219e" + integrity sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw== dependencies: "@babel/core" "^7.0.0" "@babel/runtime" "^7.0.0" - "async" "^2.1.4" - "commander" "^2.19.0" - "doctrine" "^3.0.0" - "node-dir" "^0.1.10" - "recast" "^0.17.3" + async "^2.1.4" + commander "^2.19.0" + doctrine "^3.0.0" + node-dir "^0.1.10" + recast "^0.17.3" "react-docgen5@npm:react-docgen@5.4.3": - "integrity" "sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==" - "resolved" "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz" - "version" "5.4.3" + version "5.4.3" + resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-5.4.3.tgz#7d297f73b977d0c7611402e5fc2a168acf332b26" + integrity sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA== dependencies: "@babel/core" "^7.7.5" "@babel/generator" "^7.12.11" "@babel/runtime" "^7.7.6" - "ast-types" "^0.14.2" - "commander" "^2.19.0" - "doctrine" "^3.0.0" - "estree-to-babel" "^3.1.0" - "neo-async" "^2.6.1" - "node-dir" "^0.1.10" - "strip-indent" "^3.0.0" + ast-types "^0.14.2" + commander "^2.19.0" + doctrine "^3.0.0" + estree-to-babel "^3.1.0" + neo-async "^2.6.1" + node-dir "^0.1.10" + strip-indent "^3.0.0" "react-docgen6pre@npm:react-docgen@6.0.0-alpha.3": - "integrity" "sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA==" - "resolved" "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz" - "version" "6.0.0-alpha.3" + version "6.0.0-alpha.3" + resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-6.0.0-alpha.3.tgz#4d8a4916b45de4aadb90eb5f3a6f923edf447928" + integrity sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA== dependencies: "@babel/core" "^7.7.5" "@babel/generator" "^7.12.11" - "ast-types" "^0.14.2" - "commander" "^2.19.0" - "doctrine" "^3.0.0" - "estree-to-babel" "^3.1.0" - "neo-async" "^2.6.1" - "node-dir" "^0.1.10" - "resolve" "^1.17.0" - "strip-indent" "^3.0.0" - -"recast@^0.17.3": - "integrity" "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==" - "resolved" "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz" - "version" "0.17.6" - dependencies: - "ast-types" "0.12.4" - "esprima" "~4.0.0" - "private" "^0.1.8" - "source-map" "~0.6.1" - -"regenerator-runtime@^0.13.4": - "integrity" "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" - "version" "0.13.9" - -"require-directory@^2.1.1": - "integrity" "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - "resolved" "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - "version" "2.1.1" - -"resolve@^1.17.0": - "integrity" "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==" - "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" - "version" "1.22.1" - dependencies: - "is-core-module" "^2.9.0" - "path-parse" "^1.0.7" - "supports-preserve-symlinks-flag" "^1.0.0" - -"rimraf@^3.0.2": - "integrity" "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" - "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - "version" "3.0.2" - dependencies: - "glob" "^7.1.3" - -"safe-buffer@~5.1.1": - "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - "version" "5.1.2" - -"semver@^6.0.0", "semver@^6.3.0": - "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - "version" "6.3.0" - -"shebang-command@^2.0.0": - "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" - "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" - "version" "2.0.0" - dependencies: - "shebang-regex" "^3.0.0" - -"shebang-regex@^3.0.0": - "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" - "version" "3.0.0" - -"signal-exit@^3.0.2": - "integrity" "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" - "version" "3.0.7" - -"source-map@~0.6.1": - "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" - "version" "0.6.1" - -"string-width@^4.1.0", "string-width@^4.2.0": - "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" - "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - "version" "4.2.3" - dependencies: - "emoji-regex" "^8.0.0" - "is-fullwidth-code-point" "^3.0.0" - "strip-ansi" "^6.0.1" - -"strip-ansi@^6.0.0", "strip-ansi@^6.0.1": - "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" - "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - "version" "6.0.1" - dependencies: - "ansi-regex" "^5.0.1" - -"strip-indent@^3.0.0": - "integrity" "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==" - "resolved" "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" - "version" "3.0.0" - dependencies: - "min-indent" "^1.0.0" - -"supports-color@^5.3.0": - "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" - "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - "version" "5.5.0" - dependencies: - "has-flag" "^3.0.0" - -"supports-color@^7.1.0": - "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" - "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - "version" "7.2.0" - dependencies: - "has-flag" "^4.0.0" + ast-types "^0.14.2" + commander "^2.19.0" + doctrine "^3.0.0" + estree-to-babel "^3.1.0" + neo-async "^2.6.1" + node-dir "^0.1.10" + resolve "^1.17.0" + strip-indent "^3.0.0" + +recast@^0.17.3: + version "0.17.6" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.17.6.tgz#64ae98d0d2dfb10ff92ff5fb9ffb7371823b69fa" + integrity sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ== + dependencies: + ast-types "0.12.4" + esprima "~4.0.0" + private "^0.1.8" + source-map "~0.6.1" + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve@^1.17.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" -"supports-preserve-symlinks-flag@^1.0.0": - "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - "version" "1.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -"test-exclude@^6.0.0": - "integrity" "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==" - "resolved" "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" - "version" "6.0.0" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" - "glob" "^7.1.4" - "minimatch" "^3.0.4" + glob "^7.1.4" + minimatch "^3.0.4" -"to-fast-properties@^2.0.0": - "integrity" "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" - "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - "version" "2.0.0" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== -"tslib@^2.0.1": - "integrity" "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" - "version" "2.4.0" +tslib@^2.0.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -"update-browserslist-db@^1.0.4": - "integrity" "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==" - "resolved" "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz" - "version" "1.0.5" +update-browserslist-db@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" + integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== dependencies: - "escalade" "^3.1.1" - "picocolors" "^1.0.0" + escalade "^3.1.1" + picocolors "^1.0.0" -"v8-to-istanbul@^9.0.0": - "integrity" "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==" - "resolved" "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz" - "version" "9.0.1" +v8-to-istanbul@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - "convert-source-map" "^1.6.0" - -"which@^2.0.1": - "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" - "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" - "version" "2.0.2" - dependencies: - "isexe" "^2.0.0" - -"wrap-ansi@^7.0.0": - "integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" - "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - "version" "7.0.0" - dependencies: - "ansi-styles" "^4.0.0" - "string-width" "^4.1.0" - "strip-ansi" "^6.0.0" - -"wrappy@1": - "integrity" "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - "version" "1.0.2" - -"y18n@^5.0.5": - "integrity" "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - "resolved" "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" - "version" "5.0.8" - -"yargs-parser@^20.2.2", "yargs-parser@^20.2.9": - "integrity" "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" - "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" - "version" "20.2.9" - -"yargs@^16.2.0": - "integrity" "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==" - "resolved" "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" - "version" "16.2.0" - dependencies: - "cliui" "^7.0.2" - "escalade" "^3.1.1" - "get-caller-file" "^2.0.5" - "require-directory" "^2.1.1" - "string-width" "^4.2.0" - "y18n" "^5.0.5" - "yargs-parser" "^20.2.2" - -"yocto-queue@^0.1.0": - "integrity" "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - "resolved" "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - "version" "0.1.0" + convert-source-map "^1.6.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/src/utils/getMemberExpressionValuePath.ts b/src/utils/getMemberExpressionValuePath.ts index 43fb299b245..d47fcf04cd2 100644 --- a/src/utils/getMemberExpressionValuePath.ts +++ b/src/utils/getMemberExpressionValuePath.ts @@ -1,4 +1,5 @@ import type { NodePath } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import type { Expression } from '@babel/types'; import getNameOrValue from './getNameOrValue'; import { String as toString } from './expressionTo'; @@ -68,23 +69,15 @@ function resolveName(path: NodePath): string | undefined { ); } -export default function getMemberExpressionValuePath( - variableDefinition: NodePath, - memberName: string, -): NodePath | null { - const localName = resolveName(variableDefinition); - const program = variableDefinition.findParent(path => path.isProgram()); - - if (!localName || !program) { - // likely an immediately exported and therefore nameless/anonymous node - // passed in - return null; - } - - let result: NodePath | null = null; +interface TraverseState { + readonly memberName: string; + readonly localName: string; + result: NodePath | null; +} - program.traverse({ - AssignmentExpression(path) { +const explodedVisitors = visitors.explode({ + AssignmentExpression: { + enter: function (path, state) { const memberPath = path.get('left'); if (!memberPath.isMemberExpression()) { @@ -94,16 +87,35 @@ export default function getMemberExpressionValuePath( if ( (!memberPath.node.computed || property.isLiteral()) && - getNameOrValue(property) === memberName && - toString(memberPath.get('object')) === localName + getNameOrValue(property) === state.memberName && + toString(memberPath.get('object')) === state.localName ) { - result = path.get('right'); - path.skip(); - - return; + state.result = path.get('right'); + path.stop(); } }, - }); + }, +}); + +export default function getMemberExpressionValuePath( + variableDefinition: NodePath, + memberName: string, +): NodePath | null { + const localName = resolveName(variableDefinition); + + if (!localName) { + // likely an immediately exported and therefore nameless/anonymous node + // passed in + return null; + } + + const state: TraverseState = { + localName, + memberName, + result: null, + }; + + variableDefinition.hub.file.traverse(explodedVisitors, state); - return result; + return state.result; } diff --git a/src/utils/isStatelessComponent.ts b/src/utils/isStatelessComponent.ts index 51461c7fdec..bb4afb74107 100644 --- a/src/utils/isStatelessComponent.ts +++ b/src/utils/isStatelessComponent.ts @@ -3,8 +3,10 @@ import isReactCreateElementCall from './isReactCreateElementCall'; import isReactCloneElementCall from './isReactCloneElementCall'; import isReactChildrenElementCall from './isReactChildrenElementCall'; import resolveToValue from './resolveToValue'; -import type { NodePath } from '@babel/traverse'; +import type { NodePath, Scope } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import type { Expression } from '@babel/types'; +import { ignore } from './traverse'; const validPossibleStatelessComponentTypes = [ 'ArrowFunctionExpression', @@ -142,12 +144,43 @@ function resolvesToJSXElementOrReactCall( return false; } +interface TraverseState { + readonly initialScope: Scope; + isStatelessComponent: boolean; + readonly seen: WeakSet; +} + +const explodedVisitors = visitors.explode({ + Function: { enter: ignore }, + Class: { enter: ignore }, + ObjectExpression: { enter: ignore }, + ReturnStatement: { + enter: function (path, state) { + // Only check return statements which are part of the checked function scope + if (path.scope.getFunctionParent() !== state.initialScope) { + path.skip(); + + return; + } + + if ( + path.node.argument && + resolvesToJSXElementOrReactCall( + path.get('argument') as NodePath, + state.seen, + ) + ) { + state.isStatelessComponent = true; + path.stop(); + } + }, + }, +}); + function returnsJSXElementOrReactCall( path: NodePath, seen: WeakSet = new WeakSet(), ): boolean { - let visited = false; - if (path.isObjectProperty()) { path = path.get('value'); } @@ -165,32 +198,15 @@ function returnsJSXElementOrReactCall( return true; } - const scope = path.scope; - - path.traverse({ - ReturnStatement(returnPath) { - // Only check return statements which are part of the checked function scope - if (returnPath.scope.getFunctionParent() !== scope) { - path.skip(); - - return; - } + const state: TraverseState = { + initialScope: path.scope, + isStatelessComponent: false, + seen, + }; - if ( - returnPath.node.argument && - resolvesToJSXElementOrReactCall( - returnPath.get('argument') as NodePath, - - seen, - ) - ) { - visited = true; - path.skip(); - } - }, - }); + path.traverse(explodedVisitors, state); - return visited; + return state.isStatelessComponent; } /** diff --git a/src/utils/normalizeClassDefinition.ts b/src/utils/normalizeClassDefinition.ts index 6745054ec4b..fdec8cb9d79 100644 --- a/src/utils/normalizeClassDefinition.ts +++ b/src/utils/normalizeClassDefinition.ts @@ -2,13 +2,56 @@ import { classProperty } from '@babel/types'; import getMemberExpressionRoot from '../utils/getMemberExpressionRoot'; import getMembers from '../utils/getMembers'; import type { NodePath } from '@babel/traverse'; +import { visitors } from '@babel/traverse'; import type { ClassDeclaration, ClassExpression, Expression, } from '@babel/types'; +import { ignore } from './traverse'; -const ignore = (path: NodePath) => path.skip(); +interface TraverseState { + readonly variableName: string; + readonly classDefinition: NodePath; +} + +const explodedVisitors = visitors.explode({ + Function: { enter: ignore }, + Class: { enter: ignore }, + Loop: { enter: ignore }, + AssignmentExpression(path, state) { + const left = path.get('left'); + + if (left.isMemberExpression()) { + const first = getMemberExpressionRoot(left); + + if (first.isIdentifier() && first.node.name === state.variableName) { + const [member] = getMembers(left); + + if ( + member && + !member.path.has('computed') && + !member.path.isPrivateName() + ) { + const property = classProperty( + member.path.node as Expression, + path.node.right, + null, + null, + false, + true, + ); + + state.classDefinition.get('body').unshiftContainer('body', property); + path.skip(); + path.remove(); + } + } + } else { + path.skip(); + } + }, +}); /** * Given a class definition (i.e. `class` declaration or expression), this @@ -32,7 +75,7 @@ const ignore = (path: NodePath) => path.skip(); export default function normalizeClassDefinition( classDefinition: NodePath, ): void { - let variableName; + let variableName: string | undefined; if (classDefinition.isClassDeclaration()) { // Class declarations may not have an id, e.g.: `export default class extends React.Component {}` @@ -70,45 +113,10 @@ export default function normalizeClassDefinition( return; } - const scopeBlock = classDefinition.parentPath.scope.block; - - classDefinition.parentPath.scope.traverse(scopeBlock, { - Function: ignore, - ClassDeclaration: ignore, - ClassExpression: ignore, - ForInStatement: ignore, - ForStatement: ignore, - AssignmentExpression(path) { - const left = path.get('left'); - - if (left.isMemberExpression()) { - const first = getMemberExpressionRoot(left); - - if (first.isIdentifier() && first.node.name === variableName) { - const [member] = getMembers(left); + const state: TraverseState = { + variableName, + classDefinition, + }; - if ( - member && - !member.path.has('computed') && - !member.path.isPrivateName() - ) { - const property = classProperty( - member.path.node as Expression, - path.node.right, - null, - null, - false, - true, - ); - - classDefinition.get('body').unshiftContainer('body', property); - path.skip(); - path.remove(); - } - } - } else { - path.skip(); - } - }, - }); + classDefinition.parentPath.scope.path.traverse(explodedVisitors, state); } diff --git a/src/utils/traverse.ts b/src/utils/traverse.ts index 355824fb264..3066ac486ce 100644 --- a/src/utils/traverse.ts +++ b/src/utils/traverse.ts @@ -7,17 +7,12 @@ export function ignore(path: NodePath): void { export const shallowIgnoreVisitors = { FunctionDeclaration: { enter: ignore }, FunctionExpression: { enter: ignore }, - ClassDeclaration: { enter: ignore }, - ClassExpression: { enter: ignore }, + Class: { enter: ignore }, IfStatement: { enter: ignore }, WithStatement: { enter: ignore }, SwitchStatement: { enter: ignore }, CatchClause: { enter: ignore }, - WhileStatement: { enter: ignore }, - DoWhileStatement: { enter: ignore }, - ForStatement: { enter: ignore }, - ForInStatement: { enter: ignore }, - ForOfStatement: { enter: ignore }, + Loop: { enter: ignore }, ExportNamedDeclaration: { enter: ignore }, ExportDefaultDeclaration: { enter: ignore }, ConditionalExpression: { enter: ignore }, From aba75f8f2159697b2c67de8a99c6357ac51c7659 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Fri, 5 Aug 2022 22:28:51 +0200 Subject: [PATCH 36/44] chore: fix any type --- src/utils/__tests__/getParameterName-test.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/utils/__tests__/getParameterName-test.ts b/src/utils/__tests__/getParameterName-test.ts index aab6c2eb520..20b9a983e67 100644 --- a/src/utils/__tests__/getParameterName-test.ts +++ b/src/utils/__tests__/getParameterName-test.ts @@ -1,4 +1,8 @@ -import type { ClassDeclaration, FunctionExpression } from '@babel/types'; +import type { + ArrayPattern, + ClassDeclaration, + FunctionExpression, +} from '@babel/types'; import { parse } from '../../../tests/utils'; import getParameterName from '../getParameterName'; @@ -39,10 +43,10 @@ describe('getParameterName', () => { }); it('throws when passed an invalid path', () => { - const def = parse.expression('function() {}'); - const param = def; + // ArrayPattern is wrong, but we test here the throwing, so we are cheating the types + const def = parse.expression('function() {}'); - expect(() => getParameterName(param as any)).toThrow(); + expect(() => getParameterName(def)).toThrow(); }); it('handles typescript param property correctly', () => { From 1a495694069750099484a37fc598a114f9e90514 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 6 Aug 2022 19:52:02 +0200 Subject: [PATCH 37/44] feat!: New main API BREAKING CHANGE: The main API changed and now includes only 2 arguments. Read MIGRATE.md for more info. --- benchmark/index.js | 5 +- src/FileState.ts | 41 +++++------- src/__tests__/main-test.ts | 17 ++--- src/__tests__/parse-test.ts | 65 ++++++++++++------ src/babelParser.ts | 44 ++++++------ src/config.ts | 67 +++++++++++++++++++ src/importer/makeFsImporter.ts | 6 +- src/main.ts | 35 +++------- src/parse.ts | 16 ++--- .../__tests__/getMethodDocumentation-test.ts | 2 +- tests/utils.ts | 61 +++++++++-------- yarn.lock | 29 +------- 12 files changed, 213 insertions(+), 175 deletions(-) create mode 100644 src/config.ts diff --git a/benchmark/index.js b/benchmark/index.js index 218a1ec44ce..8d074e98570 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -32,15 +32,16 @@ files.forEach(file => { const code = fs.readFileSync(path.join(__dirname, file), 'utf-8'); const suite = new Benchmark.Suite(file.replace(/\.\/fixtures\//, '')); const options = { filename: file, babelrc: false, configFile: false }; + const newOptions = { babelOptions: options }; // warmup - parse(code, undefined, undefined, undefined, options); + parse(code, newOptions); parse6old(code, undefined, undefined, options); parse5(code, undefined, undefined, options); parse4(code, undefined, undefined, options); global.gc(); suite.add('current', () => { - parse(code, undefined, undefined, undefined, options); + parse(code, newOptions); }); suite.add('v6.0.0-alpha.3', () => { parse6old(code, undefined, undefined, options); diff --git a/src/FileState.ts b/src/FileState.ts index 6db65171a51..a9dfc1159cb 100644 --- a/src/FileState.ts +++ b/src/FileState.ts @@ -1,18 +1,18 @@ -import type { Options, Parser } from './babelParser'; import type { HubInterface, Scope, Visitor } from '@babel/traverse'; import traverse, { NodePath } from '@babel/traverse'; import type { File, Node, Program } from '@babel/types'; import type { Importer, ImportPath } from './importer'; +import buildParse from './babelParser'; +import type { TransformOptions } from '@babel/core'; export default class FileState { - opts: Options; + opts: TransformOptions; path: NodePath; ast: File; scope: Scope; code: string; #importer: Importer; - #parser: Parser; hub: HubInterface = { // keep it for the usage in babel-core, ex: path.hub.file.opts.filename @@ -36,19 +36,13 @@ export default class FileState { }; constructor( - options: Options, - { - code, - ast, - importer, - parser, - }: { code: string; ast: File; importer: Importer; parser: Parser }, + options: TransformOptions, + { code, ast, importer }: { code: string; ast: File; importer: Importer }, ) { this.opts = options; this.code = code; this.ast = ast; this.#importer = importer; - this.#parser = parser; this.path = NodePath.get({ hub: this.hub, @@ -61,7 +55,7 @@ export default class FileState { } /** - * Try to resolve and import with the `name` + * Try to resolve and import the ImportPath with the `name` */ import(path: ImportPath, name: string): NodePath | null { return this.#importer(path, name, this); @@ -69,20 +63,21 @@ export default class FileState { /** * Parse the content of a new file - * The filename is required so that potential imports inside the content can be correctly resolved + * The `filename` is required so that potential imports inside the content can be correctly resolved and + * the correct babel config file could be loaded. `filename` needs to be an absolute path. */ parse(code: string, filename: string): FileState { - const ast = this.#parser(code); + const newOptions = { ...this.opts, filename }; + // We need to build a new parser, because there might be a new + // babel config file in effect, so we need to load it + const parser = buildParse(newOptions); + const ast = parser(code); - return new FileState( - { ...this.opts, filename }, - { - ast, - code, - importer: this.#importer, - parser: this.#parser, - }, - ); + return new FileState(newOptions, { + ast, + code, + importer: this.#importer, + }); } traverse(visitors: Visitor, state?: S): void; diff --git a/src/__tests__/main-test.ts b/src/__tests__/main-test.ts index d0a4a806974..73f72788d00 100644 --- a/src/__tests__/main-test.ts +++ b/src/__tests__/main-test.ts @@ -12,9 +12,9 @@ describe('main', () => { }); it('parses with custom handlers', () => { - const docs = parse(source, undefined, [ - handlers.componentDocblockHandler, - ]); + const docs = parse(source, { + handlers: [handlers.componentDocblockHandler], + }); expect(docs).toMatchSnapshot(); }); @@ -212,16 +212,13 @@ describe('main', () => { let result; expect(() => { - result = parse( - fileContent, - undefined, - undefined, - importers.makeFsImporter(), - { + result = parse(fileContent, { + importer: importers.makeFsImporter(), + babelOptions: { filename: filePath, babelrc: false, }, - ); + }); }).not.toThrowError(); expect(result).toMatchSnapshot(); }); diff --git a/src/__tests__/parse-test.ts b/src/__tests__/parse-test.ts index 8f6eafb7a92..36e2b3e920a 100644 --- a/src/__tests__/parse-test.ts +++ b/src/__tests__/parse-test.ts @@ -10,7 +10,12 @@ describe('parse', () => { const resolver = jest.fn(() => [path]); const handler = jest.fn(); - parse('//empty', resolver, [handler], noopImporter); + parse('//empty', { + resolver, + handlers: [handler], + importer: noopImporter, + babelOptions: {}, + }); expect(resolver).toBeCalled(); expect(handler.mock.calls[0][1]).toBe(path); @@ -19,14 +24,24 @@ describe('parse', () => { it('errors if component definition is not found', () => { const resolver = jest.fn(() => []); - expect(() => parse('//empty', resolver, [], noopImporter)).toThrowError( - ERROR_MISSING_DEFINITION, - ); + expect(() => + parse('//empty', { + resolver, + handlers: [], + importer: noopImporter, + babelOptions: {}, + }), + ).toThrowError(ERROR_MISSING_DEFINITION); expect(resolver).toBeCalled(); - expect(() => parse('//empty', resolver, [], noopImporter)).toThrowError( - ERROR_MISSING_DEFINITION, - ); + expect(() => + parse('//empty', { + resolver, + handlers: [], + importer: noopImporter, + babelOptions: {}, + }), + ).toThrowError(ERROR_MISSING_DEFINITION); expect(resolver).toBeCalled(); }); @@ -38,9 +53,11 @@ describe('parse', () => { fs.writeFileSync(`${dir}/.babelrc`, '{}'); expect(() => - parse('const chained = () => a |> b', () => [], [], noopImporter, { - cwd: dir, - filename: `${dir}/component.js`, + parse('const chained = () => a |> b', { + resolver: () => [], + handlers: [], + importer: noopImporter, + babelOptions: { cwd: dir, filename: `${dir}/component.js` }, }), ).toThrowError( /.*Support for the experimental syntax 'pipelineOperator' isn't currently enabled.*/, @@ -53,12 +70,17 @@ describe('parse', () => { it('supports custom parserOptions with plugins', () => { expect(() => - parse('const chained: Type = 1;', () => [], [], noopImporter, { - parserOptions: { - plugins: [ - // no flow - 'jsx', - ], + parse('const chained: Type = 1;', { + resolver: () => [], + handlers: [], + importer: noopImporter, + babelOptions: { + parserOpts: { + plugins: [ + // no flow + 'jsx', + ], + }, }, }), ).toThrowError(/.*\(1:13\).*/); @@ -66,9 +88,14 @@ describe('parse', () => { it('supports custom parserOptions without plugins', () => { expect(() => - parse('const chained: Type = 1;', () => [], [], noopImporter, { - parserOptions: { - allowSuperOutsideMethod: true, + parse('const chained: Type = 1;', { + resolver: () => [], + handlers: [], + importer: noopImporter, + babelOptions: { + parserOpts: { + allowSuperOutsideMethod: true, + }, }, }), ).toThrowError(ERROR_MISSING_DEFINITION); diff --git a/src/babelParser.ts b/src/babelParser.ts index 692ee1d0201..ec2f554bd55 100644 --- a/src/babelParser.ts +++ b/src/babelParser.ts @@ -1,7 +1,7 @@ import type { ParserOptions, TransformOptions } from '@babel/core'; import { loadPartialConfig, parseSync } from '@babel/core'; import type { File } from '@babel/types'; -import path from 'path'; +import { extname } from 'node:path'; const TYPESCRIPT_EXTS = { '.cts': true, @@ -15,9 +15,7 @@ function getDefaultPlugins( ): NonNullable { return [ 'jsx', - TYPESCRIPT_EXTS[path.extname(options.filename || '')] - ? 'typescript' - : 'flow', + TYPESCRIPT_EXTS[extname(options.filename || '')] ? 'typescript' : 'flow', 'asyncDoExpressions', 'decimal', ['decorators', { decoratorsBeforeExport: false }], @@ -36,27 +34,27 @@ function getDefaultPlugins( ]; } -export type Options = TransformOptions & { parserOptions?: ParserOptions }; -export type Parser = (src: string) => File; +type Parser = (src: string) => File; function buildPluginList( - parserOptions: ParserOptions | undefined, - babelOptions: TransformOptions, + options: TransformOptions, ): NonNullable { let plugins: NonNullable = []; - if (parserOptions && parserOptions.plugins) { - plugins = [...parserOptions.plugins]; + if (options.parserOpts?.plugins) { + plugins = [...options.parserOpts.plugins]; } - const partialConfig = loadPartialConfig(babelOptions); + // Let's check if babel finds a config file for this source file + // If babel does find a config file we do not apply our defaults + const partialConfig = loadPartialConfig(options); if ( + plugins.length === 0 && partialConfig && - !partialConfig.hasFilesystemConfig() && - plugins.length === 0 + !partialConfig.hasFilesystemConfig() ) { - plugins = getDefaultPlugins(babelOptions); + plugins = getDefaultPlugins(options); } // Ensure that the estree plugin is never active @@ -64,26 +62,22 @@ function buildPluginList( return plugins.filter(plugin => plugin !== 'estree'); } -function buildOptions( - parserOptions: ParserOptions | undefined, - babelOptions: TransformOptions, -): ParserOptions { - const plugins = buildPluginList(parserOptions, babelOptions); +function buildParserOptions(options: TransformOptions): ParserOptions { + const plugins = buildPluginList(options); return { sourceType: 'unambiguous', - tokens: false, - ...(parserOptions || {}), + ...(options.parserOpts || {}), plugins, + tokens: false, }; } -export default function buildParse(options: Options = {}): Parser { - const { parserOptions, ...babelOptions } = options; - const parserOpts = buildOptions(parserOptions, babelOptions); +export default function buildParse(options: TransformOptions = {}): Parser { + const parserOpts = buildParserOptions(options); const opts: TransformOptions = { + ...options, parserOpts, - ...babelOptions, }; return (src: string): File => { diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 00000000000..e32cc3bf8d2 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,67 @@ +import type { TransformOptions } from '@babel/core'; +import type { Handler } from './handlers'; +import { + childContextTypeHandler, + codeTypeHandler, + componentDocblockHandler, + componentMethodsHandler, + componentMethodsJsDocHandler, + contextTypeHandler, + defaultPropsHandler, + displayNameHandler, + propDocBlockHandler, + propTypeCompositionHandler, + propTypeHandler, +} from './handlers'; +import type { Importer } from './importer'; +import { makeFsImporter } from './importer'; +import type { Resolver } from './resolver'; +import { findExportedComponentDefinition } from './resolver'; + +export interface Config { + handlers?: Handler[]; + importer?: Importer; + resolver?: Resolver; + /** + * shortcut for `babelOptions.filename` + * Set to an absolute path (recommended) to the file currently being parsed or + * to an relative path that is relative to the `babelOptions.cwd`. + */ + filename?: string; + babelOptions?: TransformOptions; +} +export type InternalConfig = Omit, 'filename'>; + +const defaultResolver: Resolver = findExportedComponentDefinition; +const defaultImporter: Importer = makeFsImporter(); + +export const defaultHandlers: Handler[] = [ + propTypeHandler, + contextTypeHandler, + childContextTypeHandler, + propTypeCompositionHandler, + propDocBlockHandler, + codeTypeHandler, + defaultPropsHandler, + componentDocblockHandler, + displayNameHandler, + componentMethodsHandler, + componentMethodsJsDocHandler, +]; + +export function createConfig(inputConfig: Config): InternalConfig { + const { babelOptions, filename, handlers, importer, resolver } = inputConfig; + + const config = { + babelOptions: { ...babelOptions }, + handlers: handlers ?? defaultHandlers, + importer: importer ?? defaultImporter, + resolver: resolver ?? defaultResolver, + }; + + if (filename) { + config.babelOptions.filename = filename; + } + + return config; +} diff --git a/src/importer/makeFsImporter.ts b/src/importer/makeFsImporter.ts index 77b75473247..45dea203a48 100644 --- a/src/importer/makeFsImporter.ts +++ b/src/importer/makeFsImporter.ts @@ -40,14 +40,14 @@ export default function makeFsImporter( // Bail if no filename was provided for the current source file. // Also never traverse into react itself. const source = path.node.source?.value; - const options = file.opts; + const { filename } = file.opts; - if (!source || !options || !options.filename || source === 'react') { + if (!source || !filename || source === 'react') { return null; } // Resolve the imported module using the Node resolver - const basedir = dirname(options.filename); + const basedir = dirname(filename); let resolvedSource: string | undefined; try { diff --git a/src/main.ts b/src/main.ts index 01d4837fa8d..4b05a27a1dd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,29 +3,13 @@ import parse from './parse'; import * as allResolvers from './resolver'; import * as allImporters from './importer'; import * as utils from './utils'; -import type { Options } from './babelParser'; import type { DocumentationObject as Documentation } from './Documentation'; import type { Resolver } from './resolver'; import type { Importer } from './importer'; import type { Handler } from './handlers'; import type FileState from './FileState'; - -const defaultResolver: Resolver = allResolvers.findExportedComponentDefinition; -const defaultHandlers: Handler[] = [ - allHandlers.propTypeHandler, - allHandlers.contextTypeHandler, - allHandlers.childContextTypeHandler, - allHandlers.propTypeCompositionHandler, - allHandlers.propDocBlockHandler, - allHandlers.codeTypeHandler, - allHandlers.defaultPropsHandler, - allHandlers.componentDocblockHandler, - allHandlers.displayNameHandler, - allHandlers.componentMethodsHandler, - allHandlers.componentMethodsJsDocHandler, -]; - -const defaultImporter: Importer = allImporters.makeFsImporter(); +import type { Config } from './config'; +import { createConfig, defaultHandlers } from './config'; declare module '@babel/traverse' { export interface HubInterface { @@ -52,16 +36,15 @@ declare module '@babel/traverse' { * provided object expression, and extract prop type information, prop * documentation (from docblocks), default prop values and component * documentation (from a docblock). + * TODO jsdoc */ function defaultParse( src: Buffer | string, - resolver: Resolver = defaultResolver, - handlers: Handler[] = defaultHandlers, - importer: Importer = defaultImporter, - // Used for backwards compatibility of this method - options: Options = {}, -): Documentation | Documentation[] { - return parse(String(src), resolver, handlers, importer, options); + config: Config = {}, +): Documentation[] { + const defaultConfig = createConfig(config); + + return parse(String(src), defaultConfig); } export { @@ -73,4 +56,4 @@ export { utils, }; -export type { Importer, Handler, Resolver, FileState, Options, Documentation }; +export type { Importer, Handler, Resolver, FileState, Config, Documentation }; diff --git a/src/parse.ts b/src/parse.ts index 760b3d72f48..f0e64970963 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -2,12 +2,11 @@ import Documentation from './Documentation'; import type { DocumentationObject } from './Documentation'; import postProcessDocumentation from './utils/postProcessDocumentation'; import buildParser from './babelParser'; -import type { Options } from './babelParser'; import type { NodePath } from '@babel/traverse'; import type { Handler } from './handlers'; -import type { Importer } from './importer'; -import type { ComponentNode, Resolver } from './resolver'; +import type { ComponentNode } from './resolver'; import FileState from './FileState'; +import type { InternalConfig } from './config'; const ERROR_MISSING_DEFINITION = 'No suitable component definition found.'; @@ -45,19 +44,16 @@ function executeHandlers( */ export default function parse( code: string, - resolver: Resolver, - handlers: Handler[], - importer: Importer, - options: Options = {}, + config: InternalConfig, ): DocumentationObject[] { - const parser = buildParser(options); + const { babelOptions, handlers, importer, resolver } = config; + const parser = buildParser(babelOptions); const ast = parser(code); - const fileState = new FileState(options, { + const fileState = new FileState(babelOptions, { ast, code, importer, - parser, }); const componentDefinitions = resolver(fileState); diff --git a/src/utils/__tests__/getMethodDocumentation-test.ts b/src/utils/__tests__/getMethodDocumentation-test.ts index 5e2e29cd91a..a6a0b2599ec 100644 --- a/src/utils/__tests__/getMethodDocumentation-test.ts +++ b/src/utils/__tests__/getMethodDocumentation-test.ts @@ -388,7 +388,7 @@ describe('getMethodDocumentation', () => { `class Foo { #foo() {} }`, - { parserOptions: { plugins: ['classPrivateMethods'] } }, + { parserOpts: { plugins: ['classPrivateMethods'] } }, ); const method = def .get('body') diff --git a/tests/utils.ts b/tests/utils.ts index c834e0da564..c37fa4107c9 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,6 +1,5 @@ -import type { Node } from '@babel/core'; +import type { Node, TransformOptions } from '@babel/core'; import type { NodePath } from '@babel/traverse'; -import type { Options, Parser } from '../src/babelParser'; import type { Importer, ImportPath } from '../src/importer'; import FileState from '../src/FileState'; import buildParser from '../src/babelParser'; @@ -22,27 +21,26 @@ declare global { } } -export function getParser(options: Options = {}): Parser { - return buildParser(options); -} - interface ParseCall { (code: string, importer: Importer): NodePath; - (code: string, options: Options): NodePath; + (code: string, options: TransformOptions): NodePath; ( code: string, - options?: Options, + options?: TransformOptions, importer?: Importer, returnFileState?: B, ): B extends true ? FileState : NodePath; } interface Parse extends ParseCall { - expression(src: string, options?: Options): NodePath; + expression( + src: string, + options?: TransformOptions, + ): NodePath; expression( src: string, importer: Importer, - options?: Options, + options?: TransformOptions, ): NodePath; statement(src: string, index?: number): NodePath; statement( @@ -52,26 +50,32 @@ interface Parse extends ParseCall { ): NodePath; statement( src: string, - options: Options, + options: TransformOptions, index?: number, ): NodePath; statement( src: string, importer: Importer, - options: Options, + options: TransformOptions, index?: number, ): NodePath; - expressionLast(src: string, options?: Options): NodePath; + expressionLast( + src: string, + options?: TransformOptions, + ): NodePath; expressionLast( src: string, importer: Importer, - options?: Options, + options?: TransformOptions, + ): NodePath; + statementLast( + src: string, + options?: TransformOptions, ): NodePath; - statementLast(src: string, options?: Options): NodePath; statementLast( src: string, importer: Importer, - options?: Options, + options?: TransformOptions, ): NodePath; } @@ -81,7 +85,7 @@ interface Parse extends ParseCall { */ const parseDefault: ParseCall = function ( code: string, - options: Importer | Options = {}, + options: Importer | TransformOptions = {}, importer: Importer = noopImporter, returnFileState = false, ): typeof returnFileState extends true ? FileState : NodePath { @@ -93,13 +97,12 @@ const parseDefault: ParseCall = function ( babelrc: false, ...options, }; - const parser = getParser(opts); + const parser = buildParser(opts); const ast = parser(code); const fileState = new FileState(opts, { ast, code, importer, - parser, }); if (returnFileState) { @@ -111,7 +114,7 @@ const parseDefault: ParseCall = function ( const parseTS: ParseCall = function ( code: string, - options: Importer | Options = {}, + options: Importer | TransformOptions = {}, importer: Importer = noopImporter, ): NodePath { if (typeof options !== 'object') { @@ -123,7 +126,7 @@ const parseTS: ParseCall = function ( code, { filename: 'file.tsx', - parserOptions: { plugins: ['typescript'] }, + parserOpts: { plugins: ['typescript'] }, ...options, }, importer, @@ -138,8 +141,8 @@ function buildTestParser(parseFunction: Parse): Parse { parseFunction.statement = function ( this: Parse, src: string, - importer: Importer | Options | number = noopImporter, - options: Options | number = {}, + importer: Importer | TransformOptions | number = noopImporter, + options: TransformOptions | number = {}, index = 0, ): NodePath { if (typeof options === 'number') { @@ -165,8 +168,8 @@ function buildTestParser(parseFunction: Parse): Parse { parseFunction.statementLast = function ( this: Parse, src: string, - importer: Importer | Options = noopImporter, - options: Options = {}, + importer: Importer | TransformOptions = noopImporter, + options: TransformOptions = {}, ): NodePath { if (typeof importer === 'object') { options = importer; @@ -179,8 +182,8 @@ function buildTestParser(parseFunction: Parse): Parse { parseFunction.expression = function ( this: Parse, src: string, - importer: Importer | Options = noopImporter, - options: Options = {}, + importer: Importer | TransformOptions = noopImporter, + options: TransformOptions = {}, ): NodePath { if (typeof importer === 'object') { options = importer; @@ -197,8 +200,8 @@ function buildTestParser(parseFunction: Parse): Parse { parseFunction.expressionLast = function ( this: Parse, src: string, - importer: Importer | Options = noopImporter, - options: Options = {}, + importer: Importer | TransformOptions = noopImporter, + options: TransformOptions = {}, ): NodePath { if (typeof importer === 'object') { options = importer; diff --git a/yarn.lock b/yarn.lock index 0eead02614b..8990d9aea78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -43,15 +43,6 @@ json5 "^2.2.1" semver "^6.3.0" -"@babel/generator@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.10.tgz#794f328bfabdcbaf0ebf9bf91b5b57b61fa77a2a" - integrity sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA== - dependencies: - "@babel/types" "^7.18.10" - "@jridgewell/gen-mapping" "^0.3.2" - jsesc "^2.5.1" - "@babel/generator@^7.18.9", "@babel/generator@^7.7.2": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.9.tgz#68337e9ea8044d6ddc690fb29acae39359cca0a5" @@ -164,7 +155,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.11": +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.9": version "7.18.11" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9" integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ== @@ -260,7 +251,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/template@^7.18.10", "@babel/template@^7.18.6", "@babel/template@^7.3.3": +"@babel/template@^7.18.6", "@babel/template@^7.3.3": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== @@ -269,22 +260,6 @@ "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" -"@babel/traverse@^7.18.10": - version "7.18.11" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.11.tgz#3d51f2afbd83ecf9912bcbb5c4d94e3d2ddaa16f" - integrity sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.18.10" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.18.9" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.18.11" - "@babel/types" "^7.18.10" - debug "^4.1.0" - globals "^11.1.0" - "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98" From cb247ad4586d7cd5680a0296f74f81b9ccfe281e Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 6 Aug 2022 19:52:34 +0200 Subject: [PATCH 38/44] chore: Do not have a parser factory if parser ever only used once --- src/FileState.ts | 5 ++--- src/babelParser.ts | 19 +++++++++---------- src/parse.ts | 5 ++--- tests/utils.ts | 5 ++--- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/FileState.ts b/src/FileState.ts index a9dfc1159cb..47717b642b9 100644 --- a/src/FileState.ts +++ b/src/FileState.ts @@ -2,7 +2,7 @@ import type { HubInterface, Scope, Visitor } from '@babel/traverse'; import traverse, { NodePath } from '@babel/traverse'; import type { File, Node, Program } from '@babel/types'; import type { Importer, ImportPath } from './importer'; -import buildParse from './babelParser'; +import babelParse from './babelParser'; import type { TransformOptions } from '@babel/core'; export default class FileState { @@ -70,8 +70,7 @@ export default class FileState { const newOptions = { ...this.opts, filename }; // We need to build a new parser, because there might be a new // babel config file in effect, so we need to load it - const parser = buildParse(newOptions); - const ast = parser(code); + const ast = babelParse(code, newOptions); return new FileState(newOptions, { ast, diff --git a/src/babelParser.ts b/src/babelParser.ts index ec2f554bd55..b84942ed95f 100644 --- a/src/babelParser.ts +++ b/src/babelParser.ts @@ -34,8 +34,6 @@ function getDefaultPlugins( ]; } -type Parser = (src: string) => File; - function buildPluginList( options: TransformOptions, ): NonNullable { @@ -73,20 +71,21 @@ function buildParserOptions(options: TransformOptions): ParserOptions { }; } -export default function buildParse(options: TransformOptions = {}): Parser { +export default function babelParser( + src: string, + options: TransformOptions = {}, +): File { const parserOpts = buildParserOptions(options); const opts: TransformOptions = { ...options, parserOpts, }; - return (src: string): File => { - const ast = parseSync(src, opts); + const ast = parseSync(src, opts); - if (!ast) { - throw new Error('Unable to parse source code.'); - } + if (!ast) { + throw new Error('Unable to parse source code.'); + } - return ast; - }; + return ast; } diff --git a/src/parse.ts b/src/parse.ts index f0e64970963..80d07cdbac9 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -1,7 +1,7 @@ import Documentation from './Documentation'; import type { DocumentationObject } from './Documentation'; import postProcessDocumentation from './utils/postProcessDocumentation'; -import buildParser from './babelParser'; +import babelParse from './babelParser'; import type { NodePath } from '@babel/traverse'; import type { Handler } from './handlers'; import type { ComponentNode } from './resolver'; @@ -47,8 +47,7 @@ export default function parse( config: InternalConfig, ): DocumentationObject[] { const { babelOptions, handlers, importer, resolver } = config; - const parser = buildParser(babelOptions); - const ast = parser(code); + const ast = babelParse(code, babelOptions); const fileState = new FileState(babelOptions, { ast, diff --git a/tests/utils.ts b/tests/utils.ts index c37fa4107c9..c79dfdb3ba4 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -2,7 +2,7 @@ import type { Node, TransformOptions } from '@babel/core'; import type { NodePath } from '@babel/traverse'; import type { Importer, ImportPath } from '../src/importer'; import FileState from '../src/FileState'; -import buildParser from '../src/babelParser'; +import babelParse from '../src/babelParser'; import type { ExportDefaultDeclaration, Expression, @@ -97,8 +97,7 @@ const parseDefault: ParseCall = function ( babelrc: false, ...options, }; - const parser = buildParser(opts); - const ast = parser(code); + const ast = babelParse(code, opts); const fileState = new FileState(opts, { ast, code, From 469bad3722f2add1a399aca3aeac79dccf219e77 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 6 Aug 2022 20:25:19 +0200 Subject: [PATCH 39/44] chore: make website work again --- benchmark/index.js | 4 ++-- bin/__tests__/react-docgen-test.ts | 4 ++-- package.json | 4 ++-- src/__tests__/main-test.ts | 4 ++-- src/importer/ignoreImports.ts | 7 ------- src/importer/index.ts | 4 ++-- src/importer/makeFsImporter.ts | 4 ++-- src/importer/makeIgnoreImports.ts | 9 +++++++++ website/src/components/App.js | 22 ++++++++++++---------- website/webpack.config.js | 8 +++++--- 10 files changed, 38 insertions(+), 32 deletions(-) delete mode 100644 src/importer/ignoreImports.ts create mode 100644 src/importer/makeIgnoreImports.ts diff --git a/benchmark/index.js b/benchmark/index.js index 8d074e98570..2a4584bbae6 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -1,5 +1,5 @@ -const fs = require('fs'); -const path = require('path'); +const fs = require('node:fs'); +const path = require('node:path'); const Table = require('cli-table'); const Benchmark = require('benchmark'); const { parse } = require('..'); diff --git a/bin/__tests__/react-docgen-test.ts b/bin/__tests__/react-docgen-test.ts index b46e0c64193..36b8fc19720 100644 --- a/bin/__tests__/react-docgen-test.ts +++ b/bin/__tests__/react-docgen-test.ts @@ -3,8 +3,8 @@ const TEST_TIMEOUT = 120000; -import fs, { promises } from 'fs'; -import path from 'path'; +import fs, { promises } from 'node:fs'; +import path from 'node:path'; import rimraf from 'rimraf'; import { directory as tempDirectory, file as tempFile } from 'tempy'; import spawn from 'cross-spawn'; diff --git a/package.json b/package.json index 301ddd7f8aa..227216fb9f6 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,8 @@ "react-docgen": "bin/react-docgen.js" }, "browser": { - "./src/importer/makeFsImporter.ts": "./src/importer/ignoreImports.ts", - "./dist/importer/makeFsImporter.js": "./dist/importer/ignoreImports.js" + "./src/importer/makeFsImporter.ts": "./src/importer/makeIgnoreImports.ts", + "./dist/importer/makeFsImporter.js": "./dist/importer/makeIgnoreImports.js" }, "files": [ "bin", diff --git a/src/__tests__/main-test.ts b/src/__tests__/main-test.ts index 73f72788d00..fd571d74d64 100644 --- a/src/__tests__/main-test.ts +++ b/src/__tests__/main-test.ts @@ -1,5 +1,5 @@ -import fs from 'fs'; -import path from 'path'; +import fs from 'node:fs'; +import path from 'node:path'; import { handlers, parse, importers } from '../main'; import { ERROR_MISSING_DEFINITION } from '../parse'; diff --git a/src/importer/ignoreImports.ts b/src/importer/ignoreImports.ts deleted file mode 100644 index 7d44ece037b..00000000000 --- a/src/importer/ignoreImports.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Importer } from '.'; - -const ignoreImports: Importer = function (): null { - return null; -}; - -export default ignoreImports; diff --git a/src/importer/index.ts b/src/importer/index.ts index e0c30f2bbb7..bb9bbd3fe62 100644 --- a/src/importer/index.ts +++ b/src/importer/index.ts @@ -5,7 +5,7 @@ import type { ImportDeclaration, } from '@babel/types'; import type FileState from '../FileState'; -import ignoreImports from './ignoreImports'; +import makeIgnoreImports from './makeIgnoreImports'; import makeFsImporter from './makeFsImporter'; export type ImportPath = NodePath< @@ -18,4 +18,4 @@ export type Importer = ( file: FileState, ) => NodePath | null; -export { ignoreImports, makeFsImporter }; +export { makeIgnoreImports, makeFsImporter }; diff --git a/src/importer/makeFsImporter.ts b/src/importer/makeFsImporter.ts index 45dea203a48..3d2739eb002 100644 --- a/src/importer/makeFsImporter.ts +++ b/src/importer/makeFsImporter.ts @@ -1,7 +1,7 @@ import { shallowIgnoreVisitors } from '../utils/traverse'; import resolve from 'resolve'; -import { dirname } from 'path'; -import fs from 'fs'; +import { dirname } from 'node:path'; +import fs from 'node:fs'; import type { NodePath } from '@babel/traverse'; import { visitors } from '@babel/traverse'; import type { ExportSpecifier, Identifier, ObjectProperty } from '@babel/types'; diff --git a/src/importer/makeIgnoreImports.ts b/src/importer/makeIgnoreImports.ts new file mode 100644 index 00000000000..04c717274fe --- /dev/null +++ b/src/importer/makeIgnoreImports.ts @@ -0,0 +1,9 @@ +import type { Importer } from '.'; + +const ignoreImports: Importer = function (): null { + return null; +}; + +// Needs to be a factory because it has to be the exact same API as makeFsImport as +// we replace makeFsImport in browsers with this file +export default () => ignoreImports; diff --git a/website/src/components/App.js b/website/src/components/App.js index 50523c1b880..6eb86b25518 100644 --- a/website/src/components/App.js +++ b/website/src/components/App.js @@ -82,7 +82,7 @@ export default class App extends React.Component { } compile(value, options) { - return JSON.stringify(parse(value, null, null, options), null, 2); + return JSON.stringify(parse(value, options), null, 2); } handleChange = value => { @@ -100,22 +100,24 @@ export default class App extends React.Component { buildOptions(language) { const options = { - babelrc: false, - babelrcRoots: false, - configFile: false, - filename: 'playground.js', - parserOptions: { - plugins: [...defaultPlugins], + babelOptions: { + babelrc: false, + babelrcRoots: false, + configFile: false, + filename: 'playground.js', + parserOpts: { + plugins: [...defaultPlugins], + }, }, }; switch (language) { case 'ts': - options.parserOptions.plugins.push('typescript'); - options.filename = 'playground.tsx'; + options.babelOptions.parserOpts.plugins.push('typescript'); + options.babelOptions.filename = 'playground.tsx'; break; case 'flow': - options.parserOptions.plugins.push('flow'); + options.babelOptions.parserOpts.plugins.push('flow'); break; } diff --git a/website/webpack.config.js b/website/webpack.config.js index 45e847acad5..06695fbe12a 100644 --- a/website/webpack.config.js +++ b/website/webpack.config.js @@ -1,7 +1,7 @@ 'use strict'; const webpack = require('webpack'); -const path = require('path'); +const path = require('node:path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const TerserJsPlugin = require('terser-webpack-plugin'); @@ -13,6 +13,10 @@ const targetDirectory = path.resolve(__dirname, './dist'); const isDev = process.env.NODE_ENV !== 'production'; const plugins = [ + new webpack.NormalModuleReplacementPlugin(/^node:/, resource => { + // Remove node: file protocol + resource.request = resource.request.slice(5); + }), new HtmlWebpackPlugin({ filename: 'index.html', inject: true, @@ -96,8 +100,6 @@ module.exports = { assert: require.resolve('assert/'), buffer: require.resolve('buffer/'), fs: false, - module: false, - net: false, path: require.resolve('path-browserify'), process: require.resolve('process/browser'), }, From a809fde8595ca380643b741cfa14dbad8b5ee572 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sat, 6 Aug 2022 23:59:35 +0200 Subject: [PATCH 40/44] chore: update docs --- src/main.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main.ts b/src/main.ts index 4b05a27a1dd..efc4813792b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,17 +26,16 @@ declare module '@babel/traverse' { } /** - * See `parse.js` for more information about the arguments. This function - * simply sets default values for convenience. + * Parse the *src* and scan for react components based on the config + * that gets supplied. * - * The default resolver looks for *exported* `React.createClass(def)` calls - * and expected `def` to resolve to an object expression. + * The default resolvers look for *exported* react components. * - * The default `handlers` look for `propTypes` and `getDefaultProps` in the - * provided object expression, and extract prop type information, prop - * documentation (from docblocks), default prop values and component - * documentation (from a docblock). - * TODO jsdoc + * By default all handlers are applied, so that all possible + * different use cases are covered. + * + * The default importer is the fs-importer that tries to resolve + * files based on the nodejs resolve algorithm. */ function defaultParse( src: Buffer | string, From 25843f48805f791af00d0c3b52dfb40b0b9bcbb6 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 7 Aug 2022 00:06:53 +0200 Subject: [PATCH 41/44] fix: Handle some edge cases in resolveToValue --- .../__snapshots__/resolveToValue-test.ts.snap | 46 +++++++++++++++++ src/utils/__tests__/resolveToValue-test.ts | 51 +++++++++++++++++-- src/utils/getMethodDocumentation.ts | 1 - src/utils/resolveToValue.ts | 25 ++++----- 4 files changed, 105 insertions(+), 18 deletions(-) create mode 100644 src/utils/__tests__/__snapshots__/resolveToValue-test.ts.snap diff --git a/src/utils/__tests__/__snapshots__/resolveToValue-test.ts.snap b/src/utils/__tests__/__snapshots__/resolveToValue-test.ts.snap new file mode 100644 index 00000000000..773d94dda34 --- /dev/null +++ b/src/utils/__tests__/__snapshots__/resolveToValue-test.ts.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`resolveToValue ImportDeclaration does not crash when resolving MemberExpression with non Identifiers 1`] = ` +Node { + "computed": true, + "object": Node { + "name": "bar", + "type": "Identifier", + }, + "property": Node { + "async": false, + "body": Node { + "body": Array [], + "directives": Array [], + "type": "BlockStatement", + }, + "generator": false, + "id": null, + "params": Array [], + "type": "ArrowFunctionExpression", + }, + "type": "MemberExpression", +} +`; + +exports[`resolveToValue ImportDeclaration resolves namespace import references to the import declaration 1`] = ` +Node { + "extra": Object { + "raw": "3", + "rawValue": 3, + }, + "type": "NumericLiteral", + "value": 3, +} +`; + +exports[`resolveToValue ImportDeclaration resolves namespace import references to the import declaration 2`] = ` +Node { + "extra": Object { + "raw": "3", + "rawValue": 3, + }, + "type": "NumericLiteral", + "value": 3, +} +`; diff --git a/src/utils/__tests__/resolveToValue-test.ts b/src/utils/__tests__/resolveToValue-test.ts index 2755931189a..4725104b5fb 100644 --- a/src/utils/__tests__/resolveToValue-test.ts +++ b/src/utils/__tests__/resolveToValue-test.ts @@ -1,5 +1,6 @@ import type { NodePath } from '@babel/traverse'; import { + ExportNamedDeclaration, identifier, memberExpression, numericLiteral, @@ -11,10 +12,20 @@ import type { CallExpression, Identifier, } from '@babel/types'; -import { parse, parseTypescript } from '../../../tests/utils'; +import { makeMockImporter, parse, parseTypescript } from '../../../tests/utils'; import resolveToValue from '../resolveToValue'; describe('resolveToValue', () => { + const mockImporter = makeMockImporter({ + Foo: stmtLast => + stmtLast(` + const baz = 3; + export { baz }; + `) + .get('specifiers')[0] + .get('local') as NodePath, + }); + it('resolves simple variable declarations', () => { const path = parse.expressionLast(['var foo = 42;', 'foo;'].join('\n')); @@ -160,7 +171,7 @@ describe('resolveToValue', () => { }); describe('ImportDeclaration', () => { - it('resolves default import references to the import declaration', () => { + it('resolves unresolvable default import references to the import declaration', () => { const path = parse.expressionLast( ['import foo from "Foo"', 'foo;'].join('\n'), ); @@ -169,7 +180,7 @@ describe('resolveToValue', () => { expect(value.node.type).toBe('ImportDeclaration'); }); - it('resolves named import references to the import declaration', () => { + it('resolves unresolvable named import references to the import declaration', () => { const path = parse.expressionLast( ['import {foo} from "Foo"', 'foo;'].join('\n'), ); @@ -178,7 +189,7 @@ describe('resolveToValue', () => { expect(value.node.type).toBe('ImportDeclaration'); }); - it('resolves aliased import references to the import declaration', () => { + it('resolves unresolvable aliased import references to the import declaration', () => { const path = parse.expressionLast( ['import {foo as bar} from "Foo"', 'bar;'].join('\n'), ); @@ -187,7 +198,7 @@ describe('resolveToValue', () => { expect(value.node.type).toBe('ImportDeclaration'); }); - it('resolves namespace import references to the import declaration', () => { + it('resolves unresolvable namespace import references to the import declaration', () => { const path = parse.expressionLast( ['import * as bar from "Foo"', 'bar;'].join('\n'), ); @@ -195,6 +206,36 @@ describe('resolveToValue', () => { expect(value.node.type).toBe('ImportDeclaration'); }); + + it('resolves namespace import references to the import declaration', () => { + const path = parse.expressionLast( + `import * as bar from "Foo"; bar.baz`, + mockImporter, + ); + const value = resolveToValue(path); + + expect(value).toMatchSnapshot(); + }); + + it('resolves namespace import references to the import declaration', () => { + const path = parse.expressionLast( + `import * as bar from "Foo"; bar['baz']`, + mockImporter, + ); + const value = resolveToValue(path); + + expect(value).toMatchSnapshot(); + }); + + it('does not crash when resolving MemberExpression with non Identifiers', () => { + const path = parse.expressionLast( + `import * as bar from "Foo"; bar[()=>{}]`, + mockImporter, + ); + const value = resolveToValue(path); + + expect(value).toMatchSnapshot(); + }); }); describe('MemberExpression', () => { diff --git a/src/utils/getMethodDocumentation.ts b/src/utils/getMethodDocumentation.ts index a1a77465b4e..15850025a00 100644 --- a/src/utils/getMethodDocumentation.ts +++ b/src/utils/getMethodDocumentation.ts @@ -139,7 +139,6 @@ function getMethodModifiers( const modifiers: MethodModifier[] = []; if ( - // TODO add test for options options.isStatic === true || ((methodPath.isClassProperty() || methodPath.isClassMethod()) && methodPath.node.static) diff --git a/src/utils/resolveToValue.ts b/src/utils/resolveToValue.ts index 1c1fb53f68a..d0c173ebc31 100644 --- a/src/utils/resolveToValue.ts +++ b/src/utils/resolveToValue.ts @@ -1,10 +1,6 @@ import { Scope, visitors } from '@babel/traverse'; import type { NodePath } from '@babel/traverse'; -import type { - Identifier, - ImportDeclaration, - MemberExpression, -} from '@babel/types'; +import type { Identifier, ImportDeclaration } from '@babel/types'; import getMemberExpressionRoot from './getMemberExpressionRoot'; import getPropertyValuePath from './getPropertyValuePath'; import { Array as toArray } from './expressionTo'; @@ -13,6 +9,7 @@ import getMemberValuePath, { isSupportedDefinitionType, } from './getMemberValuePath'; import initialize from './ts-types'; +import getNameOrValue from './getNameOrValue'; function findScopePath( bindingIdentifiers: Array>, @@ -199,16 +196,20 @@ export default function resolveToValue(path: NodePath): NodePath { // Try to find a specifier that matches the root of the member expression, and // find the export that matches the property name. for (const specifier of resolved.get('specifiers')) { + const property = path.get('property'); + let propertyName: string | undefined; + + if (property.isIdentifier() || property.isStringLiteral()) { + propertyName = getNameOrValue(property) as string; + } + if ( specifier.isImportNamespaceSpecifier() && - specifier.node.local && - specifier.node.local.name === (root.node as Identifier).name // TODO TESTME could be not an identifier + root.isIdentifier() && + propertyName && + specifier.node.local.name === root.node.name ) { - const resolvedPath = path.hub.import( - resolved, - ((root.parentPath.node as MemberExpression).property as Identifier) - .name, // TODO TESTME Idk what that is - ); + const resolvedPath = path.hub.import(resolved, propertyName); if (resolvedPath) { return resolveToValue(resolvedPath); From e99b0f5e43a5928cb4929adfea6ca9f570853c35 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 7 Aug 2022 21:07:16 +0200 Subject: [PATCH 42/44] chore: Fix some eslint warnings --- src/utils/__tests__/resolveToValue-test.ts | 2 +- src/utils/getPropType.ts | 19 ++++++++++++++----- tests/utils.ts | 22 +++++++++++++++++----- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/utils/__tests__/resolveToValue-test.ts b/src/utils/__tests__/resolveToValue-test.ts index 4725104b5fb..fe0040db1f4 100644 --- a/src/utils/__tests__/resolveToValue-test.ts +++ b/src/utils/__tests__/resolveToValue-test.ts @@ -1,6 +1,5 @@ import type { NodePath } from '@babel/traverse'; import { - ExportNamedDeclaration, identifier, memberExpression, numericLiteral, @@ -11,6 +10,7 @@ import type { AssignmentExpression, CallExpression, Identifier, + ExportNamedDeclaration, } from '@babel/types'; import { makeMockImporter, parse, parseTypescript } from '../../../tests/utils'; import resolveToValue from '../resolveToValue'; diff --git a/src/utils/getPropType.ts b/src/utils/getPropType.ts index b6be8ddf628..ffa8d26ad86 100644 --- a/src/utils/getPropType.ts +++ b/src/utils/getPropType.ts @@ -255,8 +255,11 @@ export default function getPropType(path: NodePath): PropTypeDescriptor { descriptor = { name }; return true; - } else if (propTypes.has(name) && member.argumentPaths.length) { - descriptor = propTypes.get(name)!(member.argumentPaths[0]); + } + const propTypeHandler = propTypes.get(name); + + if (propTypeHandler && member.argumentPaths.length) { + descriptor = propTypeHandler(member.argumentPaths[0]); return true; } @@ -271,11 +274,17 @@ export default function getPropType(path: NodePath): PropTypeDescriptor { if (path.isIdentifier() && isSimplePropType(path.node.name)) { return { name: path.node.name }; - } else if (path.isCallExpression()) { + } + + if (path.isCallExpression()) { const callee = path.get('callee'); - if (callee.isIdentifier() && propTypes.has(callee.node.name)) { - return propTypes.get(callee.node.name)!(path.get('arguments')[0]); + if (callee.isIdentifier()) { + const propTypeHandler = propTypes.get(callee.node.name); + + if (propTypeHandler) { + return propTypeHandler(path.get('arguments')[0]); + } } } diff --git a/tests/utils.ts b/tests/utils.ts index c79dfdb3ba4..4344c13a4da 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -79,16 +79,28 @@ interface Parse extends ParseCall { ): NodePath; } +function parseDefault( + code: string, + options: Importer | TransformOptions, + importer: Importer, + returnFileState: true, +): FileState; +function parseDefault( + code: string, + options: Importer | TransformOptions, + importer: Importer, + returnFileState: false, +): NodePath; /** * Returns a NodePath to the program path of the passed node * Parses JS and Flow */ -const parseDefault: ParseCall = function ( +function parseDefault( code: string, options: Importer | TransformOptions = {}, importer: Importer = noopImporter, returnFileState = false, -): typeof returnFileState extends true ? FileState : NodePath { +): FileState | NodePath { if (typeof options !== 'object') { importer = options; options = {}; @@ -105,11 +117,11 @@ const parseDefault: ParseCall = function ( }); if (returnFileState) { - return fileState as any; + return fileState; } - return fileState.path as any; -}; + return fileState.path; +} const parseTS: ParseCall = function ( code: string, From 40e6e8c5f2890044ea75c75036142003864c6b07 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 7 Aug 2022 21:26:06 +0200 Subject: [PATCH 43/44] chore: Remove @babel/generator as unused --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 227216fb9f6..6d7374ee66b 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "license": "MIT", "dependencies": { "@babel/core": "^7.18.9", - "@babel/generator": "^7.18.9", "@babel/traverse": "^7.18.9", "@babel/types": "^7.18.9", "commander": "^2.19.0", From b716e991b5003eb537b897f931a710668c00976a Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Sun, 7 Aug 2022 21:27:38 +0200 Subject: [PATCH 44/44] chore: Move some types to dependencies because they are exposed --- package.json | 6 +++--- yarn.lock | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 6d7374ee66b..be7ddddaa48 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,9 @@ "@babel/core": "^7.18.9", "@babel/traverse": "^7.18.9", "@babel/types": "^7.18.9", + "@types/babel__traverse": "^7.18.0", + "@types/doctrine": "^0.0.5", + "@types/resolve": "^1.20.2", "commander": "^2.19.0", "doctrine": "^3.0.0", "neo-async": "^2.6.2", @@ -54,11 +57,8 @@ "strip-indent": "^3.0.0" }, "devDependencies": { - "@types/babel__traverse": "7.18.0", "@types/cross-spawn": "6.0.2", - "@types/doctrine": "0.0.5", "@types/jest": "28.1.6", - "@types/resolve": "1.20.2", "@types/rimraf": "3.0.2", "@typescript-eslint/eslint-plugin": "5.32.0", "@typescript-eslint/parser": "5.32.0", diff --git a/yarn.lock b/yarn.lock index 8990d9aea78..2a190f13852 100644 --- a/yarn.lock +++ b/yarn.lock @@ -654,7 +654,7 @@ dependencies: "@babel/types" "^7.3.0" -"@types/babel__traverse@7.18.0": +"@types/babel__traverse@^7.18.0": version "7.18.0" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.0.tgz#8134fd78cb39567465be65b9fdc16d378095f41f" integrity sha512-v4Vwdko+pgymgS+A2UIaJru93zQd85vIGWObM5ekZNdXCKtDYqATlEYnWgfo86Q6I1Lh0oXnksDnMU1cwmlPDw== @@ -668,7 +668,7 @@ dependencies: "@types/node" "*" -"@types/doctrine@0.0.5": +"@types/doctrine@^0.0.5": version "0.0.5" resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.5.tgz#9768264221e8fd422e4989c8cfdab2ff781f4eb6" integrity sha512-JJwEeFy8Sl9ctiugU4h4DGN9hCB47oyhUkM2H8g8xZr4tHTEXtmV4U6krKrU8Ng0S7RlG/J7fkta1rGu3pq+YQ== @@ -735,7 +735,7 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.4.tgz#ad899dad022bab6b5a9f0a0fe67c2f7a4a8950ed" integrity sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw== -"@types/resolve@1.20.2": +"@types/resolve@^1.20.2": version "1.20.2" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==