@atlaskit/eslint-plugin-design-system 15.1.0 → 15.1.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @atlaskit/eslint-plugin-design-system
2
2
 
3
+ ## 15.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`2b3eee14e8063`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/2b3eee14e8063) -
8
+ Update lozenge-badge-tag-labelling-system-migration ESLint rule and codemod for the new Lozenge
9
+ API.
10
+ - Lozenges no longer migrate to `<Tag>`. The `<Lozenge>` component stays as `<Lozenge>`.
11
+ - Legacy `appearance` values are now auto-fixed in-place to new semantic values: `default` →
12
+ `neutral`, `inprogress` → `information`, `moved` → `warning`, `removed` → `danger`, `new` →
13
+ `discovery`. The value `success` is unchanged.
14
+ - `isBold` is intentionally not flagged: while the feature flag
15
+ `platform-dst-lozenge-tag-badge-visual-uplifts` is OFF, users still need `isBold` to render
16
+ subtle Lozenges. It will be cleaned up in a separate pass after rollout.
17
+
3
18
  ## 15.1.0
4
19
 
5
20
  ### Minor Changes
@@ -22,9 +22,7 @@ var rule = (0, _createLintRule.createLintRule)({
22
22
  },
23
23
  messages: {
24
24
  updateAppearance: 'Update appearance value to new semantic value.',
25
- migrateTag: 'Non-bold <Lozenge> variants should migrate to <Tag> component. For safe, staged rollout, use the `migration_fallback="lozenge"` prop which renders as Lozenge when the feature flag is off.',
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.",
25
+ migrateTag: '<SimpleTag> and <RemovableTag> components should migrate to the new <Tag> or <AvatarTag> component.',
28
26
  updateBadgeAppearance: 'Update Badge appearance value "{{oldValue}}" to new semantic value "{{newValue}}".',
29
27
  dynamicBadgeAppearance: 'Dynamic appearance prop values require manual review to ensure they use the new semantic values: neutral, information, inverse, danger, success.'
30
28
  }
@@ -70,13 +68,6 @@ var rule = (0, _createLintRule.createLintRule)({
70
68
  */
71
69
  var newTagImports = {};
72
70
 
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
71
  /**
81
72
  * Check if a JSX attribute value is dynamic (not a static literal value)
82
73
  * Can be used for any prop type (boolean, string, etc.)
@@ -113,37 +104,22 @@ var rule = (0, _createLintRule.createLintRule)({
113
104
  }
114
105
 
115
106
  /**
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
107
+ * Map old Lozenge appearance values to new semantic appearance values.
108
+ * The new Lozenge no longer uses legacy values it uses semantic color names
109
+ * that align with the new labelling system.
118
110
  */
119
111
  function mapToNewAppearanceValue(oldValue) {
120
112
  var mapping = {
121
- success: 'success',
122
- default: 'default',
123
- removed: 'removed',
124
- inprogress: 'inprogress',
125
- new: 'new',
126
- moved: 'moved'
113
+ default: 'neutral',
114
+ inprogress: 'information',
115
+ moved: 'warning',
116
+ removed: 'danger',
117
+ new: 'discovery',
118
+ success: 'success'
127
119
  };
128
120
  return mapping[oldValue] || oldValue;
129
121
  }
130
122
 
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
123
  /**
148
124
  * Map Badge old appearance values to new semantic appearance values
149
125
  */
@@ -269,7 +245,7 @@ var rule = (0, _createLintRule.createLintRule)({
269
245
 
270
246
  /**
271
247
  * Generate the replacement JSX element text for Tag migration
272
- * Handles both regular Tag and avatarTag migrations
248
+ * Handles both regular Tag and AvatarTag migrations for SimpleTag/RemovableTag.
273
249
  */
274
250
  function generateTagReplacement(node) {
275
251
  var _context$sourceCode;
@@ -288,20 +264,7 @@ var rule = (0, _createLintRule.createLintRule)({
288
264
  return;
289
265
  }
290
266
  if (attrName === 'appearance') {
291
- // For Lozenge migrations, convert appearance to color prop
292
- // For SimpleTag/RemovableTag migrations, delete appearance prop
293
- if (options.isLozengeMigration) {
294
- // Map Lozenge appearance value to Tag color value and change prop name from appearance to color
295
- var stringValue = extractStringValue(attr.value);
296
- if (stringValue && typeof stringValue === 'string') {
297
- var mappedColor = mapLozengeAppearanceToTagColor(stringValue);
298
- newAttributes.push("color=\"".concat(mappedColor, "\""));
299
- }
300
- // If we can't extract the string value (dynamic expression), skip it
301
- // Dynamic expressions should be caught earlier and require manual review
302
- // This code path shouldn't be reached, but we skip to be safe
303
- }
304
- // For SimpleTag/RemovableTag migrations, skip appearance prop (delete it)
267
+ // Delete appearance prop not used in new Tag/AvatarTag API
305
268
  return;
306
269
  }
307
270
  if (attrName === 'color') {
@@ -310,10 +273,10 @@ var rule = (0, _createLintRule.createLintRule)({
310
273
  if (options.isAvatarTag) {
311
274
  return;
312
275
  }
313
- var _stringValue = extractStringValue(attr.value);
314
- if (_stringValue && typeof _stringValue === 'string') {
315
- var _mappedColor = mapTagColorValue(_stringValue);
316
- newAttributes.push("color=\"".concat(_mappedColor, "\""));
276
+ var stringValue = extractStringValue(attr.value);
277
+ if (stringValue && typeof stringValue === 'string') {
278
+ var mappedColor = mapTagColorValue(stringValue);
279
+ newAttributes.push("color=\"".concat(mappedColor, "\""));
317
280
  } else {
318
281
  // If we can't extract the string value, keep as-is
319
282
  var value = attr.value ? sourceCode.getText(attr.value) : '';
@@ -363,15 +326,10 @@ var rule = (0, _createLintRule.createLintRule)({
363
326
  }
364
327
  });
365
328
 
366
- // Add isRemovable={false} for SimpleTag migrations and Lozenge migrations
367
- if (options.isSimpleTag || options.isLozengeMigration) {
329
+ // Add isRemovable={false} for SimpleTag migrations
330
+ if (options.isSimpleTag) {
368
331
  newAttributes.push('isRemovable={false}');
369
332
  }
370
-
371
- // Add migration_fallback="lozenge" for Lozenge migrations to enable safe staged rollout
372
- if (options.isLozengeMigration) {
373
- newAttributes.push('migration_fallback="lozenge"');
374
- }
375
333
  var attributesText = newAttributes.length > 0 ? " ".concat(newAttributes.join(' ')) : '';
376
334
  var children = node.children.length > 0 ? sourceCode.getText().slice(node.openingElement.range[1], node.closingElement ? node.closingElement.range[0] : node.range[1]) : '';
377
335
  var componentName = options.preserveComponentName ? node.openingElement.name.name : options.isAvatarTag ? 'AvatarTag' : 'Tag';
@@ -642,77 +600,22 @@ var rule = (0, _createLintRule.createLintRule)({
642
600
  }
643
601
  var attributesMap = getAttributesMap(node.openingElement.attributes);
644
602
  var appearanceProp = attributesMap.appearance;
645
- var isBoldProp = attributesMap.isBold;
646
603
 
647
- // Handle appearance prop value migration
604
+ // Handle appearance prop value migration — always update to new semantic values.
605
+ // isBold is intentionally not flagged: users may still need it while the feature flag
606
+ // platform-dst-lozenge-tag-badge-visual-uplifts is OFF (subtle variant still rendered).
648
607
  if (appearanceProp) {
649
- var shouldMigrateToTag = !isBoldProp || isLiteralFalse(isBoldProp.value);
650
- if (!shouldMigrateToTag) {
651
- // Only update appearance values for Lozenge components that stay as Lozenge
652
- var _stringValue2 = extractStringValue(appearanceProp.value);
653
- if (_stringValue2 && typeof _stringValue2 === 'string') {
654
- var _mappedValue = mapToNewAppearanceValue(_stringValue2);
655
- if (_mappedValue !== _stringValue2) {
656
- context.report({
657
- node: appearanceProp,
658
- messageId: 'updateAppearance',
659
- fix: createAppearanceFixer(appearanceProp.value, _mappedValue)
660
- });
661
- }
662
- }
663
- }
664
- }
665
-
666
- // Handle isBold prop and Tag migration
667
- if (isBoldProp) {
668
- if (isLiteralFalse(isBoldProp.value)) {
669
- // isBold={false} should migrate to Tag
670
- // Check if appearance is dynamic - if so, require manual review
671
- if (appearanceProp && isDynamicExpression(appearanceProp.value)) {
608
+ var _stringValue = extractStringValue(appearanceProp.value);
609
+ if (_stringValue && typeof _stringValue === 'string') {
610
+ var _mappedValue = mapToNewAppearanceValue(_stringValue);
611
+ if (_mappedValue !== _stringValue) {
672
612
  context.report({
673
613
  node: appearanceProp,
674
- messageId: 'dynamicLozengeAppearance'
614
+ messageId: 'updateAppearance',
615
+ fix: createAppearanceFixer(appearanceProp.value, _mappedValue)
675
616
  });
676
- return;
677
617
  }
678
- context.report({
679
- node: node,
680
- messageId: 'migrateTag',
681
- fix: function fix(fixer) {
682
- var replacement = generateTagReplacement(node, {
683
- isLozengeMigration: true
684
- });
685
- return fixer.replaceText(node, replacement);
686
- }
687
- });
688
- } else if (isDynamicExpression(isBoldProp.value)) {
689
- // Dynamic isBold requires manual review
690
- context.report({
691
- node: isBoldProp,
692
- messageId: 'manualReview'
693
- });
694
618
  }
695
- // isBold={true} or isBold (implicit true) - no action needed
696
- } else {
697
- // No isBold prop means implicit false, should migrate to Tag
698
- // Check if appearance is dynamic - if so, require manual review
699
- if (appearanceProp && isDynamicExpression(appearanceProp.value)) {
700
- context.report({
701
- node: appearanceProp,
702
- messageId: 'dynamicLozengeAppearance'
703
- });
704
- return;
705
- }
706
- context.report({
707
- node: node,
708
- messageId: 'migrateTag',
709
- fix: function fix(fixer) {
710
- var replacement = generateTagReplacement(node, {
711
- isLozengeMigration: true
712
- });
713
- return fixer.replaceText(node, replacement);
714
- }
715
- });
716
619
  }
717
620
  }
718
621
  };
@@ -12,9 +12,7 @@ const rule = createLintRule({
12
12
  },
13
13
  messages: {
14
14
  updateAppearance: 'Update appearance value to new semantic value.',
15
- migrateTag: 'Non-bold <Lozenge> variants should migrate to <Tag> component. For safe, staged rollout, use the `migration_fallback="lozenge"` prop which renders as Lozenge when the feature flag is off.',
16
- manualReview: "Dynamic 'isBold' props require manual review before migration.",
17
- 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.",
15
+ migrateTag: '<SimpleTag> and <RemovableTag> components should migrate to the new <Tag> or <AvatarTag> component.',
18
16
  updateBadgeAppearance: 'Update Badge appearance value "{{oldValue}}" to new semantic value "{{newValue}}".',
19
17
  dynamicBadgeAppearance: 'Dynamic appearance prop values require manual review to ensure they use the new semantic values: neutral, information, inverse, danger, success.'
20
18
  }
@@ -60,13 +58,6 @@ const rule = createLintRule({
60
58
  */
61
59
  const newTagImports = {};
62
60
 
63
- /**
64
- * Check if a JSX attribute value is a literal false
65
- */
66
- function isLiteralFalse(node) {
67
- return node && node.type === 'JSXExpressionContainer' && node.expression && node.expression.type === 'Literal' && node.expression.value === false;
68
- }
69
-
70
61
  /**
71
62
  * Check if a JSX attribute value is dynamic (not a static literal value)
72
63
  * Can be used for any prop type (boolean, string, etc.)
@@ -103,37 +94,22 @@ const rule = createLintRule({
103
94
  }
104
95
 
105
96
  /**
106
- * Map old appearance values to new semantic appearance values
107
- * Both Lozenge and Tag now use the same appearance prop with new semantic values
97
+ * Map old Lozenge appearance values to new semantic appearance values.
98
+ * The new Lozenge no longer uses legacy values it uses semantic color names
99
+ * that align with the new labelling system.
108
100
  */
109
101
  function mapToNewAppearanceValue(oldValue) {
110
102
  const mapping = {
111
- success: 'success',
112
- default: 'default',
113
- removed: 'removed',
114
- inprogress: 'inprogress',
115
- new: 'new',
116
- moved: 'moved'
103
+ default: 'neutral',
104
+ inprogress: 'information',
105
+ moved: 'warning',
106
+ removed: 'danger',
107
+ new: 'discovery',
108
+ success: 'success'
117
109
  };
118
110
  return mapping[oldValue] || oldValue;
119
111
  }
120
112
 
121
- /**
122
- * Map Lozenge appearance values to Tag color values
123
- * Used when migrating Lozenge to Tag component
124
- */
125
- function mapLozengeAppearanceToTagColor(appearanceValue) {
126
- const mapping = {
127
- success: 'lime',
128
- default: 'gray',
129
- removed: 'red',
130
- inprogress: 'blue',
131
- new: 'purple',
132
- moved: 'yellow'
133
- };
134
- return mapping[appearanceValue] || appearanceValue;
135
- }
136
-
137
113
  /**
138
114
  * Map Badge old appearance values to new semantic appearance values
139
115
  */
@@ -259,7 +235,7 @@ const rule = createLintRule({
259
235
 
260
236
  /**
261
237
  * Generate the replacement JSX element text for Tag migration
262
- * Handles both regular Tag and avatarTag migrations
238
+ * Handles both regular Tag and AvatarTag migrations for SimpleTag/RemovableTag.
263
239
  */
264
240
  function generateTagReplacement(node, options = {}) {
265
241
  var _context$sourceCode;
@@ -277,20 +253,7 @@ const rule = createLintRule({
277
253
  return;
278
254
  }
279
255
  if (attrName === 'appearance') {
280
- // For Lozenge migrations, convert appearance to color prop
281
- // For SimpleTag/RemovableTag migrations, delete appearance prop
282
- if (options.isLozengeMigration) {
283
- // Map Lozenge appearance value to Tag color value and change prop name from appearance to color
284
- const stringValue = extractStringValue(attr.value);
285
- if (stringValue && typeof stringValue === 'string') {
286
- const mappedColor = mapLozengeAppearanceToTagColor(stringValue);
287
- newAttributes.push(`color="${mappedColor}"`);
288
- }
289
- // If we can't extract the string value (dynamic expression), skip it
290
- // Dynamic expressions should be caught earlier and require manual review
291
- // This code path shouldn't be reached, but we skip to be safe
292
- }
293
- // For SimpleTag/RemovableTag migrations, skip appearance prop (delete it)
256
+ // Delete appearance prop not used in new Tag/AvatarTag API
294
257
  return;
295
258
  }
296
259
  if (attrName === 'color') {
@@ -352,15 +315,10 @@ const rule = createLintRule({
352
315
  }
353
316
  });
354
317
 
355
- // Add isRemovable={false} for SimpleTag migrations and Lozenge migrations
356
- if (options.isSimpleTag || options.isLozengeMigration) {
318
+ // Add isRemovable={false} for SimpleTag migrations
319
+ if (options.isSimpleTag) {
357
320
  newAttributes.push('isRemovable={false}');
358
321
  }
359
-
360
- // Add migration_fallback="lozenge" for Lozenge migrations to enable safe staged rollout
361
- if (options.isLozengeMigration) {
362
- newAttributes.push('migration_fallback="lozenge"');
363
- }
364
322
  const attributesText = newAttributes.length > 0 ? ` ${newAttributes.join(' ')}` : '';
365
323
  const children = node.children.length > 0 ? sourceCode.getText().slice(node.openingElement.range[1], node.closingElement ? node.closingElement.range[0] : node.range[1]) : '';
366
324
  const componentName = options.preserveComponentName ? node.openingElement.name.name : options.isAvatarTag ? 'AvatarTag' : 'Tag';
@@ -632,77 +590,22 @@ const rule = createLintRule({
632
590
  }
633
591
  const attributesMap = getAttributesMap(node.openingElement.attributes);
634
592
  const appearanceProp = attributesMap.appearance;
635
- const isBoldProp = attributesMap.isBold;
636
593
 
637
- // Handle appearance prop value migration
594
+ // Handle appearance prop value migration — always update to new semantic values.
595
+ // isBold is intentionally not flagged: users may still need it while the feature flag
596
+ // platform-dst-lozenge-tag-badge-visual-uplifts is OFF (subtle variant still rendered).
638
597
  if (appearanceProp) {
639
- const shouldMigrateToTag = !isBoldProp || isLiteralFalse(isBoldProp.value);
640
- if (!shouldMigrateToTag) {
641
- // Only update appearance values for Lozenge components that stay as Lozenge
642
- const stringValue = extractStringValue(appearanceProp.value);
643
- if (stringValue && typeof stringValue === 'string') {
644
- const mappedValue = mapToNewAppearanceValue(stringValue);
645
- if (mappedValue !== stringValue) {
646
- context.report({
647
- node: appearanceProp,
648
- messageId: 'updateAppearance',
649
- fix: createAppearanceFixer(appearanceProp.value, mappedValue)
650
- });
651
- }
652
- }
653
- }
654
- }
655
-
656
- // Handle isBold prop and Tag migration
657
- if (isBoldProp) {
658
- if (isLiteralFalse(isBoldProp.value)) {
659
- // isBold={false} should migrate to Tag
660
- // Check if appearance is dynamic - if so, require manual review
661
- if (appearanceProp && isDynamicExpression(appearanceProp.value)) {
598
+ const stringValue = extractStringValue(appearanceProp.value);
599
+ if (stringValue && typeof stringValue === 'string') {
600
+ const mappedValue = mapToNewAppearanceValue(stringValue);
601
+ if (mappedValue !== stringValue) {
662
602
  context.report({
663
603
  node: appearanceProp,
664
- messageId: 'dynamicLozengeAppearance'
604
+ messageId: 'updateAppearance',
605
+ fix: createAppearanceFixer(appearanceProp.value, mappedValue)
665
606
  });
666
- return;
667
607
  }
668
- context.report({
669
- node: node,
670
- messageId: 'migrateTag',
671
- fix: fixer => {
672
- const replacement = generateTagReplacement(node, {
673
- isLozengeMigration: true
674
- });
675
- return fixer.replaceText(node, replacement);
676
- }
677
- });
678
- } else if (isDynamicExpression(isBoldProp.value)) {
679
- // Dynamic isBold requires manual review
680
- context.report({
681
- node: isBoldProp,
682
- messageId: 'manualReview'
683
- });
684
- }
685
- // isBold={true} or isBold (implicit true) - no action needed
686
- } else {
687
- // No isBold prop means implicit false, should migrate to Tag
688
- // Check if appearance is dynamic - if so, require manual review
689
- if (appearanceProp && isDynamicExpression(appearanceProp.value)) {
690
- context.report({
691
- node: appearanceProp,
692
- messageId: 'dynamicLozengeAppearance'
693
- });
694
- return;
695
608
  }
696
- context.report({
697
- node: node,
698
- messageId: 'migrateTag',
699
- fix: fixer => {
700
- const replacement = generateTagReplacement(node, {
701
- isLozengeMigration: true
702
- });
703
- return fixer.replaceText(node, replacement);
704
- }
705
- });
706
609
  }
707
610
  }
708
611
  };
@@ -15,9 +15,7 @@ var rule = createLintRule({
15
15
  },
16
16
  messages: {
17
17
  updateAppearance: 'Update appearance value to new semantic value.',
18
- migrateTag: 'Non-bold <Lozenge> variants should migrate to <Tag> component. For safe, staged rollout, use the `migration_fallback="lozenge"` prop which renders as Lozenge when the feature flag is off.',
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.",
18
+ migrateTag: '<SimpleTag> and <RemovableTag> components should migrate to the new <Tag> or <AvatarTag> component.',
21
19
  updateBadgeAppearance: 'Update Badge appearance value "{{oldValue}}" to new semantic value "{{newValue}}".',
22
20
  dynamicBadgeAppearance: 'Dynamic appearance prop values require manual review to ensure they use the new semantic values: neutral, information, inverse, danger, success.'
23
21
  }
@@ -63,13 +61,6 @@ var rule = createLintRule({
63
61
  */
64
62
  var newTagImports = {};
65
63
 
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
64
  /**
74
65
  * Check if a JSX attribute value is dynamic (not a static literal value)
75
66
  * Can be used for any prop type (boolean, string, etc.)
@@ -106,37 +97,22 @@ var rule = createLintRule({
106
97
  }
107
98
 
108
99
  /**
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
100
+ * Map old Lozenge appearance values to new semantic appearance values.
101
+ * The new Lozenge no longer uses legacy values it uses semantic color names
102
+ * that align with the new labelling system.
111
103
  */
112
104
  function mapToNewAppearanceValue(oldValue) {
113
105
  var mapping = {
114
- success: 'success',
115
- default: 'default',
116
- removed: 'removed',
117
- inprogress: 'inprogress',
118
- new: 'new',
119
- moved: 'moved'
106
+ default: 'neutral',
107
+ inprogress: 'information',
108
+ moved: 'warning',
109
+ removed: 'danger',
110
+ new: 'discovery',
111
+ success: 'success'
120
112
  };
121
113
  return mapping[oldValue] || oldValue;
122
114
  }
123
115
 
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
116
  /**
141
117
  * Map Badge old appearance values to new semantic appearance values
142
118
  */
@@ -262,7 +238,7 @@ var rule = createLintRule({
262
238
 
263
239
  /**
264
240
  * Generate the replacement JSX element text for Tag migration
265
- * Handles both regular Tag and avatarTag migrations
241
+ * Handles both regular Tag and AvatarTag migrations for SimpleTag/RemovableTag.
266
242
  */
267
243
  function generateTagReplacement(node) {
268
244
  var _context$sourceCode;
@@ -281,20 +257,7 @@ var rule = createLintRule({
281
257
  return;
282
258
  }
283
259
  if (attrName === 'appearance') {
284
- // For Lozenge migrations, convert appearance to color prop
285
- // For SimpleTag/RemovableTag migrations, delete appearance prop
286
- if (options.isLozengeMigration) {
287
- // Map Lozenge appearance value to Tag color value and change prop name from appearance to color
288
- var stringValue = extractStringValue(attr.value);
289
- if (stringValue && typeof stringValue === 'string') {
290
- var mappedColor = mapLozengeAppearanceToTagColor(stringValue);
291
- newAttributes.push("color=\"".concat(mappedColor, "\""));
292
- }
293
- // If we can't extract the string value (dynamic expression), skip it
294
- // Dynamic expressions should be caught earlier and require manual review
295
- // This code path shouldn't be reached, but we skip to be safe
296
- }
297
- // For SimpleTag/RemovableTag migrations, skip appearance prop (delete it)
260
+ // Delete appearance prop not used in new Tag/AvatarTag API
298
261
  return;
299
262
  }
300
263
  if (attrName === 'color') {
@@ -303,10 +266,10 @@ var rule = createLintRule({
303
266
  if (options.isAvatarTag) {
304
267
  return;
305
268
  }
306
- var _stringValue = extractStringValue(attr.value);
307
- if (_stringValue && typeof _stringValue === 'string') {
308
- var _mappedColor = mapTagColorValue(_stringValue);
309
- newAttributes.push("color=\"".concat(_mappedColor, "\""));
269
+ var stringValue = extractStringValue(attr.value);
270
+ if (stringValue && typeof stringValue === 'string') {
271
+ var mappedColor = mapTagColorValue(stringValue);
272
+ newAttributes.push("color=\"".concat(mappedColor, "\""));
310
273
  } else {
311
274
  // If we can't extract the string value, keep as-is
312
275
  var value = attr.value ? sourceCode.getText(attr.value) : '';
@@ -356,15 +319,10 @@ var rule = createLintRule({
356
319
  }
357
320
  });
358
321
 
359
- // Add isRemovable={false} for SimpleTag migrations and Lozenge migrations
360
- if (options.isSimpleTag || options.isLozengeMigration) {
322
+ // Add isRemovable={false} for SimpleTag migrations
323
+ if (options.isSimpleTag) {
361
324
  newAttributes.push('isRemovable={false}');
362
325
  }
363
-
364
- // Add migration_fallback="lozenge" for Lozenge migrations to enable safe staged rollout
365
- if (options.isLozengeMigration) {
366
- newAttributes.push('migration_fallback="lozenge"');
367
- }
368
326
  var attributesText = newAttributes.length > 0 ? " ".concat(newAttributes.join(' ')) : '';
369
327
  var children = node.children.length > 0 ? sourceCode.getText().slice(node.openingElement.range[1], node.closingElement ? node.closingElement.range[0] : node.range[1]) : '';
370
328
  var componentName = options.preserveComponentName ? node.openingElement.name.name : options.isAvatarTag ? 'AvatarTag' : 'Tag';
@@ -635,77 +593,22 @@ var rule = createLintRule({
635
593
  }
636
594
  var attributesMap = getAttributesMap(node.openingElement.attributes);
637
595
  var appearanceProp = attributesMap.appearance;
638
- var isBoldProp = attributesMap.isBold;
639
596
 
640
- // Handle appearance prop value migration
597
+ // Handle appearance prop value migration — always update to new semantic values.
598
+ // isBold is intentionally not flagged: users may still need it while the feature flag
599
+ // platform-dst-lozenge-tag-badge-visual-uplifts is OFF (subtle variant still rendered).
641
600
  if (appearanceProp) {
642
- var shouldMigrateToTag = !isBoldProp || isLiteralFalse(isBoldProp.value);
643
- if (!shouldMigrateToTag) {
644
- // Only update appearance values for Lozenge components that stay as Lozenge
645
- var _stringValue2 = extractStringValue(appearanceProp.value);
646
- if (_stringValue2 && typeof _stringValue2 === 'string') {
647
- var _mappedValue = mapToNewAppearanceValue(_stringValue2);
648
- if (_mappedValue !== _stringValue2) {
649
- context.report({
650
- node: appearanceProp,
651
- messageId: 'updateAppearance',
652
- fix: createAppearanceFixer(appearanceProp.value, _mappedValue)
653
- });
654
- }
655
- }
656
- }
657
- }
658
-
659
- // Handle isBold prop and Tag migration
660
- if (isBoldProp) {
661
- if (isLiteralFalse(isBoldProp.value)) {
662
- // isBold={false} should migrate to Tag
663
- // Check if appearance is dynamic - if so, require manual review
664
- if (appearanceProp && isDynamicExpression(appearanceProp.value)) {
601
+ var _stringValue = extractStringValue(appearanceProp.value);
602
+ if (_stringValue && typeof _stringValue === 'string') {
603
+ var _mappedValue = mapToNewAppearanceValue(_stringValue);
604
+ if (_mappedValue !== _stringValue) {
665
605
  context.report({
666
606
  node: appearanceProp,
667
- messageId: 'dynamicLozengeAppearance'
607
+ messageId: 'updateAppearance',
608
+ fix: createAppearanceFixer(appearanceProp.value, _mappedValue)
668
609
  });
669
- return;
670
610
  }
671
- context.report({
672
- node: node,
673
- messageId: 'migrateTag',
674
- fix: function fix(fixer) {
675
- var replacement = generateTagReplacement(node, {
676
- isLozengeMigration: true
677
- });
678
- return fixer.replaceText(node, replacement);
679
- }
680
- });
681
- } else if (isDynamicExpression(isBoldProp.value)) {
682
- // Dynamic isBold requires manual review
683
- context.report({
684
- node: isBoldProp,
685
- messageId: 'manualReview'
686
- });
687
611
  }
688
- // isBold={true} or isBold (implicit true) - no action needed
689
- } else {
690
- // No isBold prop means implicit false, should migrate to Tag
691
- // Check if appearance is dynamic - if so, require manual review
692
- if (appearanceProp && isDynamicExpression(appearanceProp.value)) {
693
- context.report({
694
- node: appearanceProp,
695
- messageId: 'dynamicLozengeAppearance'
696
- });
697
- return;
698
- }
699
- context.report({
700
- node: node,
701
- messageId: 'migrateTag',
702
- fix: function fix(fixer) {
703
- var replacement = generateTagReplacement(node, {
704
- isLozengeMigration: true
705
- });
706
- return fixer.replaceText(node, replacement);
707
- }
708
- });
709
612
  }
710
613
  }
711
614
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@atlaskit/eslint-plugin-design-system",
3
3
  "description": "The essential plugin for use with the Atlassian Design System.",
4
- "version": "15.1.0",
4
+ "version": "15.1.1",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
7
7
  "publishConfig": {