@octaviaflow/upgrade 1.0.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.
Files changed (58) hide show
  1. package/README.md +97 -0
  2. package/bin/carbon-upgrade.js +48 -0
  3. package/cli.js +53573 -0
  4. package/package.json +56 -0
  5. package/telemetry.yml +17 -0
  6. package/transforms/ARCHITECTURE.md +47 -0
  7. package/transforms/__testfixtures__/featureflag-deprecate-flags-prop.input.js +143 -0
  8. package/transforms/__testfixtures__/featureflag-deprecate-flags-prop.output.js +133 -0
  9. package/transforms/__testfixtures__/ibm-products-update-userprofileimage.input.js +57 -0
  10. package/transforms/__testfixtures__/ibm-products-update-userprofileimage.output.js +50 -0
  11. package/transforms/__testfixtures__/icons-react-size-prop-object-key.input.js +25 -0
  12. package/transforms/__testfixtures__/icons-react-size-prop-object-key.output.js +25 -0
  13. package/transforms/__testfixtures__/icons-react-size-prop-rename.input.js +53 -0
  14. package/transforms/__testfixtures__/icons-react-size-prop-rename.output.js +53 -0
  15. package/transforms/__testfixtures__/icons-react-size-prop-with-prop.input.js +25 -0
  16. package/transforms/__testfixtures__/icons-react-size-prop-with-prop.output.js +28 -0
  17. package/transforms/__testfixtures__/refactor-light-to-layer.input.js +23 -0
  18. package/transforms/__testfixtures__/refactor-light-to-layer.output.js +23 -0
  19. package/transforms/__testfixtures__/refactor-to-callout.input.js +34 -0
  20. package/transforms/__testfixtures__/refactor-to-callout.output.js +32 -0
  21. package/transforms/__testfixtures__/refactor-to-callout2.input.js +13 -0
  22. package/transforms/__testfixtures__/refactor-to-callout2.output.js +13 -0
  23. package/transforms/__testfixtures__/refactor-to-callout3.input.js +14 -0
  24. package/transforms/__testfixtures__/refactor-to-callout3.output.js +14 -0
  25. package/transforms/__testfixtures__/refactor-to-callout4.input.js +12 -0
  26. package/transforms/__testfixtures__/refactor-to-callout4.output.js +12 -0
  27. package/transforms/__testfixtures__/size-prop-update.input.js +152 -0
  28. package/transforms/__testfixtures__/size-prop-update.output.js +152 -0
  29. package/transforms/__testfixtures__/small-to-size-prop.input.js +20 -0
  30. package/transforms/__testfixtures__/small-to-size-prop.output.js +19 -0
  31. package/transforms/__testfixtures__/sort-prop-types.input.js +16 -0
  32. package/transforms/__testfixtures__/sort-prop-types.output.js +16 -0
  33. package/transforms/__testfixtures__/sort-prop-types2.input.js +16 -0
  34. package/transforms/__testfixtures__/sort-prop-types2.output.js +16 -0
  35. package/transforms/__testfixtures__/update-carbon-components-react-import-to-scoped.input.js +17 -0
  36. package/transforms/__testfixtures__/update-carbon-components-react-import-to-scoped.output.js +17 -0
  37. package/transforms/__testfixtures__/update-carbon-icons-react-import-to-carbon-react.input.js +17 -0
  38. package/transforms/__testfixtures__/update-carbon-icons-react-import-to-carbon-react.output.js +17 -0
  39. package/transforms/__tests__/featureflag-deprecate-flags-prop-test.js +15 -0
  40. package/transforms/__tests__/ibm-products-update-userprofileimage-test.js +21 -0
  41. package/transforms/__tests__/icons-react-size-prop.js +67 -0
  42. package/transforms/__tests__/refactor-light-to-layer-test.js +14 -0
  43. package/transforms/__tests__/refactor-to-callout.js +18 -0
  44. package/transforms/__tests__/size-prop-update-test.js +15 -0
  45. package/transforms/__tests__/small-to-size-test.js +15 -0
  46. package/transforms/__tests__/sort-prop-types-test.js +16 -0
  47. package/transforms/__tests__/update-carbon-components-react-import-to-scoped.js +15 -0
  48. package/transforms/__tests__/update-carbon-icons-react-import-to-carbon-react.js +15 -0
  49. package/transforms/featureflag-deprecate-flags-prop.js +89 -0
  50. package/transforms/ibm-products-update-userprofileimage.js +134 -0
  51. package/transforms/icons-react-size-prop.js +327 -0
  52. package/transforms/refactor-light-to-layer.js +117 -0
  53. package/transforms/refactor-to-callout.js +160 -0
  54. package/transforms/size-prop-update.js +143 -0
  55. package/transforms/small-to-size-prop.js +59 -0
  56. package/transforms/sort-prop-types.js +91 -0
  57. package/transforms/update-carbon-components-react-import-to-scoped.js +42 -0
  58. package/transforms/update-carbon-icons-react-import-to-carbon-react.js +42 -0
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+
11
+ 'use strict';
12
+
13
+ const defaultOptions = {
14
+ quote: 'auto',
15
+ trailingComma: true,
16
+ };
17
+ const defaultSize = 16;
18
+
19
+ function transform(fileInfo, api, options) {
20
+ const printOptions = options.printOptions || defaultOptions;
21
+ const j = api.jscodeshift;
22
+ const root = j(fileInfo.source);
23
+
24
+ // Find all the import declarations that come from `@octaviaflow/icons-react`
25
+ const matches = root.find(j.ImportDeclaration, {
26
+ source: {
27
+ value: '@octaviaflow/icons-react',
28
+ },
29
+ });
30
+
31
+ // If we cannot find any, then there is no work to do
32
+ if (matches.size() === 0) {
33
+ return null;
34
+ }
35
+
36
+ if (matches.size() > 1) {
37
+ throw new Error(
38
+ `Expected only one import to @octaviaflow/icons-react, instead found: ` +
39
+ `${matches.size()} imports`
40
+ );
41
+ }
42
+
43
+ // For now, these icons are available under @octaviaflow/icons-react/next
44
+ // TODO: remove in v11
45
+ matches.forEach((path) => {
46
+ path.get('source').get('value').replace('@octaviaflow/icons-react');
47
+ });
48
+
49
+ // Otherwise, we will get our import to icons and update the imported icons to
50
+ // use the new format
51
+ const iconsImport = matches.get();
52
+ const importSpecifiers = new Set();
53
+
54
+ // Iterate through each of the imported icons, get their size and name, and
55
+ // update the import and all matches in the file
56
+ j(iconsImport)
57
+ .find(j.ImportSpecifier)
58
+ .forEach((path) => {
59
+ const rootScope = path.scope;
60
+ const SIZE_REGEX = /(.+)(\d\d)$/g;
61
+ const { imported, local } = path.node;
62
+ const match = SIZE_REGEX.exec(imported.name);
63
+
64
+ if (match === null) {
65
+ throw new Error(`Expected to find size for: ${imported.name}`);
66
+ }
67
+
68
+ const name = match[1];
69
+ const size = parseInt(match[2], 10);
70
+
71
+ if (isNaN(size)) {
72
+ throw new Error(`Unable to parse size for ${imported.name}`);
73
+ }
74
+
75
+ // If they renamed the icon in the import, use that as the local name
76
+ // import { IconName32 as CustomName } from '@octaviaflow/icons-react';
77
+ const newBinding =
78
+ imported.name === local.name ? j.identifier(getSafeBinding()) : local;
79
+
80
+ function getSafeBinding() {
81
+ if (rootScope.declares(name)) {
82
+ return `${name}Icon`;
83
+ }
84
+ return name;
85
+ }
86
+
87
+ // Update the imported binding from IconName32 to IconName. Only do this
88
+ // replacement once if we have imports of the same icon but in different
89
+ // sizes.
90
+ if (!importSpecifiers.has(newBinding.name)) {
91
+ importSpecifiers.add(newBinding.name);
92
+ j(path).replaceWith(j.importSpecifier(j.identifier(name), newBinding));
93
+ } else {
94
+ j(path).remove();
95
+ }
96
+
97
+ // Finally, find all instances where we refer to this import and update
98
+ // its binding
99
+ root
100
+ .find(j.Identifier, { name: local.name })
101
+ .filter((path) => {
102
+ const { node: parent } = path.parent;
103
+
104
+ if (
105
+ j.MemberExpression.check(parent) &&
106
+ parent.property === path.node &&
107
+ !parent.computed
108
+ ) {
109
+ // obj.oldName
110
+ return false;
111
+ }
112
+
113
+ if (
114
+ j.ObjectProperty.check(parent) &&
115
+ parent.key === path.node &&
116
+ !parent.computed
117
+ ) {
118
+ // { oldName: 3 }
119
+ return false;
120
+ }
121
+
122
+ if (
123
+ j.MethodDefinition.check(parent) &&
124
+ parent.key === path.node &&
125
+ !parent.computed
126
+ ) {
127
+ // class A { oldName() {} }
128
+ return false;
129
+ }
130
+
131
+ if (
132
+ j.ClassProperty.check(parent) &&
133
+ parent.key === path.node &&
134
+ !parent.computed
135
+ ) {
136
+ // class A { oldName = 3 }
137
+ return false;
138
+ }
139
+
140
+ if (
141
+ j.JSXAttribute.check(parent) &&
142
+ parent.name === path.node &&
143
+ !parent.computed
144
+ ) {
145
+ // <Foo oldName={oldName} />
146
+ return false;
147
+ }
148
+ return true;
149
+ })
150
+ .forEach((path) => {
151
+ let scope = path.scope;
152
+ while (scope && scope !== rootScope) {
153
+ // If a scope already declares this binding, return early as it does
154
+ // not relate to our icon import
155
+ if (scope.declares(local.name)) {
156
+ return;
157
+ }
158
+ scope = scope.parent;
159
+ }
160
+
161
+ if (!scope) {
162
+ return;
163
+ }
164
+
165
+ const { node: parent } = path.parent;
166
+
167
+ // Replace the identifier name with the new binding name. If the parent
168
+ // node is an `ImportSpecifier`, we won't do this replacement as it is
169
+ // handled above
170
+ if (!j.ImportSpecifier.check(parent)) {
171
+ path.replace(newBinding);
172
+ }
173
+
174
+ // If our identifier is inside of a JSXOpeningElement, then we need to
175
+ // check to see if we need to add in the `size` prop that is now
176
+ // needed
177
+ if (j.JSXOpeningElement.check(parent) && size !== defaultSize) {
178
+ parent.attributes.unshift(
179
+ j.jsxAttribute(
180
+ j.jsxIdentifier('size'),
181
+ j.jsxExpressionContainer(j.numericLiteral(size))
182
+ )
183
+ );
184
+ }
185
+
186
+ // Handle cases where the icon is referred to in an object, for
187
+ // example:
188
+ //
189
+ // from:
190
+ // const alias = { name: IconName24 };
191
+ //
192
+ // to:
193
+ // const alias = { name: (props) => <IconName size={24} {...props} /> };
194
+ //
195
+ // Since the `size` information needs to be provided, otherwise the
196
+ // default size will be used
197
+ if (j.ObjectProperty.check(parent)) {
198
+ let replacement = null;
199
+
200
+ // map to React.createElement instead of using as the JSX Opening
201
+ // Element directly
202
+ if (newBinding.name[0] === newBinding.name[0].toLowerCase()) {
203
+ // Builds up this structure:
204
+ // (props) => React.createElement(iconName, {
205
+ // size: 20,
206
+ // ...props,
207
+ // });
208
+ replacement = j.arrowFunctionExpression(
209
+ [j.identifier('props')],
210
+ j.callExpression(
211
+ j.memberExpression(
212
+ j.identifier('React'),
213
+ j.identifier('createElement')
214
+ ),
215
+ [
216
+ newBinding,
217
+ j.objectExpression([
218
+ j.objectProperty(
219
+ j.identifier('size'),
220
+ j.numericLiteral(size)
221
+ ),
222
+ j.spreadElement(j.identifier('props')),
223
+ ]),
224
+ ]
225
+ )
226
+ );
227
+ } else {
228
+ // Build up this structure:
229
+ // (props) => <IconName size={20} {...props} />
230
+ replacement = j.arrowFunctionExpression(
231
+ [j.identifier('props')],
232
+ j.jsxElement(
233
+ j.jsxOpeningElement(
234
+ j.jsxIdentifier(newBinding.name),
235
+ [
236
+ j.jsxAttribute(
237
+ j.jsxIdentifier('size'),
238
+ j.jsxExpressionContainer(j.numericLiteral(size))
239
+ ),
240
+ j.jsxSpreadAttribute(j.identifier('props')),
241
+ ],
242
+ true
243
+ )
244
+ )
245
+ );
246
+ }
247
+
248
+ warn(fileInfo.path);
249
+
250
+ // Sometimes consumers will use the icon module name as a shorthand
251
+ // in an object property.
252
+ //
253
+ // Input:
254
+ // const o = { Add16, Add32 };
255
+ // Output:
256
+ // const o = { Add16: Add, Add32: (props) => <Add size={32} {...props} />
257
+ if (
258
+ parent.key.name !== newBinding.name &&
259
+ parent.shorthand === true
260
+ ) {
261
+ path.parent.get('shorthand').replace(false);
262
+ }
263
+
264
+ if (size !== defaultSize) {
265
+ path.parent.get('value').replace(replacement);
266
+ } else {
267
+ path.parent.get('value').replace(newBinding);
268
+ }
269
+ }
270
+
271
+ // Support `renderIcon` style props where you pass in an Icon by itself
272
+ // to the prop
273
+ //
274
+ // from:
275
+ // <Component renderIcon={Icon24} />
276
+ //
277
+ // to:
278
+ // <Component renderIcon={(props) => <Icon size={24} {...props} />} />
279
+ if (j.JSXExpressionContainer.check(parent) && size !== defaultSize) {
280
+ warn(fileInfo.path);
281
+ path.parentPath.replace(
282
+ j.jsxExpressionContainer(
283
+ j.arrowFunctionExpression(
284
+ [j.identifier('props')],
285
+ j.jsxElement(
286
+ j.jsxOpeningElement(
287
+ j.jsxIdentifier(path.node.name),
288
+ [
289
+ j.jsxAttribute(
290
+ j.jsxIdentifier('size'),
291
+ j.jsxExpressionContainer(j.numericLiteral(size))
292
+ ),
293
+ j.jsxSpreadAttribute(j.identifier('props')),
294
+ ],
295
+ true
296
+ )
297
+ )
298
+ )
299
+ )
300
+ );
301
+ }
302
+ });
303
+ });
304
+
305
+ return root.toSource(printOptions);
306
+ }
307
+
308
+ const manualCheckWarning = `[carbon] ${'='.repeat(71)}
309
+ We have updated the file: %s to the new icon API.
310
+
311
+ However, it may be that this update is missing a \`ref\` on the prop where the
312
+ icon is used. Please make sure to verify that this update is correct.
313
+
314
+ For more information, check out our migration guide: https://bit.ly/3o2vVQW\n`;
315
+
316
+ const files = new Set();
317
+
318
+ function warn(filepath) {
319
+ if (files.has(filepath)) {
320
+ return;
321
+ }
322
+
323
+ files.add(filepath);
324
+ console.log(manualCheckWarning, filepath);
325
+ }
326
+
327
+ module.exports = transform;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ /**
11
+ * Copyright IBM Corp. 2024
12
+ *
13
+ * This source code is licensed under the Apache-2.0 license found in the
14
+ * LICENSE file in the root directory of this source tree.
15
+ *
16
+ * Deprecate the `light` prop and wrap components with `Layer`
17
+ *
18
+ * Transforms:
19
+ *
20
+ * <Button light>Click me</Button>
21
+ *
22
+ * Into:
23
+ *
24
+ * <Layer>
25
+ * <Button>Click me</Button>
26
+ * </Layer>
27
+ */
28
+
29
+ 'use strict';
30
+
31
+ const defaultOptions = {
32
+ quote: 'single',
33
+ trailingComma: true,
34
+ };
35
+
36
+ function transform(fileInfo, api, options) {
37
+ const { jscodeshift: j } = api;
38
+ const root = j(fileInfo.source);
39
+ const printOptions = options.printOptions || defaultOptions;
40
+
41
+ // Check if there are any components with the 'light' prop
42
+ const hasLightProp =
43
+ root.find(j.JSXAttribute, { name: { name: 'light' } }).size() > 0;
44
+
45
+ if (!hasLightProp) {
46
+ return null; // if no 'light' prop found, don't modify & return the file
47
+ }
48
+
49
+ // Import Layer component if not already imported
50
+ const layerImport = root.find(j.ImportDeclaration, {
51
+ source: { value: '@octaviaflow/react' },
52
+ });
53
+
54
+ if (layerImport.length) {
55
+ const specifiers = layerImport.get('specifiers');
56
+ const hasLayerImport = specifiers.value.some(
57
+ (specifier) => specifier.imported && specifier.imported.name === 'Layer'
58
+ );
59
+
60
+ if (!hasLayerImport) {
61
+ specifiers.value.push(j.importSpecifier(j.identifier('Layer')));
62
+ }
63
+ } else {
64
+ const newImport = j.importDeclaration(
65
+ [j.importSpecifier(j.identifier('Layer'))],
66
+ j.literal('@octaviaflow/react')
67
+ );
68
+ // Find the first import declaration
69
+ const firstImport = root.find(j.ImportDeclaration).at(0);
70
+
71
+ if (firstImport.length) {
72
+ // Insert the new import before the first existing import
73
+ firstImport.insertAfter(newImport);
74
+ } else {
75
+ // If no imports, find the first non-comment node
76
+ const firstNonCommentNode = root
77
+ .find(j.Program)
78
+ .get('body')
79
+ .filter(
80
+ (path) =>
81
+ path.value.type !== 'CommentBlock' &&
82
+ path.value.type !== 'CommentLine'
83
+ )[0];
84
+
85
+ // Insert the new import before the first non-comment node
86
+ j(firstNonCommentNode).insertBefore(newImport);
87
+ }
88
+ }
89
+
90
+ // Find all JSX elements with a 'light' prop
91
+ root.find(j.JSXElement).forEach((path) => {
92
+ const lightProp = path.node.openingElement.attributes.find(
93
+ (attr) => attr.type === 'JSXAttribute' && attr.name.name === 'light'
94
+ );
95
+
96
+ if (lightProp) {
97
+ // Remove the 'light' prop
98
+ path.node.openingElement.attributes =
99
+ path.node.openingElement.attributes.filter(
100
+ (attr) => attr !== lightProp
101
+ );
102
+ // Wrap the component with Layer
103
+ const layerElement = j.jsxElement(
104
+ j.jsxOpeningElement(j.jsxIdentifier('Layer'), []),
105
+ j.jsxClosingElement(j.jsxIdentifier('Layer')),
106
+ [path.node]
107
+ );
108
+
109
+ // Replace the original element with the wrapped version
110
+ j(path).replaceWith(layerElement);
111
+ }
112
+ });
113
+
114
+ return root.toSource(printOptions);
115
+ }
116
+
117
+ module.exports = transform;
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+
11
+ 'use strict';
12
+
13
+ const defaultOptions = {
14
+ quote: 'auto',
15
+ trailingComma: true,
16
+ };
17
+
18
+ function transform(fileInfo, api, options) {
19
+ const printOptions = options.printOptions || defaultOptions;
20
+ const j = api.jscodeshift;
21
+ const root = j(fileInfo.source);
22
+
23
+ // Helper function to check if the import source is from '@octaviaflow/react' or its subpaths
24
+ function isCarbonReactImport(sourceValue) {
25
+ return (
26
+ sourceValue === '@octaviaflow/react' ||
27
+ sourceValue.startsWith('@octaviaflow/react/es') ||
28
+ sourceValue.startsWith('@octaviaflow/react/lib')
29
+ );
30
+ }
31
+
32
+ // Collect names of identifiers imported from '@octaviaflow/react' or its subpaths
33
+ const importedIdentifiers = new Map(); // Map of local name to transformed name
34
+
35
+ // Transform import declarations
36
+ root.find(j.ImportDeclaration).forEach((path) => {
37
+ const sourceValue = path.node.source.value;
38
+
39
+ // Only transform imports from '@octaviaflow/react' and its subpaths
40
+ if (!isCarbonReactImport(sourceValue)) {
41
+ return;
42
+ }
43
+
44
+ path.node.specifiers.forEach((specifier) => {
45
+ if (specifier.type === 'ImportSpecifier') {
46
+ let importedName = specifier.imported.name;
47
+ let localName = specifier.local ? specifier.local.name : importedName;
48
+ let transformedImportedName = importedName;
49
+ let transformedLocalName = localName;
50
+
51
+ // Transform imported names and local names as necessary
52
+ if (importedName === 'unstable__StaticNotification') {
53
+ transformedImportedName = 'unstable__Callout';
54
+ specifier.imported.name = transformedImportedName;
55
+
56
+ if (localName === 'StaticNotification') {
57
+ transformedLocalName = 'Callout';
58
+ specifier.local.name = transformedLocalName;
59
+ } else if (localName === 'unstable__StaticNotification') {
60
+ transformedLocalName = 'unstable__Callout';
61
+ specifier.local.name = transformedLocalName;
62
+ }
63
+ // If local name is something else (e.g., SomeOtherName), leave it unchanged
64
+ } else if (importedName === 'StaticNotification') {
65
+ transformedImportedName = 'Callout';
66
+ specifier.imported.name = transformedImportedName;
67
+
68
+ if (localName === 'StaticNotification') {
69
+ transformedLocalName = 'Callout';
70
+ specifier.local.name = transformedLocalName;
71
+ }
72
+ // If local name is different, leave it unchanged
73
+ } else if (importedName === 'StaticNotificationProps') {
74
+ transformedImportedName = 'CalloutProps';
75
+ specifier.imported.name = transformedImportedName;
76
+
77
+ if (localName === 'StaticNotificationProps') {
78
+ transformedLocalName = 'CalloutProps';
79
+ specifier.local.name = transformedLocalName;
80
+ }
81
+ // If local name is different, leave it unchanged
82
+ }
83
+
84
+ // If imported name and local name are the same after transformation, remove the alias
85
+ if (
86
+ specifier.local &&
87
+ specifier.local.name === specifier.imported.name
88
+ ) {
89
+ delete specifier.local;
90
+ }
91
+
92
+ // Update the mapping of imported identifiers
93
+ // Only add to the map if the local name or the transformed name is different
94
+ if (localName !== transformedLocalName) {
95
+ importedIdentifiers.set(localName, transformedLocalName);
96
+ }
97
+ }
98
+ });
99
+ });
100
+
101
+ // Deduplicate imports
102
+ const importDeclarations = root.find(j.ImportDeclaration);
103
+
104
+ importDeclarations.forEach((path) => {
105
+ const sourceValue = path.node.source.value;
106
+
107
+ // Only deduplicate imports from '@octaviaflow/react' and its subpaths
108
+ if (!isCarbonReactImport(sourceValue)) {
109
+ return;
110
+ }
111
+
112
+ const specifiers = path.node.specifiers;
113
+ const uniqueSpecifiers = [];
114
+ const seen = new Set();
115
+
116
+ specifiers.forEach((specifier) => {
117
+ const importedName = specifier.imported.name;
118
+ const localName = specifier.local ? specifier.local.name : importedName;
119
+ const key = `${importedName}:${localName}`;
120
+
121
+ if (!seen.has(key)) {
122
+ seen.add(key);
123
+ uniqueSpecifiers.push(specifier);
124
+ }
125
+ });
126
+
127
+ path.node.specifiers = uniqueSpecifiers;
128
+ });
129
+
130
+ // Remove empty import declarations
131
+ importDeclarations.forEach((path) => {
132
+ if (path.node.specifiers.length === 0) {
133
+ j(path).remove();
134
+ }
135
+ });
136
+
137
+ // Update usages in the code
138
+ root.find(j.Identifier).forEach((path) => {
139
+ const name = path.node.name;
140
+
141
+ // Skip if the identifier is part of an import specifier
142
+ if (
143
+ path.parent.node.type === 'ImportSpecifier' ||
144
+ path.parent.node.type === 'ImportDefaultSpecifier' ||
145
+ path.parent.node.type === 'ImportNamespaceSpecifier'
146
+ ) {
147
+ return;
148
+ }
149
+
150
+ // Only transform identifiers that match the imported identifiers
151
+ if (importedIdentifiers.has(name)) {
152
+ const transformedName = importedIdentifiers.get(name);
153
+ path.node.name = transformedName;
154
+ }
155
+ });
156
+
157
+ return root.toSource(printOptions);
158
+ }
159
+
160
+ module.exports = transform;