mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-30 06:42:43 +00:00
fix(r): limit library() wildcard expansion to top-level definitions
expandRWildcardNames walked the flat localDefs of the target file and filtered
only dotted names, so a function nested inside another function
(`outer <- function() { helper <- function() 1 }`) was offered as a
package-level name to every file that calls library()/require() on the package.
Reproduction: two new cases in r-dotted-s3-hooks.test.ts failed on the
unfixed code (['outer', 'helper', 'top'] instead of ['outer', 'top'];
['a', 'b', 'c', 'd'] instead of ['a']). The expansion now keeps only names bound
at module scope (rFileTopLevel().names, which already feeds the dotted-tail
guard); top-level functions and bare-call S4/R6 classes are still listed
(controls added; test/integration/resolvers/r.test.ts unchanged and green).
This commit is contained in:
parent
abcc165088
commit
f80cfa09f2
2 changed files with 40 additions and 3 deletions
|
|
@ -104,7 +104,8 @@ function emitRVirtualHeritageEdges(
|
|||
}
|
||||
|
||||
/**
|
||||
* Enumerate all top-level names exported from a target module scope's file.
|
||||
* Enumerate all top-level names exported from a target module scope's file
|
||||
* (module-scope function and class bindings; functions nested in another function are not).
|
||||
* `library()`/`require()` are R's wildcard imports — every top-level name of
|
||||
* the named local package becomes visible, UNFILTERED by NAMESPACE (a
|
||||
* `library()`/`require()` call brings the whole package's namespace into
|
||||
|
|
@ -127,12 +128,15 @@ export function expandRWildcardNames(
|
|||
): readonly string[] {
|
||||
const target = parsedFiles.find((p) => p.moduleScope === targetModuleScope);
|
||||
if (target === undefined) return [];
|
||||
const { dottedTails } = rFileTopLevel(target);
|
||||
const { names: topLevel, dottedTails } = rFileTopLevel(target);
|
||||
const seen = new Set<string>();
|
||||
const names: string[] = [];
|
||||
for (const def of target.localDefs) {
|
||||
const qn = def.qualifiedName;
|
||||
if (qn === undefined || qn.length === 0 || qn.includes('.')) continue; // top-level only
|
||||
if (qn === undefined || qn.length === 0 || qn.includes('.')) continue; // no dotted names
|
||||
// `localDefs` is flat: it also lists functions nested in other functions, which a
|
||||
// `library()` does not bring into scope. Only module-scope bindings are top-level.
|
||||
if (!topLevel.has(qn)) continue;
|
||||
if (dottedTails.has(qn)) continue; // shares its tail with an S3 method: see above
|
||||
if (seen.has(qn)) continue;
|
||||
seen.add(qn);
|
||||
|
|
|
|||
|
|
@ -104,6 +104,39 @@ describe('expandRWildcardNames', () => {
|
|||
).toEqual(['Scorer', 'tidy']);
|
||||
});
|
||||
|
||||
it('lists only top-level definitions, not functions nested in another function', () => {
|
||||
expect(
|
||||
names('outer <- function() {\n helper <- function() 1\n helper()\n}\ntop <- function() 2'),
|
||||
).toEqual(['outer', 'top']);
|
||||
});
|
||||
|
||||
it('does not list a function nested several levels deep or inside a control block', () => {
|
||||
expect(
|
||||
names(
|
||||
[
|
||||
'a <- function() {',
|
||||
' b <- function() {',
|
||||
' c <- function() 1',
|
||||
' }',
|
||||
' if (TRUE) d <- function() 2',
|
||||
'}',
|
||||
].join('\n'),
|
||||
),
|
||||
).toEqual(['a']);
|
||||
});
|
||||
|
||||
it('still lists top-level classes alongside top-level functions', () => {
|
||||
expect(
|
||||
names('Scorer <- R6::R6Class("Scorer", public = list(f = function() 1))\nrun = function() 1'),
|
||||
).toEqual(['Scorer', 'run']);
|
||||
});
|
||||
|
||||
it('still lists an S4 class defined by a bare setClass() call', () => {
|
||||
expect(
|
||||
names('setClass("Shape", representation(n = "numeric"))\nplain <- function() 1'),
|
||||
).toEqual(['Shape', 'plain']);
|
||||
});
|
||||
|
||||
it('never lists dotted names themselves', () => {
|
||||
expect(names('print.foo <- function(x) x')).toEqual([]);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue