dependency-cruiser
Version:
Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.
242 lines (209 loc) • 6.5 kB
JavaScript
import { accessSync, constants } from "node:fs";
import { isAbsolute } from "node:path";
import {
RULES_FILE_NAME_SEARCH_ARRAY,
DEFAULT_BASELINE_FILE_NAME,
OUTPUT_TO,
OUTPUT_TYPE,
WEBPACK_CONFIG,
TYPESCRIPT_CONFIG,
BABEL_CONFIG,
OLD_DEFAULT_RULES_FILE_NAME,
} from "./defaults.mjs";
import { set } from "#utl/object-util.mjs";
import loadConfig from "#config-utl/extract-depcruise-config/index.mjs";
function getOptionValue(pDefault) {
return (pValue) => (typeof pValue === "string" ? pValue : pDefault);
}
// eslint-disable-next-line complexity
function normalizeConfigFileName(pCliOptions, pConfigWrapperName, pDefault) {
let lOptions = structuredClone(pCliOptions);
if (Object.hasOwn(lOptions, pConfigWrapperName)) {
set(
lOptions,
`ruleSet.options.${pConfigWrapperName}.fileName`,
getOptionValue(pDefault)(lOptions[pConfigWrapperName]),
/* eslint security/detect-object-injection: 0 */
);
Reflect.deleteProperty(lOptions, pConfigWrapperName);
}
if (
(lOptions?.ruleSet?.options?.[pConfigWrapperName] ?? null) &&
!(lOptions?.ruleSet?.options?.[pConfigWrapperName]?.fileName ?? null)
) {
set(lOptions, `ruleSet.options.${pConfigWrapperName}.fileName`, pDefault);
}
return lOptions;
}
function fileExists(pFileName) {
try {
accessSync(pFileName, constants.R_OK);
return true;
} catch (pError) {
return false;
}
}
function validateAndGetCustomRulesFileName(pValidate) {
let lReturnValue = "";
if (fileExists(pValidate)) {
lReturnValue = pValidate;
} else {
throw new Error(
`Can't open config file '${pValidate}' for reading. Does it exist?\n` +
` - You can create a config file by running 'npx dependency-cruiser --init'\n` +
` - If you intended to run without a config file use --no-config\n`,
);
}
return lReturnValue;
}
function validateAndGetDefaultRulesFileName() {
let lReturnValue = RULES_FILE_NAME_SEARCH_ARRAY.find(fileExists);
if (typeof lReturnValue === "undefined") {
throw new TypeError(
`Can't open a config file (.dependency-cruiser.(c)js) at the default location. Does it exist?\n` +
` - You can create one by running 'npx dependency-cruiser --init'\n` +
` - Want to run a without a config file? Use --no-config\n`,
);
}
return lReturnValue;
}
function validateAndNormalizeRulesFileName(pValidate) {
let lReturnValue = "";
if (typeof pValidate === "string") {
lReturnValue = validateAndGetCustomRulesFileName(pValidate);
} else {
lReturnValue = validateAndGetDefaultRulesFileName();
}
return lReturnValue;
}
function validateAndGetKnownViolationsFileName(pKnownViolations) {
const lKnownViolationsFileName =
typeof pKnownViolations === "string"
? pKnownViolations
: DEFAULT_BASELINE_FILE_NAME;
if (fileExists(lKnownViolationsFileName)) {
return lKnownViolationsFileName;
} else {
throw new Error(
`Can't open '${lKnownViolationsFileName}' for reading. Does it exist?\n` +
` (You can create a .dependency-cruiser-known-violations.json with --output-type baseline)\n`,
);
}
}
function normalizeKnownViolationsOption(pCliOptions) {
if (
!Object.hasOwn(pCliOptions, "ignoreKnown") ||
pCliOptions.ignoreKnown === false
) {
return {};
}
return {
knownViolationsFile: validateAndGetKnownViolationsFileName(
pCliOptions.ignoreKnown,
),
};
}
async function normalizeValidationOption(pCliOptions) {
if (!pCliOptions.validate) {
return {
validate: false,
};
}
const rulesFile = validateAndNormalizeRulesFileName(pCliOptions.validate);
return {
rulesFile,
ruleSet: await loadConfig(
isAbsolute(rulesFile) ? rulesFile : `./${rulesFile}`,
),
validate: true,
};
}
function normalizeProgress(pCliOptions) {
if (!Object.hasOwn(pCliOptions, "progress")) {
return {};
}
let lProgress = pCliOptions.progress;
if (lProgress === true) {
lProgress = "cli-feedback";
}
return { progress: lProgress };
}
function normalizeCacheStrategy(pCliOptions) {
if (!Object.hasOwn(pCliOptions, "cacheStrategy")) {
return {};
}
const lStrategy =
pCliOptions.cacheStrategy === "content" ? "content" : "metadata";
let lReturnValue = {};
if (pCliOptions.cache && typeof pCliOptions.cache === "object") {
lReturnValue.cache = structuredClone(pCliOptions.cache);
lReturnValue.cache.strategy = lStrategy;
} else {
lReturnValue = {
cache: {
strategy: lStrategy,
},
};
}
return lReturnValue;
}
function normalizeCache(pCliOptions) {
if (!Object.hasOwn(pCliOptions, "cache")) {
return {};
}
if (pCliOptions.cache === true) {
return { cache: {} };
}
if (typeof pCliOptions.cache === "string") {
return {
cache: {
folder: pCliOptions.cache,
},
};
}
return { cache: false };
}
/**
* returns the pOptionsAsPassedFromCommander, so that the returned value contains a
* valid value for each possible option
*
* @param {object} pOptionsAsPassedFromCommander [description]
* @param {any} pKnownCliOptions [description]
* @return {object} [description]
*/
export default async function normalizeOptions(pOptionsAsPassedFromCommander) {
let lOptions = {
outputTo: OUTPUT_TO,
outputType: OUTPUT_TYPE,
...pOptionsAsPassedFromCommander,
};
if (Object.hasOwn(lOptions, "moduleSystems")) {
lOptions.moduleSystems = lOptions.moduleSystems
.split(",")
.map((pString) => pString.trim());
}
if (Object.hasOwn(lOptions, "config")) {
lOptions.validate = lOptions.config;
}
lOptions = { ...lOptions, ...(await normalizeValidationOption(lOptions)) };
lOptions = { ...lOptions, ...normalizeProgress(lOptions) };
lOptions = { ...lOptions, ...normalizeCache(lOptions) };
lOptions = { ...lOptions, ...normalizeCacheStrategy(lOptions) };
lOptions = { ...lOptions, ...normalizeKnownViolationsOption(lOptions) };
lOptions = normalizeConfigFileName(lOptions, "webpackConfig", WEBPACK_CONFIG);
lOptions = normalizeConfigFileName(lOptions, "tsConfig", TYPESCRIPT_CONFIG);
lOptions = normalizeConfigFileName(lOptions, "babelConfig", BABEL_CONFIG);
if (Object.hasOwn(lOptions, "affected") && lOptions.affected !== false) {
const { list } = await import("watskeburt");
lOptions.reaches = await list({
oldRevision: lOptions.affected === true ? "main" : lOptions.affected,
outputType: "regex",
extensions:
"cjs,cjsx,coffee,csx,cts,js,json,jsx,litcoffee,ls,mjs,mts,svelte,ts,tsx,vue,vuex",
});
}
return lOptions;
}
export const determineRulesFileName = getOptionValue(
OLD_DEFAULT_RULES_FILE_NAME,
);