@grafema/types 0.1.0-alpha.1

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/src/nodes.ts ADDED
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Node Types - graph node type definitions
3
+ */
4
+
5
+ // === BASE NODE TYPES ===
6
+ export const NODE_TYPE = {
7
+ // Core code entities
8
+ FUNCTION: 'FUNCTION',
9
+ CLASS: 'CLASS',
10
+ METHOD: 'METHOD',
11
+ VARIABLE: 'VARIABLE',
12
+ PARAMETER: 'PARAMETER',
13
+ CONSTANT: 'CONSTANT',
14
+ LITERAL: 'LITERAL',
15
+ EXPRESSION: 'EXPRESSION',
16
+
17
+ // Module system
18
+ MODULE: 'MODULE',
19
+ IMPORT: 'IMPORT',
20
+ EXPORT: 'EXPORT',
21
+
22
+ // Call graph
23
+ CALL: 'CALL',
24
+
25
+ // Project structure
26
+ PROJECT: 'PROJECT',
27
+ SERVICE: 'SERVICE',
28
+ FILE: 'FILE',
29
+ SCOPE: 'SCOPE',
30
+
31
+ // External dependencies
32
+ EXTERNAL: 'EXTERNAL',
33
+ EXTERNAL_MODULE: 'EXTERNAL_MODULE',
34
+
35
+ // Generic side effects
36
+ SIDE_EFFECT: 'SIDE_EFFECT',
37
+ } as const;
38
+
39
+ export type BaseNodeType = typeof NODE_TYPE[keyof typeof NODE_TYPE];
40
+
41
+ // === NAMESPACED NODE TYPES ===
42
+ export const NAMESPACED_TYPE = {
43
+ // HTTP (generic)
44
+ HTTP_ROUTE: 'http:route',
45
+ HTTP_REQUEST: 'http:request',
46
+
47
+ // Express.js
48
+ EXPRESS_ROUTER: 'express:router',
49
+ EXPRESS_MIDDLEWARE: 'express:middleware',
50
+ EXPRESS_MOUNT: 'express:mount',
51
+
52
+ // Socket.IO
53
+ SOCKETIO_EMIT: 'socketio:emit',
54
+ SOCKETIO_ON: 'socketio:on',
55
+ SOCKETIO_NAMESPACE: 'socketio:namespace',
56
+
57
+ // Database
58
+ DB_QUERY: 'db:query',
59
+ DB_CONNECTION: 'db:connection',
60
+
61
+ // Filesystem
62
+ FS_READ: 'fs:read',
63
+ FS_WRITE: 'fs:write',
64
+ FS_OPERATION: 'fs:operation',
65
+
66
+ // Network
67
+ NET_REQUEST: 'net:request',
68
+ NET_STDIO: 'net:stdio',
69
+
70
+ // Events
71
+ EVENT_LISTENER: 'event:listener',
72
+ EVENT_EMIT: 'event:emit',
73
+ } as const;
74
+
75
+ export type NamespacedNodeType = typeof NAMESPACED_TYPE[keyof typeof NAMESPACED_TYPE];
76
+
77
+ // Combined node type
78
+ export type NodeType = BaseNodeType | NamespacedNodeType | string;
79
+
80
+ // === NODE RECORD ===
81
+ // Base interface for all nodes
82
+ export interface BaseNodeRecord {
83
+ id: string;
84
+ stableId?: string;
85
+ type: NodeType;
86
+ name: string;
87
+ file: string;
88
+ line?: number; // Optional - not always available
89
+ column?: number;
90
+ metadata?: Record<string, unknown>;
91
+ // Allow arbitrary additional properties for flexibility
92
+ [key: string]: unknown;
93
+ }
94
+
95
+ // Function node
96
+ export interface FunctionNodeRecord extends BaseNodeRecord {
97
+ type: 'FUNCTION';
98
+ async: boolean;
99
+ generator: boolean;
100
+ exported: boolean;
101
+ arrowFunction: boolean;
102
+ parentScopeId?: string;
103
+ isClassMethod?: boolean;
104
+ className?: string;
105
+ params?: string[];
106
+ }
107
+
108
+ // Class node
109
+ export interface ClassNodeRecord extends BaseNodeRecord {
110
+ type: 'CLASS';
111
+ exported: boolean;
112
+ superClass?: string;
113
+ }
114
+
115
+ // Method node
116
+ export interface MethodNodeRecord extends BaseNodeRecord {
117
+ type: 'METHOD';
118
+ className: string;
119
+ async: boolean;
120
+ static: boolean;
121
+ kind: 'method' | 'get' | 'set' | 'constructor';
122
+ }
123
+
124
+ // Module node
125
+ export interface ModuleNodeRecord extends BaseNodeRecord {
126
+ type: 'MODULE';
127
+ relativePath: string;
128
+ contentHash: string;
129
+ language?: string;
130
+ }
131
+
132
+ // Import node
133
+ export interface ImportNodeRecord extends BaseNodeRecord {
134
+ type: 'IMPORT';
135
+ source: string;
136
+ specifiers: ImportSpecifier[];
137
+ isDefault?: boolean;
138
+ isNamespace?: boolean;
139
+ }
140
+
141
+ export interface ImportSpecifier {
142
+ local: string;
143
+ imported?: string;
144
+ type: 'default' | 'named' | 'namespace';
145
+ }
146
+
147
+ // Export node
148
+ export interface ExportNodeRecord extends BaseNodeRecord {
149
+ type: 'EXPORT';
150
+ exportedName: string;
151
+ localName?: string;
152
+ isDefault?: boolean;
153
+ source?: string;
154
+ }
155
+
156
+ // Variable declaration node
157
+ export interface VariableNodeRecord extends BaseNodeRecord {
158
+ type: 'VARIABLE';
159
+ kind: 'var' | 'let' | 'const';
160
+ exported: boolean;
161
+ }
162
+
163
+ // Call node (unified call site)
164
+ export interface CallNodeRecord extends BaseNodeRecord {
165
+ type: 'CALL';
166
+ callee: string;
167
+ arguments?: number;
168
+ isMethodCall?: boolean;
169
+ objectName?: string;
170
+ }
171
+
172
+ // Service node (project-level)
173
+ export interface ServiceNodeRecord extends BaseNodeRecord {
174
+ type: 'SERVICE';
175
+ projectPath: string;
176
+ }
177
+
178
+ // Scope node
179
+ export interface ScopeNodeRecord extends BaseNodeRecord {
180
+ type: 'SCOPE';
181
+ scopeType: 'function' | 'block' | 'class' | 'module' | 'global';
182
+ parentScopeId?: string;
183
+ }
184
+
185
+ // HTTP Route node
186
+ export interface HttpRouteNodeRecord extends BaseNodeRecord {
187
+ type: 'http:route';
188
+ method: string;
189
+ path: string;
190
+ handler?: string;
191
+ }
192
+
193
+ // Database query node
194
+ export interface DbQueryNodeRecord extends BaseNodeRecord {
195
+ type: 'db:query';
196
+ query: string;
197
+ operation: 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE' | 'UNKNOWN';
198
+ }
199
+
200
+ // Event listener node
201
+ export interface EventListenerNodeRecord extends BaseNodeRecord {
202
+ type: 'event:listener';
203
+ eventName: string;
204
+ objectName: string;
205
+ }
206
+
207
+ // Guarantee priority levels
208
+ export type GuaranteePriority = 'critical' | 'important' | 'observed' | 'tracked';
209
+
210
+ // Guarantee lifecycle status
211
+ export type GuaranteeStatus = 'discovered' | 'reviewed' | 'active' | 'changing' | 'deprecated';
212
+
213
+ // Guarantee node (contract-based)
214
+ export interface GuaranteeNodeRecord extends BaseNodeRecord {
215
+ type: 'guarantee:queue' | 'guarantee:api' | 'guarantee:permission';
216
+ priority: GuaranteePriority;
217
+ status: GuaranteeStatus;
218
+ owner?: string;
219
+ schema?: Record<string, unknown>;
220
+ condition?: string;
221
+ description?: string;
222
+ createdAt?: number;
223
+ updatedAt?: number;
224
+ }
225
+
226
+ // Union of all node types
227
+ export type NodeRecord =
228
+ | FunctionNodeRecord
229
+ | ClassNodeRecord
230
+ | MethodNodeRecord
231
+ | ModuleNodeRecord
232
+ | ImportNodeRecord
233
+ | ExportNodeRecord
234
+ | VariableNodeRecord
235
+ | CallNodeRecord
236
+ | ServiceNodeRecord
237
+ | ScopeNodeRecord
238
+ | HttpRouteNodeRecord
239
+ | DbQueryNodeRecord
240
+ | EventListenerNodeRecord
241
+ | GuaranteeNodeRecord
242
+ | BaseNodeRecord; // fallback for custom types
243
+
244
+ // === HELPER FUNCTIONS ===
245
+ export function isNamespacedType(nodeType: string): boolean {
246
+ return nodeType?.includes(':') ?? false;
247
+ }
248
+
249
+ export function getNamespace(nodeType: string): string | null {
250
+ if (!nodeType?.includes(':')) return null;
251
+ return nodeType.split(':')[0];
252
+ }
253
+
254
+ export function getBaseName(nodeType: string): string {
255
+ if (!nodeType) return '';
256
+ if (!nodeType.includes(':')) return nodeType;
257
+ return nodeType.split(':').slice(1).join(':');
258
+ }
259
+
260
+ export function isEndpointType(nodeType: string): boolean {
261
+ const ns = getNamespace(nodeType);
262
+ return ns === 'http' || ns === 'express' || ns === 'socketio';
263
+ }
264
+
265
+ export function isSideEffectType(nodeType: string): boolean {
266
+ if (nodeType === NODE_TYPE.SIDE_EFFECT) return true;
267
+ const ns = getNamespace(nodeType);
268
+ return ns === 'db' || ns === 'fs' || ns === 'net';
269
+ }
package/src/plugins.ts ADDED
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Plugin Types - types for analysis plugins
3
+ */
4
+
5
+ import type { NodeType, NodeRecord } from './nodes.js';
6
+ import type { EdgeType, EdgeRecord } from './edges.js';
7
+
8
+ // === PLUGIN PHASES ===
9
+ export const PLUGIN_PHASE = {
10
+ DISCOVERY: 'DISCOVERY',
11
+ INDEXING: 'INDEXING',
12
+ ANALYSIS: 'ANALYSIS',
13
+ ENRICHMENT: 'ENRICHMENT',
14
+ VALIDATION: 'VALIDATION',
15
+ } as const;
16
+
17
+ export type PluginPhase = typeof PLUGIN_PHASE[keyof typeof PLUGIN_PHASE];
18
+
19
+ // === PLUGIN METADATA ===
20
+ export interface PluginMetadata {
21
+ name: string;
22
+ phase: PluginPhase;
23
+ priority?: number;
24
+ creates?: {
25
+ nodes?: NodeType[];
26
+ edges?: EdgeType[];
27
+ };
28
+ dependencies?: string[];
29
+ }
30
+
31
+ // === PLUGIN CONTEXT ===
32
+ // Manifest varies by phase (UnitManifest, DiscoveryManifest, or full Manifest)
33
+ // Using unknown to allow all manifest types
34
+ export interface PluginContext {
35
+ manifest?: unknown;
36
+ graph: GraphBackend;
37
+ config?: OrchestratorConfig;
38
+ phase?: PluginPhase;
39
+ projectPath?: string; // Available during DISCOVERY phase
40
+ onProgress?: (info: Record<string, unknown>) => void;
41
+ forceAnalysis?: boolean;
42
+ workerCount?: number;
43
+ }
44
+
45
+ // === PLUGIN RESULT ===
46
+ export interface PluginResult {
47
+ success: boolean;
48
+ created: {
49
+ nodes: number;
50
+ edges: number;
51
+ };
52
+ errors: Error[];
53
+ warnings: string[];
54
+ metadata?: Record<string, unknown>;
55
+ }
56
+
57
+ // === MANIFEST ===
58
+ export interface Manifest {
59
+ services: ManifestService[];
60
+ entrypoints: ManifestEntrypoint[];
61
+ projectPath: string;
62
+ }
63
+
64
+ export interface ManifestService {
65
+ id: string;
66
+ name: string;
67
+ path: string;
68
+ metadata?: Record<string, unknown>;
69
+ }
70
+
71
+ export interface ManifestEntrypoint {
72
+ id: string;
73
+ name: string;
74
+ file: string;
75
+ type: string;
76
+ trigger?: string;
77
+ }
78
+
79
+ // === ORCHESTRATOR CONFIG ===
80
+ export interface OrchestratorConfig {
81
+ projectPath: string;
82
+ plugins?: string[];
83
+ phases?: PluginPhase[];
84
+ parallel?: boolean;
85
+ maxWorkers?: number;
86
+ verbose?: boolean;
87
+ }
88
+
89
+ // === GRAPH BACKEND INTERFACE ===
90
+ // Flexible input types for graph operations
91
+ export interface InputNode {
92
+ id: string;
93
+ type?: string;
94
+ nodeType?: string;
95
+ name?: string;
96
+ file?: string;
97
+ line?: number;
98
+ [key: string]: unknown;
99
+ }
100
+
101
+ export interface InputEdge {
102
+ src: string;
103
+ dst: string;
104
+ type: string;
105
+ [key: string]: unknown;
106
+ }
107
+
108
+ // Minimal interface for graph operations
109
+ export interface GraphBackend {
110
+ addNode(node: InputNode): Promise<void> | void;
111
+ addEdge(edge: InputEdge): Promise<void> | void;
112
+ addNodes(nodes: InputNode[]): Promise<void> | void;
113
+ addEdges(edges: InputEdge[]): Promise<void> | void;
114
+
115
+ getNode(id: string): Promise<NodeRecord | null>;
116
+ queryNodes(filter: NodeFilter): AsyncIterable<NodeRecord> | AsyncGenerator<NodeRecord>;
117
+ getAllNodes(filter?: NodeFilter): Promise<NodeRecord[]>;
118
+
119
+ getOutgoingEdges(nodeId: string, edgeTypes?: EdgeType[] | null): Promise<EdgeRecord[]>;
120
+ getIncomingEdges(nodeId: string, edgeTypes?: EdgeType[] | null): Promise<EdgeRecord[]>;
121
+
122
+ nodeCount(): Promise<number>;
123
+ edgeCount(): Promise<number>;
124
+
125
+ // For GUI/export - use with caution on large graphs
126
+ getAllEdges?(): Promise<EdgeRecord[]>;
127
+
128
+ // Extended query methods
129
+ countNodesByType(types?: string[] | null): Promise<Record<string, number>>;
130
+ countEdgesByType(types?: string[] | null): Promise<Record<string, number>>;
131
+ findByType?(type: string): Promise<string[]>;
132
+ findByAttr?(query: Record<string, unknown>): Promise<string[]>;
133
+ runDatalogQuery?(query: string): Promise<unknown[]>;
134
+ checkGuarantee?(query: string): unknown[] | Promise<unknown[]>;
135
+
136
+ // Optional delete methods
137
+ deleteNode?(id: string): Promise<void>;
138
+ deleteEdge?(src: string, dst: string, type: string): Promise<void>;
139
+
140
+ // Optional persistence
141
+ flush?(): Promise<void>;
142
+ close?(): Promise<void>;
143
+ }
144
+
145
+ export interface NodeFilter {
146
+ type?: NodeType;
147
+ nodeType?: NodeType; // Alias for type (backward compatibility)
148
+ name?: string;
149
+ file?: string;
150
+ [key: string]: unknown;
151
+ }
152
+
153
+ // === PLUGIN BASE CLASS TYPE ===
154
+ export interface IPlugin {
155
+ config: Record<string, unknown>;
156
+ metadata: PluginMetadata;
157
+ initialize?(context: PluginContext): Promise<void>;
158
+ execute(context: PluginContext): Promise<PluginResult>;
159
+ cleanup?(): Promise<void>;
160
+ }
161
+
162
+ // === HELPER FUNCTIONS ===
163
+ export function createSuccessResult(
164
+ created: { nodes: number; edges: number } = { nodes: 0, edges: 0 },
165
+ metadata: Record<string, unknown> = {}
166
+ ): PluginResult {
167
+ return {
168
+ success: true,
169
+ created,
170
+ errors: [],
171
+ warnings: [],
172
+ metadata,
173
+ };
174
+ }
175
+
176
+ export function createErrorResult(
177
+ error: Error,
178
+ created: { nodes: number; edges: number } = { nodes: 0, edges: 0 }
179
+ ): PluginResult {
180
+ return {
181
+ success: false,
182
+ created,
183
+ errors: [error],
184
+ warnings: [],
185
+ metadata: {},
186
+ };
187
+ }