core/quality/eslint/no-platform-coupling.eslint.rule.ts
core/quality/eslint/no-platform-coupling.eslint.rule.ts is a file in GovLab Quality. 200 lines of code and 40 definitions.
import type { Rule } from "eslint";
import { packageRootOf } from "#core/resolvers/package.resolver";
const MESSAGE =
"Package source must be OS-agnostic outside a package's own src/platform/ folder. " +
"This construct hardcodes one operating system, so the package breaks on a Windows, macOS, or Linux host. " +
"Move deterministic all-OS variation into this package's src/platform/ folder, " +
"and build paths with path.join / path.sep rather than hardcoded separators or drive letters. [platform_agnostic_surface]";
const DRIVE_MIN = 3;
const PLATFORM_STRINGS = new Set([
"win32",
"darwin",
"linux",
"freebsd",
"openbsd",
"netbsd",
"sunos",
"aix",
"android",
"cygwin",
"haiku",
]);
const EXEC_CALLEES = new Set(["exec", "execSync", "execFile", "execFileSync", "spawn", "spawnSync"]);
const OS_BOUND_COMMANDS = new Set([
"wmic",
"powershell",
"powershell.exe",
"cmd",
"cmd.exe",
"reg",
"reg.exe",
"netsh",
"sc",
"tasklist",
"wevtutil",
"system_profiler",
"sw_vers",
"diskutil",
"defaults",
"launchctl",
"scutil",
"pmset",
"lspci",
"lsblk",
"lscpu",
"dmidecode",
"systemctl",
"journalctl",
"dpkg",
"apt",
"apt-get",
"yum",
]);
const COMPARISON_OPERATORS = new Set(["===", "!==", "==", "!="]);
const REPORT_SELECTORS = ["BinaryExpression", "CallExpression", "Literal", "SwitchCase"];
interface StringNode {
type?: string;
value?: unknown;
expressions?: unknown[];
quasis?: { value?: { cooked?: string } }[];
}
interface CalleeNode {
type?: string;
name?: string;
property?: { name?: string };
}
const isStringNode = function isStringNode(node: unknown): node is StringNode {
return typeof node === "object" && node !== null;
};
const isCalleeNode = function isCalleeNode(node: unknown): node is CalleeNode {
return typeof node === "object" && node !== null;
};
const isExemptFile = function isExemptFile(filename: string): boolean {
const normalized = filename.replaceAll("\\", "/");
if (normalized.includes("/src/platform/") || normalized.endsWith("/src/platform.ts")) {
return true;
}
return normalized.endsWith(".test.ts") || normalized.includes("/tests/");
};
const literalString = function literalString(node: StringNode): string | null {
return node.type === "Literal" && typeof node.value === "string" ? node.value : null;
};
const templateString = function templateString(node: StringNode): string | null {
if (node.type !== "TemplateLiteral" || (node.expressions?.length ?? 0) !== 0 || node.quasis?.length !== 1) {
return null;
}
return node.quasis[0]?.value?.cooked ?? null;
};
const staticStringValue = function staticStringValue(node: unknown): string | null {
if (!isStringNode(node)) {
return null;
}
return literalString(node) ?? templateString(node);
};
const isPlatformStringLiteral = function isPlatformStringLiteral(node: unknown): boolean {
const value = staticStringValue(node);
return value !== null && PLATFORM_STRINGS.has(value);
};
const commandBasename = function commandBasename(token: string): string {
const cut = Math.max(token.lastIndexOf("/"), token.lastIndexOf("\\"));
return cut === -1 ? token : token.slice(cut + 1);
};
const firstToken = function firstToken(command: string): string {
const trimmed = command.trim();
let end = 0;
while (end < trimmed.length && trimmed[end] !== " " && trimmed[end] !== "\t") {
end += 1;
}
return trimmed.slice(0, end);
};
const isOsBoundCommand = function isOsBoundCommand(node: unknown): boolean {
const value = staticStringValue(node);
if (value === null) {
return false;
}
const first = firstToken(value);
return first !== "" && OS_BOUND_COMMANDS.has(commandBasename(first).toLowerCase());
};
const isAsciiLetter = function isAsciiLetter(ch: string): boolean {
return (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z");
};
const isDriveLetterPath = function isDriveLetterPath(value: string): boolean {
if (value.length < DRIVE_MIN || !isAsciiLetter(value[0] ?? "") || value[1] !== ":") {
return false;
}
const sep = value[DRIVE_MIN - 1];
return sep === "\\" || sep === "/";
};
const calleeName = function calleeName(callee: unknown): string | null {
if (!isCalleeNode(callee)) {
return null;
}
if (callee.type === "Identifier") {
return callee.name ?? null;
}
if (callee.type === "MemberExpression") {
return callee.property?.name ?? null;
}
return null;
};
const onBinary = function onBinary(node: Rule.Node, report: (n: Rule.Node) => void): void {
if (node.type !== "BinaryExpression" || !COMPARISON_OPERATORS.has(node.operator)) {
return;
}
if (isPlatformStringLiteral(node.left) || isPlatformStringLiteral(node.right)) {
report(node);
}
};
const onCall = function onCall(node: Rule.Node, report: (n: Rule.Node) => void): void {
if (node.type !== "CallExpression") {
return;
}
const name = calleeName(node.callee);
const [first] = node.arguments;
if (name !== null && EXEC_CALLEES.has(name) && first && isOsBoundCommand(first)) {
report(node);
}
};
const onLiteral = function onLiteral(node: Rule.Node, report: (n: Rule.Node) => void): void {
if (node.type === "Literal" && typeof node.value === "string" && isDriveLetterPath(node.value)) {
report(node);
}
};
const onSwitchCase = function onSwitchCase(node: Rule.Node, report: (n: Rule.Node) => void): void {
if (node.type !== "SwitchCase" || !node.test) {
return;
}
if (isPlatformStringLiteral(node.test)) {
report(node);
}
};
const HANDLERS = [onBinary, onCall, onLiteral, onSwitchCase];
const listenersFor = function listenersFor(context: Rule.RuleContext): Rule.RuleListener {
const report = (node: Rule.Node): void => {
context.report({ messageId: "platformCoupling", node });
};
const listeners: Rule.RuleListener = {};
REPORT_SELECTORS.forEach((selector, i) => {
listeners[selector] = (node: Rule.Node): void => {
HANDLERS[i]?.(node, report);
};
});
return listeners;
};
export default {
create(context): Rule.RuleListener {
if (packageRootOf(context.filename) === null || isExemptFile(context.filename)) {
return {};
}
return listenersFor(context);
},
meta: {
docs: {
description:
"Disallow OS-coupled constructs (platform-string branches, OS-bound shell commands, drive-letter paths) in workspace source outside a package's own src/platform/ folder — packages must drop into any of Windows, macOS, or Linux.",
},
messages: { platformCoupling: MESSAGE },
schema: [],
type: "problem",
},
} satisfies Rule.RuleModule;