diff --git a/transforms/__testfixtures__/v2-to-v3/changeReactImportNewImports.input.js b/transforms/__testfixtures__/v2-to-v3/changeReactImportNewImports.input.js new file mode 100644 index 0000000..ada4271 --- /dev/null +++ b/transforms/__testfixtures__/v2-to-v3/changeReactImportNewImports.input.js @@ -0,0 +1,2 @@ +import { React } from "react"; +import { Trans, withI18n } from "@lingui/react"; \ No newline at end of file diff --git a/transforms/__testfixtures__/v2-to-v3/changeReactImportNewImports.output.js b/transforms/__testfixtures__/v2-to-v3/changeReactImportNewImports.output.js new file mode 100644 index 0000000..a481641 --- /dev/null +++ b/transforms/__testfixtures__/v2-to-v3/changeReactImportNewImports.output.js @@ -0,0 +1,3 @@ +import { React } from "react"; +import { withI18n } from "@lingui/react"; +import { Trans } from "@lingui/macro"; \ No newline at end of file diff --git a/transforms/__testfixtures__/v2-to-v3/macroWrap.input.js b/transforms/__testfixtures__/v2-to-v3/macroWrap.input.js new file mode 100644 index 0000000..25441ad --- /dev/null +++ b/transforms/__testfixtures__/v2-to-v3/macroWrap.input.js @@ -0,0 +1,4 @@ +import { i18n } from "@lingui/core"; +import { t } from "@lingui/macro"; + +i18n._(t`Some input`) \ No newline at end of file diff --git a/transforms/__testfixtures__/v2-to-v3/macroWrap.output.js b/transforms/__testfixtures__/v2-to-v3/macroWrap.output.js new file mode 100644 index 0000000..ce1a8a3 --- /dev/null +++ b/transforms/__testfixtures__/v2-to-v3/macroWrap.output.js @@ -0,0 +1,4 @@ +import { i18n } from "@lingui/core"; +import { t } from "@lingui/macro"; + +t`Some input` \ No newline at end of file diff --git a/transforms/__tests__/v2-to-v3.test.ts b/transforms/__tests__/v2-to-v3.test.ts index 7be85b4..5f467cb 100644 --- a/transforms/__tests__/v2-to-v3.test.ts +++ b/transforms/__tests__/v2-to-v3.test.ts @@ -16,4 +16,23 @@ describe("i18nProvider transform", () => { null, "v2-to-v3/i18nProvider", ); +}); + +describe("Deprecated methods inside @lingui/react moved to @core and @macro transform imports", () => { + defineTest( + __dirname, + "v2-to-v3", + null, + "v2-to-v3/changeReactImportNewImports", + ); +}); + + +describe("i18n._(t``) is not required, use intead simply t``", () => { + defineTest( + __dirname, + "v2-to-v3", + null, + "v2-to-v3/macroWrap", + ); }); \ No newline at end of file diff --git a/transforms/v2-to-v3.ts b/transforms/v2-to-v3.ts index d44ddd9..486a6d1 100644 --- a/transforms/v2-to-v3.ts +++ b/transforms/v2-to-v3.ts @@ -1,4 +1,4 @@ -import { Transform } from "jscodeshift"; +import { Transform, JSCodeshift, Collection } from "jscodeshift"; const transform: Transform = (fileInfo, api) => { const j = api.jscodeshift; @@ -6,10 +6,10 @@ const transform: Transform = (fileInfo, api) => { renameDefaultRenderToDefaultComponent(root, j) pluralPropsChanges(root, j) - // changeReactImportToMacro(root, j) + changeReactImportToNewImports(root, j) + removeMacroWrap(root, j) // changeToCoreDeprecatedFuncs(root) // replaceDeprecatedMethodsToMacros(root) - // removeMacroWrap(root) return root.toSource(); }; @@ -20,13 +20,72 @@ export default transform; * NumberFormat and DateFormat components were removed. * Use date and number formats from @lingui/core package instead. */ -function changeToCoreDeprecatedFuncs(root) { +function changeToCoreDeprecatedFuncs(root: Collection , j: JSCodeshift) { } /** * Change import of components to macro from react package + * - Trans -> Trans to `@lingui/@macro` + * - NumberFormat -> number to `@lingui/@core` + * - DateFormat -> date to `@lingui/@core` */ -function changeReactImportToMacro(root, j) { +function changeReactImportToNewImports(root: Collection , j: JSCodeshift) { + const linguiReactImports = root.find(j.ImportDeclaration, { + source: { + value: "@lingui/react" + } + }); + + migrateTo(root, linguiReactImports, j, "Trans", "Trans", "@lingui/macro"); + migrateTo(root, linguiReactImports, j, "NumberFormat", "number", "@lingui/core"); + migrateTo(root, linguiReactImports, j, "DateFormat", "date", "@lingui/core"); +} + +/** + * Function to migrate deprecated imports + * @param root Collection + * @param linguiReactImports all `@lingui/react` imports + * @param j JSCodeshift + * @param lookupImport old import name, for ex: "Plural" + * @param newLookupImport new import name, for ex: "plural" + * @param newPackageName package to move the import, for ex: `"@lingui/macro"` + * This example will result in + * - import { Plural } from `"@lingui/react"` + * + import { plural } from `"@lingui/macro"` + */ +function migrateTo(root, linguiReactImports, j, lookupImport, newLookupImport, newPackageName) { + const imports = root.find(j.ImportDeclaration, { + source: { + value: newPackageName + } + }); + linguiReactImports.forEach((path) => { + const node = path.value; + const transImportIndex = node.specifiers.findIndex((el) => el.imported.name === lookupImport); + + if (transImportIndex !== -1) { + // if trans import is not imported we ignore so, beucase isn't not used + if (node.specifiers.length > 1) { + // if trans is imported we have to remove it from here and add it to @lingui/macro import + node.specifiers.splice(transImportIndex, 1); + } else { + linguiReactImports.remove(); + } + + // we check if the lingui macro import is already present, because if it's already present we just have to push to that import + if (imports.paths().length > 0) { + imports.forEach((path) => { + path.value.specifiers.push(j.importSpecifier(j.identifier(newLookupImport))); + }); + } else { + linguiReactImports.insertAfter( + j.importDeclaration([j.importSpecifier(j.identifier(newLookupImport))], j.stringLiteral(newPackageName), "value") + ); + } + } + }); + + return root; } /** @@ -55,13 +114,13 @@ function pluralPropsChanges(root, j) { * i18n.t(), i18n.plural(), i18n.select() and i18n.selectOrdinal() * methods are removed and replaced with macros. */ -function replaceDeprecatedMethodsToMacros(root) { +function replaceDeprecatedMethodsToMacros(root , j: JSCodeshift) { } /** * Rename I18nProvider.defaultRender prop to I18nProvider.defaultComponent */ -function renameDefaultRenderToDefaultComponent(root, j) { +function renameDefaultRenderToDefaultComponent(root , j: JSCodeshift) { return root.find(j.JSXElement, { openingElement: { name: { name: "I18nProvider" } } }).forEach(path => { @@ -78,6 +137,27 @@ function renameDefaultRenderToDefaultComponent(root, j) { /** * Macros don't need to be wrapped inside i18n._: i18n._(t'Message') => t'Message' */ -function removeMacroWrap(root) { - +function removeMacroWrap(root , j: JSCodeshift) { + return root + .find(j.CallExpression, { + arguments: [ + { + tag: { + name: "t" + } + } + ], + callee: { + object: { + name: "i18n" + }, + property: { + name: "_" + } + } + }) + .replaceWith((nodePath) => { + const { node } = nodePath; + return node.arguments; + }) } \ No newline at end of file