@regele/devtools
Version:
A collection of developer utilities for code processing and text analysis
3 lines (2 loc) • 37.6 kB
JavaScript
;var e=require("commander"),n=require("chalk"),t=require("ora"),i=require("@babel/parser"),s=require("fs"),o=require("@babel/types"),r=require("@babel/traverse"),a=require("path");function l(e){var n=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var i=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(n,t,i.get?i:{enumerable:!0,get:function(){return e[t]}})}})),n.default=e,Object.freeze(n)}var c,u,d,p,h=l(i),g=l(o);class f{constructor(e=!1,n=!1){this.silent=e,this.verboseMode=n,this.spinner=null}log(e){this.silent||console.log(e)}verbose(e){!this.silent&&this.verboseMode&&console.log(n.gray(`[verbose] ${e}`))}info(e){this.silent||console.log(n.blue("ℹ ")+e)}success(e){this.silent||console.log(n.green("✓ ")+e)}warn(e){this.silent||console.log(n.yellow("⚠ ")+e)}error(e){this.silent||console.log(n.red("✗ ")+e)}startSpinner(e){this.silent||(this.spinner=t({text:e,color:"cyan",spinner:"dots"}).start())}stopSpinnerSuccess(e){!this.silent&&this.spinner&&this.spinner.isSpinning&&(this.spinner.succeed(e),this.spinner=null)}stopSpinnerError(e){!this.silent&&this.spinner&&this.spinner.isSpinning&&(this.spinner.fail(e),this.spinner=null)}logResults(e,t){if(this.silent)return;const i=e.filter((e=>e.success)).length,s=e.length-i;this.log("\n"+n.bold("Results:")),this.log(`${n.green(`${i} files`)} processed successfully`),s>0&&(this.log(`${n.red(`${s} files`)} failed to process`),this.log("\n"+n.bold("Errors:")),e.filter((e=>!e.success)).forEach((e=>{this.log(` ${n.red("✗")} ${e.path}: ${e.error}`)})));const o=e.filter((e=>e.success));if(o.length>0){const e=o.reduce(((e,n)=>e+(n.originalSize||0)),0),t=o.reduce(((e,n)=>e+(n.newSize||0)),0),i=e-t,s=e>0?i/e*100:0;this.log("\n"+n.bold("Size Changes:")),this.log(` Original: ${m(e)}`),this.log(` New: ${m(t)}`),i>0?this.log(` Reduced by: ${n.green(m(i))} (${s.toFixed(2)}%)`):i<0?this.log(` Increased by: ${n.yellow(m(Math.abs(i)))} (${Math.abs(s).toFixed(2)}%)`):this.log(" No size change")}this.log("\n"+n.bold.green(`${t} completed.`))}}function m(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(2)} KB`:`${(e/1048576).toFixed(2)} MB`}!function(e){e.JavaScript="javascript",e.TypeScript="typescript",e.JSX="jsx",e.TSX="tsx",e.HTML="html",e.CSS="css",e.SCSS="scss",e.LESS="less",e.JSON="json",e.XML="xml",e.SVG="svg",e.Python="python",e.Ruby="ruby",e.PHP="php",e.Java="java",e.CSharp="csharp",e.CPP="cpp",e.C="c",e.Go="go",e.Swift="swift",e.Kotlin="kotlin",e.Rust="rust",e.Shell="shell",e.PowerShell="powershell",e.Batch="batch",e.SQL="sql",e.Markdown="markdown",e.YAML="yaml",e.Text="text",e.Unknown="unknown"}(c||(c={})),function(e){e.JavaScript="js",e.HTML="html",e.CSS="css",e.JSON="json",e.XML="xml",e.Python="python",e.Ruby="ruby",e.PHP="php",e.CStyle="cstyle",e.Shell="shell",e.SQL="sql",e.Markdown="markdown",e.YAML="yaml",e.Text="text",e.Unknown="unknown"}(u||(u={}));class y{applyWithoutAST(e,n){return[]}getLineAndColumn(e,n){const t=e.slice(0,n).split("\n");return{line:t.length,column:t[t.length-1].length+1}}getCodeSnippet(e,n,t){return e.slice(n,t)}createFinding(e){return{id:this.id,message:e.message,severity:e.severity||this.defaultSeverity,category:this.category,filePath:e.filePath,line:e.line,column:e.column,endLine:e.endLine,endColumn:e.endColumn,code:e.code,suggestion:e.suggestion,explanation:e.explanation||this.description,functionName:e.functionName}}generateSuggestion(e,...n){return"// Consider refactoring this code to address the issue"}getFunctionName(e){let n=e;for(;n;){if(n.isFunctionDeclaration()||n.isFunctionExpression()||n.isArrowFunctionExpression()){if(n.node.id&&n.node.id.name)return n.node.id.name;const e=n.parentPath;return e&&e.isVariableDeclarator()&&e.node.id&&g.isIdentifier(e.node.id)?e.node.id.name:"anonymous function"}n=n.parentPath}}}!function(e){e.Info="info",e.Warning="warning",e.Error="error",e.Critical="critical"}(d||(d={})),function(e){e.Performance="performance",e.Security="security",e.Maintainability="maintainability",e.Bugs="bugs",e.Style="style"}(p||(p={}));class v extends y{constructor(){super(...arguments),this.id="perf-nested-loops",this.name="Nested Loops",this.description="Detects nested loops that could be optimized for better performance",this.category=p.Performance,this.defaultSeverity=d.Warning,this.requiresAST=!0}apply(e,n,t){const i=[];return r(n,{ForStatement:n=>{var s,o;const r=n.parentPath;if(r.isForStatement()||r.isWhileStatement()||r.isDoWhileStatement()||r.isForInStatement()||r.isForOfStatement()){const a=r.node,l=n.node,c=null===(s=a.loc)||void 0===s?void 0:s.start,u=null===(o=l.loc)||void 0===o?void 0:o.end;if(c&&u){const s=e.slice(a.start||0,l.end||e.length);i.push(this.createFinding({message:"Nested loops detected - consider optimizing",filePath:t,line:c.line,column:c.column+1,endLine:u.line,endColumn:u.column+1,code:s,suggestion:this.generateSuggestion(s),explanation:"Nested loops have O(n²) time complexity. Consider using map/reduce/filter or restructuring the data to avoid nested iterations.",functionName:this.getFunctionName(n)}))}}}}),i}generateSuggestion(e){return"// Consider using Array methods instead of nested loops\nconst result = outerArray.flatMap(outerItem =>\n innerArray.map(innerItem => {\n // Your logic here\n return { outerItem, innerItem };\n })\n);"}}class S extends y{constructor(){super(...arguments),this.id="security-unsafe-eval",this.name="Unsafe Eval Usage",this.description="Detects potentially dangerous use of eval() and similar functions",this.category=p.Security,this.defaultSeverity=d.Critical,this.requiresAST=!0,this.dangerousFunctions=["eval","Function","setTimeout","setInterval","setImmediate","execScript","new Function"]}apply(e,n,t){const i=[];return r(n,{CallExpression:n=>{var s,o,r,a,l,c;const u=n.node.callee;if(g.isIdentifier(u)&&"eval"===u.name){const r=null===(s=n.node.loc)||void 0===s?void 0:s.start,a=null===(o=n.node.loc)||void 0===o?void 0:o.end;if(r&&a){const s=e.slice(n.node.start||0,n.node.end||e.length);i.push({id:this.id,message:"Unsafe use of eval() detected",severity:d.Critical,category:this.category,filePath:t,line:r.line,column:r.column+1,endLine:a.line,endColumn:a.column+1,code:s,suggestion:this.generateSuggestion(s),explanation:"Using eval() can introduce security vulnerabilities through code injection. It also makes your code slower and harder to debug.",functionName:this.getFunctionName(n)})}}if(g.isIdentifier(u)){const s=u.name;if(this.dangerousFunctions.includes(s)&&"eval"!==s){const o=n.node.arguments[0];if(g.isStringLiteral(o)&&o.value.includes("+")||g.isTemplateLiteral(o)||g.isBinaryExpression(o)){const o=null===(r=n.node.loc)||void 0===r?void 0:r.start,l=null===(a=n.node.loc)||void 0===a?void 0:a.end;if(o&&l){const r=e.slice(n.node.start||0,n.node.end||e.length);i.push(this.createFinding({message:`Potentially unsafe use of ${s}() with dynamic string`,severity:d.Error,filePath:t,line:o.line,column:o.column+1,endLine:l.line,endColumn:l.column+1,code:r,suggestion:this.generateAlternativeSuggestion(s,r),explanation:`Using ${s}() with dynamic strings can introduce security vulnerabilities through code injection.`,functionName:this.getFunctionName(n)}))}}}}if(g.isNewExpression(n.node)){const s=n.node;if(g.isIdentifier(s.callee)&&"Function"===s.callee.name){const o=null===(l=s.loc)||void 0===l?void 0:l.start,r=null===(c=s.loc)||void 0===c?void 0:c.end;if(o&&r){const a=e.slice(s.start||0,s.end||e.length);i.push({id:this.id,message:"Unsafe use of new Function() detected",severity:d.Critical,category:this.category,filePath:t,line:o.line,column:o.column+1,endLine:r.line,endColumn:r.column+1,code:a,suggestion:this.generateSuggestion(a),explanation:"Using new Function() can introduce security vulnerabilities through code injection. It also makes your code slower and harder to debug.",functionName:this.getFunctionName(n)})}}}}}),i}generateSuggestion(e){return"// Instead of using eval, consider:\n// 1. Using JSON.parse() for JSON data\n// 2. Using a predefined set of functions\n// 3. Restructuring your code to avoid dynamic execution\n\n// Example:\nconst data = JSON.parse(jsonString);\nconst result = predefinedFunctions[functionName](data);"}generateAlternativeSuggestion(e,n){return"setTimeout"===e||"setInterval"===e?`// Instead of passing a string to ${e}, use a function:\n${e}(() => {\n // Your code here\n}, delay);`:`// Avoid using ${e} with dynamic strings.\n// Consider using a safer alternative or restructuring your code.`}}class C extends y{constructor(){super(...arguments),this.id="maint-complex-function",this.name="Complex Function",this.description="Detects functions with high cyclomatic complexity",this.category=p.Maintainability,this.defaultSeverity=d.Warning,this.requiresAST=!0,this.WARNING_THRESHOLD=10,this.ERROR_THRESHOLD=20,this.CRITICAL_THRESHOLD=30}apply(e,n,t){const i=[];return r(n,{"FunctionDeclaration|FunctionExpression|ArrowFunctionExpression":n=>{var s,o;const r=n.node,a=this.getFunctionName(n),l=this.calculateComplexity(n);if(l>=this.WARNING_THRESHOLD){const n=null===(s=r.loc)||void 0===s?void 0:s.start,c=null===(o=r.loc)||void 0===o?void 0:o.end;if(n&&c){const s=e.slice(r.start||0,r.end||e.length);let o=d.Warning;l>=this.CRITICAL_THRESHOLD?o=d.Critical:l>=this.ERROR_THRESHOLD&&(o=d.Error),i.push(this.createFinding({message:`Function has high cyclomatic complexity (${l})`,severity:o,filePath:t,line:n.line,column:n.column+1,endLine:c.line,endColumn:c.column+1,code:s,suggestion:this.generateSuggestion(s,a||"function"),explanation:`Functions with high cyclomatic complexity (${l}) are difficult to understand, test, and maintain. Consider refactoring into smaller, more focused functions.`,functionName:a}))}}}}),i}calculateComplexity(e){let n=1;return r(e.node,{IfStatement:()=>{n++},ConditionalExpression:()=>{n++},SwitchCase:e=>{e.node.test&&n++},ForStatement:()=>{n++},ForInStatement:()=>{n++},ForOfStatement:()=>{n++},WhileStatement:()=>{n++},DoWhileStatement:()=>{n++},LogicalExpression:e=>{"&&"!==e.node.operator&&"||"!==e.node.operator||n++},CatchClause:()=>{n++},"FunctionDeclaration|FunctionExpression|ArrowFunctionExpression":e=>{e.skip()}},e.scope),n}generateSuggestion(e,n){return`// Consider refactoring ${n} into smaller functions:\nfunction ${n}() {\n // Main logic with reduced complexity\n this.helperFunction1();\n this.helperFunction2();\n}\n\nfunction helperFunction1() {\n // Extract some of the logic here\n}\n\nfunction helperFunction2() {\n // Extract more logic here\n}`}getFunctionName(e){const n=e.node;if(g.isFunctionDeclaration(n)&&n.id)return n.id.name;if(g.isFunctionExpression(n)||g.isArrowFunctionExpression(n)){const t=e.parent;if(g.isVariableDeclarator(t)&&g.isIdentifier(t.id))return t.id.name;if(g.isObjectProperty(t)&&g.isIdentifier(t.key))return t.key.name;if(g.isClassMethod(t)&&g.isIdentifier(t.key))return t.key.name;if(g.isFunctionExpression(n)&&n.id)return n.id.name}}}class b extends y{constructor(){super(...arguments),this.id="maint-deep-nesting",this.name="Deep Nesting",this.description="Detects deeply nested code blocks that reduce readability",this.category=p.Maintainability,this.defaultSeverity=d.Warning,this.requiresAST=!0}apply(e,n,t){return[]}generateSuggestion(e,n){return"// Consider refactoring deeply nested code"}}class x extends y{constructor(){super(...arguments),this.id="bugs-unhandled-promise",this.name="Unhandled Promise",this.description="Detects promises without proper error handling",this.category=p.Bugs,this.defaultSeverity=d.Error,this.requiresAST=!0}apply(e,n,t){const i=[];return r(n,{CallExpression:n=>{var s,o;if(this.isPromiseReturningCall(n.node)&&!this.isPromiseHandled(n)){const r=null===(s=n.node.loc)||void 0===s?void 0:s.start,a=null===(o=n.node.loc)||void 0===o?void 0:o.end;if(r&&a){const s=e.slice(n.node.start||0,n.node.end||e.length);i.push(this.createFinding({message:"Unhandled promise rejection detected",filePath:t,line:r.line,column:r.column+1,endLine:a.line,endColumn:a.column+1,code:s,suggestion:this.generateSuggestion(s),explanation:"Unhandled promise rejections can lead to silent failures and make debugging difficult. Always handle potential errors in promises with .catch() or try/catch in async functions.",functionName:this.getFunctionName(n)}))}}}}),i}isPromiseReturningCall(e){if(g.isMemberExpression(e.callee)){const n=e.callee.property;if(g.isIdentifier(n)){const e=n.name;if(["fetch","then","catch","finally","request","get","post","put","delete","axios"].includes(e))return!0}}if(g.isIdentifier(e.callee)){const n=e.callee.name;if(["fetch","Promise","axios","request"].includes(n))return!0;if(n.startsWith("get")||n.startsWith("fetch")||n.startsWith("load")||n.startsWith("request")||n.includes("Async"))return!0}return!1}isPromiseHandled(e){const n=e.parentPath;if(n&&n.isMemberExpression()&&n.parentPath&&n.parentPath.isCallExpression()){const e=n.node.property;if(g.isIdentifier(e)&&("then"===e.name||"catch"===e.name))return!0}let t=e;for(;t;){if(t.isAwaitExpression()){let e=t;for(;e;){if(e.isTryStatement())return!0;e=e.parentPath}return!1}if(t.isVariableDeclarator()||t.isAssignmentExpression())return!1;t=t.parentPath}return!1}generateSuggestion(e){return`// Add error handling to your promise\n${e}\n .then(result => {\n // Handle successful result\n })\n .catch(error => {\n // Handle error properly\n console.error('Operation failed:', error);\n });\n\n// Or using async/await with try/catch:\ntry {\n const result = await ${e};\n // Handle successful result\n} catch (error) {\n // Handle error properly\n console.error('Operation failed:', error);\n}`}getFunctionName(e){let n=e;for(;n;){if(n.isFunctionDeclaration()||n.isFunctionExpression()||n.isArrowFunctionExpression()){if(n.node.id&&n.node.id.name)return n.node.id.name;const e=n.parentPath;return e&&e.isVariableDeclarator()&&e.node.id&&g.isIdentifier(e.node.id)?e.node.id.name:"anonymous function"}n=n.parentPath}}}class w extends y{constructor(){super(...arguments),this.id="bugs-inconsistent-return",this.name="Inconsistent Return",this.description="Detects functions with inconsistent return types or missing returns",this.category=p.Bugs,this.defaultSeverity=d.Warning,this.requiresAST=!0}apply(e,n,t){return[]}generateSuggestion(e,n){return"// Consider making return types consistent"}}class E extends y{constructor(){super(...arguments),this.id="style-naming-convention",this.name="Naming Convention",this.description="Enforces consistent naming conventions for variables, functions, and classes",this.category=p.Style,this.defaultSeverity=d.Info,this.requiresAST=!0,this.CONSTANT_PATTERN=/^[A-Z][A-Z0-9_]*$/,this.CAMEL_CASE_PATTERN=/^[a-z][a-zA-Z0-9]*$/,this.PASCAL_CASE_PATTERN=/^[A-Z][a-zA-Z0-9]*$/,this.PRIVATE_MEMBER_PATTERN=/^_[a-z][a-zA-Z0-9]*$/}apply(e,n,t){const i=[];return r(n,{VariableDeclarator:n=>{const s=n.node;if(g.isIdentifier(s.id)){const o=s.id.name;if(n.parentPath.isVariableDeclaration()){if("const"===n.parentPath.node.kind){const n=s.init;n&&(g.isStringLiteral(n)||g.isNumericLiteral(n)||g.isBooleanLiteral(n)||g.isNullLiteral(n))?this.CONSTANT_PATTERN.test(o)||o.toUpperCase()===o||this.addNamingFinding(i,s,e,t,o,"Constants should use UPPER_CASE",this.toUpperSnakeCase(o)):!n||g.isObjectExpression(n)||g.isArrayExpression(n)||g.isFunctionExpression(n)||g.isArrowFunctionExpression(n)||this.CAMEL_CASE_PATTERN.test(o)||this.addNamingFinding(i,s,e,t,o,"Variables should use camelCase",this.toCamelCase(o))}else this.CAMEL_CASE_PATTERN.test(o)||this.addNamingFinding(i,s,e,t,o,"Variables should use camelCase",this.toCamelCase(o))}}},FunctionDeclaration:n=>{const s=n.node;if(s.id){const n=s.id.name;this.CAMEL_CASE_PATTERN.test(n)||this.addNamingFinding(i,s,e,t,n,"Functions should use camelCase",this.toCamelCase(n))}},ClassDeclaration:n=>{const s=n.node;if(s.id){const n=s.id.name;this.PASCAL_CASE_PATTERN.test(n)||this.addNamingFinding(i,s,e,t,n,"Classes should use PascalCase",this.toPascalCase(n))}},ClassProperty:n=>{const s=n.node;if(g.isIdentifier(s.key)){const n=s.key.name;"private"!==s.accessibility||this.PRIVATE_MEMBER_PATTERN.test(n)?"private"===s.accessibility||this.CAMEL_CASE_PATTERN.test(n)||this.addNamingFinding(i,s,e,t,n,"Class members should use camelCase",this.toCamelCase(n)):this.addNamingFinding(i,s,e,t,n,"Private class members should start with underscore and use camelCase",`_${this.toCamelCase(n.startsWith("_")?n.slice(1):n)}`)}}}),i}addNamingFinding(e,n,t,i,s,o,r){var a,l;const c=null===(a=n.loc)||void 0===a?void 0:a.start,u=null===(l=n.loc)||void 0===l?void 0:l.end;if(c&&u){const a=t.slice(n.start||0,n.end||t.length);e.push(this.createFinding({message:`${o}: '${s}'`,filePath:i,line:c.line,column:c.column+1,endLine:u.line,endColumn:u.column+1,code:a,suggestion:a.replace(s,r),explanation:`Consistent naming conventions improve code readability and maintainability. Consider renaming '${s}' to '${r}'.`}))}}toCamelCase(e){return e.replace(/[^\w\s]/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").split(/[\s_-]+/).map(((e,n)=>0===n?e.toLowerCase():e.charAt(0).toUpperCase()+e.slice(1).toLowerCase())).join("")}toPascalCase(e){return e.replace(/[^\w\s]/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").split(/[\s_-]+/).map((e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase())).join("")}toUpperSnakeCase(e){return e.replace(/[^\w\s]/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").split(/[\s_-]+/).map((e=>e.toUpperCase())).join("_")}}class ${constructor(e={}){this.options={minSeverity:d.Info,categories:Object.values(p),...e},this.rules=[new v,new S,new C,new b,new x,new w,new E]}async analyzeFile(e){try{const n=s.readFileSync(e,"utf8"),t=function(e,n){var t;if(n){const e=(null===(t=n.split(".").pop())||void 0===t?void 0:t.toLowerCase())||"";if(["js","cjs","mjs"].includes(e))return c.JavaScript;if(["jsx"].includes(e))return c.JSX;if(["ts"].includes(e))return c.TypeScript;if(["tsx"].includes(e))return c.TSX;if(["json"].includes(e))return c.JSON;if(["yaml","yml"].includes(e))return c.YAML;if(["css"].includes(e))return c.CSS;if(["scss","sass"].includes(e))return c.SCSS;if(["less"].includes(e))return c.LESS;if(["html","htm","xhtml","jsp","asp","aspx","cshtml","razor","ejs","hbs","handlebars","pug","jade"].includes(e))return c.HTML;if(["xml","xsd","xsl","xslt"].includes(e))return c.XML;if(["svg"].includes(e))return c.SVG;if(["py","pyw"].includes(e))return c.Python;if(["rb"].includes(e))return c.Ruby;if(["php","php5","phtml","inc"].includes(e))return c.PHP;if(["java"].includes(e))return c.Java;if(["cs"].includes(e))return c.CSharp;if(["c","h"].includes(e))return c.C;if(["cpp","hpp","cc","cxx","c++"].includes(e))return c.CPP;if(["go"].includes(e))return c.Go;if(["swift"].includes(e))return c.Swift;if(["kt"].includes(e))return c.Kotlin;if(["rs"].includes(e))return c.Rust;if(["sh","bash","zsh","fish","ksh"].includes(e))return c.Shell;if(["ps1"].includes(e))return c.PowerShell;if(["bat","cmd"].includes(e))return c.Batch;if(["sql","mysql","pgsql","sqlite","plsql"].includes(e))return c.SQL;if(["md","markdown"].includes(e))return c.Markdown;if(["txt"].includes(e))return c.Text}const i=e.slice(0,1e3).trim();return i.includes("import React")||i.includes('from "react"')||i.includes("from 'react'")||i.match(/<\w+(\s+\w+=".*?")*\s*\/?>/)||i.includes("</")?i.includes(": ")||i.includes("interface ")||i.includes("type ")||i.match(/:\s*[A-Za-z]+[<>]/)||i.includes("as ")?i.includes("JSX")||i.includes("<>")?c.TSX:c.TypeScript:i.includes("JSX")||i.includes("<>")?c.JSX:c.JavaScript:i.startsWith("{")&&i.includes('"')||i.startsWith("[")&&i.includes('"')?c.JSON:i.match(/^[a-zA-Z0-9_-]+:\s*[^\s]/)||i.match(/^\s+- [a-zA-Z0-9_-]+:/)?c.YAML:i.includes("{")&&i.includes("}")&&i.includes(":")&&(i.includes(";")||i.includes("px")||i.includes("em"))?c.CSS:i.match(/<html|<!DOCTYPE|<head|<body|<div/i)?c.HTML:i.match(/<\?xml|<[a-zA-Z0-9_-]+>[\s\S]*?<\/[a-zA-Z0-9_-]+>/)?c.XML:i.includes("<svg")||i.includes("xmlns:svg=")?c.SVG:i.match(/^(import|from|def|class)\s/m)||i.includes('if __name__ == "__main__"')||i.match(/^\s*#.*$/m)?c.Python:i.match(/^(require|class|def|module)\s/m)||i.includes("do |")||i.includes("end")?c.Ruby:i.includes("<?php")||i.match(/^\s*<\?/)?c.PHP:i.match(/public\s+(class|interface|enum)/)||i.match(/import\s+java\./)||i.match(/package\s+[a-z0-9_.]+;/)?c.Java:i.match(/using\s+System;/)||i.match(/namespace\s+[A-Za-z0-9_.]+/)||i.includes("public class ")?c.CSharp:i.match(/#include\s+[<"].*[>"]/)?i.includes("std::")||i.includes("namespace ")?c.CPP:c.C:i.match(/package\s+[a-z0-9_]+/)||i.match(/import\s+\(/)||i.match(/func\s+[A-Za-z0-9_]+\(/)?c.Go:i.match(/import\s+Foundation/)||i.match(/class\s+[A-Za-z0-9_]+\s*:/)||i.match(/func\s+[a-zA-Z0-9_]+\(/)?c.Swift:i.match(/fun\s+[a-zA-Z0-9_]+\(/)||i.match(/val\s+[a-zA-Z0-9_]+:/)||i.match(/var\s+[a-zA-Z0-9_]+:/)?c.Kotlin:i.match(/^#!/)||i.match(/^\s*#.*$/m)||i.match(/echo\s+["']/)||i.match(/export\s+[A-Z_]+=/)?c.Shell:i.includes("function ")&&i.includes("param(")?c.PowerShell:i.match(/^@echo off/i)||i.match(/^REM\s/i)||i.match(/^(set|echo|if|goto)\s/im)?c.Batch:i.match(/SELECT\s+.*\s+FROM/i)||i.match(/CREATE\s+TABLE/i)||i.match(/INSERT\s+INTO/i)||i.match(/UPDATE\s+.*\s+SET/i)?c.SQL:i.match(/^#\s+/)||i.match(/\n#{1,6}\s+/)||i.match(/\[.*\]\(.*\)/)||i.match(/\*\*.*\*\*/)?c.Markdown:i.split("\n").length>1||i.length>0?c.Text:c.Unknown}(n,e);if(![c.JavaScript,c.TypeScript,c.JSX,c.TSX].includes(t))return{filePath:e,fileType:t,findings:[],success:!0};const i=this.parseCode(n,t),o=[];if(i)for(const t of this.rules){if(this.options.categories&&!this.options.categories.includes(t.category))continue;const s=t.apply(n,i,e).filter((e=>this.compareSeverity(e.severity,this.options.minSeverity||d.Info)>=0));o.push(...s)}for(const t of this.rules)if(!t.requiresAST&&(!this.options.categories||this.options.categories.includes(t.category))){const i=t.applyWithoutAST(n,e).filter((e=>this.compareSeverity(e.severity,this.options.minSeverity||d.Info)>=0));o.push(...i)}return{filePath:e,fileType:t,findings:o,success:!0}}catch(n){return{filePath:e,fileType:c.Unknown,findings:[],success:!1,error:n.message}}}async analyzeFiles(e){const n=await this.findFiles(e),t=[];for(const e of n){const n=await this.analyzeFile(e);t.push(n)}return t}async findFiles(e){const n=require("fast-glob"),t=require("ignore"),i=["**/node_modules/**","**/dist/**","**/build/**","**/.git/**","**/package-lock.json","**/yarn.lock","**/*.min.js","**/*.min.css","**/*.bundle.js"],s=this.options.ignore?[...i,...this.options.ignore]:i;t().add(s);const o=Array.isArray(e)?e.map((e=>e.replace(/\\/g,"/"))):e.replace(/\\/g,"/");return await n(o,{ignore:s,onlyFiles:!0,absolute:!0,followSymbolicLinks:!1})}parseCode(e,n){try{const t=[];return[c.TypeScript,c.TSX].includes(n)&&t.push("typescript"),[c.JSX,c.TSX].includes(n)&&t.push("jsx"),t.push("classProperties"),t.push("decorators-legacy"),t.push("objectRestSpread"),t.push("optionalChaining"),t.push("nullishCoalescingOperator"),h.parse(e,{sourceType:"module",plugins:t})}catch(e){return null}}compareSeverity(e,n){const t=[d.Info,d.Warning,d.Error,d.Critical];return t.indexOf(e)-t.indexOf(n)}}function A(){}function P(e,n,t,i,s){for(var o,r=[];n;)r.push(n),o=n.previousComponent,delete n.previousComponent,n=o;r.reverse();for(var a=0,l=r.length,c=0,u=0;a<l;a++){var d=r[a];if(d.removed){if(d.value=e.join(i.slice(u,u+d.count)),u+=d.count,a&&r[a-1].added){var p=r[a-1];r[a-1]=r[a],r[a]=p}}else{if(!d.added&&s){var h=t.slice(c,c+d.count);h=h.map((function(e,n){var t=i[u+n];return t.length>e.length?t:e})),d.value=e.join(h)}else d.value=e.join(t.slice(c,c+d.count));c+=d.count,d.added||(u+=d.count)}}var g=r[l-1];return l>1&&"string"==typeof g.value&&(g.added||g.removed)&&e.equals("",g.value)&&(r[l-2].value+=g.value,r.pop()),r}A.prototype={diff:function(e,n){var t,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},s=i.callback;"function"==typeof i&&(s=i,i={}),this.options=i;var o=this;function r(e){return s?(setTimeout((function(){s(void 0,e)}),0),!0):e}e=this.castInput(e),n=this.castInput(n),e=this.removeEmpty(this.tokenize(e));var a=(n=this.removeEmpty(this.tokenize(n))).length,l=e.length,c=1,u=a+l;i.maxEditLength&&(u=Math.min(u,i.maxEditLength));var d=null!==(t=i.timeout)&&void 0!==t?t:1/0,p=Date.now()+d,h=[{oldPos:-1,lastComponent:void 0}],g=this.extractCommon(h[0],n,e,0);if(h[0].oldPos+1>=l&&g+1>=a)return r([{value:this.join(n),count:n.length}]);var f=-1/0,m=1/0;function y(){for(var t=Math.max(f,-c);t<=Math.min(m,c);t+=2){var i=void 0,s=h[t-1],u=h[t+1];s&&(h[t-1]=void 0);var d=!1;if(u){var p=u.oldPos-t;d=u&&0<=p&&p<a}var y=s&&s.oldPos+1<l;if(d||y){if(i=!y||d&&s.oldPos+1<u.oldPos?o.addToPath(u,!0,void 0,0):o.addToPath(s,void 0,!0,1),g=o.extractCommon(i,n,e,t),i.oldPos+1>=l&&g+1>=a)return r(P(o,i.lastComponent,n,e,o.useLongestToken));h[t]=i,i.oldPos+1>=l&&(m=Math.min(m,t-1)),g+1>=a&&(f=Math.max(f,t+1))}else h[t]=void 0}c++}if(s)!function e(){setTimeout((function(){if(c>u||Date.now()>p)return s();y()||e()}),0)}();else for(;c<=u&&Date.now()<=p;){var v=y();if(v)return v}},addToPath:function(e,n,t,i){var s=e.lastComponent;return s&&s.added===n&&s.removed===t?{oldPos:e.oldPos+i,lastComponent:{count:s.count+1,added:n,removed:t,previousComponent:s.previousComponent}}:{oldPos:e.oldPos+i,lastComponent:{count:1,added:n,removed:t,previousComponent:s}}},extractCommon:function(e,n,t,i){for(var s=n.length,o=t.length,r=e.oldPos,a=r-i,l=0;a+1<s&&r+1<o&&this.equals(n[a+1],t[r+1]);)a++,r++,l++;return l&&(e.lastComponent={count:l,previousComponent:e.lastComponent}),e.oldPos=r,a},equals:function(e,n){return this.options.comparator?this.options.comparator(e,n):e===n||this.options.ignoreCase&&e.toLowerCase()===n.toLowerCase()},removeEmpty:function(e){for(var n=[],t=0;t<e.length;t++)e[t]&&n.push(e[t]);return n},castInput:function(e){return e},tokenize:function(e){return e.split("")},join:function(e){return e.join("")}};var F=/^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/,T=/\S/,k=new A;k.equals=function(e,n){return this.options.ignoreCase&&(e=e.toLowerCase(),n=n.toLowerCase()),e===n||this.options.ignoreWhitespace&&!T.test(e)&&!T.test(n)},k.tokenize=function(e){for(var n=e.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/),t=0;t<n.length-1;t++)!n[t+1]&&n[t+2]&&F.test(n[t])&&F.test(n[t+2])&&(n[t]+=n[t+2],n.splice(t+1,2),t--);return n};var L=new A;function N(e){return N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},N(e)}L.tokenize=function(e){this.options.stripTrailingCr&&(e=e.replace(/\r\n/g,"\n"));var n=[],t=e.split(/(\n|\r\n)/);t[t.length-1]||t.pop();for(var i=0;i<t.length;i++){var s=t[i];i%2&&!this.options.newlineIsToken?n[n.length-1]+=s:(this.options.ignoreWhitespace&&(s=s.trim()),n.push(s))}return n},(new A).tokenize=function(e){return e.split(/(\S.+?[.!?])(?=\s+|$)/)},(new A).tokenize=function(e){return e.split(/([{}:;,]|\s+)/)};var M=Object.prototype.toString,I=new A;function R(e,n,t,i,s){var o,r;for(n=n||[],t=t||[],i&&(e=i(s,e)),o=0;o<n.length;o+=1)if(n[o]===e)return t[o];if("[object Array]"===M.call(e)){for(n.push(e),r=new Array(e.length),t.push(r),o=0;o<e.length;o+=1)r[o]=R(e[o],n,t,i,s);return n.pop(),t.pop(),r}if(e&&e.toJSON&&(e=e.toJSON()),"object"===N(e)&&null!==e){n.push(e),r={},t.push(r);var a,l=[];for(a in e)e.hasOwnProperty(a)&&l.push(a);for(l.sort(),o=0;o<l.length;o+=1)r[a=l[o]]=R(e[a],n,t,i,a);n.pop(),t.pop()}else r=e;return r}I.useLongestToken=!0,I.tokenize=L.tokenize,I.castInput=function(e){var n=this.options,t=n.undefinedReplacement,i=n.stringifyReplacer,s=void 0===i?function(e,n){return void 0===n?t:n}:i;return"string"==typeof e?e:JSON.stringify(R(e,null,null,s),s," ")},I.equals=function(e,n){return A.prototype.equals.call(I,e.replace(/,([\r\n])/g,"$1"),n.replace(/,([\r\n])/g,"$1"))};var _=new A;function z(e){return e.split(",").map((e=>e.trim()))}function j(e){return e.split(",").map((e=>e.trim().toLowerCase())).map((e=>{switch(e){case"performance":return p.Performance;case"security":return p.Security;case"maintainability":return p.Maintainability;case"bugs":return p.Bugs;case"style":return p.Style;default:throw new Error(`Invalid category: ${e}`)}}))}function O(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}_.tokenize=function(e){return e.slice()},_.join=_.removeEmpty=function(e){return e},exports.createAnalyzeCodeCommand=function(){const t=new e.Command("analyze-code");return t.description("Analyze code for potential issues, bugs, and improvements").argument("<patterns...>",'File patterns to analyze (e.g., "src/**/*.js")').option("--severity <level>","Minimum severity level to report (info, warning, error, critical)","info").option("--category <categories>","Categories to include (comma-separated: performance, security, maintainability, bugs, style)",j).option("--ignore <pattern>","Files to ignore (comma-separated)",z).option("--max-depth <depth>","Maximum depth for recursive analysis",parseInt).option("--root-dir <path>","Root directory for analysis").option("--output <path>","Write report to file (json or html)").option("--format <format>","Output format (text, json, html)","text").option("--silent","Suppress output",!1).action((async(e,t)=>{const i=new f(t.silent);try{const o=function(e){switch(e.toLowerCase()){case"info":return d.Info;case"warning":return d.Warning;case"error":return d.Error;case"critical":return d.Critical;default:throw new Error(`Invalid severity level: ${e}`)}}(t.severity),r=new $({minSeverity:o,categories:t.category,ignore:t.ignore,maxDepth:t.maxDepth,rootDir:t.rootDir,dryRun:t.dryRun});i.startSpinner("Analyzing code...");const l=await r.analyzeFiles(e),c=l.reduce(((e,n)=>e+n.findings.length),0);if(i.stopSpinnerSuccess(`Analyzed ${l.length} files, found ${c} issues`),!t.silent){const e=l.filter((e=>e.success)),o=l.filter((e=>!e.success));if(o.length>0&&(i.log("\n"+n.bold("Errors:")),o.forEach((e=>{i.error(`Failed to analyze ${e.filePath}: ${e.error}`)}))),c>0){i.log("\n"+n.bold("Findings:"));const t={};e.forEach((e=>{e.findings.length>0&&(t[e.filePath]=e.findings)})),Object.entries(t).forEach((([e,t])=>{i.log(`\n${n.underline(e)}`),t.sort(((e,n)=>e.line-n.line)),t.forEach((e=>{let t,s;switch(e.severity){case d.Critical:t=n.bgRed.white;break;case d.Error:t=n.red;break;case d.Warning:t=n.yellow;break;default:t=n.blue}switch(e.category){case p.Performance:s=n.magenta;break;case p.Security:s=n.red;break;case p.Maintainability:s=n.cyan;break;case p.Bugs:s=n.yellow;break;default:s=n.gray}if(i.log(` ${t(e.severity.toUpperCase())} ${s(`[${e.category}]`)} Line ${e.line}${e.column?`:${e.column}`:""}: ${e.message}`),i.log(""),i.log(n.gray(" │ "+e.code.replace(/\n/g,"\n │ "))),i.log(""),e.suggestion){if(i.log(n.green(" Suggestion:")),e.code&&e.suggestion){(o=e.code,r=e.suggestion,L.diff(o,r,a)).forEach((e=>{const t=e.added?n.green:e.removed?n.red:n.gray,s=e.added?"+ ":e.removed?"- ":" ";e.value.trim()&&e.value.split("\n").forEach((e=>{e.trim()&&i.log(t(` ${s}${e}`))}))}))}else i.log(n.green(" "+e.suggestion.replace(/\n/g,"\n ")));i.log("")}var o,r,a;i.log(n.gray(" "+e.explanation)),i.log("")}))}))}i.log("\n"+n.bold("Summary:"));const r={[d.Info]:0,[d.Warning]:0,[d.Error]:0,[d.Critical]:0},u={[p.Performance]:0,[p.Security]:0,[p.Maintainability]:0,[p.Bugs]:0,[p.Style]:0};e.forEach((e=>{e.findings.forEach((e=>{r[e.severity]++,u[e.category]++}))})),i.log(" Severity:"),i.log(` ${n.red("Critical")}: ${r[d.Critical]}`),i.log(` ${n.red("Error")}: ${r[d.Error]}`),i.log(` ${n.yellow("Warning")}: ${r[d.Warning]}`),i.log(` ${n.blue("Info")}: ${r[d.Info]}`),i.log(" Category:"),i.log(` ${n.magenta("Performance")}: ${u[p.Performance]}`),i.log(` ${n.red("Security")}: ${u[p.Security]}`),i.log(` ${n.cyan("Maintainability")}: ${u[p.Maintainability]}`),i.log(` ${n.yellow("Bugs")}: ${u[p.Bugs]}`),i.log(` ${n.gray("Style")}: ${u[p.Style]}`);const h=function(e,n,t){let i=100;i-=10*e[d.Critical],i-=5*e[d.Error],i-=2*e[d.Warning],i-=.5*e[d.Info];const s=2*Math.log10(Math.max(1,t));return i=Math.min(100,i+s),Math.max(0,Math.min(100,i))}(r,0,l.length);if(i.log(` Quality Score: ${function(e){let t,i;e>=90?(t="A+",i=n.green):e>=85?(t="A",i=n.green):e>=80?(t="A-",i=n.green):e>=75?(t="B+",i=n.greenBright):e>=70?(t="B",i=n.greenBright):e>=65?(t="B-",i=n.greenBright):e>=60?(t="C+",i=n.yellow):e>=55?(t="C",i=n.yellow):e>=50?(t="C-",i=n.yellow):e>=45?(t="D+",i=n.red):e>=40?(t="D",i=n.red):(t="F",i=n.redBright);return i(`${t} (${Math.round(e)})`)}(h)}`),t.output){"html"===(".html"===a.extname(t.output).toLowerCase()?"html":"json")?(!function(e,n,t){const i=`<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>Code Analysis Report</title>\n <style>\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; line-height: 1.6; color: #333; max-width: 1200px; margin: 0 auto; padding: 20px; }\n h1, h2, h3 { margin-top: 24px; }\n .summary { display: flex; flex-wrap: wrap; gap: 20px; margin-bottom: 30px; }\n .summary-card { background: #f5f5f5; border-radius: 8px; padding: 16px; flex: 1; min-width: 200px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n .file { margin-bottom: 30px; border: 1px solid #ddd; border-radius: 8px; overflow: hidden; }\n .file-header { background: #f0f0f0; padding: 10px 16px; font-weight: bold; border-bottom: 1px solid #ddd; }\n .finding { padding: 16px; border-bottom: 1px solid #eee; }\n .finding:last-child { border-bottom: none; }\n .severity { display: inline-block; padding: 3px 8px; border-radius: 4px; font-size: 12px; font-weight: bold; margin-right: 8px; }\n .severity.critical { background: #ffebee; color: #d32f2f; }\n .severity.error { background: #ffebee; color: #f44336; }\n .severity.warning { background: #fff8e1; color: #ff8f00; }\n .severity.info { background: #e3f2fd; color: #1976d2; }\n .category { display: inline-block; padding: 3px 8px; border-radius: 4px; font-size: 12px; margin-right: 8px; background: #f5f5f5; }\n .location { font-family: monospace; color: #666; }\n .code { background: #f8f8f8; padding: 12px; border-radius: 4px; overflow-x: auto; margin: 12px 0; font-family: monospace; white-space: pre; }\n .suggestion { background: #e8f5e9; padding: 12px; border-radius: 4px; margin: 12px 0; }\n .explanation { color: #666; font-style: italic; }\n .diff-added { background: #e6ffed; color: #22863a; }\n .diff-removed { background: #ffeef0; color: #cb2431; }\n </style>\n</head>\n<body>\n <h1>Code Analysis Report</h1>\n <p>Generated on ${(new Date).toLocaleString()}</p>\n\n <div class="summary">\n <div class="summary-card">\n <h3>Overview</h3>\n <p>Files analyzed: ${n.length}</p>\n <p>Quality score: ${function(e){let n,t;e>=90?(n="A+",t="#4caf50"):e>=85?(n="A",t="#4caf50"):e>=80?(n="A-",t="#4caf50"):e>=75?(n="B+",t="#8bc34a"):e>=70?(n="B",t="#8bc34a"):e>=65?(n="B-",t="#8bc34a"):e>=60?(n="C+",t="#ffc107"):e>=55?(n="C",t="#ffc107"):e>=50?(n="C-",t="#ffc107"):e>=45?(n="D+",t="#ff5722"):e>=40?(n="D",t="#ff5722"):(n="F",t="#f44336");return`<span style="color: ${t}; font-weight: bold;">${n}</span> (${Math.round(e)})`}(t.qualityScore)}</p>\n </div>\n\n <div class="summary-card">\n <h3>Severity</h3>\n <p>Critical: ${t.severityCounts.critical||0}</p>\n <p>Error: ${t.severityCounts.error||0}</p>\n <p>Warning: ${t.severityCounts.warning||0}</p>\n <p>Info: ${t.severityCounts.info||0}</p>\n </div>\n\n <div class="summary-card">\n <h3>Category</h3>\n <p>Performance: ${t.categoryCounts.performance||0}</p>\n <p>Security: ${t.categoryCounts.security||0}</p>\n <p>Maintainability: ${t.categoryCounts.maintainability||0}</p>\n <p>Bugs: ${t.categoryCounts.bugs||0}</p>\n <p>Style: ${t.categoryCounts.style||0}</p>\n </div>\n </div>\n\n <h2>Findings</h2>\n\n ${function(e){let n="";const t={};return e.forEach((e=>{e.success&&e.findings.length>0&&(t[e.filePath]=e.findings)})),Object.entries(t).forEach((([e,t])=>{n+=`<div class="file">\n <div class="file-header">${e}</div>\n ${t.map((e=>`\n <div class="finding">\n <div>\n <span class="severity ${e.severity}">${e.severity.toUpperCase()}</span>\n <span class="category">${e.category}</span>\n <span class="location">Line ${e.line}${e.column?`:${e.column}`:""}</span>\n </div>\n <h3>${O(e.message)}</h3>\n <div class="code">${O(e.code)}</div>\n ${e.suggestion?`\n <div class="suggestion">\n <strong>Suggestion:</strong>\n <div class="code">${O(e.suggestion)}</div>\n </div>\n `:""}\n <div class="explanation">${O(e.explanation)}</div>\n </div>\n `)).join("")}\n </div>`})),n}(n)}\n</body>\n</html>`;s.writeFileSync(e,i)}(t.output,l,{severityCounts:r,categoryCounts:u,qualityScore:h}),i.success(`HTML report written to ${t.output}`)):(!function(e,n,t){const i={summary:{...t,timestamp:(new Date).toISOString(),fileCount:n.length},results:n};s.writeFileSync(e,JSON.stringify(i,null,2))}(t.output,l,{severityCounts:r,categoryCounts:u,qualityScore:h}),i.success(`JSON report written to ${t.output}`))}}}catch(e){i.stopSpinnerError("Failed to analyze code"),i.error(e.message),process.exit(1)}})),t};
//# sourceMappingURL=codeAnalyzerCommand.js.map