@instructure/ui-codemods 8.17.1-snapshot.30 → 8.17.1-snapshot.71

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 CHANGED
@@ -45,6 +45,14 @@ This codemod helps you update your project by renaming `imports` that have chang
45
45
  jscodeshift -t node_modules/@instructure/ui-codemods/lib/updateImports.js <path> --config=node_modules/@instructure/instui-config/codemod-configs/v<version number ex. 5 or 6>/imports.config.js
46
46
  ```
47
47
 
48
+ ### Updating more complex props to the InstUI v8 syntax
49
+
50
+ This codemod upgrades more complex changes like Button, also outputs any manual changes needed to the console. Run this in a InstUI v7 codebase only. This command has an optional fileName parameter, supplying this will append to the given file the warnings.
51
+
52
+ ```sh
53
+ jscodeshift -t node_modules/@instructure/ui-codemods/lib/updateV7Props.js <path> -fileName updateV7PropsWarnings.txt
54
+ ```
55
+
48
56
  [npm]: https://img.shields.io/npm/v/@instructure/ui-codemods.svg
49
57
  [npm-url]: https://npmjs.com/package/@instructure/ui-codemods
50
58
  [license-badge]: https://img.shields.io/npm/l/instructure-ui.svg?style=flat-square
@@ -22,9 +22,6 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- import parseImport, { ParsedImport } from '../utils/parseImport'
26
- import findTransform from '../utils/findTransform'
27
- import findImportDeclaration from '../utils/findImportDeclaration'
28
25
  import {
29
26
  API,
30
27
  ASTPath,
@@ -35,6 +32,16 @@ import {
35
32
  JSCodeshift
36
33
  } from 'jscodeshift'
37
34
  import type { ConfigObject, TransformObj } from '../updateImports'
35
+ import { Transform } from '../updateImports'
36
+ import path from 'path'
37
+
38
+ export type ParsedImport = {
39
+ scope?: string
40
+ name?: string
41
+ fullName?: string
42
+ moduleName?: string
43
+ sourcePath?: string
44
+ }
38
45
 
39
46
  function transformImportPath(
40
47
  importPath: string,
@@ -319,6 +326,140 @@ function updateImports(
319
326
  return hasModifications
320
327
  }
321
328
 
329
+ function findImportDeclaration(
330
+ j: JSCodeshift,
331
+ root: Collection,
332
+ importPath: string
333
+ ) {
334
+ let importDeclaration
335
+ const declarationQueryResult = root.find(j.ImportDeclaration, {
336
+ source: {
337
+ type: 'StringLiteral',
338
+ value: importPath
339
+ }
340
+ })
341
+ if (declarationQueryResult.length > 0) {
342
+ importDeclaration = declarationQueryResult.get()
343
+ }
344
+ return importDeclaration
345
+ }
346
+
347
+ function findTransform(
348
+ transforms: Transform[],
349
+ importPath: string,
350
+ parsedImport: ParsedImport,
351
+ moduleName?: string
352
+ ) {
353
+ return (
354
+ transforms.find(({ where = {} }) => {
355
+ // If `where` has no entries, there are no matching transforms
356
+ if (Object.keys(where).length === 0) return false
357
+
358
+ let performedTest = false
359
+ let foundTransform = true
360
+
361
+ if (where.moduleName) {
362
+ performedTest = true
363
+
364
+ if (moduleName) {
365
+ // Give preference to the module name parsed from the AST vs. the import path string
366
+ foundTransform = foundTransform && where.moduleName === moduleName
367
+ } else {
368
+ foundTransform =
369
+ foundTransform && where.moduleName === parsedImport.moduleName
370
+ }
371
+ }
372
+
373
+ if (where.moduleNames) {
374
+ performedTest = true
375
+
376
+ if (moduleName) {
377
+ foundTransform =
378
+ foundTransform && where.moduleNames.includes(moduleName)
379
+ } else {
380
+ foundTransform =
381
+ foundTransform &&
382
+ where.moduleNames.includes(parsedImport.moduleName!)
383
+ }
384
+ }
385
+
386
+ if (where.packageName) {
387
+ performedTest = true
388
+
389
+ foundTransform =
390
+ foundTransform && where.packageName === parsedImport.fullName
391
+ }
392
+
393
+ if (where.packageNames) {
394
+ performedTest = true
395
+
396
+ foundTransform =
397
+ foundTransform && where.packageNames.includes(parsedImport.fullName!)
398
+ }
399
+
400
+ if (where.importPath) {
401
+ performedTest = true
402
+
403
+ foundTransform = foundTransform && where.importPath === importPath
404
+ }
405
+
406
+ if (where.importPattern) {
407
+ performedTest = true
408
+
409
+ foundTransform =
410
+ foundTransform && new RegExp(where.importPattern).test(importPath)
411
+ }
412
+
413
+ return performedTest && foundTransform
414
+ }) || {}
415
+ ).transform
416
+ }
417
+
418
+ function parseImport(importPath: string): ParsedImport {
419
+ let parsedImport = {}
420
+
421
+ if (!importPath) return {}
422
+
423
+ const splitPath = importPath.split('/')
424
+
425
+ const parseSourceAndModule = (entries: string[] = []) => {
426
+ if (entries.length === 0) return {}
427
+
428
+ const lastEntry = entries[entries.length - 1]
429
+
430
+ const moduleOffset = path.parse(lastEntry).name === 'index' ? 2 : 1
431
+
432
+ const moduleName = entries[entries.length - moduleOffset]
433
+
434
+ return {
435
+ moduleName: moduleName ? path.parse(moduleName).name : undefined,
436
+ sourcePath: entries.slice(0, entries.length - moduleOffset).join('/')
437
+ }
438
+ }
439
+
440
+ if (importPath[0] === '@') {
441
+ const [scope, name, ...rest] = splitPath
442
+
443
+ parsedImport = {
444
+ scope,
445
+ name,
446
+ fullName: `${scope}/${name}`,
447
+ moduleName: `${scope}/${name}`,
448
+ ...parseSourceAndModule(rest)
449
+ }
450
+ } else {
451
+ const [name, ...rest] = splitPath
452
+
453
+ parsedImport = {
454
+ name,
455
+ fullName: name,
456
+ moduleName: name,
457
+ ...parseSourceAndModule(rest)
458
+ }
459
+ }
460
+ return parsedImport
461
+ }
462
+
322
463
  /**
323
464
  * Find imports
324
465
  *
@@ -22,8 +22,6 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- import findDeprecatedProp from '../utils/findDeprecatedProp'
26
- import createLiteral from '../utils/createLiteral'
27
25
  import {
28
26
  ASTPath,
29
27
  Collection,
@@ -36,14 +34,16 @@ import type {
36
34
  ComponentUpdateData,
37
35
  UpdatePropNamesOptions
38
36
  } from '../updatePropNames'
37
+ import { printWarning } from './v7PropsUpdateHelpers'
39
38
 
40
39
  /**
41
- * Find JSX attributes (props)
42
- *
40
+ * Replaces deprecated pros and their values based on the given config
41
+ * object
43
42
  * Example:
44
- * <MyComponent [name] />
43
+ * <Flex wrapItems -> <Flex wrap="wrap"
45
44
  */
46
45
  export default function replaceDeprecatedProps(
46
+ filePath: string,
47
47
  j: JSCodeshift,
48
48
  root: Collection,
49
49
  config: UpdatePropNamesOptions
@@ -91,9 +91,11 @@ export default function replaceDeprecatedProps(
91
91
  // This means the value is contained in a jsx expression container. For example,
92
92
  // in the following jsx, `<div prop={someValue} />` we are looking at `{someValue}`
93
93
  expressionContainers.forEach((expressionContainer) => {
94
- const { type } = expressionContainer.value.expression
95
94
  // Verify that the expression container contains a literal
96
- if (type === 'Literal') {
95
+ if (
96
+ expressionContainer.value.expression.type ===
97
+ 'Literal'
98
+ ) {
97
99
  replaceValue(
98
100
  j,
99
101
  literals,
@@ -101,6 +103,15 @@ export default function replaceDeprecatedProps(
101
103
  attr,
102
104
  expressionContainer
103
105
  )
106
+ } else {
107
+ printWarning(
108
+ filePath,
109
+ el.value.loc?.start.line,
110
+ "Could not rename the value of '" +
111
+ prop +
112
+ "' because its value is a function or a variable " +
113
+ 'reference. Please update manually.'
114
+ )
104
115
  }
105
116
  })
106
117
  } else if (literals && literals.length > 0) {
@@ -159,3 +170,60 @@ const replaceValue = (
159
170
  }
160
171
  })
161
172
  }
173
+
174
+ /**
175
+ * Find the deprecated prop for a component
176
+ *
177
+ * @param config Deprecated property configuration
178
+ * @param comp Component name
179
+ * @param prop Property name
180
+ * @return Object if a match is found, otherwise null
181
+ */
182
+ const findDeprecatedProp = (
183
+ config: UpdatePropNamesOptions,
184
+ comp: string,
185
+ prop: string
186
+ ) => {
187
+ if (config && comp && prop && config[comp]) {
188
+ const component = config[comp]
189
+
190
+ // Iterate versions
191
+ const versions = Object.keys(component)
192
+ for (let i = 0; i < versions.length; i++) {
193
+ const props = component[versions[i]]
194
+
195
+ // Iterate properties
196
+ for (let j = 0; j < props.length; j++) {
197
+ const match = props[j]
198
+
199
+ if (prop === match.old) {
200
+ return match
201
+ }
202
+ }
203
+ }
204
+ }
205
+ return null
206
+ }
207
+
208
+ const createLiteral = (
209
+ j: JSCodeshift,
210
+ value: string | boolean | number | null
211
+ ) => {
212
+ if (typeof value === 'string') {
213
+ return j.stringLiteral(value)
214
+ }
215
+
216
+ if (typeof value === 'number') {
217
+ return j.jsxExpressionContainer(j.numericLiteral(value))
218
+ }
219
+
220
+ if (typeof value === 'boolean') {
221
+ return j.jsxExpressionContainer(j.booleanLiteral(value))
222
+ }
223
+
224
+ if (value === null) {
225
+ return j.jsxExpressionContainer(j.nullLiteral())
226
+ }
227
+
228
+ return null
229
+ }