homegraph 1.4.1 → 1.5.0
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/README.md +48 -11
- package/dist/bin/homegraph.js +295 -72
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +32 -11
- package/dist/context/index.js.map +1 -1
- package/dist/db/index.d.ts +143 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +293 -16
- package/dist/db/index.js.map +1 -1
- package/dist/db/queries.d.ts +43 -4
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +138 -14
- package/dist/db/queries.js.map +1 -1
- package/dist/db/sqlite-adapter.d.ts +24 -17
- package/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/dist/db/sqlite-adapter.js +292 -36
- package/dist/db/sqlite-adapter.js.map +1 -1
- package/dist/db/wal-valve.d.ts +15 -2
- package/dist/db/wal-valve.d.ts.map +1 -1
- package/dist/db/wal-valve.js +88 -6
- package/dist/db/wal-valve.js.map +1 -1
- package/dist/extraction/arkts-batch-worker.js +3 -2
- package/dist/extraction/arkts-batch-worker.js.map +1 -1
- package/dist/extraction/default-ignore.d.ts +39 -0
- package/dist/extraction/default-ignore.d.ts.map +1 -0
- package/dist/extraction/default-ignore.js +221 -0
- package/dist/extraction/default-ignore.js.map +1 -0
- package/dist/extraction/index.d.ts +9 -10
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +227 -323
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/arkts.d.ts +90 -6
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +1579 -128
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/extraction/store-worker.d.ts +20 -0
- package/dist/extraction/store-worker.d.ts.map +1 -0
- package/dist/extraction/store-worker.js +102 -0
- package/dist/extraction/store-worker.js.map +1 -0
- package/dist/extraction/store-writer.d.ts +48 -0
- package/dist/extraction/store-writer.d.ts.map +1 -0
- package/dist/extraction/store-writer.js +167 -0
- package/dist/extraction/store-writer.js.map +1 -0
- package/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.js +47 -0
- package/dist/extraction/tree-sitter.js.map +1 -1
- package/dist/extraction/wasm-runtime-flags.d.ts +14 -4
- package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/dist/extraction/wasm-runtime-flags.js +55 -7
- package/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/dist/index.d.ts +16 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +135 -97
- package/dist/index.js.map +1 -1
- package/dist/mcp/query-worker.d.ts +2 -2
- package/dist/mcp/query-worker.js +2 -2
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +42 -26
- package/dist/mcp/tools.js.map +1 -1
- package/dist/resolution/callback-synthesizer.d.ts +52 -16
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/dist/resolution/callback-synthesizer.js +234 -180
- package/dist/resolution/callback-synthesizer.js.map +1 -1
- package/dist/resolution/cooperative-yield.d.ts +10 -2
- package/dist/resolution/cooperative-yield.d.ts.map +1 -1
- package/dist/resolution/cooperative-yield.js +6 -4
- package/dist/resolution/cooperative-yield.js.map +1 -1
- package/dist/resolution/frameworks/go.d.ts.map +1 -1
- package/dist/resolution/frameworks/go.js +29 -6
- package/dist/resolution/frameworks/go.js.map +1 -1
- package/dist/resolution/import-resolver.d.ts +2 -3
- package/dist/resolution/import-resolver.d.ts.map +1 -1
- package/dist/resolution/import-resolver.js +166 -7
- package/dist/resolution/import-resolver.js.map +1 -1
- package/dist/resolution/index.d.ts +87 -2
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +739 -131
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/memory-budget.d.ts +48 -0
- package/dist/resolution/memory-budget.d.ts.map +1 -0
- package/dist/resolution/memory-budget.js +162 -0
- package/dist/resolution/memory-budget.js.map +1 -0
- package/dist/resolution/name-matcher.d.ts +12 -1
- package/dist/resolution/name-matcher.d.ts.map +1 -1
- package/dist/resolution/name-matcher.js +439 -97
- package/dist/resolution/name-matcher.js.map +1 -1
- package/dist/resolution/resolver-pool.d.ts +106 -0
- package/dist/resolution/resolver-pool.d.ts.map +1 -0
- package/dist/resolution/resolver-pool.js +344 -0
- package/dist/resolution/resolver-pool.js.map +1 -0
- package/dist/resolution/resolver-worker.d.ts +17 -0
- package/dist/resolution/resolver-worker.d.ts.map +1 -0
- package/dist/resolution/resolver-worker.js +141 -0
- package/dist/resolution/resolver-worker.js.map +1 -0
- package/dist/resolution/types.d.ts +3 -0
- package/dist/resolution/types.d.ts.map +1 -1
- package/dist/spec/build/diff-parser.d.ts +55 -0
- package/dist/spec/build/diff-parser.d.ts.map +1 -0
- package/dist/spec/build/diff-parser.js +205 -0
- package/dist/spec/build/diff-parser.js.map +1 -0
- package/dist/spec/build/git-scanner.d.ts +93 -0
- package/dist/spec/build/git-scanner.d.ts.map +1 -0
- package/dist/spec/build/git-scanner.js +254 -0
- package/dist/spec/build/git-scanner.js.map +1 -0
- package/dist/spec/build/pipeline.d.ts +54 -0
- package/dist/spec/build/pipeline.d.ts.map +1 -0
- package/dist/spec/build/pipeline.js +170 -0
- package/dist/spec/build/pipeline.js.map +1 -0
- package/dist/spec/build/scan.d.ts +48 -0
- package/dist/spec/build/scan.d.ts.map +1 -0
- package/dist/spec/build/scan.js +89 -0
- package/dist/spec/build/scan.js.map +1 -0
- package/dist/spec/build/scope-resolver.d.ts +50 -0
- package/dist/spec/build/scope-resolver.d.ts.map +1 -0
- package/dist/spec/build/scope-resolver.js +105 -0
- package/dist/spec/build/scope-resolver.js.map +1 -0
- package/dist/spec/build/spec-extractor.d.ts +74 -0
- package/dist/spec/build/spec-extractor.d.ts.map +1 -0
- package/dist/spec/build/spec-extractor.js +344 -0
- package/dist/spec/build/spec-extractor.js.map +1 -0
- package/dist/spec/config.d.ts +35 -1
- package/dist/spec/config.d.ts.map +1 -1
- package/dist/spec/config.js +30 -5
- package/dist/spec/config.js.map +1 -1
- package/dist/spec/db/fts.d.ts.map +1 -1
- package/dist/spec/db/fts.js +19 -50
- package/dist/spec/db/fts.js.map +1 -1
- package/dist/spec/db/index.d.ts +5 -3
- package/dist/spec/db/index.d.ts.map +1 -1
- package/dist/spec/db/index.js +16 -1
- package/dist/spec/db/index.js.map +1 -1
- package/dist/spec/db/persist.d.ts +45 -0
- package/dist/spec/db/persist.d.ts.map +1 -0
- package/dist/spec/db/persist.js +66 -0
- package/dist/spec/db/persist.js.map +1 -0
- package/dist/spec/db/relations.d.ts +80 -1
- package/dist/spec/db/relations.d.ts.map +1 -1
- package/dist/spec/db/relations.js +175 -4
- package/dist/spec/db/relations.js.map +1 -1
- package/dist/spec/db/schema.d.ts +4 -0
- package/dist/spec/db/schema.d.ts.map +1 -1
- package/dist/spec/db/schema.js +4 -0
- package/dist/spec/db/schema.js.map +1 -1
- package/dist/spec/db/schema.sql +5 -1
- package/dist/spec/db/spec-node.d.ts +5 -0
- package/dist/spec/db/spec-node.d.ts.map +1 -1
- package/dist/spec/db/spec-node.js +11 -5
- package/dist/spec/db/spec-node.js.map +1 -1
- package/dist/spec/db/sql-utils.d.ts +11 -0
- package/dist/spec/db/sql-utils.d.ts.map +1 -0
- package/dist/spec/db/sql-utils.js +19 -0
- package/dist/spec/db/sql-utils.js.map +1 -0
- package/dist/spec/evolve/cluster-context.d.ts +30 -0
- package/dist/spec/evolve/cluster-context.d.ts.map +1 -0
- package/dist/spec/evolve/cluster-context.js +78 -0
- package/dist/spec/evolve/cluster-context.js.map +1 -0
- package/dist/spec/evolve/commit-spec-analyzer.d.ts +51 -0
- package/dist/spec/evolve/commit-spec-analyzer.d.ts.map +1 -0
- package/dist/spec/evolve/commit-spec-analyzer.js +88 -0
- package/dist/spec/evolve/commit-spec-analyzer.js.map +1 -0
- package/dist/spec/evolve/commit-spec-persister.d.ts +53 -0
- package/dist/spec/evolve/commit-spec-persister.d.ts.map +1 -0
- package/dist/spec/evolve/commit-spec-persister.js +93 -0
- package/dist/spec/evolve/commit-spec-persister.js.map +1 -0
- package/dist/spec/evolve/impact-locator.d.ts +23 -7
- package/dist/spec/evolve/impact-locator.d.ts.map +1 -1
- package/dist/spec/evolve/impact-locator.js +58 -14
- package/dist/spec/evolve/impact-locator.js.map +1 -1
- package/dist/spec/evolve/pipeline.d.ts +62 -25
- package/dist/spec/evolve/pipeline.d.ts.map +1 -1
- package/dist/spec/evolve/pipeline.js +436 -457
- package/dist/spec/evolve/pipeline.js.map +1 -1
- package/dist/spec/evolve/spec-rewriter.d.ts +13 -13
- package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -1
- package/dist/spec/evolve/spec-rewriter.js +45 -45
- package/dist/spec/evolve/spec-rewriter.js.map +1 -1
- package/dist/spec/git/commits.d.ts +85 -0
- package/dist/spec/git/commits.d.ts.map +1 -0
- package/dist/spec/git/commits.js +218 -0
- package/dist/spec/git/commits.js.map +1 -0
- package/dist/spec/git/exec.d.ts +13 -0
- package/dist/spec/git/exec.d.ts.map +1 -0
- package/dist/spec/git/exec.js +19 -0
- package/dist/spec/git/exec.js.map +1 -0
- package/dist/spec/git/index.d.ts +9 -0
- package/dist/spec/git/index.d.ts.map +1 -0
- package/dist/spec/git/index.js +22 -0
- package/dist/spec/git/index.js.map +1 -0
- package/dist/spec/git-utils.d.ts +8 -0
- package/dist/spec/git-utils.d.ts.map +1 -0
- package/dist/spec/git-utils.js +14 -0
- package/dist/spec/git-utils.js.map +1 -0
- package/dist/spec/graph/index.d.ts +8 -0
- package/dist/spec/graph/index.d.ts.map +1 -0
- package/dist/spec/graph/index.js +17 -0
- package/dist/spec/graph/index.js.map +1 -0
- package/dist/spec/graph/queries.d.ts +6 -35
- package/dist/spec/graph/queries.d.ts.map +1 -1
- package/dist/spec/graph/queries.js +71 -248
- package/dist/spec/graph/queries.js.map +1 -1
- package/dist/spec/llm/agent-client.d.ts +59 -0
- package/dist/spec/llm/agent-client.d.ts.map +1 -0
- package/dist/spec/llm/agent-client.js +213 -0
- package/dist/spec/llm/agent-client.js.map +1 -0
- package/dist/spec/llm/agents/claude-code.d.ts +32 -0
- package/dist/spec/llm/agents/claude-code.d.ts.map +1 -0
- package/dist/spec/llm/agents/claude-code.js +125 -0
- package/dist/spec/llm/agents/claude-code.js.map +1 -0
- package/dist/spec/llm/agents/codex.d.ts +32 -0
- package/dist/spec/llm/agents/codex.d.ts.map +1 -0
- package/dist/spec/llm/agents/codex.js +145 -0
- package/dist/spec/llm/agents/codex.js.map +1 -0
- package/dist/spec/llm/agents/detect-utils.d.ts +28 -0
- package/dist/spec/llm/agents/detect-utils.d.ts.map +1 -0
- package/dist/spec/llm/agents/detect-utils.js +91 -0
- package/dist/spec/llm/agents/detect-utils.js.map +1 -0
- package/dist/spec/llm/agents/deveco-code.d.ts +33 -0
- package/dist/spec/llm/agents/deveco-code.d.ts.map +1 -0
- package/dist/spec/llm/agents/deveco-code.js +165 -0
- package/dist/spec/llm/agents/deveco-code.js.map +1 -0
- package/dist/spec/llm/agents/index.d.ts +31 -0
- package/dist/spec/llm/agents/index.d.ts.map +1 -0
- package/dist/spec/llm/agents/index.js +65 -0
- package/dist/spec/llm/agents/index.js.map +1 -0
- package/dist/spec/llm/agents/types.d.ts +76 -0
- package/dist/spec/llm/agents/types.d.ts.map +1 -0
- package/dist/spec/llm/agents/types.js +15 -0
- package/dist/spec/llm/agents/types.js.map +1 -0
- package/dist/spec/llm/client.d.ts +31 -11
- package/dist/spec/llm/client.d.ts.map +1 -1
- package/dist/spec/llm/client.js +143 -81
- package/dist/spec/llm/client.js.map +1 -1
- package/dist/spec/llm/factory.d.ts +41 -0
- package/dist/spec/llm/factory.d.ts.map +1 -0
- package/dist/spec/llm/factory.js +80 -0
- package/dist/spec/llm/factory.js.map +1 -0
- package/dist/spec/llm/prompts.d.ts +24 -8
- package/dist/spec/llm/prompts.d.ts.map +1 -1
- package/dist/spec/llm/prompts.js +100 -50
- package/dist/spec/llm/prompts.js.map +1 -1
- package/dist/spec/llm/retry.d.ts +53 -0
- package/dist/spec/llm/retry.d.ts.map +1 -0
- package/dist/spec/llm/retry.js +153 -0
- package/dist/spec/llm/retry.js.map +1 -0
- package/dist/spec/mine/clusterer.d.ts +63 -0
- package/dist/spec/mine/clusterer.d.ts.map +1 -0
- package/dist/spec/mine/clusterer.js +904 -0
- package/dist/spec/mine/clusterer.js.map +1 -0
- package/dist/spec/mine/clustering/features.d.ts +38 -0
- package/dist/spec/mine/clustering/features.d.ts.map +1 -0
- package/dist/spec/mine/clustering/features.js +108 -0
- package/dist/spec/mine/clustering/features.js.map +1 -0
- package/dist/spec/mine/clustering/index.d.ts +62 -0
- package/dist/spec/mine/clustering/index.d.ts.map +1 -0
- package/dist/spec/mine/clustering/index.js +259 -0
- package/dist/spec/mine/clustering/index.js.map +1 -0
- package/dist/spec/mine/clustering/leiden.d.ts +61 -0
- package/dist/spec/mine/clustering/leiden.d.ts.map +1 -0
- package/dist/spec/mine/clustering/leiden.js +489 -0
- package/dist/spec/mine/clustering/leiden.js.map +1 -0
- package/dist/spec/mine/clustering/text-similarity.d.ts +22 -0
- package/dist/spec/mine/clustering/text-similarity.d.ts.map +1 -0
- package/dist/spec/mine/clustering/text-similarity.js +98 -0
- package/dist/spec/mine/clustering/text-similarity.js.map +1 -0
- package/dist/spec/mine/generator.d.ts +54 -0
- package/dist/spec/mine/generator.d.ts.map +1 -0
- package/dist/spec/mine/generator.js +267 -0
- package/dist/spec/mine/generator.js.map +1 -0
- package/dist/spec/mine/persist.d.ts +37 -0
- package/dist/spec/mine/persist.d.ts.map +1 -0
- package/dist/spec/mine/persist.js +170 -0
- package/dist/spec/mine/persist.js.map +1 -0
- package/dist/spec/mine/pipeline.d.ts +41 -0
- package/dist/spec/mine/pipeline.d.ts.map +1 -0
- package/dist/spec/mine/pipeline.js +236 -0
- package/dist/spec/mine/pipeline.js.map +1 -0
- package/dist/spec/mine/progress-handler.d.ts +22 -0
- package/dist/spec/mine/progress-handler.d.ts.map +1 -0
- package/dist/spec/mine/progress-handler.js +108 -0
- package/dist/spec/mine/progress-handler.js.map +1 -0
- package/dist/spec/mine/progress.d.ts +23 -0
- package/dist/spec/mine/progress.d.ts.map +1 -0
- package/dist/spec/mine/progress.js +12 -0
- package/dist/spec/mine/progress.js.map +1 -0
- package/dist/spec/mine/scanner.d.ts +59 -0
- package/dist/spec/mine/scanner.d.ts.map +1 -0
- package/dist/spec/mine/scanner.js +383 -0
- package/dist/spec/mine/scanner.js.map +1 -0
- package/dist/spec/types.d.ts +32 -0
- package/dist/spec/types.d.ts.map +1 -1
- package/dist/spec/ui/index.d.ts +9 -0
- package/dist/spec/ui/index.d.ts.map +1 -0
- package/dist/spec/ui/index.js +16 -0
- package/dist/spec/ui/index.js.map +1 -0
- package/dist/spec/ui/progress-handler.d.ts +33 -0
- package/dist/spec/ui/progress-handler.d.ts.map +1 -0
- package/dist/spec/ui/progress-handler.js +132 -0
- package/dist/spec/ui/progress-handler.js.map +1 -0
- package/dist/spec/ui/progress.d.ts +24 -0
- package/dist/spec/ui/progress.d.ts.map +1 -0
- package/dist/spec/ui/progress.js +13 -0
- package/dist/spec/ui/progress.js.map +1 -0
- package/dist/spec/utils/fs.d.ts +45 -0
- package/dist/spec/utils/fs.d.ts.map +1 -0
- package/dist/spec/utils/fs.js +163 -0
- package/dist/spec/utils/fs.js.map +1 -0
- package/dist/spec/utils/index.d.ts +12 -0
- package/dist/spec/utils/index.d.ts.map +1 -0
- package/dist/spec/utils/index.js +26 -0
- package/dist/spec/utils/index.js.map +1 -0
- package/dist/spec/utils/meta.d.ts +32 -0
- package/dist/spec/utils/meta.d.ts.map +1 -0
- package/dist/spec/utils/meta.js +122 -0
- package/dist/spec/utils/meta.js.map +1 -0
- package/dist/spec/utils/truncate.d.ts +86 -0
- package/dist/spec/utils/truncate.d.ts.map +1 -0
- package/dist/spec/utils/truncate.js +172 -0
- package/dist/spec/utils/truncate.js.map +1 -0
- package/dist/spec/utils.d.ts +4 -16
- package/dist/spec/utils.d.ts.map +1 -1
- package/dist/spec/utils.js +6 -58
- package/dist/spec/utils.js.map +1 -1
- package/dist/sync/watcher.d.ts +25 -1
- package/dist/sync/watcher.d.ts.map +1 -1
- package/dist/sync/watcher.js +76 -3
- package/dist/sync/watcher.js.map +1 -1
- package/dist/telemetry/index.js +3 -3
- package/dist/telemetry/index.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -3
package/dist/extraction/index.js
CHANGED
|
@@ -41,9 +41,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
41
41
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
42
|
};
|
|
43
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
-
exports.loadAllGrammars = exports.loadGrammarsForLanguages = exports.initGrammars = exports.getSupportedLanguages = exports.isGrammarLoaded = exports.isLanguageSupported = exports.isSourceFile = exports.detectLanguage = exports.extractFromSource = exports.ExtractionOrchestrator = exports.ScopeIgnore = void 0;
|
|
44
|
+
exports.loadAllGrammars = exports.loadGrammarsForLanguages = exports.initGrammars = exports.getSupportedLanguages = exports.isGrammarLoaded = exports.isLanguageSupported = exports.isSourceFile = exports.detectLanguage = exports.extractFromSource = exports.ExtractionOrchestrator = exports.ScopeIgnore = exports.buildDefaultIgnore = void 0;
|
|
45
45
|
exports.hashContent = hashContent;
|
|
46
|
-
exports.buildDefaultIgnore = buildDefaultIgnore;
|
|
47
46
|
exports.buildScopeIgnore = buildScopeIgnore;
|
|
48
47
|
exports.discoverEmbeddedRepoRoots = discoverEmbeddedRepoRoots;
|
|
49
48
|
exports.findUnindexedIgnoredRepos = findUnindexedIgnoredRepos;
|
|
@@ -57,12 +56,17 @@ const crypto = __importStar(require("crypto"));
|
|
|
57
56
|
const child_process_1 = require("child_process");
|
|
58
57
|
const tree_sitter_1 = require("./tree-sitter");
|
|
59
58
|
const parse_pool_1 = require("./parse-pool");
|
|
59
|
+
const store_writer_1 = require("./store-writer");
|
|
60
|
+
const cooperative_yield_1 = require("../resolution/cooperative-yield");
|
|
60
61
|
const grammars_1 = require("./grammars");
|
|
61
62
|
const project_config_1 = require("../project-config");
|
|
62
63
|
const directory_1 = require("../directory");
|
|
63
64
|
const errors_1 = require("../errors");
|
|
64
65
|
const utils_1 = require("../utils");
|
|
65
66
|
const ignore_1 = __importDefault(require("ignore"));
|
|
67
|
+
const default_ignore_1 = require("./default-ignore");
|
|
68
|
+
var default_ignore_2 = require("./default-ignore");
|
|
69
|
+
Object.defineProperty(exports, "buildDefaultIgnore", { enumerable: true, get: function () { return default_ignore_2.buildDefaultIgnore; } });
|
|
66
70
|
const frameworks_1 = require("../resolution/frameworks");
|
|
67
71
|
const context_1 = require("./context");
|
|
68
72
|
const arkts_1 = require("./languages/arkts");
|
|
@@ -109,176 +113,6 @@ function hashContent(content) {
|
|
|
109
113
|
* symbols. 1 MB covers essentially all hand-written source.
|
|
110
114
|
*/
|
|
111
115
|
const MAX_FILE_SIZE = 1024 * 1024;
|
|
112
|
-
/**
|
|
113
|
-
* Directory names that are dependency, build, cache, or tooling output across the
|
|
114
|
-
* languages/frameworks HomeGraph supports — curated from the canonical
|
|
115
|
-
* github/gitignore templates. Excluded by default so the graph reflects your code,
|
|
116
|
-
* not third-party noise, without requiring a `.gitignore` (issue #407). The
|
|
117
|
-
* exclusion applies uniformly (git or not, tracked or not); the only opt-in is an
|
|
118
|
-
* explicit `.gitignore` negation (e.g. `!vendor/`). First-party-prone or generic
|
|
119
|
-
* names (`packages`, `lib`, `app`, `bin`, `src`, `deps`, `env`, `tmp`, `storage`,
|
|
120
|
-
* `Library`) are deliberately NOT listed, to avoid ever hiding real source.
|
|
121
|
-
*
|
|
122
|
-
* Only dirs that actually contain *indexable source* (or are enormous) earn a slot
|
|
123
|
-
* — IDE/state dirs like `.idea`/`.vs` are omitted because HomeGraph indexes only
|
|
124
|
-
* recognized source extensions, so they produce no symbols regardless.
|
|
125
|
-
*/
|
|
126
|
-
const DEFAULT_IGNORE_DIRS = new Set([
|
|
127
|
-
// JS / TS — dependency directories
|
|
128
|
-
'node_modules', 'bower_components', 'jspm_packages', 'web_modules',
|
|
129
|
-
'.yarn', '.pnpm-store',
|
|
130
|
-
// JS / TS — framework & bundler build / cache / deploy output
|
|
131
|
-
'.next', '.nuxt', '.svelte-kit', '.turbo', '.vite', '.parcel-cache', '.angular',
|
|
132
|
-
'.docusaurus', 'storybook-static', '.vinxi', '.nitro', 'out-tsc',
|
|
133
|
-
'.vercel', '.netlify', '.wrangler',
|
|
134
|
-
// Build output (common across ecosystems)
|
|
135
|
-
'dist', 'build', 'out', '.output',
|
|
136
|
-
// Test / coverage
|
|
137
|
-
'coverage', '.nyc_output',
|
|
138
|
-
// Python
|
|
139
|
-
'__pycache__', '__pypackages__', '.venv', 'venv', '.pixi', '.pdm-build',
|
|
140
|
-
'.mypy_cache', '.pytest_cache', '.ruff_cache', '.tox', '.nox', '.hypothesis',
|
|
141
|
-
'.ipynb_checkpoints', '.eggs',
|
|
142
|
-
// Rust / JVM (Maven, Gradle, Scala)
|
|
143
|
-
'target', '.gradle',
|
|
144
|
-
// .NET
|
|
145
|
-
'obj',
|
|
146
|
-
// Vendored deps (Go, PHP/Composer, Ruby/Bundler)
|
|
147
|
-
'vendor',
|
|
148
|
-
// Swift / iOS
|
|
149
|
-
'.build', 'Pods', 'Carthage', 'DerivedData', '.swiftpm',
|
|
150
|
-
// Dart / Flutter
|
|
151
|
-
'.dart_tool', '.pub-cache',
|
|
152
|
-
// Native (Android NDK, C/C++ deps)
|
|
153
|
-
'.cxx', '.externalNativeBuild', 'vcpkg_installed',
|
|
154
|
-
// Scala tooling
|
|
155
|
-
'.bloop', '.metals',
|
|
156
|
-
// Lua / Luau (LuaRocks)
|
|
157
|
-
'lua_modules', '.luarocks',
|
|
158
|
-
// Delphi / RAD Studio IDE backups (duplicate .pas source — would double-count)
|
|
159
|
-
'__history', '__recovery',
|
|
160
|
-
// Generic cache
|
|
161
|
-
'.cache',
|
|
162
|
-
]);
|
|
163
|
-
/**
|
|
164
|
-
* Android resource directory types. A `res/` tree holds ONLY non-code resources —
|
|
165
|
-
* layouts, drawables, value bags (strings/colors/styles), menus, navigation
|
|
166
|
-
* graphs — split into one typed subdirectory per kind, optionally density/locale/
|
|
167
|
-
* version-qualified (`values-es`, `drawable-hdpi`, `layout-v21`, …). None of it
|
|
168
|
-
* yields an extractable code symbol, yet on an Android app it DOMINATES the tree
|
|
169
|
-
* (one report: 26k XML files = 97% of the project, 0 symbols), bloating the DB,
|
|
170
|
-
* slowing indexing, and skewing both the file count and `codegraph_explore`
|
|
171
|
-
* results (#1047). So these are excluded by default. The structure is
|
|
172
|
-
* self-identifying — a non-Android project has no `res/layout/` etc., so it's
|
|
173
|
-
* untouched — and the only XML that DOES produce symbols (MyBatis mappers) lives
|
|
174
|
-
* under `src/main/resources/`, never `res/`, so nothing useful is dropped.
|
|
175
|
-
* `res/raw/` is deliberately NOT here: it holds arbitrary bundled assets that can
|
|
176
|
-
* be code-ish (a `.sql` schema, a `.js`), so we leave it indexed. Override any of
|
|
177
|
-
* these with a `.gitignore` negation (e.g. `!res/values/`).
|
|
178
|
-
*/
|
|
179
|
-
const ANDROID_RES_TYPES = [
|
|
180
|
-
'anim', 'animator', 'color', 'drawable', 'font', 'layout',
|
|
181
|
-
'menu', 'mipmap', 'navigation', 'transition', 'values', 'xml',
|
|
182
|
-
];
|
|
183
|
-
/** Gitignore-style patterns for the `ignore` matcher: the dirs above plus a few globs. */
|
|
184
|
-
const DEFAULT_IGNORE_PATTERNS = [
|
|
185
|
-
...Array.from(DEFAULT_IGNORE_DIRS, (d) => `${d}/`),
|
|
186
|
-
'*.egg-info/', // Python packaging metadata
|
|
187
|
-
'cmake-build-*/', // CLion / CMake build trees
|
|
188
|
-
'bazel-*/', // Bazel output symlink trees
|
|
189
|
-
// Android resource dirs at any depth, with their qualifier variants (#1047).
|
|
190
|
-
...ANDROID_RES_TYPES.map((t) => `**/res/${t}*/`),
|
|
191
|
-
];
|
|
192
|
-
/** True if `buf` decodes as strict UTF-8 (no invalid byte sequences). */
|
|
193
|
-
function isValidUtf8(buf) {
|
|
194
|
-
try {
|
|
195
|
-
new TextDecoder('utf-8', { fatal: true }).decode(buf);
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
return false;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Read a `.gitignore` and return patterns safe to hand to the `ignore` matcher —
|
|
204
|
-
* never throwing, even when the file isn't real gitignore text. Two failure
|
|
205
|
-
* modes, both seen in the wild (issue #682):
|
|
206
|
-
*
|
|
207
|
-
* - The file isn't valid UTF-8 — e.g. transparently encrypted in place by
|
|
208
|
-
* corporate DLP / endpoint-security software, leaving a UTF-16 header plus
|
|
209
|
-
* ciphertext. None of it is meaningful patterns, so the whole file is skipped.
|
|
210
|
-
* - The file is text but a single line can't be compiled to a regex by the
|
|
211
|
-
* `ignore` library — `\\[` and friends throw "Unterminated character class".
|
|
212
|
-
* Crucially the throw is LAZY (at match time, not `.add()`), so it would
|
|
213
|
-
* otherwise escape mid-scan. That one pattern is dropped; the rest are kept.
|
|
214
|
-
*
|
|
215
|
-
* Either way a warning that NAMES the file is logged (the reporter couldn't tell
|
|
216
|
-
* which `.gitignore` was at fault) and indexing continues instead of aborting.
|
|
217
|
-
* Returns '' when there's nothing usable.
|
|
218
|
-
*/
|
|
219
|
-
function readGitignorePatterns(giPath) {
|
|
220
|
-
let buf;
|
|
221
|
-
try {
|
|
222
|
-
buf = fs.readFileSync(giPath);
|
|
223
|
-
}
|
|
224
|
-
catch {
|
|
225
|
-
return ''; // unreadable (permissions / race) — treat as absent
|
|
226
|
-
}
|
|
227
|
-
// A NUL byte never appears in real gitignore text, and a fatal UTF-8 decode
|
|
228
|
-
// catches the rest. Such a file isn't ignore patterns at all.
|
|
229
|
-
if (buf.includes(0) || !isValidUtf8(buf)) {
|
|
230
|
-
(0, errors_1.logWarn)('Ignoring a .gitignore that is not valid UTF-8 text — it may have been encrypted ' +
|
|
231
|
-
'in place by endpoint-security software. Indexing continues without it.', { file: giPath });
|
|
232
|
-
return '';
|
|
233
|
-
}
|
|
234
|
-
const content = buf.toString('utf-8');
|
|
235
|
-
// Fast path: one `.ignores()` call forces the library to compile EVERY rule,
|
|
236
|
-
// so if it doesn't throw, the whole file is safe to use verbatim.
|
|
237
|
-
try {
|
|
238
|
-
(0, ignore_1.default)().add(content).ignores('.homegraph-probe');
|
|
239
|
-
return content;
|
|
240
|
-
}
|
|
241
|
-
catch {
|
|
242
|
-
// Fall through: a line is uncompilable — keep the good ones, drop the bad.
|
|
243
|
-
}
|
|
244
|
-
const kept = [];
|
|
245
|
-
let dropped = 0;
|
|
246
|
-
for (const line of content.split(/\r?\n/)) {
|
|
247
|
-
try {
|
|
248
|
-
(0, ignore_1.default)().add(line).ignores('.homegraph-probe');
|
|
249
|
-
kept.push(line);
|
|
250
|
-
}
|
|
251
|
-
catch {
|
|
252
|
-
dropped++;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
if (dropped > 0) {
|
|
256
|
-
(0, errors_1.logWarn)(`Skipped ${dropped} unparseable pattern(s) in a .gitignore; the rest are applied.`, { file: giPath });
|
|
257
|
-
}
|
|
258
|
-
return kept.join('\n');
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* An `ignore` matcher seeded with the built-in defaults, merged with the project's
|
|
262
|
-
* root .gitignore so a negation there (e.g. `!vendor/`) overrides a default. Shared
|
|
263
|
-
* by both enumeration paths so behavior is identical with or without git — and so
|
|
264
|
-
* the defaults apply to tracked files too (committing a dependency dir doesn't make
|
|
265
|
-
* it project code; the explicit `.gitignore` negation is the only opt-in).
|
|
266
|
-
*/
|
|
267
|
-
function buildDefaultIgnore(rootDir) {
|
|
268
|
-
const ig = (0, ignore_1.default)().add(DEFAULT_IGNORE_PATTERNS);
|
|
269
|
-
const rootGitignore = path.join(rootDir, '.gitignore');
|
|
270
|
-
if (fs.existsSync(rootGitignore))
|
|
271
|
-
ig.add(readGitignorePatterns(rootGitignore));
|
|
272
|
-
return ig;
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Defaults-only ignore matcher (no root `.gitignore` merged). Used wherever the
|
|
276
|
-
* parent repo's own ignore rules must NOT apply — inside embedded child repos,
|
|
277
|
-
* whose gitignore semantics their own `git ls-files` already enforced (#514).
|
|
278
|
-
*/
|
|
279
|
-
function defaultsOnlyIgnore() {
|
|
280
|
-
return (0, ignore_1.default)().add(DEFAULT_IGNORE_PATTERNS);
|
|
281
|
-
}
|
|
282
116
|
/**
|
|
283
117
|
* Matcher for the project's `homegraph.json` `includeIgnored` patterns — the
|
|
284
118
|
* explicit opt-in to index embedded git repos living inside gitignored
|
|
@@ -377,7 +211,7 @@ function includeStaticRoots(patterns) {
|
|
|
377
211
|
*/
|
|
378
212
|
function collectIncludedFiles(rootDir, include, exclude, roots, overrides) {
|
|
379
213
|
const out = new Set();
|
|
380
|
-
const defaults = defaultsOnlyIgnore();
|
|
214
|
+
const defaults = (0, default_ignore_1.defaultsOnlyIgnore)();
|
|
381
215
|
const visited = new Set();
|
|
382
216
|
const consider = (abs, rel, isDir) => {
|
|
383
217
|
if (isDir) {
|
|
@@ -544,7 +378,7 @@ function classifyGitDir(absDir) {
|
|
|
544
378
|
*/
|
|
545
379
|
function findNestedGitRepos(absDir, relPrefix) {
|
|
546
380
|
const found = [];
|
|
547
|
-
const defaults = defaultsOnlyIgnore();
|
|
381
|
+
const defaults = (0, default_ignore_1.defaultsOnlyIgnore)();
|
|
548
382
|
const queue = [
|
|
549
383
|
{ abs: absDir, rel: relPrefix, depth: 0 },
|
|
550
384
|
];
|
|
@@ -602,7 +436,7 @@ class ScopeIgnore {
|
|
|
602
436
|
include;
|
|
603
437
|
includeRoots;
|
|
604
438
|
embedded;
|
|
605
|
-
defaults = defaultsOnlyIgnore();
|
|
439
|
+
defaults = (0, default_ignore_1.defaultsOnlyIgnore)();
|
|
606
440
|
constructor(rootMatcher, embedded,
|
|
607
441
|
/**
|
|
608
442
|
* Project `homegraph.json` `exclude` patterns (#999), matched against the
|
|
@@ -674,7 +508,7 @@ exports.ScopeIgnore = ScopeIgnore;
|
|
|
674
508
|
function buildScopeIgnore(rootDir, embeddedRoots) {
|
|
675
509
|
const roots = embeddedRoots ? [...embeddedRoots] : discoverEmbeddedRepoRoots(rootDir);
|
|
676
510
|
const include = loadIncludeMatcher(rootDir);
|
|
677
|
-
return new ScopeIgnore(buildDefaultIgnore(rootDir), roots.map((root) => ({ root, matcher: buildDefaultIgnore(path.join(rootDir, root)) })), loadExcludeMatcher(rootDir), include, include ? includeStaticRoots((0, project_config_1.loadIncludePatterns)(rootDir)) : []);
|
|
511
|
+
return new ScopeIgnore((0, default_ignore_1.buildDefaultIgnore)(rootDir), roots.map((root) => ({ root, matcher: (0, default_ignore_1.buildDefaultIgnore)(path.join(rootDir, root)) })), loadExcludeMatcher(rootDir), include, include ? includeStaticRoots((0, project_config_1.loadIncludePatterns)(rootDir)) : []);
|
|
678
512
|
}
|
|
679
513
|
/**
|
|
680
514
|
* Whether an embedded repo found as a tracked gitlink (mode 160000, #1031/#1033)
|
|
@@ -722,7 +556,7 @@ function discoverEmbeddedRepoRoots(rootDir) {
|
|
|
722
556
|
return [];
|
|
723
557
|
}
|
|
724
558
|
const out = [];
|
|
725
|
-
const defaults = defaultsOnlyIgnore();
|
|
559
|
+
const defaults = (0, default_ignore_1.defaultsOnlyIgnore)();
|
|
726
560
|
const includeIgnored = loadIncludeIgnoredMatcher(rootDir);
|
|
727
561
|
const visit = (repoAbs, prefix) => {
|
|
728
562
|
const candidates = [];
|
|
@@ -742,7 +576,7 @@ function discoverEmbeddedRepoRoots(rootDir) {
|
|
|
742
576
|
// (#1031, #1033)
|
|
743
577
|
try {
|
|
744
578
|
const gitOpts = { cwd: repoAbs, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true };
|
|
745
|
-
const repoIgnore = buildDefaultIgnore(repoAbs);
|
|
579
|
+
const repoIgnore = (0, default_ignore_1.buildDefaultIgnore)(repoAbs);
|
|
746
580
|
for (const rel of listGitlinkRels(gitOpts)) {
|
|
747
581
|
const relDir = rel.endsWith('/') ? rel : rel + '/';
|
|
748
582
|
// A gitlink under a gitignored path is respected (not indexed) unless the
|
|
@@ -792,7 +626,7 @@ function findUnindexedIgnoredRepos(rootDir) {
|
|
|
792
626
|
catch {
|
|
793
627
|
return [];
|
|
794
628
|
}
|
|
795
|
-
const defaults = defaultsOnlyIgnore();
|
|
629
|
+
const defaults = (0, default_ignore_1.defaultsOnlyIgnore)();
|
|
796
630
|
const includeIgnored = loadIncludeIgnoredMatcher(rootDir);
|
|
797
631
|
const repos = [];
|
|
798
632
|
for (const dir of listIgnoredDirs(rootDir)) {
|
|
@@ -826,7 +660,7 @@ function findUnindexedIgnoredRepos(rootDir) {
|
|
|
826
660
|
function findIgnoredEmbeddedRepos(repoDir, includeIgnored, prefix) {
|
|
827
661
|
if (!includeIgnored)
|
|
828
662
|
return [];
|
|
829
|
-
const defaults = defaultsOnlyIgnore();
|
|
663
|
+
const defaults = (0, default_ignore_1.defaultsOnlyIgnore)();
|
|
830
664
|
const repos = [];
|
|
831
665
|
for (const dir of listIgnoredDirs(repoDir)) {
|
|
832
666
|
if (defaults.ignores(dir))
|
|
@@ -938,7 +772,7 @@ function collectGitFiles(repoDir, prefix, files, embeddedRoots, includeIgnored =
|
|
|
938
772
|
const childDir = path.join(repoDir, rel);
|
|
939
773
|
// A git worktree surfaces here as an opaque untracked dir too — skip it,
|
|
940
774
|
// it's a duplicate working view of an already-indexed repo (#848).
|
|
941
|
-
if (classifyGitDir(childDir) === 'embedded' && !defaultsOnlyIgnore().ignores(rel)) {
|
|
775
|
+
if (classifyGitDir(childDir) === 'embedded' && !(0, default_ignore_1.defaultsOnlyIgnore)().ignores(rel)) {
|
|
942
776
|
embeddedRoots?.add((0, utils_1.normalizePath)(prefix + rel));
|
|
943
777
|
collectGitFiles(childDir, prefix + rel, files, embeddedRoots, includeIgnored);
|
|
944
778
|
}
|
|
@@ -955,8 +789,8 @@ function collectGitFiles(repoDir, prefix, files, embeddedRoots, includeIgnored =
|
|
|
955
789
|
// (an uninitialized submodule — empty dir, no `.git`) has nothing to index and
|
|
956
790
|
// is left alone, as is a submodule worktree (a duplicate view, #945). (#1031, #1033)
|
|
957
791
|
if (gitlinkRels.length > 0) {
|
|
958
|
-
const defaults = defaultsOnlyIgnore();
|
|
959
|
-
const repoIgnore = buildDefaultIgnore(repoDir);
|
|
792
|
+
const defaults = (0, default_ignore_1.defaultsOnlyIgnore)();
|
|
793
|
+
const repoIgnore = (0, default_ignore_1.buildDefaultIgnore)(repoDir);
|
|
960
794
|
for (const rel of gitlinkRels) {
|
|
961
795
|
const relDir = rel.endsWith('/') ? rel : rel + '/';
|
|
962
796
|
// A gitlink under a gitignored path is respected (not indexed) unless the
|
|
@@ -1064,7 +898,7 @@ function collectGitStatus(repoDir, prefix, out, overrides, includeIgnored = null
|
|
|
1064
898
|
// repo-relative `rel` at each recursion level mirrors getGitVisibleFiles'
|
|
1065
899
|
// ScopeIgnore: every embedded repo is judged by ITS OWN rules, never the
|
|
1066
900
|
// parent's. (#766)
|
|
1067
|
-
const ig = buildDefaultIgnore(repoDir);
|
|
901
|
+
const ig = (0, default_ignore_1.buildDefaultIgnore)(repoDir);
|
|
1068
902
|
const untrackedDirs = [];
|
|
1069
903
|
for (const line of output.split('\n')) {
|
|
1070
904
|
if (line.length < 4)
|
|
@@ -1187,7 +1021,7 @@ function scanDirectoryWalk(rootDir, onProgress) {
|
|
|
1187
1021
|
// readGitignorePatterns is defensive: a non-UTF-8 (DLP-encrypted) or
|
|
1188
1022
|
// uncompilable .gitignore is skipped/filtered with a warning, never thrown
|
|
1189
1023
|
// (issue #682) — so the per-file `.ignores()` calls below can't crash.
|
|
1190
|
-
const patterns = readGitignorePatterns(giPath);
|
|
1024
|
+
const patterns = (0, default_ignore_1.readGitignorePatterns)(giPath);
|
|
1191
1025
|
return patterns ? { dir, ig: (0, ignore_1.default)().add(patterns) } : null;
|
|
1192
1026
|
};
|
|
1193
1027
|
const isIgnored = (fullPath, isDir, matchers) => {
|
|
@@ -1274,7 +1108,7 @@ function scanDirectoryWalk(rootDir, onProgress) {
|
|
|
1274
1108
|
}
|
|
1275
1109
|
// Seed a base matcher with the built-in default ignores (merged with the root
|
|
1276
1110
|
// .gitignore so a negation can override). Nested .gitignores still layer per-dir.
|
|
1277
|
-
const baseMatchers = [{ dir: rootDir, ig: buildDefaultIgnore(rootDir) }];
|
|
1111
|
+
const baseMatchers = [{ dir: rootDir, ig: (0, default_ignore_1.buildDefaultIgnore)(rootDir) }];
|
|
1278
1112
|
// Project `codegraph.json` `exclude` patterns (#999), rooted at the project so
|
|
1279
1113
|
// `isIgnored` matches them against root-relative paths — same coverage the
|
|
1280
1114
|
// git path gets via ScopeIgnore, for non-git projects.
|
|
@@ -1420,7 +1254,7 @@ class ExtractionOrchestrator {
|
|
|
1420
1254
|
/**
|
|
1421
1255
|
* Index all files in the project
|
|
1422
1256
|
*/
|
|
1423
|
-
async indexAll(onProgress, signal, verbose) {
|
|
1257
|
+
async indexAll(onProgress, signal, verbose, walBackpressure, storeWriterOpts) {
|
|
1424
1258
|
await (0, grammars_1.initGrammars)();
|
|
1425
1259
|
const startTime = Date.now();
|
|
1426
1260
|
const errors = [];
|
|
@@ -1522,6 +1356,15 @@ class ExtractionOrchestrator {
|
|
|
1522
1356
|
// In-process fallback: load grammars locally and parse on the main thread.
|
|
1523
1357
|
await (0, grammars_1.loadGrammarsForLanguages)(neededLanguages);
|
|
1524
1358
|
}
|
|
1359
|
+
const storeWorkerPath = path.join(__dirname, 'store-worker.js');
|
|
1360
|
+
let storeWriter = null;
|
|
1361
|
+
if (storeWriterOpts &&
|
|
1362
|
+
process.env.HOMEGRAPH_NO_STORE_WORKER !== '1' &&
|
|
1363
|
+
fs.existsSync(storeWorkerPath)) {
|
|
1364
|
+
storeWriter = new store_writer_1.StoreWriter(storeWorkerPath, storeWriterOpts.dbPath, storeWriterOpts.fastInit);
|
|
1365
|
+
log('Store writer thread active');
|
|
1366
|
+
}
|
|
1367
|
+
const STORE_WRITER_WINDOW = 64;
|
|
1525
1368
|
/**
|
|
1526
1369
|
* Parse one file: on the pool when available (the promise REJECTS on a worker
|
|
1527
1370
|
* crash/timeout — the caller records it and the retry pass re-attempts), or
|
|
@@ -1551,12 +1394,21 @@ class ExtractionOrchestrator {
|
|
|
1551
1394
|
let nextSeq = 0; // file-order sequence assigned at dispatch
|
|
1552
1395
|
let nextToStore = 0; // cursor: next sequence to commit
|
|
1553
1396
|
let aborted = false;
|
|
1554
|
-
const
|
|
1397
|
+
const commitYield = (0, cooperative_yield_1.createYielder)();
|
|
1398
|
+
const storeResult = async (filePath, content, stats, result) => {
|
|
1555
1399
|
processed++;
|
|
1556
|
-
|
|
1400
|
+
const bp = walBackpressure?.();
|
|
1401
|
+
if (bp)
|
|
1402
|
+
await bp;
|
|
1557
1403
|
if (result.nodes.length > 0 || result.errors.length === 0) {
|
|
1558
1404
|
const language = (0, grammars_1.detectLanguage)(filePath, content, overrides);
|
|
1559
|
-
|
|
1405
|
+
if (storeWriter) {
|
|
1406
|
+
storeWriter.send(this.buildFreshStoreBundle(filePath, content, language, stats, result));
|
|
1407
|
+
await storeWriter.waitBelow(STORE_WRITER_WINDOW);
|
|
1408
|
+
}
|
|
1409
|
+
else {
|
|
1410
|
+
await this.storeExtractionResult(filePath, content, language, stats, result, commitYield);
|
|
1411
|
+
}
|
|
1560
1412
|
}
|
|
1561
1413
|
if (result.errors.length > 0) {
|
|
1562
1414
|
for (const err of result.errors) {
|
|
@@ -1574,9 +1426,6 @@ class ExtractionOrchestrator {
|
|
|
1574
1426
|
filesErrored++;
|
|
1575
1427
|
}
|
|
1576
1428
|
else {
|
|
1577
|
-
// Files with no symbols but no errors (yaml, twig, properties) are
|
|
1578
|
-
// tracked at the file level — count them as indexed so the CLI doesn't
|
|
1579
|
-
// misleadingly report "No files found to index".
|
|
1580
1429
|
const lang = (0, grammars_1.detectLanguage)(filePath, content, overrides);
|
|
1581
1430
|
if ((0, grammars_1.isFileLevelOnlyLanguage)(lang)) {
|
|
1582
1431
|
filesIndexed++;
|
|
@@ -1598,22 +1447,28 @@ class ExtractionOrchestrator {
|
|
|
1598
1447
|
});
|
|
1599
1448
|
onProgress?.({ phase: 'parsing', current: processed, total });
|
|
1600
1449
|
};
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
// after the drain). storeResult / recordParseFailure run here single-threaded,
|
|
1604
|
-
// so shared counters and SQLite writes never race despite parallel parsing.
|
|
1450
|
+
let flushChain = Promise.resolve();
|
|
1451
|
+
let flushError = null;
|
|
1605
1452
|
const flushOrdered = () => {
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1453
|
+
flushChain = flushChain.then(async () => {
|
|
1454
|
+
if (aborted || flushError)
|
|
1455
|
+
return;
|
|
1456
|
+
try {
|
|
1457
|
+
while (completed.has(nextToStore)) {
|
|
1458
|
+
const item = completed.get(nextToStore);
|
|
1459
|
+
completed.delete(nextToStore);
|
|
1460
|
+
nextToStore++;
|
|
1461
|
+
if (item.ok)
|
|
1462
|
+
await storeResult(item.filePath, item.content, item.stats, item.result);
|
|
1463
|
+
else
|
|
1464
|
+
recordParseFailure(item.filePath, item.err);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
catch (err) {
|
|
1468
|
+
flushError = err;
|
|
1469
|
+
}
|
|
1470
|
+
});
|
|
1471
|
+
return flushChain;
|
|
1617
1472
|
};
|
|
1618
1473
|
// Dispatch one file's parse (parses run concurrently across the pool), tagged
|
|
1619
1474
|
// with its file-order sequence so flushOrdered commits results in order. The
|
|
@@ -1636,10 +1491,15 @@ class ExtractionOrchestrator {
|
|
|
1636
1491
|
// buffered), not just in-flight: a slow file sitting at the commit cursor
|
|
1637
1492
|
// lets later parses finish and buffer, which would otherwise grow without
|
|
1638
1493
|
// bound. Wait for parses to settle (each may advance the cursor) until the
|
|
1639
|
-
// window has room.
|
|
1640
|
-
//
|
|
1641
|
-
|
|
1642
|
-
|
|
1494
|
+
// window has room. When nothing is in flight but the window is still full,
|
|
1495
|
+
// the async commit chain is what's behind — await it so the cursor
|
|
1496
|
+
// advances (buffered items hold whole file contents, so this bound is
|
|
1497
|
+
// load-bearing for memory).
|
|
1498
|
+
while (nextSeq - nextToStore >= windowSize) {
|
|
1499
|
+
if (inFlight.size > 0)
|
|
1500
|
+
await Promise.race(inFlight);
|
|
1501
|
+
else
|
|
1502
|
+
await flushOrdered();
|
|
1643
1503
|
}
|
|
1644
1504
|
};
|
|
1645
1505
|
const firstEtsFile = files.find((f) => (0, grammars_1.detectLanguage)(f, undefined, overrides) === 'arkts');
|
|
@@ -1744,9 +1604,25 @@ class ExtractionOrchestrator {
|
|
|
1744
1604
|
// then commit any results the cursor hasn't reached yet.
|
|
1745
1605
|
if (!aborted) {
|
|
1746
1606
|
await Promise.all(inFlight);
|
|
1747
|
-
flushOrdered();
|
|
1607
|
+
await flushOrdered();
|
|
1608
|
+
if (flushError) {
|
|
1609
|
+
if (storeWriter)
|
|
1610
|
+
await storeWriter.close();
|
|
1611
|
+
throw flushError;
|
|
1612
|
+
}
|
|
1613
|
+
if (storeWriter) {
|
|
1614
|
+
try {
|
|
1615
|
+
await storeWriter.drain();
|
|
1616
|
+
}
|
|
1617
|
+
finally {
|
|
1618
|
+
await storeWriter.close();
|
|
1619
|
+
storeWriter = null;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1748
1622
|
}
|
|
1749
1623
|
if (signal?.aborted || aborted) {
|
|
1624
|
+
if (storeWriter)
|
|
1625
|
+
await storeWriter.close();
|
|
1750
1626
|
if (pool)
|
|
1751
1627
|
await pool.destroy();
|
|
1752
1628
|
return {
|
|
@@ -1808,7 +1684,7 @@ class ExtractionOrchestrator {
|
|
|
1808
1684
|
if (result.nodes.length > 0 || result.errors.length === 0) {
|
|
1809
1685
|
const language = (0, grammars_1.detectLanguage)(filePath, content, overrides);
|
|
1810
1686
|
const stats = await fsp.stat(path.join(this.rootDir, filePath));
|
|
1811
|
-
this.storeExtractionResult(filePath, content, language, stats, result);
|
|
1687
|
+
await this.storeExtractionResult(filePath, content, language, stats, result, (0, cooperative_yield_1.createYielder)());
|
|
1812
1688
|
const idx = errors.indexOf(errEntry);
|
|
1813
1689
|
if (idx >= 0)
|
|
1814
1690
|
errors.splice(idx, 1);
|
|
@@ -1856,7 +1732,7 @@ class ExtractionOrchestrator {
|
|
|
1856
1732
|
if (result.nodes.length > 0 || result.errors.length === 0) {
|
|
1857
1733
|
const language = (0, grammars_1.detectLanguage)(filePath, fullContent, overrides);
|
|
1858
1734
|
const stats = await fsp.stat(path.join(this.rootDir, filePath));
|
|
1859
|
-
this.storeExtractionResult(filePath, fullContent, language, stats, result);
|
|
1735
|
+
await this.storeExtractionResult(filePath, fullContent, language, stats, result, (0, cooperative_yield_1.createYielder)());
|
|
1860
1736
|
const idx = errors.indexOf(errEntry);
|
|
1861
1737
|
if (idx >= 0)
|
|
1862
1738
|
errors.splice(idx, 1);
|
|
@@ -2034,108 +1910,77 @@ class ExtractionOrchestrator {
|
|
|
2034
1910
|
const result = (0, tree_sitter_1.extractFromSource)(relativePath, content, language, frameworkNames);
|
|
2035
1911
|
// Store in database
|
|
2036
1912
|
if (result.nodes.length > 0 || result.errors.length === 0) {
|
|
2037
|
-
this.storeExtractionResult(relativePath, content, language, stats, result);
|
|
1913
|
+
await this.storeExtractionResult(relativePath, content, language, stats, result, (0, cooperative_yield_1.createYielder)());
|
|
2038
1914
|
}
|
|
2039
1915
|
return result;
|
|
2040
1916
|
}
|
|
2041
1917
|
/**
|
|
2042
1918
|
* Store extraction result in database
|
|
2043
1919
|
*/
|
|
2044
|
-
storeExtractionResult(filePath, content, language, stats, result) {
|
|
1920
|
+
async storeExtractionResult(filePath, content, language, stats, result, onYield) {
|
|
1921
|
+
const STORE_CHUNK = 2000;
|
|
2045
1922
|
const contentHash = hashContent(content);
|
|
2046
|
-
// Check if file already exists and hasn't changed
|
|
2047
1923
|
const existingFile = this.queries.getFileByPath(filePath);
|
|
2048
1924
|
if (existingFile && existingFile.contentHash === contentHash) {
|
|
2049
|
-
return;
|
|
2050
|
-
}
|
|
2051
|
-
// Snapshot incoming cross-file edges BEFORE deleting this file's nodes.
|
|
2052
|
-
// `deleteFile` cascades to delete every edge whose source OR target is a
|
|
2053
|
-
// node in this file (edges.FK ... ON DELETE CASCADE). Edges whose SOURCE is
|
|
2054
|
-
// in this file are re-emitted by the extractor below, but edges whose SOURCE
|
|
2055
|
-
// is in a *different* (unchanged) file are not — they would be silently
|
|
2056
|
-
// dropped, which is issue #899: re-indexing a callee file severs `calls`/
|
|
2057
|
-
// `references` edges from callers that import it via module-attribute
|
|
2058
|
-
// access (`pkg.mod.fn(...)`).
|
|
2059
|
-
//
|
|
2060
|
-
// We snapshot the edge plus the target node's (name, kind) so we can
|
|
2061
|
-
// re-resolve to the re-indexed target's NEW id. Node ids are
|
|
2062
|
-
// `sha256(filePath:kind:name:line)`, so any line shift in the callee file
|
|
2063
|
-
// (e.g. a docstring-only edit above the symbol) changes every target id and
|
|
2064
|
-
// a naive re-insert by old id would silently drop every edge. Matching by
|
|
2065
|
-
// (filePath, kind, name) is stable across line shifts; if the symbol was
|
|
2066
|
-
// renamed/removed, no match is found and the edge stays dropped (correct).
|
|
1925
|
+
return;
|
|
1926
|
+
}
|
|
2067
1927
|
const crossFileIncomingEdges = existingFile
|
|
2068
1928
|
? this.queries.getCrossFileIncomingEdgesWithTarget(filePath)
|
|
2069
1929
|
: [];
|
|
2070
|
-
// Delete existing data for this file
|
|
2071
1930
|
if (existingFile) {
|
|
2072
1931
|
this.queries.deleteFile(filePath);
|
|
2073
1932
|
}
|
|
2074
|
-
// Filter out nodes with missing required fields before insertion.
|
|
2075
|
-
// This prevents FK violations when edges reference nodes that would
|
|
2076
|
-
// be silently skipped by insertNode() (see issue #42).
|
|
2077
1933
|
const validNodes = result.nodes.filter((n) => n.id && n.kind && n.name && n.filePath && n.language);
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
1934
|
+
const insertedIds = new Set(validNodes.map((n) => n.id));
|
|
1935
|
+
const validEdges = result.edges.filter((e) => insertedIds.has(e.source) && insertedIds.has(e.target));
|
|
1936
|
+
const validRefs = result.unresolvedReferences
|
|
1937
|
+
.filter((ref) => insertedIds.has(ref.fromNodeId))
|
|
1938
|
+
.map((ref) => ({
|
|
1939
|
+
...ref,
|
|
1940
|
+
filePath: ref.filePath ?? filePath,
|
|
1941
|
+
language: ref.language ?? language,
|
|
1942
|
+
}));
|
|
1943
|
+
const fitsOneChunk = validNodes.length <= STORE_CHUNK &&
|
|
1944
|
+
validEdges.length <= STORE_CHUNK &&
|
|
1945
|
+
validRefs.length <= STORE_CHUNK;
|
|
1946
|
+
if (fitsOneChunk) {
|
|
1947
|
+
this.queries.storeFileBundle({
|
|
1948
|
+
nodes: validNodes,
|
|
1949
|
+
edges: validEdges,
|
|
1950
|
+
refs: validRefs,
|
|
1951
|
+
file: {
|
|
1952
|
+
path: filePath,
|
|
1953
|
+
contentHash,
|
|
1954
|
+
language,
|
|
1955
|
+
size: stats.size,
|
|
1956
|
+
modifiedAt: stats.mtimeMs,
|
|
1957
|
+
indexedAt: Date.now(),
|
|
1958
|
+
nodeCount: result.nodes.length,
|
|
1959
|
+
errors: result.errors.length > 0 ? result.errors : undefined,
|
|
1960
|
+
},
|
|
1961
|
+
});
|
|
1962
|
+
if (crossFileIncomingEdges.length > 0) {
|
|
1963
|
+
this.reattachCrossFileEdges(crossFileIncomingEdges, validNodes);
|
|
1964
|
+
}
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
for (let i = 0; i < validNodes.length; i += STORE_CHUNK) {
|
|
1968
|
+
this.queries.insertNodes(validNodes.slice(i, i + STORE_CHUNK));
|
|
1969
|
+
await onYield?.();
|
|
1970
|
+
}
|
|
1971
|
+
if (validEdges.length > 0) {
|
|
1972
|
+
for (let i = 0; i < validEdges.length; i += STORE_CHUNK) {
|
|
1973
|
+
this.queries.insertEdges(validEdges.slice(i, i + STORE_CHUNK));
|
|
1974
|
+
await onYield?.();
|
|
2088
1975
|
}
|
|
2089
1976
|
}
|
|
2090
|
-
// Re-insert cross-file incoming edges snapshotted before the delete,
|
|
2091
|
-
// re-resolving each edge's target to the re-indexed node's new id by
|
|
2092
|
-
// (filePath, kind, name). Node ids include the source line, so any line
|
|
2093
|
-
// shift in the callee file (e.g. a docstring-only edit above the symbol)
|
|
2094
|
-
// changes every target id and a naive re-insert by old id would drop them
|
|
2095
|
-
// all. `insertEdges` still filters to endpoints that exist, so edges whose
|
|
2096
|
-
// caller (source) was deleted, or whose callee (target) was renamed/removed
|
|
2097
|
-
// during the re-index (no match in `newTargetIds`), are dropped. This
|
|
2098
|
-
// closes the #899 edge-drop on `sync`.
|
|
2099
1977
|
if (crossFileIncomingEdges.length > 0) {
|
|
2100
|
-
|
|
2101
|
-
for (const n of validNodes) {
|
|
2102
|
-
newNodesByKindName.set(`${n.kind}\0${n.name}`, n.id);
|
|
2103
|
-
}
|
|
2104
|
-
const reinserted = [];
|
|
2105
|
-
const resurrected = [];
|
|
2106
|
-
for (const e of crossFileIncomingEdges) {
|
|
2107
|
-
const newTargetId = newNodesByKindName.get(`${e.targetKind}\0${e.targetName}`);
|
|
2108
|
-
if (newTargetId) {
|
|
2109
|
-
reinserted.push({ source: e.source, target: newTargetId, kind: e.kind, metadata: e.metadata, line: e.line, column: e.column, provenance: e.provenance });
|
|
2110
|
-
}
|
|
2111
|
-
else {
|
|
2112
|
-
const ref = resurrectRefFromDroppedEdge(e);
|
|
2113
|
-
if (ref)
|
|
2114
|
-
resurrected.push(ref);
|
|
2115
|
-
}
|
|
2116
|
-
}
|
|
2117
|
-
if (reinserted.length > 0) {
|
|
2118
|
-
this.queries.insertEdges(reinserted);
|
|
2119
|
-
}
|
|
2120
|
-
if (resurrected.length > 0) {
|
|
2121
|
-
this.queries.insertUnresolvedRefsBatch(resurrected);
|
|
2122
|
-
}
|
|
1978
|
+
this.reattachCrossFileEdges(crossFileIncomingEdges, validNodes);
|
|
2123
1979
|
}
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
const refsWithContext = result.unresolvedReferences
|
|
2128
|
-
.filter((ref) => insertedIds.has(ref.fromNodeId))
|
|
2129
|
-
.map((ref) => ({
|
|
2130
|
-
...ref,
|
|
2131
|
-
filePath: ref.filePath ?? filePath,
|
|
2132
|
-
language: ref.language ?? language,
|
|
2133
|
-
}));
|
|
2134
|
-
if (refsWithContext.length > 0) {
|
|
2135
|
-
this.queries.insertUnresolvedRefsBatch(refsWithContext);
|
|
2136
|
-
}
|
|
1980
|
+
for (let i = 0; i < validRefs.length; i += STORE_CHUNK) {
|
|
1981
|
+
this.queries.insertUnresolvedRefsBatch(validRefs.slice(i, i + STORE_CHUNK));
|
|
1982
|
+
await onYield?.();
|
|
2137
1983
|
}
|
|
2138
|
-
// Insert file record
|
|
2139
1984
|
const fileRecord = {
|
|
2140
1985
|
path: filePath,
|
|
2141
1986
|
contentHash,
|
|
@@ -2148,6 +1993,46 @@ class ExtractionOrchestrator {
|
|
|
2148
1993
|
};
|
|
2149
1994
|
this.queries.upsertFile(fileRecord);
|
|
2150
1995
|
}
|
|
1996
|
+
buildFileRecord(filePath, content, language, stats, nodeCount, resultErrors) {
|
|
1997
|
+
return {
|
|
1998
|
+
path: filePath,
|
|
1999
|
+
contentHash: hashContent(content),
|
|
2000
|
+
language,
|
|
2001
|
+
size: stats.size,
|
|
2002
|
+
modifiedAt: stats.mtimeMs,
|
|
2003
|
+
indexedAt: Date.now(),
|
|
2004
|
+
nodeCount,
|
|
2005
|
+
errors: resultErrors.length > 0 ? resultErrors : undefined,
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
2008
|
+
buildFreshStoreBundle(filePath, content, language, stats, result) {
|
|
2009
|
+
return (0, store_writer_1.finalizeStoreBundle)(result, filePath, language, this.buildFileRecord(filePath, content, language, stats, result.nodes.length, result.errors));
|
|
2010
|
+
}
|
|
2011
|
+
reattachCrossFileEdges(crossFileIncomingEdges, validNodes) {
|
|
2012
|
+
const newNodesByKindName = new Map();
|
|
2013
|
+
for (const n of validNodes) {
|
|
2014
|
+
newNodesByKindName.set(`${n.kind}\0${n.name}`, n.id);
|
|
2015
|
+
}
|
|
2016
|
+
const reinserted = [];
|
|
2017
|
+
const resurrected = [];
|
|
2018
|
+
for (const e of crossFileIncomingEdges) {
|
|
2019
|
+
const newTargetId = newNodesByKindName.get(`${e.targetKind}\0${e.targetName}`);
|
|
2020
|
+
if (newTargetId) {
|
|
2021
|
+
reinserted.push({ source: e.source, target: newTargetId, kind: e.kind, metadata: e.metadata, line: e.line, column: e.column, provenance: e.provenance });
|
|
2022
|
+
}
|
|
2023
|
+
else {
|
|
2024
|
+
const ref = resurrectRefFromDroppedEdge(e);
|
|
2025
|
+
if (ref)
|
|
2026
|
+
resurrected.push(ref);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
if (reinserted.length > 0) {
|
|
2030
|
+
this.queries.insertEdges(reinserted);
|
|
2031
|
+
}
|
|
2032
|
+
if (resurrected.length > 0) {
|
|
2033
|
+
this.queries.insertUnresolvedRefsBatch(resurrected);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2151
2036
|
/**
|
|
2152
2037
|
* Sync the index with the current file state.
|
|
2153
2038
|
*
|
|
@@ -2156,7 +2041,7 @@ class ExtractionOrchestrator {
|
|
|
2156
2041
|
* changes. This works in non-git projects and catches committed changes from
|
|
2157
2042
|
* `git pull`/`checkout`/`merge`/`rebase` that `git status` cannot see.
|
|
2158
2043
|
*/
|
|
2159
|
-
async sync(onProgress) {
|
|
2044
|
+
async sync(onProgress, scopedPaths) {
|
|
2160
2045
|
await (0, grammars_1.initGrammars)(); // Initialize WASM runtime (grammars loaded lazily below)
|
|
2161
2046
|
const startTime = Date.now();
|
|
2162
2047
|
let filesChecked = 0;
|
|
@@ -2171,33 +2056,36 @@ class ExtractionOrchestrator {
|
|
|
2171
2056
|
total: 0,
|
|
2172
2057
|
});
|
|
2173
2058
|
const filesToIndex = [];
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2059
|
+
let currentFiles;
|
|
2060
|
+
let trackedFiles;
|
|
2061
|
+
if (scopedPaths && scopedPaths.length > 0) {
|
|
2062
|
+
const unique = [...new Set(scopedPaths)];
|
|
2063
|
+
currentFiles = unique.filter((p) => fs.existsSync(path.join(this.rootDir, p)));
|
|
2064
|
+
trackedFiles = [];
|
|
2065
|
+
for (const p of unique) {
|
|
2066
|
+
const rec = this.queries.getFileByPath(p);
|
|
2067
|
+
if (rec)
|
|
2068
|
+
trackedFiles.push(rec);
|
|
2069
|
+
}
|
|
2070
|
+
filesChecked = unique.length;
|
|
2071
|
+
}
|
|
2072
|
+
else {
|
|
2073
|
+
currentFiles = await scanDirectoryAsync(this.rootDir);
|
|
2074
|
+
filesChecked = currentFiles.length;
|
|
2075
|
+
trackedFiles = this.queries.getAllFiles();
|
|
2076
|
+
}
|
|
2185
2077
|
const currentSet = new Set(currentFiles);
|
|
2186
|
-
const trackedFiles = this.queries.getAllFiles();
|
|
2187
2078
|
const trackedMap = new Map();
|
|
2188
2079
|
for (const f of trackedFiles) {
|
|
2189
2080
|
trackedMap.set(f.path, f);
|
|
2190
2081
|
}
|
|
2191
|
-
|
|
2192
|
-
// filesystem directly — `scanDirectory` (via `git ls-files`) still lists a
|
|
2193
|
-
// file deleted from disk but not yet staged, so set membership alone misses it.
|
|
2194
|
-
// `reconcileChecks` drives the cooperative yield shared with the adds/mods loop
|
|
2195
|
-
// below (see SYNC_RECONCILE_YIELD_INTERVAL / issue #905).
|
|
2082
|
+
const removedArkAnalyzerFiles = [];
|
|
2196
2083
|
let reconcileChecks = 0;
|
|
2197
2084
|
for (const tracked of trackedFiles) {
|
|
2198
2085
|
if (!currentSet.has(tracked.path) || !fs.existsSync(path.join(this.rootDir, tracked.path))) {
|
|
2199
|
-
|
|
2200
|
-
|
|
2086
|
+
if (tracked.path.startsWith('@')) {
|
|
2087
|
+
continue;
|
|
2088
|
+
}
|
|
2201
2089
|
const incoming = this.queries.getCrossFileIncomingEdgesWithTarget(tracked.path);
|
|
2202
2090
|
if (incoming.length > 0) {
|
|
2203
2091
|
const resurrected = incoming
|
|
@@ -2207,6 +2095,9 @@ class ExtractionOrchestrator {
|
|
|
2207
2095
|
this.queries.insertUnresolvedRefsBatch(resurrected);
|
|
2208
2096
|
}
|
|
2209
2097
|
}
|
|
2098
|
+
if ((0, arkts_1.isArkAnalyzerSourcePath)(tracked.path)) {
|
|
2099
|
+
removedArkAnalyzerFiles.push(tracked.path);
|
|
2100
|
+
}
|
|
2210
2101
|
this.queries.deleteFile(tracked.path);
|
|
2211
2102
|
filesRemoved++;
|
|
2212
2103
|
}
|
|
@@ -2216,9 +2107,6 @@ class ExtractionOrchestrator {
|
|
|
2216
2107
|
}
|
|
2217
2108
|
// Adds / modifications.
|
|
2218
2109
|
for (const filePath of currentFiles) {
|
|
2219
|
-
// Same cooperative yield as the removals loop — this is the other O(files)
|
|
2220
|
-
// synchronous-stat loop that wedges the main thread on a large repo (#905).
|
|
2221
|
-
// Yield at the top of the body so the `continue` fast-paths below still hit it.
|
|
2222
2110
|
if (++reconcileChecks % SYNC_RECONCILE_YIELD_INTERVAL === 0) {
|
|
2223
2111
|
onProgress?.({
|
|
2224
2112
|
phase: 'scanning',
|
|
@@ -2281,7 +2169,19 @@ class ExtractionOrchestrator {
|
|
|
2281
2169
|
const total = filesToIndex.length;
|
|
2282
2170
|
const overrides = (0, project_config_1.loadExtensionOverrides)(this.rootDir);
|
|
2283
2171
|
const needsArkTS = filesToIndex.some((f) => (0, grammars_1.detectLanguage)(f, undefined, overrides) === 'arkts');
|
|
2284
|
-
|
|
2172
|
+
const arktsChangedForBatch = [
|
|
2173
|
+
...removedArkAnalyzerFiles,
|
|
2174
|
+
...filesToIndex.filter((f) => (0, arkts_1.isArkAnalyzerSourcePath)(f) ||
|
|
2175
|
+
f.endsWith('module.json5') ||
|
|
2176
|
+
f.endsWith('oh-package.json5') ||
|
|
2177
|
+
f === 'build-profile.json5' ||
|
|
2178
|
+
f.endsWith('/build-profile.json5')),
|
|
2179
|
+
];
|
|
2180
|
+
// Removals alone can still dirty a Harmony module (RTA for remaining files).
|
|
2181
|
+
const needsArkTSBatch = needsArkTS ||
|
|
2182
|
+
removedArkAnalyzerFiles.length > 0 ||
|
|
2183
|
+
arktsChangedForBatch.some((f) => f === 'build-profile.json5' || f.endsWith('/build-profile.json5'));
|
|
2184
|
+
if (needsArkTSBatch && arktsChangedForBatch.length > 0) {
|
|
2285
2185
|
(0, context_1.setArkTSBatchProgressCallback)((batchProgress) => {
|
|
2286
2186
|
onProgress?.({
|
|
2287
2187
|
phase: 'arkts-batch',
|
|
@@ -2291,8 +2191,12 @@ class ExtractionOrchestrator {
|
|
|
2291
2191
|
subphase: batchProgress.subphase,
|
|
2292
2192
|
});
|
|
2293
2193
|
});
|
|
2294
|
-
const firstEts = filesToIndex.find((f) => (0, grammars_1.detectLanguage)(f, undefined, overrides) === 'arkts')
|
|
2295
|
-
|
|
2194
|
+
const firstEts = filesToIndex.find((f) => (0, grammars_1.detectLanguage)(f, undefined, overrides) === 'arkts') ??
|
|
2195
|
+
arktsChangedForBatch.find((f) => (0, arkts_1.isArkAnalyzerSourcePath)(f)) ??
|
|
2196
|
+
arktsChangedForBatch[0];
|
|
2197
|
+
await (0, arkts_1.primeArkTSBatch)(this.rootDir, this.queries, firstEts, {
|
|
2198
|
+
changedFiles: arktsChangedForBatch,
|
|
2199
|
+
});
|
|
2296
2200
|
}
|
|
2297
2201
|
try {
|
|
2298
2202
|
for (let i = 0; i < filesToIndex.length; i++) {
|
|
@@ -2317,7 +2221,7 @@ class ExtractionOrchestrator {
|
|
|
2317
2221
|
}
|
|
2318
2222
|
}
|
|
2319
2223
|
finally {
|
|
2320
|
-
if (
|
|
2224
|
+
if (needsArkTSBatch) {
|
|
2321
2225
|
(0, context_1.setArkTSBatchProgressCallback)(null);
|
|
2322
2226
|
}
|
|
2323
2227
|
}
|