Skip to content

Commit

Permalink
feat: add split-macro-imports codemod (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
timofei-iatsenko authored Jun 21, 2024
1 parent ec3f135 commit da2404f
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 1 deletion.
4 changes: 4 additions & 0 deletions bin/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ const TRANSFORMER_INQUIRER_CHOICES = [
name: "v2-to-v3: Migrates v2 standards to the new standards of @lingui v3.X.X",
value: "v2-to-v3",
},
{
name: "v5: Split @lingui/macro imports to specific packages @lingui/react/macro and @lingui/core/macro",
value: "split-macro-imports",
},
];

const PARSER_INQUIRER_CHOICES = [
Expand Down
72 changes: 72 additions & 0 deletions transforms/__tests__/split-macro-imports.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { defineInlineTest } from "jscodeshift/dist/testUtils";
import transformer from "../split-macro-imports";

describe("basic", () => {
defineInlineTest(
transformer,
{},
`
import {
// core
t,
plural,
selectOrdinal,
select,
defineMessage,
msg,
// react
Trans,
Plural,
SelectOrdinal,
Select,
useLingui,
} from "@lingui/macro";
`,
`
import { Trans, Plural, SelectOrdinal, Select, useLingui } from "@lingui/react/macro";
import { t, plural, selectOrdinal, select, defineMessage, msg } from "@lingui/core/macro";
`,
);
});

describe("Local identifiers are renamed", () => {
defineInlineTest(
transformer,
{},
`import { t as _t, Trans as _Trans } from '@lingui/macro';`,
`
import { Trans as _Trans } from "@lingui/react/macro";
import { t as _t } from "@lingui/core/macro";
`,
);
});

describe("Multiple imports", () => {
defineInlineTest(
transformer,
{},
`
import { t, Trans } from '@lingui/macro';
import { plural, Plural } from '@lingui/macro';
`,
`
import { Trans, Plural } from "@lingui/react/macro";
import { t, plural } from "@lingui/core/macro";
`,
);
});

describe("Existing imports", () => {
defineInlineTest(
transformer,
{},
`
import { useLingui } from '@lingui/react/macro';
import { t, Trans } from '@lingui/macro';
`,
`
import { t } from "@lingui/core/macro";
import { useLingui, Trans } from '@lingui/react/macro';
`,
);
});
2 changes: 1 addition & 1 deletion transforms/__tests__/v2-to-v3.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineTest } from "jscodeshift/dist/testUtils";
import { defineTest, defineInlineTest } from "jscodeshift/dist/testUtils";

describe("Plural props changed from an object, to a (value, object)", () => {
defineTest(__dirname, "v2-to-v3", null, "v2-to-v3/plural");
Expand Down
92 changes: 92 additions & 0 deletions transforms/split-macro-imports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { API, FileInfo, JSCodeshift, ImportSpecifier } from "jscodeshift";

// Define the sets of symbols for each new package
const coreMacroSymbols = new Set([
"ChoiceOptions",
"t",
"plural",
"selectOrdinal",
"select",
"defineMessage",
"msg",
]);

const reactMacroSymbols = new Set([
"Trans",
"Plural",
"SelectOrdinal",
"Select",
"useLingui",
]);

// Helper function to determine the new package for a symbol
const getNewPackageForSymbol = (symbol: string): string | null => {
if (coreMacroSymbols.has(symbol)) return "@lingui/core/macro";
if (reactMacroSymbols.has(symbol)) return "@lingui/react/macro";
return null;
};

// Helper function to add or amend an import specifier
const addOrAmendImport = (
j: JSCodeshift,
root: ReturnType<typeof j>,
packageName: string,
specifier: ImportSpecifier,
) => {
const existingImport = root.find(j.ImportDeclaration, {
source: { value: packageName },
});

if (existingImport.size() === 0) {
root
.get()
.node.program.body.unshift(
j.importDeclaration([specifier], j.literal(packageName)),
);
} else {
existingImport.get().node.specifiers.push(specifier);
}
};

export default function transformer(file: FileInfo, api: API) {
const j = api.jscodeshift;
const root = j(file.source);

// Find existing imports from '@lingui/macro'
const importedDeclarations = root.find(j.ImportDeclaration, {
source: { value: "@lingui/macro" },
});

if (importedDeclarations.size() === 0) {
return file.source; // No changes needed if there's no import from '@lingui/macro'
}

// Process each import declaration
importedDeclarations.forEach((path) => {
const importDecl = path.value;

if (importDecl.specifiers && importDecl.specifiers.length) {
importDecl.specifiers.forEach((specifier) => {
if (specifier.type === "ImportSpecifier") {
const importedName = specifier.imported.name;
const localName = specifier.local.name;
const newPackage = getNewPackageForSymbol(importedName);

if (newPackage) {
// Create a new import specifier with the local name
const newSpecifier = j.importSpecifier(
j.identifier(importedName),
j.identifier(localName),
);
addOrAmendImport(j, root, newPackage, newSpecifier);
}
}
});
}
});

// Remove the old import declaration
importedDeclarations.remove();

return root.toSource();
}

0 comments on commit da2404f

Please sign in to comment.