fix(extraction): count all file-level-tracked langs (incl .properties) as indexed (#544)

Completes #357. The no-symbol file-level class is yaml/twig/properties, but the
count fix only covered yaml/twig — so a .properties-only project still printed
"No files found to index" even though the files were stored. Introduce a single
isFileLevelOnlyLanguage predicate (the canonical set behind the tree-sitter
no-symbol branch, xml excluded since its MyBatis extractor emits a file node)
and use it at both count sites and the extraction dispatch so the list can't
drift. Adds .properties regression coverage for indexAll() and indexFiles().

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-05-28 22:47:33 -05:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 839cf63dcb
commit cdbf451440
5 changed files with 57 additions and 8 deletions
+13
View File
@@ -290,6 +290,19 @@ export function isGrammarLoaded(language: Language): boolean {
return languageCache.has(language);
}
/**
* Languages tracked at the file-record level only: parsing emits zero symbol
* nodes, but the file is still stored (and framework resolvers may add per-file
* references later, e.g. Drupal routing yml, Spring `@Value` against
* application.properties). This is the canonical set behind the no-symbol
* branch in `tree-sitter.ts`; `xml` is intentionally excluded because its
* MyBatis extractor emits a file node. Callers use this to count such files as
* indexed rather than skipped, so it must stay in sync with that branch.
*/
export function isFileLevelOnlyLanguage(language: Language): boolean {
return language === 'yaml' || language === 'twig' || language === 'properties';
}
/**
* Get all supported languages (those with grammar definitions).
*/
+6 -6
View File
@@ -17,7 +17,7 @@ import {
} from '../types';
import { QueryBuilder } from '../db/queries';
import { extractFromSource } from './tree-sitter';
import { detectLanguage, isSourceFile, isLanguageSupported, initGrammars, loadGrammarsForLanguages } from './grammars';
import { detectLanguage, isSourceFile, isLanguageSupported, isFileLevelOnlyLanguage, initGrammars, loadGrammarsForLanguages } from './grammars';
import { logDebug, logWarn } from '../errors';
import { validatePathWithinRoot, normalizePath } from '../utils';
import ignore, { Ignore } from 'ignore';
@@ -942,11 +942,11 @@ export class ExtractionOrchestrator {
} else if (result.errors.some((e) => e.severity === 'error')) {
filesErrored++;
} else {
// Files with no symbols but no errors (e.g. yaml, twig) are tracked
// at the file level — count them as indexed so the CLI doesn't
// misleadingly report "No files found to index".
// Files with no symbols but no errors (yaml, twig, properties) are
// tracked at the file level — count them as indexed so the CLI
// doesn't misleadingly report "No files found to index".
const lang = detectLanguage(filePath, content);
if (lang === 'yaml' || lang === 'twig') {
if (isFileLevelOnlyLanguage(lang)) {
filesIndexed++;
} else {
filesSkipped++;
@@ -1117,7 +1117,7 @@ export class ExtractionOrchestrator {
filesErrored++;
} else {
const tracked = this.queries.getFileByPath(filePath);
if (tracked && (tracked.language === 'yaml' || tracked.language === 'twig')) {
if (tracked && isFileLevelOnlyLanguage(tracked.language)) {
filesIndexed++;
} else {
filesSkipped++;
+2 -2
View File
@@ -15,7 +15,7 @@ import {
ExtractionError,
UnresolvedReference,
} from '../types';
import { getParser, detectLanguage, isLanguageSupported } from './grammars';
import { getParser, detectLanguage, isLanguageSupported, isFileLevelOnlyLanguage } from './grammars';
import { generateNodeId, getNodeText, getChildByField, getPrecedingDocstring } from './tree-sitter-helpers';
import type { LanguageExtractor, ExtractorContext } from './tree-sitter-types';
import { EXTRACTORS } from './languages';
@@ -3072,7 +3072,7 @@ export function extractFromSource(
// file node so the watcher tracks it without emitting symbols.
const extractor = new MyBatisExtractor(filePath, source);
result = extractor.extract();
} else if (detectedLanguage === 'yaml' || detectedLanguage === 'twig' || detectedLanguage === 'properties') {
} else if (isFileLevelOnlyLanguage(detectedLanguage)) {
// No symbol extraction at this stage — files are tracked at the file-record
// level only. Framework extractors (Drupal routing yml, Spring `@Value`
// resolution against application.yml/application.properties) run later and