Stubs
Not a separate node type — an entity with isStub: true, representing something external to the corpus (JDK, npm packages, …). Exactly two traits contribute isStub, so exactly two things are stubbable.
| Stub of | Trait | Shape | Why it must exist |
|---|---|---|---|
| a type | TType |
TNamed + TType, optionally TChildOf; no children, no anchor |
every corpus references types it does not declare |
| a module | TModule |
TNamed + TModule + TWithChildren, definedIn: [] |
the import graph is module-level, so import java.util.List points at the package java:java.util; with no module stub the first-class import layer could never satisfy closure |
A member (method, field) is deliberately not stubbable: an external member folds up to its declaring type’s stub. Fabricating a class named bill(Order) to close an endpoint is the one thing stub synthesis exists to prevent — an unresolvable member id is reported and left dangling instead.
A stub’s parent
The one non-degraded thing a stub type may hold is TChildOf — the external module it belongs to — and a stub module lists such types among its children. Two rules bound it, both extractor-side obligations:
- A stub’s parent must itself be a stub. Attributing an external type to a corpus module would make it read as internal to every module-level analysis. Where the parent cannot honestly be named — a static-analysis artefact invented inside the corpus’s own package, or a primitive, which has no module at all — the stub stays parentless and is reported as unplaceable at module level.
- Only the extractor may derive it. Ids are opaque to everything downstream; the extractor owns the id scheme and already knows the package.
Without this, an external type could not be folded to module level at all, and the tempting workaround — treating such a stub as its own module — silently changes the granularity of the result.
Membership
- Edges to stubs are kept; the internal-only view is obtained by filtering stubs out at analysis time — uniformly, for types and modules alike. That is what
--internal-onlydoes. - Membership is decided by a whitelist of corpus-declared ids built in a first pass — never by package or name prefix. Spoon in noClasspath mode invents plausible FQNs, and a prefix filter would launder them into facts.
In each rendering
| Rendering | How a stub appears |
|---|---|
analyze node lists |
external (stub) |
| DOT, PlantUML | dashed and grey node; <<stub>> stereotype in PlantUML |
| City | Building.isStub / District.isStub; a stub carries no anchor, so loc is unmeasured |
| Navigator | NavNode.isStub |
| Domain facts | no dossier is emitted for a stub type; external: true on the facts that reach one |
Why stubs rather than dropped edges: Extracting without compiling.