Files

90 lines
2.5 KiB
JavaScript

'use strict';
const fs = require('fs');
const path = require('path');
const Ajv = require('ajv');
const DEFAULT_INSTALL_CONFIG = 'ecc-install.json';
const CONFIG_SCHEMA_PATH = path.join(__dirname, '..', '..', '..', 'schemas', 'ecc-install-config.schema.json');
let cachedValidator = null;
function readJson(filePath, label) {
try {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (error) {
throw new Error(`Invalid JSON in ${label}: ${error.message}`);
}
}
function getValidator() {
if (cachedValidator) {
return cachedValidator;
}
const schema = readJson(CONFIG_SCHEMA_PATH, 'ecc-install-config.schema.json');
const ajv = new Ajv({ allErrors: true });
cachedValidator = ajv.compile(schema);
return cachedValidator;
}
function dedupeStrings(values) {
return [...new Set((Array.isArray(values) ? values : []).map(value => String(value).trim()).filter(Boolean))];
}
function formatValidationErrors(errors = []) {
return errors.map(error => `${error.instancePath || '/'} ${error.message}`).join('; ');
}
function resolveInstallConfigPath(configPath, options = {}) {
if (!configPath) {
throw new Error('An install config path is required');
}
const cwd = options.cwd || process.cwd();
return path.isAbsolute(configPath)
? configPath
: path.normalize(path.join(cwd, configPath));
}
function findDefaultInstallConfigPath(options = {}) {
const cwd = options.cwd || process.cwd();
const candidatePath = path.join(cwd, DEFAULT_INSTALL_CONFIG);
return fs.existsSync(candidatePath) ? candidatePath : null;
}
function loadInstallConfig(configPath, options = {}) {
const resolvedPath = resolveInstallConfigPath(configPath, options);
if (!fs.existsSync(resolvedPath)) {
throw new Error(`Install config not found: ${resolvedPath}`);
}
const raw = readJson(resolvedPath, path.basename(resolvedPath));
const validator = getValidator();
if (!validator(raw)) {
throw new Error(
`Invalid install config ${resolvedPath}: ${formatValidationErrors(validator.errors)}`
);
}
return {
path: resolvedPath,
version: raw.version,
target: raw.target || null,
profileId: raw.profile || null,
moduleIds: dedupeStrings(raw.modules),
includeComponentIds: dedupeStrings(raw.include),
excludeComponentIds: dedupeStrings(raw.exclude),
options: raw.options && typeof raw.options === 'object' ? { ...raw.options } : {},
};
}
module.exports = {
DEFAULT_INSTALL_CONFIG,
findDefaultInstallConfigPath,
loadInstallConfig,
resolveInstallConfigPath,
};