@atlaskit/eslint-plugin-design-system
Version:
The essential plugin for use with the Atlassian Design System.
636 lines (596 loc) • 29.4 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
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; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
import { isNodeOfType } from 'eslint-codemod-utils';
import { createLintRule } from '../utils/create-lint-rule';
import { isImportFromPackage } from '../utils/is-import-from-package';
var LOZENGE_IMPORT_SOURCES = new Set(['@atlaskit/lozenge', '@atlaskit/lozenge/lozenge']);
var BADGE_IMPORT_SOURCES = new Set(['@atlaskit/badge', '@atlaskit/badge/badge']);
var SIMPLE_TAG_IMPORT_SOURCES = new Set(['@atlaskit/tag/simple-tag']);
var REMOVABLE_TAG_IMPORT_SOURCES = new Set(['@atlaskit/tag', '@atlaskit/tag/removable-tag']);
var AVATAR_IMPORT_SOURCES = new Set(['@atlaskit/avatar', '@atlaskit/avatar/avatar', '@atlaskit/avatar/Avatar']);
var rule = createLintRule({
meta: {
name: 'lozenge-badge-tag-labelling-system-migration',
fixable: 'code',
type: 'suggestion',
docs: {
description: 'Helps migrate Lozenge isBold prop, Badge appearance values, and SimpleTag/RemovableTag components as part of the Labelling System Phase 1 migration.',
recommended: false,
severity: 'warn'
},
messages: {
updateAppearance: 'Update appearance value to new semantic value.',
migrateTag: '<SimpleTag> and <RemovableTag> components should migrate to the new <Tag> or <AvatarTag> component.',
updateBadgeAppearance: 'Update Badge appearance value "{{oldValue}}" to new semantic value "{{newValue}}".',
dynamicBadgeAppearance: 'Dynamic appearance prop values require manual review to ensure they use the new semantic values: neutral, information, inverse, danger, success.'
}
},
create: function create(context) {
/**
* Contains a map of imported Lozenge components.
*/
var lozengeImports = {}; // local name -> import source
/**
* Contains a map of imported Badge components.
*/
var badgeImports = {}; // local name -> import source
/**
* Contains a map of imported Tag components (SimpleTag, RemovableTag, or default Tag imports).
* Maps local name to { type: 'SimpleTag' | 'RemovableTag' | 'Tag', source: string, node: ImportNode }
*/
var tagImports = {};
/**
* Tracks which tag imports need to migrate to Tag (default) or AvatarTag (named)
* Maps local name to migration target: 'Tag' | 'AvatarTag'
*/
var tagMigrationTargets = {};
/**
* Tracks import declaration nodes that need to be updated
*/
var importDeclarationsToUpdate = new Set();
/**
* Contains a map of imported Avatar components from @atlaskit/avatar.
* Maps local name to import source
*/
var avatarImports = {};
/**
* Contains a map of imported Tag and AvatarTag components from @atlaskit/tag.
* These are the new components that should not be migrated.
* Maps local name to import source
*/
var newTagImports = {};
/**
* Check if a JSX attribute value is dynamic (not a static literal value)
* Can be used for any prop type (boolean, string, etc.)
*/
function isDynamicExpression(node) {
if (!node) {
return false;
}
// If it's a plain literal (e.g., appearance="value"), it's not dynamic
if (node.type === 'Literal') {
return false;
}
// If it's an expression container with a non-literal expression, it's dynamic
if (node.type === 'JSXExpressionContainer') {
var expr = node.expression;
return expr && expr.type !== 'Literal';
}
return false;
}
/**
* Get all attributes as an object for easier manipulation
*/
function getAttributesMap(attributes) {
var map = {};
attributes.forEach(function (attr) {
if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier') {
map[attr.name.name] = attr;
}
});
return map;
}
/**
* Map old Lozenge appearance values to new semantic appearance values.
* The new Lozenge no longer uses legacy values — it uses semantic color names
* that align with the new labelling system.
*/
function mapToNewAppearanceValue(oldValue) {
var mapping = {
default: 'neutral',
inprogress: 'information',
moved: 'warning',
removed: 'danger',
new: 'discovery',
success: 'success'
};
return mapping[oldValue] || oldValue;
}
/**
* Map Badge old appearance values to new semantic appearance values
*/
function mapBadgeToNewAppearanceValue(oldValue) {
var mapping = {
added: 'success',
removed: 'danger',
default: 'neutral',
primary: 'information',
primaryInverted: 'inverse',
important: 'danger'
};
return mapping[oldValue] || oldValue;
}
/**
* Map Tag color light variants to semantic color values
*/
function mapTagColorValue(oldValue) {
var mapping = {
limeLight: 'lime',
orangeLight: 'orange',
magentaLight: 'magenta',
greenLight: 'green',
blueLight: 'blue',
redLight: 'red',
purpleLight: 'purple',
greyLight: 'gray',
tealLight: 'teal',
yellowLight: 'yellow',
grey: 'gray'
};
return mapping[oldValue] || oldValue;
}
/**
* Check if elemBefore prop contains only an Avatar component from @atlaskit/avatar
* Returns the Avatar component name if it's from the avatar package, null otherwise
*/
function getAvatarComponentName(elemBeforeProp) {
var getJsxIdentifierName = function getJsxIdentifierName(node) {
return (node === null || node === void 0 ? void 0 : node.type) === 'JSXIdentifier' ? node.name : null;
};
if (!elemBeforeProp || !elemBeforeProp.value) {
return null;
}
var value = elemBeforeProp.value;
// Check for JSX element: <Avatar ... />
if (value.type === 'JSXElement') {
var avatarName = getJsxIdentifierName(value.openingElement.name);
if (!avatarName) {
return null;
}
if (avatarImports[avatarName]) {
return avatarName;
}
}
// Check for JSX expression container: {<Avatar ... />}
if (value.type === 'JSXExpressionContainer' && value.expression) {
// Direct JSX element: {<Avatar ... />}
if (value.expression.type === 'JSXElement' && getJsxIdentifierName(value.expression.openingElement.name)) {
var _avatarName = getJsxIdentifierName(value.expression.openingElement.name);
if (!_avatarName) {
return null;
}
if (avatarImports[_avatarName]) {
return _avatarName;
}
}
// Arrow function: {() => <Avatar ... />}
if (value.expression.type === 'ArrowFunctionExpression') {
var body = value.expression.body;
if (body.type === 'JSXElement') {
var _avatarName2 = getJsxIdentifierName(body.openingElement.name);
if (!_avatarName2) {
return null;
}
if (avatarImports[_avatarName2]) {
return _avatarName2;
}
}
}
}
return null;
}
/**
* Check if color prop value needs mapping
*/
function colorNeedsMapping(colorProp) {
if (!(colorProp !== null && colorProp !== void 0 && colorProp.value)) {
return false;
}
var stringValue = extractStringValue(colorProp.value);
return stringValue !== null && typeof stringValue === 'string' && mapTagColorValue(stringValue) !== stringValue;
}
/**
* Extract the string value from a JSX attribute value
*/
function extractStringValue(attrValue) {
if (!attrValue) {
return null;
}
if (attrValue.type === 'Literal') {
return attrValue.value;
}
if (attrValue.type === 'JSXExpressionContainer' && attrValue.expression && attrValue.expression.type === 'Literal') {
return attrValue.expression.value;
}
return null;
}
/**
* Create a fixer function to replace an appearance prop value
* Handles both Literal and JSXExpressionContainer with Literal
*/
function createAppearanceFixer(attrValue, newValue) {
return function (fixer) {
if (!attrValue) {
return null;
}
if (attrValue.type === 'Literal') {
return fixer.replaceText(attrValue, "\"".concat(newValue, "\""));
}
if (attrValue.type === 'JSXExpressionContainer' && 'expression' in attrValue && attrValue.expression && attrValue.expression.type === 'Literal') {
return fixer.replaceText(attrValue.expression, "\"".concat(newValue, "\""));
}
return null;
};
}
/**
* Generate the replacement JSX element text for Tag migration
* Handles both regular Tag and AvatarTag migrations for SimpleTag/RemovableTag.
*/
function generateTagReplacement(node) {
var _context$sourceCode;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// @ts-ignore - Jira's ESLint v10 types expose sourceCode, platform still checks with ESLint v9.
var sourceCode = (_context$sourceCode = context.sourceCode) !== null && _context$sourceCode !== void 0 ? _context$sourceCode : context.getSourceCode();
var attributes = node.openingElement.attributes;
// Build new attributes array
var newAttributes = [];
attributes.forEach(function (attr) {
if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier') {
var attrName = attr.name.name;
if (attrName === 'isBold') {
// Skip isBold attribute
return;
}
if (attrName === 'appearance') {
// Delete appearance prop — not used in new Tag/AvatarTag API
return;
}
if (attrName === 'color') {
// For avatar tag, skip color prop; for regular tag, map color value
// Note: Lozenge doesn't have a color prop, but Tag/SimpleTag/RemovableTag do
if (options.isAvatarTag) {
return;
}
var stringValue = extractStringValue(attr.value);
if (stringValue && typeof stringValue === 'string') {
var mappedColor = mapTagColorValue(stringValue);
newAttributes.push("color=\"".concat(mappedColor, "\""));
} else {
// If we can't extract the string value, keep as-is
var value = attr.value ? sourceCode.getText(attr.value) : '';
newAttributes.push("color".concat(value ? "=".concat(value) : ''));
}
return;
}
if (attrName === 'elemBefore') {
// For avatar tag, rename elemBefore to avatar and use render props
if (options.isAvatarTag) {
var elemBeforeValue = attr.value;
var avatarElement = null;
// Extract Avatar element from various formats
if (elemBeforeValue.type === 'JSXElement') {
avatarElement = elemBeforeValue;
} else if (elemBeforeValue.type === 'JSXExpressionContainer') {
var expr = elemBeforeValue.expression;
// Direct JSX element: {<Avatar ... />}
if (expr.type === 'JSXElement') {
avatarElement = expr;
}
// Arrow function: {() => <Avatar ... />}
else if (expr.type === 'ArrowFunctionExpression' && expr.body.type === 'JSXElement') {
avatarElement = expr.body;
}
}
if (avatarElement) {
// Generate render props: avatar={(props) => <Avatar {...props} ... />}
var avatarElementText = sourceCode.getText(avatarElement);
var avatarComponentName = avatarElement.openingElement.name.type === 'JSXIdentifier' ? avatarElement.openingElement.name.name : 'Avatar';
// Add {...props} spread to the Avatar element attributes
var avatarWithProps = avatarElementText.replace(new RegExp("<".concat(avatarComponentName, "(\\s|/>)")), "<".concat(avatarComponentName, " {...props}$1"));
newAttributes.push("avatar={(props) => ".concat(avatarWithProps, "}"));
}
return;
}
// For regular tag, keep elemBefore as-is
newAttributes.push(sourceCode.getText(attr));
return;
}
// Keep all other attributes
newAttributes.push(sourceCode.getText(attr));
} else if (attr.type === 'JSXSpreadAttribute') {
// Keep spread attributes
newAttributes.push(sourceCode.getText(attr));
}
});
// Add isRemovable={false} for SimpleTag migrations
if (options.isSimpleTag) {
newAttributes.push('isRemovable={false}');
}
var attributesText = newAttributes.length > 0 ? " ".concat(newAttributes.join(' ')) : '';
var children = node.children.length > 0 ? sourceCode.getText().slice(node.openingElement.range[1], node.closingElement ? node.closingElement.range[0] : node.range[1]) : '';
var componentName = options.preserveComponentName ? node.openingElement.name.name : options.isAvatarTag ? 'AvatarTag' : 'Tag';
if (node.closingElement) {
return "<".concat(componentName).concat(attributesText, ">").concat(children, "</").concat(componentName, ">");
} else {
return "<".concat(componentName).concat(attributesText, " />");
}
}
return {
ImportDeclaration: function ImportDeclaration(node) {
var moduleSource = node.source.value;
if (typeof moduleSource === 'string') {
// Track Lozenge imports
if (LOZENGE_IMPORT_SOURCES.has(moduleSource)) {
node.specifiers.forEach(function (spec) {
if (spec.type === 'ImportDefaultSpecifier') {
lozengeImports[spec.local.name] = moduleSource;
} else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
if (spec.imported.name === 'Lozenge') {
lozengeImports[spec.local.name] = moduleSource;
}
}
});
}
// Track Badge imports
if (BADGE_IMPORT_SOURCES.has(moduleSource)) {
node.specifiers.forEach(function (spec) {
if (spec.type === 'ImportDefaultSpecifier') {
badgeImports[spec.local.name] = moduleSource;
} else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
if (spec.imported.name === 'Badge' || spec.imported.name === 'default') {
badgeImports[spec.local.name] = moduleSource;
}
}
});
}
// Track Tag imports (SimpleTag, RemovableTag only - not the new Tag component)
if (isImportFromPackage(moduleSource, '@atlaskit/tag')) {
node.specifiers.forEach(function (spec) {
if (spec.type === 'ImportDefaultSpecifier') {
// Check for default imports from subpaths and main package
if (SIMPLE_TAG_IMPORT_SOURCES.has(moduleSource)) {
// Default import from @atlaskit/tag/simple-tag is a SimpleTag
tagImports[spec.local.name] = {
type: 'SimpleTag',
source: moduleSource,
node: _objectSpread(_objectSpread({}, spec), {}, {
parent: node
})
};
importDeclarationsToUpdate.add(node);
} else if (REMOVABLE_TAG_IMPORT_SOURCES.has(moduleSource)) {
// Default import from @atlaskit/tag/removable-tag or @atlaskit/tag is a RemovableTag
tagImports[spec.local.name] = {
type: 'RemovableTag',
source: moduleSource,
node: _objectSpread(_objectSpread({}, spec), {}, {
parent: node
})
};
importDeclarationsToUpdate.add(node);
}
} else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
var importName = spec.imported.name;
if (importName === 'SimpleTag' || importName === 'RemovableTag') {
tagImports[spec.local.name] = {
type: importName,
source: moduleSource,
node: _objectSpread(_objectSpread({}, spec), {}, {
parent: node
})
};
// Mark this import declaration for potential updates
importDeclarationsToUpdate.add(node);
} else if (importName === 'AvatarTag') {
// Track new AvatarTag component - it should not be migrated
newTagImports[spec.local.name] = moduleSource;
}
// Note: Tag from named imports is not skipped - it may still need migration
// (e.g., if it has appearance prop or other old props)
}
});
}
// Track Avatar imports
if (AVATAR_IMPORT_SOURCES.has(moduleSource)) {
node.specifiers.forEach(function (spec) {
if (spec.type === 'ImportDefaultSpecifier') {
avatarImports[spec.local.name] = moduleSource;
} else if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
if (spec.imported.name === 'Avatar') {
avatarImports[spec.local.name] = moduleSource;
}
}
});
}
}
},
JSXElement: function JSXElement(node) {
if (!isNodeOfType(node, 'JSXElement')) {
return;
}
if (!isNodeOfType(node.openingElement.name, 'JSXIdentifier')) {
return;
}
var elementName = node.openingElement.name.name;
// Skip new AvatarTag component - it should not be migrated
if (newTagImports[elementName]) {
return;
}
// Handle SimpleTag, RemovableTag, and Tag migrations
if (tagImports[elementName]) {
var tagImportInfo = tagImports[elementName];
var _attributesMap = getAttributesMap(node.openingElement.attributes);
var elemBeforeProp = _attributesMap.elemBefore,
avatarProp = _attributesMap.avatar,
_appearanceProp = _attributesMap.appearance,
colorProp = _attributesMap.color;
// For default import from @atlaskit/tag, check if it's already the new Tag
if (tagImportInfo.type === 'RemovableTag' && tagImportInfo.source === '@atlaskit/tag') {
// If using avatar prop, it's already the new Tag
if (avatarProp) {
return;
}
// Check if component name is already correct and nothing needs migration
if (elementName === 'Tag' || elementName === 'AvatarTag') {
var needsNameChange = false;
var needsMigration = needsNameChange || _appearanceProp || colorNeedsMapping(colorProp);
if (!needsMigration) {
// Still need to check elemBefore for Avatar
if (elemBeforeProp) {
var _hasAvatarInElemBefore = getAvatarComponentName(elemBeforeProp) !== null;
if (_hasAvatarInElemBefore) {
// Has Avatar in elemBefore, needs migration to AvatarTag
} else {
// No Avatar, nothing to migrate
return;
}
} else {
// No elemBefore, nothing to migrate
return;
}
}
// If we get here, something needs migration
}
}
// Determine migration target based on elemBefore containing Avatar
var hasAvatarInElemBefore = elemBeforeProp ? getAvatarComponentName(elemBeforeProp) !== null : false;
var migrationTarget = hasAvatarInElemBefore ? 'AvatarTag' : 'Tag';
// Record the migration target for this import
tagMigrationTargets[elementName] = migrationTarget;
// Migrate the JSX element
context.report({
node: node,
messageId: 'migrateTag',
fix: function fix(fixer) {
var _tagImportInfo$node, _tagImportInfo$node2, _tagImportInfo$node3, _tagImportInfo$node4, _tagImportInfo$node5, _tagImportInfo$node6;
var fixes = [];
// Fix the JSX element
var replacement = generateTagReplacement(node, {
isAvatarTag: hasAvatarInElemBefore,
isSimpleTag: !hasAvatarInElemBefore && tagImportInfo.type === 'SimpleTag'
});
fixes.push(fixer.replaceText(node, replacement));
// Fix the import statement for named imports, subpath default imports, and main package default imports
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';
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';
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') {
var _tagImportInfo$node7;
var importNode = (_tagImportInfo$node7 = tagImportInfo.node) === null || _tagImportInfo$node7 === void 0 ? void 0 : _tagImportInfo$node7.parent;
if (importNode) {
var _context$sourceCode2;
// @ts-ignore - Jira's ESLint v10 types expose sourceCode, platform still checks with ESLint v9.
var sourceCode = (_context$sourceCode2 = context.sourceCode) !== null && _context$sourceCode2 !== void 0 ? _context$sourceCode2 : context.getSourceCode();
var mainModuleSource = '@atlaskit/tag';
// Get all other specifiers that are not SimpleTag or RemovableTag
// For subpath imports and main package default imports, exclude the default specifier itself
var otherSpecifiers = importNode.specifiers.filter(function (spec) {
// Skip default specifiers from subpath imports and main package - they're being replaced
if (spec.type === 'ImportDefaultSpecifier' && (isSubpathImport || isMainPackageDefaultImport)) {
return false;
}
if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
var importName = spec.imported.name;
return importName !== 'SimpleTag' && importName !== 'RemovableTag';
}
return false;
}).map(function (spec) {
return sourceCode.getText(spec);
});
var newImportText = '';
if (migrationTarget === 'Tag') {
if (otherSpecifiers.length > 0) {
newImportText = "import Tag, { ".concat(otherSpecifiers.join(', '), " } from '").concat(mainModuleSource, "';");
} else {
newImportText = "import Tag from '".concat(mainModuleSource, "';");
}
} else if (migrationTarget === 'AvatarTag') {
if (otherSpecifiers.length > 0) {
newImportText = "import { AvatarTag, ".concat(otherSpecifiers.join(', '), " } from '").concat(mainModuleSource, "';");
} else {
newImportText = "import { AvatarTag } from '".concat(mainModuleSource, "';");
}
}
if (newImportText) {
fixes.push(fixer.replaceText(importNode, newImportText));
}
}
}
return fixes.length === 1 ? fixes[0] : fixes;
}
});
return;
}
// Handle Badge components
if (badgeImports[elementName]) {
// Find the appearance prop
var _appearanceProp2 = node.openingElement.attributes.find(function (attr) {
return attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier' && attr.name.name === 'appearance';
});
if (!_appearanceProp2 || _appearanceProp2.type !== 'JSXAttribute') {
// No appearance prop or it's a spread attribute, nothing to migrate
return;
}
// Check if it's a dynamic expression
if (isDynamicExpression(_appearanceProp2.value)) {
context.report({
node: _appearanceProp2,
messageId: 'dynamicBadgeAppearance'
});
return;
}
// Extract the string value
var stringValue = extractStringValue(_appearanceProp2.value);
if (stringValue && typeof stringValue === 'string') {
var mappedValue = mapBadgeToNewAppearanceValue(stringValue);
if (mappedValue !== stringValue) {
context.report({
node: _appearanceProp2,
messageId: 'updateBadgeAppearance',
data: {
oldValue: stringValue,
newValue: mappedValue
},
fix: createAppearanceFixer(_appearanceProp2.value, mappedValue)
});
}
}
return;
}
// Only process if this is a Lozenge component we've imported
if (!lozengeImports[elementName]) {
return;
}
var attributesMap = getAttributesMap(node.openingElement.attributes);
var appearanceProp = attributesMap.appearance;
// Handle appearance prop value migration — always update to new semantic values.
// isBold is intentionally not flagged: users may still need it while the feature flag
// platform-dst-lozenge-tag-badge-visual-uplifts is OFF (subtle variant still rendered).
if (appearanceProp) {
var _stringValue = extractStringValue(appearanceProp.value);
if (_stringValue && typeof _stringValue === 'string') {
var _mappedValue = mapToNewAppearanceValue(_stringValue);
if (_mappedValue !== _stringValue) {
context.report({
node: appearanceProp,
messageId: 'updateAppearance',
fix: createAppearanceFixer(appearanceProp.value, _mappedValue)
});
}
}
}
}
};
}
});
export default rule;