eslint-plugin-unicorn
Version:
More than 300 powerful ESLint rules
105 lines (91 loc) • 2.32 kB
JavaScript
const MESSAGE_ID_ERROR = 'prefer-explicit-viewport-units/error';
const MESSAGE_ID_SUGGESTION = 'prefer-explicit-viewport-units/suggestion';
const messages = {
[MESSAGE_ID_ERROR]: 'Prefer `{{replacement}}` over `{{value}}`.',
[MESSAGE_ID_SUGGESTION]: 'Replace `{{value}}` with `{{replacement}}`.',
};
const sizeProperties = new Set([
'height',
'min-height',
'max-height',
'width',
'min-width',
'max-width',
'block-size',
'min-block-size',
'max-block-size',
'inline-size',
'min-inline-size',
'max-inline-size',
]);
const schema = [
{
type: 'object',
additionalProperties: false,
properties: {
unit: {
enum: ['dvh', 'svh', 'lvh'],
description: 'The viewport height unit to prefer.',
},
},
},
];
const isSizeDeclaration = (node, sourceCode) => {
let currentNode = node;
while (currentNode) {
if (currentNode.type === 'Declaration') {
return sourceCode.getParent(currentNode).type === 'Block'
&& sizeProperties.has(currentNode.property.toLowerCase());
}
currentNode = sourceCode.getParent(currentNode);
}
return false;
};
const getReplacement = (unit, preferredUnit) => `${preferredUnit.slice(0, -1)}${unit.at(-1)}`;
/** @param {import('eslint').Rule.RuleContext} context */
const create = context => {
const [{unit: preferredUnit}] = context.options;
context.on('Dimension', node => {
const unit = node.unit.toLowerCase();
if (
(unit !== 'vh' && unit !== 'vw')
|| Number(node.value) !== 100
|| !isSizeDeclaration(node, context.sourceCode)
) {
return;
}
const replacement = getReplacement(unit, preferredUnit);
const value = `${node.value}${node.unit}`;
return {
node,
messageId: MESSAGE_ID_ERROR,
data: {value, replacement: `${node.value}${replacement}`},
suggest: [
{
messageId: MESSAGE_ID_SUGGESTION,
data: {value, replacement: `${node.value}${replacement}`},
fix: fixer => fixer.replaceText(node, `${node.value}${replacement}`),
},
],
};
});
};
/** @type {import('eslint').Rule.RuleModule} */
const config = {
create,
meta: {
type: 'suggestion',
docs: {
description: 'Prefer explicit viewport units.',
recommended: false,
},
hasSuggestions: true,
schema,
defaultOptions: [{unit: 'dvh'}],
messages,
languages: [
'css/css',
],
},
};
export default config;