@jafreck/lore 0.3.6 → 0.3.8
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 +38 -150
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +80 -32
- package/dist/cli.js.map +1 -1
- package/dist/db/read-only.d.ts +22 -43
- package/dist/db/read-only.d.ts.map +1 -1
- package/dist/db/read-only.js +80 -156
- package/dist/db/read-only.js.map +1 -1
- package/dist/db/schema.d.ts +9 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +171 -85
- package/dist/db/schema.js.map +1 -1
- package/dist/discovery/poller.d.ts +6 -16
- package/dist/discovery/poller.d.ts.map +1 -1
- package/dist/discovery/poller.js +21 -52
- package/dist/discovery/poller.js.map +1 -1
- package/dist/discovery/scip-flush.d.ts +44 -0
- package/dist/discovery/scip-flush.d.ts.map +1 -0
- package/dist/discovery/scip-flush.js +67 -0
- package/dist/discovery/scip-flush.js.map +1 -0
- package/dist/discovery/watcher.d.ts +6 -16
- package/dist/discovery/watcher.d.ts.map +1 -1
- package/dist/discovery/watcher.js +22 -54
- package/dist/discovery/watcher.js.map +1 -1
- package/dist/docs/docs.d.ts +0 -2
- package/dist/docs/docs.d.ts.map +1 -1
- package/dist/docs/docs.js +0 -27
- package/dist/docs/docs.js.map +1 -1
- package/dist/embeddings/embedder.d.ts +12 -8
- package/dist/embeddings/embedder.d.ts.map +1 -1
- package/dist/embeddings/embedder.js +35 -19
- package/dist/embeddings/embedder.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/indexer/index.d.ts +19 -10
- package/dist/indexer/index.d.ts.map +1 -1
- package/dist/indexer/index.js +135 -28
- package/dist/indexer/index.js.map +1 -1
- package/dist/indexer/pipeline.d.ts +44 -21
- package/dist/indexer/pipeline.d.ts.map +1 -1
- package/dist/indexer/pipeline.js +48 -26
- package/dist/indexer/pipeline.js.map +1 -1
- package/dist/indexer/stages/docs-index.d.ts +1 -3
- package/dist/indexer/stages/docs-index.d.ts.map +1 -1
- package/dist/indexer/stages/docs-index.js +1 -25
- package/dist/indexer/stages/docs-index.js.map +1 -1
- package/dist/indexer/stages/index.d.ts +4 -2
- package/dist/indexer/stages/index.d.ts.map +1 -1
- package/dist/indexer/stages/index.js +3 -2
- package/dist/indexer/stages/index.js.map +1 -1
- package/dist/indexer/stages/lsp-enrichment.d.ts +1 -1
- package/dist/indexer/stages/lsp-enrichment.d.ts.map +1 -1
- package/dist/indexer/stages/lsp-enrichment.js +44 -21
- package/dist/indexer/stages/lsp-enrichment.js.map +1 -1
- package/dist/indexer/stages/overlay-cleanup.d.ts +31 -0
- package/dist/indexer/stages/overlay-cleanup.d.ts.map +1 -0
- package/dist/indexer/stages/overlay-cleanup.js +64 -0
- package/dist/indexer/stages/overlay-cleanup.js.map +1 -0
- package/dist/indexer/stages/reverse-deps.d.ts +13 -0
- package/dist/indexer/stages/reverse-deps.d.ts.map +1 -0
- package/dist/indexer/stages/reverse-deps.js +81 -0
- package/dist/indexer/stages/reverse-deps.js.map +1 -0
- package/dist/indexer/stages/{scip-source.d.ts → scip-indexer.d.ts} +38 -9
- package/dist/indexer/stages/scip-indexer.d.ts.map +1 -0
- package/dist/indexer/stages/{scip-source.js → scip-indexer.js} +359 -98
- package/dist/indexer/stages/scip-indexer.js.map +1 -0
- package/dist/indexer/stages/source-index.d.ts +3 -3
- package/dist/indexer/stages/source-index.d.ts.map +1 -1
- package/dist/indexer/stages/source-index.js +188 -70
- package/dist/indexer/stages/source-index.js.map +1 -1
- package/dist/lsp/enrichment.d.ts.map +1 -1
- package/dist/lsp/enrichment.js +1 -18
- package/dist/lsp/enrichment.js.map +1 -1
- package/dist/parsing/extractors/go.d.ts.map +1 -1
- package/dist/parsing/extractors/go.js +0 -38
- package/dist/parsing/extractors/go.js.map +1 -1
- package/dist/parsing/extractors/javascript.d.ts.map +1 -1
- package/dist/parsing/extractors/javascript.js +0 -47
- package/dist/parsing/extractors/javascript.js.map +1 -1
- package/dist/parsing/extractors/python.d.ts.map +1 -1
- package/dist/parsing/extractors/python.js +0 -22
- package/dist/parsing/extractors/python.js.map +1 -1
- package/dist/parsing/extractors/types.d.ts +0 -16
- package/dist/parsing/extractors/types.d.ts.map +1 -1
- package/dist/parsing/extractors/types.js +1 -1
- package/dist/parsing/extractors/types.js.map +1 -1
- package/dist/parsing/extractors/typescript.d.ts.map +1 -1
- package/dist/parsing/extractors/typescript.js +18 -2
- package/dist/parsing/extractors/typescript.js.map +1 -1
- package/dist/resolution/call-graph.d.ts +3 -1
- package/dist/resolution/call-graph.d.ts.map +1 -1
- package/dist/resolution/call-graph.js +15 -13
- package/dist/resolution/call-graph.js.map +1 -1
- package/dist/resolution/resolution-method.d.ts +1 -1
- package/dist/resolution/resolution-method.d.ts.map +1 -1
- package/dist/resolution/resolution-method.js +2 -0
- package/dist/resolution/resolution-method.js.map +1 -1
- package/dist/resolution/resolver.d.ts +6 -0
- package/dist/resolution/resolver.d.ts.map +1 -1
- package/dist/resolution/resolver.js +21 -0
- package/dist/resolution/resolver.js.map +1 -1
- package/dist/runtime.d.ts +0 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/scip/compdb.d.ts +38 -0
- package/dist/scip/compdb.d.ts.map +1 -0
- package/dist/scip/compdb.js +138 -0
- package/dist/scip/compdb.js.map +1 -0
- package/dist/scip/enrichment.d.ts +6 -1
- package/dist/scip/enrichment.d.ts.map +1 -1
- package/dist/scip/enrichment.js +62 -5
- package/dist/scip/enrichment.js.map +1 -1
- package/dist/scip/installer.d.ts +59 -0
- package/dist/scip/installer.d.ts.map +1 -0
- package/dist/scip/installer.js +302 -0
- package/dist/scip/installer.js.map +1 -0
- package/dist/scip/registry.d.ts +1 -1
- package/dist/scip/registry.d.ts.map +1 -1
- package/dist/scip/registry.js +33 -5
- package/dist/scip/registry.js.map +1 -1
- package/dist/server/server.d.ts +3 -8
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +7 -66
- package/dist/server/server.js.map +1 -1
- package/dist/server/tool-registry.d.ts +2 -2
- package/dist/server/tool-registry.d.ts.map +1 -1
- package/dist/server/tool-registry.js +37 -41
- package/dist/server/tool-registry.js.map +1 -1
- package/dist/server/tools/cohesion.d.ts +46 -0
- package/dist/server/tools/cohesion.d.ts.map +1 -0
- package/dist/server/tools/cohesion.js +100 -0
- package/dist/server/tools/cohesion.js.map +1 -0
- package/dist/server/tools/dependents.d.ts +139 -0
- package/dist/server/tools/dependents.d.ts.map +1 -0
- package/dist/server/tools/dependents.js +354 -0
- package/dist/server/tools/dependents.js.map +1 -0
- package/dist/server/tools/diff.d.ts +73 -0
- package/dist/server/tools/diff.d.ts.map +1 -0
- package/dist/server/tools/diff.js +157 -0
- package/dist/server/tools/diff.js.map +1 -0
- package/dist/server/tools/graph.d.ts +7 -3
- package/dist/server/tools/graph.d.ts.map +1 -1
- package/dist/server/tools/graph.js +15 -85
- package/dist/server/tools/graph.js.map +1 -1
- package/dist/server/tools/metrics.d.ts +5 -30
- package/dist/server/tools/metrics.d.ts.map +1 -1
- package/dist/server/tools/metrics.js +21 -57
- package/dist/server/tools/metrics.js.map +1 -1
- package/dist/server/tools/structure.d.ts +77 -0
- package/dist/server/tools/structure.d.ts.map +1 -0
- package/dist/server/tools/structure.js +309 -0
- package/dist/server/tools/structure.js.map +1 -0
- package/dist/server/tools/test-map.d.ts +7 -0
- package/dist/server/tools/test-map.d.ts.map +1 -1
- package/dist/server/tools/test-map.js +18 -1
- package/dist/server/tools/test-map.js.map +1 -1
- package/dist/server/tools/trace.d.ts +84 -0
- package/dist/server/tools/trace.d.ts.map +1 -0
- package/dist/server/tools/trace.js +317 -0
- package/dist/server/tools/trace.js.map +1 -0
- package/dist/testing/coverage.d.ts +11 -0
- package/dist/testing/coverage.d.ts.map +1 -1
- package/dist/testing/coverage.js +34 -2
- package/dist/testing/coverage.js.map +1 -1
- package/dist/testing/test-mapper.d.ts +1 -1
- package/dist/testing/test-mapper.d.ts.map +1 -1
- package/dist/testing/test-mapper.js +1 -0
- package/dist/testing/test-mapper.js.map +1 -1
- package/package.json +3 -1
- package/dist/indexer/stages/scip-enrichment.d.ts +0 -43
- package/dist/indexer/stages/scip-enrichment.d.ts.map +0 -1
- package/dist/indexer/stages/scip-enrichment.js +0 -174
- package/dist/indexer/stages/scip-enrichment.js.map +0 -1
- package/dist/indexer/stages/scip-source.d.ts.map +0 -1
- package/dist/indexer/stages/scip-source.js.map +0 -1
- package/dist/server/tools/annotations.d.ts +0 -40
- package/dist/server/tools/annotations.d.ts.map +0 -1
- package/dist/server/tools/annotations.js +0 -35
- package/dist/server/tools/annotations.js.map +0 -1
- package/dist/server/tools/architecture.d.ts +0 -67
- package/dist/server/tools/architecture.d.ts.map +0 -1
- package/dist/server/tools/architecture.js +0 -209
- package/dist/server/tools/architecture.js.map +0 -1
- package/dist/server/tools/coverage.d.ts +0 -67
- package/dist/server/tools/coverage.d.ts.map +0 -1
- package/dist/server/tools/coverage.js +0 -74
- package/dist/server/tools/coverage.js.map +0 -1
- package/dist/server/tools/graph-analysis.d.ts +0 -64
- package/dist/server/tools/graph-analysis.d.ts.map +0 -1
- package/dist/server/tools/graph-analysis.js +0 -82
- package/dist/server/tools/graph-analysis.js.map +0 -1
- package/dist/server/tools/notes.d.ts +0 -165
- package/dist/server/tools/notes.d.ts.map +0 -1
- package/dist/server/tools/notes.js +0 -214
- package/dist/server/tools/notes.js.map +0 -1
- package/dist/server/tools/routes.d.ts +0 -38
- package/dist/server/tools/routes.d.ts.map +0 -1
- package/dist/server/tools/routes.js +0 -38
- package/dist/server/tools/routes.js.map +0 -1
- package/dist/server/tools/writeback.d.ts +0 -49
- package/dist/server/tools/writeback.d.ts.map +0 -1
- package/dist/server/tools/writeback.js +0 -68
- package/dist/server/tools/writeback.js.map +0 -1
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @module indexer/stages/scip-
|
|
2
|
+
* @module indexer/stages/scip-indexer
|
|
3
3
|
*
|
|
4
4
|
* Pipeline stage: for SCIP-covered languages, populate `files`, `symbols`,
|
|
5
5
|
* `symbol_refs`, `type_refs`, `symbol_relationships`, and `file_imports`
|
|
6
6
|
* **directly from the SCIP index** — bypassing tree-sitter entirely.
|
|
7
7
|
*
|
|
8
|
-
* This is the
|
|
9
|
-
*
|
|
8
|
+
* This is the single-pass SCIP architecture. SCIP is the source of truth
|
|
9
|
+
* for the symbol table, the call graph, **and** enrichment metadata (type
|
|
10
|
+
* signatures, definition locations). All data is written in one pass.
|
|
11
|
+
*
|
|
12
|
+
* For each SCIP document:
|
|
10
13
|
*
|
|
11
14
|
* 1. **Symbols**: Definition occurrences → `symbols` rows; kinds inferred
|
|
12
15
|
* from SCIP descriptor suffixes; spans from `enclosing_range`.
|
|
16
|
+
* Enrichment columns (`resolved_type_signature`, `resolved_return_type`,
|
|
17
|
+
* `definition_uri`, `definition_path`) are populated inline.
|
|
13
18
|
* 2. **Refs**: Non-definition, non-local reference occurrences →
|
|
14
19
|
* `symbol_refs` rows with both `caller_id` and `callee_id` resolved
|
|
15
20
|
* using containment (which symbol's span encloses this ref?) and
|
|
16
21
|
* definition lookup (where is the referenced SCIP symbol defined?).
|
|
22
|
+
* Enrichment columns are populated inline from the same SCIP data.
|
|
17
23
|
*
|
|
18
24
|
* SCIP refs are inserted **pre-resolved** with `resolution_method =
|
|
19
25
|
* 'scip_definition'`. The downstream resolution stage only processes
|
|
@@ -23,24 +29,36 @@
|
|
|
23
29
|
*
|
|
24
30
|
* Same tables as `SourceIndexStage`: `files`, `symbols`, `symbols_fts`,
|
|
25
31
|
* `symbol_refs`, `type_refs`, `symbol_relationships`, `file_imports`.
|
|
32
|
+
* Additionally populates enrichment columns (type signatures, definition
|
|
33
|
+
* locations) inline during the same pass.
|
|
26
34
|
*
|
|
27
35
|
* ## Pipeline ordering
|
|
28
36
|
*
|
|
29
37
|
* This stage runs **before** `SourceIndexStage`. It stores which
|
|
30
|
-
* languages and files it handled in `context.scipSourcedLanguages
|
|
31
|
-
* `context.scipSourcedFiles` so
|
|
38
|
+
* languages and files it handled in `context.scipSourcedLanguages`,
|
|
39
|
+
* `context.scipSourcedFiles`, and `context.scipCoveredLanguages` so
|
|
40
|
+
* `SourceIndexStage` can skip full extraction (but still compute
|
|
41
|
+
* tree-sitter metrics) and `LspEnrichmentStage` knows not to re-enrich
|
|
42
|
+
* these languages.
|
|
32
43
|
*/
|
|
33
44
|
import * as fs from 'node:fs';
|
|
34
45
|
import * as crypto from 'node:crypto';
|
|
46
|
+
import { tmpdir } from 'node:os';
|
|
35
47
|
import { resolve } from 'node:path';
|
|
48
|
+
import { pathToFileURL } from 'node:url';
|
|
36
49
|
import { fromBinary } from '@bufbuild/protobuf';
|
|
37
50
|
import { IndexSchema, SymbolRole, } from '../../scip/scip_pb.js';
|
|
38
|
-
import { buildStructuralEmbeddingText } from '../../embeddings/embedder.js';
|
|
39
51
|
import { normalizeTypeName } from '../../resolution/call-graph.js';
|
|
40
52
|
import { SCIP_SUPPORTED_LANGUAGES, resolveScipIndexerRegistry } from '../../scip/registry.js';
|
|
53
|
+
import { getLogger } from '../../logger.js';
|
|
54
|
+
import { extractReturnType } from '../../scip/index-reader.js';
|
|
55
|
+
import { getSpecsForLanguage, installScipIndexer } from '../../scip/installer.js';
|
|
56
|
+
import { ensureCompilationDatabase } from '../../scip/compdb.js';
|
|
57
|
+
import { EXT_TO_LANG } from '../../discovery/walker.js';
|
|
41
58
|
import { readFileSync, existsSync } from 'node:fs';
|
|
42
59
|
import { join } from 'node:path';
|
|
43
|
-
import {
|
|
60
|
+
import { execFile } from 'node:child_process';
|
|
61
|
+
import { promisify } from 'node:util';
|
|
44
62
|
// ─── SCIP symbol string → Lore kind mapping ──────────────────────────────────
|
|
45
63
|
/**
|
|
46
64
|
* Infer a Lore symbol `kind` from a SCIP symbol string.
|
|
@@ -89,6 +107,10 @@ function inferKindFromScipSymbol(scipSymbol, docHint) {
|
|
|
89
107
|
return 'constant';
|
|
90
108
|
if (docHint.includes('(property)'))
|
|
91
109
|
return 'property';
|
|
110
|
+
// scip-clang uses term descriptors for C/C++ functions:
|
|
111
|
+
// ` $ funcName(hexhash).` — the (hash) indicates a function, not a variable.
|
|
112
|
+
if (/\([0-9a-f]{8,}\)\.$/.test(scipSymbol))
|
|
113
|
+
return 'function';
|
|
92
114
|
return 'variable';
|
|
93
115
|
}
|
|
94
116
|
// Meta: ends with :
|
|
@@ -110,12 +132,17 @@ function extractNameFromScipSymbol(scipSymbol) {
|
|
|
110
132
|
let cleaned = scipSymbol.replace(/[.#/:]$/, '');
|
|
111
133
|
// For methods, strip the disambiguator: `name(+1).` → `name`
|
|
112
134
|
cleaned = cleaned.replace(/\(\+?\d*\)$/, '');
|
|
135
|
+
// scip-clang uses ` $ name(hash)` for C/C++ symbols — strip the hash.
|
|
136
|
+
// E.g., ` $ parse_analyze_fixedparams(39d222e79bbfb7c0)` → `parse_analyze_fixedparams`
|
|
137
|
+
cleaned = cleaned.replace(/\([0-9a-f]{8,}\)$/, '');
|
|
113
138
|
// Get the last descriptor's name
|
|
114
139
|
// Descriptors are separated by ., #, /, :, or ()
|
|
115
140
|
const parts = cleaned.split(/[.#/:]/);
|
|
116
141
|
let name = parts[parts.length - 1] || '';
|
|
117
142
|
// Remove backtick escaping
|
|
118
143
|
name = name.replace(/`/g, '');
|
|
144
|
+
// Strip leading ` $ ` prefix used by scip-clang
|
|
145
|
+
name = name.replace(/^\s*\$\s*/, '');
|
|
119
146
|
// Handle parameter descriptors like `(paramName)`
|
|
120
147
|
if (name.startsWith('(') && name.endsWith(')')) {
|
|
121
148
|
name = name.slice(1, -1);
|
|
@@ -243,11 +270,14 @@ function inferTypeRefKind(sourceLines, refLine, refChar) {
|
|
|
243
270
|
return 'other';
|
|
244
271
|
}
|
|
245
272
|
// ─── Stage implementation ────────────────────────────────────────────────────
|
|
246
|
-
export class
|
|
247
|
-
name = 'scip-
|
|
273
|
+
export class ScipIndexerStage {
|
|
274
|
+
name = 'scip-indexer';
|
|
248
275
|
async execute(context, mode) {
|
|
249
276
|
if (!context.scip?.enabled)
|
|
250
277
|
return;
|
|
278
|
+
// SCIP only runs during baseline builds — never during overlay updates.
|
|
279
|
+
if (context.layer === 'overlay')
|
|
280
|
+
return;
|
|
251
281
|
const log = context.log;
|
|
252
282
|
const rootDir = context.walkerConfig.rootDir;
|
|
253
283
|
// In update mode, determine which SCIP-supported languages have changed
|
|
@@ -266,19 +296,27 @@ export class ScipSourceStage {
|
|
|
266
296
|
}
|
|
267
297
|
}
|
|
268
298
|
if (staleLanguages.size === 0) {
|
|
269
|
-
log.indexing('scip-
|
|
299
|
+
log.indexing('scip-indexer: no SCIP-supported languages in changed files, skipping');
|
|
270
300
|
return;
|
|
271
301
|
}
|
|
272
|
-
log.indexing('scip-
|
|
302
|
+
log.indexing('scip-indexer: stale languages', { languages: [...staleLanguages] });
|
|
273
303
|
}
|
|
274
|
-
// Load SCIP
|
|
275
|
-
const
|
|
276
|
-
if (
|
|
277
|
-
log.indexing('scip-
|
|
304
|
+
// Load SCIP indexes (one per indexer that succeeds)
|
|
305
|
+
const indexBuffers = await this.loadScipIndexes(context.scip, rootDir, staleLanguages);
|
|
306
|
+
if (indexBuffers.length === 0) {
|
|
307
|
+
log.indexing('scip-indexer: no SCIP index available');
|
|
278
308
|
return;
|
|
279
309
|
}
|
|
280
|
-
|
|
281
|
-
|
|
310
|
+
// Parse all SCIP index buffers and combine their documents
|
|
311
|
+
const allDocuments = [];
|
|
312
|
+
const allExternalSymbols = [];
|
|
313
|
+
for (const buf of indexBuffers) {
|
|
314
|
+
const parsed = fromBinary(IndexSchema, buf);
|
|
315
|
+
allDocuments.push(...parsed.documents);
|
|
316
|
+
allExternalSymbols.push(...parsed.externalSymbols);
|
|
317
|
+
}
|
|
318
|
+
const scipIndex = { documents: allDocuments, externalSymbols: allExternalSymbols };
|
|
319
|
+
log.indexing('scip-indexer: loaded index', {
|
|
282
320
|
documents: scipIndex.documents.length,
|
|
283
321
|
externalSymbols: scipIndex.externalSymbols.length,
|
|
284
322
|
});
|
|
@@ -294,7 +332,7 @@ export class ScipSourceStage {
|
|
|
294
332
|
if (loreLang)
|
|
295
333
|
coveredLanguages.add(loreLang);
|
|
296
334
|
}
|
|
297
|
-
log.indexing('scip-
|
|
335
|
+
log.indexing('scip-indexer: languages covered', { languages: [...coveredLanguages] });
|
|
298
336
|
// Determine the project's SCIP symbol prefix so we can distinguish
|
|
299
337
|
// internal symbols from external ones (stdlib, node_modules, etc.).
|
|
300
338
|
// Internal symbols are those whose SCIP string starts with the same
|
|
@@ -350,18 +388,19 @@ export class ScipSourceStage {
|
|
|
350
388
|
const db = context.db;
|
|
351
389
|
const branch = context.branch;
|
|
352
390
|
// Prepared statements
|
|
353
|
-
const insertFile = db.prepare(`INSERT INTO files (path, branch, language, size_bytes, last_hash, source)
|
|
354
|
-
VALUES (?, ?, ?, ?, ?, ?)`);
|
|
355
|
-
const insertSymbol = db.prepare(`INSERT INTO symbols (file_id, name, kind, start_line, end_line, signature, doc_comment)
|
|
356
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`);
|
|
357
|
-
const insertFts = db.prepare('INSERT INTO symbols_fts(rowid, name, signature, kind) VALUES (?, ?, ?, ?)');
|
|
358
|
-
const insertCallRef = db.prepare(`INSERT INTO symbol_refs (caller_id, file_id, callee_id, callee_name, call_line, call_character, call_kind, resolution_method)
|
|
391
|
+
const insertFile = db.prepare(`INSERT INTO files (path, branch, language, size_bytes, last_hash, source, layer, generation)
|
|
359
392
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
360
|
-
const
|
|
361
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
393
|
+
const insertSymbol = db.prepare(`INSERT INTO symbols (file_id, name, kind, start_line, end_line, signature, doc_comment, resolved_type_signature, resolved_return_type, definition_uri, definition_path, layer, generation)
|
|
394
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
395
|
+
const insertCallRef = db.prepare(`INSERT INTO symbol_refs (caller_id, file_id, callee_id, callee_name, call_line, call_character, call_kind, resolution_method, resolved_type_signature, resolved_return_type, definition_uri, definition_path, definition_line, definition_character, layer, generation)
|
|
396
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
397
|
+
const insertTypeRef = db.prepare(`INSERT INTO type_refs (file_id, symbol_id, type_id, type_name, type_name_bare, ref_kind, ref_line, ref_character, resolution_method, resolved_type_signature, definition_uri, definition_path, definition_line, definition_character, layer, generation)
|
|
398
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
399
|
+
const insertImport = db.prepare('INSERT INTO file_imports (file_id, raw_import, resolved_id, layer, generation) VALUES (?, ?, ?, ?, ?)');
|
|
400
|
+
const insertRelationship = db.prepare(`INSERT INTO symbol_relationships (file_id, source_symbol_id, target_symbol_name, relationship_type, line, character, resolution_method, definition_uri, definition_path, definition_line, definition_character, layer, generation)
|
|
401
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
402
|
+
const layer = context.layer;
|
|
403
|
+
const generation = context.generation;
|
|
365
404
|
// Global map: SCIP symbol string → Lore numeric symbol ID (across all files)
|
|
366
405
|
const scipToLoreId = new Map();
|
|
367
406
|
// Pass 1: Create files and symbols
|
|
@@ -380,12 +419,13 @@ export class ScipSourceStage {
|
|
|
380
419
|
catch {
|
|
381
420
|
continue;
|
|
382
421
|
}
|
|
422
|
+
// Cache for downstream stages (metrics computation, enrichment).
|
|
423
|
+
context.sourceCache.set(absPath, source);
|
|
383
424
|
const sizeBytes = Buffer.byteLength(source, 'utf8');
|
|
384
425
|
const hash = crypto.createHash('sha256').update(source).digest('hex');
|
|
385
426
|
// Delete existing data for this file (like SourceIndexStage does)
|
|
386
427
|
const existing = db.prepare('SELECT id FROM files WHERE path = ? AND branch = ?').get(absPath, branch);
|
|
387
428
|
if (existing) {
|
|
388
|
-
db.prepare('DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file_id = ?)').run(existing.id);
|
|
389
429
|
db.prepare('DELETE FROM symbol_relationships WHERE file_id = ?').run(existing.id);
|
|
390
430
|
db.prepare('DELETE FROM type_refs WHERE file_id = ?').run(existing.id);
|
|
391
431
|
db.prepare('UPDATE symbol_refs SET callee_id = NULL WHERE callee_id IN (SELECT id FROM symbols WHERE file_id = ?)').run(existing.id);
|
|
@@ -395,7 +435,7 @@ export class ScipSourceStage {
|
|
|
395
435
|
db.prepare('DELETE FROM files WHERE id = ?').run(existing.id);
|
|
396
436
|
}
|
|
397
437
|
// Insert file
|
|
398
|
-
const fileInfo = insertFile.run(absPath, branch, loreLang, sizeBytes, hash, source);
|
|
438
|
+
const fileInfo = insertFile.run(absPath, branch, loreLang, sizeBytes, hash, source, layer, generation);
|
|
399
439
|
const fileId = Number(fileInfo.lastInsertRowid);
|
|
400
440
|
fileIdMap.set(absPath, fileId);
|
|
401
441
|
coveredFiles.add(absPath);
|
|
@@ -452,14 +492,18 @@ export class ScipSourceStage {
|
|
|
452
492
|
continue;
|
|
453
493
|
const signature = extractSignatureFromDoc(firstDoc);
|
|
454
494
|
const docComment = symInfo.documentation.slice(1).join('\n').trim() || null;
|
|
455
|
-
|
|
495
|
+
// Compute enrichment data inline (definition + type signature)
|
|
496
|
+
const resolvedTypeSig = signature || null;
|
|
497
|
+
const resolvedReturnType = extractReturnType(resolvedTypeSig);
|
|
498
|
+
const definitionUri = pathToFileURL(absPath).toString();
|
|
499
|
+
const info = insertSymbol.run(fileId, name, kind, defLoc.startLine, defLoc.endLine, signature || null, docComment, resolvedTypeSig, resolvedReturnType, definitionUri, absPath, layer, generation);
|
|
456
500
|
const loreId = Number(info.lastInsertRowid);
|
|
457
501
|
scipToLoreId.set(symInfo.symbol, loreId);
|
|
458
|
-
insertFts.run(loreId, name, buildStructuralEmbeddingText({ name, signature: signature || null }), kind);
|
|
459
502
|
}
|
|
460
503
|
// Insert imports (from Import-role occurrences)
|
|
461
|
-
// Prefer the actual import path from source; fall back to SCIP package
|
|
462
|
-
|
|
504
|
+
// Prefer the actual import path from source; fall back to SCIP package.
|
|
505
|
+
// Use symbolDefinitions to pre-resolve imports to target file IDs.
|
|
506
|
+
const seenImports = new Map(); // rawImport → resolved file ID
|
|
463
507
|
for (const occ of doc.occurrences) {
|
|
464
508
|
if ((occ.symbolRoles & SymbolRole.Import) !== 0 && occ.symbol) {
|
|
465
509
|
const importLine = occ.range[0] ?? 0;
|
|
@@ -475,9 +519,23 @@ export class ScipSourceStage {
|
|
|
475
519
|
const parts = occ.symbol.split(' ');
|
|
476
520
|
rawImport = parts.length >= 4 ? parts[3] : occ.symbol;
|
|
477
521
|
}
|
|
478
|
-
if (
|
|
479
|
-
|
|
480
|
-
|
|
522
|
+
if (!rawImport)
|
|
523
|
+
continue;
|
|
524
|
+
// Resolve the import's target file via SCIP symbol → definition location
|
|
525
|
+
const defLoc = symbolDefinitions.get(occ.symbol);
|
|
526
|
+
const resolvedFileId = defLoc ? (fileIdMap.get(defLoc.filePath) ?? null) : null;
|
|
527
|
+
if (seenImports.has(rawImport)) {
|
|
528
|
+
// If we already inserted this import without a resolved_id,
|
|
529
|
+
// upgrade it now that we have one.
|
|
530
|
+
if (resolvedFileId && !seenImports.get(rawImport)) {
|
|
531
|
+
seenImports.set(rawImport, resolvedFileId);
|
|
532
|
+
db.prepare('UPDATE file_imports SET resolved_id = ? WHERE file_id = ? AND raw_import = ?')
|
|
533
|
+
.run(resolvedFileId, fileId, rawImport);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
seenImports.set(rawImport, resolvedFileId);
|
|
538
|
+
insertImport.run(fileId, rawImport, resolvedFileId, layer, generation);
|
|
481
539
|
}
|
|
482
540
|
}
|
|
483
541
|
}
|
|
@@ -517,7 +575,10 @@ export class ScipSourceStage {
|
|
|
517
575
|
// relationships for symbols whose definition is in another file or
|
|
518
576
|
// external package, so defLoc may be undefined.
|
|
519
577
|
const defLoc = symbolDefinitions.get(symInfo.symbol);
|
|
520
|
-
|
|
578
|
+
// Resolve the target's definition location for enrichment
|
|
579
|
+
const targetDef = symbolDefinitions.get(rel.symbol);
|
|
580
|
+
const relDefUri = targetDef ? pathToFileURL(targetDef.filePath).toString() : null;
|
|
581
|
+
insertRelationship.run(fileId, sourceId, targetName, relType, defLoc?.line ?? null, defLoc?.character ?? null, targetId ? 'scip_definition' : 'unresolved', relDefUri, targetDef?.filePath ?? null, targetDef?.line ?? null, targetDef?.character ?? null, layer, generation);
|
|
521
582
|
// If we have both source and target IDs, update the resolved target
|
|
522
583
|
if (targetId) {
|
|
523
584
|
db.prepare('UPDATE symbol_relationships SET target_symbol_id = ? WHERE file_id = ? AND source_symbol_id = ? AND target_symbol_name = ? AND relationship_type = ?').run(targetId, fileId, sourceId, targetName, relType);
|
|
@@ -527,7 +588,7 @@ export class ScipSourceStage {
|
|
|
527
588
|
}
|
|
528
589
|
});
|
|
529
590
|
processDocuments();
|
|
530
|
-
log.indexing('scip-
|
|
591
|
+
log.indexing('scip-indexer: symbols inserted', {
|
|
531
592
|
files: fileIdMap.size,
|
|
532
593
|
symbols: scipToLoreId.size,
|
|
533
594
|
});
|
|
@@ -656,21 +717,49 @@ export class ScipSourceStage {
|
|
|
656
717
|
}
|
|
657
718
|
if (refKind === 'type') {
|
|
658
719
|
const typeRefKind = inferTypeRefKind(sourceLines, line, character);
|
|
659
|
-
|
|
660
|
-
|
|
720
|
+
// Resolve enrichment metadata for the referenced type
|
|
721
|
+
const refDef = symbolDefinitions.get(occ.symbol);
|
|
722
|
+
const refInfo = symbolInfoMap.get(occ.symbol);
|
|
723
|
+
const refSig = refInfo ? extractSignatureFromDoc(refInfo.documentation[0] ?? '') || null : null;
|
|
724
|
+
const refDefUri = refDef ? pathToFileURL(refDef.filePath).toString() : null;
|
|
725
|
+
try {
|
|
726
|
+
insertTypeRef.run(fileId, callerId, calleeId ?? null, calleeName, normalizeTypeName(calleeName), typeRefKind, line, character, method, refSig, refDefUri, refDef?.filePath ?? null, refDef?.line ?? null, refDef?.character ?? null, layer, generation);
|
|
727
|
+
typeRefsInserted++;
|
|
728
|
+
}
|
|
729
|
+
catch {
|
|
730
|
+
// FK constraint failure — skip this ref
|
|
731
|
+
refsNoCaller++;
|
|
732
|
+
}
|
|
661
733
|
}
|
|
662
734
|
else {
|
|
663
735
|
// refKind === 'call'
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
736
|
+
// Skip if callee can't be resolved — FK constraint requires valid callee_id
|
|
737
|
+
if (!calleeId) {
|
|
738
|
+
refsNoCaller++;
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
// Resolve enrichment metadata for the callee
|
|
742
|
+
const refDef = symbolDefinitions.get(occ.symbol);
|
|
743
|
+
const refInfo = symbolInfoMap.get(occ.symbol);
|
|
744
|
+
const refSig = refInfo ? extractSignatureFromDoc(refInfo.documentation[0] ?? '') || null : null;
|
|
745
|
+
const refReturnType = extractReturnType(refSig);
|
|
746
|
+
const refDefUri = refDef ? pathToFileURL(refDef.filePath).toString() : null;
|
|
747
|
+
try {
|
|
748
|
+
insertCallRef.run(callerId, fileId, calleeId, calleeName, line, character, 'direct', method, refSig, refReturnType, refDefUri, refDef?.filePath ?? null, refDef?.line ?? null, refDef?.character ?? null, layer, generation);
|
|
749
|
+
refsInserted++;
|
|
750
|
+
if (isExternal)
|
|
751
|
+
refsExternal++;
|
|
752
|
+
}
|
|
753
|
+
catch {
|
|
754
|
+
// FK constraint failure — skip this ref
|
|
755
|
+
refsNoCaller++;
|
|
756
|
+
}
|
|
668
757
|
}
|
|
669
758
|
}
|
|
670
759
|
}
|
|
671
760
|
});
|
|
672
761
|
processRefs();
|
|
673
|
-
log.indexing('scip-
|
|
762
|
+
log.indexing('scip-indexer: refs inserted', {
|
|
674
763
|
callRefs: refsInserted,
|
|
675
764
|
typeRefs: typeRefsInserted,
|
|
676
765
|
external: refsExternal,
|
|
@@ -681,6 +770,9 @@ export class ScipSourceStage {
|
|
|
681
770
|
// Communicate coverage to downstream stages
|
|
682
771
|
context.scipSourcedLanguages = coveredLanguages;
|
|
683
772
|
context.scipSourcedFiles = coveredFiles;
|
|
773
|
+
// Also set scipCoveredLanguages so that LspEnrichmentStage skips
|
|
774
|
+
// languages already fully enriched by this single SCIP pass.
|
|
775
|
+
context.scipCoveredLanguages = coveredLanguages;
|
|
684
776
|
// Add SCIP-sourced files to context.files so later stages process them
|
|
685
777
|
for (const doc of scipIndex.documents) {
|
|
686
778
|
const absPath = resolve(rootDir, doc.relativePath);
|
|
@@ -694,62 +786,191 @@ export class ScipSourceStage {
|
|
|
694
786
|
// No persistent resources to clean up
|
|
695
787
|
}
|
|
696
788
|
// ─── SCIP index loading ──────────────────────────────────────────────────
|
|
697
|
-
|
|
789
|
+
async loadScipIndexes(settings, rootDir, staleLanguages = null) {
|
|
698
790
|
// Try pre-computed index directory first
|
|
699
791
|
if (settings.indexDir) {
|
|
792
|
+
const precomputed = [];
|
|
700
793
|
// When staleLanguages is set, prefer per-language index files so
|
|
701
794
|
// we only load the languages that actually need re-processing.
|
|
702
795
|
if (staleLanguages) {
|
|
703
796
|
for (const lang of staleLanguages) {
|
|
704
797
|
const candidate = join(rootDir, settings.indexDir, `${lang}.scip`);
|
|
705
798
|
if (existsSync(candidate)) {
|
|
706
|
-
|
|
799
|
+
precomputed.push(readFileSync(candidate));
|
|
707
800
|
}
|
|
708
801
|
}
|
|
709
802
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
803
|
+
if (precomputed.length === 0) {
|
|
804
|
+
const candidates = [
|
|
805
|
+
join(rootDir, settings.indexDir, 'index.scip'),
|
|
806
|
+
...['typescript', 'javascript', 'python', 'java', 'rust', 'c', 'cpp', 'csharp', 'ruby', 'php', 'go', 'dart'].map(lang => join(rootDir, settings.indexDir, `${lang}.scip`)),
|
|
807
|
+
];
|
|
808
|
+
for (const candidate of candidates) {
|
|
809
|
+
if (existsSync(candidate)) {
|
|
810
|
+
precomputed.push(readFileSync(candidate));
|
|
811
|
+
}
|
|
718
812
|
}
|
|
719
813
|
}
|
|
814
|
+
if (precomputed.length > 0)
|
|
815
|
+
return precomputed;
|
|
720
816
|
}
|
|
721
817
|
// Try running an indexer
|
|
722
|
-
|
|
818
|
+
let resolvedIndexers = resolveScipIndexerRegistry(settings.indexers);
|
|
819
|
+
const log = getLogger();
|
|
820
|
+
// Check if any indexers are available; if not, try auto-installing
|
|
821
|
+
const requestedLanguages = staleLanguages ?? new Set(Object.keys(resolvedIndexers));
|
|
822
|
+
const hasAvailable = [...requestedLanguages].some((lang) => resolvedIndexers[lang]?.available);
|
|
823
|
+
if (!hasAvailable) {
|
|
824
|
+
const attempted = new Set();
|
|
825
|
+
for (const lang of requestedLanguages) {
|
|
826
|
+
for (const spec of getSpecsForLanguage(lang)) {
|
|
827
|
+
if (attempted.has(spec.command))
|
|
828
|
+
continue;
|
|
829
|
+
attempted.add(spec.command);
|
|
830
|
+
log.indexing(`scip-indexer: auto-installing ${spec.command} for ${lang}...`);
|
|
831
|
+
const result = await installScipIndexer(spec);
|
|
832
|
+
if (result.installed) {
|
|
833
|
+
log.indexing(`scip-indexer: installed ${spec.command} at ${result.path}`);
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
log.indexing(`scip-indexer: could not install ${spec.command}: ${result.error ?? 'unknown'}`);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
// Re-resolve after installation
|
|
841
|
+
resolvedIndexers = resolveScipIndexerRegistry(settings.indexers);
|
|
842
|
+
}
|
|
843
|
+
// Determine which SCIP-supported languages actually exist in the project
|
|
844
|
+
// so we don't waste time running irrelevant indexers (e.g., scip-go on a C project).
|
|
845
|
+
const projectLanguages = staleLanguages ?? detectProjectLanguages(resolve(rootDir));
|
|
846
|
+
// Run all available indexers and merge results — don't stop at the first success.
|
|
847
|
+
// Group by shared command to avoid running the same indexer twice (e.g., scip-java for java/scala/kotlin).
|
|
848
|
+
const commandsRun = new Set();
|
|
849
|
+
const indexBuffers = [];
|
|
723
850
|
for (const [lang, indexer] of Object.entries(resolvedIndexers)) {
|
|
724
851
|
if (!indexer.available)
|
|
725
852
|
continue;
|
|
726
|
-
//
|
|
727
|
-
if (
|
|
853
|
+
// Skip languages not present in the project
|
|
854
|
+
if (!projectLanguages.has(lang))
|
|
855
|
+
continue;
|
|
856
|
+
// Don't run the same command twice (e.g., scip-clang for both c and cpp)
|
|
857
|
+
if (commandsRun.has(indexer.command))
|
|
728
858
|
continue;
|
|
859
|
+
commandsRun.add(indexer.command);
|
|
729
860
|
try {
|
|
730
|
-
const outputPath =
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
861
|
+
const outputPath = resolve(rootDir, `.lore-scip-${lang}.scip`);
|
|
862
|
+
let args = indexer.args.map(a => a.replace(/\{output\}/g, outputPath));
|
|
863
|
+
const cwd = resolve(rootDir);
|
|
864
|
+
// For C/C++: ensure a compile_commands.json exists and pass it to scip-clang
|
|
865
|
+
if ((lang === 'c' || lang === 'cpp') && args.some(a => a.includes('{compdb}'))) {
|
|
866
|
+
const compdb = await ensureCompilationDatabase(rootDir, settings.timeoutMs);
|
|
867
|
+
if (!compdb.path) {
|
|
868
|
+
log.indexing(`scip-indexer: no compile_commands.json for ${lang}, skipping`);
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
args = args.map(a => a.replace(/\{compdb\}/g, compdb.path));
|
|
872
|
+
}
|
|
873
|
+
// For TypeScript: generate a broad tsconfig so scip-typescript
|
|
874
|
+
// indexes ALL .ts files (including tests), not just those in the
|
|
875
|
+
// project's tsconfig "include" (which typically excludes tests).
|
|
876
|
+
let tempTsconfigPath = null;
|
|
877
|
+
if (lang === 'typescript') {
|
|
878
|
+
tempTsconfigPath = createLoreScipTsconfig(rootDir);
|
|
879
|
+
if (tempTsconfigPath) {
|
|
880
|
+
args.push(tempTsconfigPath);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
// scip-clang needs a longer timeout for large C projects
|
|
884
|
+
const indexerTimeout = (lang === 'c' || lang === 'cpp')
|
|
885
|
+
? Math.max(settings.timeoutMs, 600_000)
|
|
886
|
+
: settings.timeoutMs;
|
|
887
|
+
const execFileAsync = promisify(execFile);
|
|
888
|
+
const executablePath = indexer.resolvedPath ?? indexer.command;
|
|
889
|
+
try {
|
|
890
|
+
await execFileAsync(executablePath, args, {
|
|
891
|
+
cwd,
|
|
892
|
+
timeout: indexerTimeout,
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
finally {
|
|
896
|
+
if (tempTsconfigPath) {
|
|
897
|
+
try {
|
|
898
|
+
fs.unlinkSync(tempTsconfigPath);
|
|
899
|
+
}
|
|
900
|
+
catch { /* best effort */ }
|
|
901
|
+
}
|
|
902
|
+
}
|
|
737
903
|
// Check for output
|
|
738
|
-
for (const candidate of [outputPath,
|
|
904
|
+
for (const candidate of [outputPath, resolve(rootDir, 'index.scip')]) {
|
|
739
905
|
if (existsSync(candidate)) {
|
|
740
906
|
const data = readFileSync(candidate);
|
|
741
907
|
try {
|
|
742
908
|
fs.unlinkSync(candidate);
|
|
743
909
|
}
|
|
744
910
|
catch { /* best effort */ }
|
|
745
|
-
|
|
911
|
+
indexBuffers.push(data);
|
|
912
|
+
break;
|
|
746
913
|
}
|
|
747
914
|
}
|
|
748
915
|
}
|
|
749
|
-
catch {
|
|
916
|
+
catch (error) {
|
|
917
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
918
|
+
log.indexing(`scip-indexer: indexer failed for ${lang}: ${msg}`);
|
|
750
919
|
continue;
|
|
751
920
|
}
|
|
752
921
|
}
|
|
922
|
+
return indexBuffers;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
// ─── Temporary tsconfig for broad SCIP indexing ─────────────────────────────
|
|
926
|
+
/** Fields that only affect build output, not type-checking or SCIP indexing. */
|
|
927
|
+
const TSCONFIG_BUILD_ONLY_FIELDS = [
|
|
928
|
+
'outDir', 'rootDir', 'declaration', 'declarationMap', 'declarationDir',
|
|
929
|
+
'sourceMap', 'inlineSourceMap', 'inlineSources', 'composite',
|
|
930
|
+
'tsBuildInfoFile', 'emitDeclarationOnly',
|
|
931
|
+
];
|
|
932
|
+
/**
|
|
933
|
+
* Generate a temporary tsconfig that includes **all** `.ts`/`.tsx` files
|
|
934
|
+
* in the project, so `scip-typescript` indexes tests and other files
|
|
935
|
+
* excluded by the project's production tsconfig.
|
|
936
|
+
*
|
|
937
|
+
* The file is written to `os.tmpdir()` so the indexed repo is never mutated.
|
|
938
|
+
* Include/exclude globs use absolute paths rooted at `rootDir` so
|
|
939
|
+
* `scip-typescript` resolves source files correctly even though the
|
|
940
|
+
* tsconfig lives elsewhere.
|
|
941
|
+
*
|
|
942
|
+
* Strips build-only compiler options (`outDir`, `rootDir`, `declaration`,
|
|
943
|
+
* etc.) that would conflict with the broad `include` and are irrelevant
|
|
944
|
+
* for SCIP analysis. Preserves all type-checking options (`strict`,
|
|
945
|
+
* `paths`, `baseUrl`, etc.) so SCIP still resolves types correctly.
|
|
946
|
+
*
|
|
947
|
+
* Returns the path to the temp file, or `null` if no tsconfig exists.
|
|
948
|
+
*/
|
|
949
|
+
export function createLoreScipTsconfig(rootDir) {
|
|
950
|
+
const log = getLogger();
|
|
951
|
+
const tsconfigPath = join(rootDir, 'tsconfig.json');
|
|
952
|
+
if (!existsSync(tsconfigPath))
|
|
953
|
+
return null;
|
|
954
|
+
try {
|
|
955
|
+
const raw = JSON.parse(readFileSync(tsconfigPath, 'utf8'));
|
|
956
|
+
const compilerOptions = { ...(raw.compilerOptions ?? {}) };
|
|
957
|
+
// Strip build-only fields
|
|
958
|
+
for (const field of TSCONFIG_BUILD_ONLY_FIELDS) {
|
|
959
|
+
delete compilerOptions[field];
|
|
960
|
+
}
|
|
961
|
+
// Use absolute paths so the tsconfig works from tmpdir
|
|
962
|
+
const absRoot = resolve(rootDir);
|
|
963
|
+
const loreTsconfig = {
|
|
964
|
+
compilerOptions,
|
|
965
|
+
include: [join(absRoot, '**/*.ts'), join(absRoot, '**/*.tsx')],
|
|
966
|
+
exclude: (raw.exclude ?? ['node_modules']).map((e) => join(absRoot, e)),
|
|
967
|
+
};
|
|
968
|
+
const outPath = join(tmpdir(), `lore-scip-${crypto.randomUUID()}.json`);
|
|
969
|
+
fs.writeFileSync(outPath, JSON.stringify(loreTsconfig, null, 2));
|
|
970
|
+
log.debug('scip', `generated broad tsconfig for SCIP: ${outPath}`);
|
|
971
|
+
return outPath;
|
|
972
|
+
}
|
|
973
|
+
catch {
|
|
753
974
|
return null;
|
|
754
975
|
}
|
|
755
976
|
}
|
|
@@ -770,6 +991,10 @@ function classifyScipReference(scipSymbol) {
|
|
|
770
991
|
// Method/function: ends with (). or (+N). (with disambiguator)
|
|
771
992
|
if (/\(\+?\d*\)\.$/.test(scipSymbol))
|
|
772
993
|
return 'call';
|
|
994
|
+
// scip-clang C/C++ functions: term descriptors ending with `(hexhash).`
|
|
995
|
+
// E.g., `$ parse_analyze_fixedparams(39d222e79bbfb7c0).`
|
|
996
|
+
if (/\([0-9a-f]{8,}\)\.$/.test(scipSymbol))
|
|
997
|
+
return 'call';
|
|
773
998
|
// Type: ends with #
|
|
774
999
|
if (scipSymbol.endsWith('#'))
|
|
775
1000
|
return 'type';
|
|
@@ -803,7 +1028,7 @@ function classifyScipReference(scipSymbol) {
|
|
|
803
1028
|
*/
|
|
804
1029
|
function extractImportPathFromSource(line) {
|
|
805
1030
|
const trimmed = line.trim();
|
|
806
|
-
// JS/TS: import ... from 'path' | import 'path' | require('path')
|
|
1031
|
+
// JS/TS: import ... from 'path' | import 'path' | require('path') | import('path')
|
|
807
1032
|
let m = trimmed.match(/\bfrom\s+['"]([^'"]+)['"]/);
|
|
808
1033
|
if (m)
|
|
809
1034
|
return m[1];
|
|
@@ -811,6 +1036,9 @@ function extractImportPathFromSource(line) {
|
|
|
811
1036
|
if (m)
|
|
812
1037
|
return m[1];
|
|
813
1038
|
m = trimmed.match(/^import\s+['"]([^'"]+)['"]/);
|
|
1039
|
+
if (m)
|
|
1040
|
+
return m[1];
|
|
1041
|
+
m = trimmed.match(/\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/);
|
|
814
1042
|
if (m)
|
|
815
1043
|
return m[1];
|
|
816
1044
|
// C/C++: #include "path" | #include <path>
|
|
@@ -869,32 +1097,65 @@ const SCIP_LANG_MAP = {
|
|
|
869
1097
|
go: 'go',
|
|
870
1098
|
dart: 'dart',
|
|
871
1099
|
};
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1100
|
+
/**
|
|
1101
|
+
* Quick scan of the project root to detect which SCIP-supported languages
|
|
1102
|
+
* are present. Checks for telltale file extensions and build files.
|
|
1103
|
+
* Only scans top-level + one directory deep to stay fast.
|
|
1104
|
+
*/
|
|
1105
|
+
function detectProjectLanguages(rootDir) {
|
|
1106
|
+
const found = new Set();
|
|
1107
|
+
const langIndicators = {
|
|
1108
|
+
typescript: ['tsconfig.json', 'package.json'],
|
|
1109
|
+
python: ['setup.py', 'pyproject.toml', 'requirements.txt'],
|
|
1110
|
+
java: ['pom.xml', 'build.gradle', 'build.gradle.kts'],
|
|
1111
|
+
rust: ['Cargo.toml'],
|
|
1112
|
+
c: ['Makefile', 'CMakeLists.txt', 'meson.build', 'configure', 'configure.ac'],
|
|
1113
|
+
cpp: ['CMakeLists.txt', 'meson.build'],
|
|
1114
|
+
csharp: ['.csproj', '.sln'],
|
|
1115
|
+
ruby: ['Gemfile'],
|
|
1116
|
+
go: ['go.mod'],
|
|
1117
|
+
php: ['composer.json'],
|
|
1118
|
+
dart: ['pubspec.yaml'],
|
|
1119
|
+
};
|
|
1120
|
+
// Check for language indicator files at the root
|
|
1121
|
+
for (const [lang, indicators] of Object.entries(langIndicators)) {
|
|
1122
|
+
for (const indicator of indicators) {
|
|
1123
|
+
if (existsSync(join(rootDir, indicator))) {
|
|
1124
|
+
found.add(lang);
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
// Quick extension scan: read first-level directory entries
|
|
1130
|
+
try {
|
|
1131
|
+
const entries = fs.readdirSync(rootDir, { withFileTypes: true });
|
|
1132
|
+
for (const entry of entries) {
|
|
1133
|
+
if (entry.isFile()) {
|
|
1134
|
+
const ext = entry.name.slice(entry.name.lastIndexOf('.')).toLowerCase();
|
|
1135
|
+
const lang = EXT_TO_LANG[ext];
|
|
1136
|
+
if (lang && SCIP_SUPPORTED_LANGUAGES.has(lang))
|
|
1137
|
+
found.add(lang);
|
|
1138
|
+
}
|
|
1139
|
+
else if (entry.isDirectory() && entry.name !== 'node_modules' && !entry.name.startsWith('.')) {
|
|
1140
|
+
// One level deep
|
|
1141
|
+
try {
|
|
1142
|
+
const subEntries = fs.readdirSync(join(rootDir, entry.name), { withFileTypes: true });
|
|
1143
|
+
for (const sub of subEntries.slice(0, 50)) { // Limit to avoid scanning huge dirs
|
|
1144
|
+
if (sub.isFile()) {
|
|
1145
|
+
const ext = sub.name.slice(sub.name.lastIndexOf('.')).toLowerCase();
|
|
1146
|
+
const lang = EXT_TO_LANG[ext];
|
|
1147
|
+
if (lang && SCIP_SUPPORTED_LANGUAGES.has(lang))
|
|
1148
|
+
found.add(lang);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
catch { /* ignore permission errors */ }
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
catch { /* ignore */ }
|
|
1157
|
+
return found;
|
|
1158
|
+
}
|
|
898
1159
|
/**
|
|
899
1160
|
* Determine the Lore language for a SCIP document.
|
|
900
1161
|
*
|
|
@@ -919,4 +1180,4 @@ function inferLoreLanguage(scipLanguage, relativePath) {
|
|
|
919
1180
|
// ─── Test-visible helpers ───────────────────────────────────────────────────
|
|
920
1181
|
// Exported for unit testing only. Not part of the public API.
|
|
921
1182
|
export { estimateSymbolEndLine as _estimateSymbolEndLine, inferTypeRefKind as _inferTypeRefKind, extractImportPathFromSource as _extractImportPathFromSource, inferKindFromScipSymbol as _inferKindFromScipSymbol, inferLoreLanguage as _inferLoreLanguage, classifyScipReference as _classifyScipReference, extractNameFromScipSymbol as _extractNameFromScipSymbol, };
|
|
922
|
-
//# sourceMappingURL=scip-
|
|
1183
|
+
//# sourceMappingURL=scip-indexer.js.map
|