knip
Version:
Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects
139 lines (138 loc) • 7.31 kB
JavaScript
import { partitionCompilers } from '../compilers/index.js';
import { KNIP_CONFIG_LOCATIONS } from '../constants.js';
import { knipConfigurationSchema } from '../schema/configuration.js';
import { getCatalogContainer } from './catalog.js';
import { ConfigurationError } from './errors.js';
import { findFile, loadJSON } from './fs.js';
import { getIncludedIssueTypes, shorthandDeps, shorthandExports, shorthandFiles } from './get-included-issue-types.js';
import { defaultRules } from './issue-initializers.js';
import { loadResolvedConfigFile } from './load-config.js';
import { _load } from './loader.js';
import { getKeysByValue } from './object.js';
import { isAbsolute, join, normalize, toAbsolute, toPosix } from './path.js';
import { splitTags } from './tag.js';
export const createOptions = async (options) => {
const { args = {} } = options;
const pcwd = process.cwd();
const cwd = normalize(toPosix(toAbsolute(options.cwd ?? args.directory ?? pcwd, pcwd)));
const manifestPath = findFile(cwd, 'package.json');
const manifest = manifestPath && (await loadJSON(manifestPath));
if (!(manifestPath && manifest)) {
throw new ConfigurationError('Unable to find package.json');
}
let configFilePath;
for (const configPath of args.config ? [args.config] : KNIP_CONFIG_LOCATIONS) {
const resolvedConfigFilePath = isAbsolute(configPath) ? configPath : findFile(cwd, configPath);
if (resolvedConfigFilePath) {
configFilePath = resolvedConfigFilePath;
break;
}
}
if (args.config && !configFilePath && !manifest.knip) {
throw new ConfigurationError(`Unable to find ${args.config} or package.json#knip`);
}
const loadedConfig = Object.assign({}, manifest.knip, configFilePath ? await loadResolvedConfigFile(configFilePath, args) : {});
const parsedConfig = knipConfigurationSchema.parse(partitionCompilers(loadedConfig));
if (!configFilePath && manifest.knip)
configFilePath = manifestPath;
const pnpmWorkspacePath = findFile(cwd, 'pnpm-workspace.yaml');
const pnpmWorkspace = pnpmWorkspacePath && (await _load(pnpmWorkspacePath));
const workspaces = pnpmWorkspace?.packages ??
(manifest.workspaces
? Array.isArray(manifest.workspaces)
? manifest.workspaces
: (manifest.workspaces.packages ?? [])
: []);
const isStrict = options.isStrict ?? args.strict ?? false;
const isProduction = options.isProduction ?? args.production ?? isStrict;
const isDebug = args.debug ?? false;
const isTrace = Boolean(args.trace ?? args['trace-file'] ?? args['trace-export'] ?? args['trace-dependency']);
const rules = { ...defaultRules, ...parsedConfig.rules };
const excludesFromRules = getKeysByValue(rules, 'off');
const includedIssueTypes = getIncludedIssueTypes({
isProduction,
exclude: [...excludesFromRules, ...(parsedConfig.exclude ?? [])],
include: parsedConfig.include ?? [],
excludeOverrides: options.excludedIssueTypes ?? args.exclude ?? [],
includeOverrides: [
...(options.includedIssueTypes ?? args.include ?? []),
...(args.dependencies ? shorthandDeps : []),
...(args.exports ? shorthandExports : []),
...(args.files ? shorthandFiles : []),
],
});
for (const [key, value] of Object.entries(includedIssueTypes)) {
if (!value)
rules[key] = 'off';
}
const fixTypes = options.fixTypes ?? args['fix-type'] ?? [];
const isFixFiles = args['allow-remove-files'] && (fixTypes.length === 0 || fixTypes.includes('files'));
const isIncludeLibs = args['include-libs'] ?? options.isIncludeLibs ?? false;
const isReportClassMembers = includedIssueTypes.classMembers;
const tags = splitTags(args.tags ?? options.tags ?? parsedConfig.tags ?? args['experimental-tags'] ?? []);
return {
cacheLocation: args['cache-location'] ?? join(cwd, 'node_modules', '.cache', 'knip'),
catalog: await getCatalogContainer(cwd, manifest, manifestPath, pnpmWorkspacePath, pnpmWorkspace),
config: args.config,
configFilePath,
cwd,
dependencies: args.dependencies ?? false,
experimentalTags: tags,
exports: args.exports ?? false,
files: args.files ?? false,
fixTypes,
gitignore: args['no-gitignore'] ? false : (options.gitignore ?? true),
includedIssueTypes,
isCache: args.cache ?? false,
isDebug,
isDisableConfigHints: args['no-config-hints'] || isProduction || Boolean(args.workspace),
isFix: args.fix ?? options.isFix ?? isFixFiles ?? fixTypes.length > 0,
isFixCatalog: fixTypes.length === 0 || fixTypes.includes('catalog'),
isFixDependencies: fixTypes.length === 0 || fixTypes.includes('dependencies'),
isFixFiles,
isFixUnusedExports: fixTypes.length === 0 || fixTypes.includes('exports'),
isFixUnusedTypes: fixTypes.length === 0 || fixTypes.includes('types'),
isFormat: args.format ?? options.isFormat ?? false,
isIncludeEntryExports: args['include-entry-exports'] ?? options.isIncludeEntryExports ?? false,
isIsolateWorkspaces: options.isIsolateWorkspaces ?? args['isolate-workspaces'] ?? false,
isProduction,
isReportClassMembers,
isReportDependencies: includedIssueTypes.dependencies ||
includedIssueTypes.unlisted ||
includedIssueTypes.unresolved ||
includedIssueTypes.binaries,
isReportExports: includedIssueTypes.exports ||
includedIssueTypes.types ||
includedIssueTypes.nsExports ||
includedIssueTypes.nsTypes ||
includedIssueTypes.enumMembers ||
includedIssueTypes.duplicates ||
isReportClassMembers,
isReportFiles: includedIssueTypes.files,
isReportTypes: includedIssueTypes.types || includedIssueTypes.nsTypes || includedIssueTypes.enumMembers,
isReportValues: includedIssueTypes.exports || includedIssueTypes.nsExports || isReportClassMembers,
isSession: options.isSession ?? false,
isShowProgress: !isDebug &&
!isTrace &&
args['no-progress'] !== true &&
options.isShowProgress !== false &&
process.stdout.isTTY &&
typeof process.stdout.cursorTo === 'function',
isSkipLibs: !(isIncludeLibs || includedIssueTypes.classMembers),
isStrict,
isTrace,
isTreatConfigHintsAsErrors: args['treat-config-hints-as-errors'] ?? parsedConfig.treatConfigHintsAsErrors ?? false,
isUseTscFiles: options.isUseTscFiles ?? args['use-tsconfig-files'] ?? (options.isSession && !configFilePath),
isWatch: args.watch ?? options.isWatch ?? false,
maxShowIssues: args['max-show-issues'] ? Number(args['max-show-issues']) : undefined,
parsedConfig,
rules,
tags,
traceDependency: args['trace-dependency'],
traceExport: args['trace-export'],
traceFile: args['trace-file'] ? toAbsolute(args['trace-file'], cwd) : undefined,
tsConfigFile: args.tsConfig,
workspace: options.workspace ?? args.workspace,
workspaces,
};
};