diff options
Diffstat (limited to 'node_modules/babel-plugin-jest-hoist')
-rw-r--r-- | node_modules/babel-plugin-jest-hoist/LICENSE | 21 | ||||
-rw-r--r-- | node_modules/babel-plugin-jest-hoist/README.md | 33 | ||||
-rw-r--r-- | node_modules/babel-plugin-jest-hoist/build/index.d.ts | 13 | ||||
-rw-r--r-- | node_modules/babel-plugin-jest-hoist/build/index.js | 389 | ||||
-rw-r--r-- | node_modules/babel-plugin-jest-hoist/package.json | 41 |
5 files changed, 497 insertions, 0 deletions
diff --git a/node_modules/babel-plugin-jest-hoist/LICENSE b/node_modules/babel-plugin-jest-hoist/LICENSE new file mode 100644 index 0000000..b96dcb0 --- /dev/null +++ b/node_modules/babel-plugin-jest-hoist/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/babel-plugin-jest-hoist/README.md b/node_modules/babel-plugin-jest-hoist/README.md new file mode 100644 index 0000000..1a90bbe --- /dev/null +++ b/node_modules/babel-plugin-jest-hoist/README.md @@ -0,0 +1,33 @@ +# babel-plugin-jest-hoist + +Babel plugin to hoist `jest.disableAutomock`, `jest.enableAutomock`, `jest.unmock`, `jest.mock`, calls above `import` statements. This plugin is automatically included when using [babel-jest](https://github.com/facebook/jest/tree/main/packages/babel-jest). + +## Installation + +```sh +$ yarn add --dev babel-plugin-jest-hoist +``` + +## Usage + +### Via `babel.config.js` (Recommended) + +```js +module.exports = { + plugins: ['jest-hoist'], +}; +``` + +### Via CLI + +```sh +$ babel --plugins jest-hoist script.js +``` + +### Via Node API + +```javascript +require('@babel/core').transform('code', { + plugins: ['jest-hoist'], +}); +``` diff --git a/node_modules/babel-plugin-jest-hoist/build/index.d.ts b/node_modules/babel-plugin-jest-hoist/build/index.d.ts new file mode 100644 index 0000000..007cc55 --- /dev/null +++ b/node_modules/babel-plugin-jest-hoist/build/index.d.ts @@ -0,0 +1,13 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ +import type { PluginObj } from '@babel/core'; +import { Identifier } from '@babel/types'; +export default function jestHoist(): PluginObj<{ + declareJestObjGetterIdentifier: () => Identifier; + jestObjGetterIdentifier?: Identifier; +}>; diff --git a/node_modules/babel-plugin-jest-hoist/build/index.js b/node_modules/babel-plugin-jest-hoist/build/index.js new file mode 100644 index 0000000..d8b74e5 --- /dev/null +++ b/node_modules/babel-plugin-jest-hoist/build/index.js @@ -0,0 +1,389 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); +exports.default = jestHoist; + +function _template() { + const data = require('@babel/template'); + + _template = function () { + return data; + }; + + return data; +} + +function _types() { + const data = require('@babel/types'); + + _types = function () { + return data; + }; + + return data; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ +const JEST_GLOBAL_NAME = 'jest'; +const JEST_GLOBALS_MODULE_NAME = '@jest/globals'; +const JEST_GLOBALS_MODULE_JEST_EXPORT_NAME = 'jest'; +const hoistedVariables = new WeakSet(); // We allow `jest`, `expect`, `require`, all default Node.js globals and all +// ES2015 built-ins to be used inside of a `jest.mock` factory. +// We also allow variables prefixed with `mock` as an escape-hatch. + +const ALLOWED_IDENTIFIERS = new Set( + [ + 'Array', + 'ArrayBuffer', + 'Boolean', + 'BigInt', + 'DataView', + 'Date', + 'Error', + 'EvalError', + 'Float32Array', + 'Float64Array', + 'Function', + 'Generator', + 'GeneratorFunction', + 'Infinity', + 'Int16Array', + 'Int32Array', + 'Int8Array', + 'InternalError', + 'Intl', + 'JSON', + 'Map', + 'Math', + 'NaN', + 'Number', + 'Object', + 'Promise', + 'Proxy', + 'RangeError', + 'ReferenceError', + 'Reflect', + 'RegExp', + 'Set', + 'String', + 'Symbol', + 'SyntaxError', + 'TypeError', + 'URIError', + 'Uint16Array', + 'Uint32Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'WeakMap', + 'WeakSet', + 'arguments', + 'console', + 'expect', + 'isNaN', + 'jest', + 'parseFloat', + 'parseInt', + 'exports', + 'require', + 'module', + '__filename', + '__dirname', + 'undefined', + ...Object.getOwnPropertyNames(global) + ].sort() +); +const IDVisitor = { + ReferencedIdentifier(path, {ids}) { + ids.add(path); + }, + + blacklist: ['TypeAnnotation', 'TSTypeAnnotation', 'TSTypeReference'] +}; +const FUNCTIONS = Object.create(null); + +FUNCTIONS.mock = args => { + if (args.length === 1) { + return args[0].isStringLiteral() || args[0].isLiteral(); + } else if (args.length === 2 || args.length === 3) { + const moduleFactory = args[1]; + + if (!moduleFactory.isFunction()) { + throw moduleFactory.buildCodeFrameError( + 'The second argument of `jest.mock` must be an inline function.\n', + TypeError + ); + } + + const ids = new Set(); + const parentScope = moduleFactory.parentPath.scope; // @ts-expect-error: ReferencedIdentifier and blacklist are not known on visitors + + moduleFactory.traverse(IDVisitor, { + ids + }); + + for (const id of ids) { + const {name} = id.node; + let found = false; + let scope = id.scope; + + while (scope !== parentScope) { + if (scope.bindings[name]) { + found = true; + break; + } + + scope = scope.parent; + } + + if (!found) { + let isAllowedIdentifier = + (scope.hasGlobal(name) && ALLOWED_IDENTIFIERS.has(name)) || + /^mock/i.test(name) || // Allow istanbul's coverage variable to pass. + /^(?:__)?cov/.test(name); + + if (!isAllowedIdentifier) { + const binding = scope.bindings[name]; + + if ( + binding !== null && + binding !== void 0 && + binding.path.isVariableDeclarator() + ) { + const {node} = binding.path; + const initNode = node.init; + + if (initNode && binding.constant && scope.isPure(initNode, true)) { + hoistedVariables.add(node); + isAllowedIdentifier = true; + } + } + } + + if (!isAllowedIdentifier) { + throw id.buildCodeFrameError( + 'The module factory of `jest.mock()` is not allowed to ' + + 'reference any out-of-scope variables.\n' + + 'Invalid variable access: ' + + name + + '\n' + + 'Allowed objects: ' + + Array.from(ALLOWED_IDENTIFIERS).join(', ') + + '.\n' + + 'Note: This is a precaution to guard against uninitialized mock ' + + 'variables. If it is ensured that the mock is required lazily, ' + + 'variable names prefixed with `mock` (case insensitive) are permitted.\n', + ReferenceError + ); + } + } + } + + return true; + } + + return false; +}; + +FUNCTIONS.unmock = args => args.length === 1 && args[0].isStringLiteral(); + +FUNCTIONS.deepUnmock = args => args.length === 1 && args[0].isStringLiteral(); + +FUNCTIONS.disableAutomock = FUNCTIONS.enableAutomock = args => + args.length === 0; + +const createJestObjectGetter = (0, _template().statement)` +function GETTER_NAME() { + const { JEST_GLOBALS_MODULE_JEST_EXPORT_NAME } = require("JEST_GLOBALS_MODULE_NAME"); + GETTER_NAME = () => JEST_GLOBALS_MODULE_JEST_EXPORT_NAME; + return JEST_GLOBALS_MODULE_JEST_EXPORT_NAME; +} +`; + +const isJestObject = expression => { + // global + if ( + expression.isIdentifier() && + expression.node.name === JEST_GLOBAL_NAME && + !expression.scope.hasBinding(JEST_GLOBAL_NAME) + ) { + return true; + } // import { jest } from '@jest/globals' + + if ( + expression.referencesImport( + JEST_GLOBALS_MODULE_NAME, + JEST_GLOBALS_MODULE_JEST_EXPORT_NAME + ) + ) { + return true; + } // import * as JestGlobals from '@jest/globals' + + if ( + expression.isMemberExpression() && + !expression.node.computed && + expression.get('object').referencesImport(JEST_GLOBALS_MODULE_NAME, '*') && + expression.node.property.type === 'Identifier' && + expression.node.property.name === JEST_GLOBALS_MODULE_JEST_EXPORT_NAME + ) { + return true; + } + + return false; +}; + +const extractJestObjExprIfHoistable = expr => { + var _FUNCTIONS$propertyNa; + + if (!expr.isCallExpression()) { + return null; + } + + const callee = expr.get('callee'); + const args = expr.get('arguments'); + + if (!callee.isMemberExpression() || callee.node.computed) { + return null; + } + + const object = callee.get('object'); + const property = callee.get('property'); + const propertyName = property.node.name; + const jestObjExpr = isJestObject(object) + ? object // The Jest object could be returned from another call since the functions are all chainable. + : extractJestObjExprIfHoistable(object); + + if (!jestObjExpr) { + return null; + } // Important: Call the function check last + // It might throw an error to display to the user, + // which should only happen if we're already sure it's a call on the Jest object. + + const functionLooksHoistable = + (_FUNCTIONS$propertyNa = FUNCTIONS[propertyName]) === null || + _FUNCTIONS$propertyNa === void 0 + ? void 0 + : _FUNCTIONS$propertyNa.call(FUNCTIONS, args); + return functionLooksHoistable ? jestObjExpr : null; +}; +/* eslint-disable sort-keys */ + +function jestHoist() { + return { + pre({path: program}) { + this.declareJestObjGetterIdentifier = () => { + if (this.jestObjGetterIdentifier) { + return this.jestObjGetterIdentifier; + } + + this.jestObjGetterIdentifier = + program.scope.generateUidIdentifier('getJestObj'); + program.unshiftContainer('body', [ + createJestObjectGetter({ + GETTER_NAME: this.jestObjGetterIdentifier.name, + JEST_GLOBALS_MODULE_JEST_EXPORT_NAME, + JEST_GLOBALS_MODULE_NAME + }) + ]); + return this.jestObjGetterIdentifier; + }; + }, + + visitor: { + ExpressionStatement(exprStmt) { + const jestObjExpr = extractJestObjExprIfHoistable( + exprStmt.get('expression') + ); + + if (jestObjExpr) { + jestObjExpr.replaceWith( + (0, _types().callExpression)( + this.declareJestObjGetterIdentifier(), + [] + ) + ); + } + } + }, + + // in `post` to make sure we come after an import transform and can unshift above the `require`s + post({path: program}) { + const self = this; + visitBlock(program); + program.traverse({ + BlockStatement: visitBlock + }); + + function visitBlock(block) { + // use a temporary empty statement instead of the real first statement, which may itself be hoisted + const [varsHoistPoint, callsHoistPoint] = block.unshiftContainer( + 'body', + [(0, _types().emptyStatement)(), (0, _types().emptyStatement)()] + ); + block.traverse({ + CallExpression: visitCallExpr, + VariableDeclarator: visitVariableDeclarator, + // do not traverse into nested blocks, or we'll hoist calls in there out to this block + blacklist: ['BlockStatement'] + }); + callsHoistPoint.remove(); + varsHoistPoint.remove(); + + function visitCallExpr(callExpr) { + var _self$jestObjGetterId; + + const { + node: {callee} + } = callExpr; + + if ( + (0, _types().isIdentifier)(callee) && + callee.name === + ((_self$jestObjGetterId = self.jestObjGetterIdentifier) === + null || _self$jestObjGetterId === void 0 + ? void 0 + : _self$jestObjGetterId.name) + ) { + const mockStmt = callExpr.getStatementParent(); + + if (mockStmt) { + const mockStmtParent = mockStmt.parentPath; + + if (mockStmtParent.isBlock()) { + const mockStmtNode = mockStmt.node; + mockStmt.remove(); + callsHoistPoint.insertBefore(mockStmtNode); + } + } + } + } + + function visitVariableDeclarator(varDecl) { + if (hoistedVariables.has(varDecl.node)) { + // should be assert function, but it's not. So let's cast below + varDecl.parentPath.assertVariableDeclaration(); + const {kind, declarations} = varDecl.parent; + + if (declarations.length === 1) { + varDecl.parentPath.remove(); + } else { + varDecl.remove(); + } + + varsHoistPoint.insertBefore( + (0, _types().variableDeclaration)(kind, [varDecl.node]) + ); + } + } + } + } + }; +} +/* eslint-enable */ diff --git a/node_modules/babel-plugin-jest-hoist/package.json b/node_modules/babel-plugin-jest-hoist/package.json new file mode 100644 index 0000000..2d45b7b --- /dev/null +++ b/node_modules/babel-plugin-jest-hoist/package.json @@ -0,0 +1,41 @@ +{ + "name": "babel-plugin-jest-hoist", + "version": "27.5.1", + "repository": { + "type": "git", + "url": "https://github.com/facebook/jest.git", + "directory": "packages/babel-plugin-jest-hoist" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "license": "MIT", + "main": "./build/index.js", + "types": "./build/index.d.ts", + "exports": { + ".": { + "types": "./build/index.d.ts", + "default": "./build/index.js" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "devDependencies": { + "@babel/core": "^7.11.6", + "@babel/preset-react": "^7.12.1", + "@types/babel__template": "^7.0.2", + "@types/node": "*", + "@types/prettier": "^2.0.0", + "babel-plugin-tester": "^10.0.0", + "prettier": "^2.1.1" + }, + "publishConfig": { + "access": "public" + }, + "gitHead": "67c1aa20c5fec31366d733e901fee2b981cb1850" +} |