Documentation
¶
Overview ¶
Package codegen lowers a parsed gsx AST to Go source (.x.go) targeting the gsx runtime.
It handles components (inline params + receiver/method components), pass-through Go (GoChunks: types/helpers), static markup, control flow (if/for/switch, fragments), context-aware attributes (static/bool/expr, composable class, element spread, conditional), child-component invocation with props/{children}/named slots + explicit attribute forwarding, and type-aware interpolation resolved by go/types in the component's scope. Used params bind to same-named locals so interpolation expressions emit VERBATIM (e.g. {user.Name} -> gw.Text(user.Name) after `user := p.User`). A `(T, error)` value auto-unwraps (the error propagates out of Render). The `|>` pipeline lowers to nested filter calls in every interpolation context (text/attr/<style>/<script>/JS-attr). Escaping is context-aware (HTML/attr/URL/JS-JSON; CSS value-filtered) with typed gsx.Raw* opt-outs.
Index ¶
- Constants
- Variables
- func GenerateDirs(moduleRoot string, dirs []string, opts Options, override map[string][]byte) (map[string]DirResult, error)
- func ModulePathFromGoMod(data []byte) string
- func ProjectLoadCalls() uint64
- func ResolveFilters(dir string, filterPkgs []string, aliases []FilterAlias, ...) ([]FilterInfo, []RendererInfo, error)
- func ResolveFunctions(opts Options) ([]FilterInfo, []RendererInfo, error)
- func ResolveGoWorkFile(moduleRoot string) (string, error)
- func SharedWorldBackedgeFallbacks() int64
- func SharedWorldCoverageFallbacks() int64
- func SharedWorldFastPaths() int64
- func SharedWorldHits() int64
- func SharedWorldIneligibleModules() int64
- func SharedWorldLoads() int64
- func SharedWorldPreloadFallbacks() int64
- func ValidateClassMerger(dir string, ref *ClassMergerRef) error
- func Version() string
- type Bundle
- type ClassMergerRef
- type ComponentCallFact
- type ComponentDeclKey
- type ComponentParamDeclFact
- type ComponentParamFact
- type ComponentParamRefFact
- type ComponentParamRole
- type DirOptions
- type DirResult
- type ExportedSymbol
- type FilterAlias
- type FilterCandidate
- type FilterInfo
- type GoCommandContext
- type MissingImport
- type Module
- func (m *Module) AnalyzeEphemeral(dir, absPath string, src []byte) (*PackageResult, error)
- func (m *Module) ClearOverride(absPath string) ([]string, error)
- func (m *Module) Dependents(dir string) []string
- func (m *Module) Generate(dir string) (map[string][]byte, []diag.Diagnostic, error)
- func (m *Module) GoPackageIndex(dir string) (*sourceintel.Index, *types.Package, error)
- func (m *Module) GoWorkFile() (string, error)
- func (m *Module) ImportablePackageNames(dir string) []PackageName
- func (m *Module) Invalidate(dirs ...string)
- func (m *Module) Package(dir string) (*PackageResult, error)
- func (m *Module) PackageExportedSymbols(importPath string) []ExportedSymbol
- func (m *Module) RefreshDiskSources(dirs ...string) error
- func (m *Module) RefreshDiskSourcesAndInvalidate(dirs ...string) ([]string, RefreshVerdict, error)
- func (m *Module) RefreshGoSourcesAndInvalidate(dirs ...string) ([]string, RefreshVerdict, error)
- func (m *Module) ResolveImportCandidates(dir, name, symbol string) []string
- func (m *Module) SetOverride(absPath string, src []byte) []string
- func (m *Module) SymbolGraph(gsxDirs []string) (*sourceintel.SymbolGraph, error)
- func (m *Module) TryAnalyzeEphemeral(dir, absPath string, src []byte) (*PackageResult, bool, error)
- func (m *Module) UnusedImports(dir string) (map[string][]UnusedImport, []diag.Diagnostic, error)
- func (m *Module) ValidateConfiguredMergers() error
- type Options
- type PackageName
- type PackageResult
- type RefreshVerdict
- type RendererAlias
- type RendererInfo
- type SigTypeRef
- type SymbolKind
- type UnusedImport
Constants ¶
const StdImportPath = stdImportPath
StdImportPath is the gsx built-in filter package. Re-exported from the internal stdImportPath constant so the public gen package (and external callers such as gsxplayground) can reference it without coupling to the internal filters.go symbol.
Variables ¶
var ErrUncacheableGoContext = errors.New("codegen: Go command context is not persistently cacheable")
ErrUncacheableGoContext marks a valid Go command context whose semantic inputs cannot be represented by the persistent generator cache. Analysis may still use the context; callers should bypass only the cache.
Functions ¶
func GenerateDirs ¶
func GenerateDirs(moduleRoot string, dirs []string, opts Options, override map[string][]byte) (map[string]DirResult, error)
GenerateDirs opens a fresh Module rooted at moduleRoot, applies any override bytes, and calls Module.Generate on each dir. opts carries the codegen knobs; GenerateDirs fills opts.ModuleRoot from moduleRoot and derives opts.ModulePath from go.mod only when the caller left it empty (callers that already know the module path pass it to skip the re-read). On a hard (non-diagnostic) error it returns immediately; otherwise each dir's result accumulates in the returned map, keyed by the same dir strings passed in. override maps absolute .gsx paths to in-memory source bytes; pass nil when no overrides are needed.
func ModulePathFromGoMod ¶
ModulePathFromGoMod returns the module path declared in go.mod content, or "" if the content has no module directive. It delegates to modfile.ModulePath, which correctly handles inline comments (module x // c) and quoted module paths (module "x") — both of which a naive strings.TrimPrefix(line, "module ") mishandles. The module path is load-bearing for computeKey, so correctness here matters for incremental-cache invalidation.
func ProjectLoadCalls ¶
func ProjectLoadCalls() uint64
ProjectLoadCalls returns the process-wide count of packages.Load invocations issued by internal/codegen.
func ResolveFilters ¶
func ResolveFilters(dir string, filterPkgs []string, aliases []FilterAlias, renderers []RendererAlias) ([]FilterInfo, []RendererInfo, error)
ResolveFilters harvests the filter packages (in order, last-wins) plus the explicit WithFilter aliases (appended after, in option order) and the registered [renderers] (last-wins per TypeKey), all from the ONE packages.Load harvestFilters performs — renderer package paths ride the same load as the filter packages (see harvestFilters's doc comment), so a caller needing both must pass renderers here rather than issue a second, redundant load. Returns the filter table sorted by Name (recording which earlier same-named filters each winner shadows) and the renderer table sorted by TypeKey. An empty filterPkgs defaults to [stdImportPath], matching GenerateDirs. dir anchors the go/packages load against the module's go.mod.
func ResolveFunctions ¶
func ResolveFunctions(opts Options) ([]FilterInfo, []RendererInfo, error)
ResolveFunctions resolves the configured filter and renderer info through a Module. Unlike ResolveFilters, this entry point understands module-local GSX renderer packages and therefore does not require generated .x.go declarations to exist. The Module's external importer is loaded once and reused by both the filter harvest and local renderer declaration resolver.
func ResolveGoWorkFile ¶
ResolveGoWorkFile captures the Go command universe that a newly opened Module at moduleRoot would use and returns its exact resolved workspace file. This is intentionally a real Go environment query: filesystem walks cannot account for GOENV-persisted GOWORK settings.
func SharedWorldBackedgeFallbacks ¶
func SharedWorldBackedgeFallbacks() int64
SharedWorldBackedgeFallbacks returns the process-wide count of Modules returned to the full per-Module load because a world's closure re-entered their main module (see sharedWorld.mainModuleBackedge). Mirrors ProjectLoadCalls and SharedWorldLoads: a back-edging configuration must never be served silently, because the full load is the path that turns it into the hard configuration error. Consuming tests, all in internal/codegen: TestConfiguredExternalBackedgeIsHardConfigurationError (external_backedge_test.go) and TestSharedWorldExternalConfigBackedgeFallsBack (sharedworld_configured_test.go).
func SharedWorldCoverageFallbacks ¶
func SharedWorldCoverageFallbacks() int64
SharedWorldCoverageFallbacks returns the process-wide count of Modules returned to the full load because the world did not carry types the project half references — in practice exactly one shape: a Go or `.gsx` file importing a package outside the configured closure. It is the post-load half of the eligibility rule, the half that costs three loads to reach, which is why the verdict is remembered per Module (see SharedWorldPreloadFallbacks).
It does NOT count broken dependencies, and no wording here should imply it does — the adversarial review's finding was that go/packages materializes a non-nil (empty, error-carrying) *types.Package for a broken root, so `world.types[p] != nil` passes and this check never fires for one. That shape is handled at admission instead: loadSharedWorld refuses to publish an unhealthy world, so a broken dependency is served loudly and reloaded every cycle until it is fixed, rather than being counted here.
func SharedWorldFastPaths ¶
func SharedWorldFastPaths() int64
SharedWorldFastPaths returns the process-wide count of externalImporter resolutions served by the shared world: the project half plus the world's synthetic entries, with no full-mode per-Module load.
func SharedWorldHits ¶
func SharedWorldHits() int64
SharedWorldHits returns the process-wide count of loadSharedWorld calls served from the cache (a fresh entry already keyed for this closure), the complement of SharedWorldLoads: every loadSharedWorld call is either a load or a hit, never both. It is the process-cache payoff the shared-world design exists to prove — see gen.TestWatchSession_ConfiguredModuleWorldBudget, which opens a second Module over the same root and configuration and asserts this counter moves while SharedWorldLoads does not.
func SharedWorldIneligibleModules ¶
func SharedWorldIneligibleModules() int64
SharedWorldIneligibleModules returns the process-wide count of Modules whose configuration cannot be composed into one world (per-dir class mergers or per-dir non-std filter packages). They take the single full-mode load directly, without paying for a world first.
func SharedWorldLoads ¶
func SharedWorldLoads() int64
SharedWorldLoads returns the process-wide count of times loadSharedWorld actually issued a packages.Load for a shared external world's closure — a cold miss (a new key: a new configuration, or a changed set of external packages the project references) or a stale-freshness reload after a module-owned file the world stamped changed on disk. Only EXTERNAL code is ever stamped: main-module code does not enter a world, so no edit inside the project — including an edit to a class merger the project owns — can move this counter. It does not count a Module's ordinary project-half reload (see ProjectLoadCalls), which fires on every authored .go edit.
Tests use the distinction to pin the freshness design's claim: a .go edit anywhere in the project must leave this counter alone — see gen/watch_sharedworld_test.go (including the merger-edit pin) and gen.TestWatchSession_ConfiguredModuleWorldBudget.
func SharedWorldPreloadFallbacks ¶
func SharedWorldPreloadFallbacks() int64
SharedWorldPreloadFallbacks returns the process-wide count of Modules that took the single full-mode load without touching a world at all: a manifest LoadRoot outside the configured closure (decided before any load), or a Module already known unservable from an earlier analysis. This is the cost-free refusal — exactly the one load the pre-shared-world code paid.
func ValidateClassMerger ¶
func ValidateClassMerger(dir string, ref *ClassMergerRef) error
ValidateClassMerger type-checks ref.PkgPath and verifies ref.FuncName names an exported package-level object whose type is exactly func([]string) string. Returns a clear, user-facing error otherwise (missing symbol, or wrong signature with a pointer at the wrapper idiom).
This opens its OWN throwaway Module scoped to just ref, so its composed shared-world closure can be narrower than a caller's real, fully-configured Module — see ValidateConfiguredMergers above for the caller that already holds one. Standalone callers with no Module of their own (tests; any future caller that only has a dir and a ref) should still use this. Do NOT call this from codegen.Open: that path is shared by the LSP and fmt, which must not pay a packages.Load per-Open or fail on merger config.
Types ¶
type Bundle ¶
type Bundle struct {
// contains filtered or unexported fields
}
Bundle carries a prebuilt external importer and filter table so the Module can type-check skeletons with no `go list`/packages.Load. A WASM build (browser, no toolchain) constructs a Bundle once via NewCachedResolver/NewCachedResolverFromTypes and injects it through Options.Bundle. Passive data — it resolves nothing itself. The zero value is invalid.
func NewCachedResolver ¶
func NewCachedResolver(moduleDir string, filterPkgs []string, aliases []FilterAlias, allowImports []string) (*Bundle, error)
NewCachedResolver is the public constructor for Bundle. It loads filterPkgs (plus "github.com/gsxhq/gsx" and allowImports) once from moduleDir and returns a Bundle ready for in-process generation with no per-render subprocess.
func NewCachedResolverFromTypes ¶
func NewCachedResolverFromTypes(pkgs map[string]*types.Package, sizes types.Sizes, goVersion string, filterPkgs []string, aliases []FilterAlias) (*Bundle, error)
NewCachedResolverFromTypes builds a Bundle from already-loaded packages (e.g. reconstructed from a typebundle) with NO packages.Load and NO subprocess. pkgs maps import path -> *types.Package and MUST include the gsx runtime, every filterPkg, and every import a generated snippet references. Empty filterPkgs defaults to the built-in std filter package.
type ClassMergerRef ¶
ClassMergerRef names the configured class merger: an exported package-level identifier (func decl or var of func type) whose type is exactly func([]string) string. Codegen emits a direct reference _gsxcm.<FuncName>.
type ComponentCallFact ¶
type ComponentCallFact struct {
Target types.Object
TargetOrigin types.Object
TargetPackage string
TargetKey string
Signature *types.Signature
Params map[gsxast.Attr]ComponentParamFact
TargetDecls []sourceintel.VersionedSpan
ParamDecls map[int][]sourceintel.VersionedSpan
TargetPresentation string
}
ComponentCallFact is the retained semantic identity of one successfully planned markup call. Params contains only attribute names that semantically reference a callable parameter: exact ordinary bindings and explicit lowercase attrs contributors. Fallthrough attribute names are deliberately absent even though their values feed the attrs bag.
PackageResult owns this map and its nested maps; LSP consumers treat them as immutable snapshots, like the retained go/types objects alongside them.
type ComponentDeclKey ¶
type ComponentParamDeclFact ¶
type ComponentParamDeclFact struct {
PackagePath string
ComponentKey string
Ordinal int
Name string
Role ComponentParamRole
Origin *types.Var
Decls []token.Position
BlockedNames []string
}
ComponentParamDeclFact is one semantically validated GSX component parameter family. PackagePath, ComponentKey, and Ordinal form its stable identity. Decls contains the exact authored name position for every equivalent build-tag variant. BlockedNames is the union of typed names whose scopes would collide with a renamed parameter in any variant.
type ComponentParamFact ¶
type ComponentParamFact struct {
Var *types.Var
Origin *types.Var
Name string
Ordinal int
Role ComponentParamRole
}
ComponentParamFact identifies the exact callable parameter bound by one authored markup attribute. Var belongs to the instantiated signature used at this call; Origin is the declaration identity retained across generic instantiation. Ordinal is stable within that origin signature.
type ComponentParamRefFact ¶
type ComponentParamRefFact struct {
PackagePath string
ComponentKey string
Ordinal int
Name string
Role ComponentParamRole
Origin *types.Var
Ref token.Position
BlockedNames []string
}
ComponentParamRefFact is one exact authored parameter reference: either an invocation attribute bound by the component planner or a semantic use inside a GSX component body. Unmatched fallthrough attrs and mere name matches are absent from Ref; invocation refs carry their call's other authored attribute names in BlockedNames so a rename cannot silently change planner binding.
type ComponentParamRole ¶
type ComponentParamRole uint8
ComponentParamRole is the semantic role of an authored callable parameter. It is published for retained tooling facts only; generated code continues to consume the private componentSignatureModel role directly.
const ( ComponentParamOrdinary ComponentParamRole = iota ComponentParamAttrs ComponentParamChildren ComponentParamGoOnlyVariadic )
type DirOptions ¶
type DirOptions struct {
FilterPkgs []string // nil = inherit Options.FilterPkgs
ClassMerger *ClassMergerRef // nil = inherit Options.ClassMerger
Classifier *attrclass.Classifier // nil = inherit Options.Classifier
// URLPresets names the url-attribute presets in effect for this dir (nil =
// inherit Options.URLPresets). It is the string-identity companion to
// Classifier: the Classifier carries the EXPANDED rules a preset contributes,
// but the preset NAMES (e.g. "htmx") are retained separately here so a consumer
// like the LSP can answer "is the htmx preset on?" without reverse-engineering
// it from rule contents. See Module.urlPresetsFor.
URLPresets []string
// VerbatimTags, when non-nil, overrides Options.VerbatimTags for this dir's
// tag-shape serialization (nil = inherit Options.VerbatimTags).
VerbatimTags *bool
}
DirOptions overrides Module-level options for a single package dir. The zero value means "inherit from Options".
FilterPkgs, when non-nil, replaces Options.FilterPkgs for this dir's filter table. It must name only packages the Module already loaded — i.e. packages reachable from Options.FilterPkgs, Options.LoadPkgs, or the module's own "./..." — because the table is harvested from the loaded types with NO packages.Load. Naming an unloaded package is a hard error, never an empty table: a silently-empty table would make a "this filter must be rejected" test pass for the wrong reason.
type DirResult ¶
type DirResult struct {
Files map[string][]byte // keyed by .gsx path (same as Module.Generate)
Diags []diag.Diagnostic
}
DirResult is the per-directory outcome of GenerateDirs.
type ExportedSymbol ¶
type ExportedSymbol struct {
Name string
Kind SymbolKind
Detail string
TagCallable bool
}
ExportedSymbol is one exported top-level declaration of a package, described by value (name, coarse kind, formatted type/signature) so the caller never touches a graph *types.Object outside the analysis lock.
TagCallable reports whether this declaration could be written as a gsx TAG (`<pkg.Name/>`) — tagcallable.IsCandidate, the same completion-grade predicate internal/lsp applies when scanning an ALREADY-imported package's scope. It is carried on every symbol rather than served by a separate enumeration so both the Go-expression member surface (`pkg.▮`, which wants every export) and the tag surface (`<pkg.▮`, which wants only these) read one answer computed once, inside the analysis lock, from real type objects.
type FilterAlias ¶
type FilterAlias struct {
Name string // template-level filter name, e.g. "url"
PkgPath string // target package import path, e.g. "example.com/structpages"
FuncName string // exported Go func name in that package, e.g. "URLFor"
}
FilterAlias is one explicit filter registration from gen.WithFilter: the short template Name, and the resolved Go target (PkgPath + FuncName) reflected from the registered function value. Aliases are harvested AFTER whole-package harvests in option order, participating in the same last-wins table.
type FilterCandidate ¶
type FilterCandidate struct {
Name string // template name, e.g. "upper"
Pkg string // winning package import path
Func string // exported Go func name, e.g. "Upper"
WantsCtx bool
// Pos is the target func's ALREADY-RESOLVED declaration position (see
// filterEntry.pos for why a resolved Position, not a raw token.Pos, is
// what makes two independent harvests of the same filter comparable). The
// zero Position (Pos.IsValid() false) means no Fset was available at the
// harvest site that produced this candidate (e.g. the WASM/typebundle
// path): the LSP completion path (Module-backed) always has one.
Pos token.Position
}
FilterCandidate is one pipeline-filter completion candidate, from the dir's resolved filter table.
type FilterInfo ¶
type FilterInfo struct {
Name string // template name (first-rune-lowered), e.g. "upper"
Pkg string // winning package import path
Func string // exported Go func name, e.g. "Upper"
Ctx bool // first parameter is context.Context (gsx injects ambient ctx)
Shadows []string // import paths of EARLIER same-named filters this one overrides
}
FilterInfo describes one resolved pipeline filter, for `gsx info`.
type GoCommandContext ¶
type GoCommandContext struct {
// contains filtered or unexported fields
}
GoCommandContext is one immutable snapshot of the Go command boundary used by both source selection and callers that must key work performed before a Module's first packages.Load. Its fields are deliberately private: consumers can run the captured command or obtain its canonical cache fingerprint, but cannot construct a partial environment.
func CaptureGoCommandContext ¶
func CaptureGoCommandContext(moduleRoot string) *GoCommandContext
CaptureGoCommandContext freezes exactly the environment and Go launcher a normal Module will use. Capture errors are retained rather than returned so syntax-only Open callers remain usable; Run and CacheFingerprint surface the same error when semantic work is requested.
func (*GoCommandContext) CacheFingerprint ¶
func (context *GoCommandContext) CacheFingerprint() (string, error)
CacheFingerprint returns a canonical digest of the frozen effective Go environment, selected Go launcher bytes, and exact selected compiler path and bytes. The environment excludes only GOGCCFLAGS: cmd/go documents it as an output-only variable that cannot be modified, and its derived value embeds a fresh per-command temporary path. Its actual inputs (CC, CGO_*, GOOS, GOARCH, and toolchain identity) remain in the fingerprint. Active workspaces are intentionally uncacheable: their used-module source lies outside the module-root source manifest and therefore cannot be represented by the current persistent key.
func (*GoCommandContext) Run ¶
func (context *GoCommandContext) Run(args ...string) ([]byte, error)
Run executes the captured Go command under the captured environment. It is the only supported path for pre-analysis Go metadata queries that must agree with a Module created from this context.
func (*GoCommandContext) ValidateCurrent ¶
func (context *GoCommandContext) ValidateCurrent() error
ValidateCurrent proves that the Go launcher, compiler, and frozen selection environment still match this context. It performs exact file inspection and starts no subprocesses.
type MissingImport ¶
MissingImport is a qualifier used in a .gsx file that resolves to nothing: no local, no import. Name is the qualifier ("fmt"), Symbol is the selector on it ("Sprintf") — Symbol is what lets an ambiguous name like `rand` be resolved to the one candidate that actually exports it. Pos is the qualifier's position in the .gsx source.
Deliberately UNRESOLVED: turning a Name into an import path may read package export data, which must never happen on the Package() hot path. The LSP resolves it in a user-triggered code-action handler via Module.ResolveImportCandidates.
type Module ¶
type Module struct {
// contains filtered or unexported fields
}
Module is a warm, in-process analysis graph for one module root. It is the single analysis core consumed by generate, watch, the LSP, fmt, and the playground.
Concurrency contract (Phase 1): analysisMu serializes the three top-level analysis entry points — Package, Generate, and typesPackage — so that only one analysis runs on a given Module at a time. mu guards the overrides, ext, pkgTypes, and targetDeclTypes map fields and is acquired independently of analysisMu (it is also acquired inside externalImporter and typesPackageWith, which are called from within a held analysisMu). ResolveImportCandidates is a fourth top-level analysis entry point: its complete authoritative enumeration and optional source recheck are serialized by analysisMu too. The internal recursive path (typesPackageWith → analyze → moduleImporter.Import → typesPackageWith) does NOT acquire analysisMu — those functions run within a held analysisMu and re-acquiring would deadlock. True fine-grained concurrent analysis (multiple roots in parallel or partial invalidation) is deferred to Phase 2.
TryAnalyzeEphemeral is a non-blocking variant of the AnalyzeEphemeral entry point: it acquires analysisMu via TryLock and returns acquired=false rather than waiting when another entry point holds it. It composes with this contract — the lock still serializes every entry point and stays non-reentrant; TryLock only changes wait-vs-decline, never the invariant.
Cache invalidation: SetOverride and ClearOverride compare against the frozen saved-source state beneath the buffer and return the exact sorted affected closure for effective byte or membership transitions. Package and Generate call applyDirty at the start of each run: it drops that reverse-reflexive-transitive closure from both type-package caches, then clears dirty. This means only the affected subgraph is re-type-checked; unchanged packages and the warm ext importer stay cached. A configured module-local renderer dir is the intentional exception: its result classification is module-wide, so its declaration/table caches and every retained package analysis are dropped while the ext importer stays warm. RefreshDiskSources is the explicit saved-source transition for watch events; RefreshDiskSourcesAndInvalidate is the atomic saved-source plus retained-fact transition used by concurrent callers such as the LSP. Invalidate is the public entry point for callers that only need to evict a directory without changing the source snapshot.
FileSet: the Module uses ONE *token.FileSet (m.fset) for its whole lifetime, covering BOTH the external packages.Load AND every project analyze() call. So every type-object position — package A, sibling B, external dep — resolves unambiguously against the single fset, exactly like the Module's own packages.Load fset. This is what makes cross-package go-to-def (the expression path) resolve a sibling's obj.Pos() to the sibling's source rather than a random spot in the importing package.
Growth bounding: because the fset is Module-lifetime, re-analyzing a project package each edit (applyDirty clears pkgTypes → re-parse into the same fset) accumulates fset entries (token.FileSet is append-only). maybeRebuildFset (called at the start of Package/Generate) bounds this: when project re-parse growth (fset.Base() - fsetBaseline) exceeds fsetRebuildBytes, rebuildFset replaces the fset AND drops ext+pkgTypes+targetDeclTypes+pkgResults TOGETHER, so nothing live holds positions into the discarded fset. The import graph, dirty set, and overrides survive (path/content-based). Do NOT rebuild the fset per edit, and never reset the fset while keeping ext, pkgTypes, targetDeclTypes, or pkgResults: that would orphan their positions.
func Open ¶
Open constructs a Module. It captures the normal-mode Go environment but does not load packages; semantic package analysis remains lazy.
func (*Module) AnalyzeEphemeral ¶
func (m *Module) AnalyzeEphemeral(dir, absPath string, src []byte) (*PackageResult, error)
AnalyzeEphemeral runs one warm analysis of dir with absPath's source replaced by src, WITHOUT recording the result: pkgResults is never written, and the pkgTypes/targetDeclProvenance entries analyze writes for dir are snapshotted and restored afterward. Dependency packages analyzed (and cached) along the way use their real sources — that warmth is shared and desirable. Serialized under analysisMu like Package/Generate. Source-level breakage returns a diagnostics-only PackageResult (nil Info/Types), mirroring Package's shell semantics.
Cache-write audit (analyze's full body, module_importer.go:1032+, and every function it calls with the analyzed dir): the ONLY module caches keyed by dir that analyze writes from the patched source are pkgTypes[dir] (line ~1501) and targetDeclProvenance[dir] (line ~1506); both are snapshot/restored below. goPkgAnalyses is keyed only by Go-only dirs (goPackageAnalysisWith rejects a gsx dir outright), so the analyzed dir never has an entry; the entries its Go-only dependencies get are checked from their own real sources, which the patch never touches — shared warmth, like the dependency packages below. targetDeclTypes[dir] is NOT written for the analyzed dir — analyze marks it loading in the componentTargetImporter, so a recursive targetDeclarationPackage(dir) cycle-errors before its write. The import-graph writes for dir — recordImports (shipping) and recordTargetImports (exact target, via discoverComponentTargets) — replace dir's forward edges and its reverse edges with the SAME set the live buffer records: the repair only patches bytes at the cursor, so the import specs are byte-identical and the rewrite is idempotent, exactly as the shipping-graph reasoning already accepts (recordImports' own doc: "the edited package always re-analyzes in the same turn"). sourceIndexBuildCount++ is a monotonic observability counter, not a per-dir correctness cache. All other dir-keyed writes (dirFuncTbls, typeEnvironment, configuredDeclTypes, recordSourceDeclImports) key on config/import-derived dirs whose real sources the overlay never touches — shared warmth, not corruption.
func (*Module) ClearOverride ¶
ClearOverride always ends buffer authority and exposes its exact saved state: present, absent, or unreadable. It returns the pre-clear affected closure even when unreadability also returns an operational error; callers must evict that stale scope rather than treating the error as a rollback signal.
func (*Module) Dependents ¶
Dependents returns the GSX-owned projection of the reverse-reflexive- transitive closure of dir over the import graph. Internal invalidation keeps every Go-only intermediary in the graph, but watch must regenerate only authoritative GSX source dirs. The seed is always retained so a changed or newly created GSX dir is safe before the next inventory reload. Before a cold inventory exists (Bundle and graph-only tests), the complete closure is returned because there is no authoritative source classification to apply.
Threading: like Invalidate, Dependents takes m.mu but is NOT serialized by analysisMu, so callers must not invoke it concurrently with an in-flight Package/Generate on the same Module (the recursive importer reads the graph under analysisMu without m.mu). The watch loop is single-goroutine, so this holds.
func (*Module) Generate ¶
Generate runs analysis on dir and emits a .x.go for every .gsx file in the package. It returns the generated bytes keyed by the gsx file's absolute path, any diagnostics (including script-resolution errors from analyze), and a hard error only when analysis itself fails (parse error, load error, etc.). Emit errors (per-component) are soft: they surface as diagnostics in the returned slice and the file is omitted from out.
Type-error semantics: a package that fails to type-check emits NOTHING (the emit loop below is gated on len(a.typeErrs)==0), and the type-error diagnostics collected by checkSkeletonPackage are surfaced via the returned slice (analyze adds them to the bag). The golden corpus test drives this path directly, so type-error corpus cases are validated byte-for-byte.
func (*Module) GoPackageIndex ¶
GoPackageIndex returns the identity-mapped symbol index of one Go-only package (see goPackageAnalysisWith) together with the package it was checked into. Type errors are not fatal: whatever resolved is indexed.
func (*Module) GoWorkFile ¶
GoWorkFile returns the exact workspace file frozen into this Module's Go command universe. An empty result means the authoritative GOWORK value is "off".
func (*Module) ImportablePackageNames ¶
func (m *Module) ImportablePackageNames(dir string) []PackageName
ImportablePackageNames returns every package that dir could import: its declared name and import path, from the loaded dependency graph and the baked stdlib table, filtered by Go's internal-visibility rule (stdpath.InternalVisible) for dir and excluding dir's own package (a self-import would be invalid Go).
User-triggered slow path (auto-import package-name completion), serialized on analysisMu like ResolveImportCandidates. All lookups, never a filesystem scan. The result may be large (~1000 for a real module); the caller prefix-filters.
func (*Module) Invalidate ¶
Invalidate drops the reverse-reflexive-transitive closure of dirs (the dirs plus every module-local package that transitively imports them) from pkgTypes and pkgResults, so each is re-type-checked from current retained source on the next use. Graph edges are retained (refreshed on re-analysis). Everything outside the closure stays warm, except that a configured module-local renderer seed invalidates every retained package classification while preserving the external importer/filter state. This supersedes the coarse whole-cache reset.
Threading: Invalidate takes m.mu but is NOT serialized by analysisMu, so callers must not invoke it concurrently with an in-flight Package/Generate on the same Module (the recursive importer reads pkgTypes under analysisMu without m.mu). The LSP never calls it; the normal incremental path is SetOverride → applyDirty.
func (*Module) Package ¶
func (m *Module) Package(dir string) (*PackageResult, error)
Package returns the full retained analysis for a single gsx package dir, without codegen (Files stays empty; Generate fills it). It populates the FileSets, *types.Info, *types.Package, ExprMap, GSXFiles, and the cross/nav indexes used by the LSP.
func (*Module) PackageExportedSymbols ¶
func (m *Module) PackageExportedSymbols(importPath string) []ExportedSymbol
PackageExportedSymbols returns the exported top-level declarations of the package at importPath — for auto-import completion of an UNIMPORTED qualifier (`fmt.▮` where fmt is not yet imported). Like ResolveImportCandidates it is a user-triggered slow path (never the Package() hot path) and serializes the whole read on analysisMu against one analysis snapshot: candidate names, package identities, scopes, and the shared FileSet must all come from the same generation.
The symbols come from the LOADED module dependency graph — a COMPLETE *types.Package whose scope is populated even though the asking .gsx file does not import it (the graph is packages.Load's full transitive closure, a superset of what any single file imports) — or, for a std package the graph never reached, from cached gc export data (the one expensive branch, ~46–78ms cold per distinct package, ~90µs warm thereafter). A main-module source package resolves through the source declaration resolver. An unknown/unloadable/incomplete path returns nil.
Detail is formatted with every package qualified by its own name (no "current package" here, since the asking file does not import this one), matching how packageMemberItems renders an imported package's members.
func (*Module) RefreshDiskSources ¶
RefreshDiskSources refreshes the complete saved .gsx membership and package/import facts for dirs. It is the disk counterpart to SetOverride and must run before Invalidate in a long-lived normal-mode caller such as watch. Every create, write, rename, and remove follows this same exact directory scan; callers do not classify events into "body" versus "dependency" edits.
A body-only change preserves the cold importer. Package membership/clause changes, or an import addition absent from the published importer, mark the source inventory for an atomic FileSet/importer rebuild at the next analysis. Authored-Go transitions committed by the refresh are handled the same way regardless of caller: an existing active file edit refreshes the retained syntax in place, and anything the bounded fast path cannot prove safe schedules the authoritative cmd/go reload (see refreshDiskSources). RefreshDiskSources serializes the refresh itself against analysis. Callers that also need invalidation should use RefreshDiskSourcesAndInvalidate so no analysis can observe refreshed saved bytes through stale retained facts.
func (*Module) RefreshDiskSourcesAndInvalidate ¶
func (m *Module) RefreshDiskSourcesAndInvalidate(dirs ...string) ([]string, RefreshVerdict, error)
RefreshDiskSourcesAndInvalidate atomically refreshes the complete saved-source inventory for dirs, computes their exact retained reverse closure, and evicts that closure while analysis is excluded. This is the LSP watched-file transition: returning affected dirs from the same critical section prevents a concurrent Package call from republishing facts from the pre-refresh view.
func (*Module) RefreshGoSourcesAndInvalidate ¶
func (m *Module) RefreshGoSourcesAndInvalidate(dirs ...string) ([]string, RefreshVerdict, error)
RefreshGoSourcesAndInvalidate records saved authored-Go changes, returns the GSX projection of their pre-change reverse closure, and — via refreshDiskSources — either refreshes retained syntax in place or schedules an authoritative cmd/go reload for the next analysis. Computing the closure before the refresh preserves importer edges that the cache reset discards. The verdict is the same one refreshDiskSources published, returned from the same call for the same reason RefreshDiskSourcesAndInvalidate returns it: a later separate read could observe an unrelated concurrent transition.
The reload is deliberately conservative: cmd/go remains the authority for build constraints, cgo, package membership, and the effective Go command environment. Callers can therefore regenerate only the returned GSX dirs without approximating source selection or rewriting unrelated output.
Two transitions cannot be projected through the retained graph and fall back to regenerating every authoritative GSX dir:
- a dir the cold inventory has never seen (a newly created package): a GSX package poisoned by importing the then-missing package recorded no edge, yet it is exactly the consumer this change repairs;
- no published inventory at all (before the first cold load, or after a failed reload): there is no authoritative GSX classification to project through, so the complete closure is returned unfiltered, mirroring Dependents' fallback.
func (*Module) ResolveImportCandidates ¶
ResolveImportCandidates maps an undefined qualifier to the import path(s) that could supply it, most-likely-first is NOT implied — the caller decides what to do with 0, 1, or many.
dir is the absolute directory of the .gsx package doing the asking (the LSP's planned Analyzer.ResolveImport(dir, name, symbol) surface lines up with this). It is resolved to that package's own import path via importPathForDir, then used to apply Go's internal-visibility rule (stdpath.InternalVisible) to every candidate from both sources below: a path with an "internal" component is offered only when dir's package is in the tree rooted at that component's parent. This is what lets a project's own myapp/internal/db be offered to myapp or myapp/views, while encoding/json/internal never is (no importer outside GOROOT is ever under "encoding/json"). If dir cannot be resolved to an import path (e.g. outside the module), importerPath is "", which InternalVisible treats like any other path not under the required prefix — conservative, not a special case.
Two sources, both lookups, never a filesystem scan:
- the module's dependency graph, which analyze already type-checked, giving each package's REAL declared name and a populated scope; and
- a baked stdlib name -> path table, for std packages the module does not already reach.
When more than one candidate survives, keep only those that actually export `symbol` — this is what collapses `rand` to math/rand/v2 for rand.IntN. A candidate already in the graph is checked for free via its scope; one known only from the table needs its export data, which the go/importer caches (~30-50ms cold, ~25us warm). If NO candidate exports the symbol (a typo, or an unloadable package), all candidates are kept: the caller then offers one quickfix each rather than guessing.
This is why it must never run on the Package() hot path. It is called only from user-triggered code-action handlers.
An unknown name returns nil. goimports would scan the module cache here — a measured 1.4s per unresolved identifier, which is the normal mid-typing state. We do not.
func (*Module) SetOverride ¶
SetOverride records one in-memory .gsx or .go source, shadowing the immutable saved state captured when buffer authority begins. It returns the exact sorted invalidation scope for an effective source transition; identical effective bytes return nil. Invalidation itself remains lazy until Package/Generate.
func (*Module) SymbolGraph ¶
func (m *Module) SymbolGraph(gsxDirs []string) (*sourceintel.SymbolGraph, error)
SymbolGraph merges the retained analysis of every listed gsx package dir (Package) with every reverse-dependency Go-only package (GoPackageIndex). Un-analyzable dirs are skipped (partial graph), matching find-references' historical tolerance. Returns an error only when nothing could be built.
Threading: SymbolGraph holds no lock of its own; each Package/GoPackageIndex call takes analysisMu independently, so a SetOverride landing between two of them yields a graph whose packages were analyzed at different source epochs. That is deliberate — holding analysisMu across the whole merge would block the editor for the length of a module-wide analysis — and it is detectable: every indexed file carries its SourceVersion, so a consumer answering against a buffer checks MatchesSource before publishing a span, exactly as it must for a graph that has simply gone stale since it was built.
func (*Module) TryAnalyzeEphemeral ¶
TryAnalyzeEphemeral is the non-blocking sibling of AnalyzeEphemeral. It attempts analysisMu.TryLock; if the lock is already held by an in-flight top-level entry point (a background Package/Generate, or another ephemeral run) it returns (nil, false, nil) immediately instead of blocking. On acquisition (acquired == true) it runs the identical body as AnalyzeEphemeral and returns the same (result, err) pair — when the Module is uncontended TryLock succeeds at once, so the caller sees no difference.
This is the insurance the LSP completion/nav handlers use unconditionally: they run inline on the single dispatch goroutine, so blocking on analysisMu behind a ~1 s background Package would stall the whole server. TryLock lets them fall back to a retained-snapshot answer (or reply empty/null) instead. TryLock composes cleanly with the concurrency contract above: analysisMu still serializes every top-level entry point and is still non-reentrant — TryAnalyzeEphemeral simply declines to enter rather than waiting, and the not-acquired path touches no analysisMu-guarded state at all.
func (*Module) UnusedImports ¶
func (m *Module) UnusedImports(dir string) (map[string][]UnusedImport, []diag.Diagnostic, error)
UnusedImports returns, per .gsx file (abs path) in dir, the imports the file declares but never references — determined syntactically from the skeleton, with NO type-checking and NO dependency resolution. Default imports whose path base is not referenced have their real package name resolved via a single cheap NeedName load before removal, so a package whose name differs from its path base (e.g. gopkg.in/yaml.v3 → "yaml") is handled correctly.
It also returns the Go parse diagnostics the skeletons produced, already positioned at their .gsx origin. They are diagnostics, not an error: a file whose Go does not parse simply keeps all its imports, and its siblings are still analyzed. The returned error stays reserved for faults that make the whole package unanalyzable (a gsx parse failure, an unloadable module), which callers must not present to the user as a Go diagnostic.
func (*Module) ValidateConfiguredMergers ¶
ValidateConfiguredMergers validates every class merger configured on an ALREADY-OPEN Module (the module-wide ClassMerger plus any PerDir override), against that Module's own composed shared-world closure — the one its later Generate calls will use. Prefer this over the package-level ValidateClassMerger for a caller (e.g. gen.prepareWatchSession) that already holds the fully-configured Module: a throwaway probe Module built from just a ClassMergerRef composes a NARROWER shared-world path set whenever the real Module also carries FilterPkgs/Aliases/Renderers/LoadPkgs, which mints a second, differently-keyed world at session startup instead of sharing the one this Module is about to load anyway — exactly the duplicate cold load gen.TestWatchSession_ConfiguredModuleWorldBudget pins against. The result is memoized on m (classMergersDone), so a later Generate's own defense-in-depth call is a no-op.
Holds analysisMu, like every other top-level entry point and like the package-level ValidateClassMerger below: validation resolves the merger through configuredSourcePackages, which reaches externalImporter and can therefore reach rebuildFset — the one operation that swaps m.fset and drops the cached importer, and which every analysis assumes is serialized against it.
In-package callers use the unexported form. Package/Generate/ analyzeEphemeralLocked already hold analysisMu when they do. GenerateDirs does not, and does not need to: it validates once on a Module it just opened, before any concurrent entry point can exist, on a single goroutine.
type Options ¶
type Options struct {
ModuleRoot string
ModulePath string
// GoCommandContext, when non-nil, supplies the immutable Go environment and
// launcher snapshot used by normal-mode source selection. Pre-analysis
// callers such as the persistent cache capture it once and use the same
// context for their metadata queries, preventing split build universes.
GoCommandContext *GoCommandContext
// SourceManifest, when non-nil, is the immutable sourceview already consumed
// by a pre-analysis cache metadata query. Normal codegen reuses that exact
// manifest rather than independently walking the module a second time.
SourceManifest *sourceview.Manifest
// SourceOnly makes in-memory .gsx overrides the complete package source
// universe. It is reserved for Bundle-backed virtual generation where no
// host filesystem source may participate.
SourceOnly bool
// FilterPkgs is the module-wide filter set: it is both loaded into the
// external importer AND harvested into the default filter table.
FilterPkgs []string
// LoadPkgs names extra packages to load into the external importer WITHOUT
// giving them filter semantics. It is the union half of the union/per-dir
// split: a caller that needs several dirs to see different filter tables
// lists every filter package here (one load) and narrows each dir's table
// via PerDir. A superset here is inert — it only makes more packages
// importable — whereas a superset in a dir's table silently widens the
// filter whitelist.
LoadPkgs []string
// PerDir maps a package dir to its option overrides. Keys are matched
// against the dir strings passed to Generate/Package (cleaned), and are
// also consulted for dirs reached transitively through imports, so an
// imported sibling package resolves its own filter table. Unsupported in
// Bundle mode (the Bundle carries exactly one prebuilt table).
PerDir map[string]DirOptions
Aliases []FilterAlias
// Renderers is the module-wide [renderers]/WithRenderer registration list:
// each entry is harvested alongside FilterPkgs/Aliases (one packages.Load,
// via harvestFilters) into the funcTables.renderers every dir's analyze
// consults. Unlike FilterPkgs, Renderers has no PerDir override — a
// registered renderer applies module-wide.
Renderers []RendererAlias
Classifier *attrclass.Classifier
// URLPresets names the module-wide url-attribute presets in effect (e.g.
// "htmx"). It is the string-identity companion to Classifier: Classifier
// carries the expanded rules; URLPresets retains the names so a consumer can
// tell WHICH presets are on (see Module.urlPresetsFor / PackageResult.URLPresets).
// A PerDir entry with non-nil URLPresets overrides this for that dir.
URLPresets []string
CSSMin func(string) (string, error) // custom static-CSS minifier (nil = built-in when CSSMinify)
JSMin func(string) (string, error) // custom static-JS minifier (nil = built-in when JSMinify)
// JSONMin minifies a JSON-shaped body (a data-island <script> and a
// JSON-shaped js`…` attribute value). It follows the JS gate: callers set it
// whenever JSMin's level is "full" (see gen's config.effectiveJSONMin), nil
// otherwise. This field is consulted by cascadeJS and minifyJSSegmentsHoley
// in jsmin to optimize JSON-valued attributes (htmx hx-vals/hx-headers/hx-vars).
JSONMin func(string) (string, error)
CSSMinify bool // minify static <style> CSS
JSMinify bool // minify static <script> JS
// VerbatimTags emits authored tag shapes verbatim instead of canonical
// serialization; gsx.toml `serialization = "verbatim"`.
VerbatimTags bool
// Bundle, when non-nil, supplies the external importer and filter table
// directly (a prebuilt Bundle) so the Module type-checks skeletons
// with NO packages.Load / `go list` — the mode a WASM build uses. The Module
// can additionally operate override-only when SourceOnly is set. Bundle mode
// is GENERATION-ONLY: the bundle's *types.Package values live in a foreign
// FileSet, so imported-object positions do not resolve against m.fset; use
// Generate, not Package, in this mode.
Bundle *Bundle
// ClassMerger, when non-nil, names an exported package-level func of type
// func([]string) string that codegen emits in place of gsx.DefaultClassMerge.
// Codegen imports the package under the reserved alias _gsxcm and emits
// _gsxcm.<FuncName> at every class merge site.
ClassMerger *ClassMergerRef
}
Options configures a Module. ModuleRoot is the absolute module root (dir containing go.mod); ModulePath is its declared module path (from go.mod).
type PackageName ¶
PackageName is one importable package: its declared name (the qualifier a file would use) and its import path.
type PackageResult ¶
type PackageResult struct {
Files map[string][]byte // .gsx path -> generated .x.go source
Diags []diag.Diagnostic // all diagnostics collected for this package
// Retained analysis for the language server (read-only; nil when the package
// failed before type-checking). The two FileSets are distinct: GSXFset is the
// gsx parse fset; Fset is the go/packages skeleton fset.
GSXFset *token.FileSet
Fset *token.FileSet
Info *types.Info
// PositionFor resolves a token.Pos that may belong to either this package's
// skeleton FileSet (Fset) or the process-shared external world's. The two
// reserve disjoint Pos ranges, so the owner is decided numerically; asking
// the wrong FileSet yields an invalid position, never a plausible wrong one.
// Imported-object positions (go-to-definition / hover / completion docs on
// e.g. a std filter) MUST resolve through this, not Fset. Nil only when the
// package failed before analysis.
//
// Both resolvers are closures over the FileSets THIS result was built from
// — never live Module state. A retained result therefore keeps resolving
// against its own generation after the Module rebuilds its fset (a live
// read raced rebuildFset and returned plausible wrong files; demonstrated
// in the adversarial review).
PositionFor func(token.Pos) token.Position
// PositionForPhysical is PositionFor without //line adjustment
// (FileSet.PositionFor(pos, false)) — for consumers that need the physical
// file of a generated-output position.
PositionForPhysical func(token.Pos) token.Position
// SourceIndex is the immutable authored-source semantic index harvested from
// Info. It shares PackageResult's snapshot lifetime and invalidation.
SourceIndex *sourceintel.Index
ExprMap map[gsxast.Node]goast.Expr
GSXFiles map[string]*gsxast.File
// ComponentCalls maps each successfully planned component element to its
// exact callable target and bound-parameter identities. It is the retained
// definition/hover surface for markup calls; consumers must not reconstruct
// these facts from tag spelling or a reconstructed callable shape.
ComponentCalls map[*gsxast.Element]ComponentCallFact
ComponentDecls map[ComponentDeclKey][]sourceintel.VersionedSpan
ComponentParamDecls []ComponentParamDeclFact
ComponentParamRefs []ComponentParamRefFact
// CtrlMap maps each control-flow node (ForMarkup/IfMarkup/GoBlock, and each
// value-form if condition's *ValueIf) to its
// skeleton clause position and smallest containing skeleton go/ast node.
// Used by the LSP to bridge a cursor in a for/if/goblock clause to the
// skeleton for go-to-definition on loop variables and condition identifiers.
CtrlMap map[gsxast.Node]ctrlRef
// SigTypes maps each component to the navigable spans in its signature —
// parameter types (e.g. `store.Comment` in `component C(c []store.Comment)`),
// type-parameter names and constraints, and a method receiver type — so the
// LSP can answer go-to-definition / hover on the identifiers inside them.
SigTypes map[*gsxast.Component][]SigTypeRef
// UnusedImports lists, per .gsx file path, the imports the file declares but
// does not use — safe to drop on format. Empty unless the package's ONLY type
// errors are unused-import errors (else removal is unsafe).
UnusedImports map[string][]UnusedImport
// MissingImports lists, per .gsx file path, the qualifiers the file uses that
// resolve to nothing — candidates for an added import. Unresolved by design;
// see MissingImport.
MissingImports map[string][]MissingImport
// Filters is the sorted list of pipeline-filter completion candidates from
// the package's resolved filter table.
Filters []FilterCandidate
// URLPresets names the url-attribute presets in effect for this package's
// dir (e.g. "htmx"). It carries the preset NAMES (not the expanded classifier
// rules) so the LSP can offer preset-specific attribute completions — the
// htmx hx-* attributes when "htmx" is present — without inferring the preset
// from classifier rule contents. See Module.urlPresetsFor.
URLPresets []string
// Types is the analyzed package's go/types.Package, retained for the LSP
// (e.g. hover's qualifier). nil when the package failed before type-checking.
Types *types.Package
}
PackageResult is the per-package outcome of code generation.
type RefreshVerdict ¶
type RefreshVerdict struct {
WorldReloadPending bool
Reason sourceview.ReloadReason // ReloadGoSource for authored Go changes
Path string // representative file that forced the reload, module-relative; "" when unknown
}
RefreshVerdict reports whether a disk refresh left the Module's cold world pending an in-place reload, and — when so — a deterministic attribution a caller can surface to a developer. It is returned by value from the exact critical section that published the refresh (see refreshVerdictLocked): reading m.goSourceReload/m.sourceReloadReasons through a later, separate m.mu acquisition would risk attributing a concurrent unrelated transition (SetOverride/ClearOverride do not serialize against RefreshDiskSourcesAndInvalidate) to this call's refresh.
func (RefreshVerdict) Describe ¶
func (v RefreshVerdict) Describe() string
Describe renders the verdict as a short, human-readable reason suitable for console/panel output, e.g. "changed Go source dep/dep.go" or "new import outside the loaded world in page/page.gsx". It is "" when no reload is pending.
type RendererAlias ¶
RendererAlias is one [renderers] registration: the canonical registered type key ("pkgPath.TypeName", optionally *-prefixed for a pointer type) and the resolved Go target func. Duplicate TypeKeys are last-wins, like FilterAlias.
type RendererInfo ¶
type RendererInfo struct {
TypeKey string // registered type key ("pkgPath.TypeName", optionally *-prefixed)
Pkg string // renderer func's package import path
Func string // exported Go func name
HasErr bool // true when the renderer returns (R, error)
}
RendererInfo describes one resolved [renderers] registration, for `gsx info`. Unlike FilterInfo there is no Shadows: harvestRenderers keeps only the last-wins entry per TypeKey (see rendererTable), so an earlier registration for the same key leaves no trace to report.
type SigTypeRef ¶
SigTypeRef bridges one navigable identifier region in a component signature (a parameter type, method receiver type, type-parameter name, or type-parameter constraint) to its type-checked skeleton expression. GSXPos is the region's first byte in the .gsx and Len its byte length; SkelTyp is the corresponding skeleton expression, whose bytes are identical to the .gsx source span — so the LSP bridges a cursor into it by relative offset and resolves via go/types.
type SymbolKind ¶
type SymbolKind int
SymbolKind is a coarse classification of an exported package-level symbol, carried out of the codegen graph to the LSP without leaking a *types.Object. The LSP maps it to an LSP CompletionItemKind. Only the categories a package's top-level exported scope can hold are represented (no method / package-name / builtin — those never appear at package scope).
const ( SymbolFunc SymbolKind = iota SymbolVar SymbolConst SymbolTypeStruct SymbolTypeInterface SymbolTypeOther // named non-struct/interface type, alias, or basic type )
type UnusedImport ¶
UnusedImport is one import a .gsx file declares but never references, as determined by the type-checker. Name is "" for a default import.
Source Files
¶
- add_imports.go
- analyze.go
- barecomment.go
- bundle.go
- bundle_project_imports.go
- classmerger.go
- coalesce.go
- codegen.go
- component_call_plan.go
- component_identity.go
- component_lsp_facts.go
- component_positional_emit.go
- component_positional_plan.go
- component_signature.go
- component_target.go
- component_target_importer.go
- component_target_package.go
- component_target_provenance.go
- component_target_skeleton.go
- component_variant_semantic.go
- component_variant_signature_identity.go
- component_zero.go
- configured_source_packages.go
- declnames.go
- direct_component.go
- emit.go
- export_symbols.go
- external_backedge.go
- filters.go
- generate_dirs.go
- generated_imports.go
- go_overlay.go
- go_package_index.go
- go_workspace.go
- htmlnames.go
- loadpackages.go
- modpath.go
- module.go
- module_importer.go
- parenstrip.go
- rebase.go
- renderer_decls.go
- renderers.go
- reserved_bindings.go
- reserved_fragment.go
- reserved_scan.go
- resolve_functions.go
- resolver.go
- results.go
- rtimports.go
- sharedworld.go
- skeleton_source.go
- source_inventory.go
- stdlibindex_gen.go
- symbol_extras.go
- tagcycle.go
- tagresolve.go
- toolchain.go
- unused_imports_syntactic.go
- variantcollide.go
- version.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Command mkstdlibindex writes internal/codegen/stdlibindex_gen.go: a package-name -> import-path table for the Go standard library.
|
Command mkstdlibindex writes internal/codegen/stdlibindex_gen.go: a package-name -> import-path table for the Go standard library. |
|
Package stdpath decides whether an import path is importable from ordinary user code, applying Go's own `internal`/`vendor` path rules rather than an approximation of them.
|
Package stdpath decides whether an import path is importable from ordinary user code, applying Go's own `internal`/`vendor` path rules rather than an approximation of them. |