ucn 4.1.3 → 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
@@ -128,7 +128,43 @@ const UCN_VERSION = require('../package.json').version;
128
128
  // grammar's extends_interfaces child carries no `extends` field, so the
129
129
  // field lookup silently returned nothing) — cached interface symbols lack
130
130
  // the supertypes the deadcode heritage walk reads.
131
- const CACHE_FORMAT_VERSION = 48;
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;
132
168
 
133
169
  /**
134
170
  * Save index to cache file
@@ -444,7 +480,7 @@ function loadCache(index, cachePath) {
444
480
  // Prepare lazy calls cache loading — load manifest but defer shard parsing.
445
481
  // Shards are loaded on first getCachedCalls access via ensureCallsCacheLoaded().
446
482
  if (index.callsCache.size === 0) {
447
- _prepareCallsCache(index);
483
+ _prepareCallsCache(index, cacheFile);
448
484
  }
449
485
 
450
486
  // Build directory→files index from loaded data
@@ -584,9 +620,16 @@ function isCacheStale(index) {
584
620
  * Actual shards are loaded on first ensureCallsCacheLoaded() call.
585
621
  * @param {object} index - ProjectIndex instance
586
622
  */
587
- function _prepareCallsCache(index) {
623
+ function _prepareCallsCache(index, cacheFile) {
588
624
  if (index._callsCacheLoaded) return;
589
- 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;
590
633
  const manifestFile = path.join(cacheDir, 'calls', 'manifest.json');
591
634
  if (fs.existsSync(manifestFile)) {
592
635
  try {
@@ -631,7 +674,7 @@ function loadCallsCache(index) {
631
674
 
632
675
  // Legacy format: single calls-cache.json
633
676
  const callsCacheFile = index._callsCacheLegacyFile ||
634
- path.join(index.root, '.ucn-cache', 'calls-cache.json');
677
+ path.join(index._callsCacheDir || path.join(index.root, '.ucn-cache'), 'calls-cache.json');
635
678
  if (!fs.existsSync(callsCacheFile)) return index.callsCache.size > 0;
636
679
 
637
680
  try {
@@ -669,7 +712,9 @@ function ensureCallsCacheLoaded(index) {
669
712
  * @param {string} hash - Shard hash from manifest
670
713
  */
671
714
  function _loadCallsShard(index, hash) {
672
- 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`);
673
718
  try {
674
719
  const data = JSON.parse(fs.readFileSync(shardFile, 'utf-8'));
675
720
  if (!Array.isArray(data)) return;