(filePaths, rootPath)
| 70 | } |
| 71 | |
| 72 | export async function analyzeTypeScriptFiles(filePaths, rootPath) { |
| 73 | const checks = []; |
| 74 | const metrics = []; |
| 75 | const artifacts = []; |
| 76 | |
| 77 | if (filePaths.length === 0) { |
| 78 | return { checks, metrics, artifacts }; |
| 79 | } |
| 80 | |
| 81 | const perFile = []; |
| 82 | let totalCommentLines = 0; |
| 83 | let totalCodeLines = 0; |
| 84 | let totalLongLines = 0; |
| 85 | let totalImports = 0; |
| 86 | let totalClasses = 0; |
| 87 | let maxComplexity = 0; |
| 88 | let maxFunctionLength = 0; |
| 89 | let maxNesting = 0; |
| 90 | let functionCount = 0; |
| 91 | let totalFunctionLength = 0; |
| 92 | let testFileCount = 0; |
| 93 | |
| 94 | for (const filePath of filePaths) { |
| 95 | const source = await readText(filePath); |
| 96 | const lines = source.replace(/\r\n/g, "\n").split("\n"); |
| 97 | const functions = detectFunctions(lines); |
| 98 | const commentLines = lines.filter((line) => line.trim().startsWith("//") || line.trim().startsWith("*") || line.trim().startsWith("/*")).length; |
| 99 | const longLines = lines.filter((line) => line.length > 120).length; |
| 100 | const imports = lines.filter((line) => line.trim().startsWith("import ")).length; |
| 101 | const classes = countMatches(source, /\bclass\s+[A-Za-z0-9_$]+/g); |
| 102 | const complexity = 1 + countDecisionPoints(source); |
| 103 | const fileMaxComplexity = functions.reduce((max, fn) => Math.max(max, fn.complexity), complexity); |
| 104 | const fileMaxFunctionLength = functions.reduce((max, fn) => Math.max(max, fn.length), 0); |
| 105 | const fileMaxNesting = functions.reduce((max, fn) => Math.max(max, fn.nesting), 0); |
| 106 | |
| 107 | totalCommentLines += commentLines; |
| 108 | totalCodeLines += lines.filter((line) => line.trim()).length; |
| 109 | totalLongLines += longLines; |
| 110 | totalImports += imports; |
| 111 | totalClasses += classes; |
| 112 | maxComplexity = Math.max(maxComplexity, fileMaxComplexity); |
| 113 | maxFunctionLength = Math.max(maxFunctionLength, fileMaxFunctionLength); |
| 114 | maxNesting = Math.max(maxNesting, fileMaxNesting); |
| 115 | functionCount += functions.length; |
| 116 | totalFunctionLength += functions.reduce((sum, fn) => sum + fn.length, 0); |
| 117 | if (/(^|\/)(tests?|__tests__)\/|(\.test|\.spec)\./.test(filePath)) { |
| 118 | testFileCount += 1; |
| 119 | } |
| 120 | |
| 121 | perFile.push({ |
| 122 | path: relativePath(rootPath, filePath), |
| 123 | functionCount: functions.length, |
| 124 | complexity: fileMaxComplexity, |
| 125 | maxFunctionLength: fileMaxFunctionLength, |
| 126 | maxNesting: fileMaxNesting, |
| 127 | longLines, |
| 128 | }); |
| 129 | } |
no test coverage detected