@carbon/upgrade 11.42.0 → 11.43.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/README.md +53 -1
- package/cli.js +247 -133
- package/package.json +4 -4
- package/transforms/__testfixtures__/enable-v12-release-aliased.input.tsx +20 -0
- package/transforms/__testfixtures__/enable-v12-release-aliased.output.tsx +22 -0
- package/transforms/__testfixtures__/enable-v12-release.input.tsx +22 -0
- package/transforms/__testfixtures__/enable-v12-release.output.tsx +30 -0
- package/transforms/__tests__/enable-v12-release-test.js +35 -0
- package/transforms/enable-v12-release.js +406 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carbon/upgrade",
|
|
3
3
|
"description": "A tool for upgrading Carbon versions",
|
|
4
|
-
"version": "11.
|
|
4
|
+
"version": "11.43.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
7
7
|
"carbon-upgrade": "./bin/carbon-upgrade.js"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"postinstall": "ibmtelemetry --config=telemetry.yml"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"chalk": "^
|
|
42
|
+
"chalk": "^6.0.0",
|
|
43
43
|
"execa": "^9.6.0",
|
|
44
44
|
"fast-glob": "^3.3.3",
|
|
45
45
|
"fs-extra": "^11.0.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"lodash.clonedeep": "^4.5.0",
|
|
50
50
|
"lodash.merge": "^4.6.2",
|
|
51
51
|
"memfs": "^4.0.0",
|
|
52
|
-
"nanoid": "^
|
|
52
|
+
"nanoid": "^6.0.0",
|
|
53
53
|
"npm-which": "^3.0.1",
|
|
54
54
|
"rimraf": "^6.0.1",
|
|
55
55
|
"semver": "^7.7.2",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"@ibm/telemetry-js": "^1.5.0",
|
|
61
61
|
"jscodeshift": "^17.0.0"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "188d23202ec1092322dee92cf0df9d9958224ae4"
|
|
64
64
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as Carbon from '@carbon/react';
|
|
2
|
+
import { createRoot as mountRoot } from 'react-dom/client';
|
|
3
|
+
import App from './App';
|
|
4
|
+
|
|
5
|
+
const root = mountRoot(document.getElementById('root')!);
|
|
6
|
+
root.render(
|
|
7
|
+
<Carbon.FeatureFlags enableV12Release={false} {...featureFlags}>
|
|
8
|
+
<App />
|
|
9
|
+
</Carbon.FeatureFlags>
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const unwrappedRoot = mountRoot(document.getElementById('unwrapped-root')!);
|
|
13
|
+
unwrappedRoot.render(<App />);
|
|
14
|
+
|
|
15
|
+
const wrappedRoot = mountRoot(document.getElementById('wrapped-root')!);
|
|
16
|
+
wrappedRoot.render(
|
|
17
|
+
<Carbon.FeatureFlags>
|
|
18
|
+
<App />
|
|
19
|
+
</Carbon.FeatureFlags>
|
|
20
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as Carbon from '@carbon/react';
|
|
2
|
+
import { createRoot as mountRoot } from 'react-dom/client';
|
|
3
|
+
import App from './App';
|
|
4
|
+
|
|
5
|
+
const root = mountRoot(document.getElementById('root')!);
|
|
6
|
+
root.render(
|
|
7
|
+
<Carbon.FeatureFlags {...featureFlags} enableV12Release>
|
|
8
|
+
<App />
|
|
9
|
+
</Carbon.FeatureFlags>
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const unwrappedRoot = mountRoot(document.getElementById('unwrapped-root')!);
|
|
13
|
+
unwrappedRoot.render(<Carbon.FeatureFlags enableV12Release>
|
|
14
|
+
<App />
|
|
15
|
+
</Carbon.FeatureFlags>);
|
|
16
|
+
|
|
17
|
+
const wrappedRoot = mountRoot(document.getElementById('wrapped-root')!);
|
|
18
|
+
wrappedRoot.render(
|
|
19
|
+
<Carbon.FeatureFlags enableV12Release>
|
|
20
|
+
<App />
|
|
21
|
+
</Carbon.FeatureFlags>
|
|
22
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import ReactDOMClient, { createRoot, hydrateRoot } from 'react-dom/client';
|
|
4
|
+
import { Button } from '@carbon/react';
|
|
5
|
+
import App from './App';
|
|
6
|
+
|
|
7
|
+
const root = createRoot(document.getElementById('root'));
|
|
8
|
+
root.render(
|
|
9
|
+
<React.StrictMode>
|
|
10
|
+
<App />
|
|
11
|
+
</React.StrictMode>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
ReactDOM.render(<App />, document.getElementById('legacy-root'));
|
|
15
|
+
|
|
16
|
+
hydrateRoot(document.getElementById('hydrated-root'), <App />);
|
|
17
|
+
|
|
18
|
+
ReactDOMClient.createRoot(document.getElementById('chained-root')).render(
|
|
19
|
+
<App />
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const preview = <App />;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import ReactDOMClient, { createRoot, hydrateRoot } from 'react-dom/client';
|
|
4
|
+
import { Button, FeatureFlags } from '@carbon/react';
|
|
5
|
+
import App from './App';
|
|
6
|
+
|
|
7
|
+
const root = createRoot(document.getElementById('root'));
|
|
8
|
+
root.render(
|
|
9
|
+
<FeatureFlags enableV12Release>
|
|
10
|
+
<React.StrictMode>
|
|
11
|
+
<App />
|
|
12
|
+
</React.StrictMode>
|
|
13
|
+
</FeatureFlags>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
ReactDOM.render(<FeatureFlags enableV12Release>
|
|
17
|
+
<App />
|
|
18
|
+
</FeatureFlags>, document.getElementById('legacy-root'));
|
|
19
|
+
|
|
20
|
+
hydrateRoot(document.getElementById('hydrated-root'), <FeatureFlags enableV12Release>
|
|
21
|
+
<App />
|
|
22
|
+
</FeatureFlags>);
|
|
23
|
+
|
|
24
|
+
ReactDOMClient.createRoot(document.getElementById('chained-root')).render(
|
|
25
|
+
<FeatureFlags enableV12Release>
|
|
26
|
+
<App />
|
|
27
|
+
</FeatureFlags>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const preview = <App />;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment node
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Copyright IBM Corp. 2026
|
|
7
|
+
*
|
|
8
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
9
|
+
* LICENSE file in the root directory of this source tree.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const { defineTest, applyTransform } = require('jscodeshift/dist/testUtils');
|
|
15
|
+
const transform = require('../enable-v12-release');
|
|
16
|
+
|
|
17
|
+
defineTest(__dirname, 'enable-v12-release');
|
|
18
|
+
defineTest(__dirname, 'enable-v12-release', null, 'enable-v12-release-aliased');
|
|
19
|
+
|
|
20
|
+
it('does not change an application with the v12 release flag enabled', () => {
|
|
21
|
+
const source = `
|
|
22
|
+
import { FeatureFlags } from '@carbon/react';
|
|
23
|
+
import { createRoot } from 'react-dom/client';
|
|
24
|
+
import App from './App';
|
|
25
|
+
|
|
26
|
+
const root = createRoot(document.getElementById('root'));
|
|
27
|
+
root.render(
|
|
28
|
+
<FeatureFlags enableV12Release>
|
|
29
|
+
<App />
|
|
30
|
+
</FeatureFlags>
|
|
31
|
+
);
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
expect(applyTransform(transform, {}, { source })).toBe('');
|
|
35
|
+
});
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright IBM Corp. 2026
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Wrap the application passed to a React root with the v12 release feature flag.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const defaultOptions = {
|
|
15
|
+
quote: 'single',
|
|
16
|
+
trailingComma: true,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function transform(fileInfo, api, options) {
|
|
20
|
+
const j = api.jscodeshift;
|
|
21
|
+
const root = j(fileInfo.source);
|
|
22
|
+
const printOptions = options.printOptions || defaultOptions;
|
|
23
|
+
const reactDomBindings = getReactDomBindings(root, j);
|
|
24
|
+
const reactRootBindings = getReactRootBindings(root, j, reactDomBindings);
|
|
25
|
+
const renderArguments = findRenderArguments(
|
|
26
|
+
root,
|
|
27
|
+
j,
|
|
28
|
+
reactDomBindings,
|
|
29
|
+
reactRootBindings
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (renderArguments.length === 0) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const featureFlags = getFeatureFlagsReference(root, j);
|
|
37
|
+
let didChange = false;
|
|
38
|
+
|
|
39
|
+
for (const argumentPath of renderArguments) {
|
|
40
|
+
const application = argumentPath.node;
|
|
41
|
+
|
|
42
|
+
if (isNamedJSXElement(application, featureFlags.jsxName)) {
|
|
43
|
+
didChange = enableV12Release(application.openingElement, j) || didChange;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
argumentPath.replace(
|
|
48
|
+
createFeatureFlagsWrapper(application, featureFlags, j)
|
|
49
|
+
);
|
|
50
|
+
didChange = true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!didChange) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (featureFlags.needsImport) {
|
|
58
|
+
addFeatureFlagsImport(root, featureFlags, j);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return root.toSource(printOptions);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getReactDomBindings(root, j) {
|
|
65
|
+
const bindings = {
|
|
66
|
+
createRoot: new Set(),
|
|
67
|
+
hydrateRoot: new Set(),
|
|
68
|
+
render: new Set(),
|
|
69
|
+
reactDom: new Set(),
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
root
|
|
73
|
+
.find(j.ImportDeclaration)
|
|
74
|
+
.filter(
|
|
75
|
+
(path) =>
|
|
76
|
+
path.node.source.value === 'react-dom' ||
|
|
77
|
+
path.node.source.value === 'react-dom/client'
|
|
78
|
+
)
|
|
79
|
+
.forEach((path) => {
|
|
80
|
+
const source = path.node.source.value;
|
|
81
|
+
|
|
82
|
+
for (const specifier of path.node.specifiers) {
|
|
83
|
+
if (
|
|
84
|
+
specifier.type === 'ImportDefaultSpecifier' ||
|
|
85
|
+
specifier.type === 'ImportNamespaceSpecifier'
|
|
86
|
+
) {
|
|
87
|
+
bindings.reactDom.add(specifier.local.name);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (
|
|
92
|
+
specifier.type !== 'ImportSpecifier' ||
|
|
93
|
+
path.node.importKind === 'type' ||
|
|
94
|
+
specifier.importKind === 'type'
|
|
95
|
+
) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const importedName = specifier.imported.name;
|
|
100
|
+
if (
|
|
101
|
+
source === 'react-dom/client' &&
|
|
102
|
+
(importedName === 'createRoot' || importedName === 'hydrateRoot')
|
|
103
|
+
) {
|
|
104
|
+
bindings[importedName].add(specifier.local.name);
|
|
105
|
+
} else if (source === 'react-dom' && importedName === 'render') {
|
|
106
|
+
bindings.render.add(specifier.local.name);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return bindings;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getReactRootBindings(root, j, reactDomBindings) {
|
|
115
|
+
const rootBindings = new Set();
|
|
116
|
+
|
|
117
|
+
root.find(j.VariableDeclarator).forEach((path) => {
|
|
118
|
+
if (
|
|
119
|
+
path.node.id.type === 'Identifier' &&
|
|
120
|
+
isCreateRootCall(path.node.init, reactDomBindings)
|
|
121
|
+
) {
|
|
122
|
+
rootBindings.add(path.node.id.name);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
root.find(j.AssignmentExpression).forEach((path) => {
|
|
127
|
+
if (
|
|
128
|
+
path.node.left.type === 'Identifier' &&
|
|
129
|
+
isCreateRootCall(path.node.right, reactDomBindings)
|
|
130
|
+
) {
|
|
131
|
+
rootBindings.add(path.node.left.name);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return rootBindings;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function findRenderArguments(root, j, reactDomBindings, reactRootBindings) {
|
|
139
|
+
const argumentsToWrap = [];
|
|
140
|
+
|
|
141
|
+
root.find(j.CallExpression).forEach((path) => {
|
|
142
|
+
const { callee } = path.node;
|
|
143
|
+
|
|
144
|
+
if (isHydrateRootCall(path.node, reactDomBindings)) {
|
|
145
|
+
addJSXArgument(path, 1, argumentsToWrap);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (
|
|
150
|
+
callee.type === 'Identifier' &&
|
|
151
|
+
reactDomBindings.render.has(callee.name)
|
|
152
|
+
) {
|
|
153
|
+
addJSXArgument(path, 0, argumentsToWrap);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!isMemberCall(callee, 'render') && !isMemberCall(callee, 'hydrate')) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (
|
|
162
|
+
(callee.object.type === 'Identifier' &&
|
|
163
|
+
(reactRootBindings.has(callee.object.name) ||
|
|
164
|
+
reactDomBindings.reactDom.has(callee.object.name))) ||
|
|
165
|
+
isCreateRootCall(callee.object, reactDomBindings)
|
|
166
|
+
) {
|
|
167
|
+
addJSXArgument(path, 0, argumentsToWrap);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
return argumentsToWrap;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function addJSXArgument(callPath, argumentIndex, argumentsToWrap) {
|
|
175
|
+
const argument = callPath.node.arguments[argumentIndex];
|
|
176
|
+
if (argument?.type === 'JSXElement' || argument?.type === 'JSXFragment') {
|
|
177
|
+
argumentsToWrap.push(callPath.get('arguments', argumentIndex));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function isCreateRootCall(node, reactDomBindings) {
|
|
182
|
+
if (!node || node.type !== 'CallExpression') {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
node.callee.type === 'Identifier' &&
|
|
188
|
+
reactDomBindings.createRoot.has(node.callee.name)
|
|
189
|
+
) {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
isMemberCall(node.callee, 'createRoot') &&
|
|
195
|
+
node.callee.object.type === 'Identifier' &&
|
|
196
|
+
reactDomBindings.reactDom.has(node.callee.object.name)
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function isHydrateRootCall(node, reactDomBindings) {
|
|
201
|
+
if (node.callee.type === 'Identifier') {
|
|
202
|
+
return reactDomBindings.hydrateRoot.has(node.callee.name);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
isMemberCall(node.callee, 'hydrateRoot') &&
|
|
207
|
+
node.callee.object.type === 'Identifier' &&
|
|
208
|
+
reactDomBindings.reactDom.has(node.callee.object.name)
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function isMemberCall(callee, propertyName) {
|
|
213
|
+
if (
|
|
214
|
+
callee.type !== 'MemberExpression' &&
|
|
215
|
+
callee.type !== 'OptionalMemberExpression'
|
|
216
|
+
) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (callee.computed) {
|
|
221
|
+
return (
|
|
222
|
+
(callee.property.type === 'Literal' ||
|
|
223
|
+
callee.property.type === 'StringLiteral') &&
|
|
224
|
+
callee.property.value === propertyName
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
callee.property.type === 'Identifier' &&
|
|
230
|
+
callee.property.name === propertyName
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function getFeatureFlagsReference(root, j) {
|
|
235
|
+
const carbonImports = root
|
|
236
|
+
.find(j.ImportDeclaration, {
|
|
237
|
+
source: { value: '@carbon/react' },
|
|
238
|
+
})
|
|
239
|
+
.paths();
|
|
240
|
+
|
|
241
|
+
for (const path of carbonImports) {
|
|
242
|
+
if (path.node.importKind === 'type') {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
for (const specifier of path.node.specifiers) {
|
|
247
|
+
if (
|
|
248
|
+
specifier.type === 'ImportSpecifier' &&
|
|
249
|
+
specifier.importKind !== 'type' &&
|
|
250
|
+
specifier.imported.name === 'FeatureFlags'
|
|
251
|
+
) {
|
|
252
|
+
return {
|
|
253
|
+
importName: specifier.local.name,
|
|
254
|
+
jsxName: j.jsxIdentifier(specifier.local.name),
|
|
255
|
+
needsImport: false,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
260
|
+
return {
|
|
261
|
+
importName: null,
|
|
262
|
+
jsxName: j.jsxMemberExpression(
|
|
263
|
+
j.jsxIdentifier(specifier.local.name),
|
|
264
|
+
j.jsxIdentifier('FeatureFlags')
|
|
265
|
+
),
|
|
266
|
+
needsImport: false,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const importName = getAvailableImportName(root, j);
|
|
273
|
+
return {
|
|
274
|
+
importName,
|
|
275
|
+
jsxName: j.jsxIdentifier(importName),
|
|
276
|
+
needsImport: true,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function getAvailableImportName(root, j) {
|
|
281
|
+
let importName = 'FeatureFlags';
|
|
282
|
+
let suffix = 2;
|
|
283
|
+
|
|
284
|
+
while (
|
|
285
|
+
root.find(j.Identifier, { name: importName }).size() > 0 ||
|
|
286
|
+
root.find(j.JSXIdentifier, { name: importName }).size() > 0
|
|
287
|
+
) {
|
|
288
|
+
importName = `CarbonFeatureFlags${suffix === 2 ? '' : suffix}`;
|
|
289
|
+
suffix++;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return importName;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function addFeatureFlagsImport(root, featureFlags, j) {
|
|
296
|
+
const carbonImport = root
|
|
297
|
+
.find(j.ImportDeclaration, {
|
|
298
|
+
source: { value: '@carbon/react' },
|
|
299
|
+
})
|
|
300
|
+
.filter(
|
|
301
|
+
(path) =>
|
|
302
|
+
path.node.importKind !== 'type' &&
|
|
303
|
+
!path.node.specifiers.some(
|
|
304
|
+
(specifier) => specifier.type === 'ImportNamespaceSpecifier'
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
.at(0);
|
|
308
|
+
const local =
|
|
309
|
+
featureFlags.importName === 'FeatureFlags'
|
|
310
|
+
? null
|
|
311
|
+
: j.identifier(featureFlags.importName);
|
|
312
|
+
const specifier = j.importSpecifier(j.identifier('FeatureFlags'), local);
|
|
313
|
+
|
|
314
|
+
if (carbonImport.size() > 0) {
|
|
315
|
+
carbonImport.get().node.specifiers.push(specifier);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const declaration = j.importDeclaration(
|
|
320
|
+
[specifier],
|
|
321
|
+
j.literal('@carbon/react')
|
|
322
|
+
);
|
|
323
|
+
const lastImport = root.find(j.ImportDeclaration).at(-1);
|
|
324
|
+
|
|
325
|
+
if (lastImport.size() > 0) {
|
|
326
|
+
lastImport.insertAfter(declaration);
|
|
327
|
+
} else {
|
|
328
|
+
root.get().node.program.body.unshift(declaration);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function isNamedJSXElement(node, expectedName) {
|
|
333
|
+
return (
|
|
334
|
+
node.type === 'JSXElement' &&
|
|
335
|
+
areJSXNamesEqual(node.openingElement.name, expectedName)
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function areJSXNamesEqual(actual, expected) {
|
|
340
|
+
if (actual.type !== expected.type) {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (actual.type === 'JSXIdentifier') {
|
|
345
|
+
return actual.name === expected.name;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (actual.type === 'JSXMemberExpression') {
|
|
349
|
+
return (
|
|
350
|
+
areJSXNamesEqual(actual.object, expected.object) &&
|
|
351
|
+
areJSXNamesEqual(actual.property, expected.property)
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function enableV12Release(openingElement, j) {
|
|
359
|
+
const attributes = openingElement.attributes;
|
|
360
|
+
const releaseAttributes = attributes.filter(
|
|
361
|
+
(attribute) =>
|
|
362
|
+
attribute.type === 'JSXAttribute' &&
|
|
363
|
+
attribute.name.name === 'enableV12Release'
|
|
364
|
+
);
|
|
365
|
+
const lastAttribute = attributes[attributes.length - 1];
|
|
366
|
+
const isEnabled =
|
|
367
|
+
releaseAttributes.length === 1 &&
|
|
368
|
+
releaseAttributes[0] === lastAttribute &&
|
|
369
|
+
(lastAttribute.value === null ||
|
|
370
|
+
(lastAttribute.value.type === 'JSXExpressionContainer' &&
|
|
371
|
+
(lastAttribute.value.expression.type === 'BooleanLiteral' ||
|
|
372
|
+
lastAttribute.value.expression.type === 'Literal') &&
|
|
373
|
+
lastAttribute.value.expression.value === true));
|
|
374
|
+
|
|
375
|
+
if (isEnabled) {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
openingElement.attributes = attributes
|
|
380
|
+
.filter(
|
|
381
|
+
(attribute) =>
|
|
382
|
+
attribute.type !== 'JSXAttribute' ||
|
|
383
|
+
attribute.name.name !== 'enableV12Release'
|
|
384
|
+
)
|
|
385
|
+
.concat(j.jsxAttribute(j.jsxIdentifier('enableV12Release')));
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function createFeatureFlagsWrapper(application, featureFlags, j) {
|
|
390
|
+
return j.jsxElement(
|
|
391
|
+
j.jsxOpeningElement(
|
|
392
|
+
cloneJSXName(featureFlags.jsxName),
|
|
393
|
+
[j.jsxAttribute(j.jsxIdentifier('enableV12Release'))],
|
|
394
|
+
false
|
|
395
|
+
),
|
|
396
|
+
j.jsxClosingElement(cloneJSXName(featureFlags.jsxName)),
|
|
397
|
+
[j.jsxText('\n'), application, j.jsxText('\n')]
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function cloneJSXName(name) {
|
|
402
|
+
return JSON.parse(JSON.stringify(name));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
module.exports = transform;
|
|
406
|
+
module.exports.parser = 'tsx';
|