From 89eaa8082f4b1b940649f82694af37a5b014a3db Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Tue, 10 Dec 2024 05:45:54 +0800 Subject: [PATCH 1/6] improve --- packages/babel-plugin-jest-hoist/src/index.ts | 96 +++++++++---------- 1 file changed, 43 insertions(+), 53 deletions(-) diff --git a/packages/babel-plugin-jest-hoist/src/index.ts b/packages/babel-plugin-jest-hoist/src/index.ts index 381fdad2560e..5f237d5a9960 100644 --- a/packages/babel-plugin-jest-hoist/src/index.ts +++ b/packages/babel-plugin-jest-hoist/src/index.ts @@ -10,20 +10,17 @@ import type {PluginObj} from '@babel/core'; import {statement} from '@babel/template'; import type {NodePath} from '@babel/traverse'; import { - type BlockStatement, + type Statement, type CallExpression, - type EmptyStatement, type Expression, type Identifier, type ImportDeclaration, type MemberExpression, type Node, - type Program, type Super, type VariableDeclaration, type VariableDeclarator, callExpression, - emptyStatement, isIdentifier, variableDeclaration, } from '@babel/types'; @@ -312,53 +309,6 @@ const extractJestObjExprIfHoistable = (expr: NodePath): JestObjInfo | null => { return null; }; -function visitBlock(block: NodePath | NodePath) { - // use a temporary empty statement instead of the real first statement, which may itself be hoisted - const [varsHoistPoint, callsHoistPoint] = block.unshiftContainer< - BlockStatement | Program, - 'body', - [EmptyStatement, EmptyStatement] - >('body', [emptyStatement(), emptyStatement()]); - block.traverse({ - CallExpression: visitCallExpr, - VariableDeclarator: visitVariableDeclarator, - // do not traverse into nested blocks, or we'll hoist calls in there out to this block - denylist: ['BlockStatement'], - }); - callsHoistPoint.remove(); - varsHoistPoint.remove(); - - function visitCallExpr(callExpr: NodePath) { - if (hoistedJestGetters.has(callExpr.node)) { - 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: NodePath) { - 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 as VariableDeclaration; - if (declarations.length === 1) { - varDecl.parentPath.remove(); - } else { - varDecl.remove(); - } - varsHoistPoint.insertBefore(variableDeclaration(kind, [varDecl.node])); - } - } -} - /* eslint-disable sort-keys */ export default function jestHoist(): PluginObj<{ declareJestObjGetterIdentifier: () => Identifier; @@ -404,8 +354,48 @@ export default function jestHoist(): PluginObj<{ }, // in `post` to make sure we come after an import transform and can unshift above the `require`s post({path: program}) { - visitBlock(program); - program.traverse({BlockStatement: visitBlock}); + type Item = {calls: Statement[]; vars: Statement[]}; + + const stack: Item[] = [{calls: [], vars: []}]; + program.traverse({ + BlockStatement: { + enter() { + stack.push({calls: [], vars: []}); + }, + exit(path) { + const item = stack.pop()!; + path.node.body.unshift(...item.vars, ...item.calls); + }, + }, + CallExpression(callExpr: NodePath) { + if (hoistedJestGetters.has(callExpr.node)) { + const mockStmt = callExpr.getStatementParent(); + + if (mockStmt?.parentPath.isBlock()) { + stack[stack.length - 1].calls.push(mockStmt.node); + mockStmt.remove(); + } + } + }, + VariableDeclarator(varDecl: NodePath) { + 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 as VariableDeclaration; + if (declarations.length === 1) { + varDecl.parentPath.remove(); + } else { + varDecl.remove(); + } + stack[stack.length - 1].vars.push( + variableDeclaration(kind, [varDecl.node]), + ); + } + }, + }); + const item = stack.pop()!; + program.node.body.unshift(...item.vars, ...item.calls); }, }; } From 0fbec6ac81a1125852b756f5ae7bc2e0b6ed2a08 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Tue, 10 Dec 2024 05:54:13 +0800 Subject: [PATCH 2/6] fix lint --- packages/babel-plugin-jest-hoist/src/index.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/babel-plugin-jest-hoist/src/index.ts b/packages/babel-plugin-jest-hoist/src/index.ts index 5f237d5a9960..c59632ce9e63 100644 --- a/packages/babel-plugin-jest-hoist/src/index.ts +++ b/packages/babel-plugin-jest-hoist/src/index.ts @@ -10,13 +10,13 @@ import type {PluginObj} from '@babel/core'; import {statement} from '@babel/template'; import type {NodePath} from '@babel/traverse'; import { - type Statement, type CallExpression, type Expression, type Identifier, type ImportDeclaration, type MemberExpression, type Node, + type Statement, type Super, type VariableDeclaration, type VariableDeclarator, @@ -354,9 +354,9 @@ export default function jestHoist(): PluginObj<{ }, // in `post` to make sure we come after an import transform and can unshift above the `require`s post({path: program}) { - type Item = {calls: Statement[]; vars: Statement[]}; + type Item = {calls: Array; vars: Array}; - const stack: Item[] = [{calls: [], vars: []}]; + const stack: Array = [{calls: [], vars: []}]; program.traverse({ BlockStatement: { enter() { @@ -372,7 +372,7 @@ export default function jestHoist(): PluginObj<{ const mockStmt = callExpr.getStatementParent(); if (mockStmt?.parentPath.isBlock()) { - stack[stack.length - 1].calls.push(mockStmt.node); + stack.at(-1)!.calls.push(mockStmt.node); mockStmt.remove(); } } @@ -388,9 +388,7 @@ export default function jestHoist(): PluginObj<{ } else { varDecl.remove(); } - stack[stack.length - 1].vars.push( - variableDeclaration(kind, [varDecl.node]), - ); + stack.at(-1)!.vars.push(variableDeclaration(kind, [varDecl.node])); } }, }); From e4191126fc3971efafd2964342524903fcc487ad Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:33:23 +0800 Subject: [PATCH 3/6] fix lint --- packages/babel-plugin-jest-hoist/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/babel-plugin-jest-hoist/src/index.ts b/packages/babel-plugin-jest-hoist/src/index.ts index c59632ce9e63..cb647127af23 100644 --- a/packages/babel-plugin-jest-hoist/src/index.ts +++ b/packages/babel-plugin-jest-hoist/src/index.ts @@ -371,6 +371,7 @@ export default function jestHoist(): PluginObj<{ if (hoistedJestGetters.has(callExpr.node)) { const mockStmt = callExpr.getStatementParent(); + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (mockStmt?.parentPath.isBlock()) { stack.at(-1)!.calls.push(mockStmt.node); mockStmt.remove(); From bfc707341cb09756975a1440bc9c02fe7fec584d Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 10 Dec 2024 09:55:33 +0100 Subject: [PATCH 4/6] Update packages/babel-plugin-jest-hoist/src/index.ts --- packages/babel-plugin-jest-hoist/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/babel-plugin-jest-hoist/src/index.ts b/packages/babel-plugin-jest-hoist/src/index.ts index cb647127af23..c59632ce9e63 100644 --- a/packages/babel-plugin-jest-hoist/src/index.ts +++ b/packages/babel-plugin-jest-hoist/src/index.ts @@ -371,7 +371,6 @@ export default function jestHoist(): PluginObj<{ if (hoistedJestGetters.has(callExpr.node)) { const mockStmt = callExpr.getStatementParent(); - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (mockStmt?.parentPath.isBlock()) { stack.at(-1)!.calls.push(mockStmt.node); mockStmt.remove(); From 11c09cd12a954af5eb0e0b89396041bb72235246 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 10 Dec 2024 09:57:34 +0100 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 363abee8a97e..cd34d1360be7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ ### Fixes - `[babel-plugin-jest-hoist]` Use `denylist` instead of the deprecated `blacklist` for Babel 8 support ([#14109](https://github.com/jestjs/jest/pull/14109)) +- `[babel-plugin-jest-hoist]` Do not rely on buggy Babel behaviour ([#15415](https://github.com/jestjs/jest/pull/15415)) - `[expect]` Check error instance type for `toThrow/toThrowError` ([#14576](https://github.com/jestjs/jest/pull/14576)) - `[expect]` Improve diff for failing `expect.objectContaining` ([#15038](https://github.com/jestjs/jest/pull/15038)) - `[expect]` Use `Array.isArray` to check if an array is an `Array` ([#15101](https://github.com/jestjs/jest/pull/15101)) From cc71fe4afe049801e1a6b424a8b1cffe1c241531 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 10 Dec 2024 11:17:12 +0100 Subject: [PATCH 6/6] avoid lint error --- packages/babel-plugin-jest-hoist/src/index.ts | 2 +- scripts/lintTs.mjs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/babel-plugin-jest-hoist/src/index.ts b/packages/babel-plugin-jest-hoist/src/index.ts index c59632ce9e63..2885e386ac57 100644 --- a/packages/babel-plugin-jest-hoist/src/index.ts +++ b/packages/babel-plugin-jest-hoist/src/index.ts @@ -371,7 +371,7 @@ export default function jestHoist(): PluginObj<{ if (hoistedJestGetters.has(callExpr.node)) { const mockStmt = callExpr.getStatementParent(); - if (mockStmt?.parentPath.isBlock()) { + if (mockStmt && mockStmt.parentPath.isBlock()) { stack.at(-1)!.calls.push(mockStmt.node); mockStmt.remove(); } diff --git a/scripts/lintTs.mjs b/scripts/lintTs.mjs index 5f92e8380c9e..01c4d353a74d 100644 --- a/scripts/lintTs.mjs +++ b/scripts/lintTs.mjs @@ -111,6 +111,12 @@ try { '@typescript-eslint/no-redundant-type-constituents': 'off', }, }, + // { + // files: ['packages/babel-plugin-jest-hoist/src/index.ts'], + // rules: { + // '@typescript-eslint/strict-boolean-expressions': 'off', + // }, + // }, ], parser: '@typescript-eslint/parser', parserOptions: {