core/factories/eslint.setup.factory.ts
core/factories/eslint.setup.factory.ts is a file in GovLab Quality. 119 lines of code and 27 definitions.
import {
CONSUMER_CONFIG_FILES,
CONSUMER_CONFIG_OFF,
HTML_PLUGIN,
JSX,
JS_ECOSYSTEMS,
LANGUAGE,
RULE_OFF,
TS_FILES,
TS_PARSER,
TS_PREFIX,
} from "#configuration/constants/eslint.constants";
import type { CoreState, InstalledPlugin } from "#types/eslint.types";
import type { EslintScopeConfig, GovlabConfig } from "#types/config.types";
import {
baseConfigs,
disableTypeCheckedRules,
exclusionScopes,
htmlScope,
langScopes,
manifestScope,
optionalScopes,
tsScopeOverride,
tsTestScope,
} from "#core/factories/eslint.scope.factory";
import { installedEslintPlugins, loadModule, resolveGlobals } from "#core/loaders/eslint.loader";
import {
jsRulesOf,
namespacesOf,
pluginMap,
pluginsFromRecord,
toRulesRecord,
} from "#core/converters/eslint.converter";
import type { ConcernConfig } from "#types/concern.types";
import type { Linter } from "eslint";
import { emitEslintConfig } from "#core/emitters/eslint.emitter";
import { govlabEslintSettings } from "#core/selectors/config.selector";
import { isPlugin } from "#core/predicates/eslint.predicate";
import { loadGovlabConfig } from "#core/loaders/config.loader";
import { loadUserPlugins } from "#core/loaders/plugin.loader";
import { masterExclude } from "#core/selectors/exclusions.selector";
import process from "node:process";
import { validConcepts } from "#core/selectors/concept.selector";
import { validateConcerns } from "#core/validators/concern.validator";
const TEST_GLOB_EXTENSIONS = ["ts", "mts"];
const flat = (...groups: (Linter.Config | Linter.Config[] | null)[]): Linter.Config[] =>
groups.flatMap((group) => (group ? (Array.isArray(group) ? group : [group]) : []));
const buildCoreState = async (config: GovlabConfig, concerns: ConcernConfig): Promise<CoreState> => {
const installed = await installedEslintPlugins();
const jsActive = namespacesOf(
installed.filter((entry: InstalledPlugin) => JS_ECOSYSTEMS.has(entry.record.ecosystem)),
);
const htmlPlugin = await loadModule(HTML_PLUGIN);
const plugins = { ...pluginMap(installed), ...(isPlugin(htmlPlugin) ? { html: htmlPlugin } : {}) };
const rules = toRulesRecord(emitEslintConfig({ activePlugins: jsActive, concerns }));
const settings = { govlab: govlabEslintSettings(config) };
const tsParser = await loadModule(TS_PARSER);
return { htmlPlugin, installed, plugins, rules, settings, tsParser };
};
const buildUserScopes = async (
consumerRoot: string,
config: GovlabConfig,
reserved: Set<string>,
): Promise<Linter.Config[]> => {
const userPlugins = await loadUserPlugins(consumerRoot, {
allowGlobal: config.extensions?.global ?? false,
reservedNamespaces: reserved,
});
const userRules = toRulesRecord(config.eslint?.rules ?? {});
const userTsRules = Object.fromEntries(Object.entries(userRules).filter(([key]) => key.startsWith(TS_PREFIX)));
const userManaged: Linter.Config = { plugins: pluginsFromRecord(userPlugins.eslint), rules: jsRulesOf(userRules) };
const userTs: Linter.Config[] =
Object.keys(userTsRules).length > 0 ? [{ files: TS_FILES, rules: userTsRules }] : [];
return [userManaged, ...userTs];
};
const buildTestScope = function buildTestScope(
core: CoreState,
config: GovlabConfig,
globals: Record<string, string>,
): Linter.Config | null {
const testbaseRoot = config.hostPolicy?.testRoots?.testbase;
const testbaseGlobs =
typeof testbaseRoot === "string" ? TEST_GLOB_EXTENSIONS.map((ext) => `${testbaseRoot}/**/*.${ext}`) : [];
return tsTestScope({
disabled: disableTypeCheckedRules(core.installed),
extraGlobs: testbaseGlobs,
language: { ...LANGUAGE, globals, parserOptions: JSX },
tsParser: core.tsParser,
});
};
export const govlabEslintConfig = async (consumerRoot: string = process.cwd()): Promise<Linter.Config[]> => {
const config = await loadGovlabConfig(consumerRoot);
const eslint: EslintScopeConfig = config.eslint ?? {};
const concerns = validateConcerns(config.qualityMaster?.concerns ?? {}, validConcepts());
const core = await buildCoreState(config, concerns);
const [langs, manifest, globals] = await Promise.all([
langScopes(core.installed, concerns),
manifestScope(core.installed, core.plugins),
resolveGlobals(eslint.env ?? [], eslint.globals),
]);
const master = masterExclude(config);
const userScopes = await buildUserScopes(consumerRoot, config, new Set(Object.keys(core.plugins)));
return flat(
master.length > 0 ? { ignores: master } : null,
baseConfigs({ globals, ...core }),
tsScopeOverride(core.rules),
buildTestScope(core, config, globals),
langs,
htmlScope(jsRulesOf(core.rules), core.settings, core.htmlPlugin),
exclusionScopes(eslint.exclusions ?? []),
manifest,
userScopes,
optionalScopes(eslint),
{
files: CONSUMER_CONFIG_FILES,
rules: Object.fromEntries(CONSUMER_CONFIG_OFF.map((rule) => [rule, RULE_OFF])),
},
);
};