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
package/src/types.ts ADDED
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Core type definitions for the FCIS Analyzer
3
+ *
4
+ * These types form the contract between the analyzer's layers:
5
+ * - Extraction layer produces ExtractedFunction and FileImports
6
+ * - Detection layer produces ImpurityMarker[]
7
+ * - Classification layer produces ClassifiedFunction
8
+ * - Scoring layer produces FileScore, DirectoryScore, ProjectScore
9
+ */
10
+
11
+ /**
12
+ * CallSite captures position and context for each call expression,
13
+ * enabling sequence analysis (GATHER→DECIDE→EXECUTE detection)
14
+ */
15
+ export type CallSite = {
16
+ expression: string // e.g. "db.user.findFirst", "planAcceptInvite"
17
+ line: number // position within the function (relative to function start)
18
+ isAwaited: boolean // was this call preceded by `await`?
19
+ }
20
+
21
+ /**
22
+ * Represents a function extracted from source code
23
+ */
24
+ export type ExtractedFunction = {
25
+ name: string | null
26
+ filePath: string
27
+ startLine: number
28
+ endLine: number
29
+ isAsync: boolean
30
+ isExported: boolean
31
+ bodyLineCount: number
32
+ statementCount: number
33
+ hasConditionals: boolean
34
+ parentContext: string | null // e.g. class name, variable name
35
+ callSites: CallSite[] // enriched call expressions with position and await context
36
+ hasAwait: boolean // convenience flag: true if any callSite.isAwaited
37
+ propertyAccessChains: string[] // e.g. ["process.env.NODE_ENV", "db.user"]
38
+ kind:
39
+ | 'function'
40
+ | 'method'
41
+ | 'arrow'
42
+ | 'function-expression'
43
+ | 'getter'
44
+ | 'setter'
45
+ }
46
+
47
+ /**
48
+ * Represents imports in a file
49
+ */
50
+ export type FileImports = {
51
+ filePath: string
52
+ imports: {
53
+ moduleSpecifier: string // e.g. "@sai/database", "./organizations.pure"
54
+ namedImports: string[] // e.g. ["planAcceptInvite", "AcceptInviteDecision"]
55
+ }[]
56
+ }
57
+
58
+ /**
59
+ * Strict marker type union — prevents typos, enables exhaustive matching
60
+ * Note: 'async-function' removed — async alone is not an impurity marker
61
+ * Note: React hook markers deferred to v2
62
+ */
63
+ export type MarkerType =
64
+ | 'await-expression'
65
+ | 'database-call'
66
+ | 'network-fetch'
67
+ | 'network-http'
68
+ | 'fs-import'
69
+ | 'fs-call'
70
+ | 'env-access'
71
+ | 'console-log'
72
+ | 'logging'
73
+ | 'telemetry'
74
+ | 'queue-enqueue'
75
+ | 'event-emit'
76
+
77
+ /**
78
+ * Represents a detected impurity marker in a function
79
+ */
80
+ export type ImpurityMarker = {
81
+ type: MarkerType
82
+ detail: string // e.g. "db.user.findFirst"
83
+ line?: number // optional line number for better reporting
84
+ }
85
+
86
+ /**
87
+ * Binary classification — objective, no heuristics
88
+ */
89
+ export type FunctionClassification = 'pure' | 'impure'
90
+
91
+ /**
92
+ * Derived status for UX — actionable guidance
93
+ */
94
+ export type Status = 'ok' | 'review' | 'refactor'
95
+
96
+ /**
97
+ * A function that has been classified with markers, classification, quality score, and status
98
+ */
99
+ export type ClassifiedFunction = ExtractedFunction & {
100
+ markers: ImpurityMarker[]
101
+ classification: FunctionClassification
102
+ qualityScore: number | null // 0-100 for impure functions; null for pure
103
+ status: Status // derived from classification + qualityScore
104
+ }
105
+
106
+ /**
107
+ * Breakdown of function statuses
108
+ */
109
+ export type StatusBreakdown = {
110
+ ok: number
111
+ review: number
112
+ refactor: number
113
+ }
114
+
115
+ /**
116
+ * Refactoring candidate summary for reporting
117
+ */
118
+ export type RefactoringCandidate = {
119
+ name: string | null
120
+ filePath: string
121
+ startLine: number
122
+ bodyLineCount: number
123
+ qualityScore: number
124
+ markers: MarkerType[]
125
+ }
126
+
127
+ /**
128
+ * Score for a single file
129
+ */
130
+ export type FileScore = {
131
+ filePath: string
132
+ purity: number // 0-100: pure / (pure + impure)
133
+ impurityQuality: number | null // 0-100: avg quality of impure functions; null if none
134
+ health: number // 0-100: functions with status 'ok' / total
135
+ pureCount: number
136
+ impureCount: number
137
+ excludedCount: number
138
+ statusBreakdown: StatusBreakdown
139
+ pureLineCount: number // total lines in pure functions
140
+ impureLineCount: number // total lines in impure functions
141
+ functions: ClassifiedFunction[]
142
+ refactoringCandidates: Omit<RefactoringCandidate, 'filePath'>[]
143
+ // Edge case flags
144
+ allExcluded?: boolean // true if all functions were excluded
145
+ typeOnly?: boolean // true if file has only type/interface/enum exports
146
+ }
147
+
148
+ /**
149
+ * Score for a directory
150
+ */
151
+ export type DirectoryScore = {
152
+ dirPath: string
153
+ purity: number
154
+ impurityQuality: number | null
155
+ health: number
156
+ pureCount: number
157
+ impureCount: number
158
+ excludedCount: number
159
+ statusBreakdown: StatusBreakdown
160
+ pureLineCount: number
161
+ impureLineCount: number
162
+ fileScores: FileScore[]
163
+ }
164
+
165
+ /**
166
+ * Project-level score (top-level output)
167
+ */
168
+ export type ProjectScore = {
169
+ purity: number // 0-100: percentage of pure functions
170
+ impurityQuality: number | null // 0-100: avg quality of impure functions
171
+ health: number // 0-100: percentage with status 'ok'
172
+ pureCount: number
173
+ impureCount: number
174
+ excludedCount: number
175
+ statusBreakdown: StatusBreakdown
176
+ pureLineCount: number
177
+ impureLineCount: number
178
+ directoryScores: DirectoryScore[]
179
+ timestamp: string
180
+ commitHash: string | null
181
+ // Sorted by bodyLineCount × (100 - qualityScore) descending (largest, lowest-quality first)
182
+ refactoringCandidates: RefactoringCandidate[]
183
+ // Edge case flags
184
+ allExcluded?: boolean // true if all functions were excluded
185
+ // Subset analysis metadata (when --files is used)
186
+ subset?: boolean // true if this is a subset analysis
187
+ filesGlob?: string // the glob pattern used for --files
188
+ // Errors encountered during analysis
189
+ errors?: AnalysisError[]
190
+ }
191
+
192
+ /**
193
+ * Error encountered during analysis
194
+ */
195
+ export type AnalysisError = {
196
+ filePath: string
197
+ error: string
198
+ }
199
+
200
+ /**
201
+ * Configuration options for the analyzer
202
+ */
203
+ export type AnalyzerConfig = {
204
+ tsconfigPath: string
205
+ filesGlob?: string
206
+ minHealth?: number
207
+ minPurity?: number
208
+ minQuality?: number
209
+ format?: 'console' | 'json' | 'summary'
210
+ outputPath?: string
211
+ quiet?: boolean
212
+ verbose?: boolean
213
+ }
214
+
215
+ /**
216
+ * Quality scoring thresholds (configurable)
217
+ */
218
+ export type QualityThresholds = {
219
+ okThreshold: number // >= this is 'ok' (default: 70)
220
+ reviewThreshold: number // >= this is 'review', below is 'refactor' (default: 40)
221
+ }
222
+
223
+ /**
224
+ * Default quality thresholds
225
+ */
226
+ export const DEFAULT_QUALITY_THRESHOLDS: QualityThresholds = {
227
+ okThreshold: 70,
228
+ reviewThreshold: 40,
229
+ }
230
+
231
+ /**
232
+ * Result of extracting functions from a file
233
+ */
234
+ export type ExtractionResult = {
235
+ filePath: string
236
+ functions: ExtractedFunction[]
237
+ imports: FileImports
238
+ isTypeOnly: boolean
239
+ error?: string
240
+ }
241
+
242
+ /**
243
+ * Detection context passed to marker detection
244
+ */
245
+ export type DetectionContext = {
246
+ imports: FileImports
247
+ pureFileImports: Set<string> // module specifiers ending in .pure
248
+ }