Skip to content

[Migration]: box -> boxNew #3669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e0f8e98
:construction: box migration scaffolding
JulianNymark Mar 17, 2025
1e4db81
Merge branch 'main' into darkside-migration-box
JulianNymark Mar 18, 2025
0cd7ed0
Merge branch 'main' into darkside-migration-box
JulianNymark Mar 18, 2025
59067ec
Merge branch 'main' into darkside-migration-box
JulianNymark Mar 24, 2025
fe7ff7d
:truck: boxnew -> darkside/boxnew
JulianNymark Mar 24, 2025
e94e708
:construction: wip
JulianNymark Mar 24, 2025
b81632e
:construction: working single substitution (pending lookup in replace…
JulianNymark Mar 24, 2025
026edff
:white_check_mark: working test
JulianNymark Mar 24, 2025
c1753f4
import rename in output test
JulianNymark Mar 24, 2025
88d9712
:white_check_mark: import rename + tests
JulianNymark Mar 25, 2025
db46476
use config comments, better import example
JulianNymark Mar 25, 2025
88f249c
commentblock function (append to string output) + update tests (failing)
JulianNymark Mar 27, 2025
9ecc6f3
:construction: almost good... needs to respect renamed imports
JulianNymark Mar 27, 2025
80e59b9
:white_check_mark: passing tests
JulianNymark Mar 27, 2025
0baee9d
:recycle: organize some utils
JulianNymark Mar 27, 2025
de8e38f
Merge branch 'main' into darkside-migration-box
JulianNymark Mar 27, 2025
ff30601
:test_tube: Added more tests
KenAJoh Mar 31, 2025
d54821d
Merge branch 'main' into darkside-migration-box
JulianNymark Mar 31, 2025
4f7b7b2
cast JSXIdentifier type
JulianNymark Mar 31, 2025
248f627
pass idempotency tests
JulianNymark Mar 31, 2025
552e7fb
also refactor the usage when renaming a function
JulianNymark Mar 31, 2025
1d119bd
Merge branch 'main' into darkside-migration-box
JulianNymark Mar 31, 2025
ceb7334
Update @navikt/aksel/src/codemod/migrations.ts
JulianNymark Apr 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions @navikt/aksel/src/codemod/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ export const migrations: {
value: "prop-deprecate",
path: "darkside/prop-deprecate/prop-deprecate",
},
{
description:
"Update Box to to BoxNew (future Box) using the new token system",
value: "box-to-boxnew",
path: "darkside/box-to-boxnew/box-to-boxnew",
warning: "Remember to check if 'aksel box migration'-comment were added to any files after migration. This comment will help you find and update Box-instances where we could not resolve the update for you.",
},
],
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import type { API, FileInfo, JSCodeshift, JSXIdentifier } from "jscodeshift";
import { legacyTokenConfig } from "../../../../darkside/config/legacy.tokens";
import {
findComponentImport,
findJSXElement,
findProps,
} from "../../../utils/ast";
import { getLineTerminator } from "../../../utils/lineterminator";
import moveAndRenameImport, {
addPackageImport,
} from "../../../utils/packageImports";

const propsAffected = ["background", "borderColor", "shadow"];

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

const toSourceOptions = getLineTerminator(file.source);

if (file.source.includes("TODO: aksel box migration")) {
return root.toSource(toSourceOptions);
}

const localName = findComponentImport({
root,
j,
name: "Box",
packageType: "react",
});

if (!localName) {
return;
}

const astElements = root.find(j.JSXElement, {
openingElement: {
name: {
type: "JSXIdentifier",
name: localName,
},
},
});

const tokenComments: TokenComments = [];

for (const astElement of astElements.paths()) {
let encounteredUnmigratableProp = false;
for (const prop of propsAffected) {
findProps({ j, path: astElement, name: prop }).forEach((attr) => {
const attrvalue = attr.value.value;
if (attrvalue.type === "StringLiteral") {
const config = legacyTokenConfig[attrvalue.value];
if (config?.replacement) {
attrvalue.value = config.replacement;
} else {
encounteredUnmigratableProp = true;
const tokenComment: TokenComment = {
prop,
token: attrvalue.value,
};
if (config?.comment) {
tokenComment.comment = config.comment;
}
tokenComments.push(tokenComment);
}
}
});
}
if (!encounteredUnmigratableProp) {
// TODO: ?? Box -> BoxNew type fail? (but works)
(astElement.node.openingElement.name as JSXIdentifier).name = "BoxNew";
(astElement.node.closingElement.name as JSXIdentifier).name = "BoxNew";
}
}

const blockComment = createFileComments({ tokenComments });

const importAnalysis = analyzePartialMigration(
j,
root.toSource(toSourceOptions),
);

if (importAnalysis === "no new") {
// WHY: we do nothing to the import statements if we couldn't migrate any Box
}

if (importAnalysis === "mixed") {
// WHY: mixed Box and BoxNew == we keep old, and add the new import
addPackageImport({
j,
root,
packageName: "@navikt/ds-react/Box",
specifiers: ["BoxNew"],
});
}

if (importAnalysis === "all new") {
// WHY: when we have only new boxes == we replace the old import with the new one
moveAndRenameImport(j, root, {
fromImport: "@navikt/ds-react",
toImport: "@navikt/ds-react/Box",
fromName: "Box",
toName: "BoxNew",
ignoreAlias: localName !== "Box",
});
}

const output = `${blockComment ? blockComment + "\n\n" : ""}${root.toSource(
toSourceOptions,
)}`;

return output;
}

type TokenComment = {
prop: string;
token: string;
comment?: string;
};

type TokenComments = TokenComment[];

const createFileComments = ({
tokenComments,
}: {
tokenComments: TokenComments;
}) => {
if (tokenComments.length === 0) {
return null;
}

let constructedComment =
"/*\nTODO: aksel box migration:\nCould not migrate the following:\n";

for (const { prop, token, comment } of tokenComments.values()) {
constructedComment += ` - ${prop}=${token}\n`;
if (comment) {
constructedComment += ` - ${comment}\n`;
}
}

constructedComment += "*/";

return constructedComment;
};

type MigrationResult = "all new" | "mixed" | "no new";

const analyzePartialMigration = (
j: JSCodeshift,
source: string,
): MigrationResult => {
const root = j(source);

const astNewElements = findJSXElement({
root,
j,
name: "BoxNew",
originalName: "BoxNew",
});

if (astNewElements.length === 0) {
return "no new";
}

const localName = findComponentImport({
root,
j,
name: "Box",
packageType: "react",
});

if (!localName) {
// this should never happen
throw new Error(
'package imports have been tampered with before the package import "step" in the migration',
);
}

const astOldElements = findJSXElement({
root,
j,
name: localName,
originalName: "Box",
});

if (astOldElements.length === 0) {
return "all new";
}

return "mixed";
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Box } from "@navikt/ds-react"

export const MyComponent = () => {
return (<>
<Box background="bg-subtle" borderColor="border-alt-1">
migratable
</Box>
<Box background="bg-subtle" borderColor="border-alt-1" shadow="large">
migratable + unmigratable (no comment)
</Box>
<Box background="surface-alt-3-strong" >
unmigratable (with comment)
</Box>
<Box borderWidth="4" padding={{ lg: "10", sm: "8" }} height="200rem">
old
</Box>
<Box borderWidth="4" background="bg-subtle">
old + migratable
</Box>
</>);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
TODO: aksel box migration:
Could not migrate the following:
- shadow=large
- background=surface-alt-3-strong
- Use 'bg-brand-blue-moderate' in theme 'dark'-mode.
*/

import { BoxNew } from "@navikt/ds-react/Box"
import { Box } from "@navikt/ds-react"

export const MyComponent = () => {
return (<>
<BoxNew background="bg-neutral-soft" borderColor="border-meta-purple">
migratable
</BoxNew>
<Box background="bg-neutral-soft" borderColor="border-meta-purple" shadow="large">
migratable + unmigratable (no comment)
</Box>
<Box background="surface-alt-3-strong" >
unmigratable (with comment)
</Box>
<BoxNew borderWidth="4" padding={{ lg: "10", sm: "8" }} height="200rem">
old
</BoxNew>
<BoxNew borderWidth="4" background="bg-neutral-soft">
old + migratable
</BoxNew>
</>);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
TODO: aksel box migration:
Could not migrate the following:
- shadow=large
- background=surface-alt-3-strong
- Use 'bg-brand-blue-moderate' in theme 'dark'-mode.
*/

import { Box } from "@navikt/ds-react"

export const MyComponent = () => {
return (<>
<Box background="bg-neutral-soft" borderColor="border-meta-purple" shadow="large">
migratable + unmigratable (no comment)
</Box>
<Box background="surface-alt-3-strong" >
unmigratable (with comment)
</Box>
</>);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
TODO: aksel box migration:
Could not migrate the following:
- shadow=large
- background=surface-alt-3-strong
- Use 'bg-brand-blue-moderate' in theme 'dark'-mode.
*/

import { Box } from "@navikt/ds-react"

export const MyComponent = () => {
return (<>
<Box background="bg-neutral-soft" borderColor="border-meta-purple" shadow="large">
migratable + unmigratable (no comment)
</Box>
<Box background="surface-alt-3-strong" >
unmigratable (with comment)
</Box>
</>);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
TODO: aksel box migration:
Could not migrate the following:
- shadow=large
- background=surface-alt-3-strong
- Use 'bg-brand-blue-moderate' in theme 'dark'-mode.
*/

import { BoxNew } from "@navikt/ds-react/Box"
import { Box } from "@navikt/ds-react"

export const MyComponent = () => {
return (<>
<BoxNew background="bg-neutral-soft" borderColor="border-meta-purple">
migratable
</BoxNew>
<Box background="bg-neutral-soft" borderColor="border-meta-purple" shadow="large">
migratable + unmigratable (no comment)
</Box>
<Box background="surface-alt-3-strong" >
unmigratable (with comment)
</Box>
<BoxNew borderWidth="4" padding={{ lg: "10", sm: "8" }} height="200rem">
old
</BoxNew>
<BoxNew borderWidth="4" background="bg-neutral-soft">
old + migratable
</BoxNew>
</>);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
TODO: aksel box migration:
Could not migrate the following:
- shadow=large
- background=surface-alt-3-strong
- Use 'bg-brand-blue-moderate' in theme 'dark'-mode.
*/

import { BoxNew } from "@navikt/ds-react/Box"
import { Box } from "@navikt/ds-react"

export const MyComponent = () => {
return (<>
<BoxNew background="bg-neutral-soft" borderColor="border-meta-purple">
migratable
</BoxNew>
<Box background="bg-neutral-soft" borderColor="border-meta-purple" shadow="large">
migratable + unmigratable (no comment)
</Box>
<Box background="surface-alt-3-strong" >
unmigratable (with comment)
</Box>
<BoxNew borderWidth="4" padding={{ lg: "10", sm: "8" }} height="200rem">
old
</BoxNew>
<BoxNew borderWidth="4" background="bg-neutral-soft">
old + migratable
</BoxNew>
</>);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Box as AkselBox } from "@navikt/ds-react"

export const MyComponent = () => {
return (<>
<AkselBox background="bg-subtle" borderColor="border-alt-1">
simple rename of import
</AkselBox>
<AkselBox shadow="medium">
simple rename of import
</AkselBox>
</>);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
TODO: aksel box migration:
Could not migrate the following:
- shadow=medium
*/

import { BoxNew } from "@navikt/ds-react/Box";
import { Box as AkselBox } from "@navikt/ds-react"

export const MyComponent = () => {
return (<>
<BoxNew background="bg-neutral-soft" borderColor="border-meta-purple">
simple rename of import
</BoxNew>
<AkselBox shadow="medium">
simple rename of import
</AkselBox>
</>);
}
Loading
Loading