diff --git a/src/transforms/v2-to-v3/modules/addTopLevelComments.ts b/src/transforms/v2-to-v3/modules/addTopLevelComments.ts new file mode 100644 index 000000000..a347c4510 --- /dev/null +++ b/src/transforms/v2-to-v3/modules/addTopLevelComments.ts @@ -0,0 +1,19 @@ +import { isDeepStrictEqual } from "util"; +import { CommentKind } from "ast-types/gen/kinds"; +import { Collection, JSCodeshift } from "jscodeshift"; + +export const addTopLevelComments = ( + j: JSCodeshift, + source: Collection, + comments?: CommentKind[] | null +) => { + if (!comments || comments.length === 0) { + return; + } + + const firstNode = source.find(j.Program).get("body", 0); + const newComments = firstNode.node.comments; + if (!isDeepStrictEqual(comments, newComments)) { + firstNode.insertBefore(j.emptyStatement.from({ comments })); + } +}; diff --git a/src/transforms/v2-to-v3/modules/getRequireDeclaratorsWithObjectPattern.ts b/src/transforms/v2-to-v3/modules/getRequireDeclaratorsWithObjectPattern.ts deleted file mode 100644 index 0eac500a8..000000000 --- a/src/transforms/v2-to-v3/modules/getRequireDeclaratorsWithObjectPattern.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Collection, JSCodeshift, ObjectProperty, Property } from "jscodeshift"; - -import { OBJECT_PROPERTY_TYPE_LIST } from "../config"; -import { getRequireDeclarators } from "./getRequireDeclarators"; - -export interface GetRequireDeclaratorsWithObjectPattern { - identifierName: string; - sourceValue: string; -} - -export const getRequireDeclaratorsWithObjectPattern = ( - j: JSCodeshift, - source: Collection, - { identifierName, sourceValue }: GetRequireDeclaratorsWithObjectPattern -) => - getRequireDeclarators(j, source, sourceValue).filter((declarator) => { - if (declarator.value.id.type !== "ObjectPattern") { - return false; - } - const { properties } = declarator.value.id; - return properties.some((property) => { - if (!OBJECT_PROPERTY_TYPE_LIST.includes(property.type)) return false; - const propertyValue = (property as Property | ObjectProperty).value; - return propertyValue.type === "Identifier" && propertyValue.name === identifierName; - }); - }); diff --git a/src/transforms/v2-to-v3/modules/getRequireObjectPatternProperty.ts b/src/transforms/v2-to-v3/modules/getRequireObjectPatternProperty.ts new file mode 100644 index 000000000..8e59e4968 --- /dev/null +++ b/src/transforms/v2-to-v3/modules/getRequireObjectPatternProperty.ts @@ -0,0 +1,47 @@ +import { Collection, JSCodeshift, Literal } from "jscodeshift"; +import { STRING_LITERAL_TYPE_LIST } from "../config"; + +export interface GetRequireObjectPatternPropertyOptions { + identifierName: string; + sourceValue: string; +} + +export const getRequireObjectPatternProperty = ( + j: JSCodeshift, + source: Collection, + { identifierName, sourceValue }: GetRequireObjectPatternPropertyOptions +) => { + const filter = { + key: { + type: "Identifier", + name: identifierName, + }, + value: { + type: "Identifier", + }, + } as const; + + const propertyCollection = source.find(j.Property, filter); + const objectPropertyCollection = source.find(j.ObjectProperty, filter); + const collection = propertyCollection.size() ? propertyCollection : objectPropertyCollection; + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore This expression is not callable. + return collection.filter((path) => { + const pathValueName = path.value.name; + if (pathValueName && pathValueName !== sourceValue) return false; + + const varDeclarator = j(path).closest(j.VariableDeclarator); + const init = varDeclarator.nodes()[0].init; + if (!init || init.type !== "CallExpression") return false; + + const initCallee = init.callee; + if (initCallee.type !== "Identifier" || initCallee.name !== "require") return false; + + const initArguments = init.arguments; + if (initArguments.length !== 1) return false; + const arg = initArguments[0]; + if (!STRING_LITERAL_TYPE_LIST.includes(arg.type)) return false; + return (arg as Literal).value === sourceValue; + }); +}; diff --git a/src/transforms/v2-to-v3/modules/removeRequireIdentifier.ts b/src/transforms/v2-to-v3/modules/removeRequireIdentifier.ts index a40513167..cdbdfbcc4 100644 --- a/src/transforms/v2-to-v3/modules/removeRequireIdentifier.ts +++ b/src/transforms/v2-to-v3/modules/removeRequireIdentifier.ts @@ -1,8 +1,7 @@ -import { Collection, Identifier, JSCodeshift, Literal, VariableDeclarator } from "jscodeshift"; +import { Collection, JSCodeshift } from "jscodeshift"; -import { STRING_LITERAL_TYPE_LIST } from "../config"; +import { addTopLevelComments } from "./addTopLevelComments"; import { getRequireDeclaratorsWithIdentifier } from "./getRequireDeclaratorsWithIdentifier"; -import { removeDeclaration } from "./removeDeclaration"; export interface RemoveRequireIdentifierOptions { localName: string; @@ -19,40 +18,7 @@ export const removeRequireIdentifier = ( sourceValue, }); - requireDeclarators.forEach((varDeclarator) => { - const varDeclaration = varDeclarator.parentPath.parentPath; - - // Removes variable declarator from the declarations. - varDeclaration.value.declarations = varDeclaration.value.declarations.filter( - (declaration: VariableDeclarator | Identifier) => { - if (declaration.type === "Identifier") return true; - - const id = declaration.id; - if (id.type !== "Identifier") return true; - if (id.name !== localName) return true; - - const init = declaration.init; - if (!init) return true; - if (init.type !== "CallExpression") return true; - - const callee = init.callee; - if (!callee) return true; - if (callee.type !== "Identifier") return true; - if (callee.name !== "require") return true; - - const args = init.arguments; - if (!args) return true; - if (args.length !== 1) return true; - if (!STRING_LITERAL_TYPE_LIST.includes(args[0].type)) return true; - if ((args[0] as Literal).value !== sourceValue) return true; - - return false; - } - ); - - // Remove VariableDeclaration if there are no declarations. - if (varDeclaration.value.declarations?.length === 0) { - removeDeclaration(j, source, varDeclaration); - } - }); + const comments = source.find(j.Program).get("body", 0).node.comments; + requireDeclarators.remove(); + addTopLevelComments(j, source, comments); }; diff --git a/src/transforms/v2-to-v3/modules/removeRequireObjectPattern.ts b/src/transforms/v2-to-v3/modules/removeRequireObjectPattern.ts index 631b6e92f..7e9009d1c 100644 --- a/src/transforms/v2-to-v3/modules/removeRequireObjectPattern.ts +++ b/src/transforms/v2-to-v3/modules/removeRequireObjectPattern.ts @@ -1,16 +1,7 @@ -import { - Collection, - Identifier, - JSCodeshift, - ObjectPattern, - ObjectProperty, - Property, - VariableDeclarator, -} from "jscodeshift"; +import { Collection, JSCodeshift } from "jscodeshift"; -import { OBJECT_PROPERTY_TYPE_LIST } from "../config"; -import { getRequireDeclaratorsWithObjectPattern } from "./getRequireDeclaratorsWithObjectPattern"; -import { removeDeclaration } from "./removeDeclaration"; +import { addTopLevelComments } from "./addTopLevelComments"; +import { getRequireObjectPatternProperty } from "./getRequireObjectPatternProperty"; export interface RemoveRequireObjectPropertyOptions { localName: string; @@ -22,31 +13,12 @@ export const removeRequireObjectPattern = ( source: Collection, { localName, sourceValue }: RemoveRequireObjectPropertyOptions ) => { - const requireDeclarators = getRequireDeclaratorsWithObjectPattern(j, source, { + const requireObjectPatternProperty = getRequireObjectPatternProperty(j, source, { identifierName: localName, sourceValue, }); - requireDeclarators.forEach((varDeclarator) => { - // Remove ObjectProperty from Variable Declarator. - const varDeclaratorId = varDeclarator.value.id as ObjectPattern; - varDeclaratorId.properties = varDeclaratorId.properties.filter((property) => { - if (!OBJECT_PROPERTY_TYPE_LIST.includes(property.type)) return true; - const propertyValue = (property as Property | ObjectProperty).value; - return propertyValue.type !== "Identifier" || propertyValue.name !== localName; - }); - - // Remove VariableDeclarator if there are no properties. - if (varDeclaratorId.properties.length === 0) { - const varDeclaration = varDeclarator.parentPath.parentPath; - varDeclaration.value.declarations = varDeclaration.value.declarations.filter( - (declaration: VariableDeclarator | Identifier) => declaration !== varDeclarator.value - ); - - // Remove VariableDeclaration if there are no declarations. - if (varDeclaration.value.declarations?.length === 0) { - removeDeclaration(j, source, varDeclaration); - } - } - }); + const comments = source.find(j.Program).get("body", 0).node.comments; + requireObjectPatternProperty.remove(); + addTopLevelComments(j, source, comments); };