mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-30 06:42:43 +00:00
docs(r): say that NAMESPACE refines graph nodes, not scope definitions
refineRExportStatus flips isExported on graph nodes only. The scope definitions that finalization reads carry no export verdict for R (undefined means unknown), which is deliberate: library() attaches every top-level name, as devtools::load_all() does. State that in the provider guide and pin it with a test, so a later change that stamps a verdict onto scope definitions is a conscious one.
This commit is contained in:
parent
248031b796
commit
06ae82c4e3
2 changed files with 41 additions and 1 deletions
|
|
@ -58,7 +58,7 @@ The scope query (`languages/r/query.ts`) captures three call shapes only: `f(x)`
|
|||
- Discovery may have missed a package (its limits were reached): the call keeps the name-based behaviour.
|
||||
- `::` and `:::` are not distinguished, so `pkg::name` binds to a definition whether or not the package exports it.
|
||||
- Package discovery is bounded to depth 3 and 200 directories (when the bound may have hidden a package this is flagged internally and nothing is logged), reads directories in code-unit order, ranks duplicate package names by shallowest then by whole path, and never searches directories named exactly `renv`, `packrat`, `revdep` or `<name>.Rcheck`. The shared file scanner has no such ignore entries, so `.R` files inside those trees are still parsed even though discovery skips them.
|
||||
- Export status: the language-level export check treats every symbol as public. The NAMESPACE pass then marks the remaining `R/` symbols of a NAMESPACE-bearing package non-exported. Symbols outside `R/` (`tests/`, `vignettes/`, `inst/`) are not package members and stay public; files in `R/` subdirectories are treated as `R/` files although R itself does not load them. A package without a NAMESPACE stays fully public, and a nested package without one does not inherit its enclosing package's. roxygen2 `@export` tags are not consulted.
|
||||
- Export status: the language-level export check treats every symbol as public. The NAMESPACE pass then marks the remaining `R/` symbols of a NAMESPACE-bearing package non-exported. Symbols outside `R/` (`tests/`, `vignettes/`, `inst/`) are not package members and stay public; files in `R/` subdirectories are treated as `R/` files although R itself does not load them. A package without a NAMESPACE stays fully public, and a nested package without one does not inherit its enclosing package's. roxygen2 `@export` tags are not consulted. The refinement changes the graph nodes' `isExported` only; the definitions scope resolution works from carry no export verdict, so `library()`, `pkg::name` and the global-name fallback do not consult NAMESPACE (only `importFrom()` does).
|
||||
- `exportPattern()` text comes from the analysed repository, so patterns are compiled to a linear-time automaton (`linear-regex.ts`) with a work budget. Constructs with no linear-time algorithm (back-references, look-around) and oversized patterns are dropped with one logged warning per pattern per package. Character classes use ASCII semantics. A directive argument the NAMESPACE reader cannot read at all is dropped without a warning: an R 4.0 raw string (`exportPattern(r"(^[^.])")`, `export(r"(foo)")`) and any string that spans lines. It exports nothing, so the names it was meant to cover read as non-exported.
|
||||
|
||||
## Limits and known gaps
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* R gives scope resolution no export verdict. `SymbolDefinition.isExported` is tri-state and
|
||||
* `undefined` means "unknown" (finalization then keeps its prior behaviour); R's export checker
|
||||
* says "public" for every graph node and the NAMESPACE refinement later flips graph nodes to
|
||||
* private, but neither writes a verdict onto a scope definition. That is deliberate: a
|
||||
* `library()` of a local package makes every top-level name visible, as `devtools::load_all()`
|
||||
* does (docs/languages/r-provider.md, Resolution model), so resolution must not treat a name
|
||||
* NAMESPACE omits as module-private. A verdict of `false` would make finalization drop it from
|
||||
* wildcard providers.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { extractParsedFile } from '../../../../src/core/ingestion/scope-extractor-bridge.js';
|
||||
import { rProvider } from '../../../../src/core/ingestion/languages/r.js';
|
||||
|
||||
describe('R scope definitions carry no export verdict', () => {
|
||||
const parsed = extractParsedFile(
|
||||
rProvider,
|
||||
[
|
||||
'exported_fn <- function() 1',
|
||||
'Widget <- R6Class("Widget", public = list(size = 1, grow = function() 1))',
|
||||
'setClass("Point", representation(x = "numeric"))',
|
||||
'setGeneric("area", function(shape) standardGeneric("area"))',
|
||||
].join('\n'),
|
||||
'R/a.R',
|
||||
);
|
||||
|
||||
it('extracts functions, classes and members (positive control)', () => {
|
||||
const types = new Set(parsed?.localDefs.map((d) => d.type));
|
||||
expect(types.has('Function')).toBe(true);
|
||||
expect(types.has('Class')).toBe(true);
|
||||
expect(types.has('Method')).toBe(true);
|
||||
});
|
||||
|
||||
it('leaves isExported unset on every definition', () => {
|
||||
expect(parsed?.localDefs.length).toBeGreaterThan(0);
|
||||
for (const def of parsed?.localDefs ?? []) {
|
||||
expect(def.isExported, `${def.type} ${def.qualifiedName}`).toBeUndefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue