@carbon/upgrade 11.24.0 → 11.25.0-rc.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.
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Copyright IBM Corp. 2025
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
+ 'use strict';
8
+
9
+ const STRUCTURED_LIST_WRAPPER = 'StructuredListWrapper';
10
+ const STRUCTURED_LIST_ROW = 'StructuredListRow';
11
+ const STRUCTURED_LIST_CELL = 'StructuredListCell';
12
+ const CHECKMARK_FILLED = 'CheckmarkFilled';
13
+ const ATTR_SELECTION = 'selection';
14
+ const ATTR_HEAD = 'head';
15
+
16
+ const defaultOptions = {
17
+ quote: 'single',
18
+ trailingComma: true,
19
+ };
20
+
21
+ function transform(fileInfo, api, options) {
22
+ const j = api.jscodeshift;
23
+ const root = j(fileInfo.source);
24
+ const printOptions = options.printOptions || defaultOptions;
25
+
26
+ // Track function names used inside StructuredListWrapper
27
+ const functionsUsedInWrappers = new Set();
28
+
29
+ // First pass: Find all wrappers and identify functions used within them
30
+ findFunctionsUsedInWrappers(j, root, functionsUsedInWrappers);
31
+
32
+ // Second pass: Process identified functions and wrappers
33
+ transformSelectionWrappers(j, root, functionsUsedInWrappers);
34
+
35
+ return root.toSource(printOptions);
36
+ }
37
+
38
+ function findFunctionsUsedInWrappers(j, root, functionsUsedInWrappers) {
39
+ root
40
+ .find(j.JSXElement, {
41
+ openingElement: {
42
+ name: { name: STRUCTURED_LIST_WRAPPER },
43
+ attributes: (attrs) =>
44
+ attrs.some(
45
+ (attr) =>
46
+ attr.type === 'JSXAttribute' && attr.name.name === ATTR_SELECTION
47
+ ),
48
+ },
49
+ })
50
+ .forEach((wrapper) => {
51
+ // Find all function calls within this wrapper
52
+ j(wrapper)
53
+ .find(j.JSXExpressionContainer)
54
+ .find(j.CallExpression)
55
+ .forEach((call) => {
56
+ // If it's a direct call to a function
57
+ if (call.node.callee.type === 'Identifier') {
58
+ const funcName = call.node.callee.name;
59
+ functionsUsedInWrappers.add(funcName);
60
+ }
61
+ });
62
+ });
63
+ }
64
+
65
+ function transformSelectionWrappers(j, root, functionsUsedInWrappers) {
66
+ transformIdentifiedFunctions(j, root, functionsUsedInWrappers);
67
+
68
+ // Then transform the wrappers themselves
69
+ root
70
+ .find(j.JSXElement, {
71
+ openingElement: {
72
+ name: { name: STRUCTURED_LIST_WRAPPER },
73
+ attributes: (attrs) =>
74
+ attrs.some(
75
+ (attr) =>
76
+ attr.type === 'JSXAttribute' && attr.name.name === ATTR_SELECTION
77
+ ),
78
+ },
79
+ })
80
+ .forEach((wrapper) => {
81
+ // Transform direct rows in wrapper
82
+ j(wrapper)
83
+ .find(j.JSXElement, {
84
+ openingElement: { name: { name: STRUCTURED_LIST_ROW } },
85
+ })
86
+ .forEach((row) => transformRow(j, row));
87
+ });
88
+ }
89
+
90
+ function transformIdentifiedFunctions(j, root, functionsUsedInWrappers) {
91
+ if (functionsUsedInWrappers.size === 0) return;
92
+
93
+ // Process regular function declarations
94
+ root
95
+ .find(j.FunctionDeclaration)
96
+ .filter(
97
+ (func) => func.node.id && functionsUsedInWrappers.has(func.node.id.name)
98
+ )
99
+ .forEach((func) => processNodeIfGeneratesRows(j, func));
100
+
101
+ // Process arrow functions in variable declarations
102
+ root
103
+ .find(j.VariableDeclarator)
104
+ .filter((decl) => {
105
+ // Must be named function in our set and be an arrow function
106
+ return (
107
+ decl.node.id &&
108
+ functionsUsedInWrappers.has(decl.node.id.name) &&
109
+ decl.node.init &&
110
+ decl.node.init.type === 'ArrowFunctionExpression'
111
+ );
112
+ })
113
+ .forEach((func) => processNodeIfGeneratesRows(j, func));
114
+ }
115
+
116
+ function processNodeIfGeneratesRows(j, func) {
117
+ // Find all StructuredListRow elements inside this function
118
+ j(func)
119
+ .find(j.JSXElement, {
120
+ openingElement: { name: { name: STRUCTURED_LIST_ROW } },
121
+ })
122
+ .forEach((row) => transformRow(j, row));
123
+ }
124
+
125
+ function transformRow(j, row) {
126
+ // Add selection prop to all rows if missing
127
+ const hasSelectionProp = row.node.openingElement.attributes.some(
128
+ (attr) => attr.type === 'JSXAttribute' && attr.name.name === ATTR_SELECTION
129
+ );
130
+
131
+ if (!hasSelectionProp) {
132
+ row.node.openingElement.attributes.push(
133
+ j.jsxAttribute(j.jsxIdentifier(ATTR_SELECTION))
134
+ );
135
+ }
136
+
137
+ // Only remove CheckmarkFilled cells from non-head rows
138
+ const hasHeadProp = row.node.openingElement.attributes.some(
139
+ (attr) => attr.type === 'JSXAttribute' && attr.name.name === ATTR_HEAD
140
+ );
141
+
142
+ if (!hasHeadProp) {
143
+ // Filter out cells with CheckmarkFilled
144
+ row.node.children = row.node.children.filter((child) => {
145
+ // Only check JSX elements that are StructuredListCell
146
+ if (
147
+ child.type !== 'JSXElement' ||
148
+ child.openingElement.name.name !== STRUCTURED_LIST_CELL
149
+ ) {
150
+ return true;
151
+ }
152
+
153
+ // Check if cell contains CheckmarkFilled
154
+ return (
155
+ j(child)
156
+ .find(j.JSXElement, {
157
+ openingElement: { name: { name: CHECKMARK_FILLED } },
158
+ })
159
+ .size() === 0
160
+ );
161
+ });
162
+ }
163
+ }
164
+
165
+ module.exports = transform;
166
+ module.exports.parser = 'tsx';