@atlaskit/select 21.10.1 → 21.10.2
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 +9 -0
- package/codemods/utils/add-comment-before.tsx +40 -0
- package/codemods/utils/add-comment-to-start-of-file.tsx +21 -0
- package/codemods/utils/get-default-specifier-name.tsx +24 -0
- package/codemods/utils/get-jsx-attributes-by-name.tsx +22 -0
- package/codemods/utils/get-specifier-name.tsx +31 -0
- package/codemods/utils/has-import-declaration.tsx +14 -0
- package/codemods/utils/has-jsx-attributes-by-name.tsx +15 -0
- package/codemods/utils/is-using-prop.tsx +32 -0
- package/codemods/utils/is-using-supported-spread.tsx +47 -0
- package/codemods/utils/is-using-through-spread.tsx +85 -0
- package/codemods/utils/types.tsx +1 -0
- package/codemods/utils/update-render-props.tsx +26 -0
- package/package.json +10 -2
- package/codemods/utils/helpers.tsx +0 -333
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @atlaskit/select
|
|
2
2
|
|
|
3
|
+
## 21.10.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`02483200273ec`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/02483200273ec) -
|
|
8
|
+
Enrol all Design System UI packages into the React Compiler with platform gating via
|
|
9
|
+
isReactCompilerActivePlatform.
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
|
|
3
12
|
## 21.10.1
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type default as core, type Node } from 'jscodeshift';
|
|
2
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
3
|
+
|
|
4
|
+
// not replacing newlines (which \s does)
|
|
5
|
+
const spacesAndTabs: RegExp = /[ \t]{2,}/g;
|
|
6
|
+
const lineStartWithSpaces: RegExp = /^[ \t]*/gm;
|
|
7
|
+
|
|
8
|
+
function clean(value: string): string {
|
|
9
|
+
return (
|
|
10
|
+
value
|
|
11
|
+
.replace(spacesAndTabs, ' ')
|
|
12
|
+
.replace(lineStartWithSpaces, '')
|
|
13
|
+
// using .trim() to clear the any newlines before the first text and after last text
|
|
14
|
+
.trim()
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function addCommentBefore({
|
|
19
|
+
j,
|
|
20
|
+
target,
|
|
21
|
+
message,
|
|
22
|
+
}: {
|
|
23
|
+
j: core.JSCodeshift;
|
|
24
|
+
target: Collection<Node>;
|
|
25
|
+
message: string;
|
|
26
|
+
}): void {
|
|
27
|
+
const content: string = ` TODO: (from codemod) ${clean(message)} `;
|
|
28
|
+
target.forEach((path) => {
|
|
29
|
+
path.value.comments = path.value.comments || [];
|
|
30
|
+
|
|
31
|
+
const exists = path.value.comments.find((comment) => comment.value === content);
|
|
32
|
+
|
|
33
|
+
// avoiding duplicates of the same comment
|
|
34
|
+
if (exists) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
path.value.comments.push(j.commentBlock(content));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type default as core, type Node } from 'jscodeshift';
|
|
2
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
3
|
+
|
|
4
|
+
import { addCommentBefore } from './add-comment-before';
|
|
5
|
+
|
|
6
|
+
export function addCommentToStartOfFile({
|
|
7
|
+
j,
|
|
8
|
+
base,
|
|
9
|
+
message,
|
|
10
|
+
}: {
|
|
11
|
+
j: core.JSCodeshift;
|
|
12
|
+
base: Collection<Node>;
|
|
13
|
+
message: string;
|
|
14
|
+
}): void {
|
|
15
|
+
addCommentBefore({
|
|
16
|
+
j,
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
target: base.find(j.Program),
|
|
19
|
+
message,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type default as core } from 'jscodeshift';
|
|
2
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
3
|
+
|
|
4
|
+
import { type Nullable } from './types';
|
|
5
|
+
|
|
6
|
+
export function getDefaultSpecifierName({
|
|
7
|
+
j,
|
|
8
|
+
base,
|
|
9
|
+
packageName,
|
|
10
|
+
}: {
|
|
11
|
+
j: core.JSCodeshift;
|
|
12
|
+
base: Collection<any>;
|
|
13
|
+
packageName: string;
|
|
14
|
+
}): Nullable<string> {
|
|
15
|
+
const specifiers = base
|
|
16
|
+
.find(j.ImportDeclaration)
|
|
17
|
+
.filter((path) => path.node.source.value === packageName)
|
|
18
|
+
.find(j.ImportDefaultSpecifier);
|
|
19
|
+
|
|
20
|
+
if (!specifiers.length) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return specifiers.nodes()[0]!.local!.name;
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ASTPath, type default as core, type JSXAttribute, type JSXElement } from 'jscodeshift';
|
|
2
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
3
|
+
|
|
4
|
+
export function getJSXAttributesByName({
|
|
5
|
+
j,
|
|
6
|
+
element,
|
|
7
|
+
attributeName,
|
|
8
|
+
}: {
|
|
9
|
+
j: core.JSCodeshift;
|
|
10
|
+
element: JSXElement | ASTPath<JSXElement>;
|
|
11
|
+
attributeName: string;
|
|
12
|
+
}): Collection<JSXAttribute> {
|
|
13
|
+
return j(element)
|
|
14
|
+
.find(j.JSXOpeningElement)
|
|
15
|
+
.find(j.JSXAttribute)
|
|
16
|
+
.filter((attribute) => {
|
|
17
|
+
const matches = j(attribute)
|
|
18
|
+
.find(j.JSXIdentifier)
|
|
19
|
+
.filter((identifier) => identifier.value.name === attributeName);
|
|
20
|
+
return Boolean(matches.length);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type default as core } from 'jscodeshift';
|
|
2
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
3
|
+
|
|
4
|
+
import { type Nullable } from './types';
|
|
5
|
+
|
|
6
|
+
export function getSpecifierName({
|
|
7
|
+
j,
|
|
8
|
+
base,
|
|
9
|
+
packageName,
|
|
10
|
+
component,
|
|
11
|
+
}: {
|
|
12
|
+
j: core.JSCodeshift;
|
|
13
|
+
base: Collection<any>;
|
|
14
|
+
packageName: string;
|
|
15
|
+
component: string;
|
|
16
|
+
}): Nullable<string> {
|
|
17
|
+
const specifiers = base
|
|
18
|
+
.find(j.ImportDeclaration)
|
|
19
|
+
.filter((path) => path.node.source.value === packageName)
|
|
20
|
+
.find(j.ImportSpecifier);
|
|
21
|
+
|
|
22
|
+
if (!specifiers.length) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const specifierNode = specifiers.nodes().find((node) => node.imported.name === component);
|
|
26
|
+
if (!specifierNode) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
return specifierNode.local.name;
|
|
31
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ASTPath, type default as core, type ImportDeclaration } from 'jscodeshift';
|
|
2
|
+
|
|
3
|
+
export function hasImportDeclaration(
|
|
4
|
+
j: core.JSCodeshift,
|
|
5
|
+
source: string,
|
|
6
|
+
importPath: string,
|
|
7
|
+
): boolean {
|
|
8
|
+
return (
|
|
9
|
+
j(source)
|
|
10
|
+
.find(j.ImportDeclaration)
|
|
11
|
+
.filter((path: ASTPath<ImportDeclaration>) => path.node.source.value === importPath).length >
|
|
12
|
+
0
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type default as core, type JSXElement } from 'jscodeshift';
|
|
2
|
+
|
|
3
|
+
import { getJSXAttributesByName } from './get-jsx-attributes-by-name';
|
|
4
|
+
|
|
5
|
+
export function hasJSXAttributesByName({
|
|
6
|
+
j,
|
|
7
|
+
element,
|
|
8
|
+
attributeName,
|
|
9
|
+
}: {
|
|
10
|
+
j: core.JSCodeshift;
|
|
11
|
+
element: JSXElement;
|
|
12
|
+
attributeName: string;
|
|
13
|
+
}): boolean {
|
|
14
|
+
return getJSXAttributesByName({ j, element, attributeName }).length > 0;
|
|
15
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type NodePath } from 'ast-types/lib/node-path';
|
|
2
|
+
import { type default as core, type JSXElement } from 'jscodeshift';
|
|
3
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
4
|
+
|
|
5
|
+
import { hasJSXAttributesByName } from './has-jsx-attributes-by-name';
|
|
6
|
+
import { isUsingThroughSpread } from './is-using-through-spread';
|
|
7
|
+
|
|
8
|
+
export function isUsingProp({
|
|
9
|
+
j,
|
|
10
|
+
base,
|
|
11
|
+
element,
|
|
12
|
+
propName,
|
|
13
|
+
}: {
|
|
14
|
+
j: core.JSCodeshift;
|
|
15
|
+
base: Collection<any>;
|
|
16
|
+
element: NodePath<JSXElement, JSXElement>;
|
|
17
|
+
propName: string;
|
|
18
|
+
}): boolean {
|
|
19
|
+
return (
|
|
20
|
+
hasJSXAttributesByName({
|
|
21
|
+
j,
|
|
22
|
+
element: element.value,
|
|
23
|
+
attributeName: propName,
|
|
24
|
+
}) ||
|
|
25
|
+
isUsingThroughSpread({
|
|
26
|
+
j,
|
|
27
|
+
base,
|
|
28
|
+
element,
|
|
29
|
+
propName,
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type NodePath } from 'ast-types/lib/node-path';
|
|
2
|
+
import { type default as core, type JSXElement } from 'jscodeshift';
|
|
3
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
4
|
+
|
|
5
|
+
export function isUsingSupportedSpread({
|
|
6
|
+
j,
|
|
7
|
+
base,
|
|
8
|
+
element,
|
|
9
|
+
}: {
|
|
10
|
+
j: core.JSCodeshift;
|
|
11
|
+
base: Collection<any>;
|
|
12
|
+
element: NodePath<JSXElement, JSXElement>;
|
|
13
|
+
}): boolean {
|
|
14
|
+
const isUsingSpread: boolean = j(element).find(j.JSXSpreadAttribute).length > 0;
|
|
15
|
+
|
|
16
|
+
if (!isUsingSpread) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
j(element)
|
|
22
|
+
.find(j.JSXSpreadAttribute)
|
|
23
|
+
.filter((spread) => {
|
|
24
|
+
const argument = spread.value.argument;
|
|
25
|
+
// in place expression is supported
|
|
26
|
+
if (argument.type === 'ObjectExpression') {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Supporting identifiers that point to an a local object expression
|
|
31
|
+
if (argument.type === 'Identifier') {
|
|
32
|
+
return (
|
|
33
|
+
base.find(j.VariableDeclarator).filter((declarator): boolean => {
|
|
34
|
+
return (
|
|
35
|
+
declarator.value.id.type === 'Identifier' &&
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
declarator.value.init.type === 'ObjectExpression'
|
|
38
|
+
);
|
|
39
|
+
}).length > 0
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// We don't support anything else
|
|
44
|
+
return false;
|
|
45
|
+
}).length > 0
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type NodePath } from 'ast-types/lib/node-path';
|
|
2
|
+
import { type default as core, type JSXElement } from 'jscodeshift';
|
|
3
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
4
|
+
|
|
5
|
+
import { isUsingSupportedSpread } from './is-using-supported-spread';
|
|
6
|
+
|
|
7
|
+
export function isUsingThroughSpread({
|
|
8
|
+
j,
|
|
9
|
+
base,
|
|
10
|
+
element,
|
|
11
|
+
propName,
|
|
12
|
+
}: {
|
|
13
|
+
j: core.JSCodeshift;
|
|
14
|
+
base: Collection<any>;
|
|
15
|
+
element: NodePath<JSXElement, JSXElement>;
|
|
16
|
+
propName: string;
|
|
17
|
+
}): boolean {
|
|
18
|
+
if (!isUsingSupportedSpread({ j, base, element })) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const isUsedThroughExpression: boolean =
|
|
23
|
+
j(element)
|
|
24
|
+
.find(j.JSXSpreadAttribute)
|
|
25
|
+
.find(j.ObjectExpression)
|
|
26
|
+
.filter((item) => {
|
|
27
|
+
const match: boolean =
|
|
28
|
+
item.value.properties.filter(
|
|
29
|
+
(property) =>
|
|
30
|
+
property.type === 'ObjectProperty' &&
|
|
31
|
+
property.key.type === 'Identifier' &&
|
|
32
|
+
property.key.name === propName,
|
|
33
|
+
).length > 0;
|
|
34
|
+
|
|
35
|
+
return match;
|
|
36
|
+
}).length > 0;
|
|
37
|
+
|
|
38
|
+
if (isUsedThroughExpression) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const isUsedThroughIdentifier: boolean =
|
|
43
|
+
j(element)
|
|
44
|
+
.find(j.JSXSpreadAttribute)
|
|
45
|
+
.find(j.Identifier)
|
|
46
|
+
.filter((identifier): boolean => {
|
|
47
|
+
return (
|
|
48
|
+
base
|
|
49
|
+
.find(j.VariableDeclarator)
|
|
50
|
+
.filter(
|
|
51
|
+
(declarator) =>
|
|
52
|
+
declarator.value.id.type === 'Identifier' &&
|
|
53
|
+
declarator.value.id.name === identifier.value.name,
|
|
54
|
+
)
|
|
55
|
+
.filter((declarator) => {
|
|
56
|
+
const value = declarator.value;
|
|
57
|
+
if (value.id.type !== 'Identifier') {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (value.id.name !== identifier.value.name) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
if (value.init.type !== 'ObjectExpression') {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const match: boolean =
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
value.init.properties.filter(
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
(property) =>
|
|
74
|
+
property.type === 'ObjectProperty' &&
|
|
75
|
+
property.key.type === 'Identifier' &&
|
|
76
|
+
property.key.name === propName,
|
|
77
|
+
).length > 0;
|
|
78
|
+
|
|
79
|
+
return match;
|
|
80
|
+
}).length > 0
|
|
81
|
+
);
|
|
82
|
+
}).length > 0;
|
|
83
|
+
|
|
84
|
+
return isUsedThroughIdentifier;
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Nullable<T> = T | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ASTPath, type default as core, type JSXElement } from 'jscodeshift';
|
|
2
|
+
import { type Collection } from 'jscodeshift/src/Collection';
|
|
3
|
+
|
|
4
|
+
export function updateRenderProps(
|
|
5
|
+
j: core.JSCodeshift,
|
|
6
|
+
source: Collection<any>,
|
|
7
|
+
specifier: string,
|
|
8
|
+
oldProperty: string,
|
|
9
|
+
newProperty: string,
|
|
10
|
+
): void {
|
|
11
|
+
source.findJSXElements(specifier).forEach((element: ASTPath<JSXElement>) => {
|
|
12
|
+
j(element)
|
|
13
|
+
.find(j.ArrowFunctionExpression)
|
|
14
|
+
.find(j.ObjectPattern)
|
|
15
|
+
.find(j.ObjectProperty)
|
|
16
|
+
.filter(
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
(path: ASTPath<ObjectProperty>) => path.value.key.name === oldProperty,
|
|
19
|
+
)
|
|
20
|
+
.forEach((path) => {
|
|
21
|
+
j(path).replaceWith(
|
|
22
|
+
j.property('init', j.identifier(newProperty), j.identifier(oldProperty)),
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/select",
|
|
3
|
-
"version": "21.10.
|
|
3
|
+
"version": "21.10.2",
|
|
4
4
|
"description": "Select allows users to make a single selection or multiple selections from a list of options.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -25,6 +25,13 @@
|
|
|
25
25
|
],
|
|
26
26
|
"atlaskit:src": "src/index.tsx",
|
|
27
27
|
"atlassian": {
|
|
28
|
+
"react-compiler": {
|
|
29
|
+
"enabled": true,
|
|
30
|
+
"gating": {
|
|
31
|
+
"source": "@atlassian/react-compiler-gating",
|
|
32
|
+
"importSpecifierName": "isReactCompilerActivePlatform"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
28
35
|
"team": "Design System Team",
|
|
29
36
|
"website": {
|
|
30
37
|
"name": "Select",
|
|
@@ -66,9 +73,10 @@
|
|
|
66
73
|
"@atlaskit/link": "^3.3.0",
|
|
67
74
|
"@atlaskit/logo": "^19.10.0",
|
|
68
75
|
"@atlaskit/modal-dialog": "^14.14.0",
|
|
69
|
-
"@atlaskit/radio": "^8.
|
|
76
|
+
"@atlaskit/radio": "^8.5.0",
|
|
70
77
|
"@atlaskit/section-message": "^8.12.0",
|
|
71
78
|
"@atlassian/feature-flags-test-utils": "^1.0.0",
|
|
79
|
+
"@atlassian/react-compiler-gating": "workspace:^",
|
|
72
80
|
"@atlassian/ssr-tests": "workspace:^",
|
|
73
81
|
"@atlassian/structured-docs-types": "workspace:^",
|
|
74
82
|
"@testing-library/react": "^16.3.0",
|
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
import { type NodePath } from 'ast-types/lib/node-path';
|
|
2
|
-
import {
|
|
3
|
-
type ASTPath,
|
|
4
|
-
type default as core,
|
|
5
|
-
type ImportDeclaration,
|
|
6
|
-
type JSXAttribute,
|
|
7
|
-
type JSXElement,
|
|
8
|
-
type Node,
|
|
9
|
-
} from 'jscodeshift';
|
|
10
|
-
import { type Collection } from 'jscodeshift/src/Collection';
|
|
11
|
-
|
|
12
|
-
export type Nullable<T> = T | null;
|
|
13
|
-
|
|
14
|
-
export function hasImportDeclaration(
|
|
15
|
-
j: core.JSCodeshift,
|
|
16
|
-
source: string,
|
|
17
|
-
importPath: string,
|
|
18
|
-
): boolean {
|
|
19
|
-
return (
|
|
20
|
-
j(source)
|
|
21
|
-
.find(j.ImportDeclaration)
|
|
22
|
-
.filter((path: ASTPath<ImportDeclaration>) => path.node.source.value === importPath).length >
|
|
23
|
-
0
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function getDefaultSpecifierName({
|
|
28
|
-
j,
|
|
29
|
-
base,
|
|
30
|
-
packageName,
|
|
31
|
-
}: {
|
|
32
|
-
j: core.JSCodeshift;
|
|
33
|
-
base: Collection<any>;
|
|
34
|
-
packageName: string;
|
|
35
|
-
}): Nullable<string> {
|
|
36
|
-
const specifiers = base
|
|
37
|
-
.find(j.ImportDeclaration)
|
|
38
|
-
.filter((path) => path.node.source.value === packageName)
|
|
39
|
-
.find(j.ImportDefaultSpecifier);
|
|
40
|
-
|
|
41
|
-
if (!specifiers.length) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
return specifiers.nodes()[0]!.local!.name;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function getSpecifierName({
|
|
48
|
-
j,
|
|
49
|
-
base,
|
|
50
|
-
packageName,
|
|
51
|
-
component,
|
|
52
|
-
}: {
|
|
53
|
-
j: core.JSCodeshift;
|
|
54
|
-
base: Collection<any>;
|
|
55
|
-
packageName: string;
|
|
56
|
-
component: string;
|
|
57
|
-
}): Nullable<string> {
|
|
58
|
-
const specifiers = base
|
|
59
|
-
.find(j.ImportDeclaration)
|
|
60
|
-
.filter((path) => path.node.source.value === packageName)
|
|
61
|
-
.find(j.ImportSpecifier);
|
|
62
|
-
|
|
63
|
-
if (!specifiers.length) {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
const specifierNode = specifiers.nodes().find((node) => node.imported.name === component);
|
|
67
|
-
if (!specifierNode) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
// @ts-ignore
|
|
71
|
-
return specifierNode.local.name;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function getJSXAttributesByName({
|
|
75
|
-
j,
|
|
76
|
-
element,
|
|
77
|
-
attributeName,
|
|
78
|
-
}: {
|
|
79
|
-
j: core.JSCodeshift;
|
|
80
|
-
element: JSXElement | ASTPath<JSXElement>;
|
|
81
|
-
attributeName: string;
|
|
82
|
-
}): Collection<JSXAttribute> {
|
|
83
|
-
return j(element)
|
|
84
|
-
.find(j.JSXOpeningElement)
|
|
85
|
-
.find(j.JSXAttribute)
|
|
86
|
-
.filter((attribute) => {
|
|
87
|
-
const matches = j(attribute)
|
|
88
|
-
.find(j.JSXIdentifier)
|
|
89
|
-
.filter((identifier) => identifier.value.name === attributeName);
|
|
90
|
-
return Boolean(matches.length);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function hasJSXAttributesByName({
|
|
95
|
-
j,
|
|
96
|
-
element,
|
|
97
|
-
attributeName,
|
|
98
|
-
}: {
|
|
99
|
-
j: core.JSCodeshift;
|
|
100
|
-
element: JSXElement;
|
|
101
|
-
attributeName: string;
|
|
102
|
-
}): boolean {
|
|
103
|
-
return getJSXAttributesByName({ j, element, attributeName }).length > 0;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function isUsingSupportedSpread({
|
|
107
|
-
j,
|
|
108
|
-
base,
|
|
109
|
-
element,
|
|
110
|
-
}: {
|
|
111
|
-
j: core.JSCodeshift;
|
|
112
|
-
base: Collection<any>;
|
|
113
|
-
element: NodePath<JSXElement, JSXElement>;
|
|
114
|
-
}): boolean {
|
|
115
|
-
const isUsingSpread: boolean = j(element).find(j.JSXSpreadAttribute).length > 0;
|
|
116
|
-
|
|
117
|
-
if (!isUsingSpread) {
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
j(element)
|
|
123
|
-
.find(j.JSXSpreadAttribute)
|
|
124
|
-
.filter((spread) => {
|
|
125
|
-
const argument = spread.value.argument;
|
|
126
|
-
// in place expression is supported
|
|
127
|
-
if (argument.type === 'ObjectExpression') {
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Supporting identifiers that point to an a local object expression
|
|
132
|
-
if (argument.type === 'Identifier') {
|
|
133
|
-
return (
|
|
134
|
-
base.find(j.VariableDeclarator).filter((declarator): boolean => {
|
|
135
|
-
return (
|
|
136
|
-
declarator.value.id.type === 'Identifier' &&
|
|
137
|
-
// @ts-ignore
|
|
138
|
-
declarator.value.init.type === 'ObjectExpression'
|
|
139
|
-
);
|
|
140
|
-
}).length > 0
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// We don't support anything else
|
|
145
|
-
return false;
|
|
146
|
-
}).length > 0
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export function isUsingThroughSpread({
|
|
151
|
-
j,
|
|
152
|
-
base,
|
|
153
|
-
element,
|
|
154
|
-
propName,
|
|
155
|
-
}: {
|
|
156
|
-
j: core.JSCodeshift;
|
|
157
|
-
base: Collection<any>;
|
|
158
|
-
element: NodePath<JSXElement, JSXElement>;
|
|
159
|
-
propName: string;
|
|
160
|
-
}): boolean {
|
|
161
|
-
if (!isUsingSupportedSpread({ j, base, element })) {
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const isUsedThroughExpression: boolean =
|
|
166
|
-
j(element)
|
|
167
|
-
.find(j.JSXSpreadAttribute)
|
|
168
|
-
.find(j.ObjectExpression)
|
|
169
|
-
.filter((item) => {
|
|
170
|
-
const match: boolean =
|
|
171
|
-
item.value.properties.filter(
|
|
172
|
-
(property) =>
|
|
173
|
-
property.type === 'ObjectProperty' &&
|
|
174
|
-
property.key.type === 'Identifier' &&
|
|
175
|
-
property.key.name === propName,
|
|
176
|
-
).length > 0;
|
|
177
|
-
|
|
178
|
-
return match;
|
|
179
|
-
}).length > 0;
|
|
180
|
-
|
|
181
|
-
if (isUsedThroughExpression) {
|
|
182
|
-
return true;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const isUsedThroughIdentifier: boolean =
|
|
186
|
-
j(element)
|
|
187
|
-
.find(j.JSXSpreadAttribute)
|
|
188
|
-
.find(j.Identifier)
|
|
189
|
-
.filter((identifier): boolean => {
|
|
190
|
-
return (
|
|
191
|
-
base
|
|
192
|
-
.find(j.VariableDeclarator)
|
|
193
|
-
.filter(
|
|
194
|
-
(declarator) =>
|
|
195
|
-
declarator.value.id.type === 'Identifier' &&
|
|
196
|
-
declarator.value.id.name === identifier.value.name,
|
|
197
|
-
)
|
|
198
|
-
.filter((declarator) => {
|
|
199
|
-
const value = declarator.value;
|
|
200
|
-
if (value.id.type !== 'Identifier') {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (value.id.name !== identifier.value.name) {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
// @ts-ignore
|
|
208
|
-
if (value.init.type !== 'ObjectExpression') {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const match: boolean =
|
|
213
|
-
// @ts-ignore
|
|
214
|
-
value.init.properties.filter(
|
|
215
|
-
// @ts-ignore
|
|
216
|
-
(property) =>
|
|
217
|
-
property.type === 'ObjectProperty' &&
|
|
218
|
-
property.key.type === 'Identifier' &&
|
|
219
|
-
property.key.name === propName,
|
|
220
|
-
).length > 0;
|
|
221
|
-
|
|
222
|
-
return match;
|
|
223
|
-
}).length > 0
|
|
224
|
-
);
|
|
225
|
-
}).length > 0;
|
|
226
|
-
|
|
227
|
-
return isUsedThroughIdentifier;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export function isUsingProp({
|
|
231
|
-
j,
|
|
232
|
-
base,
|
|
233
|
-
element,
|
|
234
|
-
propName,
|
|
235
|
-
}: {
|
|
236
|
-
j: core.JSCodeshift;
|
|
237
|
-
base: Collection<any>;
|
|
238
|
-
element: NodePath<JSXElement, JSXElement>;
|
|
239
|
-
propName: string;
|
|
240
|
-
}): boolean {
|
|
241
|
-
return (
|
|
242
|
-
hasJSXAttributesByName({
|
|
243
|
-
j,
|
|
244
|
-
element: element.value,
|
|
245
|
-
attributeName: propName,
|
|
246
|
-
}) ||
|
|
247
|
-
isUsingThroughSpread({
|
|
248
|
-
j,
|
|
249
|
-
base,
|
|
250
|
-
element,
|
|
251
|
-
propName,
|
|
252
|
-
})
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// not replacing newlines (which \s does)
|
|
257
|
-
const spacesAndTabs: RegExp = /[ \t]{2,}/g;
|
|
258
|
-
const lineStartWithSpaces: RegExp = /^[ \t]*/gm;
|
|
259
|
-
|
|
260
|
-
function clean(value: string): string {
|
|
261
|
-
return (
|
|
262
|
-
value
|
|
263
|
-
.replace(spacesAndTabs, ' ')
|
|
264
|
-
.replace(lineStartWithSpaces, '')
|
|
265
|
-
// using .trim() to clear the any newlines before the first text and after last text
|
|
266
|
-
.trim()
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export function addCommentToStartOfFile({
|
|
271
|
-
j,
|
|
272
|
-
base,
|
|
273
|
-
message,
|
|
274
|
-
}: {
|
|
275
|
-
j: core.JSCodeshift;
|
|
276
|
-
base: Collection<Node>;
|
|
277
|
-
message: string;
|
|
278
|
-
}): void {
|
|
279
|
-
addCommentBefore({
|
|
280
|
-
j,
|
|
281
|
-
// @ts-ignore
|
|
282
|
-
target: base.find(j.Program),
|
|
283
|
-
message,
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
export function addCommentBefore({
|
|
288
|
-
j,
|
|
289
|
-
target,
|
|
290
|
-
message,
|
|
291
|
-
}: {
|
|
292
|
-
j: core.JSCodeshift;
|
|
293
|
-
target: Collection<Node>;
|
|
294
|
-
message: string;
|
|
295
|
-
}): void {
|
|
296
|
-
const content: string = ` TODO: (from codemod) ${clean(message)} `;
|
|
297
|
-
target.forEach((path) => {
|
|
298
|
-
path.value.comments = path.value.comments || [];
|
|
299
|
-
|
|
300
|
-
const exists = path.value.comments.find((comment) => comment.value === content);
|
|
301
|
-
|
|
302
|
-
// avoiding duplicates of the same comment
|
|
303
|
-
if (exists) {
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
path.value.comments.push(j.commentBlock(content));
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export function updateRenderProps(
|
|
312
|
-
j: core.JSCodeshift,
|
|
313
|
-
source: Collection<any>,
|
|
314
|
-
specifier: string,
|
|
315
|
-
oldProperty: string,
|
|
316
|
-
newProperty: string,
|
|
317
|
-
): void {
|
|
318
|
-
source.findJSXElements(specifier).forEach((element: ASTPath<JSXElement>) => {
|
|
319
|
-
j(element)
|
|
320
|
-
.find(j.ArrowFunctionExpression)
|
|
321
|
-
.find(j.ObjectPattern)
|
|
322
|
-
.find(j.ObjectProperty)
|
|
323
|
-
.filter(
|
|
324
|
-
// @ts-ignore
|
|
325
|
-
(path: ASTPath<ObjectProperty>) => path.value.key.name === oldProperty,
|
|
326
|
-
)
|
|
327
|
-
.forEach((path) => {
|
|
328
|
-
j(path).replaceWith(
|
|
329
|
-
j.property('init', j.identifier(newProperty), j.identifier(oldProperty)),
|
|
330
|
-
);
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
}
|