76 lines · 2.3 KB · TypeScript
RawDownload
import { defineRule } from "@oxlint/plugins"; const NODE_MODULE_ALIASES = new Map([  ["assert/strict", "Assert"],  ["fs/promises", "FSP"],]); const NODE_SEGMENT_ALIASES = new Map([  ["fs", "FS"],  ["os", "OS"],  ["url", "URL"],  ["vm", "VM"],]); const toPascalCase = (value: string) =>  value    .split(/[_-]/u)    .filter((segment) => segment.length > 0)    .map((segment) => segment[0]?.toUpperCase() + segment.slice(1))    .join(""); const expectedNamespaceAlias = (source: string) => {  const moduleName = source.slice("node:".length);  const knownAlias = NODE_MODULE_ALIASES.get(moduleName);  if (knownAlias !== undefined) return `Node${knownAlias}`;   return `Node${moduleName    .split("/")    .map((segment) => NODE_SEGMENT_ALIASES.get(segment) ?? toPascalCase(segment))    .join("")}`;}; const literalStringValue = (node: unknown): string | undefined => {  if (typeof node !== "object" || node === null) return undefined;  if (!("type" in node) || node.type !== "Literal") return undefined;  if (!("value" in node) || typeof node.value !== "string") return undefined;  return node.value;}; const identifierName = (node: unknown): string | undefined => {  if (typeof node !== "object" || node === null) return undefined;  if (!("type" in node) || node.type !== "Identifier") return undefined;  if (!("name" in node) || typeof node.name !== "string") return undefined;  return node.name;}; export default defineRule({  meta: {    type: "problem",    docs: {      description: "Require canonical namespace imports for Node.js built-in modules.",    },  },  create(context) {    return {      ImportDeclaration(node) {        const source = literalStringValue(node.source);        if (source === undefined || !source.startsWith("node:")) return;         const expectedAlias = expectedNamespaceAlias(source);        const namespaceImport =          node.specifiers.length === 1 && node.specifiers[0]?.type === "ImportNamespaceSpecifier"            ? node.specifiers[0]            : undefined;        const actualAlias = identifierName(namespaceImport?.local);         if (actualAlias === expectedAlias) return;         context.report({          node,          message: `Import ${source} as a namespace named ${expectedAlias}.`,        });      },    };  },});