knip
Version:
Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects
79 lines (78 loc) • 4.39 kB
JavaScript
import { compact } from '../../util/array.js';
import { toConfig, toDeferResolve } from '../../util/input.js';
import { getPackageNameFromFilePath, getPackageNameFromModuleSpecifier } from '../../util/modules.js';
import { extname, isAbsolute, isInternal } from '../../util/path.js';
import { getDependenciesFromConfig } from '../babel/index.js';
export const getInputs = (config, options) => {
const { configFileName } = options;
if (extname(configFileName) === '.json' || !/eslint\.config/.test(configFileName)) {
return getInputsDeprecated(config, options);
}
const dependencies = config.flatMap(config => config.settings ? getDependenciesFromSettings(config.settings).filter(id => id !== '@typescript-eslint/parser') : []);
return compact(dependencies).map(id => toDeferResolve(id, { optional: true }));
};
const getInputsDeprecated = (config, options) => {
const extendsSpecifiers = config.extends ? compact([config.extends].flat().map(resolveExtendSpecifier)) : [];
if (extendsSpecifiers.some(specifier => specifier?.startsWith('eslint-plugin-prettier')))
extendsSpecifiers.push('eslint-config-prettier');
const extendConfigs = extendsSpecifiers.map(specifier => toConfig('eslint', specifier, { containingFilePath: options.configFilePath }));
const plugins = config.plugins ? config.plugins.map(resolvePluginSpecifier) : [];
const parser = config.parser ?? config.parserOptions?.parser;
const babelDependencies = config.parserOptions?.babelOptions
? getDependenciesFromConfig(config.parserOptions.babelOptions)
: [];
const settings = config.settings ? getDependenciesFromSettings(config.settings) : [];
const rules = getDependenciesFromRules({});
const overrides = config.overrides ? [config.overrides].flat().flatMap(d => getInputsDeprecated(d, options)) : [];
const deferred = compact([...extendsSpecifiers, ...plugins, parser, ...settings, ...rules]).map(id => toDeferResolve(id));
return [...extendConfigs, ...deferred, ...babelDependencies, ...overrides];
};
const isQualifiedSpecifier = (specifier) => specifier === 'eslint' ||
/\/eslint-(config|plugin)$/.test(specifier) ||
/.+eslint-(config|plugin)\//.test(specifier) ||
/eslint-(config|plugin)-/.test(specifier);
const resolveSpecifier = (namespace, rawSpecifier) => {
const specifier = rawSpecifier.replace(/(^plugin:|:.+$)/, '');
if (isQualifiedSpecifier(specifier))
return specifier;
if (!specifier.startsWith('@')) {
const id = rawSpecifier.startsWith('plugin:')
? getPackageNameFromModuleSpecifier(specifier)
: specifier.split('/')[0];
return `${namespace}-${id}`;
}
const [scope, name, ...rest] = specifier.split('/');
if (rawSpecifier.startsWith('plugin:') && rest.length === 0)
return [scope, namespace].join('/');
return [scope, name ? `${namespace}-${name}` : namespace, ...rest].join('/');
};
const resolvePluginSpecifier = (specifier) => resolveSpecifier('eslint-plugin', specifier);
const resolveExtendSpecifier = (specifier) => {
if (isInternal(specifier))
return;
const namespace = specifier.startsWith('plugin:') ? 'eslint-plugin' : 'eslint-config';
return resolveSpecifier(namespace, specifier);
};
const getDependenciesFromRules = (rules = {}) => Object.keys(rules).flatMap(ruleKey => ruleKey.includes('/') ? [resolveSpecifier('eslint-plugin', ruleKey.split('/').slice(0, -1).join('/'))] : []);
const getDependenciesFromSettings = (settings = {}) => {
return Object.entries(settings).flatMap(([settingKey, settings]) => {
if (settingKey === 'import/resolver') {
return (typeof settings === 'string' ? [settings] : Object.keys(settings))
.filter(key => key !== 'node')
.map(key => {
if (isInternal(key))
return key;
if (isAbsolute(key))
return getPackageNameFromFilePath(key);
return `eslint-import-resolver-${key}`;
});
}
if (settingKey === 'import/parsers') {
return (typeof settings === 'string' ? [settings] : Object.keys(settings)).map(key => {
if (isAbsolute(key))
return getPackageNameFromFilePath(key);
return key;
});
}
});
};