Skip to content

Commit 47baa33

Browse files
docs: add codemod (#6100)
1 parent beb2b0d commit 47baa33

File tree

3 files changed

+150
-20
lines changed

3 files changed

+150
-20
lines changed

docs/MigrationGuide.mdx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import './MigrationGuide.css';
12
import { Footer, TableOfContent } from '@sb/components';
23
import { Meta } from '@storybook/blocks';
3-
import './MigrationGuide.css';
4+
import { MessageStrip } from '@ui5/webcomponents-react';
45

56
<Meta title="Migration Guide" />
67

@@ -14,10 +15,35 @@ or the [changelog](?path=/docs/change-log--page)._
1415
> This migration guide only covers breaking changes when updating from v1 to v2.
1516
> For migration guides for older releases, please refer to our [Migration Guide Archive](https://github.com/SAP/ui5-webcomponents-react/blob/main/docs/MigrationGuide.archive.md).
1617
17-
<br />
18-
1918
<TableOfContent headingSelector="h2, h3" />
2019

20+
## Codemod
21+
22+
To make the migration to UI5 Web Components (for React) v2 easier,
23+
we provide a codemod which tries to transform most of the breaking changes.
24+
25+
<MessageStrip
26+
hideCloseButton
27+
design="Critical"
28+
children={
29+
<>
30+
The codemod is a best efforts attempt to help you migrate the breaking change. Please review the generated code
31+
thoroughly!
32+
<br />
33+
<strong>
34+
Applying the codemod might break your code formatting, so please don't forget to run prettier and/or eslint
35+
after you've applied the codemod!
36+
</strong>
37+
</>
38+
}
39+
/>
40+
41+
```shell
42+
npx @ui5/webcomponents-react-cli codemod --transform v2 \
43+
--src ./path/to/src \
44+
--typescript # only if you use TypeScript in your project, omit if you use JavaScript
45+
```
46+
2147
## General changes
2248

2349
### Removed `react-jss`

packages/cli/src/bin/index.ts

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,25 @@ import { resolve } from 'node:path';
33
import { parseArgs } from 'node:util';
44
import * as process from 'process';
55

6-
const options = {
7-
packageName: {
8-
type: 'string' as const
9-
},
10-
out: {
11-
type: 'string' as const,
12-
short: 'o'
13-
},
14-
additionalComponentNote: {
15-
type: 'string' as const
16-
}
17-
};
18-
const { values, positionals } = parseArgs({ options, allowPositionals: true });
6+
const { positionals } = parseArgs({ allowPositionals: true, strict: false });
197

208
const [command] = positionals;
219

22-
console.log(command);
23-
2410
switch (command) {
2511
case 'create-wrappers': {
12+
const wrapperOptions = {
13+
packageName: {
14+
type: 'string' as const
15+
},
16+
out: {
17+
type: 'string' as const,
18+
short: 'o'
19+
},
20+
additionalComponentNote: {
21+
type: 'string' as const
22+
}
23+
};
24+
const { values } = parseArgs({ options: wrapperOptions, allowPositionals: true });
2625
const { packageName, out, additionalComponentNote } = values;
2726
const missingParameters = [];
2827
if (!packageName) {
@@ -51,9 +50,74 @@ switch (command) {
5150
}
5251

5352
case 'resolve-cem': {
53+
const cemOptions = {
54+
packageName: {
55+
type: 'string' as const
56+
},
57+
out: {
58+
type: 'string' as const,
59+
short: 'o'
60+
}
61+
};
62+
const { values } = parseArgs({ options: cemOptions, allowPositionals: true });
63+
const { packageName, out } = values;
64+
const missingParameters = [];
65+
if (!packageName) {
66+
missingParameters.push('--packageName');
67+
}
68+
if (!out) {
69+
missingParameters.push('--out');
70+
}
71+
72+
if (missingParameters.length > 0) {
73+
console.error(`
74+
Missing parameters: ${missingParameters.join(', ')}
75+
Example: ui5-wcr resolve-cem --packageName @ui5/webcomponents --out ./src/components
76+
77+
Please add the missing parameters and try again.
78+
`);
79+
process.exit(1);
80+
}
81+
5482
const resolveCEM = await import('../scripts/resolve-cem/main.js');
55-
const outPath = resolve(process.cwd(), values.out!);
56-
await resolveCEM.default(values.packageName!, outPath);
83+
const outPath = resolve(process.cwd(), out!);
84+
await resolveCEM.default(packageName!, outPath);
85+
break;
86+
}
87+
88+
case 'codemod': {
89+
const codemodOptions = {
90+
transform: {
91+
type: 'string' as const
92+
},
93+
src: {
94+
type: 'string' as const
95+
},
96+
typescript: {
97+
type: 'boolean' as const,
98+
default: false
99+
}
100+
};
101+
const { values } = parseArgs({ options: codemodOptions, allowPositionals: true });
102+
const missingParameters = [];
103+
if (!values.src) {
104+
missingParameters.push('--src');
105+
}
106+
if (!values.transform) {
107+
missingParameters.push('--transform');
108+
}
109+
110+
if (missingParameters.length > 0) {
111+
console.error(`
112+
Missing parameters: ${missingParameters.join(', ')}
113+
Example: ui5-wcr codemod --src ./src --transform v2 (--typescript)
114+
115+
Please add the missing parameters and try again.
116+
`);
117+
process.exit(1);
118+
}
119+
const codemod = await import('../scripts/codemod/main.js');
120+
await codemod.default(values.transform!, values.src!, values.typescript!);
57121
break;
58122
}
59123
default:
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import childProcess from 'node:child_process';
2+
import path from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
5+
const SUPPORTED_TRANSFORMERS = ['v2'];
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
10+
const transformerDir = path.resolve(__dirname, 'transforms');
11+
12+
export default async function runCodemod(transform: string, inputDir: string, useTypeScript: boolean) {
13+
if (!SUPPORTED_TRANSFORMERS.includes(transform)) {
14+
// eslint-disable-next-line no-console
15+
console.error('Invalid transform choice, pick one of:');
16+
// eslint-disable-next-line no-console
17+
console.error(SUPPORTED_TRANSFORMERS.map((x) => '- ' + x).join('\n'));
18+
process.exit(1);
19+
}
20+
21+
const jscodeshiftOptions = [];
22+
23+
const transformerPath = path.join(transformerDir, transform, `main.cjs`);
24+
jscodeshiftOptions.push(`--transform`, transformerPath);
25+
26+
if (useTypeScript) {
27+
jscodeshiftOptions.push('--extensions=tsx,ts,jsx,js');
28+
jscodeshiftOptions.push('--parser', 'tsx');
29+
} else {
30+
jscodeshiftOptions.push('--extensions=jsx,js');
31+
}
32+
33+
jscodeshiftOptions.push('--ignore-pattern=**/node_modules/**');
34+
35+
// eslint-disable-next-line no-console
36+
console.log(`Executing 'npx jscodeshift ${jscodeshiftOptions.join(' ')} ${inputDir}'`);
37+
childProcess.spawnSync('npx', ['jscodeshift', ...jscodeshiftOptions, inputDir], {
38+
stdio: 'inherit'
39+
});
40+
}

0 commit comments

Comments
 (0)