linkinator
Version:
Find broken links, missing images, etc in your HTML. Scurry around your site and find all those broken links.
81 lines (80 loc) • 2.96 kB
JavaScript
import { promises as fs } from 'node:fs';
import path from 'node:path';
import process from 'node:process';
const validConfigExtensions = ['.js', '.mjs', '.cjs', '.json'];
export async function getConfig(flags) {
// Check to see if a config file path was passed
let config;
if (flags.config) {
config = await parseConfigFile(flags.config);
}
else {
config = (await tryGetDefaultConfig()) || {};
}
// `meow` is set up to pass boolean flags as `undefined` if not passed.
// copy the struct, and delete properties that are `undefined` so the merge
// doesn't blast away config level settings.
const strippedFlags = { ...flags };
for (const [key, value] of Object.entries(strippedFlags)) {
if (value === undefined || (Array.isArray(value) && value.length === 0)) {
delete strippedFlags[key];
}
}
// Combine the flags passed on the CLI with the flags in the config file,
// with CLI flags getting precedence
config = { ...config, ...strippedFlags };
return config;
}
/**
* Attempt to load `linkinator.config.json`, assuming the user hasn't
* passed a specific path to a config.
* @returns The contents of the default config if present, or an empty config.
*/
async function tryGetDefaultConfig() {
const defaultConfigPath = path.join(process.cwd(), 'linkinator.config.json');
try {
const config = await parseConfigFile(defaultConfigPath);
return config;
}
catch (e) {
return {};
}
}
async function parseConfigFile(configPath) {
const typeOfConfig = getTypeOfConfig(configPath);
switch (typeOfConfig) {
case '.json': {
return readJsonConfigFile(configPath);
}
case '.js':
case '.mjs':
case '.cjs': {
return importConfigFile(configPath);
}
default: {
throw new Error(`Config file ${configPath} is invalid`);
}
}
}
function getTypeOfConfig(configPath) {
// Returning json in case file doesn't have an extension for backward compatibility
const configExtension = path.extname(configPath) || '.json';
if (validConfigExtensions.includes(configExtension)) {
return configExtension;
}
throw new Error(`Config file should be either of extensions ${validConfigExtensions.join(',')}`);
}
async function importConfigFile(configPath) {
// Use a filthy hack to prevent ncc / webpack from trying to process
// the runtime dynamic import. This hurt me more than it disgusts
// whoever is reading the code.
const _import = new Function('p', 'return import(p)');
const config = (await _import(`file://${path.resolve(process.cwd(), configPath)}`));
return config.default;
}
async function readJsonConfigFile(configPath) {
const configFileContents = await fs.readFile(configPath, {
encoding: 'utf8',
});
return JSON.parse(configFileContents);
}