@atlaskit/eslint-plugin-design-system 13.30.1 → 13.32.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 (51) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +75 -75
  3. package/dist/cjs/presets/all-flat.codegen.js +3 -3
  4. package/dist/cjs/presets/all.codegen.js +3 -3
  5. package/dist/cjs/presets/recommended-flat.codegen.js +2 -2
  6. package/dist/cjs/presets/recommended.codegen.js +2 -2
  7. package/dist/cjs/rules/index.codegen.js +5 -5
  8. package/dist/cjs/rules/lozenge-badge-tag-labelling-system-migration/index.js +712 -0
  9. package/dist/cjs/rules/no-placeholder/index.js +162 -0
  10. package/dist/es2019/presets/all-flat.codegen.js +3 -3
  11. package/dist/es2019/presets/all.codegen.js +3 -3
  12. package/dist/es2019/presets/recommended-flat.codegen.js +2 -2
  13. package/dist/es2019/presets/recommended.codegen.js +2 -2
  14. package/dist/es2019/rules/index.codegen.js +5 -5
  15. package/dist/es2019/rules/lozenge-badge-tag-labelling-system-migration/index.js +702 -0
  16. package/dist/es2019/rules/no-placeholder/index.js +142 -0
  17. package/dist/esm/presets/all-flat.codegen.js +3 -3
  18. package/dist/esm/presets/all.codegen.js +3 -3
  19. package/dist/esm/presets/recommended-flat.codegen.js +2 -2
  20. package/dist/esm/presets/recommended.codegen.js +2 -2
  21. package/dist/esm/rules/index.codegen.js +5 -5
  22. package/dist/esm/rules/lozenge-badge-tag-labelling-system-migration/index.js +705 -0
  23. package/dist/esm/rules/no-placeholder/index.js +154 -0
  24. package/dist/types/presets/all-flat.codegen.d.ts +1 -1
  25. package/dist/types/presets/all.codegen.d.ts +1 -1
  26. package/dist/types/presets/recommended-flat.codegen.d.ts +1 -1
  27. package/dist/types/presets/recommended.codegen.d.ts +1 -1
  28. package/dist/types/rules/index.codegen.d.ts +1 -1
  29. package/dist/types/rules/no-placeholder/index.d.ts +6 -0
  30. package/dist/types-ts4.5/presets/all-flat.codegen.d.ts +1 -1
  31. package/dist/types-ts4.5/presets/all.codegen.d.ts +1 -1
  32. package/dist/types-ts4.5/presets/recommended-flat.codegen.d.ts +1 -1
  33. package/dist/types-ts4.5/presets/recommended.codegen.d.ts +1 -1
  34. package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -1
  35. package/dist/types-ts4.5/rules/no-placeholder/index.d.ts +6 -0
  36. package/package.json +2 -2
  37. package/dist/cjs/rules/lozenge-isBold-and-lozenge-badge-appearance-migration/index.js +0 -332
  38. package/dist/cjs/rules/no-utility-icons/checks.js +0 -246
  39. package/dist/cjs/rules/no-utility-icons/index.js +0 -49
  40. package/dist/es2019/rules/lozenge-isBold-and-lozenge-badge-appearance-migration/index.js +0 -324
  41. package/dist/es2019/rules/no-utility-icons/checks.js +0 -177
  42. package/dist/es2019/rules/no-utility-icons/index.js +0 -44
  43. package/dist/esm/rules/lozenge-isBold-and-lozenge-badge-appearance-migration/index.js +0 -326
  44. package/dist/esm/rules/no-utility-icons/checks.js +0 -239
  45. package/dist/esm/rules/no-utility-icons/index.js +0 -43
  46. package/dist/types/rules/lozenge-isBold-and-lozenge-badge-appearance-migration/index.d.ts +0 -3
  47. package/dist/types/rules/no-utility-icons/checks.d.ts +0 -10
  48. package/dist/types/rules/no-utility-icons/index.d.ts +0 -3
  49. package/dist/types-ts4.5/rules/no-utility-icons/checks.d.ts +0 -10
  50. /package/dist/{types-ts4.5/rules/no-utility-icons → types/rules/lozenge-badge-tag-labelling-system-migration}/index.d.ts +0 -0
  51. /package/dist/types-ts4.5/rules/{lozenge-isBold-and-lozenge-badge-appearance-migration → lozenge-badge-tag-labelling-system-migration}/index.d.ts +0 -0
@@ -0,0 +1,705 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import { isNodeOfType } from 'eslint-codemod-utils';
5
+ import { createLintRule } from '../utils/create-rule';
6
+ var rule = createLintRule({
7
+ meta: {
8
+ name: 'lozenge-badge-tag-labelling-system-migration',
9
+ fixable: 'code',
10
+ type: 'suggestion',
11
+ docs: {
12
+ description: 'Helps migrate Lozenge isBold prop, Badge appearance values, and SimpleTag/RemovableTag components as part of the Labelling System Phase 1 migration.',
13
+ recommended: false,
14
+ severity: 'warn'
15
+ },
16
+ messages: {
17
+ updateAppearance: 'Update appearance value to new semantic value.',
18
+ migrateTag: 'Non-bold <Lozenge> variants should migrate to <Tag> component.',
19
+ manualReview: "Dynamic 'isBold' props require manual review before migration.",
20
+ dynamicLozengeAppearance: "Dynamic 'appearance' prop values require manual review before migrating to Tag. Please verify the appearance value and manually convert it to the appropriate color prop value.",
21
+ updateBadgeAppearance: 'Update Badge appearance value "{{oldValue}}" to new semantic value "{{newValue}}".',
22
+ dynamicBadgeAppearance: 'Dynamic appearance prop values require manual review to ensure they use the new semantic values: neutral, information, inverse, danger, success.'
23
+ }
24
+ },
25
+ create: function create(context) {
26
+ /**
27
+ * Contains a map of imported Lozenge components.
28
+ */
29
+ var lozengeImports = {}; // local name -> import source
30
+
31
+ /**
32
+ * Contains a map of imported Badge components.
33
+ */
34
+ var badgeImports = {}; // local name -> import source
35
+
36
+ /**
37
+ * Contains a map of imported Tag components (SimpleTag, RemovableTag, or default Tag imports).
38
+ * Maps local name to { type: 'SimpleTag' | 'RemovableTag' | 'Tag', source: string, node: ImportNode }
39
+ */
40
+ var tagImports = {};
41
+
42
+ /**
43
+ * Tracks which tag imports need to migrate to Tag (default) or AvatarTag (named)
44
+ * Maps local name to migration target: 'Tag' | 'AvatarTag'
45
+ */
46
+ var tagMigrationTargets = {};
47
+
48
+ /**
49
+ * Tracks import declaration nodes that need to be updated
50
+ */
51
+ var importDeclarationsToUpdate = new Set();
52
+
53
+ /**
54
+ * Contains a map of imported Avatar components from @atlaskit/avatar.
55
+ * Maps local name to import source
56
+ */
57
+ var avatarImports = {};
58
+
59
+ /**
60
+ * Contains a map of imported Tag and AvatarTag components from @atlaskit/tag.
61
+ * These are the new components that should not be migrated.
62
+ * Maps local name to import source
63
+ */
64
+ var newTagImports = {};
65
+
66
+ /**
67
+ * Check if a JSX attribute value is a literal false
68
+ */
69
+ function isLiteralFalse(node) {
70
+ return node && node.type === 'JSXExpressionContainer' && node.expression && node.expression.type === 'Literal' && node.expression.value === false;
71
+ }
72
+
73
+ /**
74
+ * Check if a JSX attribute value is dynamic (not a static literal value)
75
+ * Can be used for any prop type (boolean, string, etc.)
76
+ */
77
+ function isDynamicExpression(node) {
78
+ if (!node) {
79
+ return false;
80
+ }
81
+
82
+ // If it's a plain literal (e.g., appearance="value"), it's not dynamic
83
+ if (node.type === 'Literal') {
84
+ return false;
85
+ }
86
+
87
+ // If it's an expression container with a non-literal expression, it's dynamic
88
+ if (node.type === 'JSXExpressionContainer') {
89
+ var expr = node.expression;
90
+ return expr && expr.type !== 'Literal';
91
+ }
92
+ return false;
93
+ }
94
+
95
+ /**
96
+ * Get all attributes as an object for easier manipulation
97
+ */
98
+ function getAttributesMap(attributes) {
99
+ var map = {};
100
+ attributes.forEach(function (attr) {
101
+ if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier') {
102
+ map[attr.name.name] = attr;
103
+ }
104
+ });
105
+ return map;
106
+ }
107
+
108
+ /**
109
+ * Map old appearance values to new semantic appearance values
110
+ * Both Lozenge and Tag now use the same appearance prop with new semantic values
111
+ */
112
+ function mapToNewAppearanceValue(oldValue) {
113
+ var mapping = {
114
+ success: 'success',
115
+ default: 'default',
116
+ removed: 'removed',
117
+ inprogress: 'inprogress',
118
+ new: 'new',
119
+ moved: 'moved'
120
+ };
121
+ return mapping[oldValue] || oldValue;
122
+ }
123
+
124
+ /**
125
+ * Map Lozenge appearance values to Tag color values
126
+ * Used when migrating Lozenge to Tag component
127
+ */
128
+ function mapLozengeAppearanceToTagColor(appearanceValue) {
129
+ var mapping = {
130
+ success: 'lime',
131
+ default: 'gray',
132
+ removed: 'red',
133
+ inprogress: 'blue',
134
+ new: 'purple',
135
+ moved: 'yellow'
136
+ };
137
+ return mapping[appearanceValue] || appearanceValue;
138
+ }
139
+
140
+ /**
141
+ * Map Badge old appearance values to new semantic appearance values
142
+ */
143
+ function mapBadgeToNewAppearanceValue(oldValue) {
144
+ var mapping = {
145
+ added: 'success',
146
+ removed: 'danger',
147
+ default: 'neutral',
148
+ primary: 'information',
149
+ primaryInverted: 'inverse',
150
+ important: 'danger'
151
+ };
152
+ return mapping[oldValue] || oldValue;
153
+ }
154
+
155
+ /**
156
+ * Map Tag color light variants to semantic color values
157
+ */
158
+ function mapTagColorValue(oldValue) {
159
+ var mapping = {
160
+ limeLight: 'lime',
161
+ orangeLight: 'orange',
162
+ magentaLight: 'magenta',
163
+ greenLight: 'green',
164
+ blueLight: 'blue',
165
+ redLight: 'red',
166
+ purpleLight: 'purple',
167
+ greyLight: 'gray',
168
+ tealLight: 'teal',
169
+ yellowLight: 'yellow',
170
+ grey: 'gray'
171
+ };
172
+ return mapping[oldValue] || oldValue;
173
+ }
174
+
175
+ /**
176
+ * Check if elemBefore prop contains only an Avatar component from @atlaskit/avatar
177
+ * Returns the Avatar component name if it's from the avatar package, null otherwise
178
+ */
179
+ function getAvatarComponentName(elemBeforeProp) {
180
+ if (!elemBeforeProp || !elemBeforeProp.value) {
181
+ return null;
182
+ }
183
+ var value = elemBeforeProp.value;
184
+
185
+ // Check for JSX element: <Avatar ... />
186
+ if (value.type === 'JSXElement' && value.openingElement.name.name === 'Avatar') {
187
+ var avatarName = value.openingElement.name.name;
188
+ if (avatarImports[avatarName]) {
189
+ return avatarName;
190
+ }
191
+ }
192
+
193
+ // Check for JSX expression container: {<Avatar ... />}
194
+ if (value.type === 'JSXExpressionContainer' && value.expression) {
195
+ // Direct JSX element: {<Avatar ... />}
196
+ if (value.expression.type === 'JSXElement' && value.expression.openingElement.name.name === 'Avatar') {
197
+ var _avatarName = value.expression.openingElement.name.name;
198
+ if (avatarImports[_avatarName]) {
199
+ return _avatarName;
200
+ }
201
+ }
202
+
203
+ // Arrow function: {() => <Avatar ... />}
204
+ if (value.expression.type === 'ArrowFunctionExpression') {
205
+ var body = value.expression.body;
206
+ if (body.type === 'JSXElement' && body.openingElement.name.name === 'Avatar') {
207
+ var _avatarName2 = body.openingElement.name.name;
208
+ if (avatarImports[_avatarName2]) {
209
+ return _avatarName2;
210
+ }
211
+ }
212
+ }
213
+ }
214
+ return null;
215
+ }
216
+
217
+ /**
218
+ * Check if color prop value needs mapping
219
+ */
220
+ function colorNeedsMapping(colorProp) {
221
+ if (!(colorProp !== null && colorProp !== void 0 && colorProp.value)) {
222
+ return false;
223
+ }
224
+ var stringValue = extractStringValue(colorProp.value);
225
+ return stringValue !== null && typeof stringValue === 'string' && mapTagColorValue(stringValue) !== stringValue;
226
+ }
227
+
228
+ /**
229
+ * Extract the string value from a JSX attribute value
230
+ */
231
+ function extractStringValue(attrValue) {
232
+ if (!attrValue) {
233
+ return null;
234
+ }
235
+ if (attrValue.type === 'Literal') {
236
+ return attrValue.value;
237
+ }
238
+ if (attrValue.type === 'JSXExpressionContainer' && attrValue.expression && attrValue.expression.type === 'Literal') {
239
+ return attrValue.expression.value;
240
+ }
241
+ return null;
242
+ }
243
+
244
+ /**
245
+ * Create a fixer function to replace an appearance prop value
246
+ * Handles both Literal and JSXExpressionContainer with Literal
247
+ */
248
+ function createAppearanceFixer(attrValue, newValue) {
249
+ return function (fixer) {
250
+ if (!attrValue) {
251
+ return null;
252
+ }
253
+ if (attrValue.type === 'Literal') {
254
+ return fixer.replaceText(attrValue, "\"".concat(newValue, "\""));
255
+ }
256
+ if (attrValue.type === 'JSXExpressionContainer' && 'expression' in attrValue && attrValue.expression && attrValue.expression.type === 'Literal') {
257
+ return fixer.replaceText(attrValue.expression, "\"".concat(newValue, "\""));
258
+ }
259
+ return null;
260
+ };
261
+ }
262
+
263
+ /**
264
+ * Generate the replacement JSX element text for Tag migration
265
+ * Handles both regular Tag and avatarTag migrations
266
+ */
267
+ function generateTagReplacement(node) {
268
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
269
+ var sourceCode = context.getSourceCode();
270
+ var attributes = node.openingElement.attributes;
271
+
272
+ // Build new attributes array
273
+ var newAttributes = [];
274
+ attributes.forEach(function (attr) {
275
+ if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier') {
276
+ var attrName = attr.name.name;
277
+ if (attrName === 'isBold') {
278
+ // Skip isBold attribute
279
+ return;
280
+ }
281
+ if (attrName === 'appearance') {
282
+ // For Lozenge migrations, convert appearance to color prop
283
+ // For SimpleTag/RemovableTag migrations, delete appearance prop
284
+ if (options.isLozengeMigration) {
285
+ // Map Lozenge appearance value to Tag color value and change prop name from appearance to color
286
+ var stringValue = extractStringValue(attr.value);
287
+ if (stringValue && typeof stringValue === 'string') {
288
+ var mappedColor = mapLozengeAppearanceToTagColor(stringValue);
289
+ newAttributes.push("color=\"".concat(mappedColor, "\""));
290
+ }
291
+ // If we can't extract the string value (dynamic expression), skip it
292
+ // Dynamic expressions should be caught earlier and require manual review
293
+ // This code path shouldn't be reached, but we skip to be safe
294
+ }
295
+ // For SimpleTag/RemovableTag migrations, skip appearance prop (delete it)
296
+ return;
297
+ }
298
+ if (attrName === 'color') {
299
+ // For avatar tag, skip color prop; for regular tag, map color value
300
+ // Note: Lozenge doesn't have a color prop, but Tag/SimpleTag/RemovableTag do
301
+ if (options.isAvatarTag) {
302
+ return;
303
+ }
304
+ var _stringValue = extractStringValue(attr.value);
305
+ if (_stringValue && typeof _stringValue === 'string') {
306
+ var _mappedColor = mapTagColorValue(_stringValue);
307
+ newAttributes.push("color=\"".concat(_mappedColor, "\""));
308
+ } else {
309
+ // If we can't extract the string value, keep as-is
310
+ var value = attr.value ? sourceCode.getText(attr.value) : '';
311
+ newAttributes.push("color".concat(value ? "=".concat(value) : ''));
312
+ }
313
+ return;
314
+ }
315
+ if (attrName === 'elemBefore') {
316
+ // For avatar tag, rename elemBefore to avatar and use render props
317
+ if (options.isAvatarTag) {
318
+ var elemBeforeValue = attr.value;
319
+ var avatarElement = null;
320
+
321
+ // Extract Avatar element from various formats
322
+ if (elemBeforeValue.type === 'JSXElement') {
323
+ avatarElement = elemBeforeValue;
324
+ } else if (elemBeforeValue.type === 'JSXExpressionContainer') {
325
+ var expr = elemBeforeValue.expression;
326
+ // Direct JSX element: {<Avatar ... />}
327
+ if (expr.type === 'JSXElement') {
328
+ avatarElement = expr;
329
+ }
330
+ // Arrow function: {() => <Avatar ... />}
331
+ else if (expr.type === 'ArrowFunctionExpression' && expr.body.type === 'JSXElement') {
332
+ avatarElement = expr.body;
333
+ }
334
+ }
335
+ if (avatarElement) {
336
+ // Generate render props: avatar={(props) => <Avatar {...props} ... />}
337
+ var avatarElementText = sourceCode.getText(avatarElement);
338
+ // Add {...props} spread to the Avatar element attributes
339
+ var avatarWithProps = avatarElementText.replace(/<Avatar\s/, '<Avatar {...props} ');
340
+ newAttributes.push("avatar={(props) => ".concat(avatarWithProps, "}"));
341
+ }
342
+ return;
343
+ }
344
+ // For regular tag, keep elemBefore as-is
345
+ newAttributes.push(sourceCode.getText(attr));
346
+ return;
347
+ }
348
+
349
+ // Keep all other attributes
350
+ newAttributes.push(sourceCode.getText(attr));
351
+ } else if (attr.type === 'JSXSpreadAttribute') {
352
+ // Keep spread attributes
353
+ newAttributes.push(sourceCode.getText(attr));
354
+ }
355
+ });
356
+
357
+ // Add isRemovable={false} for SimpleTag migrations and Lozenge migrations
358
+ if (options.isSimpleTag || options.isLozengeMigration) {
359
+ newAttributes.push('isRemovable={false}');
360
+ }
361
+ var attributesText = newAttributes.length > 0 ? " ".concat(newAttributes.join(' ')) : '';
362
+ var children = node.children.length > 0 ? sourceCode.getText().slice(node.openingElement.range[1], node.closingElement ? node.closingElement.range[0] : node.range[1]) : '';
363
+ var componentName = options.preserveComponentName ? node.openingElement.name.name : options.isAvatarTag ? 'AvatarTag' : 'Tag';
364
+ if (node.closingElement) {
365
+ return "<".concat(componentName).concat(attributesText, ">").concat(children, "</").concat(componentName, ">");
366
+ } else {
367
+ return "<".concat(componentName).concat(attributesText, " />");
368
+ }
369
+ }
370
+ return {
371
+ ImportDeclaration: function ImportDeclaration(node) {
372
+ var moduleSource = node.source.value;
373
+ if (typeof moduleSource === 'string') {
374
+ // Track Lozenge imports
375
+ if (moduleSource === '@atlaskit/lozenge' || moduleSource.startsWith('@atlaskit/lozenge')) {
376
+ node.specifiers.forEach(function (spec) {
377
+ if (spec.type === 'ImportDefaultSpecifier') {
378
+ lozengeImports[spec.local.name] = moduleSource;
379
+ } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
380
+ if (spec.imported.name === 'Lozenge') {
381
+ lozengeImports[spec.local.name] = moduleSource;
382
+ }
383
+ }
384
+ });
385
+ }
386
+ // Track Badge imports
387
+ if (moduleSource === '@atlaskit/badge' || moduleSource.startsWith('@atlaskit/badge')) {
388
+ node.specifiers.forEach(function (spec) {
389
+ if (spec.type === 'ImportDefaultSpecifier') {
390
+ badgeImports[spec.local.name] = moduleSource;
391
+ } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
392
+ if (spec.imported.name === 'Badge' || spec.imported.name === 'default') {
393
+ badgeImports[spec.local.name] = moduleSource;
394
+ }
395
+ }
396
+ });
397
+ }
398
+ // Track Tag imports (SimpleTag, RemovableTag only - not the new Tag component)
399
+ if (moduleSource === '@atlaskit/tag' || moduleSource.startsWith('@atlaskit/tag')) {
400
+ node.specifiers.forEach(function (spec) {
401
+ if (spec.type === 'ImportDefaultSpecifier') {
402
+ // Check for default imports from subpaths and main package
403
+ if (moduleSource === '@atlaskit/tag/simple-tag') {
404
+ // Default import from @atlaskit/tag/simple-tag is a SimpleTag
405
+ tagImports[spec.local.name] = {
406
+ type: 'SimpleTag',
407
+ source: moduleSource,
408
+ node: _objectSpread(_objectSpread({}, spec), {}, {
409
+ parent: node
410
+ })
411
+ };
412
+ importDeclarationsToUpdate.add(node);
413
+ } else if (moduleSource === '@atlaskit/tag/removable-tag' || moduleSource === '@atlaskit/tag') {
414
+ // Default import from @atlaskit/tag/removable-tag or @atlaskit/tag is a RemovableTag
415
+ tagImports[spec.local.name] = {
416
+ type: 'RemovableTag',
417
+ source: moduleSource,
418
+ node: _objectSpread(_objectSpread({}, spec), {}, {
419
+ parent: node
420
+ })
421
+ };
422
+ importDeclarationsToUpdate.add(node);
423
+ }
424
+ } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
425
+ var importName = spec.imported.name;
426
+ if (importName === 'SimpleTag' || importName === 'RemovableTag') {
427
+ tagImports[spec.local.name] = {
428
+ type: importName,
429
+ source: moduleSource,
430
+ node: _objectSpread(_objectSpread({}, spec), {}, {
431
+ parent: node
432
+ })
433
+ };
434
+ // Mark this import declaration for potential updates
435
+ importDeclarationsToUpdate.add(node);
436
+ } else if (importName === 'AvatarTag') {
437
+ // Track new AvatarTag component - it should not be migrated
438
+ newTagImports[spec.local.name] = moduleSource;
439
+ }
440
+ // Note: Tag from named imports is not skipped - it may still need migration
441
+ // (e.g., if it has appearance prop or other old props)
442
+ }
443
+ });
444
+ }
445
+ // Track Avatar imports
446
+ if (moduleSource === '@atlaskit/avatar' || moduleSource.startsWith('@atlaskit/avatar')) {
447
+ node.specifiers.forEach(function (spec) {
448
+ if (spec.type === 'ImportDefaultSpecifier') {
449
+ avatarImports[spec.local.name] = moduleSource;
450
+ } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
451
+ if (spec.imported.name === 'Avatar') {
452
+ avatarImports[spec.local.name] = moduleSource;
453
+ }
454
+ }
455
+ });
456
+ }
457
+ }
458
+ },
459
+ JSXElement: function JSXElement(node) {
460
+ if (!isNodeOfType(node, 'JSXElement')) {
461
+ return;
462
+ }
463
+ if (!isNodeOfType(node.openingElement.name, 'JSXIdentifier')) {
464
+ return;
465
+ }
466
+ var elementName = node.openingElement.name.name;
467
+
468
+ // Skip new AvatarTag component - it should not be migrated
469
+ if (newTagImports[elementName]) {
470
+ return;
471
+ }
472
+
473
+ // Handle SimpleTag, RemovableTag, and Tag migrations
474
+ if (tagImports[elementName]) {
475
+ var tagImportInfo = tagImports[elementName];
476
+ var _attributesMap = getAttributesMap(node.openingElement.attributes);
477
+ var elemBeforeProp = _attributesMap.elemBefore,
478
+ avatarProp = _attributesMap.avatar,
479
+ _appearanceProp = _attributesMap.appearance,
480
+ colorProp = _attributesMap.color;
481
+
482
+ // For default import from @atlaskit/tag, check if it's already the new Tag
483
+ if (tagImportInfo.type === 'RemovableTag' && tagImportInfo.source === '@atlaskit/tag') {
484
+ // If using avatar prop, it's already the new Tag
485
+ if (avatarProp) {
486
+ return;
487
+ }
488
+
489
+ // Check if component name is already correct and nothing needs migration
490
+ if (elementName === 'Tag' || elementName === 'AvatarTag') {
491
+ var needsNameChange = false;
492
+ var needsMigration = needsNameChange || _appearanceProp || colorNeedsMapping(colorProp);
493
+ if (!needsMigration) {
494
+ // Still need to check elemBefore for Avatar
495
+ if (elemBeforeProp) {
496
+ var _hasAvatarInElemBefore = getAvatarComponentName(elemBeforeProp) !== null;
497
+ if (_hasAvatarInElemBefore) {
498
+ // Has Avatar in elemBefore, needs migration to AvatarTag
499
+ } else {
500
+ // No Avatar, nothing to migrate
501
+ return;
502
+ }
503
+ } else {
504
+ // No elemBefore, nothing to migrate
505
+ return;
506
+ }
507
+ }
508
+ // If we get here, something needs migration
509
+ }
510
+ }
511
+
512
+ // Determine migration target based on elemBefore containing Avatar
513
+ var hasAvatarInElemBefore = elemBeforeProp ? getAvatarComponentName(elemBeforeProp) !== null : false;
514
+ var migrationTarget = hasAvatarInElemBefore ? 'AvatarTag' : 'Tag';
515
+
516
+ // Record the migration target for this import
517
+ tagMigrationTargets[elementName] = migrationTarget;
518
+
519
+ // Migrate the JSX element
520
+ context.report({
521
+ node: node,
522
+ messageId: 'migrateTag',
523
+ fix: function fix(fixer) {
524
+ var _tagImportInfo$node, _tagImportInfo$node2, _tagImportInfo$node3, _tagImportInfo$node4, _tagImportInfo$node5, _tagImportInfo$node6;
525
+ var fixes = [];
526
+
527
+ // Fix the JSX element
528
+ var replacement = generateTagReplacement(node, {
529
+ isAvatarTag: hasAvatarInElemBefore,
530
+ isSimpleTag: !hasAvatarInElemBefore && tagImportInfo.type === 'SimpleTag'
531
+ });
532
+ fixes.push(fixer.replaceText(node, replacement));
533
+
534
+ // Fix the import statement for named imports, subpath default imports, and main package default imports
535
+ var isSubpathImport = ((_tagImportInfo$node = tagImportInfo.node) === null || _tagImportInfo$node === void 0 || (_tagImportInfo$node = _tagImportInfo$node.parent) === null || _tagImportInfo$node === void 0 || (_tagImportInfo$node = _tagImportInfo$node.source) === null || _tagImportInfo$node === void 0 ? void 0 : _tagImportInfo$node.value) === '@atlaskit/tag/simple-tag' || ((_tagImportInfo$node2 = tagImportInfo.node) === null || _tagImportInfo$node2 === void 0 || (_tagImportInfo$node2 = _tagImportInfo$node2.parent) === null || _tagImportInfo$node2 === void 0 || (_tagImportInfo$node2 = _tagImportInfo$node2.source) === null || _tagImportInfo$node2 === void 0 ? void 0 : _tagImportInfo$node2.value) === '@atlaskit/tag/removable-tag';
536
+ var isMainPackageDefaultImport = ((_tagImportInfo$node3 = tagImportInfo.node) === null || _tagImportInfo$node3 === void 0 || (_tagImportInfo$node3 = _tagImportInfo$node3.parent) === null || _tagImportInfo$node3 === void 0 || (_tagImportInfo$node3 = _tagImportInfo$node3.source) === null || _tagImportInfo$node3 === void 0 ? void 0 : _tagImportInfo$node3.value) === '@atlaskit/tag' && ((_tagImportInfo$node4 = tagImportInfo.node) === null || _tagImportInfo$node4 === void 0 ? void 0 : _tagImportInfo$node4.type) === 'ImportDefaultSpecifier';
537
+ if (isSubpathImport || isMainPackageDefaultImport || ((_tagImportInfo$node5 = tagImportInfo.node) === null || _tagImportInfo$node5 === void 0 || (_tagImportInfo$node5 = _tagImportInfo$node5.parent) === null || _tagImportInfo$node5 === void 0 || (_tagImportInfo$node5 = _tagImportInfo$node5.source) === null || _tagImportInfo$node5 === void 0 ? void 0 : _tagImportInfo$node5.value) === '@atlaskit/tag' && ((_tagImportInfo$node6 = tagImportInfo.node) === null || _tagImportInfo$node6 === void 0 ? void 0 : _tagImportInfo$node6.type) === 'ImportSpecifier') {
538
+ var _tagImportInfo$node7;
539
+ var importNode = (_tagImportInfo$node7 = tagImportInfo.node) === null || _tagImportInfo$node7 === void 0 ? void 0 : _tagImportInfo$node7.parent;
540
+ if (importNode) {
541
+ var sourceCode = context.getSourceCode();
542
+ var mainModuleSource = '@atlaskit/tag';
543
+
544
+ // Get all other specifiers that are not SimpleTag or RemovableTag
545
+ // For subpath imports and main package default imports, exclude the default specifier itself
546
+ var otherSpecifiers = importNode.specifiers.filter(function (spec) {
547
+ // Skip default specifiers from subpath imports and main package - they're being replaced
548
+ if (spec.type === 'ImportDefaultSpecifier' && (isSubpathImport || isMainPackageDefaultImport)) {
549
+ return false;
550
+ }
551
+ if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
552
+ var importName = spec.imported.name;
553
+ return importName !== 'SimpleTag' && importName !== 'RemovableTag';
554
+ }
555
+ return false;
556
+ }).map(function (spec) {
557
+ return sourceCode.getText(spec);
558
+ });
559
+ var newImportText = '';
560
+ if (migrationTarget === 'Tag') {
561
+ if (otherSpecifiers.length > 0) {
562
+ newImportText = "import Tag, { ".concat(otherSpecifiers.join(', '), " } from '").concat(mainModuleSource, "';");
563
+ } else {
564
+ newImportText = "import Tag from '".concat(mainModuleSource, "';");
565
+ }
566
+ } else if (migrationTarget === 'AvatarTag') {
567
+ if (otherSpecifiers.length > 0) {
568
+ newImportText = "import { AvatarTag, ".concat(otherSpecifiers.join(', '), " } from '").concat(mainModuleSource, "';");
569
+ } else {
570
+ newImportText = "import { AvatarTag } from '".concat(mainModuleSource, "';");
571
+ }
572
+ }
573
+ if (newImportText) {
574
+ fixes.push(fixer.replaceText(importNode, newImportText));
575
+ }
576
+ }
577
+ }
578
+ return fixes.length === 1 ? fixes[0] : fixes;
579
+ }
580
+ });
581
+ return;
582
+ }
583
+
584
+ // Handle Badge components
585
+ if (badgeImports[elementName]) {
586
+ // Find the appearance prop
587
+ var _appearanceProp2 = node.openingElement.attributes.find(function (attr) {
588
+ return attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier' && attr.name.name === 'appearance';
589
+ });
590
+ if (!_appearanceProp2 || _appearanceProp2.type !== 'JSXAttribute') {
591
+ // No appearance prop or it's a spread attribute, nothing to migrate
592
+ return;
593
+ }
594
+
595
+ // Check if it's a dynamic expression
596
+ if (isDynamicExpression(_appearanceProp2.value)) {
597
+ context.report({
598
+ node: _appearanceProp2,
599
+ messageId: 'dynamicBadgeAppearance'
600
+ });
601
+ return;
602
+ }
603
+
604
+ // Extract the string value
605
+ var stringValue = extractStringValue(_appearanceProp2.value);
606
+ if (stringValue && typeof stringValue === 'string') {
607
+ var mappedValue = mapBadgeToNewAppearanceValue(stringValue);
608
+ if (mappedValue !== stringValue) {
609
+ context.report({
610
+ node: _appearanceProp2,
611
+ messageId: 'updateBadgeAppearance',
612
+ data: {
613
+ oldValue: stringValue,
614
+ newValue: mappedValue
615
+ },
616
+ fix: createAppearanceFixer(_appearanceProp2.value, mappedValue)
617
+ });
618
+ }
619
+ }
620
+ return;
621
+ }
622
+
623
+ // Only process if this is a Lozenge component we've imported
624
+ if (!lozengeImports[elementName]) {
625
+ return;
626
+ }
627
+ var attributesMap = getAttributesMap(node.openingElement.attributes);
628
+ var appearanceProp = attributesMap.appearance;
629
+ var isBoldProp = attributesMap.isBold;
630
+
631
+ // Handle appearance prop value migration
632
+ if (appearanceProp) {
633
+ var shouldMigrateToTag = !isBoldProp || isLiteralFalse(isBoldProp.value);
634
+ if (!shouldMigrateToTag) {
635
+ // Only update appearance values for Lozenge components that stay as Lozenge
636
+ var _stringValue2 = extractStringValue(appearanceProp.value);
637
+ if (_stringValue2 && typeof _stringValue2 === 'string') {
638
+ var _mappedValue = mapToNewAppearanceValue(_stringValue2);
639
+ if (_mappedValue !== _stringValue2) {
640
+ context.report({
641
+ node: appearanceProp,
642
+ messageId: 'updateAppearance',
643
+ fix: createAppearanceFixer(appearanceProp.value, _mappedValue)
644
+ });
645
+ }
646
+ }
647
+ }
648
+ }
649
+
650
+ // Handle isBold prop and Tag migration
651
+ if (isBoldProp) {
652
+ if (isLiteralFalse(isBoldProp.value)) {
653
+ // isBold={false} should migrate to Tag
654
+ // Check if appearance is dynamic - if so, require manual review
655
+ if (appearanceProp && isDynamicExpression(appearanceProp.value)) {
656
+ context.report({
657
+ node: appearanceProp,
658
+ messageId: 'dynamicLozengeAppearance'
659
+ });
660
+ return;
661
+ }
662
+ context.report({
663
+ node: node,
664
+ messageId: 'migrateTag',
665
+ fix: function fix(fixer) {
666
+ var replacement = generateTagReplacement(node, {
667
+ isLozengeMigration: true
668
+ });
669
+ return fixer.replaceText(node, replacement);
670
+ }
671
+ });
672
+ } else if (isDynamicExpression(isBoldProp.value)) {
673
+ // Dynamic isBold requires manual review
674
+ context.report({
675
+ node: isBoldProp,
676
+ messageId: 'manualReview'
677
+ });
678
+ }
679
+ // isBold={true} or isBold (implicit true) - no action needed
680
+ } else {
681
+ // No isBold prop means implicit false, should migrate to Tag
682
+ // Check if appearance is dynamic - if so, require manual review
683
+ if (appearanceProp && isDynamicExpression(appearanceProp.value)) {
684
+ context.report({
685
+ node: appearanceProp,
686
+ messageId: 'dynamicLozengeAppearance'
687
+ });
688
+ return;
689
+ }
690
+ context.report({
691
+ node: node,
692
+ messageId: 'migrateTag',
693
+ fix: function fix(fixer) {
694
+ var replacement = generateTagReplacement(node, {
695
+ isLozengeMigration: true
696
+ });
697
+ return fixer.replaceText(node, replacement);
698
+ }
699
+ });
700
+ }
701
+ }
702
+ };
703
+ }
704
+ });
705
+ export default rule;