@principal-ai/quality-lens-cli 0.1.62 → 0.1.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -357,7 +357,7 @@ NOTE: as of Ohm v16, there is no default action for iteration nodes \u2014 see `
|
|
|
357
357
|
`)[0];return h.length>200?h.substring(0,197)+"...":h}formatTestFailureMessage(c,f){let S=f.replace(/\u001b\[[0-9;]*m/g,"").split(`
|
|
358
358
|
`)[0].substring(0,150);return`Test "${c}" failed: ${S}`}getEmptyResults(){return{numFailedTestSuites:0,numFailedTests:0,numPassedTestSuites:0,numPassedTests:0,numPendingTestSuites:0,numPendingTests:0,numRuntimeErrorTestSuites:0,numTodoTests:0,numTotalTestSuites:0,numTotalTests:0,openHandles:[],snapshot:{added:0,didUpdate:!1,failure:!1,filesAdded:0,filesRemoved:0,filesRemovedList:[],filesUnmatched:0,filesUpdated:0,matched:0,total:0,unchecked:0,uncheckedKeysByFile:[],unmatched:0,updated:0},startTime:Date.now(),success:!0,testResults:[],wasInterrupted:!1}}normalizeResults(c){let f=this.getEmptyResults(),h=c;return{...f,...h,testResults:(h.testResults||[]).map(S=>({...S,assertionResults:S.assertionResults||[],perfStats:S.perfStats||{}}))}}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new Aur.PathMapper(c)}return this.pathMapper}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];c.some(h=>h==="--json")||this.addArgsToNpmScript(["--json"]),c.some(h=>h.includes("--no-colors")||h.includes("--colors=false"))||this.addArgsToNpmScript(["--no-colors"]),c.some(h=>h==="--coverage")||this.addArgsToNpmScript(["--coverage"])}return super.execute()}};Eoe.JestLens=bke});var o_t=jt(HR=>{"use strict";Object.defineProperty(HR,"__esModule",{value:!0});HR.KnipLens=HR.SOURCE_EXTENSIONS=void 0;var Fur=SC(),kur=RT(),Iur=EC();HR.SOURCE_EXTENSIONS=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]);var Cke=class _ extends Fur.BaseLens{name="knip";description="Find unused files, exports, and dependencies";languages=["javascript","typescript"];supportedTools=["knip"];requirements=kur.KNIP_REQUIREMENTS;pathMapper;injectedSourceFiles;constructor(c,f={}){super(c,f),this.injectedSourceFiles=f.sourceFiles}static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f?.custom)return 100;let h=f.custom,S=(h.unlistedDependencies||0)*15,k=(h.unresolvedImports||0)*10,M=(h.unusedFiles||0)*5,G=(h.unusedDependencies||0)*2,ne=(h.unusedDevDependencies||0)*1,fe=(h.unusedExports||0)*1,pe=(h.unusedTypes||0)*.5,xe=S+k+M+G+ne+fe+pe,$=Math.max(0,Math.min(100,100-xe));return Math.round($*100)/100}parse(c){let f=c.stderr||c.stdout;if(!f)return this.getEmptyOutput();try{let h=JSON.parse(f);return this.normalizeOutput(h)}catch(h){this.debug("Failed to parse Knip output as JSON, trying to extract from npm wrapper:",h);let S=f.split(`
|
|
359
359
|
`);for(let k of S){let M=k.trim();if(M.startsWith("{"))try{let G=JSON.parse(M);return this.debug("Successfully extracted JSON from npm wrapper output"),this.normalizeOutput(G)}catch{this.debug("Line started with { but was not valid JSON:",M.substring(0,50));continue}}if(c.stderr&&!c.stderr.trim().startsWith("{"))throw new Error(`Knip execution error: ${c.stderr}`);return this.debug("No valid JSON found in output, returning empty results"),this.getEmptyOutput()}}format(c){let f=[],h=this.getPathMapper();for(let[$,He]of Object.entries(c.files||{})){let Oe=h.toRelative($);f.push({file:Oe,line:1,column:1,severity:"warning",message:`Unused file: ${He.join(", ")||"file not referenced"}`,rule:"unused-file",source:this.name,category:"files"})}for(let[$,He]of c.dependencies||[])f.push({file:h.toRelative($+"/package.json"),line:1,column:1,severity:"warning",message:`Unused dependency: ${He}`,rule:"unused-dependency",source:this.name,category:"dependencies"});for(let[$,He]of c.devDependencies||[])f.push({file:h.toRelative($+"/package.json"),line:1,column:1,severity:"info",message:`Unused devDependency: ${He}`,rule:"unused-devDependency",source:this.name,category:"dependencies"});for(let[$,He]of Object.entries(c.unlisted||{})){let Oe=h.toRelative($);for(let je of He)f.push({file:Oe,line:1,column:1,severity:"error",message:`Unlisted dependency: ${je}`,rule:"unlisted-dependency",source:this.name,category:"dependencies"})}for(let[$,He]of Object.entries(c.unresolved||{})){let Oe=h.toRelative($);for(let je of He)f.push({file:Oe,line:1,column:1,severity:"error",message:`Unresolved import: ${je}`,rule:"unresolved-import",source:this.name,category:"imports"})}for(let[$,He]of Object.entries(c.exports||{})){let Oe=h.toRelative($);for(let je of He){let{line:yt,col:Vt,name:dr}=this.parseExportInfo(je);f.push({file:Oe,line:yt||1,column:Vt||1,severity:"warning",message:`Unused export: ${dr}`,rule:"unused-export",source:this.name,category:"exports"})}}for(let[$,He]of Object.entries(c.nsExports||{})){let Oe=h.toRelative($);for(let je of He){let{line:yt,col:Vt,name:dr}=this.parseExportInfo(je);f.push({file:Oe,line:yt||1,column:Vt||1,severity:"warning",message:`Unused namespace export: ${dr}`,rule:"unused-ns-export",source:this.name,category:"exports"})}}for(let[$,He]of Object.entries(c.types||{})){let Oe=h.toRelative($);for(let je of He){let{line:yt,col:Vt,name:dr}=this.parseExportInfo(je);f.push({file:Oe,line:yt||1,column:Vt||1,severity:"info",message:`Unused type: ${dr}`,rule:"unused-type",source:this.name,category:"types"})}}for(let[$,He]of Object.entries(c.classMembers||{})){let Oe=h.toRelative($);for(let je of He){let{line:yt,col:Vt,name:dr}=this.parseExportInfo(je);f.push({file:Oe,line:yt||1,column:Vt||1,severity:"info",message:`Unused class member: ${dr}`,rule:"unused-class-member",source:this.name,category:"class-members"})}}for(let[$,He]of Object.entries(c.enumMembers||{})){let Oe=h.toRelative($);for(let je of He){let{line:yt,col:Vt,name:dr}=this.parseExportInfo(je);f.push({file:Oe,line:yt||1,column:Vt||1,severity:"info",message:`Unused enum member: ${dr}`,rule:"unused-enum-member",source:this.name,category:"enum-members"})}}for(let[$,He]of Object.entries(c.duplicates||{})){let Oe=h.toRelative($);for(let[je,yt]of He)f.push({file:Oe,line:1,column:1,severity:"warning",message:`Duplicate export: ${yt} (original: ${je})`,rule:"duplicate-export",source:this.name,category:"duplicates"})}let S=this.findAllSourceFiles(),k=new Set([...Object.keys(c.files||{}),...Object.keys(c.exports||{}),...Object.keys(c.nsExports||{}),...Object.keys(c.types||{}),...Object.keys(c.nsTypes||{}),...Object.keys(c.classMembers||{}),...Object.keys(c.enumMembers||{}),...Object.keys(c.unlisted||{}),...Object.keys(c.unresolved||{}),...Object.keys(c.duplicates||{})].map($=>h.toRelative($))),M=[...new Set([...S,...k])],G=M.length,ne={error:f.filter($=>$.severity==="error").length,warning:f.filter($=>$.severity==="warning").length,info:f.filter($=>$.severity==="info").length,hint:f.filter($=>$.severity==="hint").length},fe={};for(let $ of f){let He=$.category||"uncategorized";fe[He]=(fe[He]||0)+1}let pe=this.buildFileMetrics(M,f),xe={lensName:this.name,tool:this.config?.tool.name||"knip",timestamp:Date.now(),success:!0,issues:f,fileMetrics:pe,metrics:{filesAnalyzed:G,totalIssues:f.length,issuesBySeverity:ne,executionTime:0,custom:{unusedFiles:Object.keys(c.files||{}).length,unusedDependencies:(c.dependencies||[]).length,unusedDevDependencies:(c.devDependencies||[]).length,unlistedDependencies:Object.values(c.unlisted||{}).flat().length,unresolvedImports:Object.values(c.unresolved||{}).flat().length,unusedExports:Object.values(c.exports||{}).flat().length,unusedTypes:Object.values(c.types||{}).flat().length,issuesByCategory:fe}}};return xe.qualityScore=_.calculateQualityScore(xe),xe}parseExportInfo(c){let f=c.match(/^(.+?)\s*\((\d+):(\d+)\)$/);return f?{name:f[1].trim(),line:parseInt(f[2],10),col:parseInt(f[3],10)}:{name:c}}getEmptyOutput(){return{files:{},dependencies:[],devDependencies:[],optionalPeerDependencies:[],unlisted:{},binaries:{},unresolved:{},exports:{},nsExports:{},classMembers:{},types:{},nsTypes:{},enumMembers:{},duplicates:{}}}isV5Format(c){let f=Array.isArray(c.files),h=Array.isArray(c.issues);return f||h}convertV5ToV4(c){let f=this.getEmptyOutput();if(c.files&&Array.isArray(c.files))for(let h of c.files)f.files[h]=[];if(c.issues&&Array.isArray(c.issues))for(let h of c.issues){let{file:S}=h;if(h.dependencies&&Array.isArray(h.dependencies))for(let k of h.dependencies)f.dependencies.push(["",k]);if(h.devDependencies&&Array.isArray(h.devDependencies))for(let k of h.devDependencies)f.devDependencies.push(["",k]);if(h.optionalPeerDependencies&&Array.isArray(h.optionalPeerDependencies))for(let k of h.optionalPeerDependencies)f.optionalPeerDependencies.push(["",k]);if(h.unlisted&&Array.isArray(h.unlisted)&&(f.unlisted[S]||(f.unlisted[S]=[]),f.unlisted[S].push(...h.unlisted)),h.binaries&&Array.isArray(h.binaries)&&(f.binaries[S]||(f.binaries[S]=[]),f.binaries[S].push(...h.binaries)),h.unresolved&&Array.isArray(h.unresolved)&&(f.unresolved[S]||(f.unresolved[S]=[]),f.unresolved[S].push(...h.unresolved)),h.exports&&Array.isArray(h.exports)){f.exports[S]||(f.exports[S]=[]);for(let k of h.exports)f.exports[S].push(`${k.name} (${k.line}:${k.col})`)}if(h.nsExports&&Array.isArray(h.nsExports)){f.nsExports[S]||(f.nsExports[S]=[]);for(let k of h.nsExports)f.nsExports[S].push(`${k.name} (${k.line}:${k.col})`)}if(h.types&&Array.isArray(h.types)){f.types[S]||(f.types[S]=[]);for(let k of h.types)f.types[S].push(`${k.name} (${k.line}:${k.col})`)}if(h.nsTypes&&Array.isArray(h.nsTypes)){f.nsTypes[S]||(f.nsTypes[S]=[]);for(let k of h.nsTypes)f.nsTypes[S].push(`${k.name} (${k.line}:${k.col})`)}if(h.classMembers&&Array.isArray(h.classMembers)){f.classMembers[S]||(f.classMembers[S]=[]);for(let k of h.classMembers)f.classMembers[S].push(`${k.name} (${k.line}:${k.col})`)}if(h.enumMembers&&Array.isArray(h.enumMembers)){f.enumMembers[S]||(f.enumMembers[S]=[]);for(let k of h.enumMembers)f.enumMembers[S].push(`${k.name} (${k.line}:${k.col})`)}if(h.duplicates&&Array.isArray(h.duplicates)){f.duplicates[S]||(f.duplicates[S]=[]);for(let k of h.duplicates)f.duplicates[S].push([k.name,k.name])}}return f}normalizeOutput(c){return this.isV5Format(c)?(this.debug("Detected Knip v5+ format, converting to v4 format"),this.convertV5ToV4(c)):{...this.getEmptyOutput(),...c}}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new Iur.PathMapper(c)}return this.pathMapper}findAllSourceFiles(){return this.injectedSourceFiles?this.injectedSourceFiles:(this.debug("No source files injected, file metrics will only include files with issues"),[])}async execute(){return this.config?.tool&&((this.config.tool.args||[]).some(h=>h.includes("--reporter")||h==="-r")||this.addArgsToNpmScript(["--reporter","json"])),super.execute()}};HR.KnipLens=Cke});var c_t=jt(xoe=>{"use strict";Object.defineProperty(xoe,"__esModule",{value:!0});xoe.PrettierLens=void 0;var wur=SC(),Pur=RT(),Nur=EC(),Ske=class _ extends wur.BaseLens{name="prettier";description="Code formatter";languages=["javascript","typescript","json","css","html","markdown"];supportedTools=["prettier"];requirements=Pur.PRETTIER_REQUIREMENTS;pathMapper;static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f)return 100;let h=Math.max(f.filesAnalyzed,1),S=f.issuesBySeverity.error;if(S===0)return 100;let k=Math.max(0,100-S/h*100);return Math.round(k*100)/100}parse(c){let f=[],h=[],S=c.stderr||c.stdout||"";if(!S)return{filesNeedingFormatting:f,filesChecked:0,analyzedFilePaths:h};let k=S.split(`
|
|
360
|
-
`).map(ne=>ne.trim()).filter(Boolean),M=/^\[debug\] resolve config from ["'](.+?)["']$/;for(let ne of k){let fe=ne.match(M);if(fe){h.push(fe[1]);continue}if(ne.startsWith("Checking formatting...")||ne.startsWith("All matched files")||ne.startsWith("Code style issues found")||ne.startsWith("Code style issues")||ne.includes("prettier --write")||ne.startsWith(">")||ne.startsWith("$")||ne.startsWith("[debug]")||ne.match(/^(npm|yarn|pnpm|bun)\s+/)||ne==="")continue;let pe=ne.replace(/^\[warn\]\s*/,"");pe&&!pe.match(/^\d+.*files?.*checked/i)&&!pe.match(/Code style issues/)&&f.push(pe)}let G=h.length;if(G===0){let ne=S.match(/Code style issues found in (\d+) file/i);if(ne){let xe=parseInt(ne[1],10);xe===f.length&&(G=xe)}let pe=(c.stderr||"").match(/Checked (\d+) files/i)||S.match(/Checked (\d+) files/i);pe&&(G=parseInt(pe[1],10))}return{filesNeedingFormatting:f,filesChecked:G,analyzedFilePaths:h}}format(c){let f=[],h=[],S=this.getPathMapper(),k=c.analyzedFilePaths.map(pe=>S.toRelative(pe)),M=new Set(c.filesNeedingFormatting.map(pe=>S.toRelative(pe)));for(let pe of k){let xe=M.has(pe);h.push({path:pe,hasIssues:xe})}for(let pe of c.filesNeedingFormatting){let xe=S.toRelative(pe);f.push({file:xe,line:1,column:1,severity:"error",message:"File is not formatted according to Prettier rules",rule:"prettier",source:this.name,category:"formatting"})}let G=c.filesChecked||c.filesNeedingFormatting.length,ne=this.buildFileMetrics(k,f),fe={lensName:this.name,tool:this.config?.tool.name||"prettier",timestamp:Date.now(),success:!0,issues:f,analyzedFiles:h,fileMetrics:ne,metrics:{filesAnalyzed:G,totalIssues:f.length,issuesBySeverity:{error:f.length,warning:0,info:0,hint:0},executionTime:0,custom:{filesNeedingFormatting:c.filesNeedingFormatting.length,formattingCompliance:G>0?Math.round((1-c.filesNeedingFormatting.length/G)*100*100)/100:100}}};return fe.qualityScore=_.calculateQualityScore(fe),fe}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new Nur.PathMapper(c)}return this.pathMapper}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];c.some(k=>k==="--check"||k==="-c")||this.addArgsToNpmScript(["--check"]),c.some(k=>k==="--no-error-on-unmatched-pattern")||this.addArgsToNpmScript(["--no-error-on-unmatched-pattern"]),c.some(k=>k.startsWith("--log-level"))||this.addArgsToNpmScript(["--log-level","debug"])}return super.execute()}};xoe.PrettierLens=Ske});var u_t=jt(QR=>{"use strict";Object.defineProperty(QR,"__esModule",{value:!0});QR.TypeScriptLens=QR.TS_SOURCE_EXTENSIONS=void 0;var Our=SC(),Lur=RT(),Rur=EC();QR.TS_SOURCE_EXTENSIONS=new Set([".ts",".tsx",".js",".jsx",".mts",".mjs",".cts",".cjs"]);var P2;(function(_){_[_.Warning=0]="Warning",_[_.Error=1]="Error",_[_.Suggestion=2]="Suggestion",_[_.Message=3]="Message"})(P2||(P2={}));var Eke=class _ extends Our.BaseLens{name="typescript";description="TypeScript type checking";languages=["typescript","javascript"];supportedTools=["tsc","typescript"];requirements=Lur.TYPESCRIPT_REQUIREMENTS;pathMapper;injectedSourceFiles;constructor(c,f={}){super(c,f),this.injectedSourceFiles=f.sourceFiles}static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f)return 100;let h=Math.max(f.custom?.filesWithErrors||f.filesAnalyzed,1),{error:S,warning:k,info:M}=f.issuesBySeverity;if(S===0&&k===0&&M===0)return 100;let G=S/h*8,ne=k/h*2,fe=M/h*.5,pe=G+ne+fe,xe=Math.max(0,Math.min(100,100-pe));return Math.round(xe*100)/100}parse(c){let f=[],h=[];if(c.stdout){let fe=c.stdout.split(`
|
|
360
|
+
`).map(ne=>ne.trim()).filter(Boolean),M=/^\[debug\] resolve config from ["'](.+?)["']$/;for(let ne of k){let fe=ne.match(M);if(fe){h.push(fe[1]);continue}if(ne.startsWith("Checking formatting...")||ne.startsWith("All matched files")||ne.startsWith("Code style issues found")||ne.startsWith("Code style issues")||ne.startsWith("Ignored unknown option")||ne.includes("prettier --write")||ne.startsWith(">")||ne.startsWith("$")||ne.startsWith("[debug]")||ne.match(/^(npm|yarn|pnpm|bun)\s+/)||ne==="")continue;let pe=ne.replace(/^\[warn\]\s*/,"");pe&&!pe.match(/^\d+.*files?.*checked/i)&&!pe.match(/Code style issues/)&&f.push(pe)}let G=h.length;if(G===0){let ne=S.match(/Code style issues found in (\d+) file/i);if(ne){let xe=parseInt(ne[1],10);xe===f.length&&(G=xe)}let pe=(c.stderr||"").match(/Checked (\d+) files/i)||S.match(/Checked (\d+) files/i);pe&&(G=parseInt(pe[1],10))}return{filesNeedingFormatting:f,filesChecked:G,analyzedFilePaths:h}}format(c){let f=[],h=[],S=this.getPathMapper(),k=c.analyzedFilePaths.map(pe=>S.toRelative(pe)),M=new Set(c.filesNeedingFormatting.map(pe=>S.toRelative(pe)));for(let pe of k){let xe=M.has(pe);h.push({path:pe,hasIssues:xe})}for(let pe of c.filesNeedingFormatting){let xe=S.toRelative(pe);f.push({file:xe,line:1,column:1,severity:"error",message:"File is not formatted according to Prettier rules",rule:"prettier",source:this.name,category:"formatting"})}let G=c.filesChecked||c.filesNeedingFormatting.length,ne=this.buildFileMetrics(k,f),fe={lensName:this.name,tool:this.config?.tool.name||"prettier",timestamp:Date.now(),success:!0,issues:f,analyzedFiles:h,fileMetrics:ne,metrics:{filesAnalyzed:G,totalIssues:f.length,issuesBySeverity:{error:f.length,warning:0,info:0,hint:0},executionTime:0,custom:{filesNeedingFormatting:c.filesNeedingFormatting.length,formattingCompliance:G>0?Math.round((1-c.filesNeedingFormatting.length/G)*100*100)/100:100}}};return fe.qualityScore=_.calculateQualityScore(fe),fe}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new Nur.PathMapper(c)}return this.pathMapper}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];c.some(k=>k==="--check"||k==="-c")||this.addArgsToNpmScript(["--check"]),c.some(k=>k==="--no-error-on-unmatched-pattern")||this.addArgsToNpmScript(["--no-error-on-unmatched-pattern"]),c.some(k=>k.startsWith("--log-level")||k.startsWith("--loglevel"))||this.addArgsToNpmScript(["--log-level","debug","--loglevel","debug"])}return super.execute()}};xoe.PrettierLens=Ske});var u_t=jt(QR=>{"use strict";Object.defineProperty(QR,"__esModule",{value:!0});QR.TypeScriptLens=QR.TS_SOURCE_EXTENSIONS=void 0;var Our=SC(),Lur=RT(),Rur=EC();QR.TS_SOURCE_EXTENSIONS=new Set([".ts",".tsx",".js",".jsx",".mts",".mjs",".cts",".cjs"]);var P2;(function(_){_[_.Warning=0]="Warning",_[_.Error=1]="Error",_[_.Suggestion=2]="Suggestion",_[_.Message=3]="Message"})(P2||(P2={}));var Eke=class _ extends Our.BaseLens{name="typescript";description="TypeScript type checking";languages=["typescript","javascript"];supportedTools=["tsc","typescript"];requirements=Lur.TYPESCRIPT_REQUIREMENTS;pathMapper;injectedSourceFiles;constructor(c,f={}){super(c,f),this.injectedSourceFiles=f.sourceFiles}static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f)return 100;let h=Math.max(f.custom?.filesWithErrors||f.filesAnalyzed,1),{error:S,warning:k,info:M}=f.issuesBySeverity;if(S===0&&k===0&&M===0)return 100;let G=S/h*8,ne=k/h*2,fe=M/h*.5,pe=G+ne+fe,xe=Math.max(0,Math.min(100,100-pe));return Math.round(xe*100)/100}parse(c){let f=[],h=[];if(c.stdout){let fe=c.stdout.split(`
|
|
361
361
|
`).filter(pe=>pe.trim().length>0);for(let pe of fe){let xe=pe.trim();(xe.endsWith(".ts")||xe.endsWith(".tsx"))&&!xe.includes("/node_modules/")&&h.push(xe)}}let S=h.length,k=c.stderr||"";if(!k)return{errors:f,filesAnalyzed:S,analyzedFilePaths:h};let M=/^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+(TS\d+):\s+(.+)$/gm,G;for(;(G=M.exec(k))!==null;){let[,fe,pe,xe,$,He,Oe]=G;f.push({file:fe,line:parseInt(pe,10),column:parseInt(xe,10),code:He,message:Oe,category:$==="error"?P2.Error:P2.Warning})}let ne=/^([^:]+):(\d+):(\d+)\s+-\s+(error|warning)\s+(TS\d+):\s+(.+)$/gm;for(;(G=ne.exec(k))!==null;){let[,fe,pe,xe,$,He,Oe]=G;f.some(yt=>yt.file===fe&&yt.line===parseInt(pe,10)&&yt.column===parseInt(xe,10)&&yt.code===He)||f.push({file:fe,line:parseInt(pe,10),column:parseInt(xe,10),code:He,message:Oe,category:$==="error"?P2.Error:P2.Warning})}return{errors:f,filesAnalyzed:S,analyzedFilePaths:h}}format(c){let f=[],h=this.getPathMapper(),S;if(c.analyzedFilePaths.length>0)S=c.analyzedFilePaths.map(Oe=>h.toRelative(Oe));else if(S=this.findAllSourceFiles(),S.length===0&&c.errors.length>0){let Oe=[...new Set(c.errors.map(je=>h.toRelative(je.file)))];S=Oe,this.debug(`Using ${Oe.length} files extracted from errors as fallback`)}for(let Oe of c.errors){let je=h.toRelative(Oe.file);f.push({file:je,line:Oe.line,column:Oe.column,severity:this.mapTSSeverity(Oe.category),message:Oe.message,rule:Oe.code,source:this.name,category:this.categorizeError(Oe.code)})}let k=new Set(c.errors.map(Oe=>Oe.file)).size,M=c.errors.filter(Oe=>Oe.category===P2.Error).length,G=c.errors.filter(Oe=>Oe.category===P2.Warning).length,ne=c.errors.filter(Oe=>Oe.category===P2.Suggestion).length,fe={};for(let Oe of c.errors)fe[Oe.code]=(fe[Oe.code]||0)+1;let pe=Object.entries(fe).sort((Oe,je)=>je[1]-Oe[1]).slice(0,5),xe=this.buildFileMetrics(S,f),$=S.length,He={lensName:this.name,tool:this.config?.tool.name||"tsc",timestamp:Date.now(),success:!0,issues:f,fileMetrics:xe,metrics:{filesAnalyzed:$,totalIssues:f.length,issuesBySeverity:{error:M,warning:G,info:ne,hint:0},executionTime:0,custom:{filesWithErrors:k,totalErrors:M,totalWarnings:G,totalSuggestions:ne,uniqueErrorCodes:Object.keys(fe).length,topErrors:pe.map(([Oe,je])=>({code:Oe,count:je}))}}};return He.qualityScore=_.calculateQualityScore(He),He}mapTSSeverity(c){switch(c){case P2.Error:return"error";case P2.Warning:return"warning";case P2.Suggestion:return"info";case P2.Message:default:return"info"}}categorizeError(c){switch(c){case"TS2307":case"TS2304":case"TS2552":return"resolution";case"TS2322":case"TS2345":case"TS2769":return"type-mismatch";case"TS2339":case"TS2551":return"property-access";case"TS7006":case"TS7031":return"implicit-any"}let f=parseInt(c.replace("TS",""),10);return f>=1e3&&f<2e3?"syntax":f>=2e3&&f<3e3?"semantic":f>=3e3&&f<4e3?"declaration":f>=4e3&&f<5e3?"signature":f>=5e3&&f<6e3?"jsx":f>=6e3&&f<7e3?"messages":f>=7e3&&f<8e3?"noImplicitAny":f>=8e3&&f<9e3?"decorators":f>=17e3&&f<18e3?"jsx-attributes":f>=18e3&&f<19e3?"async":"general"}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new Rur.PathMapper(c)}return this.pathMapper}findAllSourceFiles(){return this.injectedSourceFiles&&this.injectedSourceFiles.length>0?this.injectedSourceFiles:(this.debug("No source files injected, file metrics will only include files from tsc output"),[])}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];!c.some(h=>h==="--noEmit")&&!c.some(h=>h==="--build"||h==="-b")&&this.addArgsToNpmScript(["--noEmit"]),c.some(h=>h.includes("--pretty"))||this.addArgsToNpmScript(["--pretty","false"]),c.some(h=>h==="--listFiles")||this.addArgsToNpmScript(["--listFiles"])}return super.execute()}};QR.TypeScriptLens=Eke});var l_t=jt(Toe=>{"use strict";Object.defineProperty(Toe,"__esModule",{value:!0});Toe.VitestLens=void 0;var Mur=SC(),Bur=RT(),jur=EC(),xke=class _ extends Mur.BaseLens{name="vitest";description="Vitest test runner";languages=["javascript","typescript"];supportedTools=["vitest"];requirements=Bur.VITEST_REQUIREMENTS;pathMapper;static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f?.custom)return 100;let h=f.custom,S=h.totalTests||0,k=h.passedTests||0,M=h.skippedTests||0;if(S===0)return 0;let ne=k/S*100,fe=M/S*50;return ne-=fe,Math.max(0,Math.min(100,Math.round(ne*100)/100))}parse(c){let f=c.stdout||c.stderr||"";if(!f)return this.getEmptyResults();try{let h=f.indexOf("{"),S=f.lastIndexOf("}");if(h!==-1&&S!==-1&&S>h){let M=f.substring(h,S+1),G=JSON.parse(M);return this.normalizeResults(G)}let k=JSON.parse(f);return this.normalizeResults(k)}catch(h){return this.debug("Failed to parse Vitest output as JSON:",h),this.parseTextOutput(f)}}parseTextOutput(c){let f=this.getEmptyResults(),h=c.split(`
|
|
362
362
|
`),S=0,k=0,M=0,G=0;for(let ne of h){let fe=ne.match(/Tests\s+(\d+)\s+passed(?:\s*\|\s*(\d+)\s+failed)?(?:\s*\|\s*(\d+)\s+(?:skipped|todo))?/i);fe&&(k=parseInt(fe[1],10)||0,M=parseInt(fe[2],10)||0,G=parseInt(fe[3],10)||0,S=k+M+G);let pe=ne.match(/[✓✗]\s+(.+\.(?:test|spec)\.[jt]sx?)\s+\((\d+)\)/);if(pe){let xe=ne.includes("\u2713");f.testResults=f.testResults||[],f.testResults.push({name:pe[1],status:xe?"pass":"fail"})}}return f.numTotalTests=S,f.numPassedTests=k,f.numFailedTests=M,f.numPendingTests=G,f.success=M===0,f}format(c){let f=[],h=this.getPathMapper();for(let je of c.testResults||[]){let yt=h.toRelative(je.name),Vt=je.assertionResults||this.extractTestsFromTasks(je.tasks||[]);for(let dr of Vt)if(dr.status==="fail"){let ur=dr.error?.message||"Test failed";f.push({file:yt,line:1,column:1,severity:"error",message:`Test "${dr.name}" failed: ${this.cleanMessage(ur)}`,rule:"test-failed",source:this.name,category:"test-case"})}}let S=c.numTotalTests||0,k=c.numPassedTests||0,M=c.numFailedTests||0,G=(c.numPendingTests||0)+(c.numTodoTests||0),ne=c.numTotalTestSuites||c.testResults?.length||0,fe=c.numPassedTestSuites||0,pe=c.numFailedTestSuites||0,xe=S>0?k/S*100:0,$=(c.testResults||[]).map(je=>h.toRelative(je.name)),He=this.buildFileMetrics($,f),Oe={lensName:this.name,tool:this.config?.tool.name||"vitest",timestamp:Date.now(),success:c.success!==!1&&M===0,issues:f,fileMetrics:He,metrics:{filesAnalyzed:ne,totalIssues:f.length,issuesBySeverity:{error:M,warning:0,info:0,hint:0},executionTime:0,custom:{totalTests:S,passedTests:k,failedTests:M,skippedTests:G,testSuites:ne,passedSuites:fe,failedSuites:pe,passRate:Math.round(xe*100)/100}}};return Oe.qualityScore=_.calculateQualityScore(Oe),Oe}extractTestsFromTasks(c){let f=[];for(let h of c)h.type==="test"&&f.push({name:h.name,status:this.mapTaskState(h.result?.state,h.mode),duration:h.result?.duration,error:h.result?.error}),h.tasks&&f.push(...this.extractTestsFromTasks(h.tasks));return f}mapTaskState(c,f){if(f==="skip"||f==="todo")return f;switch(c){case"pass":return"pass";case"fail":return"fail";case"skip":return"skip";default:return"pending"}}cleanMessage(c){let h=c.replace(/\u001b\[[0-9;]*m/g,"").split(`
|
|
363
363
|
`)[0];return h.length>150?h.substring(0,147)+"...":h}getEmptyResults(){return{numTotalTestSuites:0,numPassedTestSuites:0,numFailedTestSuites:0,numPendingTestSuites:0,numTotalTests:0,numPassedTests:0,numFailedTests:0,numPendingTests:0,numTodoTests:0,startTime:Date.now(),success:!0,testResults:[]}}normalizeResults(c){return{...this.getEmptyResults(),...c}}getPathMapper(){if(!this.pathMapper){let c=this.config?.cwd||process.cwd();this.pathMapper=new jur.PathMapper(c)}return this.pathMapper}async execute(){if(this.config?.tool){let c=this.config.tool.args||[];c.some(h=>h.includes("--reporter"))||this.addArgsToNpmScript(["--reporter=json"]),c.some(h=>h==="--run"||h==="--watch=false")||this.addArgsToNpmScript(["--run"])}return super.execute()}};Toe.VitestLens=xke});var f_t=jt(Aoe=>{"use strict";Object.defineProperty(Aoe,"__esModule",{value:!0});Aoe.GitLens=void 0;var Jur=SC(),qur=EC(),Tke=class _ extends Jur.BaseLens{name="git";description="Version control insights from Git";languages=["*"];supportedTools=["git"];pathMapper;includeCommitDetails=!1;static calculateQualityScore(c){if(!c.success||c.error)return 0;let f=c.metrics;if(!f?.custom)return 100;let h=f.custom;if(!h.hasUncommittedChanges)return 100;let S=(h.modified||0)*2,k=(h.deleted||0)*2,M=(h.untracked||0)*1,G=S+k+M,ne=Math.max(0,Math.min(100,100-G));return Math.round(ne*100)/100}configure(c){super.configure(c),this.includeCommitDetails=c.includeCommitDetails??!1}async execute(){if(!this.config)throw new Error(`Lens ${this.name} is not configured`);if(!this.executor)throw new Error(`Lens ${this.name} has no executor`);let c=this.config.tool.cwd||this.config.cwd,f=this.config.tool.command||"git",h={},S=[];try{let k=await this.executor.execute(f,["rev-parse","--abbrev-ref","HEAD"],{cwd:c});k.error?(this.debug("Branch command error:",k.error),S.push("branch retrieval failed")):k.exitCode===0?h.branch=k.stdout.trim():(this.debug("Branch command failed with exit code:",k.exitCode),S.push("branch retrieval failed"))}catch(k){this.debug("Failed to get branch:",k),S.push("branch retrieval failed")}try{let k=await this.executor.execute(f,["rev-parse","HEAD"],{cwd:c});k.error?(this.debug("Commit command error:",k.error),S.push("commit retrieval failed")):k.exitCode===0?h.commit=k.stdout.trim():(this.debug("Commit command failed with exit code:",k.exitCode),S.push("commit retrieval failed"))}catch(k){this.debug("Failed to get commit:",k),S.push("commit retrieval failed")}try{let k=await this.executor.execute(f,["status","--porcelain"],{cwd:c});if(k.error)throw new Error(`Git command not found or failed to execute: ${k.error.message}`);if(k.exitCode===0)h.status=k.stdout;else throw new Error(`Git status failed with exit code ${k.exitCode}: ${k.stderr}`)}catch(k){throw this.debug("Failed to get status:",k),S.push("status retrieval failed"),new Error(`Git status failed: ${k}`)}if(this.includeCommitDetails&&h.commit)try{let k=await this.executor.execute(f,["log","-1",'--format="%H|%h|%an|%ae|%ad|%B"',"--date=iso"],{cwd:c});k.exitCode===0&&(h.commitDetails=k.stdout.trim());let M=await this.executor.execute(f,["show","--stat","--format=","HEAD"],{cwd:c});M.exitCode===0&&(h.commitStats=M.stdout.trim())}catch(k){this.debug("Failed to get commit details:",k)}return{stdout:JSON.stringify(h),stderr:S.join(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principal-ai/quality-lens-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.63",
|
|
4
4
|
"description": "CLI tool for running quality lenses on codebases in CI/CD pipelines",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"license": "MIT",
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@principal-ai/codebase-composition": "^0.2.20",
|
|
46
|
-
"@principal-ai/codebase-quality-lenses": "^0.1.
|
|
46
|
+
"@principal-ai/codebase-quality-lenses": "^0.1.41",
|
|
47
47
|
"@principal-ai/repository-abstraction": "^0.2.0",
|
|
48
48
|
"@types/jest": "^30.0.0",
|
|
49
49
|
"@types/node": "^20.0.0",
|