@grafema/util 0.3.0-beta

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 (324) hide show
  1. package/LICENSE +190 -0
  2. package/dist/api/GraphAPI.d.ts +87 -0
  3. package/dist/api/GraphAPI.d.ts.map +1 -0
  4. package/dist/api/GraphAPI.js +212 -0
  5. package/dist/api/GraphAPI.js.map +1 -0
  6. package/dist/api/GuaranteeAPI.d.ts +147 -0
  7. package/dist/api/GuaranteeAPI.d.ts.map +1 -0
  8. package/dist/api/GuaranteeAPI.js +290 -0
  9. package/dist/api/GuaranteeAPI.js.map +1 -0
  10. package/dist/config/ConfigLoader.d.ts +214 -0
  11. package/dist/config/ConfigLoader.d.ts.map +1 -0
  12. package/dist/config/ConfigLoader.js +441 -0
  13. package/dist/config/ConfigLoader.js.map +1 -0
  14. package/dist/config/index.d.ts +6 -0
  15. package/dist/config/index.d.ts.map +1 -0
  16. package/dist/config/index.js +5 -0
  17. package/dist/config/index.js.map +1 -0
  18. package/dist/core/CoverageAnalyzer.d.ts +65 -0
  19. package/dist/core/CoverageAnalyzer.d.ts.map +1 -0
  20. package/dist/core/CoverageAnalyzer.js +199 -0
  21. package/dist/core/CoverageAnalyzer.js.map +1 -0
  22. package/dist/core/FileExplainer.d.ts +101 -0
  23. package/dist/core/FileExplainer.d.ts.map +1 -0
  24. package/dist/core/FileExplainer.js +140 -0
  25. package/dist/core/FileExplainer.js.map +1 -0
  26. package/dist/core/FileOverview.d.ts +124 -0
  27. package/dist/core/FileOverview.d.ts.map +1 -0
  28. package/dist/core/FileOverview.js +279 -0
  29. package/dist/core/FileOverview.js.map +1 -0
  30. package/dist/core/GrafemaUri.d.ts +66 -0
  31. package/dist/core/GrafemaUri.d.ts.map +1 -0
  32. package/dist/core/GrafemaUri.js +191 -0
  33. package/dist/core/GrafemaUri.js.map +1 -0
  34. package/dist/core/GraphBackend.d.ts +158 -0
  35. package/dist/core/GraphBackend.d.ts.map +1 -0
  36. package/dist/core/GraphBackend.js +85 -0
  37. package/dist/core/GraphBackend.js.map +1 -0
  38. package/dist/core/GraphFreshnessChecker.d.ts +33 -0
  39. package/dist/core/GraphFreshnessChecker.d.ts.map +1 -0
  40. package/dist/core/GraphFreshnessChecker.js +104 -0
  41. package/dist/core/GraphFreshnessChecker.js.map +1 -0
  42. package/dist/core/GuaranteeManager.d.ts +254 -0
  43. package/dist/core/GuaranteeManager.d.ts.map +1 -0
  44. package/dist/core/GuaranteeManager.js +447 -0
  45. package/dist/core/GuaranteeManager.js.map +1 -0
  46. package/dist/core/HashUtils.d.ts +24 -0
  47. package/dist/core/HashUtils.d.ts.map +1 -0
  48. package/dist/core/HashUtils.js +46 -0
  49. package/dist/core/HashUtils.js.map +1 -0
  50. package/dist/core/IncrementalReanalyzer.d.ts +33 -0
  51. package/dist/core/IncrementalReanalyzer.d.ts.map +1 -0
  52. package/dist/core/IncrementalReanalyzer.js +67 -0
  53. package/dist/core/IncrementalReanalyzer.js.map +1 -0
  54. package/dist/core/ResourceRegistry.d.ts +17 -0
  55. package/dist/core/ResourceRegistry.d.ts.map +1 -0
  56. package/dist/core/ResourceRegistry.js +32 -0
  57. package/dist/core/ResourceRegistry.js.map +1 -0
  58. package/dist/core/SemanticId.d.ts +159 -0
  59. package/dist/core/SemanticId.d.ts.map +1 -0
  60. package/dist/core/SemanticId.js +291 -0
  61. package/dist/core/SemanticId.js.map +1 -0
  62. package/dist/core/VersionManager.d.ts +166 -0
  63. package/dist/core/VersionManager.d.ts.map +1 -0
  64. package/dist/core/VersionManager.js +239 -0
  65. package/dist/core/VersionManager.js.map +1 -0
  66. package/dist/core/brandNodeInternal.d.ts +14 -0
  67. package/dist/core/brandNodeInternal.d.ts.map +1 -0
  68. package/dist/core/brandNodeInternal.js +4 -0
  69. package/dist/core/brandNodeInternal.js.map +1 -0
  70. package/dist/core/nodes/GuaranteeNode.d.ts +76 -0
  71. package/dist/core/nodes/GuaranteeNode.d.ts.map +1 -0
  72. package/dist/core/nodes/GuaranteeNode.js +118 -0
  73. package/dist/core/nodes/GuaranteeNode.js.map +1 -0
  74. package/dist/core/nodes/IssueNode.d.ts +73 -0
  75. package/dist/core/nodes/IssueNode.d.ts.map +1 -0
  76. package/dist/core/nodes/IssueNode.js +130 -0
  77. package/dist/core/nodes/IssueNode.js.map +1 -0
  78. package/dist/core/nodes/NodeKind.d.ts +104 -0
  79. package/dist/core/nodes/NodeKind.d.ts.map +1 -0
  80. package/dist/core/nodes/NodeKind.js +166 -0
  81. package/dist/core/nodes/NodeKind.js.map +1 -0
  82. package/dist/diagnostics/DiagnosticCollector.d.ts +103 -0
  83. package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -0
  84. package/dist/diagnostics/DiagnosticCollector.js +133 -0
  85. package/dist/diagnostics/DiagnosticCollector.js.map +1 -0
  86. package/dist/diagnostics/DiagnosticReporter.d.ts +122 -0
  87. package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -0
  88. package/dist/diagnostics/DiagnosticReporter.js +300 -0
  89. package/dist/diagnostics/DiagnosticReporter.js.map +1 -0
  90. package/dist/diagnostics/DiagnosticWriter.d.ts +31 -0
  91. package/dist/diagnostics/DiagnosticWriter.d.ts.map +1 -0
  92. package/dist/diagnostics/DiagnosticWriter.js +44 -0
  93. package/dist/diagnostics/DiagnosticWriter.js.map +1 -0
  94. package/dist/diagnostics/categories.d.ts +57 -0
  95. package/dist/diagnostics/categories.d.ts.map +1 -0
  96. package/dist/diagnostics/categories.js +71 -0
  97. package/dist/diagnostics/categories.js.map +1 -0
  98. package/dist/diagnostics/index.d.ts +17 -0
  99. package/dist/diagnostics/index.d.ts.map +1 -0
  100. package/dist/diagnostics/index.js +15 -0
  101. package/dist/diagnostics/index.js.map +1 -0
  102. package/dist/errors/GrafemaError.d.ts +200 -0
  103. package/dist/errors/GrafemaError.d.ts.map +1 -0
  104. package/dist/errors/GrafemaError.js +209 -0
  105. package/dist/errors/GrafemaError.js.map +1 -0
  106. package/dist/index.d.ts +75 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +76 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/instructions/index.d.ts +8 -0
  111. package/dist/instructions/index.d.ts.map +1 -0
  112. package/dist/instructions/index.js +20 -0
  113. package/dist/instructions/index.js.map +1 -0
  114. package/dist/instructions/onboarding.md +133 -0
  115. package/dist/knowledge/KnowledgeBase.d.ts +113 -0
  116. package/dist/knowledge/KnowledgeBase.d.ts.map +1 -0
  117. package/dist/knowledge/KnowledgeBase.js +420 -0
  118. package/dist/knowledge/KnowledgeBase.js.map +1 -0
  119. package/dist/knowledge/SemanticAddressResolver.d.ts +59 -0
  120. package/dist/knowledge/SemanticAddressResolver.d.ts.map +1 -0
  121. package/dist/knowledge/SemanticAddressResolver.js +160 -0
  122. package/dist/knowledge/SemanticAddressResolver.js.map +1 -0
  123. package/dist/knowledge/git-ingest.d.ts +58 -0
  124. package/dist/knowledge/git-ingest.d.ts.map +1 -0
  125. package/dist/knowledge/git-ingest.js +301 -0
  126. package/dist/knowledge/git-ingest.js.map +1 -0
  127. package/dist/knowledge/git-queries.d.ts +86 -0
  128. package/dist/knowledge/git-queries.d.ts.map +1 -0
  129. package/dist/knowledge/git-queries.js +177 -0
  130. package/dist/knowledge/git-queries.js.map +1 -0
  131. package/dist/knowledge/index.d.ts +14 -0
  132. package/dist/knowledge/index.d.ts.map +1 -0
  133. package/dist/knowledge/index.js +10 -0
  134. package/dist/knowledge/index.js.map +1 -0
  135. package/dist/knowledge/parser.d.ts +39 -0
  136. package/dist/knowledge/parser.d.ts.map +1 -0
  137. package/dist/knowledge/parser.js +292 -0
  138. package/dist/knowledge/parser.js.map +1 -0
  139. package/dist/knowledge/types.d.ts +133 -0
  140. package/dist/knowledge/types.d.ts.map +1 -0
  141. package/dist/knowledge/types.js +8 -0
  142. package/dist/knowledge/types.js.map +1 -0
  143. package/dist/logging/Logger.d.ts +98 -0
  144. package/dist/logging/Logger.d.ts.map +1 -0
  145. package/dist/logging/Logger.js +274 -0
  146. package/dist/logging/Logger.js.map +1 -0
  147. package/dist/notation/archetypes.d.ts +36 -0
  148. package/dist/notation/archetypes.d.ts.map +1 -0
  149. package/dist/notation/archetypes.js +173 -0
  150. package/dist/notation/archetypes.js.map +1 -0
  151. package/dist/notation/fold.d.ts +25 -0
  152. package/dist/notation/fold.d.ts.map +1 -0
  153. package/dist/notation/fold.js +598 -0
  154. package/dist/notation/fold.js.map +1 -0
  155. package/dist/notation/index.d.ts +18 -0
  156. package/dist/notation/index.d.ts.map +1 -0
  157. package/dist/notation/index.js +16 -0
  158. package/dist/notation/index.js.map +1 -0
  159. package/dist/notation/lodExtractor.d.ts +32 -0
  160. package/dist/notation/lodExtractor.d.ts.map +1 -0
  161. package/dist/notation/lodExtractor.js +149 -0
  162. package/dist/notation/lodExtractor.js.map +1 -0
  163. package/dist/notation/nameShortener.d.ts +22 -0
  164. package/dist/notation/nameShortener.d.ts.map +1 -0
  165. package/dist/notation/nameShortener.js +24 -0
  166. package/dist/notation/nameShortener.js.map +1 -0
  167. package/dist/notation/perspectives.d.ts +11 -0
  168. package/dist/notation/perspectives.d.ts.map +1 -0
  169. package/dist/notation/perspectives.js +16 -0
  170. package/dist/notation/perspectives.js.map +1 -0
  171. package/dist/notation/renderer.d.ts +31 -0
  172. package/dist/notation/renderer.d.ts.map +1 -0
  173. package/dist/notation/renderer.js +315 -0
  174. package/dist/notation/renderer.js.map +1 -0
  175. package/dist/notation/traceRenderer.d.ts +39 -0
  176. package/dist/notation/traceRenderer.d.ts.map +1 -0
  177. package/dist/notation/traceRenderer.js +358 -0
  178. package/dist/notation/traceRenderer.js.map +1 -0
  179. package/dist/notation/types.d.ts +66 -0
  180. package/dist/notation/types.d.ts.map +1 -0
  181. package/dist/notation/types.js +10 -0
  182. package/dist/notation/types.js.map +1 -0
  183. package/dist/queries/NodeContext.d.ts +81 -0
  184. package/dist/queries/NodeContext.d.ts.map +1 -0
  185. package/dist/queries/NodeContext.js +196 -0
  186. package/dist/queries/NodeContext.js.map +1 -0
  187. package/dist/queries/findCallsInFunction.d.ts +62 -0
  188. package/dist/queries/findCallsInFunction.d.ts.map +1 -0
  189. package/dist/queries/findCallsInFunction.js +169 -0
  190. package/dist/queries/findCallsInFunction.js.map +1 -0
  191. package/dist/queries/findContainingFunction.d.ts +57 -0
  192. package/dist/queries/findContainingFunction.d.ts.map +1 -0
  193. package/dist/queries/findContainingFunction.js +91 -0
  194. package/dist/queries/findContainingFunction.js.map +1 -0
  195. package/dist/queries/index.d.ts +18 -0
  196. package/dist/queries/index.d.ts.map +1 -0
  197. package/dist/queries/index.js +14 -0
  198. package/dist/queries/index.js.map +1 -0
  199. package/dist/queries/traceDataflow.d.ts +65 -0
  200. package/dist/queries/traceDataflow.d.ts.map +1 -0
  201. package/dist/queries/traceDataflow.js +754 -0
  202. package/dist/queries/traceDataflow.js.map +1 -0
  203. package/dist/queries/traceValues.d.ts +70 -0
  204. package/dist/queries/traceValues.d.ts.map +1 -0
  205. package/dist/queries/traceValues.js +373 -0
  206. package/dist/queries/traceValues.js.map +1 -0
  207. package/dist/queries/types.d.ts +166 -0
  208. package/dist/queries/types.d.ts.map +1 -0
  209. package/dist/queries/types.js +10 -0
  210. package/dist/queries/types.js.map +1 -0
  211. package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
  212. package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
  213. package/dist/schema/GraphSchemaExtractor.js +125 -0
  214. package/dist/schema/GraphSchemaExtractor.js.map +1 -0
  215. package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
  216. package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
  217. package/dist/schema/InterfaceSchemaExtractor.js +113 -0
  218. package/dist/schema/InterfaceSchemaExtractor.js.map +1 -0
  219. package/dist/schema/index.d.ts +5 -0
  220. package/dist/schema/index.d.ts.map +1 -0
  221. package/dist/schema/index.js +3 -0
  222. package/dist/schema/index.js.map +1 -0
  223. package/dist/storage/backends/RFDBServerBackend.d.ts +356 -0
  224. package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -0
  225. package/dist/storage/backends/RFDBServerBackend.js +748 -0
  226. package/dist/storage/backends/RFDBServerBackend.js.map +1 -0
  227. package/dist/storage/backends/typeValidation.d.ts +47 -0
  228. package/dist/storage/backends/typeValidation.d.ts.map +1 -0
  229. package/dist/storage/backends/typeValidation.js +141 -0
  230. package/dist/storage/backends/typeValidation.js.map +1 -0
  231. package/dist/utils/findRfdbBinary.d.ts +67 -0
  232. package/dist/utils/findRfdbBinary.d.ts.map +1 -0
  233. package/dist/utils/findRfdbBinary.js +261 -0
  234. package/dist/utils/findRfdbBinary.js.map +1 -0
  235. package/dist/utils/lazyDownload.d.ts +43 -0
  236. package/dist/utils/lazyDownload.d.ts.map +1 -0
  237. package/dist/utils/lazyDownload.js +175 -0
  238. package/dist/utils/lazyDownload.js.map +1 -0
  239. package/dist/utils/moduleResolution.d.ts +134 -0
  240. package/dist/utils/moduleResolution.d.ts.map +1 -0
  241. package/dist/utils/moduleResolution.js +189 -0
  242. package/dist/utils/moduleResolution.js.map +1 -0
  243. package/dist/utils/resolveNodeFile.d.ts +13 -0
  244. package/dist/utils/resolveNodeFile.d.ts.map +1 -0
  245. package/dist/utils/resolveNodeFile.js +18 -0
  246. package/dist/utils/resolveNodeFile.js.map +1 -0
  247. package/dist/utils/startRfdbServer.d.ts +63 -0
  248. package/dist/utils/startRfdbServer.d.ts.map +1 -0
  249. package/dist/utils/startRfdbServer.js +142 -0
  250. package/dist/utils/startRfdbServer.js.map +1 -0
  251. package/dist/validation/PathValidator.d.ts +80 -0
  252. package/dist/validation/PathValidator.d.ts.map +1 -0
  253. package/dist/validation/PathValidator.js +252 -0
  254. package/dist/validation/PathValidator.js.map +1 -0
  255. package/dist/version.d.ts +11 -0
  256. package/dist/version.d.ts.map +1 -0
  257. package/dist/version.js +26 -0
  258. package/dist/version.js.map +1 -0
  259. package/package.json +50 -0
  260. package/src/api/GraphAPI.ts +307 -0
  261. package/src/api/GuaranteeAPI.ts +402 -0
  262. package/src/config/ConfigLoader.ts +653 -0
  263. package/src/config/index.ts +13 -0
  264. package/src/core/CoverageAnalyzer.ts +243 -0
  265. package/src/core/FileExplainer.ts +179 -0
  266. package/src/core/FileOverview.ts +397 -0
  267. package/src/core/GrafemaUri.ts +216 -0
  268. package/src/core/GraphBackend.ts +266 -0
  269. package/src/core/GraphFreshnessChecker.ts +145 -0
  270. package/src/core/GuaranteeManager.ts +684 -0
  271. package/src/core/HashUtils.ts +48 -0
  272. package/src/core/IncrementalReanalyzer.ts +106 -0
  273. package/src/core/ResourceRegistry.ts +39 -0
  274. package/src/core/SemanticId.ts +423 -0
  275. package/src/core/VersionManager.ts +405 -0
  276. package/src/core/brandNodeInternal.ts +16 -0
  277. package/src/core/nodes/GuaranteeNode.ts +162 -0
  278. package/src/core/nodes/IssueNode.ts +177 -0
  279. package/src/core/nodes/NodeKind.ts +192 -0
  280. package/src/diagnostics/DiagnosticCollector.ts +170 -0
  281. package/src/diagnostics/DiagnosticReporter.ts +395 -0
  282. package/src/diagnostics/DiagnosticWriter.ts +50 -0
  283. package/src/diagnostics/categories.ts +104 -0
  284. package/src/diagnostics/index.ts +30 -0
  285. package/src/errors/GrafemaError.ts +297 -0
  286. package/src/index.ts +261 -0
  287. package/src/instructions/index.ts +21 -0
  288. package/src/instructions/onboarding.md +133 -0
  289. package/src/knowledge/KnowledgeBase.ts +486 -0
  290. package/src/knowledge/SemanticAddressResolver.ts +191 -0
  291. package/src/knowledge/git-ingest.ts +402 -0
  292. package/src/knowledge/git-queries.ts +269 -0
  293. package/src/knowledge/index.ts +29 -0
  294. package/src/knowledge/parser.ts +294 -0
  295. package/src/knowledge/types.ts +146 -0
  296. package/src/logging/Logger.ts +303 -0
  297. package/src/notation/archetypes.ts +189 -0
  298. package/src/notation/fold.ts +696 -0
  299. package/src/notation/index.ts +27 -0
  300. package/src/notation/lodExtractor.ts +177 -0
  301. package/src/notation/nameShortener.ts +24 -0
  302. package/src/notation/perspectives.ts +18 -0
  303. package/src/notation/renderer.ts +394 -0
  304. package/src/notation/traceRenderer.ts +458 -0
  305. package/src/notation/types.ts +79 -0
  306. package/src/queries/NodeContext.ts +280 -0
  307. package/src/queries/findCallsInFunction.ts +249 -0
  308. package/src/queries/findContainingFunction.ts +124 -0
  309. package/src/queries/index.ts +44 -0
  310. package/src/queries/traceDataflow.ts +838 -0
  311. package/src/queries/traceValues.ts +531 -0
  312. package/src/queries/types.ts +191 -0
  313. package/src/schema/GraphSchemaExtractor.ts +177 -0
  314. package/src/schema/InterfaceSchemaExtractor.ts +173 -0
  315. package/src/schema/index.ts +5 -0
  316. package/src/storage/backends/RFDBServerBackend.ts +895 -0
  317. package/src/storage/backends/typeValidation.ts +154 -0
  318. package/src/utils/findRfdbBinary.ts +288 -0
  319. package/src/utils/lazyDownload.ts +206 -0
  320. package/src/utils/moduleResolution.ts +271 -0
  321. package/src/utils/resolveNodeFile.ts +18 -0
  322. package/src/utils/startRfdbServer.ts +197 -0
  323. package/src/validation/PathValidator.ts +334 -0
  324. package/src/version.ts +28 -0
@@ -0,0 +1,395 @@
1
+ /**
2
+ * DiagnosticReporter - Formats diagnostics for output
3
+ *
4
+ * Supports multiple output formats:
5
+ * - text: Human-readable format with severity indicators
6
+ * - json: Machine-readable JSON format for CI integration
7
+ * - csv: Spreadsheet-compatible format
8
+ *
9
+ * Usage:
10
+ * const reporter = new DiagnosticReporter(collector);
11
+ * console.log(reporter.report({ format: 'text', includeSummary: true }));
12
+ * console.log(reporter.summary());
13
+ */
14
+
15
+ import type { Diagnostic, DiagnosticCollector } from './DiagnosticCollector.js';
16
+ import { CODE_TO_CATEGORY } from './categories.js';
17
+
18
+ /**
19
+ * Report output options
20
+ */
21
+ export interface ReportOptions {
22
+ format: 'text' | 'json' | 'csv';
23
+ includeSummary?: boolean;
24
+ includeTrace?: boolean;
25
+ }
26
+
27
+ /**
28
+ * Options for strict mode formatting (REG-332)
29
+ */
30
+ export interface StrictFormatOptions {
31
+ /** Show resolution chain (hybrid: auto-show for ≤3 errors, hide for more) */
32
+ verbose?: boolean;
33
+ /** REG-332: Number of errors suppressed by grafema-ignore comments */
34
+ suppressedCount?: number;
35
+ }
36
+
37
+ /**
38
+ * Summary statistics
39
+ */
40
+ export interface SummaryStats {
41
+ total: number;
42
+ fatal: number;
43
+ errors: number;
44
+ warnings: number;
45
+ info: number;
46
+ }
47
+
48
+ /**
49
+ * Category count with metadata
50
+ */
51
+ export interface CategoryCount {
52
+ code: string;
53
+ count: number;
54
+ name: string;
55
+ checkCommand: string;
56
+ }
57
+
58
+ /**
59
+ * Summary statistics with category breakdown
60
+ */
61
+ export interface CategorizedSummaryStats extends SummaryStats {
62
+ byCode: CategoryCount[];
63
+ }
64
+
65
+ /**
66
+ * DiagnosticReporter - formats diagnostics for different output formats
67
+ */
68
+ export class DiagnosticReporter {
69
+ constructor(private collector: DiagnosticCollector) {}
70
+
71
+ /**
72
+ * Generate a formatted report of all diagnostics.
73
+ */
74
+ report(options: ReportOptions): string {
75
+ const diagnostics = this.collector.getAll();
76
+
77
+ if (options.format === 'json') {
78
+ return this.jsonReport(diagnostics, options);
79
+ } else if (options.format === 'csv') {
80
+ return this.csvReport(diagnostics);
81
+ } else {
82
+ return this.textReport(diagnostics, options);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Generate a human-readable summary of diagnostic counts.
88
+ */
89
+ summary(): string {
90
+ const stats = this.getStats();
91
+
92
+ if (stats.total === 0) {
93
+ return 'No issues found.';
94
+ }
95
+
96
+ const parts: string[] = [];
97
+
98
+ if (stats.fatal > 0) {
99
+ parts.push(`Fatal: ${stats.fatal}`);
100
+ }
101
+ if (stats.errors > 0) {
102
+ parts.push(`Errors: ${stats.errors}`);
103
+ }
104
+ if (stats.warnings > 0) {
105
+ parts.push(`Warnings: ${stats.warnings}`);
106
+ }
107
+
108
+ return parts.join(', ');
109
+ }
110
+
111
+ /**
112
+ * Generate a categorized summary with actionable commands.
113
+ */
114
+ categorizedSummary(): string {
115
+ const stats = this.getCategorizedStats();
116
+
117
+ if (stats.total === 0) {
118
+ return 'No issues found.';
119
+ }
120
+
121
+ const lines: string[] = [];
122
+
123
+ // Severity totals (same format as summary())
124
+ const severityParts: string[] = [];
125
+ if (stats.fatal > 0) {
126
+ severityParts.push(`Fatal: ${stats.fatal}`);
127
+ }
128
+ if (stats.errors > 0) {
129
+ severityParts.push(`Errors: ${stats.errors}`);
130
+ }
131
+ if (stats.warnings > 0) {
132
+ severityParts.push(`Warnings: ${stats.warnings}`);
133
+ }
134
+ lines.push(severityParts.join(', '));
135
+
136
+ // Top 5 categories
137
+ const topCategories = stats.byCode.slice(0, 5);
138
+ for (const category of topCategories) {
139
+ lines.push(` - ${category.count} ${category.name} (run \`${category.checkCommand}\`)`);
140
+ }
141
+
142
+ // "Other issues" if more than 5 categories
143
+ if (stats.byCode.length > 5) {
144
+ const remainingCount = stats.byCode.slice(5).reduce((sum, cat) => sum + cat.count, 0);
145
+ const issueWord = remainingCount === 1 ? 'other issue' : 'other issues';
146
+ lines.push(` - ${remainingCount} ${issueWord}`);
147
+ }
148
+
149
+ // Footer
150
+ lines.push('');
151
+ lines.push('Run `grafema check --all` for full diagnostics.');
152
+
153
+ return lines.join('\n');
154
+ }
155
+
156
+ /**
157
+ * Get diagnostic statistics by severity.
158
+ */
159
+ getStats(): SummaryStats {
160
+ const diagnostics = this.collector.getAll();
161
+ return {
162
+ total: diagnostics.length,
163
+ fatal: diagnostics.filter(d => d.severity === 'fatal').length,
164
+ errors: diagnostics.filter(d => d.severity === 'error').length,
165
+ warnings: diagnostics.filter(d => d.severity === 'warning').length,
166
+ info: diagnostics.filter(d => d.severity === 'info').length,
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Get diagnostic statistics grouped by category.
172
+ */
173
+ getCategorizedStats(): CategorizedSummaryStats {
174
+ const diagnostics = this.collector.getAll();
175
+
176
+ // Get severity stats
177
+ const severityStats: SummaryStats = {
178
+ total: diagnostics.length,
179
+ fatal: diagnostics.filter(d => d.severity === 'fatal').length,
180
+ errors: diagnostics.filter(d => d.severity === 'error').length,
181
+ warnings: diagnostics.filter(d => d.severity === 'warning').length,
182
+ info: diagnostics.filter(d => d.severity === 'info').length,
183
+ };
184
+
185
+ // Group by code
186
+ const codeMap = new Map<string, number>();
187
+ for (const diag of diagnostics) {
188
+ const count = codeMap.get(diag.code) || 0;
189
+ codeMap.set(diag.code, count + 1);
190
+ }
191
+
192
+ // Convert to CategoryCount array with metadata
193
+ const byCode: CategoryCount[] = [];
194
+ for (const [code, count] of codeMap.entries()) {
195
+ const category = CODE_TO_CATEGORY[code];
196
+ byCode.push({
197
+ code,
198
+ count,
199
+ name: category?.name || code,
200
+ checkCommand: category?.checkCommand || 'grafema check --all',
201
+ });
202
+ }
203
+
204
+ // Sort by count descending
205
+ byCode.sort((a, b) => b.count - a.count);
206
+
207
+ return {
208
+ ...severityStats,
209
+ byCode,
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Format strict mode errors with enhanced context (REG-332).
215
+ * Shows resolution chain and context-aware suggestions.
216
+ *
217
+ * Uses hybrid progressive disclosure:
218
+ * - ≤3 errors: show chain by default
219
+ * - >3 errors: hide chain unless verbose=true
220
+ *
221
+ * @param diagnostics - The fatal diagnostics from strict mode
222
+ * @param options - Formatting options
223
+ * @returns Formatted string for CLI output
224
+ */
225
+ formatStrict(diagnostics: Diagnostic[], options: StrictFormatOptions = {}): string {
226
+ const lines: string[] = [];
227
+ // Hybrid: show chain for ≤3 errors unless explicitly set
228
+ const showChain = options.verbose ?? diagnostics.length <= 3;
229
+
230
+ for (const diag of diagnostics) {
231
+ // Header: CODE file:line
232
+ const location = diag.file
233
+ ? diag.line
234
+ ? `${diag.file}:${diag.line}`
235
+ : diag.file
236
+ : '';
237
+ lines.push(`${diag.code} ${location}`);
238
+ lines.push('');
239
+
240
+ // Message
241
+ lines.push(` ${diag.message}`);
242
+
243
+ // Resolution chain (if showing and present)
244
+ if (showChain && diag.resolutionChain && diag.resolutionChain.length > 0) {
245
+ lines.push('');
246
+ lines.push(' Resolution chain:');
247
+ for (const step of diag.resolutionChain) {
248
+ const stepLocation = step.file
249
+ ? step.line
250
+ ? ` (${step.file}:${step.line})`
251
+ : ` (${step.file})`
252
+ : '';
253
+ lines.push(` ${step.step} -> ${step.result}${stepLocation}`);
254
+ }
255
+ }
256
+
257
+ // Suggestion (if present)
258
+ if (diag.suggestion) {
259
+ lines.push('');
260
+ lines.push(` Suggestion: ${diag.suggestion}`);
261
+ }
262
+
263
+ lines.push('');
264
+ lines.push('---');
265
+ lines.push('');
266
+ }
267
+
268
+ // Remove trailing separator
269
+ if (lines.length > 0) {
270
+ lines.splice(-3);
271
+ }
272
+
273
+ // Add hint about verbose mode if chain hidden
274
+ if (!showChain && diagnostics.some(d => d.resolutionChain && d.resolutionChain.length > 0)) {
275
+ lines.push('');
276
+ lines.push(' Run with --verbose to see resolution chains.');
277
+ }
278
+
279
+ // REG-332: Show suppression summary if any errors were suppressed
280
+ if (options.suppressedCount && options.suppressedCount > 0) {
281
+ lines.push('');
282
+ lines.push(` ${options.suppressedCount} error(s) suppressed by grafema-ignore comments.`);
283
+ }
284
+
285
+ return lines.join('\n');
286
+ }
287
+
288
+ /**
289
+ * Generate human-readable text report.
290
+ */
291
+ private textReport(diagnostics: Diagnostic[], options: ReportOptions): string {
292
+ if (diagnostics.length === 0) {
293
+ return 'No issues found.';
294
+ }
295
+
296
+ const lines: string[] = [];
297
+
298
+ for (const diag of diagnostics) {
299
+ const icon = this.getSeverityIcon(diag.severity);
300
+ const location = this.formatLocation(diag);
301
+
302
+ lines.push(`${icon} ${diag.code} ${location} ${diag.message}`);
303
+
304
+ if (diag.suggestion) {
305
+ lines.push(` Suggestion: ${diag.suggestion}`);
306
+ }
307
+ }
308
+
309
+ if (options.includeSummary) {
310
+ lines.push('');
311
+ lines.push(this.summary());
312
+ }
313
+
314
+ return lines.join('\n');
315
+ }
316
+
317
+ /**
318
+ * Generate JSON report.
319
+ */
320
+ private jsonReport(diagnostics: Diagnostic[], options: ReportOptions): string {
321
+ const result: {
322
+ diagnostics: Diagnostic[];
323
+ summary?: SummaryStats;
324
+ } = {
325
+ diagnostics,
326
+ };
327
+
328
+ if (options.includeSummary) {
329
+ result.summary = this.getStats();
330
+ }
331
+
332
+ return JSON.stringify(result, null, 2);
333
+ }
334
+
335
+ /**
336
+ * Generate CSV report.
337
+ */
338
+ private csvReport(diagnostics: Diagnostic[]): string {
339
+ const header = 'severity,code,file,line,message,plugin,phase,suggestion';
340
+ const rows = diagnostics.map(d =>
341
+ [
342
+ d.severity,
343
+ d.code,
344
+ d.file || '',
345
+ d.line || '',
346
+ this.csvEscape(d.message),
347
+ d.plugin,
348
+ d.phase,
349
+ d.suggestion ? this.csvEscape(d.suggestion) : '',
350
+ ].join(',')
351
+ );
352
+ return [header, ...rows].join('\n');
353
+ }
354
+
355
+ /**
356
+ * Get severity indicator for text output.
357
+ */
358
+ private getSeverityIcon(severity: Diagnostic['severity']): string {
359
+ switch (severity) {
360
+ case 'fatal':
361
+ return '[FATAL]';
362
+ case 'error':
363
+ return '[ERROR]';
364
+ case 'warning':
365
+ return '[WARN]';
366
+ case 'info':
367
+ return '[INFO]';
368
+ default:
369
+ return '[?]';
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Format file location for display.
375
+ */
376
+ private formatLocation(diag: Diagnostic): string {
377
+ if (!diag.file) {
378
+ return '';
379
+ }
380
+ if (diag.line) {
381
+ return `(${diag.file}:${diag.line})`;
382
+ }
383
+ return `(${diag.file})`;
384
+ }
385
+
386
+ /**
387
+ * Escape a value for CSV output.
388
+ * Wraps in quotes and escapes internal quotes.
389
+ */
390
+ private csvEscape(value: string): string {
391
+ // Always quote to handle commas and special characters
392
+ const escaped = value.replace(/"/g, '""');
393
+ return `"${escaped}"`;
394
+ }
395
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * DiagnosticWriter - Writes diagnostics to .grafema/diagnostics.log
3
+ *
4
+ * Writes diagnostics in JSON lines format (one JSON object per line).
5
+ * This format is:
6
+ * - Easy to parse line-by-line
7
+ * - Appendable without reading entire file
8
+ * - Compatible with streaming tools (grep, jq, etc.)
9
+ *
10
+ * Usage:
11
+ * const writer = new DiagnosticWriter();
12
+ * await writer.write(collector, '/project/.grafema');
13
+ */
14
+
15
+ import { writeFileSync, existsSync, mkdirSync } from 'fs';
16
+ import { join, dirname } from 'path';
17
+
18
+ import type { DiagnosticCollector } from './DiagnosticCollector.js';
19
+
20
+ /**
21
+ * DiagnosticWriter - writes diagnostics.log file
22
+ */
23
+ export class DiagnosticWriter {
24
+ /**
25
+ * Write all diagnostics to .grafema/diagnostics.log
26
+ *
27
+ * Creates the directory if it doesn't exist.
28
+ * Overwrites existing file.
29
+ */
30
+ async write(collector: DiagnosticCollector, grafemaDir: string): Promise<void> {
31
+ const logPath = this.getLogPath(grafemaDir);
32
+
33
+ // Create directory if it doesn't exist
34
+ const dir = dirname(logPath);
35
+ if (!existsSync(dir)) {
36
+ mkdirSync(dir, { recursive: true });
37
+ }
38
+
39
+ // Write diagnostics as JSON lines
40
+ const content = collector.toDiagnosticsLog();
41
+ writeFileSync(logPath, content, 'utf-8');
42
+ }
43
+
44
+ /**
45
+ * Get the path to the diagnostics.log file
46
+ */
47
+ getLogPath(grafemaDir: string): string {
48
+ return join(grafemaDir, 'diagnostics.log');
49
+ }
50
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Diagnostic Categories - Single source of truth for category/code mappings
3
+ *
4
+ * This module defines diagnostic categories once and derives both mapping
5
+ * directions:
6
+ * - DIAGNOSTIC_CATEGORIES: category → codes (used by CLI check command)
7
+ * - CODE_TO_CATEGORY: code → category metadata (used by DiagnosticReporter)
8
+ *
9
+ * Adding a new diagnostic code requires updating only this file.
10
+ */
11
+
12
+ /**
13
+ * Category definition with human-readable metadata and associated codes
14
+ */
15
+ export interface DiagnosticCategory {
16
+ /** Human-readable name for display */
17
+ readonly name: string;
18
+ /** Description of what this category checks */
19
+ readonly description: string;
20
+ /** Diagnostic codes that belong to this category */
21
+ readonly codes: readonly string[];
22
+ }
23
+
24
+ /**
25
+ * Valid category keys
26
+ */
27
+ export type DiagnosticCategoryKey = 'connectivity' | 'calls' | 'dataflow' | 'imports';
28
+
29
+ /**
30
+ * Canonical definition of all diagnostic categories
31
+ *
32
+ * This is the SINGLE SOURCE OF TRUTH for category mappings.
33
+ * Both CLI and DiagnosticReporter derive their mappings from this.
34
+ */
35
+ export const DIAGNOSTIC_CATEGORIES: Record<DiagnosticCategoryKey, DiagnosticCategory> = {
36
+ connectivity: {
37
+ name: 'Graph Connectivity',
38
+ description: 'Check for disconnected nodes in the graph',
39
+ codes: ['ERR_DISCONNECTED_NODES', 'ERR_DISCONNECTED_NODE'],
40
+ },
41
+ calls: {
42
+ name: 'Call Resolution',
43
+ description: 'Check for unresolved function calls',
44
+ codes: ['ERR_UNRESOLVED_CALL'],
45
+ },
46
+ dataflow: {
47
+ name: 'Data Flow',
48
+ description: 'Check for missing assignments and broken references',
49
+ codes: ['ERR_MISSING_ASSIGNMENT', 'ERR_BROKEN_REFERENCE', 'ERR_NO_LEAF_NODE'],
50
+ },
51
+ imports: {
52
+ name: 'Import Validation',
53
+ description: 'Check for broken imports and undefined symbols',
54
+ codes: ['ERR_BROKEN_IMPORT', 'ERR_UNDEFINED_SYMBOL'],
55
+ },
56
+ };
57
+
58
+ /**
59
+ * Metadata for code-to-category lookup (used by DiagnosticReporter)
60
+ */
61
+ export interface CodeCategoryInfo {
62
+ /** Human-readable name for the issue type */
63
+ name: string;
64
+ /** CLI command to check this category */
65
+ checkCommand: string;
66
+ }
67
+
68
+ /**
69
+ * Derived mapping: code → category metadata
70
+ *
71
+ * Auto-generated from DIAGNOSTIC_CATEGORIES.
72
+ * Used by DiagnosticReporter to show actionable commands.
73
+ */
74
+ export const CODE_TO_CATEGORY: Record<string, CodeCategoryInfo> = (() => {
75
+ const result: Record<string, CodeCategoryInfo> = {};
76
+
77
+ for (const [categoryKey, category] of Object.entries(DIAGNOSTIC_CATEGORIES)) {
78
+ // Generate human-readable name from category name (lowercase, plural)
79
+ const issueName = category.name.toLowerCase().replace('graph ', '');
80
+
81
+ for (const code of category.codes) {
82
+ result[code] = {
83
+ name: issueName,
84
+ checkCommand: `grafema check ${categoryKey}`,
85
+ };
86
+ }
87
+ }
88
+
89
+ return result;
90
+ })();
91
+
92
+ /**
93
+ * Get category for a diagnostic code
94
+ */
95
+ export function getCategoryForCode(code: string): CodeCategoryInfo | undefined {
96
+ return CODE_TO_CATEGORY[code];
97
+ }
98
+
99
+ /**
100
+ * Get all codes for a category
101
+ */
102
+ export function getCodesForCategory(category: DiagnosticCategoryKey): readonly string[] {
103
+ return DIAGNOSTIC_CATEGORIES[category].codes;
104
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Diagnostics - Error collection, reporting, and logging
3
+ *
4
+ * This module provides the diagnostics infrastructure for Grafema:
5
+ * - DiagnosticCollector: Collects errors from plugin execution
6
+ * - DiagnosticReporter: Formats diagnostics for output (text/json/csv)
7
+ * - DiagnosticWriter: Writes diagnostics.log file
8
+ * - categories: Single source of truth for diagnostic category mappings
9
+ */
10
+
11
+ export { DiagnosticCollector } from './DiagnosticCollector.js';
12
+ export type { Diagnostic, DiagnosticInput } from './DiagnosticCollector.js';
13
+
14
+ export { DiagnosticReporter } from './DiagnosticReporter.js';
15
+ export type { ReportOptions, SummaryStats, CategoryCount, CategorizedSummaryStats } from './DiagnosticReporter.js';
16
+
17
+ export { DiagnosticWriter } from './DiagnosticWriter.js';
18
+
19
+ // Category mappings (single source of truth)
20
+ export {
21
+ DIAGNOSTIC_CATEGORIES,
22
+ CODE_TO_CATEGORY,
23
+ getCategoryForCode,
24
+ getCodesForCategory,
25
+ } from './categories.js';
26
+ export type {
27
+ DiagnosticCategory,
28
+ DiagnosticCategoryKey,
29
+ CodeCategoryInfo,
30
+ } from './categories.js';