code-graph-context 2.4.0 → 2.4.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.
@@ -525,13 +525,11 @@ export const FAIRSQUARE_FRAMEWORK_SCHEMA = {
525
525
  {
526
526
  type: 'function',
527
527
  pattern: (parsedNode) => {
528
- const node = parsedNode.sourceNode;
529
- if (!node || !Node.isVariableDeclaration(node))
530
- return false;
531
- const name = node.getName();
532
- const typeNode = node.getTypeNode();
528
+ // Use pre-extracted properties (works after AST cleanup in streaming/chunking)
529
+ const name = parsedNode.properties.name;
530
+ const typeAnnotation = parsedNode.properties.typeAnnotation;
533
531
  // Check if variable name ends with "Routes" AND has type ModuleRoute[]
534
- return !!name.endsWith('Routes') && !!typeNode?.getText().includes('ModuleRoute');
532
+ return !!name?.endsWith('Routes') && !!typeAnnotation?.includes('ModuleRoute');
535
533
  },
536
534
  confidence: 1.0,
537
535
  priority: 10,
@@ -696,14 +694,8 @@ export const FAIRSQUARE_FRAMEWORK_SCHEMA = {
696
694
  if (matchingRoutes.length === 0)
697
695
  return false;
698
696
  // CRITICAL FIX: Verify the method belongs to the correct controller
699
- // Find the parent class of this method by checking the AST node
700
- const targetNode = parsedTargetNode.sourceNode;
701
- if (!targetNode || !Node.isMethodDeclaration(targetNode))
702
- return false;
703
- const parentClass = targetNode.getParent();
704
- if (!parentClass || !Node.isClassDeclaration(parentClass))
705
- return false;
706
- const parentClassName = parentClass.getName();
697
+ // Use pre-extracted parentClassName property (works after AST cleanup in streaming/chunking)
698
+ const parentClassName = parsedTargetNode.properties.parentClassName;
707
699
  if (!parentClassName)
708
700
  return false;
709
701
  // Check if any matching route's controller name matches the parent class
@@ -434,7 +434,7 @@ export const NESTJS_FRAMEWORK_SCHEMA = {
434
434
  },
435
435
  {
436
436
  type: 'function',
437
- pattern: (node) => node.getName()?.endsWith('Service'),
437
+ pattern: (parsedNode) => parsedNode.sourceNode?.getName()?.endsWith('Service'),
438
438
  confidence: 0.7,
439
439
  priority: 7,
440
440
  },
@@ -516,7 +516,10 @@ export const NESTJS_FRAMEWORK_SCHEMA = {
516
516
  detectionPatterns: [
517
517
  {
518
518
  type: 'function',
519
- pattern: (node) => {
519
+ pattern: (parsedNode) => {
520
+ const node = parsedNode.sourceNode;
521
+ if (!node)
522
+ return false;
520
523
  const decorators = node.getDecorators?.() ?? [];
521
524
  const messageDecorators = ['MessagePattern', 'EventPattern'];
522
525
  return decorators.some((d) => messageDecorators.includes(d.getName()));
@@ -567,7 +570,10 @@ export const NESTJS_FRAMEWORK_SCHEMA = {
567
570
  detectionPatterns: [
568
571
  {
569
572
  type: 'function',
570
- pattern: (node) => {
573
+ pattern: (parsedNode) => {
574
+ const node = parsedNode.sourceNode;
575
+ if (!node)
576
+ return false;
571
577
  const decorators = node.getDecorators?.() ?? [];
572
578
  const httpDecorators = ['Get', 'Post', 'Put', 'Delete', 'Patch', 'Head', 'Options'];
573
579
  return decorators.some((d) => httpDecorators.includes(d.getName()));
@@ -480,6 +480,12 @@ export const CORE_TYPESCRIPT_SCHEMA = {
480
480
  extraction: { method: 'static', defaultValue: false }, // We'll set this manually
481
481
  neo4j: { indexed: true, unique: false, required: true },
482
482
  },
483
+ {
484
+ name: 'typeAnnotation',
485
+ type: 'string',
486
+ extraction: { method: 'ast', source: 'getTypeNode', transform: 'getText' },
487
+ neo4j: { indexed: false, unique: false, required: false },
488
+ },
483
489
  ],
484
490
  relationships: [],
485
491
  children: {},
@@ -277,16 +277,24 @@ Provide ONLY the JSON response with no additional text, markdown formatting, or
277
277
  frameworkHint = '\nFRAMEWORK DETECTED: React/functional codebase. Use Function nodes for components.';
278
278
  }
279
279
  return `
280
- ACTUAL GRAPH SCHEMA (use these exact labels):
280
+ === VALID NODE LABELS (use ONLY these after the colon) ===
281
+ ${nodeTypes}
281
282
 
282
- Node Types: ${nodeTypes}
283
- Relationship Types: ${relTypes}
284
- Semantic Types: ${semTypes}
283
+ === VALID RELATIONSHIP TYPES ===
284
+ ${relTypes}
285
+
286
+ === SEMANTIC TYPES (these are PROPERTY values, NOT labels) ===
287
+ ${semTypes}
288
+ Query semantic types via property: WHERE n.semanticType = 'TypeName'
285
289
  ${frameworkHint}
286
- CRITICAL: Use ONLY these node labels. Do NOT invent labels like :DbService, :UserService, etc.
287
- For queries about specific classes/services, use: (n:Class {name: 'ClassName'})
288
- For inheritance: (child:Class)-[:EXTENDS]->(parent:Class {name: 'ParentName'})
289
- For decorator-based queries: Use semanticType property with values from the discovered semantic types above.
290
+
291
+ === CRITICAL RULES ===
292
+ 1. Use ONLY the labels listed above after the colon (:Label)
293
+ 2. Semantic types are PROPERTY values, NOT labels
294
+ 3. Class/service names are PROPERTY values, NOT labels
295
+ 4. WRONG: (n:MyService), (n:MyController) - names as labels
296
+ 5. CORRECT: (n:Service {name: 'MyService'}), (n:Controller {name: 'MyController'})
297
+ 6. CORRECT: (n:Class) WHERE n.semanticType = 'Service'
290
298
  `.trim();
291
299
  }
292
300
  catch (error) {
@@ -507,7 +515,7 @@ Remember to include WHERE n.projectId = $projectId for all node patterns.
507
515
  }
508
516
  /**
509
517
  * Load valid labels dynamically from the schema file.
510
- * Returns all keys from rawSchema which represent actual Neo4j labels.
518
+ * Returns all keys from rawSchema AND discoveredSchema.nodeTypes which represent actual Neo4j labels.
511
519
  */
512
520
  loadValidLabelsFromSchema() {
513
521
  // Fallback to core TypeScript labels if schema not available
@@ -535,12 +543,21 @@ Remember to include WHERE n.projectId = $projectId for all node patterns.
535
543
  try {
536
544
  const content = fs.readFileSync(this.schemaPath, 'utf-8');
537
545
  const schema = JSON.parse(content);
538
- if (!schema.rawSchema?.records?.[0]?._fields?.[0]) {
539
- return coreLabels;
546
+ const allLabels = new Set(coreLabels);
547
+ // Extract labels from rawSchema keys
548
+ if (schema.rawSchema?.records?.[0]?._fields?.[0]) {
549
+ const schemaLabels = Object.keys(schema.rawSchema.records[0]._fields[0]);
550
+ schemaLabels.forEach((label) => allLabels.add(label));
551
+ }
552
+ // Also extract labels from discoveredSchema.nodeTypes (includes framework labels)
553
+ if (schema.discoveredSchema?.nodeTypes) {
554
+ for (const nodeType of schema.discoveredSchema.nodeTypes) {
555
+ if (nodeType.label) {
556
+ allLabels.add(nodeType.label);
557
+ }
558
+ }
540
559
  }
541
- // Extract all keys from rawSchema - these are the valid labels
542
- const schemaLabels = Object.keys(schema.rawSchema.records[0]._fields[0]);
543
- return new Set([...coreLabels, ...schemaLabels]);
560
+ return allLabels;
544
561
  }
545
562
  catch {
546
563
  return coreLabels;
@@ -542,6 +542,11 @@ export class TypeScriptParser {
542
542
  return astNode.getName();
543
543
  }
544
544
  break;
545
+ case CoreNodeType.VARIABLE_DECLARATION:
546
+ if (Node.isVariableDeclaration(astNode)) {
547
+ return astNode.getName();
548
+ }
549
+ break;
545
550
  default:
546
551
  return astNode.getKindName();
547
552
  }
@@ -552,13 +557,18 @@ export class TypeScriptParser {
552
557
  return 'Unknown';
553
558
  }
554
559
  extractProperty(astNode, propDef) {
555
- const { method, source, defaultValue } = propDef.extraction;
560
+ const { method, source, defaultValue, transform } = propDef.extraction;
556
561
  try {
557
562
  switch (method) {
558
563
  case 'ast':
559
564
  if (typeof source === 'string') {
560
565
  const fn = astNode[source];
561
- return typeof fn === 'function' ? fn.call(astNode) : defaultValue;
566
+ let result = typeof fn === 'function' ? fn.call(astNode) : defaultValue;
567
+ // Apply transform if specified (e.g., 'getText' on a returned node)
568
+ if (result && transform && typeof result[transform] === 'function') {
569
+ result = result[transform]();
570
+ }
571
+ return result ?? defaultValue;
562
572
  }
563
573
  return defaultValue;
564
574
  case 'function':
@@ -1284,11 +1294,9 @@ export class TypeScriptParser {
1284
1294
  }
1285
1295
  case 'function':
1286
1296
  if (typeof pattern.pattern === 'function') {
1287
- // Pass the AST sourceNode to pattern functions, not the ParsedNode wrapper
1288
- const astNode = node.sourceNode;
1289
- if (!astNode)
1290
- return false;
1291
- return pattern.pattern(astNode);
1297
+ // Pass the ParsedNode to pattern functions
1298
+ // Patterns should use pre-extracted properties for cross-chunk compatibility
1299
+ return pattern.pattern(node);
1292
1300
  }
1293
1301
  return false;
1294
1302
  case 'classname':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-graph-context",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "MCP server that builds code graphs to provide rich context to LLMs",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/drewdrewH/code-graph-context#readme",