@atlaskit/eslint-plugin-design-system 13.30.1 → 13.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +75 -75
  3. package/dist/cjs/presets/all-flat.codegen.js +3 -3
  4. package/dist/cjs/presets/all.codegen.js +3 -3
  5. package/dist/cjs/presets/recommended-flat.codegen.js +2 -2
  6. package/dist/cjs/presets/recommended.codegen.js +2 -2
  7. package/dist/cjs/rules/index.codegen.js +5 -5
  8. package/dist/cjs/rules/lozenge-badge-tag-labelling-system-migration/index.js +712 -0
  9. package/dist/cjs/rules/no-placeholder/index.js +162 -0
  10. package/dist/es2019/presets/all-flat.codegen.js +3 -3
  11. package/dist/es2019/presets/all.codegen.js +3 -3
  12. package/dist/es2019/presets/recommended-flat.codegen.js +2 -2
  13. package/dist/es2019/presets/recommended.codegen.js +2 -2
  14. package/dist/es2019/rules/index.codegen.js +5 -5
  15. package/dist/es2019/rules/lozenge-badge-tag-labelling-system-migration/index.js +702 -0
  16. package/dist/es2019/rules/no-placeholder/index.js +142 -0
  17. package/dist/esm/presets/all-flat.codegen.js +3 -3
  18. package/dist/esm/presets/all.codegen.js +3 -3
  19. package/dist/esm/presets/recommended-flat.codegen.js +2 -2
  20. package/dist/esm/presets/recommended.codegen.js +2 -2
  21. package/dist/esm/rules/index.codegen.js +5 -5
  22. package/dist/esm/rules/lozenge-badge-tag-labelling-system-migration/index.js +705 -0
  23. package/dist/esm/rules/no-placeholder/index.js +154 -0
  24. package/dist/types/presets/all-flat.codegen.d.ts +1 -1
  25. package/dist/types/presets/all.codegen.d.ts +1 -1
  26. package/dist/types/presets/recommended-flat.codegen.d.ts +1 -1
  27. package/dist/types/presets/recommended.codegen.d.ts +1 -1
  28. package/dist/types/rules/index.codegen.d.ts +1 -1
  29. package/dist/types/rules/no-placeholder/index.d.ts +6 -0
  30. package/dist/types-ts4.5/presets/all-flat.codegen.d.ts +1 -1
  31. package/dist/types-ts4.5/presets/all.codegen.d.ts +1 -1
  32. package/dist/types-ts4.5/presets/recommended-flat.codegen.d.ts +1 -1
  33. package/dist/types-ts4.5/presets/recommended.codegen.d.ts +1 -1
  34. package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -1
  35. package/dist/types-ts4.5/rules/no-placeholder/index.d.ts +6 -0
  36. package/package.json +2 -2
  37. package/dist/cjs/rules/lozenge-isBold-and-lozenge-badge-appearance-migration/index.js +0 -332
  38. package/dist/cjs/rules/no-utility-icons/checks.js +0 -246
  39. package/dist/cjs/rules/no-utility-icons/index.js +0 -49
  40. package/dist/es2019/rules/lozenge-isBold-and-lozenge-badge-appearance-migration/index.js +0 -324
  41. package/dist/es2019/rules/no-utility-icons/checks.js +0 -177
  42. package/dist/es2019/rules/no-utility-icons/index.js +0 -44
  43. package/dist/esm/rules/lozenge-isBold-and-lozenge-badge-appearance-migration/index.js +0 -326
  44. package/dist/esm/rules/no-utility-icons/checks.js +0 -239
  45. package/dist/esm/rules/no-utility-icons/index.js +0 -43
  46. package/dist/types/rules/lozenge-isBold-and-lozenge-badge-appearance-migration/index.d.ts +0 -3
  47. package/dist/types/rules/no-utility-icons/checks.d.ts +0 -10
  48. package/dist/types/rules/no-utility-icons/index.d.ts +0 -3
  49. package/dist/types-ts4.5/rules/no-utility-icons/checks.d.ts +0 -10
  50. /package/dist/{types-ts4.5/rules/no-utility-icons → types/rules/lozenge-badge-tag-labelling-system-migration}/index.d.ts +0 -0
  51. /package/dist/types-ts4.5/rules/{lozenge-isBold-and-lozenge-badge-appearance-migration → lozenge-badge-tag-labelling-system-migration}/index.d.ts +0 -0
@@ -1,177 +0,0 @@
1
- import { isNodeOfType } from 'eslint-codemod-utils';
2
- const specialCases = {
3
- '@atlaskit/icon/utility/migration/cross--editor-close': '@atlaskit/icon/core/migration/cross--editor-close'
4
- };
5
- const iconPropsinNewButton = ['icon', 'iconBefore', 'iconAfter'];
6
- export const createChecks = context => {
7
- const importStatementsUtility = {};
8
- const importStatementsCore = {};
9
- const newButtonImports = new Set();
10
- const errors = {};
11
-
12
- /**
13
- * Gets the value of a boolean configuration flag
14
- * @param key the key of the configuration flag
15
- * @param defaultValue The default value of the configuration flag
16
- * @returns defaultValue if the configuration flag is not set, the defaultValue of the configuration flag otherwise
17
- */
18
- const getConfigFlag = (key, defaultValue) => {
19
- if (context.options && context.options.length > 0 && context.options[0] && context.options[0].hasOwnProperty(key)) {
20
- return context.options[0][key] === !defaultValue ? !defaultValue : defaultValue;
21
- }
22
- return defaultValue;
23
- };
24
- const checkImportDeclarations = node => {
25
- const moduleSource = node.source.value;
26
- if (typeof moduleSource !== 'string') {
27
- return;
28
- }
29
- if (moduleSource.startsWith('@atlaskit/icon/utility/')) {
30
- for (const specifier of node.specifiers) {
31
- if (specifier.type === 'ImportDefaultSpecifier') {
32
- importStatementsUtility[specifier.local.name] = node;
33
- }
34
- }
35
- } else if (moduleSource.startsWith('@atlaskit/icon/core/')) {
36
- for (const specifier of node.specifiers) {
37
- if (specifier.type === 'ImportDefaultSpecifier') {
38
- importStatementsCore[moduleSource] = {
39
- node,
40
- localName: specifier.local.name
41
- };
42
- }
43
- }
44
- } else if (moduleSource.startsWith('@atlaskit/button/')) {
45
- for (const specifier of node.specifiers) {
46
- newButtonImports.add(specifier.local.name);
47
- }
48
- }
49
- };
50
- const checkJSXElement = node => {
51
- if (!(isNodeOfType(node, 'JSXElement') && isNodeOfType(node.openingElement.name, 'JSXIdentifier') && importStatementsUtility.hasOwnProperty(node.openingElement.name.name) && typeof importStatementsUtility[node.openingElement.name.name].source.value === 'string')) {
52
- return;
53
- }
54
- if (!errors.hasOwnProperty(node.openingElement.name.name)) {
55
- errors[node.openingElement.name.name] = [];
56
- }
57
- errors[node.openingElement.name.name].push({
58
- node,
59
- messageId: 'noUtilityIconsJSXElement',
60
- localName: node.openingElement.name.name,
61
- fixable: true,
62
- inNewButton: false
63
- });
64
- };
65
-
66
- // Cases: As Props, In Function Calls, In Arrays, In Maps, In Exports
67
- const checkIconReference = node => {
68
- //if this is an import statement then exit early
69
- if (node.parent && (isNodeOfType(node.parent, 'ImportSpecifier') || isNodeOfType(node.parent, 'ImportDefaultSpecifier'))) {
70
- return;
71
- }
72
-
73
- //check the reference to see if it's a utility icon, if not exit early
74
- if (!importStatementsUtility.hasOwnProperty(node.name)) {
75
- return;
76
- }
77
-
78
- // if it is in new Button then we can fix it
79
- if (node.parent && node.parent.parent && node.parent.parent.parent && isNodeOfType(node.parent, 'JSXExpressionContainer') && isNodeOfType(node.parent.parent, 'JSXAttribute') && isNodeOfType(node.parent.parent.name, 'JSXIdentifier') && iconPropsinNewButton.includes(node.parent.parent.name.name) && isNodeOfType(node.parent.parent.parent, 'JSXOpeningElement') && isNodeOfType(node.parent.parent.parent.name, 'JSXIdentifier') && newButtonImports.has(node.parent.parent.parent.name.name)) {
80
- // if it is in new Button then we can fix it
81
- if (!errors.hasOwnProperty(node.name)) {
82
- errors[node.name] = [];
83
- }
84
- errors[node.name].push({
85
- node,
86
- messageId: 'noUtilityIconsReference',
87
- localName: node.name,
88
- fixable: true,
89
- inNewButton: true
90
- });
91
- return;
92
- }
93
-
94
- // manually error
95
- if (!errors.hasOwnProperty(node.name)) {
96
- errors[node.name] = [];
97
- }
98
- errors[node.name].push({
99
- node,
100
- messageId: 'noUtilityIconsReference',
101
- localName: node.name,
102
- fixable: false,
103
- inNewButton: false
104
- });
105
- };
106
-
107
- /**
108
- * Throws the relevant errors in the correct order.
109
- */
110
- const throwErrors = () => {
111
- const shouldAutoFix = getConfigFlag('enableAutoFixer', false);
112
- for (const utilityIcon of Object.keys(errors)) {
113
- const allFixable = errors[utilityIcon].every(x => x.fixable); // Check if ALL errors for a giving import are fixable
114
- const originalImportNode = importStatementsUtility[utilityIcon];
115
- const oldImportName = importStatementsUtility[utilityIcon].source.value;
116
- const newImportName = specialCases.hasOwnProperty(oldImportName) ? specialCases[oldImportName] : oldImportName.replace('@atlaskit/icon/utility/', '@atlaskit/icon/core/');
117
- const existingImport = importStatementsCore.hasOwnProperty(newImportName) ? importStatementsCore[newImportName].localName : null;
118
- let replacementImportName = existingImport ? existingImport : allFixable ? utilityIcon : `${utilityIcon}Core`;
119
- let importFixAdded = false;
120
- for (const [index, error] of errors[utilityIcon].entries()) {
121
- if (error.fixable && shouldAutoFix) {
122
- context.report({
123
- node: error.node,
124
- messageId: error.messageId,
125
- fix: fixer => {
126
- const fixes = [];
127
-
128
- // Add a new import statement if it doesn't already exist
129
- if (!existingImport && !importFixAdded) {
130
- importFixAdded = true;
131
- fixes.push(fixer.insertTextBefore(originalImportNode, `import ${replacementImportName} from '${newImportName}';\n`));
132
- }
133
-
134
- // Handle JSX elements differently if they are in a "new Button"
135
- if (error.inNewButton) {
136
- // Replace the icon with a function that wraps it with iconProps and size="small"
137
- const wrappedIcon = `(iconProps) => <${replacementImportName} {...iconProps} size="small" />`;
138
- fixes.push(fixer.replaceText(error.node, wrappedIcon));
139
- } else if (isNodeOfType(error.node, 'JSXElement') && isNodeOfType(error.node.openingElement.name, 'JSXIdentifier')) {
140
- // Replace the JSX element's closing tag with size="small"
141
- const newOpeningElementText = context.sourceCode.getText(error.node.openingElement).replace(/\s*\/\s*>$/, ` size="small"\/>`).replace(new RegExp('<s*' + error.node.openingElement.name.name), `<${replacementImportName}`);
142
- fixes.push(fixer.replaceText(error.node.openingElement, newOpeningElementText));
143
- }
144
-
145
- // Handle the first fixable error for import removal if all fixable for this import
146
- if (index === 0 && allFixable) {
147
- fixes.push(fixer.remove(originalImportNode));
148
- }
149
- return fixes;
150
- }
151
- });
152
- } else {
153
- // Report non-fixable errors
154
- context.report({
155
- node: error.node,
156
- messageId: error.messageId
157
- });
158
- }
159
- }
160
- }
161
-
162
- // If other utility icons are imported but there were no errors for them - (this should only be unused imports but good to have as a backup), report them
163
- const otherUtilityImportsWithoutErrors = Object.keys(importStatementsUtility).filter(utilityIcon => !errors.hasOwnProperty(utilityIcon));
164
- for (const utilityIcon of otherUtilityImportsWithoutErrors) {
165
- context.report({
166
- node: importStatementsUtility[utilityIcon],
167
- messageId: 'noUtilityIconsImport'
168
- });
169
- }
170
- };
171
- return {
172
- checkImportDeclarations,
173
- checkJSXElement,
174
- checkIconReference,
175
- throwErrors
176
- };
177
- };
@@ -1,44 +0,0 @@
1
- import { createLintRule } from '../utils/create-rule';
2
- import { createChecks } from './checks';
3
- const rule = createLintRule({
4
- meta: {
5
- name: 'no-utility-icons',
6
- fixable: 'code',
7
- hasSuggestions: true,
8
- type: 'problem',
9
- schema: [{
10
- type: 'object',
11
- properties: {
12
- enableAutoFixer: {
13
- type: 'boolean'
14
- }
15
- },
16
- additionalProperties: false
17
- }],
18
- docs: {
19
- description: 'Disallow use of deprecated utility icons, in favor of core icons with `size="small"`.',
20
- recommended: true,
21
- severity: 'warn'
22
- },
23
- messages: {
24
- noUtilityIconsJSXElement: `Utility icons are deprecated. Please use core icons instead with the size prop set to small.`,
25
- noUtilityIconsImport: `Utility icons are deprecated. Please do not import them, use core icons instead.`,
26
- noUtilityIconsReference: `Utility icons are deprecated. To replace them, please use core icons with the size prop set to small instead.`
27
- }
28
- },
29
- create(context) {
30
- const {
31
- checkImportDeclarations,
32
- checkJSXElement,
33
- checkIconReference,
34
- throwErrors
35
- } = createChecks(context);
36
- return {
37
- ImportDeclaration: checkImportDeclarations,
38
- JSXElement: checkJSXElement,
39
- Identifier: checkIconReference,
40
- 'Program:exit': throwErrors
41
- };
42
- }
43
- });
44
- export default rule;
@@ -1,326 +0,0 @@
1
- import { isNodeOfType } from 'eslint-codemod-utils';
2
- import { createLintRule } from '../utils/create-rule';
3
- var rule = createLintRule({
4
- meta: {
5
- name: 'lozenge-isBold-and-lozenge-badge-appearance-migration',
6
- fixable: 'code',
7
- type: 'suggestion',
8
- docs: {
9
- description: 'Helps migrate Lozenge isBold prop and appearance values (for both Lozenge and Badge components) as part of the Labelling System Phase 1 migration.',
10
- recommended: false,
11
- severity: 'warn'
12
- },
13
- messages: {
14
- updateAppearance: 'Update appearance value to new semantic value.',
15
- migrateTag: 'Non-bold <Lozenge> variants should migrate to <Tag> component.',
16
- manualReview: "Dynamic 'isBold' props require manual review before migration.",
17
- updateBadgeAppearance: 'Update Badge appearance value "{{oldValue}}" to new semantic value "{{newValue}}".',
18
- dynamicBadgeAppearance: 'Dynamic appearance prop values require manual review to ensure they use the new semantic values: neutral, information, inverse, danger, success.'
19
- }
20
- },
21
- create: function create(context) {
22
- /**
23
- * Contains a map of imported Lozenge components.
24
- */
25
- var lozengeImports = {}; // local name -> import source
26
-
27
- /**
28
- * Contains a map of imported Badge components.
29
- */
30
- var badgeImports = {}; // local name -> import source
31
-
32
- /**
33
- * Check if a JSX attribute value is a literal false
34
- */
35
- function isLiteralFalse(node) {
36
- return node && node.type === 'JSXExpressionContainer' && node.expression && node.expression.type === 'Literal' && node.expression.value === false;
37
- }
38
-
39
- /**
40
- * Check if a JSX attribute value is dynamic (not a static literal value)
41
- * Can be used for any prop type (boolean, string, etc.)
42
- */
43
- function isDynamicExpression(node) {
44
- if (!node) {
45
- return false;
46
- }
47
-
48
- // If it's a plain literal (e.g., appearance="value"), it's not dynamic
49
- if (node.type === 'Literal') {
50
- return false;
51
- }
52
-
53
- // If it's an expression container with a non-literal expression, it's dynamic
54
- if (node.type === 'JSXExpressionContainer') {
55
- var expr = node.expression;
56
- return expr && expr.type !== 'Literal';
57
- }
58
- return false;
59
- }
60
-
61
- /**
62
- * Get all attributes as an object for easier manipulation
63
- */
64
- function getAttributesMap(attributes) {
65
- var map = {};
66
- attributes.forEach(function (attr) {
67
- if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier') {
68
- map[attr.name.name] = attr;
69
- }
70
- });
71
- return map;
72
- }
73
-
74
- /**
75
- * Map old appearance values to new semantic appearance values
76
- * Both Lozenge and Tag now use the same appearance prop with new semantic values
77
- */
78
- function mapToNewAppearanceValue(oldValue) {
79
- var mapping = {
80
- success: 'success',
81
- default: 'default',
82
- removed: 'removed',
83
- inprogress: 'inprogress',
84
- new: 'new',
85
- moved: 'moved'
86
- };
87
- // TODO: Update this mapping based on actual new semantic values when provided
88
- return mapping[oldValue] || oldValue;
89
- }
90
-
91
- /**
92
- * Map Badge old appearance values to new semantic appearance values
93
- */
94
- function mapBadgeToNewAppearanceValue(oldValue) {
95
- var mapping = {
96
- added: 'success',
97
- removed: 'danger',
98
- default: 'neutral',
99
- primary: 'information',
100
- primaryInverted: 'inverse',
101
- important: 'danger'
102
- };
103
- return mapping[oldValue] || oldValue;
104
- }
105
-
106
- /**
107
- * Extract the string value from a JSX attribute value
108
- */
109
- function extractStringValue(attrValue) {
110
- if (!attrValue) {
111
- return null;
112
- }
113
- if (attrValue.type === 'Literal') {
114
- return attrValue.value;
115
- }
116
- if (attrValue.type === 'JSXExpressionContainer' && attrValue.expression && attrValue.expression.type === 'Literal') {
117
- return attrValue.expression.value;
118
- }
119
- return null;
120
- }
121
-
122
- /**
123
- * Create a fixer function to replace an appearance prop value
124
- * Handles both Literal and JSXExpressionContainer with Literal
125
- */
126
- function createAppearanceFixer(attrValue, newValue) {
127
- return function (fixer) {
128
- if (!attrValue) {
129
- return null;
130
- }
131
- if (attrValue.type === 'Literal') {
132
- return fixer.replaceText(attrValue, "\"".concat(newValue, "\""));
133
- }
134
- if (attrValue.type === 'JSXExpressionContainer' && 'expression' in attrValue && attrValue.expression && attrValue.expression.type === 'Literal') {
135
- return fixer.replaceText(attrValue.expression, "\"".concat(newValue, "\""));
136
- }
137
- return null;
138
- };
139
- }
140
-
141
- /**
142
- * Generate the replacement JSX element text
143
- */
144
- function generateTagReplacement(node) {
145
- var sourceCode = context.getSourceCode();
146
- var attributes = node.openingElement.attributes;
147
-
148
- // Build new attributes array, excluding isBold and mapping appearance values to new semantics
149
- var newAttributes = [];
150
- attributes.forEach(function (attr) {
151
- if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier') {
152
- var attrName = attr.name.name;
153
- if (attrName === 'isBold') {
154
- // Skip isBold attribute
155
- return;
156
- }
157
- if (attrName === 'appearance') {
158
- // Map appearance value to new semantic value but keep the prop name as appearance
159
- var stringValue = extractStringValue(attr.value);
160
- if (stringValue && typeof stringValue === 'string') {
161
- var mappedAppearance = mapToNewAppearanceValue(stringValue);
162
- newAttributes.push("appearance=\"".concat(mappedAppearance, "\""));
163
- } else {
164
- // If we can't extract the string value, keep as-is with appearance prop
165
- var value = attr.value ? sourceCode.getText(attr.value) : '';
166
- newAttributes.push("appearance".concat(value ? "=".concat(value) : ''));
167
- }
168
- return;
169
- }
170
-
171
- // Keep all other attributes
172
- newAttributes.push(sourceCode.getText(attr));
173
- } else if (attr.type === 'JSXSpreadAttribute') {
174
- // Keep spread attributes
175
- newAttributes.push(sourceCode.getText(attr));
176
- }
177
- });
178
- var attributesText = newAttributes.length > 0 ? " ".concat(newAttributes.join(' ')) : '';
179
- var children = node.children.length > 0 ? sourceCode.getText().slice(node.openingElement.range[1], node.closingElement ? node.closingElement.range[0] : node.range[1]) : '';
180
- if (node.closingElement) {
181
- return "<Tag".concat(attributesText, ">").concat(children, "</Tag>");
182
- } else {
183
- return "<Tag".concat(attributesText, " />");
184
- }
185
- }
186
- return {
187
- ImportDeclaration: function ImportDeclaration(node) {
188
- var moduleSource = node.source.value;
189
- if (typeof moduleSource === 'string') {
190
- // Track Lozenge imports
191
- if (moduleSource === '@atlaskit/lozenge' || moduleSource.startsWith('@atlaskit/lozenge')) {
192
- node.specifiers.forEach(function (spec) {
193
- if (spec.type === 'ImportDefaultSpecifier') {
194
- lozengeImports[spec.local.name] = moduleSource;
195
- } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
196
- if (spec.imported.name === 'Lozenge') {
197
- lozengeImports[spec.local.name] = moduleSource;
198
- }
199
- }
200
- });
201
- }
202
- // Track Badge imports
203
- if (moduleSource === '@atlaskit/badge' || moduleSource.startsWith('@atlaskit/badge')) {
204
- node.specifiers.forEach(function (spec) {
205
- if (spec.type === 'ImportDefaultSpecifier') {
206
- badgeImports[spec.local.name] = moduleSource;
207
- } else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
208
- if (spec.imported.name === 'Badge' || spec.imported.name === 'default') {
209
- badgeImports[spec.local.name] = moduleSource;
210
- }
211
- }
212
- });
213
- }
214
- }
215
- },
216
- JSXElement: function JSXElement(node) {
217
- if (!isNodeOfType(node, 'JSXElement')) {
218
- return;
219
- }
220
- if (!isNodeOfType(node.openingElement.name, 'JSXIdentifier')) {
221
- return;
222
- }
223
- var elementName = node.openingElement.name.name;
224
-
225
- // Handle Badge components
226
- if (badgeImports[elementName]) {
227
- // Find the appearance prop
228
- var _appearanceProp = node.openingElement.attributes.find(function (attr) {
229
- return attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier' && attr.name.name === 'appearance';
230
- });
231
- if (!_appearanceProp || _appearanceProp.type !== 'JSXAttribute') {
232
- // No appearance prop or it's a spread attribute, nothing to migrate
233
- return;
234
- }
235
-
236
- // Check if it's a dynamic expression
237
- if (isDynamicExpression(_appearanceProp.value)) {
238
- context.report({
239
- node: _appearanceProp,
240
- messageId: 'dynamicBadgeAppearance'
241
- });
242
- return;
243
- }
244
-
245
- // Extract the string value
246
- var stringValue = extractStringValue(_appearanceProp.value);
247
- if (stringValue && typeof stringValue === 'string') {
248
- var mappedValue = mapBadgeToNewAppearanceValue(stringValue);
249
- if (mappedValue !== stringValue) {
250
- context.report({
251
- node: _appearanceProp,
252
- messageId: 'updateBadgeAppearance',
253
- data: {
254
- oldValue: stringValue,
255
- newValue: mappedValue
256
- },
257
- fix: createAppearanceFixer(_appearanceProp.value, mappedValue)
258
- });
259
- }
260
- }
261
- return;
262
- }
263
-
264
- // Only process if this is a Lozenge component we've imported
265
- if (!lozengeImports[elementName]) {
266
- return;
267
- }
268
- var attributesMap = getAttributesMap(node.openingElement.attributes);
269
- var appearanceProp = attributesMap.appearance;
270
- var isBoldProp = attributesMap.isBold;
271
-
272
- // Handle appearance prop value migration
273
- if (appearanceProp) {
274
- var shouldMigrateToTag = !isBoldProp || isLiteralFalse(isBoldProp.value);
275
- if (!shouldMigrateToTag) {
276
- // Only update appearance values for Lozenge components that stay as Lozenge
277
- var _stringValue = extractStringValue(appearanceProp.value);
278
- if (_stringValue && typeof _stringValue === 'string') {
279
- var _mappedValue = mapToNewAppearanceValue(_stringValue);
280
- if (_mappedValue !== _stringValue) {
281
- context.report({
282
- node: appearanceProp,
283
- messageId: 'updateAppearance',
284
- fix: createAppearanceFixer(appearanceProp.value, _mappedValue)
285
- });
286
- }
287
- }
288
- }
289
- }
290
-
291
- // Handle isBold prop and Tag migration
292
- if (isBoldProp) {
293
- if (isLiteralFalse(isBoldProp.value)) {
294
- // isBold={false} should migrate to Tag
295
- context.report({
296
- node: node,
297
- messageId: 'migrateTag',
298
- fix: function fix(fixer) {
299
- var replacement = generateTagReplacement(node);
300
- return fixer.replaceText(node, replacement);
301
- }
302
- });
303
- } else if (isDynamicExpression(isBoldProp.value)) {
304
- // Dynamic isBold requires manual review
305
- context.report({
306
- node: isBoldProp,
307
- messageId: 'manualReview'
308
- });
309
- }
310
- // isBold={true} or isBold (implicit true) - no action needed
311
- } else {
312
- // No isBold prop means implicit false, should migrate to Tag
313
- context.report({
314
- node: node,
315
- messageId: 'migrateTag',
316
- fix: function fix(fixer) {
317
- var replacement = generateTagReplacement(node);
318
- return fixer.replaceText(node, replacement);
319
- }
320
- });
321
- }
322
- }
323
- };
324
- }
325
- });
326
- export default rule;