UNPKG

dce-dev-wizard

Version:

Wizard for managing development apps at Harvard DCE.

234 lines 9.85 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); // Import constants const TOP_LEVEL_DIRECTORY_1 = __importDefault(require("./constants/TOP_LEVEL_DIRECTORY")); const APP_DIRECTORY_1 = __importDefault(require("./constants/APP_DIRECTORY")); // Error code regex const errorCodeRegex = /new ErrorWithCode\(\s*(.+),\s*(.+)\s*\)(;|,)/; /*------------------------------------------------------------------------*/ /* ------------------------------- Helpers ------------------------------ */ /*------------------------------------------------------------------------*/ /** * Get all paths to the error code types within a folder * @author Gabe Abrams * @param parentFolderPath - the path to the parent folder * @returns an array of paths to the error code types */ const getErrorCodesPaths = (parentFolderPath) => { // Get all files in the folder const files = fs_1.default.readdirSync(parentFolderPath); // For each item in the folder, recurse if folder, analyze if file const paths = []; files.forEach((file) => { // Get the full path const fullPath = path_1.default.join(parentFolderPath, file); // If folder, recurse const isFolder = (fs_1.default .lstatSync(fullPath) .isDirectory()); if (isFolder) { // Skip if the "from-server" folder if (file !== 'from-server') { // Recurse paths.push(...getErrorCodesPaths(fullPath)); } } else { // Not folder. Analyze if (file.includes('ErrorCode') && (file.endsWith('.ts') || file.endsWith('.tsx'))) { // Found an error code file paths.push(fullPath); } } }); // Return all accumulated paths return paths; }; /** * Read an error code file and return the error codes within it * @author Gabe Abrams * @param filePath - the path to the error code file * @returns an array of error codes */ const readErrorCodes = (filePath) => { // Read the file const fileContents = fs_1.default.readFileSync(filePath, 'utf8'); // Get the name of the error code file const parent = ((filePath.split('/').pop() || 'UnknownErrorCodeParent') .replace('.tsx', '') .replace('.ts', '')); // Split the file into lines const lines = fileContents.split('\n'); // Find all error codes const errorCodes = []; lines.forEach((line, lineNumber) => { // Format of an error code: // DescriptionOfErrorCode = 'CODE', // Check if this line is an error code const matches = line.trim().match(/(\w+) = '(\w+)',/); if (matches) { // Found an error code const name = matches[1]; const code = matches[2]; // Add to error codes errorCodes.push({ parent, code, found: false, prop: name, appearances: [], }); } }); // Return all error codes return errorCodes; }; /*------------------------------------------------------------------------*/ /* -------------------------------- Main -------------------------------- */ /*------------------------------------------------------------------------*/ /*----------------------------------------*/ /* ---------- Parse Error Codes --------- */ /*----------------------------------------*/ console.log('\nUpdating error docs...'); // Get error code file paths const serverPaths = getErrorCodesPaths(path_1.default.join(APP_DIRECTORY_1.default, '/server/src')); const clientPaths = getErrorCodesPaths(path_1.default.join(APP_DIRECTORY_1.default, '/client/src')); const errorCodePaths = serverPaths.concat(clientPaths); // Read each and process the enums const errorCodes = []; errorCodePaths.forEach((filePath) => { errorCodes.push(...readErrorCodes(filePath)); }); /*----------------------------------------*/ /* -------- Validate Error Codes -------- */ /*----------------------------------------*/ // Display fatal error if duplicate error codes exist const errorCodeSet = new Set(); errorCodes.forEach((errorCode) => { if (errorCodeSet.has(errorCode.code)) { console.error(`Duplicate error code defined: ${errorCode.code} in ${errorCode.parent}. Fatal error. Exiting!`); process.exit(1); } }); /*----------------------------------------*/ /* ---------- Find Appearances ---------- */ /*----------------------------------------*/ /** * Recursively look for appearances of error codes * @author Gabe Abrams * @param folderPath - the path to the folder to search */ const findAppearances = (folderPath) => { // Format of an error appearance: // new ErrorWithCode( // `Message template with ${templateVariables} in it perhaps`, // ErrorCodeParent.ErrorCodePropName, // ); // Get all files in the folder const files = fs_1.default.readdirSync(folderPath); // For each item in the folder, recurse if folder, analyze if file files.forEach((file) => { // Get the full path const fullPath = path_1.default.join(folderPath, file); // If folder, recurse const isFolder = (fs_1.default .lstatSync(fullPath) .isDirectory()); if (isFolder) { // Recurse findAppearances(fullPath); } else { // Not folder. Analyze if ((file.endsWith('.ts') || file.endsWith('.tsx')) && !errorCodePaths.includes(fullPath)) { // Read the file let fileContents = fs_1.default.readFileSync(fullPath, 'utf8'); // Check if found errorCodes.find((errorCode) => { if (fileContents.includes(`${errorCode.parent}.${errorCode.prop},`) || fileContents.includes(`${errorCode.parent}.${errorCode.prop};`) || fileContents.includes(`${errorCode.parent}.${errorCode.prop} `) || fileContents.includes(`${errorCode.parent}.${errorCode.prop})`) || fileContents.includes(`${errorCode.parent}.${errorCode.prop}\n`)) { errorCode.found = true; } }); // Check if this line is an error appearance let matches = fileContents.trim().match(errorCodeRegex); while (matches) { // Found an error appearance const messageTemplate = matches[1]; const parentAndProp = matches[2]; // Find the error code const errorCode = errorCodes.find((errorCode) => { return (`${errorCode.parent}.${errorCode.prop},` === parentAndProp.trim()); }); if (errorCode) { // Add the appearance errorCode.appearances.push({ messageTemplate, filePath: fullPath, }); } // Remove this match fileContents = fileContents.replace(matches[0], ''); matches = fileContents.trim().match(errorCodeRegex); } } } }); }; // Add appearances in each folder findAppearances(path_1.default.join(APP_DIRECTORY_1.default, '/server/src')); findAppearances(path_1.default.join(APP_DIRECTORY_1.default, '/client/src')); /*------------------------------------------------------------------------*/ /* ----------------------------- Build Docs ----------------------------- */ /*------------------------------------------------------------------------*/ let docsMD = ''; /*----------------------------------------*/ /* -------------- Metadata -------------- */ /*----------------------------------------*/ const pkg = require(path_1.default.join(APP_DIRECTORY_1.default, 'package.json')); if (!pkg) { console.log('package.json not found'); process.exit(1); } const projectName = pkg.name || 'This Project'; /*----------------------------------------*/ /* ---------------- Intro --------------- */ /*----------------------------------------*/ docsMD = `# Error Cheatsheet for ${projectName}\n`; docsMD += 'This is an auto-generated document that outlines the friendly error codes that users may encounter when using this app.\n\n'; /*----------------------------------------*/ /* ---------------- Table --------------- */ /*----------------------------------------*/ // Header docsMD += '\n| Code | Internal Name | Associated Message |\n'; docsMD += '| -------- | -------- | -------- |\n'; // Error codes errorCodes.forEach((err) => { // Skip ones that are not in use if (!err.found) { return; } let associatedMessage = (err .appearances .map((appearance) => { return `<div>${appearance.messageTemplate.replace('`', '\'')}<div style="font-size: 80%">${appearance.filePath.replace(APP_DIRECTORY_1.default, '')}</div></div>`; }) .join('<br>')); if (err.appearances.length === 0) { associatedMessage = 'No additional information'; } docsMD += `| ${err.code} | ${err.prop} | ${associatedMessage} |\n`; }); // Finish fs_1.default.writeFileSync(path_1.default.join(TOP_LEVEL_DIRECTORY_1.default, 'docs/ErrorCodeDocs.md'), docsMD, 'utf-8'); console.log('Success! Written to docs/ErrorCodeDocs.md'); //# sourceMappingURL=buildErrorDocs.js.map