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