@volue/wave-codemod__react 0.1.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +38 -0
- package/dist/index.cjs +136 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.mjs +131 -0
- package/package.json +67 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# `@volue/wave-codemod__react`
|
|
2
|
+
|
|
3
|
+
Codemods for migration to the newer version of the `@volue/wave-react` library.
|
|
4
|
+
|
|
5
|
+
These codemods utilize [jscodeshift](https://github.com/facebook/jscodeshift) library for transformations and [Hypermod.io CLI tool](https://www.hypermod.io/docs/tools/cli) for downloading and running them against your codebase.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
No installation of this package is necessary.
|
|
10
|
+
Downloading and running codemods can be done via `npx @hypermod/cli`.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### Considerations
|
|
15
|
+
|
|
16
|
+
- You should run codemods on a separate Git branch, then manually review the changes before deploying them.
|
|
17
|
+
- Codemods are designed to do the heavy lifting, but they may not be perfect, so some manual work may still be required in order to successfully migrate.
|
|
18
|
+
- Codemods might output code that doesn’t follow your coding style. Make sure to run your code formatter and/or linter before committing the changes.
|
|
19
|
+
|
|
20
|
+
### Examples
|
|
21
|
+
|
|
22
|
+
To run a transform for version `1.0.0` of `@volue/wave-react`, use one of the following commands:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
# Transform multiple files
|
|
26
|
+
npx @hypermod/cli --packages @volue/wave-codemod__react@1.0.0 --experimental-loader /project/src/**/*.tsx
|
|
27
|
+
|
|
28
|
+
# Transform single file
|
|
29
|
+
npx @hypermod/cli --packages @volue/wave-codemod__react@1.0.0 --experimental-loader /project/src/path/to/file
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
To run all transforms for `@volue/wave-react` in sequence from version `1.0.0` to the latest, add `--sequence` flag:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npx @hypermod/cli --sequence --packages @volue/wave-codemod__react@1.0.0 --experimental-loader /project/src/**/*.tsx
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
[See the Hypermod CLI docs for more information and examples](https://www.hypermod.io/docs/tools/cli)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var utils = require('@hypermod/utils');
|
|
6
|
+
|
|
7
|
+
const componentsSet = /* @__PURE__ */ new Set([
|
|
8
|
+
"ActionBar",
|
|
9
|
+
"Anchor",
|
|
10
|
+
"AppFrame",
|
|
11
|
+
"Avatar",
|
|
12
|
+
"ButtonGroup",
|
|
13
|
+
"Card",
|
|
14
|
+
"Checkbox",
|
|
15
|
+
"Collapsible",
|
|
16
|
+
"CollapsibleCard",
|
|
17
|
+
"Combobox",
|
|
18
|
+
"DataItem",
|
|
19
|
+
"DataList",
|
|
20
|
+
"DatePicker",
|
|
21
|
+
"Dialog",
|
|
22
|
+
"Drawer",
|
|
23
|
+
"FormField",
|
|
24
|
+
"HeaderNavList",
|
|
25
|
+
"Menu",
|
|
26
|
+
"MultiSelectMenu",
|
|
27
|
+
"Notification",
|
|
28
|
+
"Pagination",
|
|
29
|
+
"Popover",
|
|
30
|
+
"Positioner",
|
|
31
|
+
"Radio",
|
|
32
|
+
"RovingFocusGroup",
|
|
33
|
+
"SelectMenu",
|
|
34
|
+
"SidebarNavigation",
|
|
35
|
+
"SingleSelectMenu",
|
|
36
|
+
"Switch",
|
|
37
|
+
"Table",
|
|
38
|
+
"Tabs",
|
|
39
|
+
"ToggleButtonGroup",
|
|
40
|
+
"TreeView"
|
|
41
|
+
]);
|
|
42
|
+
function addRootToMultipartComps(j, ast) {
|
|
43
|
+
const componentsToTransform = [];
|
|
44
|
+
ast.find(j.ImportDeclaration, { source: { value: "@volue/wave-react" } }).forEach((path) => {
|
|
45
|
+
path.node.specifiers?.forEach((specifier) => {
|
|
46
|
+
if (specifier.type === "ImportSpecifier") {
|
|
47
|
+
const importedName = specifier.imported.name;
|
|
48
|
+
if (componentsSet.has(importedName)) {
|
|
49
|
+
componentsToTransform.push(importedName);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
if (componentsToTransform.length === 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
componentsToTransform.forEach((componentName) => {
|
|
58
|
+
ast.find(j.JSXOpeningElement, {
|
|
59
|
+
name: {
|
|
60
|
+
type: "JSXIdentifier",
|
|
61
|
+
name: componentName
|
|
62
|
+
}
|
|
63
|
+
}).forEach((openingTagPath) => {
|
|
64
|
+
if (openingTagPath.node.name.type === "JSXIdentifier") {
|
|
65
|
+
openingTagPath.node.name.name = `${componentName}.Root`;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
ast.find(j.JSXClosingElement, {
|
|
69
|
+
name: {
|
|
70
|
+
type: "JSXIdentifier",
|
|
71
|
+
name: componentName
|
|
72
|
+
}
|
|
73
|
+
}).forEach((closingTagPath) => {
|
|
74
|
+
if (closingTagPath.node.name.type === "JSXIdentifier") {
|
|
75
|
+
closingTagPath.node.name.name = `${componentName}.Root`;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
ast.find(j.TSTypeQuery, {
|
|
79
|
+
exprName: {
|
|
80
|
+
type: "Identifier",
|
|
81
|
+
name: componentName
|
|
82
|
+
}
|
|
83
|
+
}).replaceWith(
|
|
84
|
+
j.tsTypeQuery(
|
|
85
|
+
j.tsQualifiedName(j.identifier(componentName), j.identifier("Root"))
|
|
86
|
+
)
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const REG_RETURN = /return\s+\((\s+)\(<([^\s>]+)/g;
|
|
92
|
+
function removeParentheses(string) {
|
|
93
|
+
const matches = string.matchAll(REG_RETURN);
|
|
94
|
+
let result = "";
|
|
95
|
+
const allMatches = [...matches];
|
|
96
|
+
if (allMatches.length === 0) return string;
|
|
97
|
+
allMatches.forEach((match) => {
|
|
98
|
+
const [, spaces, componentName] = match;
|
|
99
|
+
const sl = spaces.length;
|
|
100
|
+
const REG_DOUBLE_TAG = `(return\\s+\\(\\s{${sl}})\\((<${componentName}.+?\\s{${sl}}<\\/${componentName}>)\\)(\\s+\\))`;
|
|
101
|
+
const REG_SELF_CLOSING = `(return\\s+\\(\\s{${sl}})\\((<${componentName}.+?\\/>)\\)(\\s+\\))`;
|
|
102
|
+
const regexp = new RegExp(`${REG_DOUBLE_TAG}|${REG_SELF_CLOSING}`, "gs");
|
|
103
|
+
result = string.replace(
|
|
104
|
+
regexp,
|
|
105
|
+
(match2, doubleTagStart, doubleTagContent, doubleTagEnd, selfTagStart, selfTagContent, selfTagEnd) => {
|
|
106
|
+
if (doubleTagStart && doubleTagContent && doubleTagEnd) {
|
|
107
|
+
return doubleTagStart + doubleTagContent + doubleTagEnd;
|
|
108
|
+
}
|
|
109
|
+
if (selfTagStart && selfTagContent && selfTagEnd) {
|
|
110
|
+
return selfTagStart + selfTagContent + selfTagEnd;
|
|
111
|
+
}
|
|
112
|
+
return match2;
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function transformer(file, api, options) {
|
|
120
|
+
const { jscodeshift: j } = api;
|
|
121
|
+
const ast = j(file.source);
|
|
122
|
+
if (!utils.hasImportDeclaration(j, ast, "@volue/wave-react")) {
|
|
123
|
+
return file.source;
|
|
124
|
+
}
|
|
125
|
+
utils.applyMotions(j, ast, [addRootToMultipartComps]);
|
|
126
|
+
return removeParentheses(ast.toSource(options.printOptions));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
var index = {
|
|
130
|
+
transforms: {
|
|
131
|
+
"1.0.0": transformer
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
exports.default = index;
|
|
136
|
+
exports.v1 = transformer;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FileInfo, API, Options } from 'jscodeshift';
|
|
2
|
+
|
|
3
|
+
declare function transformer(file: FileInfo, api: API, options: Options): string;
|
|
4
|
+
|
|
5
|
+
declare const _default: {
|
|
6
|
+
transforms: {
|
|
7
|
+
'1.0.0': typeof transformer;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export { _default as default, transformer as v1 };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FileInfo, API, Options } from 'jscodeshift';
|
|
2
|
+
|
|
3
|
+
declare function transformer(file: FileInfo, api: API, options: Options): string;
|
|
4
|
+
|
|
5
|
+
declare const _default: {
|
|
6
|
+
transforms: {
|
|
7
|
+
'1.0.0': typeof transformer;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export { _default as default, transformer as v1 };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { hasImportDeclaration, applyMotions } from '@hypermod/utils';
|
|
2
|
+
|
|
3
|
+
const componentsSet = /* @__PURE__ */ new Set([
|
|
4
|
+
"ActionBar",
|
|
5
|
+
"Anchor",
|
|
6
|
+
"AppFrame",
|
|
7
|
+
"Avatar",
|
|
8
|
+
"ButtonGroup",
|
|
9
|
+
"Card",
|
|
10
|
+
"Checkbox",
|
|
11
|
+
"Collapsible",
|
|
12
|
+
"CollapsibleCard",
|
|
13
|
+
"Combobox",
|
|
14
|
+
"DataItem",
|
|
15
|
+
"DataList",
|
|
16
|
+
"DatePicker",
|
|
17
|
+
"Dialog",
|
|
18
|
+
"Drawer",
|
|
19
|
+
"FormField",
|
|
20
|
+
"HeaderNavList",
|
|
21
|
+
"Menu",
|
|
22
|
+
"MultiSelectMenu",
|
|
23
|
+
"Notification",
|
|
24
|
+
"Pagination",
|
|
25
|
+
"Popover",
|
|
26
|
+
"Positioner",
|
|
27
|
+
"Radio",
|
|
28
|
+
"RovingFocusGroup",
|
|
29
|
+
"SelectMenu",
|
|
30
|
+
"SidebarNavigation",
|
|
31
|
+
"SingleSelectMenu",
|
|
32
|
+
"Switch",
|
|
33
|
+
"Table",
|
|
34
|
+
"Tabs",
|
|
35
|
+
"ToggleButtonGroup",
|
|
36
|
+
"TreeView"
|
|
37
|
+
]);
|
|
38
|
+
function addRootToMultipartComps(j, ast) {
|
|
39
|
+
const componentsToTransform = [];
|
|
40
|
+
ast.find(j.ImportDeclaration, { source: { value: "@volue/wave-react" } }).forEach((path) => {
|
|
41
|
+
path.node.specifiers?.forEach((specifier) => {
|
|
42
|
+
if (specifier.type === "ImportSpecifier") {
|
|
43
|
+
const importedName = specifier.imported.name;
|
|
44
|
+
if (componentsSet.has(importedName)) {
|
|
45
|
+
componentsToTransform.push(importedName);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
if (componentsToTransform.length === 0) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
componentsToTransform.forEach((componentName) => {
|
|
54
|
+
ast.find(j.JSXOpeningElement, {
|
|
55
|
+
name: {
|
|
56
|
+
type: "JSXIdentifier",
|
|
57
|
+
name: componentName
|
|
58
|
+
}
|
|
59
|
+
}).forEach((openingTagPath) => {
|
|
60
|
+
if (openingTagPath.node.name.type === "JSXIdentifier") {
|
|
61
|
+
openingTagPath.node.name.name = `${componentName}.Root`;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
ast.find(j.JSXClosingElement, {
|
|
65
|
+
name: {
|
|
66
|
+
type: "JSXIdentifier",
|
|
67
|
+
name: componentName
|
|
68
|
+
}
|
|
69
|
+
}).forEach((closingTagPath) => {
|
|
70
|
+
if (closingTagPath.node.name.type === "JSXIdentifier") {
|
|
71
|
+
closingTagPath.node.name.name = `${componentName}.Root`;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
ast.find(j.TSTypeQuery, {
|
|
75
|
+
exprName: {
|
|
76
|
+
type: "Identifier",
|
|
77
|
+
name: componentName
|
|
78
|
+
}
|
|
79
|
+
}).replaceWith(
|
|
80
|
+
j.tsTypeQuery(
|
|
81
|
+
j.tsQualifiedName(j.identifier(componentName), j.identifier("Root"))
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const REG_RETURN = /return\s+\((\s+)\(<([^\s>]+)/g;
|
|
88
|
+
function removeParentheses(string) {
|
|
89
|
+
const matches = string.matchAll(REG_RETURN);
|
|
90
|
+
let result = "";
|
|
91
|
+
const allMatches = [...matches];
|
|
92
|
+
if (allMatches.length === 0) return string;
|
|
93
|
+
allMatches.forEach((match) => {
|
|
94
|
+
const [, spaces, componentName] = match;
|
|
95
|
+
const sl = spaces.length;
|
|
96
|
+
const REG_DOUBLE_TAG = `(return\\s+\\(\\s{${sl}})\\((<${componentName}.+?\\s{${sl}}<\\/${componentName}>)\\)(\\s+\\))`;
|
|
97
|
+
const REG_SELF_CLOSING = `(return\\s+\\(\\s{${sl}})\\((<${componentName}.+?\\/>)\\)(\\s+\\))`;
|
|
98
|
+
const regexp = new RegExp(`${REG_DOUBLE_TAG}|${REG_SELF_CLOSING}`, "gs");
|
|
99
|
+
result = string.replace(
|
|
100
|
+
regexp,
|
|
101
|
+
(match2, doubleTagStart, doubleTagContent, doubleTagEnd, selfTagStart, selfTagContent, selfTagEnd) => {
|
|
102
|
+
if (doubleTagStart && doubleTagContent && doubleTagEnd) {
|
|
103
|
+
return doubleTagStart + doubleTagContent + doubleTagEnd;
|
|
104
|
+
}
|
|
105
|
+
if (selfTagStart && selfTagContent && selfTagEnd) {
|
|
106
|
+
return selfTagStart + selfTagContent + selfTagEnd;
|
|
107
|
+
}
|
|
108
|
+
return match2;
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function transformer(file, api, options) {
|
|
116
|
+
const { jscodeshift: j } = api;
|
|
117
|
+
const ast = j(file.source);
|
|
118
|
+
if (!hasImportDeclaration(j, ast, "@volue/wave-react")) {
|
|
119
|
+
return file.source;
|
|
120
|
+
}
|
|
121
|
+
applyMotions(j, ast, [addRootToMultipartComps]);
|
|
122
|
+
return removeParentheses(ast.toSource(options.printOptions));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
var index = {
|
|
126
|
+
transforms: {
|
|
127
|
+
"1.0.0": transformer
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export { index as default, transformer as v1 };
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@volue/wave-codemod__react",
|
|
3
|
+
"version": "0.1.0-next.0",
|
|
4
|
+
"description": "Codemods for Wave React library",
|
|
5
|
+
"license": "",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Volue/wave",
|
|
9
|
+
"directory": "codemods/react"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"main": "./dist/index.cjs",
|
|
18
|
+
"module": "./dist/index.mjs",
|
|
19
|
+
"types": "./dist/index.d.cts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"require": {
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"default": "./dist/index.cjs"
|
|
25
|
+
},
|
|
26
|
+
"import": {
|
|
27
|
+
"types": "./dist/index.d.mts",
|
|
28
|
+
"default": "./dist/index.mjs"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"files": [
|
|
35
|
+
"dist"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"jest": "jest",
|
|
39
|
+
"lint": "eslint . --cache",
|
|
40
|
+
"lint:fix": "yarn run lint --fix",
|
|
41
|
+
"lint:types": "tsc",
|
|
42
|
+
"_prettier": "prettier \"**/*.{json,md,yml}\"",
|
|
43
|
+
"format": "yarn run _prettier --write",
|
|
44
|
+
"test": "run-p lint:types lint \"_prettier --check\" jest",
|
|
45
|
+
"clean": "premove dist",
|
|
46
|
+
"build": "yarn run clean && pkgroll",
|
|
47
|
+
"prepack": "yarn run build"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@jest/types": "29.6.3",
|
|
51
|
+
"@types/jest": "29.5.14",
|
|
52
|
+
"@volue/eslint-config": "1.3.11",
|
|
53
|
+
"eslint": "9.20.1",
|
|
54
|
+
"jest": "29.7.0",
|
|
55
|
+
"npm-run-all2": "7.0.2",
|
|
56
|
+
"pkgroll": "2.11.0",
|
|
57
|
+
"premove": "4.0.0",
|
|
58
|
+
"prettier": "3.5.1",
|
|
59
|
+
"ts-jest": "29.2.6",
|
|
60
|
+
"typescript": "5.7.3"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@hypermod/utils": "0.5.0",
|
|
64
|
+
"@types/jscodeshift": "0.12.0",
|
|
65
|
+
"jscodeshift": "17.1.2"
|
|
66
|
+
}
|
|
67
|
+
}
|