first commit
This commit is contained in:
+144
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @fileoverview Rule to require layers in CSS.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// Type Definitions
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* @import { CSSRuleDefinition } from "../types.js"
|
||||
* @typedef {"missingLayer" | "missingLayerName" | "missingImportLayer" | "layerNameMismatch"} UseLayersMessageIds
|
||||
* @typedef {[{
|
||||
* allowUnnamedLayers?: boolean,
|
||||
* requireImportLayers?: boolean,
|
||||
* layerNamePattern?: string
|
||||
* }]} UseLayersOptions
|
||||
* @typedef {CSSRuleDefinition<{ RuleOptions: UseLayersOptions, MessageIds: UseLayersMessageIds }>} UseLayersRuleDefinition
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//-----------------------------------------------------------------------------
|
||||
export default /** @satisfies {UseLayersRuleDefinition} */ ({
|
||||
meta: {
|
||||
type: "problem",
|
||||
docs: {
|
||||
description: "Require use of layers",
|
||||
url: "https://github.com/eslint/css/blob/main/docs/rules/use-layers.md",
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowUnnamedLayers: {
|
||||
type: "boolean",
|
||||
},
|
||||
requireImportLayers: {
|
||||
type: "boolean",
|
||||
},
|
||||
layerNamePattern: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
defaultOptions: [
|
||||
{
|
||||
allowUnnamedLayers: false,
|
||||
requireImportLayers: true,
|
||||
layerNamePattern: "",
|
||||
},
|
||||
],
|
||||
messages: {
|
||||
missingLayer: "Expected rule to be within a layer.",
|
||||
missingLayerName: "Expected layer to have a name.",
|
||||
missingImportLayer: "Expected import to be within a layer.",
|
||||
layerNameMismatch: "Expected layer name '{{ name }}' to match pattern '{{pattern}}'.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
let layerDepth = 0;
|
||||
const options = context.options[0];
|
||||
const layerNameRegex = options.layerNamePattern
|
||||
? new RegExp(options.layerNamePattern, "u")
|
||||
: null;
|
||||
return {
|
||||
"Atrule[name=/^import$/i]"(node) {
|
||||
// layer, if present, must always be the second child of the prelude
|
||||
const secondChild = node.prelude?.children[1];
|
||||
const layerNode = secondChild?.name === "layer" ? secondChild : null;
|
||||
if (options.requireImportLayers && !layerNode) {
|
||||
context.report({
|
||||
loc: node.loc,
|
||||
messageId: "missingImportLayer",
|
||||
});
|
||||
}
|
||||
if (layerNode) {
|
||||
const isLayerFunction = layerNode.type === "Function";
|
||||
if (!options.allowUnnamedLayers && !isLayerFunction) {
|
||||
context.report({
|
||||
loc: layerNode.loc,
|
||||
messageId: "missingLayerName",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
Layer(node) {
|
||||
if (!layerNameRegex) {
|
||||
return;
|
||||
}
|
||||
const parts = node.name.split(".");
|
||||
let currentPos = 0;
|
||||
parts.forEach((part, index) => {
|
||||
if (!layerNameRegex.test(part)) {
|
||||
const startColumn = node.loc.start.column + currentPos;
|
||||
const endColumn = startColumn + part.length;
|
||||
context.report({
|
||||
loc: {
|
||||
start: {
|
||||
line: node.loc.start.line,
|
||||
column: startColumn,
|
||||
},
|
||||
end: {
|
||||
line: node.loc.start.line,
|
||||
column: endColumn,
|
||||
},
|
||||
},
|
||||
messageId: "layerNameMismatch",
|
||||
data: {
|
||||
name: part,
|
||||
pattern: options.layerNamePattern,
|
||||
},
|
||||
});
|
||||
}
|
||||
currentPos += part.length;
|
||||
// add 1 to account for the . symbol
|
||||
if (index < parts.length - 1) {
|
||||
currentPos += 1;
|
||||
}
|
||||
});
|
||||
},
|
||||
"Atrule[name=/^layer$/i]"(node) {
|
||||
layerDepth++;
|
||||
if (!options.allowUnnamedLayers && !node.prelude) {
|
||||
context.report({
|
||||
loc: node.loc,
|
||||
messageId: "missingLayerName",
|
||||
});
|
||||
}
|
||||
},
|
||||
"Atrule[name=/^layer$/i]:exit"() {
|
||||
layerDepth--;
|
||||
},
|
||||
Rule(node) {
|
||||
if (layerDepth > 0) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
loc: node.loc,
|
||||
messageId: "missingLayer",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user