UNPKG

taylo

Version:

Make changes to a branch a plugin. A command-line tool to manage and apply plugins '.taylored'. Supports applying, removing, verifying plugins, and generating them from branch (GIT).

325 lines (324 loc) 16.7 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const fs = __importStar(require("fs/promises")); const path = __importStar(require("path")); const constants_1 = require("./lib/constants"); const apply_logic_1 = require("./lib/apply-logic"); const save_handler_1 = require("./lib/handlers/save-handler"); const list_handler_1 = require("./lib/handlers/list-handler"); const offset_handler_1 = require("./lib/handlers/offset-handler"); const automatic_handler_1 = require("./lib/handlers/automatic-handler"); const utils_1 = require("./lib/utils"); const PatchAnalyzer_1 = require("./lib/PatchAnalyzer"); async function main() { const rawArgs = process.argv.slice(2); const CWD = process.cwd(); if (rawArgs.length === 0) { (0, utils_1.printUsageAndExit)(undefined, true); return; } const mode = rawArgs[0]; let argument; let branchName; const relevantModesForGitCheck = [ '--add', '--remove', '--verify-add', '--verify-remove', '--save', '--list', '--offset', '--automatic', '--upgrade', ]; if (relevantModesForGitCheck.includes(mode)) { const gitDirPath = path.join(CWD, '.git'); try { const gitDirStats = await fs.stat(gitDirPath); if (!gitDirStats.isDirectory()) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: A '.git' entity exists at '${gitDirPath}', but it is not a directory. This script must be run from the root of a Git repository for the command '${mode}'.`); } } catch (error) { if (error.code === 'ENOENT') { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: No '.git' directory found in '${CWD}'. The command '${mode}' must be run from the root of a Git repository.`); } else { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Could not verify '.git' directory presence for '${mode}' in '${CWD}'. Details: ${error.message}`); } } } try { if (mode === '--save') { if (rawArgs.length !== 2) { (0, utils_1.printUsageAndExit)('CRITICAL ERROR: --save option requires exactly one <branch_name> argument.'); } argument = rawArgs[1]; if (argument.startsWith('--')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Invalid branch name '${argument}' after --save. It cannot start with '--'.`); } await (0, save_handler_1.handleSaveOperation)(argument, CWD); } else if (mode === '--list') { if (rawArgs.length !== 1) { (0, utils_1.printUsageAndExit)('CRITICAL ERROR: --list option does not take any arguments.'); } await (0, list_handler_1.handleListOperation)(CWD); } else if (mode === '--offset') { if (rawArgs.length < 2) { (0, utils_1.printUsageAndExit)('CRITICAL ERROR: --offset option requires at least one <taylored_file_name> argument.'); } argument = rawArgs[1]; if (argument.startsWith('--')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Invalid taylored file name '${argument}' after --offset. It cannot start with '--'.`); } if (argument.includes(path.sep) || argument.includes('/') || argument.includes('\\')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: <taylored_file_name> ('${argument}') must be a simple filename without path separators. It is assumed to be in the '${constants_1.TAYLORED_DIR_NAME}/' directory.`); } branchName = undefined; let currentArgIndex = 2; if (rawArgs.length > currentArgIndex && !rawArgs[currentArgIndex].startsWith('--')) { branchName = rawArgs[currentArgIndex]; if (branchName.startsWith('--')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Invalid branch name '${branchName}' provided for --offset. It cannot start with '--'.`); } currentArgIndex++; } if (rawArgs.length > currentArgIndex) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Unknown or unexpected argument '${rawArgs[currentArgIndex]}' for --offset. Expected optional [BRANCH_NAME] only.`); } await (0, offset_handler_1.handleOffsetCommand)(argument, CWD, branchName); } else if (mode === '--automatic') { let extensionsInput; let branchNameArgument; let excludeDirs; if (rawArgs.length === 3) { extensionsInput = rawArgs[1]; branchNameArgument = rawArgs[2]; } else if (rawArgs.length === 5) { extensionsInput = rawArgs[1]; branchNameArgument = rawArgs[2]; if (rawArgs[3] !== '--exclude') { (0, utils_1.printUsageAndExit)("CRITICAL ERROR: Expected '--exclude' as the fourth argument for --automatic with 5 arguments."); } const excludeArgument = rawArgs[4]; if (excludeArgument.startsWith('--')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Invalid exclude argument '${excludeArgument}'. It cannot start with '--'.`); } excludeDirs = excludeArgument .split(',') .map((dir) => dir.trim()) .filter((dir) => dir.length > 0); if (excludeDirs.length === 0 && excludeArgument.length > 0) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Exclude argument '${excludeArgument}' resulted in an empty list of directories.`); } else if (excludeDirs.length === 0 && excludeArgument.length === 0) { excludeDirs = undefined; } } else { (0, utils_1.printUsageAndExit)('CRITICAL ERROR: --automatic option requires either 2 arguments (<EXTENSIONS> <branch_name>) or 4 arguments (<EXTENSIONS> <branch_name> --exclude <DIR_LIST>).'); return; } if (extensionsInput.startsWith('--')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Invalid extensions input '${extensionsInput}' after --automatic. It cannot start with '--'.`); } if (extensionsInput.includes(path.sep) || extensionsInput.includes('/') || extensionsInput.includes('\\')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: <EXTENSIONS> ('${extensionsInput}') must be a simple extension string (e.g., 'ts,js,py') without path separators.`); } if (branchNameArgument.startsWith('--')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Invalid branch name '${branchNameArgument}' after --automatic <EXTENSIONS>. It cannot start with '--'.`); } await (0, automatic_handler_1.handleAutomaticOperation)(extensionsInput, branchNameArgument, CWD, excludeDirs); } else if (mode === '--upgrade') { if (rawArgs.length < 2 || rawArgs.length > 3) { (0, utils_1.printUsageAndExit)('CRITICAL ERROR: --upgrade option requires a <patch_file> argument and optionally a [target_file_path].'); } const patchFile = rawArgs[1]; if (patchFile.startsWith('--')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Invalid patch file argument '${patchFile}'. It cannot start with '--'.`); } const resolvedPatchFileName = (0, utils_1.resolveTayloredFileName)(patchFile); const fullPatchPath = path.join(CWD, constants_1.TAYLORED_DIR_NAME, resolvedPatchFileName); let targetFilePath; if (rawArgs.length === 3) { targetFilePath = path.resolve(CWD, rawArgs[2]); } try { const analyzer = new PatchAnalyzer_1.PatchAnalyzer(); const results = await analyzer.verifyIntegrityAndUpgrade(fullPatchPath, targetFilePath); console.log(`\n=== Report for --upgrade command ===`); results.forEach((result) => { console.log(`File: ${result.file}`); console.log(`Status: ${result.status.toUpperCase()}`); console.log(`Message: ${result.message}`); if (result.updated) { console.log(`Patch updated: YES`); } else { console.log(`Patch updated: NO`); } if (result.blocks && result.blocks.length > 0) { console.log(` Modification blocks checked: ${result.blocks.length}`); result.blocks.forEach((blockCheck, index) => { console.log(` Block ${index + 1} (${blockCheck.blockType}):`); console.log(` Top Frame: ${blockCheck.topFrame.intact ? 'INTACT' : 'MODIFIED/MISSING'}`); if (!blockCheck.topFrame.intact) { console.log(` Expected: "${blockCheck.topFrame.expected}"`); console.log(` Actual: "${blockCheck.topFrame.actual}"`); } console.log(` Bottom Frame: ${blockCheck.bottomFrame.intact ? 'INTACT' : 'MODIFIED/MISSING'}`); if (!blockCheck.bottomFrame.intact) { console.log(` Expected: "${blockCheck.bottomFrame.expected}"`); console.log(` Actual: "${blockCheck.bottomFrame.actual}"`); } }); } console.log('-----------------------------------'); }); console.log(`\n--upgrade command completed.`); } catch (error) { console.error(`CRITICAL ERROR: Failed to execute --upgrade command. Details: ${error.message}`); throw error; } } else { const applyModes = [ '--add', '--remove', '--verify-add', '--verify-remove', ]; if (applyModes.includes(mode)) { if (rawArgs.length !== 2) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: ${mode} requires a <taylored_file_name_or_path> argument.`); } const userInputFileName = rawArgs[1]; if (userInputFileName.startsWith('--')) { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Invalid taylored file name '${userInputFileName}' after ${mode}. It cannot start with '--'.`); } const userInputAbsolutePath = path.join(CWD, constants_1.TAYLORED_DIR_NAME, userInputFileName); let stats; try { stats = await fs.stat(userInputAbsolutePath); } catch (e) { if (e.code !== 'ENOENT') { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Could not access '${userInputAbsolutePath}'. Details: ${e.message}`); return; } } let isVerify = false; let isReverse = false; switch (mode) { case '--add': break; case '--remove': isReverse = true; break; case '--verify-add': isVerify = true; break; case '--verify-remove': isVerify = true; isReverse = true; break; } if (stats && stats.isDirectory()) { console.log(`INFO: Processing patch group in directory: ${userInputFileName}`); const patches = await (0, utils_1.findPatchesInDirectory)(userInputAbsolutePath); if (patches.length === 0) { console.log(`INFO: No .taylored files found in directory '${userInputAbsolutePath}'. Nothing to do.`); return; } let patchesToProcess = (0, utils_1.sortPatchesNumerically)(patches); if (isReverse) { patchesToProcess = patchesToProcess.reverse(); console.log(`INFO: Found ${patchesToProcess.length} patch(es) to process in REVERSE order (for removal):`); } else { console.log(`INFO: Found ${patchesToProcess.length} patch(es) to process in order:`); } patchesToProcess.forEach((p) => console.log(` - ${path.relative(path.join(CWD, constants_1.TAYLORED_DIR_NAME), p)}`)); for (const patchPath of patchesToProcess) { const patchFileNameForApply = path.relative(path.join(CWD, constants_1.TAYLORED_DIR_NAME), patchPath); console.log(`\nINFO: ==> ${mode} patch: ${patchFileNameForApply}`); try { await (0, apply_logic_1.handleApplyOperation)(patchFileNameForApply, isVerify, isReverse, mode, CWD); console.log(`INFO: <== Successfully processed: ${patchFileNameForApply}`); } catch (error) { console.error(`CRITICAL ERROR: Failed to process patch ${patchFileNameForApply} in group ${userInputFileName}. Halting group operation.`); process.exit(1); } } console.log(`\nINFO: Finished processing patch group: ${userInputFileName}`); } else { const resolvedTayloredFileName = (0, utils_1.resolveTayloredFileName)(userInputFileName); await (0, apply_logic_1.handleApplyOperation)(resolvedTayloredFileName, isVerify, isReverse, mode, CWD); } } else { (0, utils_1.printUsageAndExit)(`CRITICAL ERROR: Unknown option or command '${mode}'.`, true); } } } catch (error) { if (!error.message.includes('CRITICAL ERROR')) { console.error(`An unexpected error occurred: ${error.message}`); } process.exit(1); } } main().catch((err) => { const errorMessage = err && err.message ? err.message : 'Unknown error in main().catch'; if (!errorMessage.includes('CRITICAL ERROR')) { console.error(`Error in main().catch: ${errorMessage}`); } process.exit(1); });