core/quality/eslint/require-canonical-concept.eslint.rule.ts
core/quality/eslint/require-canonical-concept.eslint.rule.ts is a file in GovLab Quality. 72 lines of code and 14 definitions.
import type { Rule } from "eslint";
const MESSAGE =
"govlabMeta() is missing '{{field}}'. Every @govlab/* rule must declare meta.docs.description and a non-empty " +
"meta.docs.canonical (its shared quality concept) so the quality-relations ingest registers it with a concept — " +
"a concept-less rule breaks the SSOT completeness gate. [require_canonical_concept]";
const SELECTORS = ["CallExpression"];
interface PropValue {
type?: string;
elements?: unknown[];
}
interface PropNode {
type: string;
key?: { type?: string; name?: string };
value?: PropValue;
}
interface CallNode {
type: string;
callee?: { type?: string; name?: string };
arguments?: { type?: string; properties?: PropNode[] }[];
}
const isCallNode = function isCallNode(node: unknown): node is CallNode {
return node !== null && typeof node === "object" && "type" in node;
};
const propNamed = function propNamed(properties: PropNode[], name: string): PropNode | null {
for (const prop of properties) {
if (prop.type === "Property" && prop.key?.type === "Identifier" && prop.key.name === name) {
return prop;
}
}
return null;
};
const hasNonEmptyArray = function hasNonEmptyArray(prop: PropNode | null): boolean {
return prop?.value?.type === "ArrayExpression" && (prop.value.elements?.length ?? 0) > 0;
};
const reportMissing = function reportMissing(context: Rule.RuleContext, node: Rule.Node, properties: PropNode[]): void {
if (propNamed(properties, "description") === null) {
context.report({ data: { field: "description" }, messageId: "missing", node });
}
if (!hasNonEmptyArray(propNamed(properties, "canonical"))) {
context.report({ data: { field: "canonical" }, messageId: "missing", node });
}
};
const onCall = function onCall(context: Rule.RuleContext, node: Rule.Node): void {
const call: CallNode | null = isCallNode(node) ? node : null;
if (call?.callee?.type !== "Identifier" || call.callee.name !== "govlabMeta") {
return;
}
const arg = call.arguments?.[0];
if (arg?.type !== "ObjectExpression") {
return;
}
reportMissing(context, node, arg.properties ?? []);
};
export default {
create(context): Rule.RuleListener {
const listeners: Rule.RuleListener = {};
for (const selector of SELECTORS) {
listeners[selector] = (node: Rule.Node): void => {
onCall(context, node);
};
}
return listeners;
},
meta: {
docs: {
description: "Require meta.docs.description and a non-empty meta.docs.canonical on every govlabMeta rule",
},
messages: { missing: MESSAGE },
schema: [],
type: "problem",
},
} satisfies Rule.RuleModule;