@instructure/ui-codemods 10.20.2-snapshot-11 → 10.20.2-snapshot-13

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 (38) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +5 -87
  3. package/lib/__node_tests__/codemodHelpers.test.tsx +455 -0
  4. package/lib/__node_tests__/{updateV10Breaking.test.ts → codemods.test.ts} +3 -3
  5. package/lib/__node_tests__/{testHelpers.ts → runTest.ts} +1 -3
  6. package/lib/index.ts +1 -16
  7. package/lib/{utils → instui-codemods}/updateToV10Colors.ts +6 -7
  8. package/lib/updateV10Breaking.ts +12 -26
  9. package/lib/{helpers → utils}/codemodHelpers.ts +153 -164
  10. package/lib/utils/codemodTypeCheckers.ts +221 -0
  11. package/lib/utils/instUICodemodExecutor.ts +89 -0
  12. package/package.json +2 -2
  13. package/tsconfig.build.tsbuildinfo +1 -1
  14. package/lib/helpers/replaceDeprecatedImports.ts +0 -546
  15. package/lib/helpers/replaceDeprecatedProps.ts +0 -230
  16. package/lib/updateImports.ts +0 -86
  17. package/lib/updatePropNames.ts +0 -66
  18. package/lib/updateV7Props.ts +0 -101
  19. package/lib/updateV8Breaking.ts +0 -49
  20. package/lib/updateV8ReactDOM.ts +0 -61
  21. package/lib/updateV9Breaking.ts +0 -54
  22. package/lib/utils/UpdateV7ButtonsLink.ts +0 -139
  23. package/lib/utils/requireUncached.ts +0 -28
  24. package/lib/utils/updateToV8Theming.ts +0 -84
  25. package/lib/utils/updateToV9Theming.ts +0 -70
  26. package/lib/utils/updateV7ButtonsClose.ts +0 -104
  27. package/lib/utils/updateV7ButtonsIconCircle.ts +0 -240
  28. package/lib/utils/updateV7ButtonsMisc.ts +0 -137
  29. package/lib/utils/updateV7ButtonsWithText.ts +0 -111
  30. package/lib/utils/updateV7FocusableView.ts +0 -105
  31. package/lib/utils/updateV7Heading.ts +0 -145
  32. package/lib/utils/updateV7Lists.ts +0 -113
  33. package/lib/utils/updateV7Pill.ts +0 -83
  34. package/lib/utils/updateV7Popover.ts +0 -133
  35. package/lib/utils/updateV7Tabs.ts +0 -129
  36. package/lib/utils/updateV8RenderProp.ts +0 -142
  37. package/lib/utils/updateV8ThemeProp.ts +0 -51
  38. package/lib/utils/warnV7ComponentDeprecations.ts +0 -96
@@ -1,546 +0,0 @@
1
- /*
2
- * The MIT License (MIT)
3
- *
4
- * Copyright (c) 2015 - present Instructure, Inc.
5
- *
6
- * Permission is hereby granted, free of charge, to any person obtaining a copy
7
- * of this software and associated documentation files (the "Software"), to deal
8
- * in the Software without restriction, including without limitation the rights
9
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- * copies of the Software, and to permit persons to whom the Software is
11
- * furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice shall be included in all
14
- * copies or substantial portions of the Software.
15
- *
16
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- * SOFTWARE.
23
- */
24
-
25
- import type {
26
- API,
27
- ASTPath,
28
- Collection,
29
- ImportDeclaration,
30
- ImportDefaultSpecifier,
31
- ImportSpecifier,
32
- JSCodeshift
33
- } from 'jscodeshift'
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
- }
45
-
46
- function transformImportPath(
47
- importPath: string,
48
- parsedImport: ParsedImport,
49
- transform: TransformObj,
50
- transformDefaults: TransformObj
51
- ) {
52
- let updatedImportPath = transform.importPath || transformDefaults.importPath
53
-
54
- if (updatedImportPath) {
55
- updatedImportPath =
56
- typeof updatedImportPath === 'function'
57
- ? updatedImportPath(importPath, parsedImport)
58
- : updatedImportPath
59
- } else {
60
- updatedImportPath = importPath
61
- }
62
-
63
- return updatedImportPath
64
- }
65
-
66
- function updateImports(
67
- j: JSCodeshift,
68
- root: Collection,
69
- config: ConfigObject,
70
- api: API,
71
- importDeclaration: ASTPath<ImportDeclaration>,
72
- importSpecifier: ASTPath<ImportDefaultSpecifier> | ASTPath<ImportSpecifier>,
73
- importPath: string
74
- ) {
75
- let hasModifications = false
76
- const { transformDefaults = {} as TransformObj, transforms = [] } = config
77
- // This is the name of the export imported from the module. For example, in the import
78
- // `import { Foo as Bar } from '@instructure...` this would be Foo
79
- let moduleName
80
- if (
81
- importSpecifier &&
82
- importSpecifier.value &&
83
- (importSpecifier.value as ImportSpecifier).imported
84
- ) {
85
- moduleName = (importSpecifier.value as ImportSpecifier).imported.name
86
- }
87
-
88
- // This is the local name created by the consumer. For example, in the import
89
- // `import { Foo as Bar } from '@instructure...` this would be Bar
90
- const localName = (importSpecifier.value as ImportDefaultSpecifier).local!
91
- .name as string
92
-
93
- const parsedImport = parseImport(importPath)
94
- const transform = findTransform(
95
- transforms,
96
- importPath,
97
- parsedImport,
98
- moduleName
99
- )
100
-
101
- if (transform) {
102
- let importType = Object.keys(transform).includes('importType')
103
- ? transform.importType
104
- : transformDefaults.importType
105
-
106
- if (!importType) {
107
- importType = moduleName ? 'named' : 'default'
108
- }
109
-
110
- const updatedModuleName =
111
- transform.moduleName || transformDefaults.moduleName
112
- const currentModuleName = moduleName || parsedImport.moduleName!
113
- let updatedModuleNameStr: string
114
- if (updatedModuleName) {
115
- updatedModuleNameStr =
116
- typeof updatedModuleName === 'function'
117
- ? updatedModuleName(currentModuleName as string)
118
- : updatedModuleName
119
- } else {
120
- updatedModuleNameStr = currentModuleName as string
121
- }
122
-
123
- const updatedImportPath = transformImportPath(
124
- importPath,
125
- parsedImport,
126
- transform,
127
- transformDefaults
128
- )
129
-
130
- // If the importType we are transforming to is default, the existing import path is equal to the updated import path,
131
- // and there is no module name, that means we already have a default import at the specified import path and the
132
- // transform is unnecessary so we return false.
133
- if (
134
- importType === 'default' &&
135
- importPath === updatedImportPath &&
136
- !moduleName
137
- ) {
138
- return false
139
- }
140
-
141
- // If the importType we are transforming to is named, the existing import path is equal to the updated import path,
142
- // and the module name is equal to the updated module name, the transform is unecessary so we return false.
143
- if (
144
- importType === 'named' &&
145
- importPath === updatedImportPath &&
146
- moduleName === updatedModuleNameStr
147
- ) {
148
- return false
149
- }
150
-
151
- // Now that we have the import path, check to see if there is already an import declaration with that path. For example,
152
- // if we were moving the module Foo to the import path `ui-bar`, check to see within the file if there is already a
153
- // `ui-bar` import path.
154
- const updatedDeclaration = findImportDeclaration(j, root, updatedImportPath)
155
-
156
- // Preserve any comments, we'll need to restore them after the modifications
157
- const { comments = [] } = (importDeclaration || {}).value || {}
158
- const { comments: existingComments = [] } =
159
- (updatedDeclaration || {}).value || {}
160
-
161
- const cleanup = (newDeclaration?: ImportDeclaration) => {
162
- hasModifications = true
163
- j(importSpecifier).remove()
164
-
165
- let removedImportDeclaration = false
166
-
167
- // Do some cleanup. If we no longer have any import specifiers in the line, remove it
168
- if (
169
- j(importDeclaration).find(j.ImportSpecifier).length === 0 &&
170
- j(importDeclaration).find(j.ImportDefaultSpecifier).length === 0
171
- ) {
172
- j(importDeclaration).remove()
173
- removedImportDeclaration = true
174
- }
175
-
176
- // Restore comments. If we have removed an import declaration, amend any comments to the updated location
177
- if (newDeclaration && removedImportDeclaration) {
178
- // This means we have a new declaration, and we removed the old declaration. Assign the comments from the old import
179
- // declaration to the new import declaration
180
-
181
- // eslint-disable-next-line no-param-reassign
182
- newDeclaration.comments = comments
183
- } else if (updatedDeclaration && updatedDeclaration.value) {
184
- // This means we have an updated import declaration. We need to restore any comments in the updated import declaration,
185
- // _and_ if we removed an import declaration we need to amend the old import declaration comments to the comments that
186
- // were already on the updated import declaration
187
- updatedDeclaration.value.comments = [
188
- ...(existingComments || []),
189
- ...(removedImportDeclaration ? comments! : [])
190
- ]
191
- }
192
- }
193
-
194
- if (importType === 'named') {
195
- // We are migrating to a named import. The following query determines if there is already an existing import in the file
196
- // where this import needs to be moved
197
-
198
- if (updatedDeclaration) {
199
- // If we're here, it means that there's already another import declaration with the updated import path. For
200
- // example, we are moving `import { Foo } from 'ui-foo'` to `ui-bar` but `ui-bar` is already being used as
201
- // an import in the file. We need to amend this import to any existing ones.
202
- const updatedImportSpecifiers = j(updatedDeclaration).find(
203
- j.ImportSpecifier
204
- )
205
- const updatedImportDefaultSpecifiers = j(updatedDeclaration).find(
206
- j.ImportDefaultSpecifier
207
- )
208
-
209
- if (updatedImportSpecifiers.length > 0) {
210
- // If we're here, it means there's already one or more named imports from the module referenced in the import
211
- // path. For example, we have `import { Foo } from 'ui-foo'` and we want to move it to `ui-bar` but there is
212
- // already `import { Bar } from 'ui-bar'` defined in the file. The end result of this operation should be
213
- // `import { Bar, Foo } from 'ui-bar'`
214
- j(updatedDeclaration)
215
- .find(j.ImportSpecifier)
216
- .at(0)
217
- .insertAfter(
218
- j.importSpecifier(
219
- j.identifier(updatedModuleNameStr),
220
- j.identifier(localName)
221
- )
222
- )
223
- cleanup()
224
- } else if (updatedImportDefaultSpecifiers.length > 0) {
225
- // Same case as above but there is a default import ex. `import Bar from 'ui-bar' the end result would be
226
- // `import Bar, { Foo } from 'ui-bar'`
227
- j(updatedDeclaration)
228
- .find(j.ImportDefaultSpecifier)
229
- .at(0)
230
- .insertAfter(
231
- j.importSpecifier(
232
- j.identifier(updatedModuleNameStr),
233
- j.identifier(localName)
234
- )
235
- )
236
- cleanup()
237
- } else {
238
- // If we're here, the import is present but there are no named or default specifiers. For example we have
239
- // `import 'ui-bar'` and we want to move Foo from `import { Foo } from 'ui-foo'` to `ui-bar`. Amend the
240
- // import to the declaration so the end result will be `import { Foo } from 'ui-bar'`
241
- j(updatedDeclaration).replaceWith(
242
- j.importDeclaration(
243
- [
244
- j.importSpecifier(
245
- j.identifier(updatedModuleNameStr),
246
- j.identifier(localName)
247
- )
248
- ],
249
- j.stringLiteral(updatedImportPath)
250
- )
251
- )
252
- cleanup()
253
- }
254
- } else {
255
- // Add a new import declaration because there isn't an existing one
256
- const newDeclaration = j.importDeclaration(
257
- [
258
- j.importSpecifier(
259
- j.identifier(updatedModuleNameStr),
260
- j.identifier(localName)
261
- )
262
- ],
263
- j.stringLiteral(updatedImportPath)
264
- )
265
- j(importDeclaration).insertAfter(newDeclaration)
266
- cleanup(newDeclaration)
267
- }
268
- } else {
269
- // We're moving to default imports. For example, we are going from `import { Foo } from '@instructure/ui-something`
270
- // to `import Foo from '@instructure/ui-something-else'
271
-
272
- if (updatedDeclaration) {
273
- // There is already an import from this same path, we need to amend this default import to that one.
274
- const updatedImportSpecifiers = j(updatedDeclaration).find(
275
- j.ImportSpecifier
276
- )
277
- const updatedImportDefaultSpecifiers = j(updatedDeclaration).find(
278
- j.ImportDefaultSpecifier
279
- )
280
-
281
- if (updatedImportDefaultSpecifiers.length > 0) {
282
- // This case occurs if there is already a default import at the updated path. For example, you are trying
283
- // to move `import { Something } from 'ui-foo'` to a default import `import SomethingElse from 'ui-bar'`.
284
- // We don't want to break things by overriding it, so we'll skip this one and throw the following warning.
285
- if (api && api.report) {
286
- api.report(
287
- `[Warning]: Skipping transform for import \`${moduleName}\` to default import for \`${updatedImportPath}\`. There is already a default import specified for that import path and the transformation would be breaking.`
288
- )
289
- }
290
- } else if (updatedImportSpecifiers.length > 0) {
291
- // This case occurs if the import path is defined in the file and there exist one or more named imports already
292
- // for the import path. We need to insert the default import before the named imports. For example, we have an
293
- // import like `import { Something } from 'ui-foo'` and we want to move it to a default import from the path
294
- // 'ui-bar'. There already exists in the file `import { AnotherThing } from 'ui-bar'`. The end result will be
295
- // `import Something, { AnotherThing } from 'ui-bar'`
296
- j(updatedDeclaration)
297
- .find(j.ImportSpecifier)
298
- .at(0)
299
- .insertBefore(j.importDefaultSpecifier(j.identifier(localName)))
300
- cleanup()
301
- } else {
302
- // This case occurs if the import doesn't have named or default specifiers but there is still an import that
303
- // matches the updated import path. ex. we have `import { Something } from 'ui-foo' and we want to update the
304
- // import path to `ui-bar` but there is already `import 'ui-bar'` in the file. We add the default import to the
305
- // existing import declaration.
306
- j(updatedDeclaration).replaceWith(
307
- j.importDeclaration(
308
- [j.importDefaultSpecifier(j.identifier(localName))],
309
- j.stringLiteral(updatedImportPath)
310
- )
311
- )
312
- cleanup()
313
- }
314
- } else {
315
- // Add a new default declaration after b/c there isn't one currently
316
- const newDeclaration = j.importDeclaration(
317
- [j.importDefaultSpecifier(j.identifier(localName))],
318
- j.stringLiteral(updatedImportPath)
319
- )
320
- j(importDeclaration).insertAfter(newDeclaration)
321
- cleanup(newDeclaration)
322
- }
323
- }
324
- }
325
-
326
- return hasModifications
327
- }
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?: ImportSpecifier['imported']['name']
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 as string)
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
-
463
- /**
464
- * DEPRECATED, this should be deleted in the future
465
- * Find imports
466
- *
467
- * Example:
468
- * import Modal from 'instructure-ui/lib/Modal'
469
- */
470
- export default function replaceDeprecatedImports(
471
- j: JSCodeshift,
472
- root: Collection,
473
- config: ConfigObject,
474
- api: API
475
- ) {
476
- let hasModifications = false
477
-
478
- root.find(j.ImportDeclaration).forEach((importDeclaration) => {
479
- j(importDeclaration)
480
- .find(j.StringLiteral)
481
- .forEach((source) => {
482
- // Collect the string portion of the import, ex. `import Baz from '@instructure/ui-baz'` this would
483
- // look at the `@instructure/ui-baz` portion
484
- const importPath = source.value.value
485
-
486
- const importSpecifiers = j(importDeclaration).find(j.ImportSpecifier)
487
- const importDefaultSpecifiers = j(importDeclaration).find(
488
- j.ImportDefaultSpecifier
489
- )
490
-
491
- if (importSpecifiers.length > 0 || importDefaultSpecifiers.length > 0) {
492
- // This will look for named imports, ex. `import { Foo } from '@instructure...`
493
- importSpecifiers.forEach((importSpecifier) => {
494
- hasModifications =
495
- updateImports(
496
- j,
497
- root,
498
- config,
499
- api,
500
- importDeclaration,
501
- importSpecifier,
502
- importPath
503
- ) || hasModifications
504
- })
505
-
506
- // This will look for default imports, ex. `import Foo from '@instructure...`
507
- importDefaultSpecifiers.forEach((importDefaultSpecifier) => {
508
- hasModifications =
509
- updateImports(
510
- j,
511
- root,
512
- config,
513
- api,
514
- importDeclaration,
515
- importDefaultSpecifier,
516
- importPath
517
- ) || hasModifications
518
- })
519
- } else {
520
- // If we have a declaration, but no specifiers that means there is just the import path
521
- const { transformDefaults = {} as TransformObj, transforms = [] } =
522
- config
523
- const parsedImport = parseImport(importPath)
524
- const transform = findTransform(transforms, importPath, parsedImport)
525
-
526
- if (transform) {
527
- const updatedImportPath = transformImportPath(
528
- importPath,
529
- parsedImport,
530
- transform,
531
- transformDefaults
532
- )
533
-
534
- // Only proceed with the transform if it is necessary. If the import path is already equal to the updated import
535
- // path we skip it
536
- if (importPath !== updatedImportPath) {
537
- j(source).replaceWith(j.literal(updatedImportPath))
538
- hasModifications = true
539
- }
540
- }
541
- }
542
- })
543
- })
544
-
545
- return hasModifications
546
- }