mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-10 22:43:40 +00:00
Trimmed rebuild of 6ea5aa44 (fork PR #4): Move core (gitnexus/src/core/move/)
and Move tests, plus the functional minimum elsewhere.
Dropped from the original commit:
- .gitignore .codex/ entry (unrelated)
- cli/analyze.ts env-constant swap (cosmetic; same string literal)
- core/logger.ts warnRespectingProgressBar extraction and the
filesystem-walker.ts reuse of it (Move code never imports the helper)
- scope-resolution callable-value-flow warning aggregation and pipeline/run.ts
progress-warning formatting, with their two tests (warning-UX hardening,
not Move-functional)
- process-detection interface doc-comment retuning (DEFAULT_CONFIG runtime
values already match upstream; region left byte-identical to upstream)
Kept outside src/core/move/ and Move tests (one line each):
- gitnexus-shared/src/graph/types.ts: 'external' locationFidelity for
dependency symbols
- gitnexus-shared/src/lbug/schema-constants.ts: 'Type' node table registration
- core/lbug/schema.ts: Type table schema + Move rel-table endpoint pairs
- core/lbug/node-table-layout.ts: TYPE_LAYOUT CSV layout
- core/lbug/csv-generator.ts: 'Type' in MULTI_LANG_TYPES routing
- core/lbug/lbug-adapter.ts: deleteAllExternalNodes + shared delete-by-label
mechanics; Type backtick entry
- core/incremental/subgraph-extract.ts: external nodes get the
delete-all-then-rebuild treatment
- core/run-analyze.ts: Move consistency digest to meta.json;
deleteAllExternalNodes call; grouped Move meta; finally-based shutdown
- storage/repo-manager.ts: moveConsistency in RepoMeta;
INCREMENTAL_SCHEMA_VERSION 13 (Type/EnumVariant persistence)
- core/ingestion/pipeline.ts: generic TStandaloneIngest output threading
- types/pipeline.ts: PipelineResult.standaloneIngest replaces ingestWarnings
- core/ingestion/process-processor.ts: ENTRY_POINT_OF explicit graph roots
- tests: schema, node-table-layout, process-processor,
repo-manager-reconcile, call-summary-schema-version,
incremental-subgraph-extract, run-analyze-fts-repair (unit);
lbug-core-adapter (integration)
Gates: tsc clean; Move unit 185/185; full unit suite green except three
pre-existing Darwin-environment failures reproduced on the pristine base;
integration (move + lbug-core-adapter) 29/29.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
174 lines
5.7 KiB
TypeScript
174 lines
5.7 KiB
TypeScript
// gitnexus/test/unit/move/ref-resolver.test.ts
|
|
import { describe, it, expect } from 'vitest';
|
|
import { createKnowledgeGraph } from '../../../src/core/graph/graph.js';
|
|
import { resolveRefs, buildLocalNameIndex } from '../../../src/core/move/move-linker.js';
|
|
import { ExternalMoveSymbols } from '../../../src/core/move/move-linker.js';
|
|
import type { PendingRef, DroppedRef } from '../../../src/core/move/refs.js';
|
|
import { MOVE_EDGE_REASON } from '../../../src/core/move/constants.js';
|
|
|
|
function fnNode(graph: ReturnType<typeof createKnowledgeGraph>, id: string) {
|
|
graph.addNode({
|
|
id,
|
|
label: 'Function',
|
|
properties: {
|
|
name: id,
|
|
filePath: 'a.move',
|
|
language: 'move',
|
|
qualifiedName: id,
|
|
usedTypes: [],
|
|
},
|
|
});
|
|
}
|
|
function structNode(graph: ReturnType<typeof createKnowledgeGraph>, id: string, qn: string) {
|
|
graph.addNode({
|
|
id,
|
|
label: 'Struct',
|
|
properties: { name: qn, filePath: 'a.move', language: 'move', qualifiedName: qn },
|
|
});
|
|
}
|
|
|
|
describe('resolveRefs', () => {
|
|
it('resolves a type ref to a mapped struct and records usedTypes', () => {
|
|
const graph = createKnowledgeGraph();
|
|
fnNode(graph, 'Function:a.move:0xa::m::f');
|
|
structNode(graph, 'Struct:a.move:0xa::m::S', '0xa::m::S');
|
|
const structNodeMap = new Map([['0xa::m::S', 'Struct:a.move:0xa::m::S']]);
|
|
const drops: DroppedRef[] = [];
|
|
const external = new ExternalMoveSymbols(graph, new Map([['0xa::m', 'Module:a.move:0xa::m']]));
|
|
const refs: PendingRef[] = [
|
|
{
|
|
kind: 'type',
|
|
knownNodeId: 'Function:a.move:0xa::m::f',
|
|
target: '0xa::m::S',
|
|
moduleQualified: '0xa::m',
|
|
edgeType: 'USES_TYPE',
|
|
reason: MOVE_EDGE_REASON.fnParamType,
|
|
},
|
|
];
|
|
resolveRefs(
|
|
graph,
|
|
refs,
|
|
{
|
|
structNodeMap,
|
|
structIdsByLocalName: buildLocalNameIndex(structNodeMap),
|
|
moduleFileMap: new Map(),
|
|
functionNodeMap: new Map(),
|
|
},
|
|
external,
|
|
drops,
|
|
);
|
|
const edges = [...graph.iterRelationshipsByType('USES_TYPE')];
|
|
expect(edges).toHaveLength(1);
|
|
expect(graph.getNode('Function:a.move:0xa::m::f')!.properties.usedTypes).toContain('0xa::m::S');
|
|
expect(drops).toHaveLength(0);
|
|
});
|
|
|
|
it('drops an ambiguous local-name struct ref without externalizing', () => {
|
|
const graph = createKnowledgeGraph();
|
|
fnNode(graph, 'Function:a.move:0xa::m::f');
|
|
structNode(graph, 'Struct:a.move:0xa::m::S', '0xa::m::S');
|
|
structNode(graph, 'Struct:b.move:0xb::n::S', '0xb::n::S');
|
|
const structNodeMap = new Map([
|
|
['0xa::m::S', 'Struct:a.move:0xa::m::S'],
|
|
['0xb::n::S', 'Struct:b.move:0xb::n::S'],
|
|
]);
|
|
const drops: DroppedRef[] = [];
|
|
const external = new ExternalMoveSymbols(graph, new Map());
|
|
const refs: PendingRef[] = [
|
|
{
|
|
kind: 'resource',
|
|
knownNodeId: 'Function:a.move:0xa::m::f',
|
|
target: 'S',
|
|
moduleQualified: '0xc::other',
|
|
edgeType: 'READS_RESOURCE',
|
|
reason: MOVE_EDGE_REASON.readsResource,
|
|
},
|
|
];
|
|
resolveRefs(
|
|
graph,
|
|
refs,
|
|
{
|
|
structNodeMap,
|
|
structIdsByLocalName: buildLocalNameIndex(structNodeMap),
|
|
moduleFileMap: new Map(),
|
|
functionNodeMap: new Map(),
|
|
},
|
|
external,
|
|
drops,
|
|
);
|
|
expect([...graph.iterRelationshipsByType('READS_RESOURCE')]).toHaveLength(0);
|
|
expect(drops).toEqual([
|
|
{ kind: 'resource', sourceId: 'Function:a.move:0xa::m::f', target: 'S' },
|
|
]);
|
|
});
|
|
|
|
it('externalizes an unresolved qualified type ref', () => {
|
|
const graph = createKnowledgeGraph();
|
|
fnNode(graph, 'Function:a.move:0xa::m::f');
|
|
const drops: DroppedRef[] = [];
|
|
const external = new ExternalMoveSymbols(graph, new Map([['0xa::m', 'Module:a.move:0xa::m']]));
|
|
const refs: PendingRef[] = [
|
|
{
|
|
kind: 'type',
|
|
knownNodeId: 'Function:a.move:0xa::m::f',
|
|
target: '0x1::coin::Coin',
|
|
moduleQualified: '0xa::m',
|
|
edgeType: 'USES_TYPE',
|
|
reason: MOVE_EDGE_REASON.fnParamType,
|
|
},
|
|
];
|
|
resolveRefs(
|
|
graph,
|
|
refs,
|
|
{
|
|
structNodeMap: new Map(),
|
|
structIdsByLocalName: new Map(),
|
|
moduleFileMap: new Map(),
|
|
functionNodeMap: new Map(),
|
|
},
|
|
external,
|
|
drops,
|
|
);
|
|
expect([...graph.iterRelationshipsByType('USES_TYPE')]).toHaveLength(1);
|
|
expect(drops).toHaveLength(0);
|
|
expect(graph.getNode('Type::<external>:0x1::coin::Coin')).toBeTruthy();
|
|
});
|
|
|
|
it('resolves lambda-host with the resolved host as the edge source (known-target)', () => {
|
|
const graph = createKnowledgeGraph();
|
|
fnNode(graph, 'Function:a.move:0xa::m::host');
|
|
fnNode(graph, 'Function:a.move:0xa::m::__lambda__0__host');
|
|
const functionNodeMap = new Map([['0xa::m::host', 'Function:a.move:0xa::m::host']]);
|
|
const drops: DroppedRef[] = [];
|
|
const external = new ExternalMoveSymbols(graph, new Map());
|
|
const refs: PendingRef[] = [
|
|
{
|
|
kind: 'lambda-host',
|
|
knownNodeId: 'Function:a.move:0xa::m::__lambda__0__host',
|
|
target: '0xa::m::host',
|
|
moduleQualified: '',
|
|
edgeType: 'CALLS',
|
|
reason: MOVE_EDGE_REASON.lambdaHost,
|
|
},
|
|
];
|
|
resolveRefs(
|
|
graph,
|
|
refs,
|
|
{
|
|
structNodeMap: new Map(),
|
|
structIdsByLocalName: new Map(),
|
|
moduleFileMap: new Map(),
|
|
functionNodeMap,
|
|
},
|
|
external,
|
|
drops,
|
|
);
|
|
const calls = [...graph.iterRelationshipsByType('CALLS')];
|
|
expect(calls).toHaveLength(1);
|
|
expect(calls[0].sourceId).toBe('Function:a.move:0xa::m::host');
|
|
expect(calls[0].targetId).toBe('Function:a.move:0xa::m::__lambda__0__host');
|
|
// Behavior-preservation: lambda-host CALLS keeps the legacy 0.9 confidence
|
|
// (resource/type/friend use 1.0).
|
|
expect(calls[0].confidence).toBe(0.9);
|
|
});
|
|
});
|