@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.
- package/LICENSE +190 -0
- package/dist/api/GraphAPI.d.ts +87 -0
- package/dist/api/GraphAPI.d.ts.map +1 -0
- package/dist/api/GraphAPI.js +212 -0
- package/dist/api/GraphAPI.js.map +1 -0
- package/dist/api/GuaranteeAPI.d.ts +147 -0
- package/dist/api/GuaranteeAPI.d.ts.map +1 -0
- package/dist/api/GuaranteeAPI.js +290 -0
- package/dist/api/GuaranteeAPI.js.map +1 -0
- package/dist/config/ConfigLoader.d.ts +214 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +441 -0
- package/dist/config/ConfigLoader.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/CoverageAnalyzer.d.ts +65 -0
- package/dist/core/CoverageAnalyzer.d.ts.map +1 -0
- package/dist/core/CoverageAnalyzer.js +199 -0
- package/dist/core/CoverageAnalyzer.js.map +1 -0
- package/dist/core/FileExplainer.d.ts +101 -0
- package/dist/core/FileExplainer.d.ts.map +1 -0
- package/dist/core/FileExplainer.js +140 -0
- package/dist/core/FileExplainer.js.map +1 -0
- package/dist/core/FileOverview.d.ts +124 -0
- package/dist/core/FileOverview.d.ts.map +1 -0
- package/dist/core/FileOverview.js +279 -0
- package/dist/core/FileOverview.js.map +1 -0
- package/dist/core/GrafemaUri.d.ts +66 -0
- package/dist/core/GrafemaUri.d.ts.map +1 -0
- package/dist/core/GrafemaUri.js +191 -0
- package/dist/core/GrafemaUri.js.map +1 -0
- package/dist/core/GraphBackend.d.ts +158 -0
- package/dist/core/GraphBackend.d.ts.map +1 -0
- package/dist/core/GraphBackend.js +85 -0
- package/dist/core/GraphBackend.js.map +1 -0
- package/dist/core/GraphFreshnessChecker.d.ts +33 -0
- package/dist/core/GraphFreshnessChecker.d.ts.map +1 -0
- package/dist/core/GraphFreshnessChecker.js +104 -0
- package/dist/core/GraphFreshnessChecker.js.map +1 -0
- package/dist/core/GuaranteeManager.d.ts +254 -0
- package/dist/core/GuaranteeManager.d.ts.map +1 -0
- package/dist/core/GuaranteeManager.js +447 -0
- package/dist/core/GuaranteeManager.js.map +1 -0
- package/dist/core/HashUtils.d.ts +24 -0
- package/dist/core/HashUtils.d.ts.map +1 -0
- package/dist/core/HashUtils.js +46 -0
- package/dist/core/HashUtils.js.map +1 -0
- package/dist/core/IncrementalReanalyzer.d.ts +33 -0
- package/dist/core/IncrementalReanalyzer.d.ts.map +1 -0
- package/dist/core/IncrementalReanalyzer.js +67 -0
- package/dist/core/IncrementalReanalyzer.js.map +1 -0
- package/dist/core/ResourceRegistry.d.ts +17 -0
- package/dist/core/ResourceRegistry.d.ts.map +1 -0
- package/dist/core/ResourceRegistry.js +32 -0
- package/dist/core/ResourceRegistry.js.map +1 -0
- package/dist/core/SemanticId.d.ts +159 -0
- package/dist/core/SemanticId.d.ts.map +1 -0
- package/dist/core/SemanticId.js +291 -0
- package/dist/core/SemanticId.js.map +1 -0
- package/dist/core/VersionManager.d.ts +166 -0
- package/dist/core/VersionManager.d.ts.map +1 -0
- package/dist/core/VersionManager.js +239 -0
- package/dist/core/VersionManager.js.map +1 -0
- package/dist/core/brandNodeInternal.d.ts +14 -0
- package/dist/core/brandNodeInternal.d.ts.map +1 -0
- package/dist/core/brandNodeInternal.js +4 -0
- package/dist/core/brandNodeInternal.js.map +1 -0
- package/dist/core/nodes/GuaranteeNode.d.ts +76 -0
- package/dist/core/nodes/GuaranteeNode.d.ts.map +1 -0
- package/dist/core/nodes/GuaranteeNode.js +118 -0
- package/dist/core/nodes/GuaranteeNode.js.map +1 -0
- package/dist/core/nodes/IssueNode.d.ts +73 -0
- package/dist/core/nodes/IssueNode.d.ts.map +1 -0
- package/dist/core/nodes/IssueNode.js +130 -0
- package/dist/core/nodes/IssueNode.js.map +1 -0
- package/dist/core/nodes/NodeKind.d.ts +104 -0
- package/dist/core/nodes/NodeKind.d.ts.map +1 -0
- package/dist/core/nodes/NodeKind.js +166 -0
- package/dist/core/nodes/NodeKind.js.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts +103 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.js +133 -0
- package/dist/diagnostics/DiagnosticCollector.js.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts +122 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.js +300 -0
- package/dist/diagnostics/DiagnosticReporter.js.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts +31 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.js +44 -0
- package/dist/diagnostics/DiagnosticWriter.js.map +1 -0
- package/dist/diagnostics/categories.d.ts +57 -0
- package/dist/diagnostics/categories.d.ts.map +1 -0
- package/dist/diagnostics/categories.js +71 -0
- package/dist/diagnostics/categories.js.map +1 -0
- package/dist/diagnostics/index.d.ts +17 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +15 -0
- package/dist/diagnostics/index.js.map +1 -0
- package/dist/errors/GrafemaError.d.ts +200 -0
- package/dist/errors/GrafemaError.d.ts.map +1 -0
- package/dist/errors/GrafemaError.js +209 -0
- package/dist/errors/GrafemaError.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions/index.d.ts +8 -0
- package/dist/instructions/index.d.ts.map +1 -0
- package/dist/instructions/index.js +20 -0
- package/dist/instructions/index.js.map +1 -0
- package/dist/instructions/onboarding.md +133 -0
- package/dist/knowledge/KnowledgeBase.d.ts +113 -0
- package/dist/knowledge/KnowledgeBase.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeBase.js +420 -0
- package/dist/knowledge/KnowledgeBase.js.map +1 -0
- package/dist/knowledge/SemanticAddressResolver.d.ts +59 -0
- package/dist/knowledge/SemanticAddressResolver.d.ts.map +1 -0
- package/dist/knowledge/SemanticAddressResolver.js +160 -0
- package/dist/knowledge/SemanticAddressResolver.js.map +1 -0
- package/dist/knowledge/git-ingest.d.ts +58 -0
- package/dist/knowledge/git-ingest.d.ts.map +1 -0
- package/dist/knowledge/git-ingest.js +301 -0
- package/dist/knowledge/git-ingest.js.map +1 -0
- package/dist/knowledge/git-queries.d.ts +86 -0
- package/dist/knowledge/git-queries.d.ts.map +1 -0
- package/dist/knowledge/git-queries.js +177 -0
- package/dist/knowledge/git-queries.js.map +1 -0
- package/dist/knowledge/index.d.ts +14 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/knowledge/index.js +10 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/knowledge/parser.d.ts +39 -0
- package/dist/knowledge/parser.d.ts.map +1 -0
- package/dist/knowledge/parser.js +292 -0
- package/dist/knowledge/parser.js.map +1 -0
- package/dist/knowledge/types.d.ts +133 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/dist/knowledge/types.js +8 -0
- package/dist/knowledge/types.js.map +1 -0
- package/dist/logging/Logger.d.ts +98 -0
- package/dist/logging/Logger.d.ts.map +1 -0
- package/dist/logging/Logger.js +274 -0
- package/dist/logging/Logger.js.map +1 -0
- package/dist/notation/archetypes.d.ts +36 -0
- package/dist/notation/archetypes.d.ts.map +1 -0
- package/dist/notation/archetypes.js +173 -0
- package/dist/notation/archetypes.js.map +1 -0
- package/dist/notation/fold.d.ts +25 -0
- package/dist/notation/fold.d.ts.map +1 -0
- package/dist/notation/fold.js +598 -0
- package/dist/notation/fold.js.map +1 -0
- package/dist/notation/index.d.ts +18 -0
- package/dist/notation/index.d.ts.map +1 -0
- package/dist/notation/index.js +16 -0
- package/dist/notation/index.js.map +1 -0
- package/dist/notation/lodExtractor.d.ts +32 -0
- package/dist/notation/lodExtractor.d.ts.map +1 -0
- package/dist/notation/lodExtractor.js +149 -0
- package/dist/notation/lodExtractor.js.map +1 -0
- package/dist/notation/nameShortener.d.ts +22 -0
- package/dist/notation/nameShortener.d.ts.map +1 -0
- package/dist/notation/nameShortener.js +24 -0
- package/dist/notation/nameShortener.js.map +1 -0
- package/dist/notation/perspectives.d.ts +11 -0
- package/dist/notation/perspectives.d.ts.map +1 -0
- package/dist/notation/perspectives.js +16 -0
- package/dist/notation/perspectives.js.map +1 -0
- package/dist/notation/renderer.d.ts +31 -0
- package/dist/notation/renderer.d.ts.map +1 -0
- package/dist/notation/renderer.js +315 -0
- package/dist/notation/renderer.js.map +1 -0
- package/dist/notation/traceRenderer.d.ts +39 -0
- package/dist/notation/traceRenderer.d.ts.map +1 -0
- package/dist/notation/traceRenderer.js +358 -0
- package/dist/notation/traceRenderer.js.map +1 -0
- package/dist/notation/types.d.ts +66 -0
- package/dist/notation/types.d.ts.map +1 -0
- package/dist/notation/types.js +10 -0
- package/dist/notation/types.js.map +1 -0
- package/dist/queries/NodeContext.d.ts +81 -0
- package/dist/queries/NodeContext.d.ts.map +1 -0
- package/dist/queries/NodeContext.js +196 -0
- package/dist/queries/NodeContext.js.map +1 -0
- package/dist/queries/findCallsInFunction.d.ts +62 -0
- package/dist/queries/findCallsInFunction.d.ts.map +1 -0
- package/dist/queries/findCallsInFunction.js +169 -0
- package/dist/queries/findCallsInFunction.js.map +1 -0
- package/dist/queries/findContainingFunction.d.ts +57 -0
- package/dist/queries/findContainingFunction.d.ts.map +1 -0
- package/dist/queries/findContainingFunction.js +91 -0
- package/dist/queries/findContainingFunction.js.map +1 -0
- package/dist/queries/index.d.ts +18 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/queries/index.js +14 -0
- package/dist/queries/index.js.map +1 -0
- package/dist/queries/traceDataflow.d.ts +65 -0
- package/dist/queries/traceDataflow.d.ts.map +1 -0
- package/dist/queries/traceDataflow.js +754 -0
- package/dist/queries/traceDataflow.js.map +1 -0
- package/dist/queries/traceValues.d.ts +70 -0
- package/dist/queries/traceValues.d.ts.map +1 -0
- package/dist/queries/traceValues.js +373 -0
- package/dist/queries/traceValues.js.map +1 -0
- package/dist/queries/types.d.ts +166 -0
- package/dist/queries/types.d.ts.map +1 -0
- package/dist/queries/types.js +10 -0
- package/dist/queries/types.js.map +1 -0
- package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
- package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/GraphSchemaExtractor.js +125 -0
- package/dist/schema/GraphSchemaExtractor.js.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.js +113 -0
- package/dist/schema/InterfaceSchemaExtractor.js.map +1 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts +356 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.js +748 -0
- package/dist/storage/backends/RFDBServerBackend.js.map +1 -0
- package/dist/storage/backends/typeValidation.d.ts +47 -0
- package/dist/storage/backends/typeValidation.d.ts.map +1 -0
- package/dist/storage/backends/typeValidation.js +141 -0
- package/dist/storage/backends/typeValidation.js.map +1 -0
- package/dist/utils/findRfdbBinary.d.ts +67 -0
- package/dist/utils/findRfdbBinary.d.ts.map +1 -0
- package/dist/utils/findRfdbBinary.js +261 -0
- package/dist/utils/findRfdbBinary.js.map +1 -0
- package/dist/utils/lazyDownload.d.ts +43 -0
- package/dist/utils/lazyDownload.d.ts.map +1 -0
- package/dist/utils/lazyDownload.js +175 -0
- package/dist/utils/lazyDownload.js.map +1 -0
- package/dist/utils/moduleResolution.d.ts +134 -0
- package/dist/utils/moduleResolution.d.ts.map +1 -0
- package/dist/utils/moduleResolution.js +189 -0
- package/dist/utils/moduleResolution.js.map +1 -0
- package/dist/utils/resolveNodeFile.d.ts +13 -0
- package/dist/utils/resolveNodeFile.d.ts.map +1 -0
- package/dist/utils/resolveNodeFile.js +18 -0
- package/dist/utils/resolveNodeFile.js.map +1 -0
- package/dist/utils/startRfdbServer.d.ts +63 -0
- package/dist/utils/startRfdbServer.d.ts.map +1 -0
- package/dist/utils/startRfdbServer.js +142 -0
- package/dist/utils/startRfdbServer.js.map +1 -0
- package/dist/validation/PathValidator.d.ts +80 -0
- package/dist/validation/PathValidator.d.ts.map +1 -0
- package/dist/validation/PathValidator.js +252 -0
- package/dist/validation/PathValidator.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +26 -0
- package/dist/version.js.map +1 -0
- package/package.json +50 -0
- package/src/api/GraphAPI.ts +307 -0
- package/src/api/GuaranteeAPI.ts +402 -0
- package/src/config/ConfigLoader.ts +653 -0
- package/src/config/index.ts +13 -0
- package/src/core/CoverageAnalyzer.ts +243 -0
- package/src/core/FileExplainer.ts +179 -0
- package/src/core/FileOverview.ts +397 -0
- package/src/core/GrafemaUri.ts +216 -0
- package/src/core/GraphBackend.ts +266 -0
- package/src/core/GraphFreshnessChecker.ts +145 -0
- package/src/core/GuaranteeManager.ts +684 -0
- package/src/core/HashUtils.ts +48 -0
- package/src/core/IncrementalReanalyzer.ts +106 -0
- package/src/core/ResourceRegistry.ts +39 -0
- package/src/core/SemanticId.ts +423 -0
- package/src/core/VersionManager.ts +405 -0
- package/src/core/brandNodeInternal.ts +16 -0
- package/src/core/nodes/GuaranteeNode.ts +162 -0
- package/src/core/nodes/IssueNode.ts +177 -0
- package/src/core/nodes/NodeKind.ts +192 -0
- package/src/diagnostics/DiagnosticCollector.ts +170 -0
- package/src/diagnostics/DiagnosticReporter.ts +395 -0
- package/src/diagnostics/DiagnosticWriter.ts +50 -0
- package/src/diagnostics/categories.ts +104 -0
- package/src/diagnostics/index.ts +30 -0
- package/src/errors/GrafemaError.ts +297 -0
- package/src/index.ts +261 -0
- package/src/instructions/index.ts +21 -0
- package/src/instructions/onboarding.md +133 -0
- package/src/knowledge/KnowledgeBase.ts +486 -0
- package/src/knowledge/SemanticAddressResolver.ts +191 -0
- package/src/knowledge/git-ingest.ts +402 -0
- package/src/knowledge/git-queries.ts +269 -0
- package/src/knowledge/index.ts +29 -0
- package/src/knowledge/parser.ts +294 -0
- package/src/knowledge/types.ts +146 -0
- package/src/logging/Logger.ts +303 -0
- package/src/notation/archetypes.ts +189 -0
- package/src/notation/fold.ts +696 -0
- package/src/notation/index.ts +27 -0
- package/src/notation/lodExtractor.ts +177 -0
- package/src/notation/nameShortener.ts +24 -0
- package/src/notation/perspectives.ts +18 -0
- package/src/notation/renderer.ts +394 -0
- package/src/notation/traceRenderer.ts +458 -0
- package/src/notation/types.ts +79 -0
- package/src/queries/NodeContext.ts +280 -0
- package/src/queries/findCallsInFunction.ts +249 -0
- package/src/queries/findContainingFunction.ts +124 -0
- package/src/queries/index.ts +44 -0
- package/src/queries/traceDataflow.ts +838 -0
- package/src/queries/traceValues.ts +531 -0
- package/src/queries/types.ts +191 -0
- package/src/schema/GraphSchemaExtractor.ts +177 -0
- package/src/schema/InterfaceSchemaExtractor.ts +173 -0
- package/src/schema/index.ts +5 -0
- package/src/storage/backends/RFDBServerBackend.ts +895 -0
- package/src/storage/backends/typeValidation.ts +154 -0
- package/src/utils/findRfdbBinary.ts +288 -0
- package/src/utils/lazyDownload.ts +206 -0
- package/src/utils/moduleResolution.ts +271 -0
- package/src/utils/resolveNodeFile.ts +18 -0
- package/src/utils/startRfdbServer.ts +197 -0
- package/src/validation/PathValidator.ts +334 -0
- package/src/version.ts +28 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IssueNode - contract for issue:* nodes
|
|
3
|
+
*
|
|
4
|
+
* Types: issue:security, issue:performance, issue:style, issue:smell
|
|
5
|
+
* ID format: issue:<category>#<hash>
|
|
6
|
+
*
|
|
7
|
+
* Issues represent detected problems in the codebase.
|
|
8
|
+
* They connect to affected code via AFFECTS edges.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { createHash } from 'crypto';
|
|
12
|
+
import type { BaseNodeRecord } from '@grafema/types';
|
|
13
|
+
import { getNamespace } from './NodeKind.js';
|
|
14
|
+
|
|
15
|
+
// Severity type
|
|
16
|
+
export type IssueSeverity = 'error' | 'warning' | 'info';
|
|
17
|
+
|
|
18
|
+
// Issue types
|
|
19
|
+
export type IssueType = `issue:${string}`;
|
|
20
|
+
|
|
21
|
+
export interface IssueNodeRecord extends BaseNodeRecord {
|
|
22
|
+
type: IssueType;
|
|
23
|
+
severity: IssueSeverity;
|
|
24
|
+
category: string;
|
|
25
|
+
message: string;
|
|
26
|
+
plugin: string;
|
|
27
|
+
targetNodeId?: string;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
context?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface IssueNodeOptions {
|
|
33
|
+
context?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Valid severity levels
|
|
37
|
+
const VALID_SEVERITIES = ['error', 'warning', 'info'] as const;
|
|
38
|
+
|
|
39
|
+
export class IssueNode {
|
|
40
|
+
static readonly REQUIRED = ['category', 'severity', 'message', 'plugin', 'file'] as const;
|
|
41
|
+
static readonly OPTIONAL = ['targetNodeId', 'context'] as const;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Generate deterministic issue ID
|
|
45
|
+
* Format: issue:<category>#<hash12>
|
|
46
|
+
*
|
|
47
|
+
* Hash is based on plugin + file + line + column + message
|
|
48
|
+
* This ensures same issue = same ID across analysis runs
|
|
49
|
+
*/
|
|
50
|
+
static generateId(
|
|
51
|
+
category: string,
|
|
52
|
+
plugin: string,
|
|
53
|
+
file: string,
|
|
54
|
+
line: number,
|
|
55
|
+
column: number,
|
|
56
|
+
message: string
|
|
57
|
+
): string {
|
|
58
|
+
const hashInput = `${plugin}|${file}|${line}|${column}|${message}`;
|
|
59
|
+
const hash = createHash('sha256').update(hashInput).digest('hex').substring(0, 12);
|
|
60
|
+
return `issue:${category}#${hash}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create issue node
|
|
65
|
+
*
|
|
66
|
+
* @param category - Issue category (security, performance, style, smell, or custom)
|
|
67
|
+
* @param severity - error | warning | info
|
|
68
|
+
* @param message - Human-readable description
|
|
69
|
+
* @param plugin - Plugin name that detected this issue
|
|
70
|
+
* @param file - File where issue was detected
|
|
71
|
+
* @param line - Line number
|
|
72
|
+
* @param column - Column number (optional, defaults to 0)
|
|
73
|
+
* @param options - Optional fields (context)
|
|
74
|
+
*/
|
|
75
|
+
static create(
|
|
76
|
+
category: string,
|
|
77
|
+
severity: IssueSeverity,
|
|
78
|
+
message: string,
|
|
79
|
+
plugin: string,
|
|
80
|
+
file: string,
|
|
81
|
+
line: number,
|
|
82
|
+
column: number = 0,
|
|
83
|
+
options: IssueNodeOptions = {}
|
|
84
|
+
): IssueNodeRecord {
|
|
85
|
+
if (!category) throw new Error('IssueNode.create: category is required');
|
|
86
|
+
if (!severity) throw new Error('IssueNode.create: severity is required');
|
|
87
|
+
if (!VALID_SEVERITIES.includes(severity)) {
|
|
88
|
+
throw new Error(`IssueNode.create: invalid severity "${severity}". Valid: ${VALID_SEVERITIES.join(', ')}`);
|
|
89
|
+
}
|
|
90
|
+
if (!message) throw new Error('IssueNode.create: message is required');
|
|
91
|
+
if (!plugin) throw new Error('IssueNode.create: plugin is required');
|
|
92
|
+
if (!file) throw new Error('IssueNode.create: file is required');
|
|
93
|
+
|
|
94
|
+
const type = `issue:${category}` as IssueType;
|
|
95
|
+
const id = this.generateId(category, plugin, file, line, column, message);
|
|
96
|
+
const now = Date.now();
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
id,
|
|
100
|
+
type,
|
|
101
|
+
name: message.substring(0, 100), // Truncate for display
|
|
102
|
+
file,
|
|
103
|
+
line,
|
|
104
|
+
column,
|
|
105
|
+
severity,
|
|
106
|
+
category,
|
|
107
|
+
message,
|
|
108
|
+
plugin,
|
|
109
|
+
createdAt: now,
|
|
110
|
+
context: options.context,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Validate issue node
|
|
116
|
+
* @returns array of error messages, empty if valid
|
|
117
|
+
*/
|
|
118
|
+
static validate(node: IssueNodeRecord): string[] {
|
|
119
|
+
const errors: string[] = [];
|
|
120
|
+
|
|
121
|
+
if (!IssueNode.isIssueType(node.type)) {
|
|
122
|
+
errors.push(`Expected issue:* type, got ${node.type}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!node.category) {
|
|
126
|
+
errors.push('Missing required field: category');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!node.severity) {
|
|
130
|
+
errors.push('Missing required field: severity');
|
|
131
|
+
} else if (!VALID_SEVERITIES.includes(node.severity as IssueSeverity)) {
|
|
132
|
+
errors.push(`Invalid severity: ${node.severity}. Valid: ${VALID_SEVERITIES.join(', ')}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!node.message) {
|
|
136
|
+
errors.push('Missing required field: message');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!node.plugin) {
|
|
140
|
+
errors.push('Missing required field: plugin');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return errors;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Parse issue ID into components
|
|
148
|
+
* @param id - full ID (e.g., 'issue:security#a3f2b1c4d5e6')
|
|
149
|
+
* @returns { category, hash } or null if invalid
|
|
150
|
+
*/
|
|
151
|
+
static parseId(id: string): { category: string; hash: string } | null {
|
|
152
|
+
if (!id) return null;
|
|
153
|
+
|
|
154
|
+
const match = id.match(/^issue:([^#]+)#(.+)$/);
|
|
155
|
+
if (!match) return null;
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
category: match[1],
|
|
159
|
+
hash: match[2],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check if type is an issue type
|
|
165
|
+
*/
|
|
166
|
+
static isIssueType(type: string): boolean {
|
|
167
|
+
if (!type) return false;
|
|
168
|
+
return getNamespace(type) === 'issue';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get all known issue categories
|
|
173
|
+
*/
|
|
174
|
+
static getCategories(): string[] {
|
|
175
|
+
return ['security', 'performance', 'style', 'smell'];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node Types - string type system for nodes
|
|
3
|
+
*
|
|
4
|
+
* Base types: FUNCTION, CLASS, METHOD, etc.
|
|
5
|
+
* Namespaced types: http:route, socketio:emit, express:router, etc.
|
|
6
|
+
*
|
|
7
|
+
* Namespace convention:
|
|
8
|
+
* - http:* - HTTP endpoints and requests
|
|
9
|
+
* - express:* - Express.js specifics
|
|
10
|
+
* - socketio:* - Socket.IO
|
|
11
|
+
* - db:* - Database queries
|
|
12
|
+
* - fs:* - Filesystem operations
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// === BASE TYPES ===
|
|
16
|
+
// Abstract types, not tied to language or framework
|
|
17
|
+
|
|
18
|
+
export const NODE_TYPE = {
|
|
19
|
+
// Core code entities
|
|
20
|
+
FUNCTION: 'FUNCTION',
|
|
21
|
+
CLASS: 'CLASS',
|
|
22
|
+
METHOD: 'METHOD',
|
|
23
|
+
VARIABLE: 'VARIABLE',
|
|
24
|
+
PARAMETER: 'PARAMETER',
|
|
25
|
+
CONSTANT: 'CONSTANT',
|
|
26
|
+
LITERAL: 'LITERAL',
|
|
27
|
+
EXPRESSION: 'EXPRESSION', // Generic expression node for data flow tracking
|
|
28
|
+
TYPE_PARAMETER: 'TYPE_PARAMETER',
|
|
29
|
+
|
|
30
|
+
// Module system
|
|
31
|
+
MODULE: 'MODULE',
|
|
32
|
+
IMPORT: 'IMPORT',
|
|
33
|
+
EXPORT: 'EXPORT',
|
|
34
|
+
|
|
35
|
+
// Call graph
|
|
36
|
+
CALL: 'CALL', // unified METHOD_CALL + CALL_SITE
|
|
37
|
+
|
|
38
|
+
// Project structure
|
|
39
|
+
PROJECT: 'PROJECT',
|
|
40
|
+
SERVICE: 'SERVICE',
|
|
41
|
+
FILE: 'FILE',
|
|
42
|
+
SCOPE: 'SCOPE',
|
|
43
|
+
|
|
44
|
+
// External dependencies
|
|
45
|
+
EXTERNAL: 'EXTERNAL',
|
|
46
|
+
EXTERNAL_MODULE: 'EXTERNAL_MODULE',
|
|
47
|
+
|
|
48
|
+
// Generic side effects
|
|
49
|
+
SIDE_EFFECT: 'SIDE_EFFECT',
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
52
|
+
export type BaseNodeType = typeof NODE_TYPE[keyof typeof NODE_TYPE];
|
|
53
|
+
|
|
54
|
+
// === NAMESPACED TYPES ===
|
|
55
|
+
// Types specific to frameworks and libraries
|
|
56
|
+
|
|
57
|
+
export const NAMESPACED_TYPE = {
|
|
58
|
+
// HTTP (generic)
|
|
59
|
+
HTTP_ROUTE: 'http:route',
|
|
60
|
+
HTTP_REQUEST: 'http:request',
|
|
61
|
+
|
|
62
|
+
// Express.js
|
|
63
|
+
EXPRESS_ROUTER: 'express:router',
|
|
64
|
+
EXPRESS_MIDDLEWARE: 'express:middleware',
|
|
65
|
+
EXPRESS_MOUNT: 'express:mount',
|
|
66
|
+
|
|
67
|
+
// Socket.IO
|
|
68
|
+
SOCKETIO_EMIT: 'socketio:emit',
|
|
69
|
+
SOCKETIO_ON: 'socketio:on',
|
|
70
|
+
SOCKETIO_NAMESPACE: 'socketio:namespace',
|
|
71
|
+
|
|
72
|
+
// Database
|
|
73
|
+
DB_QUERY: 'db:query',
|
|
74
|
+
DB_CONNECTION: 'db:connection',
|
|
75
|
+
|
|
76
|
+
// Redis
|
|
77
|
+
REDIS_READ: 'redis:read',
|
|
78
|
+
REDIS_WRITE: 'redis:write',
|
|
79
|
+
REDIS_DELETE: 'redis:delete',
|
|
80
|
+
REDIS_PUBLISH: 'redis:publish',
|
|
81
|
+
REDIS_SUBSCRIBE: 'redis:subscribe',
|
|
82
|
+
REDIS_TRANSACTION: 'redis:transaction',
|
|
83
|
+
REDIS_CONNECTION: 'redis:connection',
|
|
84
|
+
|
|
85
|
+
// Filesystem
|
|
86
|
+
FS_READ: 'fs:read',
|
|
87
|
+
FS_WRITE: 'fs:write',
|
|
88
|
+
FS_OPERATION: 'fs:operation',
|
|
89
|
+
|
|
90
|
+
// Network
|
|
91
|
+
NET_REQUEST: 'net:request',
|
|
92
|
+
NET_STDIO: 'net:stdio',
|
|
93
|
+
|
|
94
|
+
// Events
|
|
95
|
+
EVENT_LISTENER: 'event:listener',
|
|
96
|
+
EVENT_EMIT: 'event:emit',
|
|
97
|
+
|
|
98
|
+
// Guarantees (contract-based)
|
|
99
|
+
GUARANTEE_QUEUE: 'guarantee:queue',
|
|
100
|
+
GUARANTEE_API: 'guarantee:api',
|
|
101
|
+
GUARANTEE_PERMISSION: 'guarantee:permission',
|
|
102
|
+
|
|
103
|
+
// Grafema internal (self-describing pipeline)
|
|
104
|
+
GRAFEMA_PLUGIN: 'grafema:plugin',
|
|
105
|
+
} as const;
|
|
106
|
+
|
|
107
|
+
export type NamespacedNodeType = typeof NAMESPACED_TYPE[keyof typeof NAMESPACED_TYPE];
|
|
108
|
+
|
|
109
|
+
// Combined node type
|
|
110
|
+
export type NodeType = BaseNodeType | NamespacedNodeType | string;
|
|
111
|
+
|
|
112
|
+
// === HELPERS ===
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check if type is namespaced (contains :)
|
|
116
|
+
*/
|
|
117
|
+
export function isNamespacedType(nodeType: string): boolean {
|
|
118
|
+
return nodeType !== undefined && nodeType !== null && nodeType.includes(':');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get namespace from type
|
|
123
|
+
* @returns namespace or null for base types
|
|
124
|
+
*/
|
|
125
|
+
export function getNamespace(nodeType: string): string | null {
|
|
126
|
+
if (!nodeType || !nodeType.includes(':')) return null;
|
|
127
|
+
return nodeType.split(':')[0];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get base name from namespaced type
|
|
132
|
+
*/
|
|
133
|
+
export function getBaseName(nodeType: string): string {
|
|
134
|
+
if (!nodeType) return '';
|
|
135
|
+
if (!nodeType.includes(':')) return nodeType;
|
|
136
|
+
return nodeType.split(':').slice(1).join(':');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Check if type is an endpoint (HTTP route, WebSocket handler, etc.)
|
|
141
|
+
*/
|
|
142
|
+
export function isEndpointType(nodeType: string): boolean {
|
|
143
|
+
if (!nodeType) return false;
|
|
144
|
+
const ns = getNamespace(nodeType);
|
|
145
|
+
return ns === 'http' || ns === 'express' || ns === 'socketio';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Check if type is a side effect (DB, FS, Network)
|
|
150
|
+
*/
|
|
151
|
+
export function isSideEffectType(nodeType: string): boolean {
|
|
152
|
+
if (!nodeType) return false;
|
|
153
|
+
if (nodeType === NODE_TYPE.SIDE_EFFECT) return true;
|
|
154
|
+
const ns = getNamespace(nodeType);
|
|
155
|
+
return ns === 'db' || ns === 'fs' || ns === 'net' || ns === 'redis';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if type matches a pattern with wildcard
|
|
160
|
+
* @param nodeType - node type
|
|
161
|
+
* @param pattern - pattern (e.g., "http:*", "FUNCTION")
|
|
162
|
+
*/
|
|
163
|
+
export function matchesTypePattern(nodeType: string, pattern: string): boolean {
|
|
164
|
+
if (!nodeType || !pattern) return false;
|
|
165
|
+
|
|
166
|
+
// Exact match
|
|
167
|
+
if (nodeType === pattern) return true;
|
|
168
|
+
|
|
169
|
+
// Wildcard match (e.g., "http:*" matches "http:route")
|
|
170
|
+
if (pattern.endsWith(':*')) {
|
|
171
|
+
const patternNs = pattern.slice(0, -2);
|
|
172
|
+
return getNamespace(nodeType) === patternNs;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Check if type is a guarantee type (guarantee:queue, guarantee:api, etc.)
|
|
180
|
+
*/
|
|
181
|
+
export function isGuaranteeType(nodeType: string): boolean {
|
|
182
|
+
if (!nodeType) return false;
|
|
183
|
+
return getNamespace(nodeType) === 'guarantee';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check if type is a grafema internal type (grafema:plugin, etc.)
|
|
188
|
+
*/
|
|
189
|
+
export function isGrafemaType(nodeType: string): boolean {
|
|
190
|
+
if (!nodeType) return false;
|
|
191
|
+
return getNamespace(nodeType) === 'grafema';
|
|
192
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DiagnosticCollector - Collects and filters diagnostics from plugin execution
|
|
3
|
+
*
|
|
4
|
+
* The DiagnosticCollector aggregates errors from PluginResult.errors[],
|
|
5
|
+
* converting both GrafemaError instances (with rich info) and plain Error
|
|
6
|
+
* instances (treated as generic errors) into unified Diagnostic entries.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const collector = new DiagnosticCollector();
|
|
10
|
+
* collector.addFromPluginResult('INDEXING', 'JSModuleIndexer', result);
|
|
11
|
+
*
|
|
12
|
+
* if (collector.hasFatal()) {
|
|
13
|
+
* throw new Error('Fatal error detected');
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* console.log(collector.toDiagnosticsLog());
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { PluginPhase, PluginResult } from '@grafema/types';
|
|
20
|
+
import { GrafemaError, type ResolutionStep, type ResolutionFailureReason } from '../errors/GrafemaError.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Diagnostic entry - unified format for all errors/warnings
|
|
24
|
+
*/
|
|
25
|
+
export interface Diagnostic {
|
|
26
|
+
code: string;
|
|
27
|
+
severity: 'fatal' | 'error' | 'warning' | 'info';
|
|
28
|
+
message: string;
|
|
29
|
+
file?: string;
|
|
30
|
+
line?: number;
|
|
31
|
+
phase: PluginPhase;
|
|
32
|
+
plugin: string;
|
|
33
|
+
timestamp: number;
|
|
34
|
+
suggestion?: string;
|
|
35
|
+
/** Resolution chain for context (REG-332) */
|
|
36
|
+
resolutionChain?: ResolutionStep[];
|
|
37
|
+
/** Failure reason for context-aware suggestions (REG-332) */
|
|
38
|
+
failureReason?: ResolutionFailureReason;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Diagnostic input (without timestamp, which is auto-generated)
|
|
43
|
+
*/
|
|
44
|
+
export type DiagnosticInput = Omit<Diagnostic, 'timestamp'>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* DiagnosticCollector - collects, filters, and formats diagnostics
|
|
48
|
+
*/
|
|
49
|
+
export class DiagnosticCollector {
|
|
50
|
+
private diagnostics: Diagnostic[] = [];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Extract errors from PluginResult and add as diagnostics.
|
|
54
|
+
*
|
|
55
|
+
* GrafemaError instances provide rich info (code, severity, context, suggestion).
|
|
56
|
+
* Plain Error instances are treated as generic errors with code 'ERR_UNKNOWN'.
|
|
57
|
+
*/
|
|
58
|
+
addFromPluginResult(phase: PluginPhase, plugin: string, result: PluginResult): void {
|
|
59
|
+
for (const error of result.errors) {
|
|
60
|
+
if (error instanceof GrafemaError) {
|
|
61
|
+
this.add({
|
|
62
|
+
code: error.code,
|
|
63
|
+
severity: error.severity,
|
|
64
|
+
message: error.message,
|
|
65
|
+
file: error.context.filePath,
|
|
66
|
+
line: error.context.lineNumber,
|
|
67
|
+
phase,
|
|
68
|
+
plugin,
|
|
69
|
+
suggestion: error.suggestion,
|
|
70
|
+
// REG-332: Pass through resolution context
|
|
71
|
+
resolutionChain: error.context.resolutionChain as ResolutionStep[] | undefined,
|
|
72
|
+
failureReason: error.context.failureReason as ResolutionFailureReason | undefined,
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
// Plain Error - treat as generic error
|
|
76
|
+
this.add({
|
|
77
|
+
code: 'ERR_UNKNOWN',
|
|
78
|
+
severity: 'error',
|
|
79
|
+
message: error.message,
|
|
80
|
+
phase,
|
|
81
|
+
plugin,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Add a diagnostic directly.
|
|
89
|
+
* Timestamp is set automatically.
|
|
90
|
+
*/
|
|
91
|
+
add(diagnostic: DiagnosticInput): void {
|
|
92
|
+
this.diagnostics.push({
|
|
93
|
+
...diagnostic,
|
|
94
|
+
timestamp: Date.now(),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get all diagnostics.
|
|
100
|
+
* Returns a copy to prevent external modification.
|
|
101
|
+
*/
|
|
102
|
+
getAll(): Diagnostic[] {
|
|
103
|
+
return [...this.diagnostics];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get diagnostics filtered by phase.
|
|
108
|
+
*/
|
|
109
|
+
getByPhase(phase: PluginPhase): Diagnostic[] {
|
|
110
|
+
return this.diagnostics.filter(d => d.phase === phase);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get diagnostics filtered by plugin name (case-sensitive).
|
|
115
|
+
*/
|
|
116
|
+
getByPlugin(plugin: string): Diagnostic[] {
|
|
117
|
+
return this.diagnostics.filter(d => d.plugin === plugin);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get diagnostics filtered by error code.
|
|
122
|
+
*/
|
|
123
|
+
getByCode(code: string): Diagnostic[] {
|
|
124
|
+
return this.diagnostics.filter(d => d.code === code);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if any fatal diagnostic exists.
|
|
129
|
+
* Fatal errors require immediate stop of analysis.
|
|
130
|
+
*/
|
|
131
|
+
hasFatal(): boolean {
|
|
132
|
+
return this.diagnostics.some(d => d.severity === 'fatal');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Check if any error (including fatal) exists.
|
|
137
|
+
*/
|
|
138
|
+
hasErrors(): boolean {
|
|
139
|
+
return this.diagnostics.some(d => d.severity === 'error' || d.severity === 'fatal');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check if any warning exists.
|
|
144
|
+
*/
|
|
145
|
+
hasWarnings(): boolean {
|
|
146
|
+
return this.diagnostics.some(d => d.severity === 'warning');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get total count of diagnostics.
|
|
151
|
+
*/
|
|
152
|
+
count(): number {
|
|
153
|
+
return this.diagnostics.length;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Format diagnostics as JSON lines (one JSON object per line).
|
|
158
|
+
* Suitable for .grafema/diagnostics.log file.
|
|
159
|
+
*/
|
|
160
|
+
toDiagnosticsLog(): string {
|
|
161
|
+
return this.diagnostics.map(d => JSON.stringify(d)).join('\n');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Clear all diagnostics.
|
|
166
|
+
*/
|
|
167
|
+
clear(): void {
|
|
168
|
+
this.diagnostics = [];
|
|
169
|
+
}
|
|
170
|
+
}
|