All files / src json-key-validator.js

0% Statements 0/31
0% Branches 0/21
0% Functions 0/4
0% Lines 0/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125                                                                                                                                                                                                                                                         
/**
 * @file json-key-validator.js
 * @description This script validates the presence of required keys in a JSON object loaded from 'specs.json'.
 * It uses synchronous methods to read the file and check the keys. If any required key is missing, it logs an error.
 * The script pauses execution and waits for the user to press ENTER before continuing.
 * 
 * @requires fs - File system module to read the JSON file.
 * @requires readline-sync - Module to pause the script and wait for user input.
 */
 
const fs = require('node:fs');
const readlineSync = require('readline-sync');
const Logger = require('./utils/logger');
 
let errorFound = false;
 
// Function to pause the script and wait for the ENTER key synchronously
function pauseForEnterSync() {
    readlineSync.question('Press ENTER to continue...');
}
 
// Load the JSON data from the 'specs.json' file
function loadData() {
    return JSON.parse(fs.readFileSync('./specs.json', 'utf8'));
}
 
// This function recursively checks if the required keys are present in the object
function checkKeysSync(object, expectedKeys, parentKey = '') {
    // Guard against undefined or non-iterable expected key definitions so the validator fails gracefully instead of throwing.
    if (!Array.isArray(expectedKeys)) {
        return;
    }
 
    for (let key of expectedKeys) {
        if (Array.isArray(object)) {
            // If the object is an array, check each item within the array
            for (let [index, item] of object.entries()) {
                checkKeysSync(item, expectedKeys, `${parentKey}[${index}]`);
            }
        } else if (typeof object === 'object') {
            // If the key is missing from the object, log an error
            if (!(key in object)) {
                Logger.error(`Error: Missing key '${key}'\n   We cannot guarantee that Spec-Up-T will work properly.\n   Here is an example specs.json file:\n   https://github.com/trustoverip/spec-up-t-starter-pack/blob/main/spec-up-t-boilerplate/specs.json`);
                errorFound = true;
                pauseForEnterSync(); // Pause synchronously to allow user to acknowledge the error
            }
            // If the expected key contains nested objects, recursively check for them
            if (typeof expectedKeys[key] === 'object' && object[key]) {
                checkKeysSync(object[key], expectedKeys[key], `${parentKey}.${key}`);
            }
        }
    }
}
 
// Main function that runs the validator script
function runJsonKeyValidatorSync() {
    const data = loadData(); // Load the JSON file data
 
    // Define the keys expected in the JSON structure
    const expectedKeys = {
        specs: [
            "title",
            "spec_directory",
            "spec_terms_directory",
            "output_path",
            "markdown_paths",
            "logo",
            "logo_link",
            "source",
            // "external_specs"
            // "assets"  // Commented out: We no longer check for 'assets' in the specs object
        ],
        source: [
            "host",
            "account",
            "repo"
        ],
        // external_specs: [
        //     "gh_page",
        //     "external_spec",
        //     "url",
        //     "terms_dir"
        // ],
        // Removed the 'assets' block entirely, as it's no longer part of the required keys:
        // assets: [
        //     "path",
        //     "inject",
        //     "module"
        // ]
    };
 
    // Iterate over each spec entry in the specs array from the JSON file
    for (let [index, spec] of data.specs.entries()) {
        Logger.info(`Checking spec #${index + 1}`);
 
        // Check for keys defined in expectedKeys.specs
        checkKeysSync(spec, expectedKeys.specs, `specs[${index}]`);
 
        // Check for keys inside the 'source' object, if present
        if (spec.source) {
            checkKeysSync(spec.source, expectedKeys.source, `specs[${index}].source`);
        }
 
        // Check for keys inside the 'external_specs' array, if present
        if (spec.external_specs && Array.isArray(expectedKeys.external_specs)) {
            checkKeysSync(spec.external_specs, expectedKeys.external_specs, `specs[${index}].external_specs`);
        }
 
        // The assets check is no longer necessary and has been commented out
        // if (spec.assets) {
        //     checkKeysSync(spec.assets, expectedKeys.assets, `specs[${index}].assets`);
        // }
    }
 
    // If no errors were found, print a success message
    if (!errorFound) {
        Logger.success('All keys are present. No errors found. Continuing…');
    }
}
 
// Export the function to be used in other scripts
module.exports = {
    runJsonKeyValidatorSync
};