sourcecontrol
Version:
A modern TypeScript CLI application for source control
151 lines • 5.85 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigParser = void 0;
const config_level_1 = require("./config-level");
class ConfigParser {
static parse(content, source, level) {
const result = new Map();
if (!content.trim())
return result;
try {
const configData = JSON.parse(content);
this.parseSection(configData, result, source, level);
}
catch (error) {
throw new Error(`Invalid JSON in configuration file ${source}: ${error.message}`);
}
return result;
}
static serialize(entries) {
const configData = {};
entries.forEach((entryList, fullKey) => {
entryList.forEach((entry) => this.setNestedValue(configData, fullKey, entry.value));
});
return JSON.stringify(configData, null, 2);
}
static validate(content) {
const errors = [];
try {
const parsed = JSON.parse(content);
if (typeof parsed !== 'object' || parsed === null) {
errors.push('Configuration must be a JSON object');
}
this.validateSection(parsed, '', errors);
}
catch (error) {
errors.push(`Invalid JSON: ${error.message}`);
}
return { valid: errors.length === 0, errors };
}
static formatForDisplay(entries) {
const configData = {};
entries.forEach((entryList, fullKey) => {
const effectiveEntry = entryList[entryList.length - 1];
if (effectiveEntry)
this.setNestedValue(configData, fullKey, effectiveEntry.value);
});
return JSON.stringify(configData, null, 2);
}
static parseSection(configData, result, source, level, keyPrefix = '') {
Object.entries(configData).forEach(([sectionKey, sectionValue]) => {
const fullKey = this.buildFullKey(keyPrefix, sectionKey);
this.processConfigValue(fullKey, sectionValue, result, source, level);
});
}
static buildFullKey(prefix, key) {
return prefix ? `${prefix}.${key}` : key;
}
static processConfigValue(key, value, result, source, level) {
if (Array.isArray(value)) {
this.processArrayValue(key, value, result, source, level);
}
else if (this.isNestedObject(value)) {
this.parseSection(value, result, source, level, key);
}
else if (typeof value === 'string') {
this.addEntry(result, key, value, source, level);
}
}
static processArrayValue(key, values, result, source, level) {
values.forEach((item) => {
if (typeof item === 'string') {
this.addEntry(result, key, item, source, level);
}
});
}
static isNestedObject(value) {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
static addEntry(entryMap, configKey, configValue, source, level) {
this.ensureKeyExists(entryMap, configKey);
const configEntry = this.createConfigEntry(configKey, configValue, level, source);
entryMap.get(configKey).push(configEntry);
}
static ensureKeyExists(entryMap, key) {
if (!entryMap.has(key)) {
entryMap.set(key, []);
}
}
static createConfigEntry(key, value, level, source) {
const DEFAULT_LINE_NUMBER = 0;
return new config_level_1.ConfigEntry(key, value, level, source, DEFAULT_LINE_NUMBER);
}
static setNestedValue(configObject, keyPath, value) {
const pathSegments = keyPath.split('.');
const finalKey = pathSegments.pop();
const targetObject = this.navigateToTargetObject(configObject, pathSegments);
this.setValueInObject(targetObject, finalKey, value);
}
static navigateToTargetObject(rootObject, pathSegments) {
let currentObject = rootObject;
for (const segment of pathSegments) {
if (!this.hasValidObjectProperty(currentObject, segment)) {
currentObject[segment] = {};
}
currentObject = currentObject[segment];
}
return currentObject;
}
static hasValidObjectProperty(obj, propertyKey) {
return propertyKey in obj &&
typeof obj[propertyKey] === 'object' &&
!Array.isArray(obj[propertyKey]);
}
static setValueInObject(targetObject, key, newValue) {
if (key in targetObject) {
const existingValue = targetObject[key];
targetObject[key] = Array.isArray(existingValue)
? [...existingValue, newValue]
: [existingValue, newValue];
}
else {
targetObject[key] = newValue;
}
}
static validateSection(configSection, currentPath, errors) {
Object.entries(configSection).forEach(([key, value]) => {
const valuePath = this.buildFullKey(currentPath, key);
this.validateConfigValue(valuePath, value, errors);
});
}
static validateConfigValue(path, value, errors) {
if (Array.isArray(value)) {
this.validateArrayValue(path, value, errors);
}
else if (this.isNestedObject(value)) {
this.validateSection(value, path, errors);
}
else if (typeof value !== 'string') {
errors.push(`Configuration value at '${path}' must be a string`);
}
}
static validateArrayValue(path, values, errors) {
values.forEach((item) => {
if (typeof item !== 'string') {
errors.push(`Configuration array at '${path}' must contain only strings`);
}
});
}
}
exports.ConfigParser = ConfigParser;
//# sourceMappingURL=config-parser.js.map
;