mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-11 22:53:04 +00:00
fix(zig): a build-module alias bound to an unindexed root fails closed
resolveThroughBuildModules returned undefined when the containing module
bound the alias to a file that is not indexed, which let the repo-wide
addModule map answer under the same name (gitnexus-check on 5299c552).
The module's table is the authority for its aliases: bound-but-unindexed
is null, only an unbound name falls through. Unit case with a same-named
repo-wide decoy, plus the outside-module file that still reaches it.
This commit is contained in:
parent
5299c5521f
commit
fe24b37f5e
2 changed files with 23 additions and 6 deletions
|
|
@ -69,9 +69,11 @@ function zigModulesContaining(
|
||||||
* tables. `undefined` when no containing module binds the name (the caller
|
* tables. `undefined` when no containing module binds the name (the caller
|
||||||
* falls back to the repo-wide tables); `null` when the containing modules
|
* falls back to the repo-wide tables); `null` when the containing modules
|
||||||
* DISAGREE — two same-directory modules that bind one alias to different
|
* DISAGREE — two same-directory modules that bind one alias to different
|
||||||
* roots. That is fail-closed on purpose: picking either would mint a
|
* roots — or when the alias is bound to a root that is not indexed (a
|
||||||
* confident wrong `IMPORTS` edge for half the files, which is the
|
* generated or skipped file). Both are fail-closed on purpose: the module's
|
||||||
* first-wins defect this table exists to remove.
|
* own table is the authority for the alias, and falling through to the
|
||||||
|
* repo-wide map would reintroduce the first-wins answer this table exists
|
||||||
|
* to remove, under a name the module never meant.
|
||||||
*/
|
*/
|
||||||
function resolveThroughBuildModules(
|
function resolveThroughBuildModules(
|
||||||
currentFile: string,
|
currentFile: string,
|
||||||
|
|
@ -80,11 +82,14 @@ function resolveThroughBuildModules(
|
||||||
modules: readonly ZigBuildModule[],
|
modules: readonly ZigBuildModule[],
|
||||||
): string | null | undefined {
|
): string | null | undefined {
|
||||||
const targets = new Set<string>();
|
const targets = new Set<string>();
|
||||||
|
let bound = false;
|
||||||
for (const mod of zigModulesContaining(currentFile, modules)) {
|
for (const mod of zigModulesContaining(currentFile, modules)) {
|
||||||
const target = mod.imports.get(importPath);
|
const target = mod.imports.get(importPath);
|
||||||
if (target !== undefined && allFiles.has(target)) targets.add(target);
|
if (target === undefined) continue;
|
||||||
|
bound = true;
|
||||||
|
if (allFiles.has(target)) targets.add(target);
|
||||||
}
|
}
|
||||||
if (targets.size === 0) return undefined;
|
if (targets.size === 0) return bound ? null : undefined;
|
||||||
if (targets.size > 1) return null;
|
if (targets.size > 1) return null;
|
||||||
return targets.values().next().value ?? null;
|
return targets.values().next().value ?? null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -317,12 +317,24 @@ describe('resolveZigImportInternal', () => {
|
||||||
buildModules: [{ root: 'src/main.zig', imports: new Map([['cfg', 'src/cfg.zig']]) }],
|
buildModules: [{ root: 'src/main.zig', imports: new Map([['cfg', 'src/cfg.zig']]) }],
|
||||||
};
|
};
|
||||||
expect(resolveZigImportInternal('src/main.zig', 'mylib', files, config)).toBe('src/lib.zig');
|
expect(resolveZigImportInternal('src/main.zig', 'mylib', files, config)).toBe('src/lib.zig');
|
||||||
// A table entry whose root is not indexed is not an answer either.
|
// A table entry whose root is not indexed is not an answer either — and
|
||||||
|
// it does not fall through: the module's table is the authority for the
|
||||||
|
// alias, so a same-named repo-wide `addModule("cfg")` pointing elsewhere
|
||||||
|
// must not answer in its place (gitnexus-check on 5299c552).
|
||||||
const stale = {
|
const stale = {
|
||||||
...config,
|
...config,
|
||||||
|
rootModules: new Map([
|
||||||
|
['mylib', 'src/lib.zig'],
|
||||||
|
['cfg', 'src/cfg.zig'],
|
||||||
|
]),
|
||||||
buildModules: [{ root: 'src/main.zig', imports: new Map([['cfg', 'src/gone.zig']]) }],
|
buildModules: [{ root: 'src/main.zig', imports: new Map([['cfg', 'src/gone.zig']]) }],
|
||||||
};
|
};
|
||||||
expect(resolveZigImportInternal('src/main.zig', 'cfg', files, stale)).toBeNull();
|
expect(resolveZigImportInternal('src/main.zig', 'cfg', files, stale)).toBeNull();
|
||||||
|
// …while a file OUTSIDE that module (`src/lib.zig` shares the root's
|
||||||
|
// directory and so belongs to it; `other/x.zig` does not) still reaches
|
||||||
|
// the repo-wide name.
|
||||||
|
const outside = new Set<string>([...files, 'other/x.zig']);
|
||||||
|
expect(resolveZigImportInternal('other/x.zig', 'cfg', outside, stale)).toBe('src/cfg.zig');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns null for an unknown bare name not in build.zig.zon', () => {
|
it('returns null for an unknown bare name not in build.zig.zon', () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue