ucn 4.1.2 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/bridge.js CHANGED
@@ -26,7 +26,6 @@ const fs = require('fs');
26
26
  const { codeUnitCompare } = require('./shared');
27
27
  const path = require('path');
28
28
  const { getCachedCalls } = require('./callers');
29
- const { langTraits } = require('../languages');
30
29
 
31
30
  // ============================================================================
32
31
  // HTTP METHOD CONSTANTS
package/core/brief.js CHANGED
@@ -16,8 +16,7 @@
16
16
 
17
17
  const fs = require('fs');
18
18
  const path = require('path');
19
- const { parse } = require('./parser');
20
- const { detectLanguage, langTraits } = require('../languages');
19
+ const { detectLanguage } = require('../languages');
21
20
  const { formatSymbolHandle } = require('./shared');
22
21
 
23
22
  // ============================================================================
@@ -377,7 +376,7 @@ function sideEffectsFor(index, symbol) {
377
376
  if (index._sideEffectCache.has(key)) return index._sideEffectCache.get(key);
378
377
 
379
378
  const filePath = path.isAbsolute(symbol.file || '') ? symbol.file : path.join(index.root, symbol.file || symbol.relativePath || '');
380
- let bodyText = '';
379
+ let bodyText;
381
380
  try {
382
381
  const content = fs.readFileSync(filePath, 'utf-8');
383
382
  const lines = content.split('\n');
@@ -40,6 +40,8 @@ function addSymbol(fileEntry, item, type) {
40
40
  // compare full symbol shapes, but only for shapes present in their
41
41
  // fixtures — keep this list in sync by hand when addSymbol grows.
42
42
  if (item.paramTypes) symbol.paramTypes = item.paramTypes;
43
+ if (item.returnedFunctionResult) symbol.returnedFunctionResult = item.returnedFunctionResult;
44
+ if (item.isFunctionVariable) symbol.isFunctionVariable = true;
43
45
  if (item.isAsync) symbol.isAsync = true;
44
46
  if (item.isGenerator) symbol.isGenerator = true;
45
47
  if (item.generics) symbol.generics = item.generics;
@@ -62,6 +64,8 @@ function addSymbol(fileEntry, item, type) {
62
64
  if (item.traitName) symbol.traitName = item.traitName;
63
65
  if (item.isSignature) symbol.isSignature = true;
64
66
  if (item.memberAssigned) symbol.memberAssigned = true;
67
+ if (item.registryMember) symbol.registryMember = true;
68
+ if (item.registryContainer) symbol.registryContainer = item.registryContainer;
65
69
 
66
70
  fileEntry.symbols.push(symbol);
67
71
  // Property-assignment defs declare no lexical name (fix #269) — kept in
@@ -169,6 +173,7 @@ function processFile(filePath) {
169
173
  bindings: [],
170
174
  dynamicImports: dynamicCount || 0,
171
175
  };
176
+ if (parsed.parseRecovery) fileEntry.parseRecovery = true;
172
177
  if (importAliases) fileEntry.importAliases = importAliases;
173
178
  if (parsed.moduleAssignedNames) fileEntry.moduleAssignedNames = parsed.moduleAssignedNames;
174
179
  if (isBundled) fileEntry.isBundled = true;
package/core/cache.js CHANGED
@@ -124,7 +124,47 @@ const UCN_VERSION = require('../package.json').version;
124
124
  // v47 (fix #269): Python absolute imports resolve through the PEP-517 src
125
125
  // layout (`import click` → src/click/__init__.py) — persisted
126
126
  // importGraph/exportGraph/moduleResolved content changed.
127
- const CACHE_FORMAT_VERSION = 47;
127
+ // v48 (fix #270): Java interface symbols record their extends clause (the
128
+ // grammar's extends_interfaces child carries no `extends` field, so the
129
+ // field lookup silently returned nothing) — cached interface symbols lack
130
+ // the supertypes the deadcode heritage walk reads.
131
+ // v49: JS/TS module-scope object-literal dispatch members carry
132
+ // registryMember/registryContainer so reachability does not classify live
133
+ // HANDLERS[command](...) implementations as dead code.
134
+ // v50: persist the same registry fields from parallel workers; v49 worker-built
135
+ // caches silently dropped them and therefore cannot be trusted.
136
+ // v51: JS/TS call aliases are lexical/position-aware; old calls caches can
137
+ // contain resolvedName values leaked from an unrelated block or later line.
138
+ // v55: Rust `Self { ... }` struct expressions persist the concrete enclosing
139
+ // impl type as their constructor-call name.
140
+ // v56: Java call records preserve typed identifiers/static-factory argument
141
+ // kinds and capitalized static-field receiver roots for overload/dispatch
142
+ // identity.
143
+ // v57: Java capitalized type receivers are no longer also persisted as
144
+ // implicit-this fields.
145
+ // v58: Java enhanced-for variables persist their declared receiver type.
146
+ // v59: Java class-literal argument kinds and capitalized static-field
147
+ // receivers are persisted for inherited overload/field ownership.
148
+ // v60: argument/comment scans ignore every tree-sitter comment node kind
149
+ // (line_comment, block_comment, documentation_comment), not only `comment`.
150
+ // v61: file entries persist tree-sitter parse-recovery state so doctor never
151
+ // reports a recovered/possibly-partial file as a clean parse.
152
+ // v62: Go call records preserve receiverTypeQualifier,
153
+ // receiverRootTypeQualifier, and package-owned value receiver shape; symbols
154
+ // preserve function-valued variables and returned-function result signatures.
155
+ // These fields feed package identity and higher-order return flow.
156
+ // v63: Python constructor-derived receiver types preserve the imported module
157
+ // qualifier (`threading.Thread()` -> receiverTypeQualifier:'threading').
158
+ // This prevents external/unresolved type owners from entering the confirmed
159
+ // project-method tier through a bare class-name collision.
160
+ // v64: Rust calls whose receiver is rebound by an enclosing if-let/while-let
161
+ // pattern preserve receiverPatternShadow. Query-time return flow must not
162
+ // smear an outer binding's type onto that inner pattern binding.
163
+ // v65: Rust turbofish calls inside macro token trees are persisted as calls
164
+ // (`m.get_many::<T>()`); v64 caches misclassified them as references.
165
+ // v66: Rust call records preserve receiverFlowInvalidated after a non-call
166
+ // lexical rebinding, preventing stale return types from excluding true calls.
167
+ const CACHE_FORMAT_VERSION = 66;
128
168
 
129
169
  /**
130
170
  * Save index to cache file
@@ -440,7 +480,7 @@ function loadCache(index, cachePath) {
440
480
  // Prepare lazy calls cache loading — load manifest but defer shard parsing.
441
481
  // Shards are loaded on first getCachedCalls access via ensureCallsCacheLoaded().
442
482
  if (index.callsCache.size === 0) {
443
- _prepareCallsCache(index);
483
+ _prepareCallsCache(index, cacheFile);
444
484
  }
445
485
 
446
486
  // Build directory→files index from loaded data
@@ -580,9 +620,16 @@ function isCacheStale(index) {
580
620
  * Actual shards are loaded on first ensureCallsCacheLoaded() call.
581
621
  * @param {object} index - ProjectIndex instance
582
622
  */
583
- function _prepareCallsCache(index) {
623
+ function _prepareCallsCache(index, cacheFile) {
584
624
  if (index._callsCacheLoaded) return;
585
- const cacheDir = path.join(index.root, '.ucn-cache');
625
+ // Shards live beside the selected index.json. A custom cachePath must be
626
+ // a complete portable cache, not an index file that silently looks for
627
+ // call shards under <project>/.ucn-cache. The latter caused cache-loaded
628
+ // semantic queries to reparse source (or consume unrelated stale shards).
629
+ const cacheDir = cacheFile
630
+ ? path.dirname(cacheFile)
631
+ : path.join(index.root, '.ucn-cache');
632
+ index._callsCacheDir = cacheDir;
586
633
  const manifestFile = path.join(cacheDir, 'calls', 'manifest.json');
587
634
  if (fs.existsSync(manifestFile)) {
588
635
  try {
@@ -627,7 +674,7 @@ function loadCallsCache(index) {
627
674
 
628
675
  // Legacy format: single calls-cache.json
629
676
  const callsCacheFile = index._callsCacheLegacyFile ||
630
- path.join(index.root, '.ucn-cache', 'calls-cache.json');
677
+ path.join(index._callsCacheDir || path.join(index.root, '.ucn-cache'), 'calls-cache.json');
631
678
  if (!fs.existsSync(callsCacheFile)) return index.callsCache.size > 0;
632
679
 
633
680
  try {
@@ -665,7 +712,9 @@ function ensureCallsCacheLoaded(index) {
665
712
  * @param {string} hash - Shard hash from manifest
666
713
  */
667
714
  function _loadCallsShard(index, hash) {
668
- const shardFile = path.join(index.root, '.ucn-cache', 'calls', `${hash}.json`);
715
+ const shardFile = path.join(
716
+ index._callsCacheDir || path.join(index.root, '.ucn-cache'),
717
+ 'calls', `${hash}.json`);
669
718
  try {
670
719
  const data = JSON.parse(fs.readFileSync(shardFile, 'utf-8'));
671
720
  if (!Array.isArray(data)) return;