core/quality/eslint/no-wildcard-exports.eslint.rule.ts

core/quality/eslint/no-wildcard-exports.eslint.rule.ts is a file in GovLab Quality. 59 lines of code and 12 definitions.

import type { Rule } from "eslint";
import { packageRelOf } from "#core/resolvers/package.resolver";

const EXPORT_ALL_MESSAGE =
    "Re-export-all (export * from '...') is forbidden in workspace packages — every export must be explicit so the public surface is grep-able and the barrel is the package's exhaustive index. " +
    "Replace with a named re-export listing every public symbol. [explicit_exports_only]";

const NAMESPACE_IMPORT_MESSAGE =
    "Wildcard imports (import * as ns from './...') from a relative/sibling source are forbidden in workspace packages — every in-package symbol is an explicit dependency surface, named one at a time. " +
    "Replace with a named import listing every symbol you actually use. " +
    "Namespace imports from a bare third-party specifier (e.g. import * as THREE from 'three') are permitted — that is the vendor's own consumption contract. [explicit_imports_only]";

const SELECTORS = ["ExportAllDeclaration", "ImportNamespaceSpecifier"];

interface WithSource {
    source?: { value?: unknown };
}

const hasSource = function hasSource(node: unknown): node is WithSource {
    return typeof node === "object" && node !== null;
};

const sourceValueOf = function sourceValueOf(node: unknown): unknown {
    return hasSource(node) ? node.source?.value : null;
};

const isRelativeSource = function isRelativeSource(source: unknown): boolean {
    return typeof source === "string" && source.length > 0 && source.startsWith(".");
};

const isInWorkspacePackage = function isInWorkspacePackage(filename: string): boolean {
    return packageRelOf(filename) !== null;
};

const onNamespaceImport = function onNamespaceImport(context: Rule.RuleContext, node: Rule.Node): void {
    if (isRelativeSource(sourceValueOf(node.parent))) {
        context.report({ messageId: "noNamespaceImport", node });
    }
};

export default {
    create(context): Rule.RuleListener {
        if (!isInWorkspacePackage(context.filename)) {
            return {};
        }
        const handlers: ((node: Rule.Node) => void)[] = [
            (node): void => {
                context.report({ messageId: "noExportAll", node });
            },
            (node): void => {
                onNamespaceImport(context, node);
            },
        ];
        const listeners: Rule.RuleListener = {};
        SELECTORS.forEach((selector, i) => {
            listeners[selector] = handlers[i];
        });
        return listeners;
    },

    meta: {
        docs: {
            description:
                "Ban wildcard exports (export *) and relative-source namespace imports (import * as ns from './...') in workspace packages — the barrel must enumerate every public symbol and every in-package import must name what it consumes. Bare third-party namespace imports are exempt.",
        },
        messages: { noExportAll: EXPORT_ALL_MESSAGE, noNamespaceImport: NAMESPACE_IMPORT_MESSAGE },
        schema: [],
        type: "problem",
    },
} satisfies Rule.RuleModule;