UNPKG

blast-shield

Version:

Technical debt protection tool for any codebase

6 lines (5 loc) 4.93 kB
#!/usr/bin/env node import {logger}from'@blast-shield/logger';import {Command}from'commander';import*as s from'fs';import s__default from'fs';import {defaultConfig,applyProfile,debtChecker,profiles}from'@blast-shield/core';import*as h from'path';import*as d from'readline';function b(e){let o={...defaultConfig},r=false;try{if(s__default.existsSync(e)){console.log(`Loading config from ${e}`);let i=JSON.parse(s__default.readFileSync(e,"utf8"));r=i.weights!==void 0,o={...defaultConfig,...i};}else console.log(`No config file found at ${e}, using defaults`);return {config:o,weightsExplicitlyDefined:r}}catch(i){throw i instanceof Error?new Error(`Failed to load config from ${e}: ${i.message}`):new Error(`Failed to load config from ${e}: Unknown error`)}}var g=["defensive","balanced","aggressive","extreme","maintenance","custom"];function w(e,o,r){if(r){e.profile="custom";return}if(o){S(e,o);return}if(e.profile){E(e);return}applyProfile(e,"balanced");}function S(e,o){let r=o.toLowerCase();g.includes(r)?applyProfile(e,r):(console.warn(`\u26A0\uFE0F Warning: Unknown profile "${r}". Falling back to "balanced" profile.`),applyProfile(e,"balanced"));}function E(e){let o=e.profile.toLowerCase();g.includes(o)?applyProfile(e,o):(console.warn(`\u26A0\uFE0F Warning: Unknown profile "${o}" in config file. Falling back to "balanced" profile.`),applyProfile(e,"balanced"));}function C(e){e.option("-c, --config <path>","Path to config JSON","blast-shield.config.json").option("-s, --src <glob>","Source glob pattern (excludes node_modules, dist, build)").option("-r, --generate-report","Generate detailed technical debt report").option("-p, --profile <profile>","Debt profile (defensive, balanced, aggressive, extreme)").action(async o=>{try{let{config:r,weightsExplicitlyDefined:i}=b(o.config);$(r,o),w(r,o.profile,i),await k(r);}catch(r){O(r);}});}function $(e,o){o.src&&(e.src=o.src),o.generateReport!==void 0&&(e.generateReport=o.generateReport);}async function k(e){try{await debtChecker(e);}catch(o){o instanceof Error?logger.error(`Debt checker failed: ${o.message}`):logger.error("Debt checker failed with an unknown error"),process.exit(1);}}function O(e){e instanceof Error?logger.error(`Error: ${e.message}`):logger.error("An unknown error occurred"),process.exit(1);}function v(e){e.command("init").description("Initialize a new blast-shield configuration file").option("-o, --output <path>","Output path for the config file","blast-shield.config.json").action(async o=>{try{await I(o.output);}catch(r){N(r);}});}async function I(e){if(s.existsSync(e)&&(logger.warn(`Configuration file '${e}' already exists.`),!await F("Do you want to overwrite it?"))){logger.info("Initialization cancelled.");return}let o=await T();logger.info("Select a debt profile:"),logger.info(` defensive - ${profiles.defensive.description}`),logger.info(` balanced - ${profiles.balanced.description} (recommended)`),logger.info(` aggressive - ${profiles.aggressive.description}`),logger.info(` extreme - ${profiles.extreme.description}`);let r=await L(),i=r,t=profiles[i],D={src:o,profile:i,generateReport:i==="defensive"||i==="balanced",maxDebtScore:t.maxDebtScore??100,healthTarget:t.healthTarget??80,weights:{...t.weights},ignorePatterns:["dist/**","build/**","coverage/**","node_modules/**",".git/**","tmp/**","*.test.*","*.spec.*"],respectGitignore:true},m=h.dirname(e);m!=="."&&!s.existsSync(m)&&s.mkdirSync(m,{recursive:true}),s.writeFileSync(e,JSON.stringify(D,null,2)),logger.success(`Configuration file created at '${e}' with '${r}' profile.`);}async function F(e){let o=d.createInterface({input:process.stdin,output:process.stdout});return new Promise(r=>{o.question(`${e} (y/n): `,i=>{o.close(),r(i.toLowerCase()==="y"||i.toLowerCase()==="yes");});})}async function L(){let e=d.createInterface({input:process.stdin,output:process.stdout}),o=Object.keys(profiles).filter(r=>r!=="custom"&&r!=="maintenance");return new Promise(r=>{e.question(`Enter profile (${o.join("/")}) [balanced]: `,i=>{e.close();let t=i.trim().toLowerCase();!t||!o.includes(t)?r("balanced"):r(t);});})}async function T(){let e=d.createInterface({input:process.stdin,output:process.stdout});return new Promise(o=>{e.question("Enter the source file glob pattern for your project (e.g. src/**/*.{js,ts}): ",r=>{e.close(),r.trim()?o(r.trim()):(logger.warn("No src pattern provided. You must specify this in your config later."),o(""));});})}function N(e){e instanceof Error?logger.error(`Error: ${e.message}`):logger.error("An unknown error occurred"),process.exit(1);}async function x(){let e=new Command;e.name("blast-shield").description("CLI to protect your codebase from technical debt").version("0.0.27"),C(e),v(e),await e.parseAsync();}x().catch(e=>{logger.error("Unexpected error","INFO",e instanceof Error?e.message:String(e)),process.exit(1);}); // Blast Shield v0.0.27 // Technical Debt Protection Tool // Copyright © 2025 | Made with ❤️