first commit

This commit is contained in:
2026-08-06 12:00:39 +10:00
commit 91221f5a8e
3259 changed files with 569069 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
/**
* @fileoverview Enforce the use of relative units for font size.
* @author Tanuj Kanti
*/
//-----------------------------------------------------------------------------
// Type Definitions
//-----------------------------------------------------------------------------
/**
* @import { CSSRuleDefinition } from "../types.js"
* @typedef {"allowedFontUnits"} RelativeFontUnitsMessageIds
* @typedef {[{allowUnits?: string[]}]} RelativeFontUnitsOptions
* @typedef {CSSRuleDefinition<{ RuleOptions: RelativeFontUnitsOptions, MessageIds: RelativeFontUnitsMessageIds}>} RelativeFontUnitsRuleDefinition
*/
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
const relativeFontUnits = [
"%",
"cap",
"ch",
"em",
"ex",
"ic",
"lh",
"rcap",
"rch",
"rem",
"rex",
"ric",
"rlh",
];
const disallowedFontSizeKeywords = new Set([
"xx-small",
"x-small",
"small",
"medium",
"large",
"x-large",
"xx-large",
"xxx-large",
"math",
]);
//-----------------------------------------------------------------------------
// Rule Definition
//-----------------------------------------------------------------------------
export default /** @satisfies {RelativeFontUnitsRuleDefinition} */ ({
meta: {
type: "suggestion",
docs: {
description: "Enforce the use of relative font units",
recommended: false,
url: "https://github.com/eslint/css/blob/main/docs/rules/relative-font-units.md",
},
schema: [
{
type: "object",
properties: {
allowUnits: {
type: "array",
items: {
enum: relativeFontUnits,
},
uniqueItems: true,
},
},
additionalProperties: false,
},
],
defaultOptions: [
{
allowUnits: ["rem"],
},
],
messages: {
allowedFontUnits: "Use only allowed relative units for 'font-size' - {{allowedFontUnits}}.",
},
},
create(context) {
const [{ allowUnits: allowedFontUnits }] = context.options;
return {
Declaration(node) {
if (node.property === "font-size") {
if (node.value.type === "Value" &&
node.value.children.length > 0) {
const value = node.value.children[0];
if ((value.type === "Dimension" &&
!allowedFontUnits.includes(value.unit.toLowerCase())) ||
(value.type === "Identifier" &&
disallowedFontSizeKeywords.has(value.name.toLowerCase())) ||
(value.type === "Percentage" &&
!allowedFontUnits.includes("%"))) {
context.report({
loc: value.loc,
messageId: "allowedFontUnits",
data: {
allowedFontUnits: allowedFontUnits.join(", "),
},
});
}
}
}
if (node.property === "font") {
if (node.value.type === "Value" &&
node.value.children.length > 0) {
const value = node.value;
const dimensionNode = value.children.find(child => child.type === "Dimension");
const identifierNode = value.children.find(child => child.type === "Identifier" &&
disallowedFontSizeKeywords.has(child.name.toLowerCase()));
const percentageNode = value.children.find((child, index) => {
const isPercentage = child.type === "Percentage";
const previousNode = value.children[index - 1];
const previousNodeIsSlashOperator = previousNode &&
previousNode.type === "Operator" &&
previousNode.value === "/";
return (isPercentage && !previousNodeIsSlashOperator);
});
let location;
let shouldReport = false;
const conditions = [
{
check: !allowedFontUnits.includes("%") &&
percentageNode,
loc: percentageNode?.loc,
},
{
check: identifierNode,
loc: identifierNode?.loc,
},
{
check: dimensionNode &&
!allowedFontUnits.includes(dimensionNode.unit.toLowerCase()),
loc: dimensionNode?.loc,
},
];
for (const condition of conditions) {
if (condition.check) {
shouldReport = true;
location = condition.loc;
break;
}
}
if (shouldReport) {
context.report({
loc: location,
messageId: "allowedFontUnits",
data: {
allowedFontUnits: allowedFontUnits.join(", "),
},
});
}
}
}
},
};
},
});