Files
renovate/tools/lint/rules/prefer-fs-util.ts
Sebastian Poxhofer e44c9a2070 ci(oxlint): move custom oxlint rules to typescript and alternative API (#45337)
* ci: move custom oxlint rules to typescript and alternative API

* ci: add  to test sharding
2026-08-19 05:37:56 +00:00

69 lines
2.5 KiB
TypeScript

import { defineRule } from '@oxlint/plugins';
/**
* Modules whose value imports are restricted in `lib/` in favor of the
* scoped helpers from `lib/util/fs`.
*/
const RESTRICTED_MODULES = new Set([
'fs',
'node:fs',
'fs/promises',
'node:fs/promises',
'fs-extra',
'fs-extra/esm',
]);
/*
* Paths exempt from this rule (via overrides in `.oxlintrc.json`). The
* `lib/util/fs` helpers scope file access to the `localDir`/`cacheDir` from
* `GlobalConfig`, so they only make sense for code that runs after those
* directories are configured and that operates inside them. The following
* areas legitimately need raw `fs` access:
*
* - `lib/util/fs/` implements the helpers themselves.
* - `lib/logger/` opens log-file streams at user-configured system paths
* during process bootstrap, before any config exists; `lib/util/fs` also
* depends on the logger, so the reverse import would be a cycle.
* - `lib/workers/global/` is process bootstrap: it creates `baseDir` and
* `cacheDir` themselves and reads/writes user-supplied paths (config
* files, `writeDiscoveredRepos` output) before `GlobalConfig` is seeded
* with the directory config the scoped helpers resolve against.
* - `lib/config-validator.ts` is a standalone CLI entry point that validates
* arbitrary files without any `GlobalConfig`.
* - `lib/util/git/` sits beneath the scoped-helper abstraction: it owns the
* `localDir` lifecycle (clone, emptyDir, symlinks) and manages private-key
* files with synchronous cleanup on process exit, which the async scoped
* helpers cannot express.
* - `lib/instrumentation/` bootstraps OpenTelemetry and writes traces to a
* user-configured system path (`RENOVATE_TRACING_FILE_EXPORTER_PATH`)
* outside `localDir`/`cacheDir`, before any `GlobalConfig` exists.
*/
export default defineRule({
meta: {
type: 'suggestion',
messages: {
preferFsUtil:
"Use the helpers from 'lib/util/fs' instead of importing '{{module}}' directly: they scope file access to the configured local/cache directories.",
},
},
createOnce(context) {
return {
ImportDeclaration(node) {
// type-only imports don't touch the filesystem
if (node.importKind === 'type') {
return;
}
const source = node.source.value;
if (RESTRICTED_MODULES.has(source)) {
context.report({
node,
messageId: 'preferFsUtil',
data: { module: source },
});
}
},
};
},
});