patch-pulse
Version:
Check for outdated npm dependencies
172 lines • 6.18 kB
JavaScript
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import { CONFIG_FILENAMES, PACKAGE_MANAGERS } from '../constant.js';
/**
* Get the config from the config file and merged with the CLI config
* @param argv - The command line arguments
* @returns The merged configuration
*/
export function getConfig() {
const fileConfig = readConfigFile();
const cliConfig = parseCliConfig(process.argv.slice(2));
return mergeConfigs(fileConfig, cliConfig);
}
/**
* Reads configuration from patchpulse.config.json file
* @param cwd - The current working directory
* @returns The configuration from the file
*/
export function readConfigFile(cwd = process.cwd()) {
for (const filename of CONFIG_FILENAMES) {
const configPath = join(cwd, filename);
if (existsSync(configPath)) {
try {
const content = readFileSync(configPath, 'utf-8');
const config = JSON.parse(content);
return validateConfig(config);
}
catch (error) {
console.warn(`Warning: Could not parse ${filename}: ${error}`);
return null;
}
}
}
return null;
}
/**
* Parses CLI arguments for configuration options
* @param args - The command line arguments
* @returns The parsed configuration
*/
export function parseCliConfig(args) {
const config = {};
// Parse skip argument
const skipIndex = args.indexOf('--skip');
const shortSkipIndex = args.indexOf('-s');
const skipArgIndex = skipIndex !== -1 ? skipIndex : shortSkipIndex;
if (skipArgIndex !== -1 && skipArgIndex + 1 < args.length) {
const skipValue = args[skipArgIndex + 1];
if (!skipValue.startsWith('-')) {
config.skip = skipValue
.split(',')
.map(s => s.trim())
.filter(Boolean);
}
}
// Parse package manager argument
const packageManagerIndex = args.indexOf('--package-manager');
if (packageManagerIndex !== -1 && packageManagerIndex + 1 < args.length) {
const packageManagerValue = args[packageManagerIndex + 1];
if (!packageManagerValue.startsWith('-')) {
const typeSafePackageManager = packageManagerValue;
if (PACKAGE_MANAGERS.includes(typeSafePackageManager)) {
config.packageManager = typeSafePackageManager;
}
}
}
// Parse no update prompt argument
if (args.includes('--no-update-prompt')) {
config.noUpdatePrompt = true;
}
// Parse update prompt argument (overrides noUpdatePrompt)
if (args.includes('--update-prompt')) {
config.noUpdatePrompt = false;
}
return config;
}
/**
* Merges file config and CLI config, combining skip arrays from both sources
* @param fileConfig - The configuration from the file
* @param cliConfig - The configuration from the CLI
* @returns The merged configuration
*/
export function mergeConfigs(fileConfig, cliConfig) {
const merged = {
skip: [],
};
// Add file config values
if (fileConfig?.skip) {
merged.skip.push(...fileConfig.skip);
}
// Add CLI config values (merge instead of override)
if (cliConfig.skip) {
merged.skip.push(...cliConfig.skip);
}
// Remove duplicates while preserving order
merged.skip = [...new Set(merged.skip)];
// Handle packageManager (CLI takes precedence)
if (cliConfig.packageManager) {
merged.packageManager = cliConfig.packageManager;
}
else if (fileConfig?.packageManager) {
merged.packageManager = fileConfig.packageManager;
}
// Handle noUpdatePrompt (CLI takes precedence)
if (cliConfig.noUpdatePrompt !== undefined) {
merged.noUpdatePrompt = cliConfig.noUpdatePrompt;
}
else if (fileConfig?.noUpdatePrompt !== undefined) {
merged.noUpdatePrompt = fileConfig.noUpdatePrompt;
}
return merged;
}
/**
* Validates configuration object
* @param config - The configuration to validate
* @returns The validated configuration
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function validateConfig(config) {
const validated = {};
if (config.skip && Array.isArray(config.skip)) {
validated.skip = config.skip.filter(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(item) => typeof item === 'string');
}
if (typeof config.packageManager === 'string') {
validated.packageManager = config.packageManager;
}
if (typeof config.noUpdatePrompt === 'boolean') {
validated.noUpdatePrompt = config.noUpdatePrompt;
}
return validated;
}
/**
* Checks if a package should be skipped based on configuration
* @param packageName - The name of the package to check
* @param config - The configuration to use
* @param version - The version of the package to check
* @returns True if the package should be skipped, false otherwise
*/
export function shouldSkipPackage({ packageName, config = {}, }) {
if (!config.skip) {
return false;
}
return config.skip.some(pattern => {
// If the pattern contains regex special characters (other than * and ?), treat as regex
if (/[. +?^${}()|[\]]/.test(pattern.replace(['*', '?'].join('|'), ''))) {
try {
const regex = new RegExp(pattern);
return regex.test(packageName);
}
catch {
return packageName.includes(pattern);
}
}
else if (pattern.includes('*') || pattern.includes('?')) {
// Convert glob to regex
const regexPattern = '^' +
pattern
.replace(/([.+^${}()|[\\]])/g, '\\$1') // Escape regex special chars
.replace(/\*/g, '.*') // * => .*
.replace(/\?/g, '.') + // ? => .
'$';
const regex = new RegExp(regexPattern);
return regex.test(packageName);
}
else {
return packageName === pattern;
}
});
}
//# sourceMappingURL=config.js.map