@syntropysoft/praetorian
Version:
Praetorian CLI – A universal multi-environment configuration validator for DevSecOps teams. Validate, compare, and secure YAML/ENV files with ease.
266 lines • 9.23 kB
JavaScript
;
/**
* @file src/application/services/rule-loading/SimpleRuleDictionary.ts
* @description Pure functional dictionary for simple rules (SOLID SRP + Functional Programming)
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateSimpleRules = exports.validateSimpleRule = exports.overrideSimpleRulesInDictionary = exports.removeSimpleRulesFromDictionary = exports.filterSimpleDictionary = exports.getSimpleDictionaryStats = exports.hasSimpleRule = exports.getSimpleRuleById = exports.simpleDictionaryToRules = exports.mergeSimpleRuleDictionaries = exports.addSimpleRulesToDictionary = exports.createEmptySimpleDictionary = void 0;
/**
* Creates an empty simple rule dictionary
* @returns Empty rule dictionary
*/
const createEmptySimpleDictionary = () => ({});
exports.createEmptySimpleDictionary = createEmptySimpleDictionary;
/**
* Adds simple rules to dictionary, skipping duplicates (Guard Clause Pattern)
* @param dictionary - Current dictionary
* @param rules - Rules to add
* @param source - Source identifier for warnings
* @returns Dictionary result with added/skipped rules
*/
const addSimpleRulesToDictionary = (dictionary, rules, source = 'unknown') => {
// Guard clause: no rules to add
if (!rules || rules.length === 0) {
return {
dictionary,
added: [],
skipped: [],
warnings: [],
};
}
const newDictionary = { ...dictionary };
const added = [];
const skipped = [];
const warnings = [];
for (const rule of rules) {
// Guard clause: rule without ID
if (!rule.id || rule.id.trim().length === 0) {
warnings.push(`Rule from ${source} has no ID, skipping`);
continue;
}
// Guard clause: rule without name
if (!rule.name || rule.name.trim().length === 0) {
warnings.push(`Rule '${rule.id}' from ${source} has no name, skipping`);
continue;
}
if (newDictionary[rule.id]) {
// Rule already exists
skipped.push(rule.id);
warnings.push(`Rule '${rule.id}' already exists, skipping duplicate from ${source}`);
}
else {
// Add new rule
newDictionary[rule.id] = rule;
added.push(rule.id);
}
}
return {
dictionary: newDictionary,
added,
skipped,
warnings,
};
};
exports.addSimpleRulesToDictionary = addSimpleRulesToDictionary;
/**
* Merges multiple simple rule dictionaries (Functional Composition)
* @param dictionaries - Array of dictionaries to merge
* @param sources - Source identifiers for warnings
* @returns Merged dictionary result
*/
const mergeSimpleRuleDictionaries = (dictionaries, sources = []) => {
// Guard clause: no dictionaries
if (!dictionaries || dictionaries.length === 0) {
return {
dictionary: (0, exports.createEmptySimpleDictionary)(),
added: [],
skipped: [],
warnings: [],
};
}
let result = (0, exports.createEmptySimpleDictionary)();
const allAdded = [];
const allSkipped = [];
const allWarnings = [];
for (let i = 0; i < dictionaries.length; i++) {
const dict = dictionaries[i];
const source = sources[i] || `source-${i}`;
// Convert dictionary to array of rules
const rules = Object.values(dict);
const mergeResult = (0, exports.addSimpleRulesToDictionary)(result, rules, source);
result = mergeResult.dictionary;
allAdded.push(...mergeResult.added);
allSkipped.push(...mergeResult.skipped);
allWarnings.push(...mergeResult.warnings);
}
return {
dictionary: result,
added: allAdded,
skipped: allSkipped,
warnings: allWarnings,
};
};
exports.mergeSimpleRuleDictionaries = mergeSimpleRuleDictionaries;
/**
* Converts dictionary to array of simple rules (Pure Function)
* @param dictionary - Rule dictionary
* @returns Array of rules
*/
const simpleDictionaryToRules = (dictionary) => {
return Object.values(dictionary);
};
exports.simpleDictionaryToRules = simpleDictionaryToRules;
/**
* Gets simple rule by ID from dictionary (Pure Function)
* @param dictionary - Rule dictionary
* @param ruleId - Rule ID to find
* @returns Rule if found, undefined otherwise
*/
const getSimpleRuleById = (dictionary, ruleId) => {
return dictionary[ruleId];
};
exports.getSimpleRuleById = getSimpleRuleById;
/**
* Checks if simple rule exists in dictionary (Pure Function)
* @param dictionary - Rule dictionary
* @param ruleId - Rule ID to check
* @returns True if rule exists
*/
const hasSimpleRule = (dictionary, ruleId) => {
return ruleId in dictionary;
};
exports.hasSimpleRule = hasSimpleRule;
/**
* Gets simple rule dictionary statistics (Pure Function)
* @param dictionary - Rule dictionary
* @returns Statistics about the dictionary
*/
const getSimpleDictionaryStats = (dictionary) => {
const rules = Object.values(dictionary);
const uniqueIds = Object.keys(dictionary).length;
return {
totalRules: rules.length,
uniqueIds,
ruleIds: Object.keys(dictionary).sort(),
ruleNames: rules.map(rule => rule.name).sort(),
};
};
exports.getSimpleDictionaryStats = getSimpleDictionaryStats;
/**
* Filters simple dictionary by predicate (Pure Function)
* @param dictionary - Rule dictionary
* @param predicate - Filter function
* @returns Filtered dictionary
*/
const filterSimpleDictionary = (dictionary, predicate) => {
const filtered = {};
for (const [id, rule] of Object.entries(dictionary)) {
if (predicate(rule)) {
filtered[id] = rule;
}
}
return filtered;
};
exports.filterSimpleDictionary = filterSimpleDictionary;
/**
* Removes simple rules from dictionary (Pure Function)
* @param dictionary - Rule dictionary
* @param ruleIds - Rule IDs to remove
* @returns New dictionary without specified rules
*/
const removeSimpleRulesFromDictionary = (dictionary, ruleIds) => {
const newDictionary = { ...dictionary };
for (const ruleId of ruleIds) {
delete newDictionary[ruleId];
}
return newDictionary;
};
exports.removeSimpleRulesFromDictionary = removeSimpleRulesFromDictionary;
/**
* Overrides simple rules in dictionary (Pure Function)
* @param dictionary - Rule dictionary
* @param overrides - Rules to override (by ID)
* @returns New dictionary with overridden rules
*/
const overrideSimpleRulesInDictionary = (dictionary, overrides) => {
const newDictionary = { ...dictionary };
const overridden = [];
const warnings = [];
for (const override of overrides) {
// Guard clause: no ID in override
if (!override.id || override.id.trim().length === 0) {
warnings.push('Override rule has no ID, skipping');
continue;
}
if (newDictionary[override.id]) {
// Merge with existing rule
newDictionary[override.id] = {
...newDictionary[override.id],
...override,
id: override.id, // Ensure ID is not overridden
};
overridden.push(override.id);
}
else {
warnings.push(`Cannot override rule '${override.id}' - rule not found in dictionary`);
}
}
return {
dictionary: newDictionary,
added: overridden,
skipped: [],
warnings,
};
};
exports.overrideSimpleRulesInDictionary = overrideSimpleRulesInDictionary;
/**
* Validates simple rule structure (Pure Function with Guard Clauses)
* @param rule - Rule to validate
* @returns Validation result
*/
const validateSimpleRule = (rule) => {
const errors = [];
// Guard clause: no rule object
if (!rule) {
errors.push('Rule object is required');
return { valid: false, errors };
}
// Guard clause: no ID
if (!rule.id || typeof rule.id !== 'string' || rule.id.trim().length === 0) {
errors.push('Rule must have a valid ID');
}
// Guard clause: no name
if (!rule.name || typeof rule.name !== 'string' || rule.name.trim().length === 0) {
errors.push('Rule must have a valid name');
}
return {
valid: errors.length === 0,
errors,
};
};
exports.validateSimpleRule = validateSimpleRule;
/**
* Validates array of simple rules (Pure Function)
* @param rules - Rules to validate
* @returns Validation result
*/
const validateSimpleRules = (rules) => {
// Guard clause: no rules array
if (!Array.isArray(rules)) {
return { valid: false, errors: ['Rules must be an array'] };
}
const allErrors = [];
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
const validation = (0, exports.validateSimpleRule)(rule);
if (!validation.valid) {
allErrors.push(`Rule at index ${i}: ${validation.errors.join(', ')}`);
}
}
return {
valid: allErrors.length === 0,
errors: allErrors,
};
};
exports.validateSimpleRules = validateSimpleRules;
//# sourceMappingURL=SimpleRuleDictionary.js.map