eslint-plugin-esm
Version:
ESLint plugin for linting ESM (import/export syntax)
59 lines (55 loc) • 1.82 kB
text/typescript
import childProcess from "node:child_process";
import path from "node:path";
import process from "node:process";
import { isNativeError } from "node:util/types";
import { create, createRule, getRuleName, getSourceType } from "../common.ts";
import { memoize } from "../utils.ts";
export const noGitIgnoredImports = createRule({
name: getRuleName(import.meta.url),
message: "Disallow to import module from a git-ignored path.",
create: (context) => create(context, checkIgnored),
});
function checkIgnored(filename: string, source: string) {
// from node_modules
if (getSourceType(source) !== "local") {
return false;
}
// out side of project root
if (source.startsWith("/") && !source.startsWith(process.cwd())) {
return true;
}
// This file of absolutePath may be a symbolic link
const absolutePath = path.resolve(path.dirname(filename), source);
if (!absolutePath.startsWith("/")) {
throw new Error(
`ESLint plugin internal error. Absolute path incorrect: ${absolutePath}.`,
);
}
return isIgnored(absolutePath);
}
const isIgnored = memoize((filePath: string) => {
try {
return (
childProcess
// Adding `stdio: 'pipe'` to depress unexpected error messages in console.
// For example, `git check-ignore /absolute/path/to/file` (even wrapped with try-catch) will print something unnecessary.
.execSync(`git check-ignore ${filePath}`, {
encoding: "utf8",
stdio: "pipe",
})
.trim() === filePath
);
} catch (e) {
if (
isNativeError(e) &&
"stdout" in e &&
e.stdout === "" &&
"stderr" in e &&
e.stderr === ""
) {
return false;
}
// We cannot throw an error here. So we have to return true to report the filePath is bad.
return true;
}
});