fcis 0.1.0

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.
Files changed (151) hide show
  1. package/.plans/001-fcis-analyzer.md +832 -0
  2. package/.plans/002-fcis-analyzer-improvements.md +205 -0
  3. package/README.md +272 -0
  4. package/TECHNICAL.md +386 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +1836 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/index.d.ts +709 -0
  9. package/dist/index.js +1845 -0
  10. package/dist/index.js.map +1 -0
  11. package/package.json +47 -0
  12. package/pnpm-workspace.yaml +0 -0
  13. package/src/analyzer.ts +266 -0
  14. package/src/classification/classifier.ts +156 -0
  15. package/src/classification/derive-status.ts +171 -0
  16. package/src/classification/quality-scorer.ts +481 -0
  17. package/src/cli.ts +286 -0
  18. package/src/detection/detect-markers.ts +480 -0
  19. package/src/detection/markers.ts +332 -0
  20. package/src/extraction/extract-functions.ts +570 -0
  21. package/src/extraction/extractor.ts +188 -0
  22. package/src/index.ts +111 -0
  23. package/src/reporting/report-console.ts +416 -0
  24. package/src/reporting/report-json.ts +232 -0
  25. package/src/scoring/scorer.ts +504 -0
  26. package/src/types.ts +248 -0
  27. package/tests/classifier.test.ts +480 -0
  28. package/tests/derive-status.test.ts +464 -0
  29. package/tests/detect-markers.test.ts +639 -0
  30. package/tests/extractor.test.ts +155 -0
  31. package/tests/integration.test.ts +706 -0
  32. package/tests/quality-scorer.test.ts +650 -0
  33. package/tests/scorer.test.ts +768 -0
  34. package/tsconfig.json +34 -0
  35. package/tsup.config.ts +17 -0
  36. package/vendor/ts-morph/.editorconfig +10 -0
  37. package/vendor/ts-morph/.gitattributes +11 -0
  38. package/vendor/ts-morph/.github/CODE_OF_CONDUCT.md +77 -0
  39. package/vendor/ts-morph/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  40. package/vendor/ts-morph/.github/ISSUE_TEMPLATE/custom.md +4 -0
  41. package/vendor/ts-morph/.github/ISSUE_TEMPLATE/feature_request.md +18 -0
  42. package/vendor/ts-morph/.github/workflows/ci.yml +50 -0
  43. package/vendor/ts-morph/.github/workflows/publish.yml +53 -0
  44. package/vendor/ts-morph/.vscode/settings.json +10 -0
  45. package/vendor/ts-morph/CONTRIBUTING.md +23 -0
  46. package/vendor/ts-morph/DEVELOPMENT.md +32 -0
  47. package/vendor/ts-morph/LICENSE +21 -0
  48. package/vendor/ts-morph/deno.json +8 -0
  49. package/vendor/ts-morph/deno.lock +1233 -0
  50. package/vendor/ts-morph/docs/CNAME +1 -0
  51. package/vendor/ts-morph/docs/Gemfile +2 -0
  52. package/vendor/ts-morph/docs/_config.yml +5 -0
  53. package/vendor/ts-morph/docs/_layouts/default.html +159 -0
  54. package/vendor/ts-morph/docs/_script-templates/main.ts +116 -0
  55. package/vendor/ts-morph/docs/assets/css/style.scss +212 -0
  56. package/vendor/ts-morph/docs/details/ambient.md +38 -0
  57. package/vendor/ts-morph/docs/details/async.md +31 -0
  58. package/vendor/ts-morph/docs/details/classes.md +314 -0
  59. package/vendor/ts-morph/docs/details/comment-ranges.md +7 -0
  60. package/vendor/ts-morph/docs/details/comments.md +122 -0
  61. package/vendor/ts-morph/docs/details/decorators.md +119 -0
  62. package/vendor/ts-morph/docs/details/documentation.md +73 -0
  63. package/vendor/ts-morph/docs/details/enums.md +117 -0
  64. package/vendor/ts-morph/docs/details/exports.md +308 -0
  65. package/vendor/ts-morph/docs/details/expressions.md +46 -0
  66. package/vendor/ts-morph/docs/details/functions.md +150 -0
  67. package/vendor/ts-morph/docs/details/generators.md +27 -0
  68. package/vendor/ts-morph/docs/details/identifiers.md +79 -0
  69. package/vendor/ts-morph/docs/details/imports.md +191 -0
  70. package/vendor/ts-morph/docs/details/index.md +52 -0
  71. package/vendor/ts-morph/docs/details/initializers.md +40 -0
  72. package/vendor/ts-morph/docs/details/interfaces.md +218 -0
  73. package/vendor/ts-morph/docs/details/literals.md +20 -0
  74. package/vendor/ts-morph/docs/details/modifiers.md +38 -0
  75. package/vendor/ts-morph/docs/details/modules.md +113 -0
  76. package/vendor/ts-morph/docs/details/namespaces.md +7 -0
  77. package/vendor/ts-morph/docs/details/object-literal-expressions.md +106 -0
  78. package/vendor/ts-morph/docs/details/parameters.md +64 -0
  79. package/vendor/ts-morph/docs/details/signatures.md +41 -0
  80. package/vendor/ts-morph/docs/details/source-files.md +292 -0
  81. package/vendor/ts-morph/docs/details/type-aliases.md +34 -0
  82. package/vendor/ts-morph/docs/details/type-parameters.md +72 -0
  83. package/vendor/ts-morph/docs/details/types.md +254 -0
  84. package/vendor/ts-morph/docs/details/variables.md +110 -0
  85. package/vendor/ts-morph/docs/emitting.md +151 -0
  86. package/vendor/ts-morph/docs/index.md +25 -0
  87. package/vendor/ts-morph/docs/manipulation/code-writer.md +20 -0
  88. package/vendor/ts-morph/docs/manipulation/formatting.md +76 -0
  89. package/vendor/ts-morph/docs/manipulation/index.md +136 -0
  90. package/vendor/ts-morph/docs/manipulation/order.md +14 -0
  91. package/vendor/ts-morph/docs/manipulation/performance.md +222 -0
  92. package/vendor/ts-morph/docs/manipulation/removing.md +31 -0
  93. package/vendor/ts-morph/docs/manipulation/renaming.md +106 -0
  94. package/vendor/ts-morph/docs/manipulation/settings.md +76 -0
  95. package/vendor/ts-morph/docs/manipulation/structures.md +117 -0
  96. package/vendor/ts-morph/docs/manipulation/transforms.md +84 -0
  97. package/vendor/ts-morph/docs/metrics/performance.json +4 -0
  98. package/vendor/ts-morph/docs/navigation/ambient-modules.md +22 -0
  99. package/vendor/ts-morph/docs/navigation/compiler-nodes.md +82 -0
  100. package/vendor/ts-morph/docs/navigation/directories.md +287 -0
  101. package/vendor/ts-morph/docs/navigation/example.md +50 -0
  102. package/vendor/ts-morph/docs/navigation/finding-references.md +53 -0
  103. package/vendor/ts-morph/docs/navigation/getting-source-files.md +59 -0
  104. package/vendor/ts-morph/docs/navigation/images/getChildrenVsForEachChild.gif +0 -0
  105. package/vendor/ts-morph/docs/navigation/index.md +94 -0
  106. package/vendor/ts-morph/docs/navigation/language-service.md +23 -0
  107. package/vendor/ts-morph/docs/navigation/program.md +25 -0
  108. package/vendor/ts-morph/docs/navigation/type-checker.md +33 -0
  109. package/vendor/ts-morph/docs/setup/adding-source-files.md +145 -0
  110. package/vendor/ts-morph/docs/setup/ast-viewers.md +46 -0
  111. package/vendor/ts-morph/docs/setup/diagnostics.md +109 -0
  112. package/vendor/ts-morph/docs/setup/file-system.md +106 -0
  113. package/vendor/ts-morph/docs/setup/images/atom-ast.png +0 -0
  114. package/vendor/ts-morph/docs/setup/images/atom-ast_small.png +0 -0
  115. package/vendor/ts-morph/docs/setup/images/atom-command-palette.png +0 -0
  116. package/vendor/ts-morph/docs/setup/images/atom-file.png +0 -0
  117. package/vendor/ts-morph/docs/setup/images/ts-ast-viewer.png +0 -0
  118. package/vendor/ts-morph/docs/setup/index.md +94 -0
  119. package/vendor/ts-morph/docs/utilities.md +55 -0
  120. package/vendor/ts-morph/dprint.json +23 -0
  121. package/vendor/ts-morph/package.json +30 -0
  122. package/vendor/ts-morph/packages/bootstrap/LICENSE +21 -0
  123. package/vendor/ts-morph/packages/bootstrap/lib/ts-morph-bootstrap.d.ts +397 -0
  124. package/vendor/ts-morph/packages/bootstrap/package.json +46 -0
  125. package/vendor/ts-morph/packages/bootstrap/readme.md +200 -0
  126. package/vendor/ts-morph/packages/common/LICENSE +21 -0
  127. package/vendor/ts-morph/packages/common/lib/ts-morph-common.d.ts +1082 -0
  128. package/vendor/ts-morph/packages/common/lib/typescript.d.ts +11439 -0
  129. package/vendor/ts-morph/packages/common/package.json +65 -0
  130. package/vendor/ts-morph/packages/common/readme.md +5 -0
  131. package/vendor/ts-morph/packages/scripts/changeTypeScriptVersion.ts +28 -0
  132. package/vendor/ts-morph/packages/scripts/createDeclarationProject.ts +47 -0
  133. package/vendor/ts-morph/packages/scripts/deps.ts +2 -0
  134. package/vendor/ts-morph/packages/scripts/execScript.ts +31 -0
  135. package/vendor/ts-morph/packages/scripts/folders.ts +11 -0
  136. package/vendor/ts-morph/packages/scripts/getDevCompilerVersions.ts +19 -0
  137. package/vendor/ts-morph/packages/scripts/mod.ts +7 -0
  138. package/vendor/ts-morph/packages/scripts/utils/Memoize.ts +36 -0
  139. package/vendor/ts-morph/packages/scripts/utils/forEachTypeText.ts +23 -0
  140. package/vendor/ts-morph/packages/scripts/utils/makeConstructorsPrivate.ts +26 -0
  141. package/vendor/ts-morph/packages/scripts/utils/mod.ts +4 -0
  142. package/vendor/ts-morph/packages/scripts/utils/printDiagnostics.ts +10 -0
  143. package/vendor/ts-morph/packages/ts-morph/LICENSE +21 -0
  144. package/vendor/ts-morph/packages/ts-morph/lib/ts-morph.d.ts +11198 -0
  145. package/vendor/ts-morph/packages/ts-morph/package.json +78 -0
  146. package/vendor/ts-morph/packages/ts-morph/readme.md +111 -0
  147. package/vendor/ts-morph/readme.md +14 -0
  148. package/vendor/ts-morph/rfcs/README.md +13 -0
  149. package/vendor/ts-morph/rfcs/RFC-0001 - Inserting Into Statements Handling Comments.md +181 -0
  150. package/vendor/ts-morph/tsconfig.common.json +17 -0
  151. package/vitest.config.ts +16 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/extraction/extract-functions.ts","../src/extraction/extractor.ts","../src/detection/detect-markers.ts","../src/classification/classifier.ts","../src/classification/quality-scorer.ts","../src/classification/derive-status.ts","../src/scoring/scorer.ts","../src/analyzer.ts","../src/reporting/report-console.ts","../src/reporting/report-json.ts","../src/cli.ts"],"names":["path","fs","relative","path2","path3","fs2","chalk"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Core type definitions for the FCIS Analyzer\n *\n * These types form the contract between the analyzer's layers:\n * - Extraction layer produces ExtractedFunction and FileImports\n * - Detection layer produces ImpurityMarker[]\n * - Classification layer produces ClassifiedFunction\n * - Scoring layer produces FileScore, DirectoryScore, ProjectScore\n */\n\n/**\n * CallSite captures position and context for each call expression,\n * enabling sequence analysis (GATHER→DECIDE→EXECUTE detection)\n */\nexport type CallSite = {\n expression: string // e.g. \"db.user.findFirst\", \"planAcceptInvite\"\n line: number // position within the function (relative to function start)\n isAwaited: boolean // was this call preceded by `await`?\n}\n\n/**\n * Represents a function extracted from source code\n */\nexport type ExtractedFunction = {\n name: string | null\n filePath: string\n startLine: number\n endLine: number\n isAsync: boolean\n isExported: boolean\n bodyLineCount: number\n statementCount: number\n hasConditionals: boolean\n parentContext: string | null // e.g. class name, variable name\n callSites: CallSite[] // enriched call expressions with position and await context\n hasAwait: boolean // convenience flag: true if any callSite.isAwaited\n propertyAccessChains: string[] // e.g. [\"process.env.NODE_ENV\", \"db.user\"]\n kind:\n | 'function'\n | 'method'\n | 'arrow'\n | 'function-expression'\n | 'getter'\n | 'setter'\n}\n\n/**\n * Represents imports in a file\n */\nexport type FileImports = {\n filePath: string\n imports: {\n moduleSpecifier: string // e.g. \"@sai/database\", \"./organizations.pure\"\n namedImports: string[] // e.g. [\"planAcceptInvite\", \"AcceptInviteDecision\"]\n }[]\n}\n\n/**\n * Strict marker type union — prevents typos, enables exhaustive matching\n * Note: 'async-function' removed — async alone is not an impurity marker\n * Note: React hook markers deferred to v2\n */\nexport type MarkerType =\n | 'await-expression'\n | 'database-call'\n | 'network-fetch'\n | 'network-http'\n | 'fs-import'\n | 'fs-call'\n | 'env-access'\n | 'console-log'\n | 'logging'\n | 'telemetry'\n | 'queue-enqueue'\n | 'event-emit'\n\n/**\n * Represents a detected impurity marker in a function\n */\nexport type ImpurityMarker = {\n type: MarkerType\n detail: string // e.g. \"db.user.findFirst\"\n line?: number // optional line number for better reporting\n}\n\n/**\n * Binary classification — objective, no heuristics\n */\nexport type FunctionClassification = 'pure' | 'impure'\n\n/**\n * Derived status for UX — actionable guidance\n */\nexport type Status = 'ok' | 'review' | 'refactor'\n\n/**\n * A function that has been classified with markers, classification, quality score, and status\n */\nexport type ClassifiedFunction = ExtractedFunction & {\n markers: ImpurityMarker[]\n classification: FunctionClassification\n qualityScore: number | null // 0-100 for impure functions; null for pure\n status: Status // derived from classification + qualityScore\n}\n\n/**\n * Breakdown of function statuses\n */\nexport type StatusBreakdown = {\n ok: number\n review: number\n refactor: number\n}\n\n/**\n * Refactoring candidate summary for reporting\n */\nexport type RefactoringCandidate = {\n name: string | null\n filePath: string\n startLine: number\n bodyLineCount: number\n qualityScore: number\n markers: MarkerType[]\n}\n\n/**\n * Score for a single file\n */\nexport type FileScore = {\n filePath: string\n purity: number // 0-100: pure / (pure + impure)\n impurityQuality: number | null // 0-100: avg quality of impure functions; null if none\n health: number // 0-100: functions with status 'ok' / total\n pureCount: number\n impureCount: number\n excludedCount: number\n statusBreakdown: StatusBreakdown\n pureLineCount: number // total lines in pure functions\n impureLineCount: number // total lines in impure functions\n functions: ClassifiedFunction[]\n refactoringCandidates: Omit<RefactoringCandidate, 'filePath'>[]\n // Edge case flags\n allExcluded?: boolean // true if all functions were excluded\n typeOnly?: boolean // true if file has only type/interface/enum exports\n}\n\n/**\n * Score for a directory\n */\nexport type DirectoryScore = {\n dirPath: string\n purity: number\n impurityQuality: number | null\n health: number\n pureCount: number\n impureCount: number\n excludedCount: number\n statusBreakdown: StatusBreakdown\n pureLineCount: number\n impureLineCount: number\n fileScores: FileScore[]\n}\n\n/**\n * Project-level score (top-level output)\n */\nexport type ProjectScore = {\n purity: number // 0-100: percentage of pure functions\n impurityQuality: number | null // 0-100: avg quality of impure functions\n health: number // 0-100: percentage with status 'ok'\n pureCount: number\n impureCount: number\n excludedCount: number\n statusBreakdown: StatusBreakdown\n pureLineCount: number\n impureLineCount: number\n directoryScores: DirectoryScore[]\n timestamp: string\n commitHash: string | null\n // Sorted by bodyLineCount × (100 - qualityScore) descending (largest, lowest-quality first)\n refactoringCandidates: RefactoringCandidate[]\n // Edge case flags\n allExcluded?: boolean // true if all functions were excluded\n // Subset analysis metadata (when --files is used)\n subset?: boolean // true if this is a subset analysis\n filesGlob?: string // the glob pattern used for --files\n // Errors encountered during analysis\n errors?: AnalysisError[]\n}\n\n/**\n * Error encountered during analysis\n */\nexport type AnalysisError = {\n filePath: string\n error: string\n}\n\n/**\n * Configuration options for the analyzer\n */\nexport type AnalyzerConfig = {\n tsconfigPath: string\n filesGlob?: string\n minHealth?: number\n minPurity?: number\n minQuality?: number\n format?: 'console' | 'json' | 'summary'\n outputPath?: string\n quiet?: boolean\n verbose?: boolean\n}\n\n/**\n * Quality scoring thresholds (configurable)\n */\nexport type QualityThresholds = {\n okThreshold: number // >= this is 'ok' (default: 70)\n reviewThreshold: number // >= this is 'review', below is 'refactor' (default: 40)\n}\n\n/**\n * Default quality thresholds\n */\nexport const DEFAULT_QUALITY_THRESHOLDS: QualityThresholds = {\n okThreshold: 70,\n reviewThreshold: 40,\n}\n\n/**\n * Result of extracting functions from a file\n */\nexport type ExtractionResult = {\n filePath: string\n functions: ExtractedFunction[]\n imports: FileImports\n isTypeOnly: boolean\n error?: string\n}\n\n/**\n * Detection context passed to marker detection\n */\nexport type DetectionContext = {\n imports: FileImports\n pureFileImports: Set<string> // module specifiers ending in .pure\n}\n","/**\n * AST Function Extraction\n *\n * Extracts all function-like nodes from a TypeScript source file into\n * normalized ExtractedFunction structures. This is part of the SHELL layer\n * as it interacts with ts-morph AST nodes.\n *\n * Handles all function forms:\n * - FunctionDeclaration\n * - MethodDeclaration\n * - ArrowFunction (including those passed as arguments)\n * - FunctionExpression (including those passed as arguments)\n * - GetAccessorDeclaration\n * - SetAccessorDeclaration\n */\n\nimport {\n type ArrowFunction,\n type CallExpression,\n type FunctionDeclaration,\n type FunctionExpression,\n type GetAccessorDeclaration,\n type MethodDeclaration,\n type Node,\n type PropertyAccessExpression,\n type SetAccessorDeclaration,\n type SourceFile,\n SyntaxKind,\n} from 'ts-morph'\n\nimport type { CallSite, ExtractedFunction, FileImports } from '../types.js'\n\ntype FunctionLikeNode =\n | FunctionDeclaration\n | MethodDeclaration\n | ArrowFunction\n | FunctionExpression\n | GetAccessorDeclaration\n | SetAccessorDeclaration\n\n/**\n * Extract all functions from a source file\n */\nexport function extractFunctions(sourceFile: SourceFile): ExtractedFunction[] {\n const functions: ExtractedFunction[] = []\n const filePath = sourceFile.getFilePath()\n // Track already-added functions by their position to avoid duplicates\n const addedPositions = new Set<string>()\n\n const addFunction = (fn: ExtractedFunction) => {\n const posKey = `${fn.startLine}:${fn.endLine}`\n if (!addedPositions.has(posKey)) {\n addedPositions.add(posKey)\n functions.push(fn)\n }\n }\n\n // Get all function declarations\n for (const func of sourceFile.getFunctions()) {\n addFunction(extractFunctionData(func, filePath, 'function'))\n }\n\n // Get all class methods, getters, and setters\n for (const classDecl of sourceFile.getClasses()) {\n const className = classDecl.getName() ?? null\n\n for (const method of classDecl.getMethods()) {\n addFunction(extractFunctionData(method, filePath, 'method', className))\n }\n\n for (const getter of classDecl.getGetAccessors()) {\n addFunction(extractFunctionData(getter, filePath, 'getter', className))\n }\n\n for (const setter of classDecl.getSetAccessors()) {\n addFunction(extractFunctionData(setter, filePath, 'setter', className))\n }\n }\n\n // Get arrow functions and function expressions from variable declarations\n // These get named after their variable\n for (const varStatement of sourceFile.getVariableStatements()) {\n const isExported = varStatement.isExported()\n\n for (const decl of varStatement.getDeclarations()) {\n const initializer = decl.getInitializer()\n const varName = decl.getName()\n\n if (initializer) {\n if (initializer.getKind() === SyntaxKind.ArrowFunction) {\n addFunction(\n extractFunctionData(\n initializer as ArrowFunction,\n filePath,\n 'arrow',\n varName,\n isExported,\n ),\n )\n } else if (initializer.getKind() === SyntaxKind.FunctionExpression) {\n addFunction(\n extractFunctionData(\n initializer as FunctionExpression,\n filePath,\n 'function-expression',\n varName,\n isExported,\n ),\n )\n }\n }\n }\n }\n\n // Also check for exported default arrow functions/function expressions\n const defaultExport = sourceFile.getDefaultExportSymbol()\n if (defaultExport) {\n const declarations = defaultExport.getDeclarations()\n for (const decl of declarations) {\n if (decl.getKind() === SyntaxKind.ArrowFunction) {\n addFunction(\n extractFunctionData(\n decl as ArrowFunction,\n filePath,\n 'arrow',\n 'default',\n true,\n ),\n )\n } else if (decl.getKind() === SyntaxKind.FunctionExpression) {\n addFunction(\n extractFunctionData(\n decl as FunctionExpression,\n filePath,\n 'function-expression',\n 'default',\n true,\n ),\n )\n }\n }\n }\n\n // Extract ALL arrow functions and function expressions in the file,\n // including those passed as arguments (e.g., tRPC handlers, callbacks, React components)\n // This catches patterns like: .mutation(async ({ ctx }) => { ... })\n sourceFile.forEachDescendant(node => {\n if (node.getKind() === SyntaxKind.ArrowFunction) {\n const arrowFn = node as ArrowFunction\n const parentContext = inferParentContext(arrowFn)\n addFunction(\n extractFunctionData(arrowFn, filePath, 'arrow', parentContext, false),\n )\n } else if (node.getKind() === SyntaxKind.FunctionExpression) {\n const funcExpr = node as FunctionExpression\n const parentContext = inferParentContext(funcExpr)\n addFunction(\n extractFunctionData(\n funcExpr,\n filePath,\n 'function-expression',\n parentContext,\n false,\n ),\n )\n }\n })\n\n return functions\n}\n\n/**\n * Infer a meaningful name/context for an arrow function or function expression\n * based on its position in the AST (e.g., method name it's passed to, property name, etc.)\n */\nfunction inferParentContext(\n node: ArrowFunction | FunctionExpression,\n): string | null {\n const parent = node.getParent()\n if (!parent) return null\n\n // Case 1: Passed as argument to a method call like .mutation(async () => {})\n // Look for patterns like: .methodName(fn) or methodName(fn)\n if (parent.getKind() === SyntaxKind.CallExpression) {\n const callExpr = parent as CallExpression\n const expression = callExpr.getExpression()\n\n // Handle property access: obj.method(fn) -> \"method\"\n if (expression.getKind() === SyntaxKind.PropertyAccessExpression) {\n const propAccess = expression as PropertyAccessExpression\n return propAccess.getName()\n }\n\n // Handle direct call: method(fn) -> \"method\"\n if (expression.getKind() === SyntaxKind.Identifier) {\n return expression.getText()\n }\n }\n\n // Case 2: Property assignment like { onClick: () => {} }\n if (parent.getKind() === SyntaxKind.PropertyAssignment) {\n const propAssignment = parent as import('ts-morph').PropertyAssignment\n return propAssignment.getName()\n }\n\n // Case 3: Short-hand property like { onClick }\n if (parent.getKind() === SyntaxKind.ShorthandPropertyAssignment) {\n const shorthand = parent as import('ts-morph').ShorthandPropertyAssignment\n return shorthand.getName()\n }\n\n return null\n}\n\n/**\n * Extract data from a function-like node\n */\nfunction extractFunctionData(\n node: FunctionLikeNode,\n filePath: string,\n kind: ExtractedFunction['kind'],\n parentContext: string | null = null,\n isExportedOverride?: boolean,\n): ExtractedFunction {\n const startLine = node.getStartLineNumber()\n const endLine = node.getEndLineNumber()\n const bodyLineCount = endLine - startLine + 1\n\n // Get function name\n let name: string | null = null\n if ('getName' in node && typeof node.getName === 'function') {\n name = node.getName() ?? null\n }\n\n // For arrow functions and function expressions assigned to variables,\n // use the variable name as the function name if no intrinsic name exists\n if (name === null && parentContext !== null) {\n name = parentContext\n }\n\n // Check if async\n const isAsync = 'isAsync' in node ? (node.isAsync?.() ?? false) : false\n\n // Check if exported\n let isExported = isExportedOverride ?? false\n if (!isExported && 'isExported' in node) {\n isExported = (node as FunctionDeclaration).isExported?.() ?? false\n }\n\n // Get body for analysis\n const body = getBodyNode(node)\n\n // Count statements\n const statementCount = countStatements(body)\n\n // Check for conditionals\n const hasConditionals = checkForConditionals(body)\n\n // Extract call sites\n const callSites = extractCallSites(node, startLine)\n\n // Check if any call is awaited\n const hasAwait = callSites.some(cs => cs.isAwaited) || checkForAwait(node)\n\n // Extract property access chains\n const propertyAccessChains = extractPropertyAccessChains(node)\n\n return {\n name,\n filePath,\n startLine,\n endLine,\n isAsync,\n isExported,\n bodyLineCount,\n statementCount,\n hasConditionals,\n parentContext,\n callSites,\n hasAwait,\n propertyAccessChains,\n kind,\n }\n}\n\n/**\n * Get the body node of a function-like node\n */\nfunction getBodyNode(node: FunctionLikeNode): Node | undefined {\n if ('getBody' in node) {\n return node.getBody()\n }\n return undefined\n}\n\n/**\n * Count statements in a function body\n */\nfunction countStatements(body: Node | undefined): number {\n if (!body) return 0\n\n // If it's a block, count statements\n if (body.getKind() === SyntaxKind.Block) {\n const statements = body.getChildrenOfKind(SyntaxKind.SyntaxList)\n if (statements.length > 0 && statements[0]) {\n return statements[0].getChildren().filter(isStatement).length\n }\n }\n\n // If it's an expression body (arrow function), count as 1\n return 1\n}\n\n/**\n * Check if a node is a statement\n */\nfunction isStatement(node: Node): boolean {\n const kind = node.getKind()\n return (\n kind === SyntaxKind.VariableStatement ||\n kind === SyntaxKind.ExpressionStatement ||\n kind === SyntaxKind.ReturnStatement ||\n kind === SyntaxKind.IfStatement ||\n kind === SyntaxKind.ForStatement ||\n kind === SyntaxKind.ForInStatement ||\n kind === SyntaxKind.ForOfStatement ||\n kind === SyntaxKind.WhileStatement ||\n kind === SyntaxKind.DoStatement ||\n kind === SyntaxKind.SwitchStatement ||\n kind === SyntaxKind.TryStatement ||\n kind === SyntaxKind.ThrowStatement ||\n kind === SyntaxKind.BreakStatement ||\n kind === SyntaxKind.ContinueStatement\n )\n}\n\n/**\n * Check if a function body contains conditionals\n */\nfunction checkForConditionals(body: Node | undefined): boolean {\n if (!body) return false\n\n let hasConditionals = false\n\n body.forEachDescendant(node => {\n const kind = node.getKind()\n if (\n kind === SyntaxKind.IfStatement ||\n kind === SyntaxKind.ConditionalExpression ||\n kind === SyntaxKind.SwitchStatement\n ) {\n hasConditionals = true\n }\n })\n\n return hasConditionals\n}\n\n/**\n * Check if a function contains await expressions\n */\nfunction checkForAwait(node: FunctionLikeNode): boolean {\n let hasAwait = false\n\n node.forEachDescendant((descendant, traversal) => {\n // Don't descend into nested functions\n const kind = descendant.getKind()\n if (\n kind === SyntaxKind.FunctionDeclaration ||\n kind === SyntaxKind.FunctionExpression ||\n kind === SyntaxKind.ArrowFunction ||\n kind === SyntaxKind.MethodDeclaration\n ) {\n traversal.skip()\n return\n }\n\n if (kind === SyntaxKind.AwaitExpression) {\n hasAwait = true\n }\n })\n\n return hasAwait\n}\n\n/**\n * Extract call sites from a function\n */\nfunction extractCallSites(\n node: FunctionLikeNode,\n functionStartLine: number,\n): CallSite[] {\n const callSites: CallSite[] = []\n\n node.forEachDescendant((descendant, traversal) => {\n // Don't descend into nested functions\n const kind = descendant.getKind()\n if (\n kind === SyntaxKind.FunctionDeclaration ||\n kind === SyntaxKind.FunctionExpression ||\n kind === SyntaxKind.ArrowFunction ||\n kind === SyntaxKind.MethodDeclaration\n ) {\n traversal.skip()\n return\n }\n\n if (kind === SyntaxKind.CallExpression) {\n const callExpr = descendant as CallExpression\n const expression = getCallExpressionText(callExpr)\n const line = callExpr.getStartLineNumber() - functionStartLine\n\n // Check if this call is awaited\n const parent = callExpr.getParent()\n const isAwaited = parent?.getKind() === SyntaxKind.AwaitExpression\n\n callSites.push({\n expression,\n line,\n isAwaited,\n })\n }\n })\n\n return callSites\n}\n\n/**\n * Get the text representation of a call expression\n */\nfunction getCallExpressionText(callExpr: CallExpression): string {\n const expression = callExpr.getExpression()\n\n // Handle property access chains like db.user.findFirst\n if (expression.getKind() === SyntaxKind.PropertyAccessExpression) {\n return getPropertyAccessChainText(expression as PropertyAccessExpression)\n }\n\n // Handle simple function calls\n return expression.getText()\n}\n\n/**\n * Get the full text of a property access chain\n */\nfunction getPropertyAccessChainText(node: PropertyAccessExpression): string {\n const parts: string[] = []\n let current: Node = node\n\n while (current.getKind() === SyntaxKind.PropertyAccessExpression) {\n const propAccess = current as PropertyAccessExpression\n parts.unshift(propAccess.getName())\n current = propAccess.getExpression()\n }\n\n // Add the base expression\n parts.unshift(current.getText())\n\n return parts.join('.')\n}\n\n/**\n * Extract property access chains from a function\n */\nfunction extractPropertyAccessChains(node: FunctionLikeNode): string[] {\n const chains = new Set<string>()\n\n node.forEachDescendant((descendant, traversal) => {\n // Don't descend into nested functions\n const kind = descendant.getKind()\n if (\n kind === SyntaxKind.FunctionDeclaration ||\n kind === SyntaxKind.FunctionExpression ||\n kind === SyntaxKind.ArrowFunction ||\n kind === SyntaxKind.MethodDeclaration\n ) {\n traversal.skip()\n return\n }\n\n if (kind === SyntaxKind.PropertyAccessExpression) {\n const propAccess = descendant as PropertyAccessExpression\n // Only get top-level property access chains (not nested ones)\n const parent = propAccess.getParent()\n if (parent?.getKind() !== SyntaxKind.PropertyAccessExpression) {\n const chain = getPropertyAccessChainText(propAccess)\n // Filter out simple single-level access\n if (chain.includes('.')) {\n chains.add(chain)\n }\n }\n }\n })\n\n return Array.from(chains)\n}\n\n/**\n * Extract imports from a source file\n */\nexport function extractImports(sourceFile: SourceFile): FileImports {\n const filePath = sourceFile.getFilePath()\n const imports: FileImports['imports'] = []\n\n for (const importDecl of sourceFile.getImportDeclarations()) {\n const moduleSpecifier = importDecl.getModuleSpecifierValue()\n const namedImports: string[] = []\n\n // Get named imports\n for (const namedImport of importDecl.getNamedImports()) {\n namedImports.push(namedImport.getName())\n }\n\n // Get default import\n const defaultImport = importDecl.getDefaultImport()\n if (defaultImport) {\n namedImports.push(defaultImport.getText())\n }\n\n // Get namespace import\n const namespaceImport = importDecl.getNamespaceImport()\n if (namespaceImport) {\n namedImports.push(namespaceImport.getText())\n }\n\n imports.push({\n moduleSpecifier,\n namedImports,\n })\n }\n\n return {\n filePath,\n imports,\n }\n}\n\n/**\n * Check if a file is type-only (contains only types, interfaces, enums, no function bodies)\n */\nexport function isTypeOnlyFile(sourceFile: SourceFile): boolean {\n // Check for function declarations\n if (sourceFile.getFunctions().length > 0) return false\n\n // Check for classes with methods\n for (const classDecl of sourceFile.getClasses()) {\n if (classDecl.getMethods().length > 0) return false\n if (classDecl.getGetAccessors().length > 0) return false\n if (classDecl.getSetAccessors().length > 0) return false\n }\n\n // Check for variable declarations with functions\n for (const varStatement of sourceFile.getVariableStatements()) {\n for (const decl of varStatement.getDeclarations()) {\n const initializer = decl.getInitializer()\n if (initializer) {\n const kind = initializer.getKind()\n if (\n kind === SyntaxKind.ArrowFunction ||\n kind === SyntaxKind.FunctionExpression\n ) {\n return false\n }\n }\n }\n }\n\n // If we got here, file has no function bodies\n return true\n}\n","/**\n * Extractor - Shell layer for loading TypeScript projects via ts-morph\n *\n * This module handles the I/O of loading a TypeScript project from disk.\n * It's a thin shell that delegates to ts-morph for actual parsing.\n */\n\nimport { Project, SourceFile } from 'ts-morph'\nimport * as path from 'node:path'\nimport * as fs from 'node:fs'\n\n/**\n * Strips JSON comments (both line // and block /* comments)\n * This allows parsing tsconfig.json files that contain comments\n */\nexport function stripJsonComments(jsonString: string): string {\n let result = ''\n let inString = false\n let inLineComment = false\n let inBlockComment = false\n let i = 0\n\n while (i < jsonString.length) {\n const char = jsonString[i]\n const nextChar = jsonString[i + 1]\n\n // Handle string state (don't strip comments inside strings)\n if (!inLineComment && !inBlockComment && char === '\"') {\n // Check if this quote is escaped\n let backslashCount = 0\n let j = i - 1\n while (j >= 0 && jsonString[j] === '\\\\') {\n backslashCount++\n j--\n }\n if (backslashCount % 2 === 0) {\n inString = !inString\n }\n }\n\n if (inString) {\n result += char\n i++\n continue\n }\n\n // Handle line comment start\n if (!inBlockComment && char === '/' && nextChar === '/') {\n inLineComment = true\n i += 2\n continue\n }\n\n // Handle line comment end\n if (inLineComment && (char === '\\n' || char === '\\r')) {\n inLineComment = false\n result += char\n i++\n continue\n }\n\n // Handle block comment start\n if (!inLineComment && char === '/' && nextChar === '*') {\n inBlockComment = true\n i += 2\n continue\n }\n\n // Handle block comment end\n if (inBlockComment && char === '*' && nextChar === '/') {\n inBlockComment = false\n i += 2\n continue\n }\n\n // Add character if not in a comment\n if (!inLineComment && !inBlockComment) {\n result += char\n }\n\n i++\n }\n\n return result\n}\n\nexport type ExtractorOptions = {\n tsconfigPath: string\n filesGlob?: string\n}\n\nexport type ExtractorResult = {\n project: Project\n sourceFiles: SourceFile[]\n errors: { filePath: string; error: string }[]\n}\n\n/**\n * Loads a TypeScript project from a tsconfig.json path\n *\n * @param options - Configuration options for the extractor\n * @returns The loaded project and source files\n * @throws Error if tsconfig.json doesn't exist or is invalid\n */\nexport function loadProject(options: ExtractorOptions): ExtractorResult {\n const { tsconfigPath, filesGlob } = options\n const errors: { filePath: string; error: string }[] = []\n\n // Validate tsconfig exists\n const absoluteTsconfigPath = path.resolve(tsconfigPath)\n if (!fs.existsSync(absoluteTsconfigPath)) {\n throw new Error(`tsconfig.json not found at: ${absoluteTsconfigPath}`)\n }\n\n // Validate tsconfig is valid JSON (strip comments first since TypeScript allows them)\n try {\n const content = fs.readFileSync(absoluteTsconfigPath, 'utf-8')\n const strippedContent = stripJsonComments(content)\n JSON.parse(strippedContent)\n } catch (e) {\n throw new Error(\n `Invalid tsconfig.json at ${absoluteTsconfigPath}: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n\n // Create the ts-morph project\n const project = new Project({\n tsConfigFilePath: absoluteTsconfigPath,\n skipAddingFilesFromTsConfig: false,\n })\n\n // Get source files, filtering to .ts only (excluding .tsx for v1)\n let sourceFiles = project.getSourceFiles().filter(sf => {\n const filePath = sf.getFilePath()\n // Include only .ts files, exclude .tsx, .d.ts, test files, and generated files\n return (\n filePath.endsWith('.ts') &&\n !filePath.endsWith('.d.ts') &&\n !filePath.endsWith('.test.ts') &&\n !filePath.endsWith('.spec.ts') &&\n !filePath.includes('/node_modules/') &&\n !filePath.includes('/generated/')\n )\n })\n\n // Apply files glob filter if provided\n if (filesGlob) {\n const globPattern = createGlobMatcher(filesGlob)\n sourceFiles = sourceFiles.filter(sf => globPattern(sf.getFilePath()))\n }\n\n return {\n project,\n sourceFiles,\n errors,\n }\n}\n\n/**\n * Creates a simple glob matcher function\n * Supports basic glob patterns: *, **, ?\n */\nfunction createGlobMatcher(glob: string): (filePath: string) => boolean {\n // Convert glob to regex\n const regexStr = glob\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape special regex chars except * and ?\n .replace(/\\*\\*/g, '{{DOUBLE_STAR}}') // Placeholder for **\n .replace(/\\*/g, '[^/]*') // * matches anything except /\n .replace(/\\?/g, '.') // ? matches single char\n .replace(/\\{\\{DOUBLE_STAR\\}\\}/g, '.*') // ** matches anything including /\n\n const regex = new RegExp(regexStr)\n\n return (filePath: string) => regex.test(filePath)\n}\n\n/**\n * Gets the commit hash from git if available\n */\nexport function getCommitHash(): string | null {\n try {\n const { execSync } = require('node:child_process')\n const hash = execSync('git rev-parse HEAD', { encoding: 'utf-8' }).trim()\n return hash\n } catch {\n return null\n }\n}\n","/**\n * Marker Detection - Pure Core\n *\n * Detects impurity markers in extracted functions. This is a PURE module -\n * all functions take data in and return data out with no I/O.\n *\n * Marker categories:\n * - Async/Await: await expressions indicate I/O suspension\n * - Database: Prisma/db calls\n * - Network: fetch, axios, http calls\n * - File System: fs operations\n * - Environment: process.env access\n * - Logging: console, logger calls\n * - Queue/Events: enqueue, emit calls\n */\n\nimport type {\n DetectionContext,\n ExtractedFunction,\n ImpurityMarker,\n} from '../types.js'\n\n/**\n * Database operations that indicate impurity\n */\nconst DATABASE_OPERATIONS = new Set([\n 'findFirst',\n 'findMany',\n 'findUnique',\n 'findUniqueOrThrow',\n 'findFirstOrThrow',\n 'create',\n 'createMany',\n 'update',\n 'updateMany',\n 'delete',\n 'deleteMany',\n 'upsert',\n 'aggregate',\n 'count',\n 'groupBy',\n '$transaction',\n '$queryRaw',\n '$executeRaw',\n])\n\n/**\n * Telemetry/analytics patterns\n */\nconst TELEMETRY_PATTERNS = [\n /^track[A-Z]/,\n /^analytics\\./,\n /^segment\\./,\n /^mixpanel\\./,\n /^amplitude\\./,\n /^posthog\\./,\n /^gtag\\(/,\n /^ga\\(/,\n]\n\n/**\n * Detect all impurity markers in a function\n *\n * @param fn - The extracted function to analyze\n * @param context - Detection context including imports\n * @returns Array of detected impurity markers\n */\nexport function detectMarkers(\n fn: ExtractedFunction,\n context: DetectionContext,\n): ImpurityMarker[] {\n const markers: ImpurityMarker[] = []\n\n // Detect await expressions\n detectAwaitMarkers(fn, markers)\n\n // Detect database calls\n detectDatabaseMarkers(fn, markers)\n\n // Detect network calls\n detectNetworkMarkers(fn, context, markers)\n\n // Detect file system usage\n detectFileSystemMarkers(fn, context, markers)\n\n // Detect environment access\n detectEnvMarkers(fn, markers)\n\n // Detect logging\n detectLoggingMarkers(fn, context, markers)\n\n // Detect telemetry\n detectTelemetryMarkers(fn, markers)\n\n // Detect queue operations\n detectQueueMarkers(fn, markers)\n\n // Detect event emissions\n detectEventMarkers(fn, markers)\n\n return markers\n}\n\n/**\n * Detect await expressions\n */\nfunction detectAwaitMarkers(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n): void {\n if (fn.hasAwait) {\n // Find awaited call sites for details\n const awaitedCalls = fn.callSites.filter(cs => cs.isAwaited)\n if (awaitedCalls.length > 0) {\n for (const call of awaitedCalls) {\n markers.push({\n type: 'await-expression',\n detail: `await ${call.expression}`,\n line: call.line,\n })\n }\n } else {\n // Await on something other than a call (e.g., await promise variable)\n markers.push({\n type: 'await-expression',\n detail: 'await expression',\n })\n }\n }\n}\n\n/**\n * Detect database calls (Prisma pattern: db.<entity>.<operation>)\n */\nfunction detectDatabaseMarkers(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n): void {\n for (const callSite of fn.callSites) {\n if (isDatabaseCall(callSite.expression)) {\n markers.push({\n type: 'database-call',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n }\n}\n\n/**\n * Check if an expression is a database call\n */\nfunction isDatabaseCall(expression: string): boolean {\n // Match patterns like: db.user.findFirst, prisma.user.create, ctx.db.user.findMany\n const parts = expression.split('.')\n\n // Need at least 3 parts: db.entity.operation\n if (parts.length < 3) {\n // Check for direct prisma operations like prisma.$transaction\n if (parts.length === 2) {\n const [base, operation] = parts\n if (\n (base === 'db' || base === 'prisma') &&\n operation &&\n DATABASE_OPERATIONS.has(operation)\n ) {\n return true\n }\n }\n return false\n }\n\n // Check if any part is 'db' or 'prisma' and the last part is a database operation\n const lastPart = parts[parts.length - 1]\n if (!lastPart || !DATABASE_OPERATIONS.has(lastPart)) {\n return false\n }\n\n // Check for db or prisma in the chain\n return parts.some(\n part => part === 'db' || part === 'prisma' || part === 'database',\n )\n}\n\n/**\n * Detect network/HTTP calls\n *\n * Note: We only detect actual call sites, not file-level imports.\n * A function is only marked with network markers if it actually calls\n * fetch, axios, or other HTTP client functions.\n */\nfunction detectNetworkMarkers(\n fn: ExtractedFunction,\n _context: DetectionContext,\n markers: ImpurityMarker[],\n): void {\n // Check for fetch calls\n for (const callSite of fn.callSites) {\n if (\n callSite.expression === 'fetch' ||\n callSite.expression.endsWith('.fetch')\n ) {\n markers.push({\n type: 'network-fetch',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n\n // Check for axios calls\n if (\n callSite.expression.startsWith('axios') ||\n callSite.expression === 'axios'\n ) {\n markers.push({\n type: 'network-http',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n }\n}\n\n/**\n * Detect file system usage\n *\n * Note: We only detect actual call sites, not file-level imports.\n * A function is only marked with fs markers if it actually calls\n * fs functions like readFile, writeFile, etc.\n */\nfunction detectFileSystemMarkers(\n fn: ExtractedFunction,\n _context: DetectionContext,\n markers: ImpurityMarker[],\n): void {\n // Check for fs calls in the function\n for (const callSite of fn.callSites) {\n if (isFsCall(callSite.expression)) {\n markers.push({\n type: 'fs-call',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n }\n}\n\n/**\n * Check if an expression is a file system call\n */\nfunction isFsCall(expression: string): boolean {\n const parts = expression.split('.')\n return parts.some(\n part => part === 'fs' || part === 'readFile' || part === 'writeFile',\n )\n}\n\n/**\n * Detect environment variable access\n */\nfunction detectEnvMarkers(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n): void {\n for (const chain of fn.propertyAccessChains) {\n if (chain.startsWith('process.env')) {\n markers.push({\n type: 'env-access',\n detail: chain,\n })\n }\n }\n}\n\n/**\n * Detect logging calls\n *\n * Note: We only detect actual call sites, not file-level imports.\n * A function is only marked with logging markers if it actually calls\n * console.log, logger.info, log(), etc.\n */\nfunction detectLoggingMarkers(\n fn: ExtractedFunction,\n _context: DetectionContext,\n markers: ImpurityMarker[],\n): void {\n for (const callSite of fn.callSites) {\n // Console logging\n if (isConsoleLog(callSite.expression)) {\n markers.push({\n type: 'console-log',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n\n // Logger calls\n if (isLoggerCall(callSite.expression)) {\n markers.push({\n type: 'logging',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n }\n}\n\n/**\n * Check if an expression is a console.log call\n */\nfunction isConsoleLog(expression: string): boolean {\n return (\n expression === 'console.log' ||\n expression === 'console.error' ||\n expression === 'console.warn' ||\n expression === 'console.info' ||\n expression === 'console.debug'\n )\n}\n\n/**\n * Check if an expression is a logger call\n */\nfunction isLoggerCall(expression: string): boolean {\n const parts = expression.split('.')\n if (parts.length < 2) {\n return expression === 'log'\n }\n\n const base = parts[0]\n const method = parts[parts.length - 1]\n\n if (base === 'logger' || base === 'log') {\n return true\n }\n\n // Check for common logger methods\n const logMethods = new Set([\n 'info',\n 'warn',\n 'error',\n 'debug',\n 'trace',\n 'fatal',\n ])\n return (\n (parts.includes('logger') || parts.includes('log')) &&\n method !== undefined &&\n logMethods.has(method)\n )\n}\n\n/**\n * Detect telemetry/analytics calls\n */\nfunction detectTelemetryMarkers(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n): void {\n for (const callSite of fn.callSites) {\n if (isTelemetryCall(callSite.expression)) {\n markers.push({\n type: 'telemetry',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n }\n}\n\n/**\n * Check if an expression is a telemetry call\n */\nfunction isTelemetryCall(expression: string): boolean {\n return TELEMETRY_PATTERNS.some(pattern => pattern.test(expression))\n}\n\n/**\n * Detect queue operations\n */\nfunction detectQueueMarkers(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n): void {\n for (const callSite of fn.callSites) {\n if (isQueueCall(callSite.expression)) {\n markers.push({\n type: 'queue-enqueue',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n }\n}\n\n/**\n * Check if an expression is a queue operation\n */\nfunction isQueueCall(expression: string): boolean {\n return (\n expression.endsWith('.enqueue') ||\n expression.endsWith('.add') ||\n expression.endsWith('.publish') ||\n expression.includes('queue.') ||\n expression.includes('Queue.')\n )\n}\n\n/**\n * Detect event emissions\n */\nfunction detectEventMarkers(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n): void {\n for (const callSite of fn.callSites) {\n if (isEventEmit(callSite.expression)) {\n markers.push({\n type: 'event-emit',\n detail: callSite.expression,\n line: callSite.line,\n })\n }\n }\n}\n\n/**\n * Check if an expression is an event emission\n */\nfunction isEventEmit(expression: string): boolean {\n return (\n expression.endsWith('.emit') ||\n expression.endsWith('.dispatch') ||\n expression.endsWith('.trigger') ||\n expression.endsWith('.fire')\n )\n}\n\n/**\n * Create detection context from file imports\n */\nexport function createDetectionContext(\n imports: import('../types.js').FileImports,\n): DetectionContext {\n // Identify imports from .pure files\n const pureFileImports = new Set<string>()\n\n for (const imp of imports.imports) {\n if (\n imp.moduleSpecifier.endsWith('.pure') ||\n imp.moduleSpecifier.includes('.pure/')\n ) {\n pureFileImports.add(imp.moduleSpecifier)\n }\n }\n\n return {\n imports,\n pureFileImports,\n }\n}\n\n/**\n * Get the names of functions imported from .pure files\n */\nexport function getPureImportedFunctions(\n context: DetectionContext,\n): Set<string> {\n const pureFunctions = new Set<string>()\n\n for (const imp of context.imports.imports) {\n if (context.pureFileImports.has(imp.moduleSpecifier)) {\n for (const name of imp.namedImports) {\n pureFunctions.add(name)\n }\n }\n }\n\n return pureFunctions\n}\n","/**\n * Function Classifier - Pure Core\n *\n * Classifies functions as pure or impure based on their markers.\n * This is a PURE module - all functions take data in and return data out.\n *\n * Classification is binary and objective:\n * - Pure: Zero I/O markers\n * - Impure: Has one or more I/O markers\n *\n * Note: `async` without `await` (and without other I/O markers) is still pure.\n */\n\nimport type {\n ClassifiedFunction,\n ExtractedFunction,\n FunctionClassification,\n ImpurityMarker,\n Status,\n} from '../types.js'\n\n/**\n * Minimum statements for a function to be considered for scoring\n * Functions with fewer statements are considered trivial\n */\nconst TRIVIAL_STATEMENT_THRESHOLD = 3\n\n/**\n * Classify a function based on its markers\n *\n * @param fn - The extracted function\n * @param markers - Detected impurity markers\n * @returns The function classification ('pure' or 'impure')\n */\nexport function classifyFunction(\n _fn: ExtractedFunction,\n markers: ImpurityMarker[],\n): FunctionClassification {\n // A function is pure if it has no impurity markers\n if (markers.length === 0) {\n return 'pure'\n }\n\n return 'impure'\n}\n\n/**\n * Check if a function should be excluded from scoring\n *\n * Excluded functions:\n * - Trivial functions (< 3 statements and no conditionals)\n * - Test files (should already be filtered at extraction)\n * - Type-only files (should already be filtered at extraction)\n */\nexport function shouldExcludeFunction(fn: ExtractedFunction): boolean {\n // Exclude trivial functions: less than threshold statements and no conditionals\n if (fn.statementCount < TRIVIAL_STATEMENT_THRESHOLD && !fn.hasConditionals) {\n return true\n }\n\n return false\n}\n\n/**\n * Create a fully classified function with all computed properties\n *\n * @param fn - The extracted function\n * @param markers - Detected impurity markers\n * @param qualityScore - Quality score (null for pure functions)\n * @param status - Derived status\n * @returns A fully classified function\n */\nexport function createClassifiedFunction(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n qualityScore: number | null,\n status: Status,\n): ClassifiedFunction {\n const classification = classifyFunction(fn, markers)\n\n return {\n ...fn,\n markers,\n classification,\n qualityScore,\n status,\n }\n}\n\n/**\n * Batch classify multiple functions\n *\n * @param functions - Array of extracted functions with their markers\n * @returns Array of classified functions\n */\nexport function classifyFunctions(\n functions: Array<{\n fn: ExtractedFunction\n markers: ImpurityMarker[]\n qualityScore: number | null\n status: Status\n }>,\n): ClassifiedFunction[] {\n return functions.map(({ fn, markers, qualityScore, status }) =>\n createClassifiedFunction(fn, markers, qualityScore, status),\n )\n}\n\n/**\n * Partition functions into pure and impure\n *\n * @param functions - Array of classified functions\n * @returns Object with pure and impure function arrays\n */\nexport function partitionByClassification(functions: ClassifiedFunction[]): {\n pure: ClassifiedFunction[]\n impure: ClassifiedFunction[]\n} {\n const pure: ClassifiedFunction[] = []\n const impure: ClassifiedFunction[] = []\n\n for (const fn of functions) {\n if (fn.classification === 'pure') {\n pure.push(fn)\n } else {\n impure.push(fn)\n }\n }\n\n return { pure, impure }\n}\n\n/**\n * Get classification summary for a set of functions\n *\n * @param functions - Array of classified functions\n * @returns Summary statistics\n */\nexport function getClassificationSummary(functions: ClassifiedFunction[]): {\n total: number\n pureCount: number\n impureCount: number\n purityPercentage: number\n} {\n const total = functions.length\n const pureCount = functions.filter(f => f.classification === 'pure').length\n const impureCount = total - pureCount\n const purityPercentage = total > 0 ? (pureCount / total) * 100 : 100\n\n return {\n total,\n pureCount,\n impureCount,\n purityPercentage,\n }\n}\n","/**\n * Quality Scorer - Pure Core\n *\n * Computes quality scores (0-100) for impure functions measuring how\n * well-structured the impurity is. This is a PURE module - all functions\n * take data in and return data out with no I/O.\n *\n * Quality signals measure structural quality, not whether impurity exists.\n * A high score means the impure function is well-organized and maintainable.\n */\n\nimport type {\n CallSite,\n DetectionContext,\n ExtractedFunction,\n ImpurityMarker,\n MarkerType,\n} from '../types.js'\n\n/**\n * Quality scoring weights and thresholds\n */\nexport const QUALITY_WEIGHTS = {\n // Positive signals (additive)\n callsPureFile: 30, // Calls a function from .pure.ts file\n callsPureNamingConvention: 20, // Calls plan*/derive*/compute*/calculate*/transform*\n ioConcentratedAtStart: 15, // I/O calls concentrated at start (GATHER pattern)\n ioConcentratedAtEnd: 15, // I/O calls concentrated at end (EXECUTE pattern)\n lowComplexity: 10, // Low cyclomatic complexity (≤ 5)\n shellNamingConvention: 5, // Function name matches shell conventions\n callsPredicateFunctions: 5, // Calls is*/has*/should* functions\n\n // Negative signals (penalties)\n ioInterleaved: -20, // I/O calls interleaved throughout\n highComplexity: -15, // High cyclomatic complexity (> 10)\n multipleIoTypes: -10, // Multiple I/O types in same function\n noPureFunctionCalls: -10, // No pure function calls at all\n veryLongFunction: -10, // > 100 lines\n} as const\n\n/**\n * Pure function naming patterns\n */\nconst PURE_FUNCTION_PATTERNS = [\n /^plan[A-Z]/,\n /^derive[A-Z]/,\n /^compute[A-Z]/,\n /^calculate[A-Z]/,\n /^transform[A-Z]/,\n /^build[A-Z]/,\n /^create[A-Z](?!.*Service)/, // createX but not createXService\n /^parse[A-Z]/,\n /^format[A-Z]/,\n /^validate[A-Z]/,\n /^normalize[A-Z]/,\n /^convert[A-Z]/,\n /^map[A-Z]/,\n /^filter[A-Z]/,\n /^reduce[A-Z]/,\n /^merge[A-Z]/,\n /^extract[A-Z]/,\n /^to[A-Z]/, // toPublicX, toDTO, etc.\n]\n\n/**\n * Predicate function patterns (return boolean)\n */\nconst PREDICATE_PATTERNS = [\n /^is[A-Z]/,\n /^has[A-Z]/,\n /^should[A-Z]/,\n /^can[A-Z]/,\n /^will[A-Z]/,\n /^was[A-Z]/,\n /^did[A-Z]/,\n /^are[A-Z]/,\n /^does[A-Z]/,\n /^needs[A-Z]/,\n]\n\n/**\n * Shell function naming patterns\n */\nconst SHELL_FUNCTION_PATTERNS = [\n /^handle[A-Z]/,\n /^fetch[A-Z]/,\n /^save[A-Z]/,\n /^send[A-Z]/,\n /^load[A-Z]/,\n /^get[A-Z]/, // getData, getUser, etc.\n /^set[A-Z]/,\n /^update[A-Z]/,\n /^delete[A-Z]/,\n /^remove[A-Z]/,\n /^create[A-Z].*Service/, // createXService\n /^init[A-Z]/,\n /^process[A-Z]/,\n /^execute[A-Z]/,\n /^run[A-Z]/,\n /^perform[A-Z]/,\n]\n\n/**\n * I/O marker types for concentration analysis\n */\nconst IO_MARKER_TYPES: Set<MarkerType> = new Set([\n 'await-expression',\n 'database-call',\n 'network-fetch',\n 'network-http',\n 'fs-call',\n])\n\n/**\n * Compute quality score for an impure function\n *\n * @param fn - The extracted function data\n * @param markers - The detected impurity markers\n * @param context - Detection context with import information\n * @returns Quality score from 0-100\n */\nexport function computeQualityScore(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n context: DetectionContext,\n): number {\n let score = 50 // Start at neutral\n\n // Analyze the function and accumulate score adjustments\n const analysis = analyzeFunction(fn, markers, context)\n\n // Apply positive signals\n if (analysis.callsPureFile) {\n score += QUALITY_WEIGHTS.callsPureFile\n }\n if (analysis.callsPureNamingConvention) {\n score += QUALITY_WEIGHTS.callsPureNamingConvention\n }\n if (analysis.ioConcentratedAtStart) {\n score += QUALITY_WEIGHTS.ioConcentratedAtStart\n }\n if (analysis.ioConcentratedAtEnd) {\n score += QUALITY_WEIGHTS.ioConcentratedAtEnd\n }\n if (analysis.lowComplexity) {\n score += QUALITY_WEIGHTS.lowComplexity\n }\n if (analysis.shellNamingConvention) {\n score += QUALITY_WEIGHTS.shellNamingConvention\n }\n if (analysis.callsPredicateFunctions) {\n score += QUALITY_WEIGHTS.callsPredicateFunctions\n }\n\n // Apply negative signals (penalties)\n if (analysis.ioInterleaved) {\n score += QUALITY_WEIGHTS.ioInterleaved\n }\n if (analysis.highComplexity) {\n score += QUALITY_WEIGHTS.highComplexity\n }\n if (analysis.multipleIoTypes) {\n score += QUALITY_WEIGHTS.multipleIoTypes\n }\n if (analysis.noPureFunctionCalls) {\n score += QUALITY_WEIGHTS.noPureFunctionCalls\n }\n if (analysis.veryLongFunction) {\n score += QUALITY_WEIGHTS.veryLongFunction\n }\n\n // Clamp score to 0-100\n return Math.max(0, Math.min(100, score))\n}\n\n/**\n * Analysis result for a function\n */\nexport type FunctionAnalysis = {\n // Positive signals\n callsPureFile: boolean\n callsPureNamingConvention: boolean\n ioConcentratedAtStart: boolean\n ioConcentratedAtEnd: boolean\n lowComplexity: boolean\n shellNamingConvention: boolean\n callsPredicateFunctions: boolean\n\n // Negative signals\n ioInterleaved: boolean\n highComplexity: boolean\n multipleIoTypes: boolean\n noPureFunctionCalls: boolean\n veryLongFunction: boolean\n\n // Metrics\n estimatedComplexity: number\n ioMarkerCount: number\n uniqueIoTypes: Set<MarkerType>\n pureCallCount: number\n predicateCallCount: number\n}\n\n/**\n * Analyze a function for quality signals\n */\nexport function analyzeFunction(\n fn: ExtractedFunction,\n markers: ImpurityMarker[],\n context: DetectionContext,\n): FunctionAnalysis {\n // Get I/O markers with line information\n const ioMarkers = markers.filter(\n m => IO_MARKER_TYPES.has(m.type) && m.line !== undefined,\n )\n\n // Unique I/O types\n const uniqueIoTypes = new Set(markers.map(m => m.type))\n\n // Check for pure file imports being called\n const callsPureFile = checkCallsPureFile(fn, context)\n\n // Check for pure naming convention calls\n const { callsPureNaming, pureCallCount } = checkCallsPureNamingConvention(\n fn.callSites,\n )\n\n // Check for predicate function calls\n const { callsPredicates, predicateCallCount } = checkCallsPredicateFunctions(\n fn.callSites,\n )\n\n // Check I/O concentration\n const { concentratedAtStart, concentratedAtEnd, interleaved } =\n analyzeIoConcentration(fn, ioMarkers)\n\n // Estimate complexity\n const estimatedComplexity = estimateCyclomaticComplexity(fn)\n\n // Check shell naming convention\n const shellNamingConvention = checkShellNamingConvention(fn.name)\n\n return {\n callsPureFile,\n callsPureNamingConvention: callsPureNaming,\n ioConcentratedAtStart: concentratedAtStart,\n ioConcentratedAtEnd: concentratedAtEnd,\n lowComplexity: estimatedComplexity <= 5,\n shellNamingConvention,\n callsPredicateFunctions: callsPredicates,\n\n ioInterleaved: interleaved,\n highComplexity: estimatedComplexity > 10,\n multipleIoTypes: uniqueIoTypes.size >= 3,\n noPureFunctionCalls: pureCallCount === 0 && predicateCallCount === 0,\n veryLongFunction: fn.bodyLineCount > 100,\n\n estimatedComplexity,\n ioMarkerCount: ioMarkers.length,\n uniqueIoTypes,\n pureCallCount,\n predicateCallCount,\n }\n}\n\n/**\n * Check if function calls any imports from .pure files\n */\nfunction checkCallsPureFile(\n fn: ExtractedFunction,\n context: DetectionContext,\n): boolean {\n // Get names of functions imported from .pure files\n const pureImports = new Set<string>()\n for (const imp of context.imports.imports) {\n if (context.pureFileImports.has(imp.moduleSpecifier)) {\n for (const name of imp.namedImports) {\n pureImports.add(name)\n }\n }\n }\n\n // Check if any call site calls a pure import\n for (const callSite of fn.callSites) {\n const calledFn = extractFunctionName(callSite.expression)\n if (pureImports.has(calledFn)) {\n return true\n }\n }\n\n return false\n}\n\n/**\n * Check if function calls functions with pure naming conventions\n */\nfunction checkCallsPureNamingConvention(callSites: CallSite[]): {\n callsPureNaming: boolean\n pureCallCount: number\n} {\n let pureCallCount = 0\n\n for (const callSite of callSites) {\n const calledFn = extractFunctionName(callSite.expression)\n if (matchesAnyPattern(calledFn, PURE_FUNCTION_PATTERNS)) {\n pureCallCount++\n }\n }\n\n return {\n callsPureNaming: pureCallCount > 0,\n pureCallCount,\n }\n}\n\n/**\n * Check if function calls predicate functions\n */\nfunction checkCallsPredicateFunctions(callSites: CallSite[]): {\n callsPredicates: boolean\n predicateCallCount: number\n} {\n let predicateCallCount = 0\n\n for (const callSite of callSites) {\n const calledFn = extractFunctionName(callSite.expression)\n if (matchesAnyPattern(calledFn, PREDICATE_PATTERNS)) {\n predicateCallCount++\n }\n }\n\n return {\n callsPredicates: predicateCallCount > 0,\n predicateCallCount,\n }\n}\n\n/**\n * Analyze I/O concentration within a function\n *\n * Good FCIS patterns:\n * - GATHER: I/O at the start, then pure logic\n * - EXECUTE: Pure logic, then I/O at the end\n * - GATHER-DECIDE-EXECUTE: I/O at start, pure in middle, I/O at end\n *\n * Bad pattern:\n * - Interleaved: I/O calls scattered throughout\n */\nfunction analyzeIoConcentration(\n fn: ExtractedFunction,\n ioMarkers: ImpurityMarker[],\n): {\n concentratedAtStart: boolean\n concentratedAtEnd: boolean\n interleaved: boolean\n} {\n if (ioMarkers.length === 0) {\n return {\n concentratedAtStart: false,\n concentratedAtEnd: false,\n interleaved: false,\n }\n }\n\n // Get I/O positions as percentages through the function\n const positions = ioMarkers\n .map(m => (m.line ?? 0) / Math.max(fn.bodyLineCount, 1))\n .sort((a, b) => a - b)\n\n // Calculate concentration metrics\n const startThreshold = 0.33 // First third\n const endThreshold = 0.67 // Last third\n\n const atStart = positions.filter(p => p <= startThreshold).length\n const atEnd = positions.filter(p => p >= endThreshold).length\n const inMiddle = positions.filter(\n p => p > startThreshold && p < endThreshold,\n ).length\n\n const total = positions.length\n\n // Concentrated at start: most I/O in first third\n const concentratedAtStart = atStart >= total * 0.6 && inMiddle <= 1\n\n // Concentrated at end: most I/O in last third\n const concentratedAtEnd = atEnd >= total * 0.6 && inMiddle <= 1\n\n // Interleaved: I/O scattered throughout\n // Consider it interleaved if there's significant I/O in all sections\n // or if there are many transitions between I/O and non-I/O regions\n const interleaved =\n inMiddle >= 2 ||\n (atStart > 0 && atEnd > 0 && inMiddle > 0) ||\n (total >= 4 && !concentratedAtStart && !concentratedAtEnd)\n\n return {\n concentratedAtStart,\n concentratedAtEnd,\n interleaved,\n }\n}\n\n/**\n * Estimate cyclomatic complexity from extracted function data\n *\n * Cyclomatic complexity = 1 + number of decision points\n * Since we don't have full AST access here, we estimate based on:\n * - hasConditionals flag\n * - statement count\n * - body line count\n */\nfunction estimateCyclomaticComplexity(fn: ExtractedFunction): number {\n let complexity = 1 // Base complexity\n\n // If has conditionals, estimate based on statement density\n if (fn.hasConditionals) {\n // Rough estimate: conditionals add 1-2 per ~10 statements\n complexity += Math.ceil(fn.statementCount / 10)\n }\n\n // Factor in line count for very long functions\n if (fn.bodyLineCount > 50) {\n complexity += Math.floor((fn.bodyLineCount - 50) / 25)\n }\n\n return complexity\n}\n\n/**\n * Check if function name matches shell naming conventions\n */\nfunction checkShellNamingConvention(name: string | null): boolean {\n if (!name) return false\n return matchesAnyPattern(name, SHELL_FUNCTION_PATTERNS)\n}\n\n/**\n * Extract the function name from a call expression\n * e.g., \"db.user.findFirst\" -> \"findFirst\"\n * \"planAcceptInvite\" -> \"planAcceptInvite\"\n * \"this.validate\" -> \"validate\"\n */\nfunction extractFunctionName(expression: string): string {\n const parts = expression.split('.')\n return parts[parts.length - 1] ?? expression\n}\n\n/**\n * Check if a string matches any of the given patterns\n */\nfunction matchesAnyPattern(str: string, patterns: RegExp[]): boolean {\n return patterns.some(pattern => pattern.test(str))\n}\n\n/**\n * Get quality score interpretation\n */\nexport function interpretQualityScore(score: number): {\n level: 'high' | 'medium' | 'low'\n description: string\n} {\n if (score >= 70) {\n return {\n level: 'high',\n description:\n 'Well-structured impure function. I/O is organized and pure logic is separated.',\n }\n } else if (score >= 40) {\n return {\n level: 'medium',\n description:\n 'Moderately structured. Could benefit from extracting pure logic.',\n }\n } else {\n return {\n level: 'low',\n description:\n 'Tangled structure. Business logic mixed with I/O. Consider refactoring.',\n }\n }\n}\n","/**\n * Status Derivation - Pure Core\n *\n * Derives actionable status from classification and quality score.\n * This is a PURE module - all functions take data in and return data out with no I/O.\n *\n * Status provides developer guidance:\n * - ok: No action needed (pure function, or well-structured impure function)\n * - review: Consider improving if touching this code\n * - refactor: Tangled code, prioritize cleanup\n */\n\nimport type {\n ClassifiedFunction,\n FunctionClassification,\n QualityThresholds,\n Status,\n} from '../types.js'\nimport { DEFAULT_QUALITY_THRESHOLDS } from '../types.js'\n\n/**\n * Derive status from classification and quality score\n *\n * Status rules:\n * - Pure functions always get 'ok' (testable without mocks)\n * - Impure functions with quality >= okThreshold (default 70) get 'ok'\n * - Impure functions with quality >= reviewThreshold (default 40) get 'review'\n * - Impure functions with quality < reviewThreshold get 'refactor'\n *\n * @param classification - 'pure' or 'impure'\n * @param qualityScore - Quality score for impure functions (0-100), null for pure\n * @param thresholds - Optional custom thresholds\n * @returns Status: 'ok' | 'review' | 'refactor'\n */\nexport function deriveStatus(\n classification: FunctionClassification,\n qualityScore: number | null,\n thresholds: QualityThresholds = DEFAULT_QUALITY_THRESHOLDS,\n): Status {\n // Pure functions are always ok - testable without mocks\n if (classification === 'pure') {\n return 'ok'\n }\n\n // Impure functions need quality score evaluation\n if (qualityScore === null) {\n // This shouldn't happen for impure functions, but handle defensively\n return 'review'\n }\n\n if (qualityScore >= thresholds.okThreshold) {\n return 'ok'\n }\n\n if (qualityScore >= thresholds.reviewThreshold) {\n return 'review'\n }\n\n return 'refactor'\n}\n\n/**\n * Get status description for display\n */\nexport function getStatusDescription(status: Status): string {\n switch (status) {\n case 'ok':\n return 'No action needed'\n case 'review':\n return 'Consider improving if touching this code'\n case 'refactor':\n return 'Tangled code, prioritize cleanup'\n }\n}\n\n/**\n * Get status emoji for display\n */\nexport function getStatusEmoji(status: Status): string {\n switch (status) {\n case 'ok':\n return '✓'\n case 'review':\n return '◐'\n case 'refactor':\n return '✗'\n }\n}\n\n/**\n * Get status color for terminal display\n */\nexport function getStatusColor(status: Status): 'green' | 'yellow' | 'red' {\n switch (status) {\n case 'ok':\n return 'green'\n case 'review':\n return 'yellow'\n case 'refactor':\n return 'red'\n }\n}\n\n/**\n * Check if a classified function should be flagged for attention\n * (status is 'review' or 'refactor')\n */\nexport function needsAttention(fn: ClassifiedFunction): boolean {\n return fn.status === 'review' || fn.status === 'refactor'\n}\n\n/**\n * Check if a classified function is in good standing\n * (status is 'ok')\n */\nexport function isOk(fn: ClassifiedFunction): boolean {\n return fn.status === 'ok'\n}\n\n/**\n * Sort functions by status priority (refactor first, then review, then ok)\n */\nexport function sortByStatusPriority(\n functions: ClassifiedFunction[],\n): ClassifiedFunction[] {\n const priorityMap: Record<Status, number> = {\n refactor: 0,\n review: 1,\n ok: 2,\n }\n\n return [...functions].sort((a, b) => {\n const priorityDiff = priorityMap[a.status] - priorityMap[b.status]\n if (priorityDiff !== 0) return priorityDiff\n\n // Secondary sort by quality score (lower first for impure functions)\n if (a.qualityScore !== null && b.qualityScore !== null) {\n return a.qualityScore - b.qualityScore\n }\n\n // Tertiary sort by body line count (larger first)\n return b.bodyLineCount - a.bodyLineCount\n })\n}\n\n/**\n * Validate threshold configuration\n */\nexport function validateThresholds(thresholds: QualityThresholds): {\n valid: boolean\n errors: string[]\n} {\n const errors: string[] = []\n\n if (thresholds.okThreshold < 0 || thresholds.okThreshold > 100) {\n errors.push('okThreshold must be between 0 and 100')\n }\n\n if (thresholds.reviewThreshold < 0 || thresholds.reviewThreshold > 100) {\n errors.push('reviewThreshold must be between 0 and 100')\n }\n\n if (thresholds.reviewThreshold >= thresholds.okThreshold) {\n errors.push('reviewThreshold must be less than okThreshold')\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}\n","/**\n * Scoring Engine - Pure Core\n *\n * Aggregates classification and quality scores into metrics at\n * file, directory, and project levels. This is a PURE module -\n * all functions take data in and return data out with no I/O.\n *\n * Metrics:\n * - Purity: percentage of pure functions\n * - Impurity Quality: average quality score of impure functions\n * - Health: percentage of functions with status 'ok'\n */\n\nimport type {\n ClassifiedFunction,\n DirectoryScore,\n FileScore,\n ProjectScore,\n RefactoringCandidate,\n StatusBreakdown,\n} from '../types.js'\n\n/**\n * Score a single file based on its classified functions\n *\n * @param filePath - Path to the file\n * @param functions - Classified functions from the file\n * @param isTypeOnly - Whether the file contains only types\n * @returns FileScore with all computed metrics\n */\nexport function scoreFile(\n filePath: string,\n functions: ClassifiedFunction[],\n isTypeOnly: boolean = false,\n): FileScore {\n // Handle type-only files\n if (isTypeOnly) {\n return {\n filePath,\n purity: 100,\n impurityQuality: null,\n health: 100,\n pureCount: 0,\n impureCount: 0,\n excludedCount: 0,\n statusBreakdown: { ok: 0, review: 0, refactor: 0 },\n pureLineCount: 0,\n impureLineCount: 0,\n functions: [],\n refactoringCandidates: [],\n typeOnly: true,\n }\n }\n\n // Partition functions by classification\n const pureFunctions = functions.filter(f => f.classification === 'pure')\n const impureFunctions = functions.filter(f => f.classification === 'impure')\n\n const pureCount = pureFunctions.length\n const impureCount = impureFunctions.length\n const total = pureCount + impureCount\n\n // Handle empty files\n if (total === 0) {\n return {\n filePath,\n purity: 100,\n impurityQuality: null,\n health: 100,\n pureCount: 0,\n impureCount: 0,\n excludedCount: 0,\n statusBreakdown: { ok: 0, review: 0, refactor: 0 },\n pureLineCount: 0,\n impureLineCount: 0,\n functions: [],\n refactoringCandidates: [],\n allExcluded: true,\n }\n }\n\n // Calculate purity (percentage of pure functions)\n const purity = (pureCount / total) * 100\n\n // Calculate impurity quality (average quality of impure functions)\n let impurityQuality: number | null = null\n if (impureCount > 0) {\n const totalQuality = impureFunctions.reduce(\n (sum, f) => sum + (f.qualityScore ?? 0),\n 0,\n )\n impurityQuality = totalQuality / impureCount\n }\n\n // Calculate status breakdown\n const statusBreakdown: StatusBreakdown = {\n ok: functions.filter(f => f.status === 'ok').length,\n review: functions.filter(f => f.status === 'review').length,\n refactor: functions.filter(f => f.status === 'refactor').length,\n }\n\n // Calculate health (percentage with status 'ok')\n const health = (statusBreakdown.ok / total) * 100\n\n // Calculate line counts\n const pureLineCount = pureFunctions.reduce(\n (sum, f) => sum + f.bodyLineCount,\n 0,\n )\n const impureLineCount = impureFunctions.reduce(\n (sum, f) => sum + f.bodyLineCount,\n 0,\n )\n\n // Get refactoring candidates (functions with status 'refactor')\n // Sorted by impact: bodyLineCount × (100 - qualityScore) descending\n const refactoringCandidates = impureFunctions\n .filter(f => f.status === 'refactor')\n .map(f => ({\n name: f.name,\n startLine: f.startLine,\n bodyLineCount: f.bodyLineCount,\n qualityScore: f.qualityScore ?? 0,\n markers: f.markers.map(m => m.type),\n }))\n .sort((a, b) => {\n const impactA = a.bodyLineCount * (100 - a.qualityScore)\n const impactB = b.bodyLineCount * (100 - b.qualityScore)\n return impactB - impactA\n })\n\n return {\n filePath,\n purity,\n impurityQuality,\n health,\n pureCount,\n impureCount,\n excludedCount: 0,\n statusBreakdown,\n pureLineCount,\n impureLineCount,\n functions,\n refactoringCandidates,\n }\n}\n\n/**\n * Score a directory by aggregating its file scores\n *\n * @param dirPath - Path to the directory\n * @param fileScores - Scores for all files in the directory\n * @returns DirectoryScore with weighted averages\n */\nexport function scoreDirectory(\n dirPath: string,\n fileScores: FileScore[],\n): DirectoryScore {\n // Filter out type-only and empty files for aggregation\n const scorableFiles = fileScores.filter(\n f => !f.typeOnly && !f.allExcluded && f.pureCount + f.impureCount > 0,\n )\n\n if (scorableFiles.length === 0) {\n return {\n dirPath,\n purity: 100,\n impurityQuality: null,\n health: 100,\n pureCount: 0,\n impureCount: 0,\n excludedCount: fileScores.reduce((sum, f) => sum + f.excludedCount, 0),\n statusBreakdown: { ok: 0, review: 0, refactor: 0 },\n pureLineCount: 0,\n impureLineCount: 0,\n fileScores,\n }\n }\n\n // Calculate totals\n const totalPure = scorableFiles.reduce((sum, f) => sum + f.pureCount, 0)\n const totalImpure = scorableFiles.reduce((sum, f) => sum + f.impureCount, 0)\n const total = totalPure + totalImpure\n\n // Weighted purity by function count\n const purity = total > 0 ? (totalPure / total) * 100 : 100\n\n // Weighted impurity quality\n let impurityQuality: number | null = null\n if (totalImpure > 0) {\n const weightedQuality = scorableFiles.reduce((sum, f) => {\n if (f.impurityQuality !== null && f.impureCount > 0) {\n return sum + f.impurityQuality * f.impureCount\n }\n return sum\n }, 0)\n impurityQuality = weightedQuality / totalImpure\n }\n\n // Aggregate status breakdown\n const statusBreakdown: StatusBreakdown = {\n ok: scorableFiles.reduce((sum, f) => sum + f.statusBreakdown.ok, 0),\n review: scorableFiles.reduce((sum, f) => sum + f.statusBreakdown.review, 0),\n refactor: scorableFiles.reduce(\n (sum, f) => sum + f.statusBreakdown.refactor,\n 0,\n ),\n }\n\n // Calculate health\n const health = total > 0 ? (statusBreakdown.ok / total) * 100 : 100\n\n // Aggregate line counts\n const pureLineCount = scorableFiles.reduce(\n (sum, f) => sum + f.pureLineCount,\n 0,\n )\n const impureLineCount = scorableFiles.reduce(\n (sum, f) => sum + f.impureLineCount,\n 0,\n )\n\n return {\n dirPath,\n purity,\n impurityQuality,\n health,\n pureCount: totalPure,\n impureCount: totalImpure,\n excludedCount: fileScores.reduce((sum, f) => sum + f.excludedCount, 0),\n statusBreakdown,\n pureLineCount,\n impureLineCount,\n fileScores,\n }\n}\n\n/**\n * Score an entire project by aggregating directory scores\n *\n * @param directoryScores - Scores for all directories in the project\n * @param options - Additional options for the project score\n * @returns ProjectScore with all metrics\n */\nexport function scoreProject(\n directoryScores: DirectoryScore[],\n options: {\n timestamp?: string\n commitHash?: string | null\n subset?: boolean\n filesGlob?: string\n errors?: { filePath: string; error: string }[]\n } = {},\n): ProjectScore {\n const {\n timestamp = new Date().toISOString(),\n commitHash = null,\n subset = false,\n filesGlob,\n errors = [],\n } = options\n\n // Filter directories with actual functions\n const scorableDirs = directoryScores.filter(\n d => d.pureCount + d.impureCount > 0,\n )\n\n if (scorableDirs.length === 0) {\n return {\n purity: 100,\n impurityQuality: null,\n health: 100,\n pureCount: 0,\n impureCount: 0,\n excludedCount: directoryScores.reduce(\n (sum, d) => sum + d.excludedCount,\n 0,\n ),\n statusBreakdown: { ok: 0, review: 0, refactor: 0 },\n pureLineCount: 0,\n impureLineCount: 0,\n directoryScores,\n timestamp,\n commitHash,\n refactoringCandidates: [],\n allExcluded: true,\n ...(subset && { subset: true, filesGlob }),\n ...(errors.length > 0 && { errors }),\n }\n }\n\n // Calculate totals\n const totalPure = scorableDirs.reduce((sum, d) => sum + d.pureCount, 0)\n const totalImpure = scorableDirs.reduce((sum, d) => sum + d.impureCount, 0)\n const total = totalPure + totalImpure\n\n // Weighted purity by function count\n const purity = total > 0 ? (totalPure / total) * 100 : 100\n\n // Weighted impurity quality\n let impurityQuality: number | null = null\n if (totalImpure > 0) {\n const weightedQuality = scorableDirs.reduce((sum, d) => {\n if (d.impurityQuality !== null && d.impureCount > 0) {\n return sum + d.impurityQuality * d.impureCount\n }\n return sum\n }, 0)\n impurityQuality = weightedQuality / totalImpure\n }\n\n // Aggregate status breakdown\n const statusBreakdown: StatusBreakdown = {\n ok: scorableDirs.reduce((sum, d) => sum + d.statusBreakdown.ok, 0),\n review: scorableDirs.reduce((sum, d) => sum + d.statusBreakdown.review, 0),\n refactor: scorableDirs.reduce(\n (sum, d) => sum + d.statusBreakdown.refactor,\n 0,\n ),\n }\n\n // Calculate health\n const health = total > 0 ? (statusBreakdown.ok / total) * 100 : 100\n\n // Aggregate line counts\n const pureLineCount = scorableDirs.reduce(\n (sum, d) => sum + d.pureLineCount,\n 0,\n )\n const impureLineCount = scorableDirs.reduce(\n (sum, d) => sum + d.impureLineCount,\n 0,\n )\n\n // Collect all refactoring candidates across all files\n const allCandidates: RefactoringCandidate[] = []\n for (const dir of directoryScores) {\n for (const file of dir.fileScores) {\n for (const candidate of file.refactoringCandidates) {\n allCandidates.push({\n ...candidate,\n filePath: file.filePath,\n })\n }\n }\n }\n\n // Sort by impact: bodyLineCount × (100 - qualityScore) descending\n const refactoringCandidates = allCandidates.sort((a, b) => {\n const impactA = a.bodyLineCount * (100 - a.qualityScore)\n const impactB = b.bodyLineCount * (100 - b.qualityScore)\n return impactB - impactA\n })\n\n const result: ProjectScore = {\n purity,\n impurityQuality,\n health,\n pureCount: totalPure,\n impureCount: totalImpure,\n excludedCount: directoryScores.reduce((sum, d) => sum + d.excludedCount, 0),\n statusBreakdown,\n pureLineCount,\n impureLineCount,\n directoryScores,\n timestamp,\n commitHash,\n refactoringCandidates,\n }\n\n if (subset && filesGlob !== undefined) {\n result.subset = true\n result.filesGlob = filesGlob\n }\n\n if (errors.length > 0) {\n result.errors = errors\n }\n\n return result\n}\n\n/**\n * Group file scores by directory\n *\n * @param fileScores - Array of file scores\n * @returns Map of directory path to file scores\n */\nexport function groupFilesByDirectory(\n fileScores: FileScore[],\n): Map<string, FileScore[]> {\n const groups = new Map<string, FileScore[]>()\n\n for (const fileScore of fileScores) {\n const dirPath = getDirectoryPath(fileScore.filePath)\n const existing = groups.get(dirPath)\n if (existing) {\n existing.push(fileScore)\n } else {\n groups.set(dirPath, [fileScore])\n }\n }\n\n return groups\n}\n\n/**\n * Get directory path from file path\n */\nfunction getDirectoryPath(filePath: string): string {\n const lastSlash = filePath.lastIndexOf('/')\n if (lastSlash === -1) return '.'\n return filePath.slice(0, lastSlash)\n}\n\n/**\n * Calculate delta between two project scores\n *\n * @param current - Current project score\n * @param previous - Previous project score\n * @returns Delta metrics\n */\nexport function calculateDelta(\n current: ProjectScore,\n previous: ProjectScore,\n): {\n purityDelta: number\n impurityQualityDelta: number | null\n healthDelta: number\n pureCountDelta: number\n impureCountDelta: number\n} {\n return {\n purityDelta: current.purity - previous.purity,\n impurityQualityDelta:\n current.impurityQuality !== null && previous.impurityQuality !== null\n ? current.impurityQuality - previous.impurityQuality\n : null,\n healthDelta: current.health - previous.health,\n pureCountDelta: current.pureCount - previous.pureCount,\n impureCountDelta: current.impureCount - previous.impureCount,\n }\n}\n\n/**\n * Get diagnostic insights based on metrics\n *\n * @param score - Project or file score\n * @returns Array of insight messages\n */\nexport function getDiagnosticInsights(\n score: Pick<ProjectScore, 'purity' | 'impurityQuality' | 'health'>,\n): string[] {\n const insights: string[] = []\n\n // High purity + low impurity quality\n if (\n score.purity >= 60 &&\n score.impurityQuality !== null &&\n score.impurityQuality < 50\n ) {\n insights.push(\n 'Most code is pure, but the impure code is tangled. Focus on improving the structure of impure functions.',\n )\n }\n\n // Low purity + high impurity quality\n if (\n score.purity < 40 &&\n score.impurityQuality !== null &&\n score.impurityQuality >= 70\n ) {\n insights.push(\n \"Lots of I/O code, but it's well-structured. Consider extracting more pure business logic.\",\n )\n }\n\n // Low purity + low impurity quality\n if (\n score.purity < 40 &&\n score.impurityQuality !== null &&\n score.impurityQuality < 50\n ) {\n insights.push(\n 'Significant technical debt in I/O code. Both purity and structure need improvement.',\n )\n }\n\n // High health with low purity\n if (score.health >= 80 && score.purity < 50) {\n insights.push(\n 'Despite low purity, impure functions are well-structured. Good FCIS patterns in shell code.',\n )\n }\n\n // Low health\n if (score.health < 50) {\n insights.push(\n 'More than half of functions need attention. Prioritize refactoring candidates.',\n )\n }\n\n return insights\n}\n","/**\n * Analyzer - Main Orchestration Layer (Shell)\n *\n * This module orchestrates the full analysis pipeline:\n * 1. Load project via ts-morph\n * 2. Extract functions from source files\n * 3. Detect impurity markers\n * 4. Classify functions\n * 5. Compute quality scores\n * 6. Aggregate into file, directory, and project scores\n *\n * This is a SHELL module - it coordinates I/O and calls pure functions.\n */\n\nimport type { SourceFile } from 'ts-morph'\n\nimport type {\n AnalysisError,\n AnalyzerConfig,\n ClassifiedFunction,\n DirectoryScore,\n FileScore,\n ProjectScore,\n} from './types.js'\nimport { DEFAULT_QUALITY_THRESHOLDS } from './types.js'\n\nimport {\n extractFunctions,\n extractImports,\n isTypeOnlyFile,\n} from './extraction/extract-functions.js'\nimport { loadProject, getCommitHash } from './extraction/extractor.js'\nimport {\n detectMarkers,\n createDetectionContext,\n} from './detection/detect-markers.js'\nimport {\n classifyFunction,\n shouldExcludeFunction,\n createClassifiedFunction,\n} from './classification/classifier.js'\nimport { computeQualityScore } from './classification/quality-scorer.js'\nimport { deriveStatus } from './classification/derive-status.js'\nimport {\n scoreFile,\n scoreDirectory,\n scoreProject,\n groupFilesByDirectory,\n} from './scoring/scorer.js'\n\n/**\n * Run the full analysis pipeline\n *\n * @param config - Analyzer configuration\n * @returns Project score with all metrics\n */\nexport async function analyze(config: AnalyzerConfig): Promise<ProjectScore> {\n const errors: AnalysisError[] = []\n\n // Step 1: Load project\n const extractorOptions: { tsconfigPath: string; filesGlob?: string } = {\n tsconfigPath: config.tsconfigPath,\n }\n if (config.filesGlob !== undefined) {\n extractorOptions.filesGlob = config.filesGlob\n }\n const { sourceFiles } = loadProject(extractorOptions)\n\n if (sourceFiles.length === 0) {\n throw new Error('No source files found to analyze')\n }\n\n // Step 2-5: Extract, detect, classify each file\n const fileScores: FileScore[] = []\n\n for (const sourceFile of sourceFiles) {\n try {\n const fileScore = analyzeFile(sourceFile)\n fileScores.push(fileScore)\n } catch (error) {\n errors.push({\n filePath: sourceFile.getFilePath(),\n error: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n // Check if any files were successfully analyzed\n if (fileScores.length === 0 && errors.length > 0) {\n throw new Error(\n `Failed to analyze any files. ${errors.length} files had errors.`,\n )\n }\n\n // Step 6: Aggregate into directory scores\n const directoryGroups = groupFilesByDirectory(fileScores)\n const directoryScores: DirectoryScore[] = []\n\n for (const [dirPath, files] of directoryGroups) {\n const dirScore = scoreDirectory(dirPath, files)\n directoryScores.push(dirScore)\n }\n\n // Sort directories by path for consistent output\n directoryScores.sort((a, b) => a.dirPath.localeCompare(b.dirPath))\n\n // Step 7: Aggregate into project score\n const projectOptions: {\n timestamp?: string\n commitHash?: string | null\n subset?: boolean\n filesGlob?: string\n errors?: { filePath: string; error: string }[]\n } = {\n timestamp: new Date().toISOString(),\n commitHash: getCommitHash(),\n }\n\n if (config.filesGlob !== undefined) {\n projectOptions.subset = true\n projectOptions.filesGlob = config.filesGlob\n }\n\n if (errors.length > 0) {\n projectOptions.errors = errors\n }\n\n const projectScore = scoreProject(directoryScores, projectOptions)\n\n return projectScore\n}\n\n/**\n * Analyze a single source file\n *\n * @param sourceFile - The ts-morph source file to analyze\n * @returns FileScore with all metrics\n */\nexport function analyzeFile(sourceFile: SourceFile): FileScore {\n const filePath = sourceFile.getFilePath()\n\n // Check if type-only file\n if (isTypeOnlyFile(sourceFile)) {\n return scoreFile(filePath, [], true)\n }\n\n // Extract functions and imports\n const functions = extractFunctions(sourceFile)\n const imports = extractImports(sourceFile)\n\n // Create detection context\n const context = createDetectionContext(imports)\n\n // Classify each function\n const classifiedFunctions: ClassifiedFunction[] = []\n\n for (const fn of functions) {\n // Check if function should be excluded\n if (shouldExcludeFunction(fn)) {\n continue\n }\n\n // Detect markers\n const markers = detectMarkers(fn, context)\n\n // Classify\n const classification = classifyFunction(fn, markers)\n\n // Compute quality score (only for impure functions)\n let qualityScore: number | null = null\n if (classification === 'impure') {\n qualityScore = computeQualityScore(fn, markers, context)\n }\n\n // Derive status\n const status = deriveStatus(\n classification,\n qualityScore,\n DEFAULT_QUALITY_THRESHOLDS,\n )\n\n // Create classified function\n const classifiedFn = createClassifiedFunction(\n fn,\n markers,\n qualityScore,\n status,\n )\n classifiedFunctions.push(classifiedFn)\n }\n\n // Score the file\n return scoreFile(filePath, classifiedFunctions, false)\n}\n\n/**\n * Analyze a single file from a file path (convenience function)\n *\n * @param tsconfigPath - Path to tsconfig.json\n * @param filePath - Path to the file to analyze\n * @returns FileScore with all metrics\n */\nexport async function analyzeFilePath(\n tsconfigPath: string,\n filePath: string,\n): Promise<FileScore | null> {\n const { sourceFiles } = loadProject({\n tsconfigPath,\n filesGlob: filePath,\n })\n\n if (sourceFiles.length === 0) {\n return null\n }\n\n const sourceFile = sourceFiles[0]\n if (!sourceFile) {\n return null\n }\n\n return analyzeFile(sourceFile)\n}\n\n/**\n * Check if analysis passes thresholds\n *\n * @param score - Project score to check\n * @param config - Configuration with threshold values\n * @returns Object indicating pass/fail status and messages\n */\nexport function checkThresholds(\n score: ProjectScore,\n config: Pick<AnalyzerConfig, 'minHealth' | 'minPurity' | 'minQuality'>,\n): {\n passed: boolean\n failures: string[]\n} {\n const failures: string[] = []\n\n if (config.minHealth !== undefined && score.health < config.minHealth) {\n failures.push(\n `Health ${score.health.toFixed(1)}% is below minimum ${config.minHealth}%`,\n )\n }\n\n if (config.minPurity !== undefined && score.purity < config.minPurity) {\n failures.push(\n `Purity ${score.purity.toFixed(1)}% is below minimum ${config.minPurity}%`,\n )\n }\n\n if (\n config.minQuality !== undefined &&\n score.impurityQuality !== null &&\n score.impurityQuality < config.minQuality\n ) {\n failures.push(\n `Impurity Quality ${score.impurityQuality.toFixed(1)}% is below minimum ${config.minQuality}%`,\n )\n }\n\n return {\n passed: failures.length === 0,\n failures,\n }\n}\n","/**\n * Console Report Generator - Shell Layer\n *\n * Produces human-readable console output with colors, visual bars,\n * and formatted tables. This is part of the SHELL layer as it\n * performs I/O (writing to console).\n */\n\nimport chalk from 'chalk'\nimport * as path from 'node:path'\n\nimport type {\n DirectoryScore,\n FileScore,\n ProjectScore,\n RefactoringCandidate,\n StatusBreakdown,\n} from '../types.js'\nimport { getDiagnosticInsights } from '../scoring/scorer.js'\nimport {\n getStatusColor,\n getStatusEmoji,\n} from '../classification/derive-status.js'\n\n/**\n * Generate and print the full console report\n */\nexport function printConsoleReport(\n score: ProjectScore,\n options: { verbose?: boolean } = {},\n): void {\n const { verbose = false } = options\n\n printHeader()\n printProjectSummary(score)\n printStatusBreakdown(\n score.statusBreakdown,\n score.pureCount + score.impureCount,\n )\n printInsights(score)\n\n if (verbose) {\n printDirectoryBreakdown(score.directoryScores)\n } else {\n printWorstDirectories(score.directoryScores)\n }\n\n printRefactoringCandidates(score.refactoringCandidates.slice(0, 10))\n\n if (score.errors && score.errors.length > 0) {\n printErrors(score.errors)\n }\n\n printFooter(score)\n}\n\n/**\n * Print the report header\n */\nfunction printHeader(): void {\n console.log()\n console.log(chalk.bold('FCIS Analysis'))\n console.log(\n chalk.gray('═══════════════════════════════════════════════════════════'),\n )\n console.log()\n}\n\n/**\n * Print the project summary with visual bars\n */\nfunction printProjectSummary(score: ProjectScore): void {\n const healthBar = createProgressBar(score.health, 25)\n\n const healthColor =\n score.health >= 70\n ? chalk.green\n : score.health >= 50\n ? chalk.yellow\n : chalk.red\n const purityColor =\n score.purity >= 70\n ? chalk.green\n : score.purity >= 50\n ? chalk.yellow\n : chalk.red\n\n console.log(\n `Project Health: ${healthColor(score.health.toFixed(0) + '%')} ${healthBar}`,\n )\n console.log(\n ` Purity: ${purityColor(score.purity.toFixed(0) + '%')} (${score.pureCount} pure / ${score.pureCount + score.impureCount} total)`,\n )\n\n if (score.impurityQuality !== null) {\n const qualityColor =\n score.impurityQuality >= 70\n ? chalk.green\n : score.impurityQuality >= 50\n ? chalk.yellow\n : chalk.red\n console.log(\n ` Impurity Quality: ${qualityColor(score.impurityQuality.toFixed(0) + '%')} average`,\n )\n }\n\n console.log()\n}\n\n/**\n * Print status breakdown\n */\nfunction printStatusBreakdown(breakdown: StatusBreakdown, total: number): void {\n console.log('Status Breakdown:')\n\n const okPercent = total > 0 ? ((breakdown.ok / total) * 100).toFixed(0) : '0'\n const reviewPercent =\n total > 0 ? ((breakdown.review / total) * 100).toFixed(0) : '0'\n const refactorPercent =\n total > 0 ? ((breakdown.refactor / total) * 100).toFixed(0) : '0'\n\n console.log(\n ` ${chalk.green('✓ OK:')} ${String(breakdown.ok).padStart(4)} functions (${okPercent}%) — no action needed`,\n )\n console.log(\n ` ${chalk.yellow('◐ Review:')} ${String(breakdown.review).padStart(4)} functions (${reviewPercent}%) — could be improved`,\n )\n console.log(\n ` ${chalk.red('✗ Refactor:')} ${String(breakdown.refactor).padStart(4)} functions (${refactorPercent}%) — tangled, needs work`,\n )\n\n console.log()\n}\n\n/**\n * Print diagnostic insights\n */\nfunction printInsights(score: ProjectScore): void {\n const insights = getDiagnosticInsights(score)\n\n if (insights.length > 0) {\n console.log(chalk.bold('Insights:'))\n for (const insight of insights) {\n console.log(` ${chalk.cyan('→')} ${insight}`)\n }\n console.log()\n }\n}\n\n/**\n * Print directory breakdown (verbose mode)\n */\nfunction printDirectoryBreakdown(directories: DirectoryScore[]): void {\n // Sort by health ascending (worst first)\n const sorted = [...directories]\n .filter(d => d.pureCount + d.impureCount > 0)\n .sort((a, b) => a.health - b.health)\n\n if (sorted.length === 0) return\n\n console.log(chalk.bold('Directory Breakdown:'))\n console.log(chalk.gray('─'.repeat(80)))\n console.log(\n chalk.gray(\n padEnd('Directory', 45) +\n padEnd('Health', 10) +\n padEnd('Purity', 10) +\n padEnd('Functions', 15),\n ),\n )\n console.log(chalk.gray('─'.repeat(80)))\n\n for (const dir of sorted) {\n const healthColor =\n dir.health >= 70\n ? chalk.green\n : dir.health >= 50\n ? chalk.yellow\n : chalk.red\n const purityColor =\n dir.purity >= 70\n ? chalk.green\n : dir.purity >= 50\n ? chalk.yellow\n : chalk.red\n\n const relativePath = toRelativePath(dir.dirPath)\n const total = dir.pureCount + dir.impureCount\n\n console.log(\n padEnd(relativePath, 45) +\n healthColor(padEnd(dir.health.toFixed(0) + '%', 10)) +\n purityColor(padEnd(dir.purity.toFixed(0) + '%', 10)) +\n padEnd(`${dir.pureCount}/${total}`, 15),\n )\n }\n\n console.log()\n}\n\n/**\n * Print worst directories (non-verbose mode)\n */\nfunction printWorstDirectories(directories: DirectoryScore[]): void {\n const sorted = [...directories]\n .filter(d => d.pureCount + d.impureCount > 0 && d.health < 70)\n .sort((a, b) => a.health - b.health)\n .slice(0, 5)\n\n if (sorted.length === 0) return\n\n console.log(chalk.bold('Directories Needing Attention:'))\n\n for (const dir of sorted) {\n const healthColor = dir.health >= 50 ? chalk.yellow : chalk.red\n const total = dir.pureCount + dir.impureCount\n const relativePath = toRelativePath(dir.dirPath)\n\n console.log(\n ` ${healthColor(dir.health.toFixed(0).padStart(3) + '%')} ` +\n chalk.gray(`(${dir.pureCount}/${total} pure)`) +\n ` ${relativePath}`,\n )\n }\n\n console.log()\n}\n\n/**\n * Print refactoring candidates\n */\nfunction printRefactoringCandidates(candidates: RefactoringCandidate[]): void {\n if (candidates.length === 0) {\n console.log(chalk.green('No refactoring candidates found. Great job!'))\n console.log()\n return\n }\n\n console.log(chalk.bold('Top Refactoring Candidates:'))\n console.log(chalk.gray('(Sorted by impact: size × complexity)'))\n console.log()\n\n for (let i = 0; i < candidates.length; i++) {\n const candidate = candidates[i]\n if (!candidate) continue\n\n const qualityColor = candidate.qualityScore >= 40 ? chalk.yellow : chalk.red\n const relativePath = toRelativePath(candidate.filePath)\n\n console.log(\n chalk.gray(`${(i + 1).toString().padStart(2)}.`) +\n ` ${qualityColor(candidate.qualityScore.toFixed(0).padStart(3))}` +\n chalk.gray('/100') +\n ` ${chalk.cyan(candidate.name ?? '<anonymous>')}` +\n chalk.gray(` (${candidate.bodyLineCount} lines)`),\n )\n console.log(chalk.gray(` ${relativePath}:${candidate.startLine}`))\n\n if (candidate.markers.length > 0) {\n const markerStr = candidate.markers.slice(0, 3).join(', ')\n const more =\n candidate.markers.length > 3\n ? ` +${candidate.markers.length - 3} more`\n : ''\n console.log(chalk.gray(` Markers: ${markerStr}${more}`))\n }\n\n console.log()\n }\n}\n\n/**\n * Print errors encountered during analysis\n */\nfunction printErrors(errors: { filePath: string; error: string }[]): void {\n console.log(chalk.yellow.bold(`Errors (${errors.length} files skipped):`))\n\n for (const err of errors.slice(0, 5)) {\n console.log(` ${chalk.yellow('!')} ${err.filePath}`)\n console.log(chalk.gray(` ${err.error}`))\n }\n\n if (errors.length > 5) {\n console.log(chalk.gray(` ... and ${errors.length - 5} more`))\n }\n\n console.log()\n}\n\n/**\n * Print the report footer\n */\nfunction printFooter(score: ProjectScore): void {\n console.log(\n chalk.gray('═══════════════════════════════════════════════════════════'),\n )\n\n const timestamp = new Date(score.timestamp).toLocaleString()\n console.log(chalk.gray(`Generated: ${timestamp}`))\n\n if (score.commitHash) {\n console.log(chalk.gray(`Commit: ${score.commitHash.slice(0, 8)}`))\n }\n\n if (score.subset) {\n console.log(chalk.yellow(`Subset analysis: ${score.filesGlob}`))\n }\n\n console.log()\n}\n\n/**\n * Create a visual progress bar\n */\nfunction createProgressBar(percent: number, width: number): string {\n const filled = Math.round((percent / 100) * width)\n const empty = width - filled\n\n const filledChar = '█'\n const emptyChar = '░'\n\n const bar = filledChar.repeat(filled) + emptyChar.repeat(empty)\n\n if (percent >= 70) {\n return chalk.green(bar)\n } else if (percent >= 50) {\n return chalk.yellow(bar)\n } else {\n return chalk.red(bar)\n }\n}\n\n/**\n * Generate a single-line summary suitable for CI output\n */\nexport function generateSummaryLine(score: ProjectScore): string {\n const parts = [\n `FCIS Health: ${score.health.toFixed(0)}%`,\n `Purity: ${score.purity.toFixed(0)}%`,\n ]\n\n if (score.impurityQuality !== null) {\n parts.push(`Impurity Quality: ${score.impurityQuality.toFixed(0)}%`)\n }\n\n return parts.join(' | ')\n}\n\n/**\n * Convert an absolute path to a path relative to the current working directory\n */\nfunction toRelativePath(absolutePath: string): string {\n const cwd = process.cwd()\n if (absolutePath.startsWith(cwd)) {\n const relative = path.relative(cwd, absolutePath)\n return relative || '.'\n }\n return absolutePath\n}\n\n/**\n * Pad end of string to a fixed length\n */\nfunction padEnd(str: string, length: number): string {\n if (str.length >= length) return str.slice(0, length)\n return str + ' '.repeat(length - str.length)\n}\n\n/**\n * Print a file-level report (for verbose output)\n */\nexport function printFileReport(fileScore: FileScore): void {\n const healthColor =\n fileScore.health >= 70\n ? chalk.green\n : fileScore.health >= 50\n ? chalk.yellow\n : chalk.red\n const total = fileScore.pureCount + fileScore.impureCount\n const relativePath = toRelativePath(fileScore.filePath)\n\n console.log()\n console.log(chalk.bold(relativePath))\n console.log(\n ` Health: ${healthColor(fileScore.health.toFixed(0) + '%')} | ` +\n `Purity: ${fileScore.purity.toFixed(0)}% | ` +\n `Functions: ${fileScore.pureCount}/${total} pure`,\n )\n\n if (fileScore.functions.length > 0 && fileScore.impureCount > 0) {\n console.log()\n console.log(' Functions:')\n\n for (const fn of fileScore.functions) {\n const statusEmoji = getStatusEmoji(fn.status)\n const statusColor = getStatusColor(fn.status)\n const colorFn =\n statusColor === 'green'\n ? chalk.green\n : statusColor === 'yellow'\n ? chalk.yellow\n : chalk.red\n\n const name = fn.name ?? '<anonymous>'\n const classification =\n fn.classification === 'pure'\n ? chalk.green('pure')\n : chalk.yellow('impure')\n const quality = fn.qualityScore !== null ? ` (${fn.qualityScore})` : ''\n\n console.log(\n ` ${colorFn(statusEmoji)} ${name} — ${classification}${quality}`,\n )\n }\n }\n}\n","/**\n * JSON Report Generator - Shell Layer\n *\n * Serializes analysis results to JSON format for storage, diffing, and\n * trend analysis. This is part of the SHELL layer as it produces output.\n *\n * The JSON output includes:\n * - Timestamp and commit hash for versioning\n * - Full project score with all metrics\n * - Directory and file breakdowns\n * - Refactoring candidates\n * - Any errors encountered during analysis\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nimport type { ProjectScore } from '../types.js'\n\n/**\n * JSON report options\n */\nexport type JsonReportOptions = {\n pretty?: boolean // Pretty print with indentation (default: true)\n includeFunction?: boolean // Include function details (default: false for smaller output)\n}\n\n/**\n * Generate JSON report string from project score\n *\n * @param score - The project score to serialize\n * @param options - Report options\n * @returns JSON string representation\n */\nexport function generateJsonReport(\n score: ProjectScore,\n options: JsonReportOptions = {},\n): string {\n const { pretty = true, includeFunction = false } = options\n\n // Create a copy to potentially filter out function details\n const reportData = prepareReportData(score, includeFunction)\n\n if (pretty) {\n return JSON.stringify(reportData, null, 2)\n }\n\n return JSON.stringify(reportData)\n}\n\n/**\n * Prepare report data, optionally excluding function details for smaller output\n */\nfunction prepareReportData(\n score: ProjectScore,\n includeFunctions: boolean,\n): ProjectScore {\n if (includeFunctions) {\n return score\n }\n\n // Create a shallow copy with stripped function details\n return {\n ...score,\n directoryScores: score.directoryScores.map(dir => ({\n ...dir,\n fileScores: dir.fileScores.map(file => ({\n ...file,\n functions: [], // Strip function details to reduce size\n })),\n })),\n }\n}\n\n/**\n * Write JSON report to file\n *\n * @param score - The project score to write\n * @param outputPath - Path to write the JSON file\n * @param options - Report options\n */\nexport function writeJsonReport(\n score: ProjectScore,\n outputPath: string,\n options: JsonReportOptions = {},\n): void {\n const json = generateJsonReport(score, options)\n\n // Ensure directory exists\n const dir = path.dirname(outputPath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n\n fs.writeFileSync(outputPath, json, 'utf-8')\n}\n\n/**\n * Read a previous JSON report from file\n *\n * @param inputPath - Path to the JSON file\n * @returns Parsed ProjectScore or null if file doesn't exist\n */\nexport function readJsonReport(inputPath: string): ProjectScore | null {\n if (!fs.existsSync(inputPath)) {\n return null\n }\n\n const content = fs.readFileSync(inputPath, 'utf-8')\n return JSON.parse(content) as ProjectScore\n}\n\n/**\n * Create a summary JSON suitable for PR comments or CI output\n *\n * @param score - The project score\n * @returns Minimal JSON object with key metrics\n */\nexport function createSummaryJson(score: ProjectScore): {\n health: number\n purity: number\n impurityQuality: number | null\n pureCount: number\n impureCount: number\n statusBreakdown: { ok: number; review: number; refactor: number }\n timestamp: string\n commitHash: string | null\n topRefactoringCandidates: Array<{\n name: string | null\n filePath: string\n qualityScore: number\n }>\n} {\n return {\n health: Math.round(score.health * 10) / 10,\n purity: Math.round(score.purity * 10) / 10,\n impurityQuality:\n score.impurityQuality !== null\n ? Math.round(score.impurityQuality * 10) / 10\n : null,\n pureCount: score.pureCount,\n impureCount: score.impureCount,\n statusBreakdown: score.statusBreakdown,\n timestamp: score.timestamp,\n commitHash: score.commitHash,\n topRefactoringCandidates: score.refactoringCandidates\n .slice(0, 5)\n .map(c => ({\n name: c.name,\n filePath: c.filePath,\n qualityScore: c.qualityScore,\n })),\n }\n}\n\n/**\n * Compare two project scores and generate a diff report\n *\n * @param current - Current project score\n * @param previous - Previous project score\n * @returns JSON object with comparison data\n */\nexport function generateComparisonReport(\n current: ProjectScore,\n previous: ProjectScore,\n): {\n current: ReturnType<typeof createSummaryJson>\n previous: ReturnType<typeof createSummaryJson>\n delta: {\n health: number\n purity: number\n impurityQuality: number | null\n pureCount: number\n impureCount: number\n }\n improved: boolean\n newRefactoringCandidates: Array<{ name: string | null; filePath: string }>\n resolvedRefactoringCandidates: Array<{\n name: string | null\n filePath: string\n }>\n} {\n const currentSummary = createSummaryJson(current)\n const previousSummary = createSummaryJson(previous)\n\n // Calculate deltas\n const delta = {\n health: Math.round((current.health - previous.health) * 10) / 10,\n purity: Math.round((current.purity - previous.purity) * 10) / 10,\n impurityQuality:\n current.impurityQuality !== null && previous.impurityQuality !== null\n ? Math.round(\n (current.impurityQuality - previous.impurityQuality) * 10,\n ) / 10\n : null,\n pureCount: current.pureCount - previous.pureCount,\n impureCount: current.impureCount - previous.impureCount,\n }\n\n // Find new and resolved refactoring candidates\n const currentCandidateKeys = new Set(\n current.refactoringCandidates.map(c => `${c.filePath}:${c.name}`),\n )\n const previousCandidateKeys = new Set(\n previous.refactoringCandidates.map(c => `${c.filePath}:${c.name}`),\n )\n\n const newRefactoringCandidates = current.refactoringCandidates\n .filter(c => !previousCandidateKeys.has(`${c.filePath}:${c.name}`))\n .map(c => ({ name: c.name, filePath: c.filePath }))\n\n const resolvedRefactoringCandidates = previous.refactoringCandidates\n .filter(c => !currentCandidateKeys.has(`${c.filePath}:${c.name}`))\n .map(c => ({ name: c.name, filePath: c.filePath }))\n\n // Overall improvement check (health went up or stayed same with other improvements)\n const improved =\n delta.health > 0 ||\n (delta.health >= 0 && delta.purity > 0) ||\n (delta.health >= 0 &&\n delta.impurityQuality !== null &&\n delta.impurityQuality > 0)\n\n return {\n current: currentSummary,\n previous: previousSummary,\n delta,\n improved,\n newRefactoringCandidates,\n resolvedRefactoringCandidates,\n }\n}\n","#!/usr/bin/env node\n/**\n * FCIS CLI - Command Line Interface\n *\n * Entry point for the FCIS analyzer. Supports running analysis against\n * a TypeScript project and outputting results in various formats.\n *\n * Exit codes:\n * - 0: Success, all thresholds passed\n * - 1: Analysis completed but below threshold\n * - 2: Configuration error\n * - 3: Analysis error (zero files could be analyzed)\n */\n\nimport { cli } from 'cleye'\nimport { z } from 'zod'\nimport chalk from 'chalk'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nimport { analyze, checkThresholds } from './analyzer.js'\nimport { stripJsonComments } from './extraction/extractor.js'\nimport {\n printConsoleReport,\n generateSummaryLine,\n} from './reporting/report-console.js'\nimport { generateJsonReport, writeJsonReport } from './reporting/report-json.js'\nimport type { AnalyzerConfig } from './types.js'\n\nconst EXIT_SUCCESS = 0\nconst EXIT_THRESHOLD_FAILED = 1\nconst EXIT_CONFIG_ERROR = 2\nconst EXIT_ANALYSIS_ERROR = 3\n\nconst ThresholdSchema = z.number().min(0).max(100)\n\nconst argv = cli({\n name: 'fcis',\n version: '0.1.0',\n flags: {\n json: {\n type: Boolean,\n description: 'Output JSON to stdout (for piping/parsing)',\n default: false,\n },\n output: {\n type: String,\n alias: 'o',\n description: 'Write JSON report to file',\n },\n minHealth: {\n type: Number,\n description: 'Exit with code 1 if project health < N (0-100)',\n },\n minPurity: {\n type: Number,\n description: 'Exit with code 1 if purity < N (0-100)',\n },\n minQuality: {\n type: Number,\n description: 'Exit with code 1 if impurity quality < N (0-100)',\n },\n files: {\n type: String,\n alias: 'f',\n description:\n 'Analyze only files matching glob (for incremental/pre-commit)',\n },\n format: {\n type: String,\n description: 'Output format: console (default), json, summary',\n default: 'console',\n },\n quiet: {\n type: Boolean,\n alias: 'q',\n description: 'Suppress all output except errors; rely on exit code',\n default: false,\n },\n verbose: {\n type: Boolean,\n alias: 'v',\n description: 'Show per-file scores and all classified functions',\n default: false,\n },\n },\n parameters: ['<tsconfig>'],\n help: {\n description:\n 'Analyze TypeScript code for Functional Core, Imperative Shell patterns',\n examples: [\n 'fcis analyze tsconfig.json',\n 'fcis analyze tsconfig.json --min-health 70',\n 'fcis analyze tsconfig.json --format json --output report.json',\n 'fcis analyze tsconfig.json --files \"src/services/**/*.ts\"',\n ],\n },\n})\n\nasync function main(): Promise<void> {\n const { flags, _: args } = argv\n\n const tsconfigPath = args.tsconfig\n\n // Validate tsconfig exists\n if (!tsconfigPath) {\n console.error(chalk.red('Error: tsconfig path is required'))\n console.error('Usage: fcis <tsconfig> [options]')\n process.exit(EXIT_CONFIG_ERROR)\n }\n\n const absoluteTsconfigPath = path.resolve(tsconfigPath)\n if (!fs.existsSync(absoluteTsconfigPath)) {\n console.error(\n chalk.red(`Error: tsconfig.json not found at: ${absoluteTsconfigPath}`),\n )\n process.exit(EXIT_CONFIG_ERROR)\n }\n\n // Validate tsconfig is valid JSON (strip comments first since TypeScript allows them)\n try {\n const content = fs.readFileSync(absoluteTsconfigPath, 'utf-8')\n const strippedContent = stripJsonComments(content)\n JSON.parse(strippedContent)\n } catch (e) {\n console.error(\n chalk.red(`Error: Invalid tsconfig.json at ${absoluteTsconfigPath}`),\n )\n console.error(e instanceof Error ? e.message : String(e))\n process.exit(EXIT_CONFIG_ERROR)\n }\n\n // Validate threshold values\n if (flags.minHealth !== undefined) {\n const result = ThresholdSchema.safeParse(flags.minHealth)\n if (!result.success) {\n console.error(\n chalk.red('Error: --min-health must be a number between 0 and 100'),\n )\n process.exit(EXIT_CONFIG_ERROR)\n }\n }\n\n if (flags.minPurity !== undefined) {\n const result = ThresholdSchema.safeParse(flags.minPurity)\n if (!result.success) {\n console.error(\n chalk.red('Error: --min-purity must be a number between 0 and 100'),\n )\n process.exit(EXIT_CONFIG_ERROR)\n }\n }\n\n if (flags.minQuality !== undefined) {\n const result = ThresholdSchema.safeParse(flags.minQuality)\n if (!result.success) {\n console.error(\n chalk.red('Error: --min-quality must be a number between 0 and 100'),\n )\n process.exit(EXIT_CONFIG_ERROR)\n }\n }\n\n // Validate format\n const validFormats = ['console', 'json', 'summary']\n if (!validFormats.includes(flags.format)) {\n console.error(\n chalk.red(`Error: --format must be one of: ${validFormats.join(', ')}`),\n )\n process.exit(EXIT_CONFIG_ERROR)\n }\n\n // Validate output path if provided\n if (flags.output) {\n const outputDir = path.dirname(path.resolve(flags.output))\n if (!fs.existsSync(outputDir)) {\n try {\n fs.mkdirSync(outputDir, { recursive: true })\n } catch (e) {\n console.error(\n chalk.red(`Error: Cannot create output directory: ${outputDir}`),\n )\n process.exit(EXIT_CONFIG_ERROR)\n }\n }\n }\n\n // Run analysis\n try {\n if (!flags.quiet && flags.format === 'console') {\n console.log(chalk.gray(`Analyzing ${process.cwd()}...`))\n }\n\n // Build config with proper undefined handling\n const config: AnalyzerConfig = {\n tsconfigPath: absoluteTsconfigPath,\n format: flags.format as 'console' | 'json' | 'summary',\n quiet: flags.quiet,\n verbose: flags.verbose,\n }\n\n // Only add optional properties if they are defined\n if (flags.files !== undefined) {\n config.filesGlob = flags.files\n }\n if (flags.minHealth !== undefined) {\n config.minHealth = flags.minHealth\n }\n if (flags.minPurity !== undefined) {\n config.minPurity = flags.minPurity\n }\n if (flags.minQuality !== undefined) {\n config.minQuality = flags.minQuality\n }\n if (flags.output !== undefined) {\n config.outputPath = flags.output\n }\n\n const score = await analyze(config)\n\n // Output results based on format\n if (!flags.quiet) {\n if (flags.json || flags.format === 'json') {\n console.log(generateJsonReport(score, { pretty: true }))\n } else if (flags.format === 'summary') {\n console.log(generateSummaryLine(score))\n } else {\n printConsoleReport(score, { verbose: flags.verbose })\n }\n }\n\n // Write JSON to file if requested\n if (flags.output) {\n writeJsonReport(score, flags.output, { pretty: true })\n if (!flags.quiet && flags.format !== 'json') {\n console.log(chalk.green(`Report written to: ${flags.output}`))\n }\n }\n\n // Check thresholds - build object only with defined values\n const thresholdConfig: {\n minHealth?: number\n minPurity?: number\n minQuality?: number\n } = {}\n\n if (flags.minHealth !== undefined) {\n thresholdConfig.minHealth = flags.minHealth\n }\n if (flags.minPurity !== undefined) {\n thresholdConfig.minPurity = flags.minPurity\n }\n if (flags.minQuality !== undefined) {\n thresholdConfig.minQuality = flags.minQuality\n }\n\n const thresholdResult = checkThresholds(score, thresholdConfig)\n\n if (!thresholdResult.passed) {\n if (!flags.quiet) {\n console.log()\n console.log(chalk.red.bold('Threshold check failed:'))\n for (const failure of thresholdResult.failures) {\n console.log(chalk.red(` ✗ ${failure}`))\n }\n }\n process.exit(EXIT_THRESHOLD_FAILED)\n }\n\n process.exit(EXIT_SUCCESS)\n } catch (error) {\n if (!flags.quiet) {\n console.error(chalk.red('Analysis failed:'))\n console.error(error instanceof Error ? error.message : String(error))\n }\n\n // Check if it's a \"no files\" error\n if (error instanceof Error && error.message.includes('No source files')) {\n process.exit(EXIT_ANALYSIS_ERROR)\n }\n\n process.exit(EXIT_ANALYSIS_ERROR)\n }\n}\n\nmain()\n"]}