@react-spectrum/codemods 1.0.0 → 1.1.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.
@@ -59,6 +59,10 @@ availableComponents.add('Section');
59
59
  availableComponents.delete('Provider');
60
60
  // Replaced by ActionButtonGroup and ToggleButtonGroup
61
61
  availableComponents.add('ActionGroup');
62
+ // components renamed between v3 and S2
63
+ let renamedComponents = {
64
+ ContextualHelpTrigger: 'UnavailableMenuItemTrigger'
65
+ };
62
66
  function transformer(file, api, options) {
63
67
  let j = api.jscodeshift.withParser({
64
68
  parse(source) {
@@ -69,6 +73,8 @@ function transformer(file, api, options) {
69
73
  });
70
74
  let root = j(file.source);
71
75
  let componentsToTransform = options.components ? new Set(options.components.split(',').filter(s => availableComponents.has(s))) : availableComponents;
76
+ let v3ComponentsToRename = new Set(Object.keys(renamedComponents));
77
+ let S2ComponentsToImport = new Set();
72
78
  let bindings = [];
73
79
  let importedComponents = new Map();
74
80
  let elements = [];
@@ -87,9 +93,19 @@ function transformer(file, api, options) {
87
93
  if (binding) {
88
94
  let isUsed = false;
89
95
  for (let path of binding.referencePaths) {
90
- if (path.parentPath?.isJSXMemberExpression() && componentsToTransform.has(path.parentPath.node.property.name) && path.parentPath.parentPath.parentPath?.isJSXElement()) {
91
- importedComponents.set(path.parentPath.node.property.name, clonedSpecifier);
92
- elements.push([path.parentPath.node.property.name, path.parentPath.parentPath.parentPath]);
96
+ let propName = path.parentPath?.isJSXMemberExpression() && path.parentPath.node.property.name;
97
+ if (propName && path.parentPath.parentPath?.parentPath?.isJSXElement()) {
98
+ if (componentsToTransform.has(propName)) {
99
+ importedComponents.set(propName, clonedSpecifier);
100
+ elements.push([propName, path.parentPath.parentPath.parentPath]);
101
+ }
102
+ else if (v3ComponentsToRename.has(propName)) {
103
+ S2ComponentsToImport.add(renamedComponents[propName]);
104
+ elements.push([propName, path.parentPath.parentPath.parentPath]);
105
+ }
106
+ else {
107
+ isUsed = true;
108
+ }
93
109
  }
94
110
  else {
95
111
  isUsed = true;
@@ -112,11 +128,16 @@ function transformer(file, api, options) {
112
128
  typeof specifier.local.name === 'string' &&
113
129
  specifier.imported.type === 'Identifier' &&
114
130
  typeof specifier.imported.name === 'string' &&
115
- componentsToTransform.has(specifier.imported.name)) {
116
- // e.g. import {Button} from '@adobe/react-spectrum';
131
+ (componentsToTransform.has(specifier.imported.name) || v3ComponentsToRename.has(specifier.imported.name))) {
132
+ // e.g. import {Button} from '@adobe/react-spectrum'; or import {ContextualHelpTrigger} from '@adobe/react-spectrum';
117
133
  let binding = path.scope.getBinding(specifier.local.name);
118
134
  if (binding) {
119
- importedComponents.set(specifier.imported.name, specifier);
135
+ if (componentsToTransform.has(specifier.imported.name)) {
136
+ importedComponents.set(specifier.imported.name, specifier);
137
+ }
138
+ else {
139
+ S2ComponentsToImport.add(renamedComponents[specifier.imported.name]);
140
+ }
120
141
  bindings.push(binding);
121
142
  for (let path of binding.referencePaths) {
122
143
  if (path.parentPath?.isJSXOpeningElement() && path.parentPath.parentPath.isJSXElement()) {
@@ -234,11 +255,14 @@ function transformer(file, api, options) {
234
255
  macroImport.assertions = [t.importAttribute(t.identifier('type'), t.stringLiteral('macro'))];
235
256
  lastImportPath.insertAfter(macroImport);
236
257
  }
237
- if (importedComponents.size) {
258
+ if (importedComponents.size || S2ComponentsToImport.size) {
238
259
  // Add imports to existing @react-spectrum/s2 import if it exists, otherwise add a new one.
239
260
  let importSpecifiers = new Set([...importedComponents]
240
261
  .filter(([c]) => c !== 'Flex' && c !== 'Grid' && c !== 'View' && c !== 'Item' && c !== 'Section' && c !== 'ActionGroup')
241
262
  .map(([, specifier]) => specifier));
263
+ for (let s2Name of S2ComponentsToImport) {
264
+ importSpecifiers.add(t.importSpecifier(t.identifier(s2Name), t.identifier(s2Name)));
265
+ }
242
266
  let existingImport = root.find(j.ImportDeclaration, {
243
267
  source: { value: '@react-spectrum/s2' }
244
268
  });
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.default = transformContextualHelpTrigger;
37
+ const utils_1 = require("../../shared/utils");
38
+ const getComponents_1 = require("../../../getComponents");
39
+ const t = __importStar(require("@babel/types"));
40
+ let availableComponents = (0, getComponents_1.getComponents)();
41
+ /**
42
+ * Transforms ContextualHelpTrigger:
43
+ * - Rename ContextualHelpTrigger to UnavailableMenuItemTrigger.
44
+ * - Replace the old Dialog with ContextualHelpPopover.
45
+ */
46
+ function transformContextualHelpTrigger(path) {
47
+ let program = path.findParent((p) => t.isProgram(p.node));
48
+ let localName = (0, utils_1.addComponentImport)(program, 'UnavailableMenuItemTrigger');
49
+ // replace ContextualHelpTrigger with UnavailableMenuItemTrigger
50
+ path.node.openingElement.name = t.jsxIdentifier(localName);
51
+ if (path.node.closingElement) {
52
+ path.node.closingElement.name = t.jsxIdentifier(localName);
53
+ }
54
+ // replace Dialog with ContextualHelpPopover
55
+ let dialog = path.node.children.filter((c) => t.isJSXElement(c))[1];
56
+ if (dialog && t.isJSXIdentifier(dialog.openingElement.name)) {
57
+ let name = (0, utils_1.getName)(path, dialog.openingElement.name);
58
+ if (name === 'Dialog') {
59
+ let contextualHelpPopover = availableComponents.has('ContextualHelpPopover')
60
+ ? (0, utils_1.addComponentImport)(program, 'ContextualHelpPopover')
61
+ : 'ContextualHelpPopover';
62
+ dialog.openingElement.name = t.jsxIdentifier(contextualHelpPopover);
63
+ if (dialog.closingElement) {
64
+ dialog.closingElement.name = t.jsxIdentifier(contextualHelpPopover);
65
+ }
66
+ }
67
+ }
68
+ }
@@ -10,16 +10,19 @@ const transforms_1 = require("../../shared/transforms");
10
10
  * - If within Breadcrumbs: Update Item to be a Breadcrumb.
11
11
  * - If within Picker: Update Item to be a PickerItem.
12
12
  * - If within ComboBox: Update Item to be a ComboBoxItem.
13
+ * - If within ListView: Update Item to be a ListViewItem.
13
14
  * - Update key to id (and keep key if rendered inside array.map).
14
15
  */
15
16
  function transformItem(path) {
16
17
  // Update Items based on parent collection component
17
18
  (0, transforms_1.updateComponentWithinCollection)(path, { parentComponentName: 'Menu', newComponentName: 'MenuItem' });
18
19
  (0, transforms_1.updateComponentWithinCollection)(path, { parentComponentName: 'ActionMenu', newComponentName: 'MenuItem' });
20
+ (0, transforms_1.updateComponentWithinCollection)(path, { parentComponentName: 'ContextualHelpTrigger', newComponentName: 'MenuItem' });
19
21
  (0, transforms_1.updateComponentWithinCollection)(path, { parentComponentName: 'TagGroup', newComponentName: 'Tag' });
20
22
  (0, transforms_1.updateComponentWithinCollection)(path, { parentComponentName: 'Breadcrumbs', newComponentName: 'Breadcrumb' });
21
23
  (0, transforms_1.updateComponentWithinCollection)(path, { parentComponentName: 'Picker', newComponentName: 'PickerItem' });
22
24
  (0, transforms_1.updateComponentWithinCollection)(path, { parentComponentName: 'ComboBox', newComponentName: 'ComboBoxItem' });
25
+ (0, transforms_1.updateComponentWithinCollection)(path, { parentComponentName: 'ListView', newComponentName: 'ListViewItem' });
23
26
  // Comment if parent collection not detected
24
27
  (0, transforms_1.commentIfParentCollectionNotDetected)(path);
25
28
  }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = transformListView;
4
+ const transforms_1 = require("../../shared/transforms");
5
+ /**
6
+ * Transforms ListView:
7
+ * - Comment out density (it has not been implemented yet).
8
+ * - Comment out dragAndDropHooks (it has not been implemented yet).
9
+ */
10
+ function transformListView(path) {
11
+ (0, transforms_1.commentOutProp)(path, { propName: 'density' });
12
+ (0, transforms_1.commentOutProp)(path, { propName: 'dragAndDropHooks' });
13
+ }
@@ -680,7 +680,7 @@ function transformStyleProps(path, element) {
680
680
  if (isDOMElement) {
681
681
  let index = path.node.openingElement.attributes?.findIndex(a => a.type === 'JSXAttribute' && a.name.name === 'className');
682
682
  if (index != null && index >= 0) {
683
- classNameAttribute = path.get('openingElement').get('attributes').at(index);
683
+ classNameAttribute = path.get('openingElement').get('attributes')[index];
684
684
  }
685
685
  }
686
686
  let valueToAST = (v) => {
@@ -346,9 +346,9 @@ function moveRenderPropsToChild(path, options) {
346
346
  */
347
347
  function updateComponentWithinCollection(path, options) {
348
348
  const { parentComponentName, newComponentName } = options;
349
- // Collections currently implemented
350
- // TODO: Add 'ActionGroup', 'ListBox', 'ListView' once implemented
351
- const collectionItemParents = new Set(['Menu', 'ActionMenu', 'TagGroup', 'Breadcrumbs', 'Picker', 'ComboBox', 'ListBox', 'TabList', 'TabPanels', 'Collection']);
349
+ // Collections currently implemented.
350
+ // TODO: Add 'ActionGroup', 'ListBox' once implemented
351
+ const collectionItemParents = new Set(['Menu', 'ActionMenu', 'TagGroup', 'Breadcrumbs', 'Picker', 'ComboBox', 'ListBox', 'ListView', 'TabList', 'TabPanels', 'Collection', 'ContextualHelpTrigger']);
352
352
  if (t.isJSXElement(path.node) &&
353
353
  t.isJSXIdentifier(path.node.openingElement.name)) {
354
354
  // Find closest parent collection component
@@ -377,7 +377,7 @@ function updateComponentWithinCollection(path, options) {
377
377
  * Example: If they're declaring declaring Items somewhere above the collection.
378
378
  */
379
379
  function commentIfParentCollectionNotDetected(path) {
380
- const collectionItemParents = new Set(['Menu', 'ActionMenu', 'TagGroup', 'Breadcrumbs', 'Picker', 'ComboBox', 'ListBox', 'TabList', 'TabPanels', 'ActionGroup', 'ActionButtonGroup', 'ToggleButtonGroup', 'ListBox', 'ListView', 'Collection', 'SearchAutocomplete', 'Accordion', 'ActionBar', 'StepList']);
380
+ const collectionItemParents = new Set(['Menu', 'ActionMenu', 'TagGroup', 'Breadcrumbs', 'Picker', 'ComboBox', 'ListBox', 'TabList', 'TabPanels', 'ActionGroup', 'ActionButtonGroup', 'ToggleButtonGroup', 'ListBox', 'ListView', 'Collection', 'SearchAutocomplete', 'Accordion', 'ActionBar', 'StepList', 'ContextualHelpTrigger']);
381
381
  if (t.isJSXElement(path.node)) {
382
382
  // Find closest parent collection component
383
383
  let closestParentCollection = path.findParent((p) => t.isJSXElement(p.node) &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-spectrum/codemods",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "main": "dist/index.js",
5
5
  "source": "src/index.ts",
6
6
  "bin": "dist/index.js",
@@ -24,9 +24,9 @@
24
24
  "@babel/parser": "^7.24.5",
25
25
  "@babel/traverse": "^7.24.5",
26
26
  "@babel/types": "^7.24.5",
27
- "@react-spectrum/s2": "^1.0.0",
28
- "@react-types/shared": "^3.32.1",
29
- "@types/node": "^22",
27
+ "@react-spectrum/s2": "^1.2.0",
28
+ "@react-types/shared": "^3.33.1",
29
+ "@types/node": "^24",
30
30
  "boxen": "^5.1.2",
31
31
  "chalk": "^4.0.0",
32
32
  "execa": "^5.1.1",
@@ -49,5 +49,5 @@
49
49
  "publishConfig": {
50
50
  "access": "public"
51
51
  },
52
- "gitHead": "4d838da5bfe36abb35aed166995a9ef63825370f"
52
+ "gitHead": "8df187370053aa35f553cb388ad670f65e1ab371"
53
53
  }