@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 +15 -0
- package/dist/cjs/rules/lozenge-badge-tag-labelling-system-migration/index.js +27 -124
- package/dist/es2019/rules/lozenge-badge-tag-labelling-system-migration/index.js +23 -120
- package/dist/esm/rules/lozenge-badge-tag-labelling-system-migration/index.js +27 -124
- package/package.json +1 -1
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: '
|
|
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
|
-
*
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
new: '
|
|
126
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
|
314
|
-
if (
|
|
315
|
-
var
|
|
316
|
-
newAttributes.push("color=\"".concat(
|
|
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
|
|
367
|
-
if (options.isSimpleTag
|
|
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
|
|
650
|
-
if (
|
|
651
|
-
|
|
652
|
-
|
|
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: '
|
|
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: '
|
|
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
|
-
*
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
new: '
|
|
116
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
|
356
|
-
if (options.isSimpleTag
|
|
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
|
|
640
|
-
if (
|
|
641
|
-
|
|
642
|
-
|
|
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: '
|
|
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: '
|
|
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
|
-
*
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
new: '
|
|
119
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
|
307
|
-
if (
|
|
308
|
-
var
|
|
309
|
-
newAttributes.push("color=\"".concat(
|
|
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
|
|
360
|
-
if (options.isSimpleTag
|
|
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
|
|
643
|
-
if (
|
|
644
|
-
|
|
645
|
-
|
|
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: '
|
|
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