API Reference
polytype
Section titled “polytype”import "github.com/tylergannon/polytype"- func Camel(name string) string
- func Pascal(name string) string
- func Snake(name string) string
- type Configuration
- type ConfigurationSpec
- type Declaration
- func Declare[T any](entrypoint …func(T) json.RawMessage) *Declaration[T]
- func (d *Declaration[T]) Accessor[F any](field FieldRef[F], provider func(T) json.Marshaler) *Declaration[T]
- func (d *Declaration[T]) Function[F any](field FieldRef[F], provider func(F) json.Marshaler) *Declaration[T]
- func (d *Declaration[T]) Method[F any](field FieldRef[F], provider func(T, F) json.Marshaler) *Declaration[T]
- func (d *Declaration[T]) Ref() *Declaration[T]
- func (d *Declaration[T]) RenderProviders() *Declaration[T]
- func (d *Declaration[T]) StringerEnum[F any](field FieldRef[F]) *Declaration[T]
- type DeclarationSpec
- type FieldRef
- type FieldSpec
- type Nullable
- type Optional
- type RuleKind
- type RuleSpec
- type SchemaFunction
- type SchemaMarker
- type SchemaMethod
- type SchemaMethodOption
- func AsRef() SchemaMethodOption
- func WithFunction[T any](val T, f func(T) json.Marshaler) SchemaMethodOption
- func WithRenderProviders() SchemaMethodOption
- func WithStringerEnum[T any](field T) SchemaMethodOption
- func WithStructAccessorMethod[T, U any](val T, f func(U) json.Marshaler) SchemaMethodOption
- func WithStructFunctionMethod[T, U any](val U, f func(T, U) json.Marshaler) SchemaMethodOption
- type SchemaMethodOptionObj
- type SealedUnionMarker
- type SealedUnionSpec
- type TypeSpec
func Camel
Section titled “func Camel”func Camel(name string) stringCamel converts a Go type name to lower camelCase for use as a discriminator value.
func Pascal
Section titled “func Pascal”func Pascal(name string) stringPascal returns a Go type name unchanged. It is the default discriminator inflection and preserves the historical concrete-type-name wire value.
func Snake
Section titled “func Snake”func Snake(name string) stringSnake converts a Go type name to lower snake_case for use as a discriminator value.
type Configuration
Section titled “type Configuration”Configuration is the common value accepted by polytype generators. Declarations, sealed-union settings, and Compose results implement it.
type Configuration interface { // contains filtered or unexported methods}func Compose
Section titled “func Compose”func Compose(configs ...Configuration) ConfigurationCompose combines declarations and union settings into one configuration for a generator program, such as one calling codegen.Gen. A declaration file lists each Declare and SealedUnion as its own var _ = declaration instead; the polytype CLI rejects a Compose call there.
func DeclareType
Section titled “func DeclareType”func DeclareType(typ TypeSpec) ConfigurationDeclareType selects a named type by source identity without importing its application package into the generator binary. The generator resolves the name against current source and reports missing or unsupported types there. It has no schema entrypoint or field/provider rules; select outputs explicitly.
type ConfigurationSpec
Section titled “type ConfigurationSpec”ConfigurationSpec is the resolved meaning of one or more configuration values. Generators obtain it with ResolveConfiguration.
type ConfigurationSpec struct { Declarations []DeclarationSpec SealedUnions []SealedUnionSpec // contains filtered or unexported fields}func ResolveConfiguration
Section titled “func ResolveConfiguration”func ResolveConfiguration(configs ...Configuration) (ConfigurationSpec, error)ResolveConfiguration returns the complete meaning of configs and validates identities that must agree before source loading begins.
type Declaration
Section titled “type Declaration”Declaration is an executable description of one code-generation root. It is both the value used by build-tagged declaration files and the value accepted by the programmatic code-generation API.
type Declaration[T any] struct { // contains filtered or unexported fields}func Declare
Section titled “func Declare”func Declare[T any](entrypoint ...func(T) json.RawMessage) *Declaration[T]Declare selects T as a generation root. With no argument it does not imply JSON Schema or an accessor method. Passing a method expression or free function records its name for schema-accessor generation.
Both forms produce an ordinary configuration value:
config := polytype.Declare[Person]()config := polytype.Declare(Person.Schema)A declaration file read by the polytype CLI accepts both forms too: Declare[Person]() gives Person the generated Go JSON codecs, and TypeScript with --typescript, but no schema file or accessor.
func (*Declaration[T]) Accessor
Section titled “func (*Declaration[T]) Accessor”func (d *Declaration[T]) Accessor[F any](field FieldRef[F], provider func(T) json.Marshaler) *Declaration[T]Accessor registers a provider for field that is a struct method taking only the receiver T (equivalent to WithStructAccessorMethod).
func (*Declaration[T]) Function
Section titled “func (*Declaration[T]) Function”func (d *Declaration[T]) Function[F any](field FieldRef[F], provider func(F) json.Marshaler) *Declaration[T]Function registers a provider for field that is a free function taking only the field’s own value F (equivalent to WithFunction). field and provider must agree on F: passing a field of one type alongside a provider expecting another fails to compile.
func (*Declaration[T]) Method
Section titled “func (*Declaration[T]) Method”func (d *Declaration[T]) Method[F any](field FieldRef[F], provider func(T, F) json.Marshaler) *Declaration[T]Method registers a provider for field that is a struct method also taking the field’s own value F (equivalent to WithStructFunctionMethod). field and provider must agree on F: passing a field of one type alongside a provider expecting another fails to compile.
func (*Declaration[T]) Ref
Section titled “func (*Declaration[T]) Ref”func (d *Declaration[T]) Ref() *Declaration[T]Ref requests that, wherever T is referenced from another registered schema, it be rendered as a “$ref” into that schema’s “$defs” instead of being inlined (equivalent to AsRef).
func (*Declaration[T]) RenderProviders
Section titled “func (*Declaration[T]) RenderProviders”func (d *Declaration[T]) RenderProviders() *Declaration[T]RenderProviders requests generation of RenderedSchema() and provider execution at runtime (equivalent to WithRenderProviders).
func (*Declaration[T]) StringerEnum
Section titled “func (*Declaration[T]) StringerEnum”func (d *Declaration[T]) StringerEnum[F any](field FieldRef[F]) *Declaration[T]StringerEnum emits an integer enum field using its constant names instead of its underlying integer values (equivalent to WithStringerEnum).
type DeclarationSpec
Section titled “type DeclarationSpec”DeclarationSpec is the generator-facing form of a Declaration.
type DeclarationSpec struct { Type TypeSpec EntrypointName string EntrypointFunc bool Rules []RuleSpec}type FieldRef
Section titled “type FieldRef”FieldRef retains a field’s identity and value type after a declaration is evaluated. The value type keeps provider bindings type-safe.
type FieldRef[F any] struct { // contains filtered or unexported fields}func Field
Section titled “func Field”func Field[T, F any](name string) FieldRef[F]Field returns a stable reference to a field of T.
type FieldSpec
Section titled “type FieldSpec”FieldSpec identifies a field by owner and Go field name.
type FieldSpec struct { Owner TypeSpec Name string}type Nullable
Section titled “type Nullable”Nullable represents a required object property whose value may be null. The zero value encodes as null; Present reports whether Value is non-null.
type Nullable[T any] struct { Present bool Value T}func (Nullable[T]) IsZero
Section titled “func (Nullable[T]) IsZero”func (Nullable[T]) IsZero() boolIsZero always reports false so json:“,omitzero” cannot omit a required nullable property.
func (Nullable[T]) MarshalJSON
Section titled “func (Nullable[T]) MarshalJSON”func (n Nullable[T]) MarshalJSON() ([]byte, error)MarshalJSON encodes null or a present non-null value.
func (*Nullable[T]) UnmarshalJSON
Section titled “func (*Nullable[T]) UnmarshalJSON”func (n *Nullable[T]) UnmarshalJSON(data []byte) errorUnmarshalJSON decodes null or a present value without mutating the receiver when decoding fails.
type Optional
Section titled “type Optional”Optional represents an object property that may be absent. The zero value is absent; a present value may contain T’s zero value but may not encode as null. Containing struct fields must use json:“,omitzero” so absent values are omitted before MarshalJSON is called.
type Optional[T any] struct { Present bool Value T}func (Optional[T]) IsZero
Section titled “func (Optional[T]) IsZero”func (o Optional[T]) IsZero() boolIsZero reports whether the property is absent.
func (Optional[T]) MarshalJSON
Section titled “func (Optional[T]) MarshalJSON”func (o Optional[T]) MarshalJSON() ([]byte, error)MarshalJSON encodes a present non-null value.
func (*Optional[T]) UnmarshalJSON
Section titled “func (*Optional[T]) UnmarshalJSON”func (o *Optional[T]) UnmarshalJSON(data []byte) errorUnmarshalJSON decodes a present non-null value without mutating the receiver when decoding fails.
type RuleKind
Section titled “type RuleKind”RuleKind identifies one declaration rule.
type RuleKind stringconst ( RuleAccessor RuleKind = "accessor" RuleMethod RuleKind = "method" RuleFunction RuleKind = "function" RuleStringerEnum RuleKind = "stringer-enum" RuleRef RuleKind = "ref" RuleRenderProviders RuleKind = "render-providers")type RuleSpec
Section titled “type RuleSpec”RuleSpec is one executable declaration rule.
type RuleSpec struct { Kind RuleKind Field FieldSpec ProviderName string ProviderIsMethod bool}type SchemaFunction
Section titled “type SchemaFunction”type SchemaFunction func() json.RawMessagetype SchemaMarker
Section titled “type SchemaMarker”type SchemaMarker struct{}func NewJSONSchemaBuilder
Section titled “func NewJSONSchemaBuilder”func NewJSONSchemaBuilder[T any](SchemaFunction) SchemaMarkerNewJSONSchemaBuilder registers a function as being a stub that should be implemented with a proper json schema and, as needed, unmarshaler functionality.
func NewJSONSchemaFunc
Section titled “func NewJSONSchemaFunc”func NewJSONSchemaFunc[T any](f SchemaMethod[T], _ ...SchemaMethodOption) SchemaMarkerNewJSONSchemaFunc registers a free function that takes the receiver as its sole parameter as a schema entrypoint. It is equivalent to NewJSONSchemaMethod.
Deprecated: use Declare(fn) with a free function instead.
func NewJSONSchemaMethod
Section titled “func NewJSONSchemaMethod”func NewJSONSchemaMethod[T any](SchemaMethod[T], ...SchemaMethodOption) SchemaMarkerNewJSONSchemaMethod registers a struct method as a stub that will be implemented with a proper json schema and, as needed, unmarshaler functionality.
Deprecated: use Declare(T.Schema) instead. For example, NewJSONSchemaMethod(Task.Schema, WithStringerEnum(Task{}.Level)) becomes Declare(Task.Schema).StringerEnum(Field[Task, Level](“Level”)).
type SchemaMethod
Section titled “type SchemaMethod”type SchemaMethod[T any] func(T) json.RawMessagetype SchemaMethodOption
Section titled “type SchemaMethodOption”type SchemaMethodOption interface { // contains filtered or unexported methods}func AsRef
Section titled “func AsRef”func AsRef() SchemaMethodOptionAsRef requests that, wherever this type is referenced from another registered schema, it be rendered as a “$ref” into that schema’s “$defs” instead of being inlined.
Deprecated: use Declare(T.Schema).Ref() instead.
func WithFunction
Section titled “func WithFunction”func WithFunction[T any](val T, f func(T) json.Marshaler) SchemaMethodOptionDeprecated: use Declare(T.Schema).Function(Field[T, F](“Field”), fn) instead.
func WithRenderProviders
Section titled “func WithRenderProviders”func WithRenderProviders() SchemaMethodOptionWithRenderProviders requests generation of RenderedSchema() and provider execution at runtime.
Deprecated: use Declare(T.Schema).RenderProviders() instead.
func WithStringerEnum
Section titled “func WithStringerEnum”func WithStringerEnum[T any](field T) SchemaMethodOptionEnum options (v1) - stubs for scanning/type-checking; parsed by scanner
Deprecated: use Declare(T.Schema).StringerEnum(Field[T, F](“Field”)) instead.
func WithStructAccessorMethod
Section titled “func WithStructAccessorMethod”func WithStructAccessorMethod[T, U any](val T, f func(U) json.Marshaler) SchemaMethodOptionDeprecated: use Declare(T.Schema).Accessor(Field[T, F](“Field”), T.method) instead.
func WithStructFunctionMethod
Section titled “func WithStructFunctionMethod”func WithStructFunctionMethod[T, U any](val U, f func(T, U) json.Marshaler) SchemaMethodOptionDeprecated: use Declare(T.Schema).Method(Field[T, F](“Field”), T.method) instead.
type SchemaMethodOptionObj
Section titled “type SchemaMethodOptionObj”type SchemaMethodOptionObj struct{}type SealedUnionMarker
Section titled “type SealedUnionMarker”SealedUnionMarker is executable configuration for one sealed interface.
type SealedUnionMarker struct { // contains filtered or unexported fields}func SealedUnion
Section titled “func SealedUnion”func SealedUnion[I any](discriminator string, inflectors ...func(string) string) SealedUnionMarkerSealedUnion declares the discriminator property for the sealed interface I. A sealed interface is one whose own body declares an unexported method; its variants are inferred from the same-package struct types that declare that method directly, so membership needs no declaration. The default property is “type” and needs no declaration; SealedUnion sets a different property for every use of I in every generated schema, codec, and TypeScript output. The optional inflector determines each variant’s value from its concrete Go type name. Pascal is the default; Snake and Camel are also provided. Executable codegen configuration may supply any non-nil func(string) string. Build-tagged source markers accept the named Pascal, Snake, and Camel functions.
The declaration must appear in the build-tagged file of the package that declares I, exactly once per interface, with a string literal argument:
var _ = polytype.SealedUnion[Animal]("kind", polytype.Snake)A declaration in another package, a duplicate declaration, a declaration for a non-sealed interface or a non-interface type, a non-literal argument, or an invalid property name is a generation error naming the interface.
type SealedUnionSpec
Section titled “type SealedUnionSpec”SealedUnionSpec configures the discriminator property of one inferred sealed interface.
type SealedUnionSpec struct { Type TypeSpec Discriminator string Inflect func(string) string}type TypeSpec
Section titled “type TypeSpec”TypeSpec identifies a named Go type without retaining a runtime value.
type TypeSpec struct { PackagePath string Name string Pointer bool}codegen
Section titled “codegen”import "github.com/tylergannon/polytype/codegen"Package codegen runs polytype generation from executable configuration values. It does not require a schema.go registration file in the target package.
- func Gen(config polytype.Configuration, options …Option) error
- func Generate(config polytype.Configuration, opts Options) error
- type DevalueOptions
- type Option
- type Options
- type TypeScriptOptions
- type Worker
- type WorkerStats
func Gen
Section titled “func Gen”func Gen(config polytype.Configuration, options ...Option) errorGen runs generation with functional options. With no options, Declare(T.Schema) preserves the traditional schema-and-accessor behavior. A declaration without an entrypoint must select at least one output.
func Generate
Section titled “func Generate”func Generate(config polytype.Configuration, opts Options) errorGenerate runs the selected backends from the same declaration value used by build-tagged bindings.
type DevalueOptions
Section titled “type DevalueOptions”DevalueOptions selects generated devalue Go codecs.
type DevalueOptions struct { File string PackageName string ImportPath string}type Option
Section titled “type Option”Option modifies the convenience Gen request.
type Option func(*Options)func Devalue
Section titled “func Devalue”func Devalue(file, packageName, importPath string) OptionDevalue writes strict devalue codecs to file.
func GoJSON
Section titled “func GoJSON”func GoJSON() OptionGoJSON selects generated MarshalJSON and UnmarshalJSON support required by configured enums and sealed unions, without selecting JSON Schema.
func JSONSchema
Section titled “func JSONSchema”func JSONSchema() OptionJSONSchema selects JSON Schema files. If the declaration carries an entrypoint, its Go accessor is emitted as well.
func Pretty
Section titled “func Pretty”func Pretty() OptionPretty formats JSON Schema output with indentation.
func Target
Section titled “func Target”func Target(dir string) OptionTarget loads and writes the configured package at dir.
func TypeScript
Section titled “func TypeScript”func TypeScript(dir string, barrel ...bool) OptionTypeScript writes structural TypeScript declarations to dir.
func Validation
Section titled “func Validation”func Validation() OptionValidation selects JSON Schema, its Go accessors, and generated validators.
func WithSession
Section titled “func WithSession”func WithSession(session *goload.Session) OptionWithSession shares compatible Go package analysis within an invocation.
type Options
Section titled “type Options”Options selects outputs for Generate. JSON Schema is optional: TypeScript, devalue, and generated Go JSON codecs can be requested independently.
type Options struct {
// Session shares Go analysis on persistent-cache misses. It does not affect // cache identity, and a persistent hit performs no session work. Session *goload.Session
TargetDir string Pretty bool Force bool
JSONSchema bool GoCode bool Validate bool
TypeScript *TypeScriptOptions Devalue *DevalueOptions // contains filtered or unexported fields}type TypeScriptOptions
Section titled “type TypeScriptOptions”TypeScriptOptions selects structural TypeScript output.
type TypeScriptOptions struct { Dir string Barrel bool}type Worker
Section titled “type Worker”Worker retains analysis and emitted TypeScript between serialized development edits. Its zero value is ready to use. Each Worker retains one request; use separate workers for independent targets. Close releases private source files.
Callback-free TypeScript requests reuse captured local source and type analysis. The first analysis checks the selected local source closure together so later edits retain a coherent graph. The owned session retains at most four graph versions. If Options.Session is supplied, its owner must call SetMaxUniverses with a positive limit for sustained edits; Worker does not change a shared session’s retention policy. This bounds graph versions, not bytes. Other output modes, workspaces, mutable native/embed dependencies and custom loader configurations keep Generate’s behavior. Versioned module-cache files and the Go toolchain must remain immutable during its lifetime. Changing environment, module controls, imports or file membership refreshes discovery. A failed edit never replaces the last successful output.
type Worker struct { // contains filtered or unexported fields}func (*Worker) Close
Section titled “func (*Worker) Close”func (w *Worker) Close() errorClose releases retained analysis and private files. The Worker may be reused.
func (*Worker) Generate
Section titled “func (*Worker) Generate”func (w *Worker) Generate(config polytype.Configuration, opts Options) errorGenerate updates the selected outputs from current authored source. Missing or modified output is repaired even when no input changed.
func (*Worker) Stats
Section titled “func (*Worker) Stats”func (w *Worker) Stats() WorkerStatsStats returns cumulative work for this Worker, including across Close calls.
type WorkerStats
Section titled “type WorkerStats”WorkerStats counts retained TypeScript work. Other output modes use Generate directly and do not contribute. Emissions count backend executions, including executions whose bytes match the existing output; Replays run no backend.
type WorkerStats struct{ Analyses, Emissions, Replays uint64 }jsonschema
Section titled “jsonschema”import "github.com/tylergannon/polytype/jsonschema"- type DataType
- type JSONSchema
- type JSONUnionType
- type ObjectSchema
- type ParentSchema
- type SchemaNode
- func ArraySchema(items SchemaNode, description string) SchemaNode
- func BoolSchema(description string) SchemaNode
- func ConstSchema[T ~int | ~string](val T, description string) SchemaNode
- func EnumSchema[T ~int | ~string](description string, vals …T) SchemaNode
- func IntSchema(description string) SchemaNode
- func RefSchemaEl(ref string) SchemaNode
- func StringSchema(description string) SchemaNode
- func UnionSchemaEl(alts …SchemaNode) SchemaNode
- type SchemaProperty
type DataType
Section titled “type DataType”type DataType stringconst ( Object DataType = "object" Number DataType = "number" Integer DataType = "integer" String DataType = "string" Array DataType = "array" Null DataType = "null" Boolean DataType = "boolean")type JSONSchema
Section titled “type JSONSchema”JSONSchema is a struct for describing a JSON Schema. It is fairly limited, and you may have better luck using a third-party library. This is a copy from go-openai’s “jsonschema.Definition{}” struct, with the difference being that this one holds references to json.Marshaler, rather than to itself.
type JSONSchema struct { // Type specifies the data type of the schema. Type DataType `json:"type" yaml:"type"` // Description is the description of the schema. Description string `json:"description,omitempty" yaml:"description,omitempty"` // Enum is used to restrict a value to a fixed set of values. It must be an // array with at least one element, where each element is unique. You will // probably only use this with strings. Enum []any `json:"enum,omitempty" yaml:"enum,omitempty"` // Properties describes the properties of an object, if the schema type is // Object. Properties map[string]SchemaNode `json:"properties,omitempty" yaml:"properties,omitempty"` // Required specifies which properties are required, if the schema type is // Object. Required []string `json:"required,omitempty" yaml:"required,omitempty"` // Items specifies which data type an array contains, if the schema type is // Array. Items SchemaNode `json:"items,omitempty" yaml:"items,omitempty"` // AdditionalProperties is used to control the handling of properties in an // object that are not explicitly defined in the properties section of the // schema. example: additionalProperties: true additionalProperties: false // additionalProperties: jsonschema.Definition{Type: jsonschema.String} AdditionalProperties any `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"` Definitions map[string]SchemaNode `json:"$defs,omitzero" yaml:"$defs,omitempty"` Const any `json:"const,omitempty"` // Provide a const value // Strict will make all properties required and set additionalProperties to // false. Applies only if Type = "object". Strict bool `json:"-" yaml:"-"`}func (JSONSchema) MarshalJSON
Section titled “func (JSONSchema) MarshalJSON”func (s JSONSchema) MarshalJSON() ([]byte, error)type JSONUnionType
Section titled “type JSONUnionType”type JSONUnionType []*JSONSchemafunc (JSONUnionType) MarshalJSON
Section titled “func (JSONUnionType) MarshalJSON”func (j JSONUnionType) MarshalJSON() ([]byte, error)MarshalJSON implements json.Marshaler.
type ObjectSchema
Section titled “type ObjectSchema”type ObjectSchema struct { Properties []SchemaProperty Strict bool Required []string Description string AdditionalProperties any}func (*ObjectSchema) AddProperty
Section titled “func (*ObjectSchema) AddProperty”func (s *ObjectSchema) AddProperty(key string, value SchemaNode)func (*ObjectSchema) AddRequiredProperty
Section titled “func (*ObjectSchema) AddRequiredProperty”func (s *ObjectSchema) AddRequiredProperty(key string, value SchemaNode)func (ObjectSchema) MarshalJSON
Section titled “func (ObjectSchema) MarshalJSON”func (s ObjectSchema) MarshalJSON() ([]byte, error)type ParentSchema
Section titled “type ParentSchema”type ParentSchema struct { *ObjectSchema Definitions []SchemaProperty // The key name for the definitions map. Defaults to "definitions" DefinitionsKeyName string `json:"-"` Title string `json:"title,omitzero"`}func (*ParentSchema) AddDefinition
Section titled “func (*ParentSchema) AddDefinition”func (s *ParentSchema) AddDefinition(key string, value SchemaNode)func (ParentSchema) MarshalJSON
Section titled “func (ParentSchema) MarshalJSON”func (s ParentSchema) MarshalJSON() ([]byte, error)type SchemaNode
Section titled “type SchemaNode”type SchemaNode = json.Marshalerfunc ArraySchema
Section titled “func ArraySchema”func ArraySchema(items SchemaNode, description string) SchemaNodefunc BoolSchema
Section titled “func BoolSchema”func BoolSchema(description string) SchemaNodefunc ConstSchema
Section titled “func ConstSchema”func ConstSchema[T ~int | ~string](val T, description string) SchemaNodeConstSchema returns a schema that accepts exactly val. Named values whose underlying type is int or string retain their corresponding JSON Schema type.
func EnumSchema
Section titled “func EnumSchema”func EnumSchema[T ~int | ~string](description string, vals ...T) SchemaNodeEnumSchema returns a schema that accepts one of vals. Named values whose underlying type is int or string retain their corresponding JSON Schema type. If vals is empty, the returned node reports an error when marshaled.
func IntSchema
Section titled “func IntSchema”func IntSchema(description string) SchemaNodefunc RefSchemaEl
Section titled “func RefSchemaEl”func RefSchemaEl(ref string) SchemaNodeA ref into definitions
func StringSchema
Section titled “func StringSchema”func StringSchema(description string) SchemaNodefunc UnionSchemaEl
Section titled “func UnionSchemaEl”func UnionSchemaEl(alts ...SchemaNode) SchemaNodeAn anyOf element
type SchemaProperty
Section titled “type SchemaProperty”type SchemaProperty struct { Key string Value SchemaNode}grammar
Section titled “grammar”import "github.com/tylergannon/polytype/grammar"Package grammar is the exported entry point for lowering Go types into the static type-definition grammar of github.com/tylergannon/polytype/typegrammar.
Load reads a Go package the way the polytype CLI does, and Lower turns caller-chosen root types into a validated definition graph plus one grammar node per root. Callers use it to write their own code-generation backend without going through the CLI or asking for a schema file. FromPackages accepts an existing go/packages snapshot without loading its source again.
Roots are matched structurally and by name, so a *types.Type obtained from the caller’s own packages.Load works. A named root does not need a Declare marker; whatever the CLI would refuse in a struct field (maps, channels, functions, unconfigured interfaces, presence wrappers) is refused here with the same wording.
- Constants
- type Package
- func FromPackages(config *packages.Config, root *packages.Package, additional …*packages.Package) (*Package, error)
- func Load(dir string) (*Package, error)
- func LoadWithConfig(config *packages.Config, pattern string) (*Package, error)
- func LoadWithLoader(config *packages.Config, load goload.LoadFunc, pattern string) (*Package, error)
- func LoadWithSession(config *packages.Config, session *goload.Session, pattern string) (*Package, error)
- func (p *Package) Lower(roots []Root) (typegrammar.Definitions, []typegrammar.Type, error)
- func (p *Package) Types() *types.Package
- type Root
Constants
Section titled “Constants”LoadMode is the information FromPackages needs for each package whose source is lowered. Add packages.NeedDeps to obtain that information for imports, or select the necessary dependency packages as explicit packages.Load patterns.
const LoadMode = syntax.PackageLoadNeeds | packages.NeedImportstype Package
Section titled “type Package”Package is a loaded Go package that roots can be lowered against.
type Package struct { // contains filtered or unexported fields}func FromPackages
Section titled “func FromPackages”func FromPackages(config *packages.Config, root *packages.Package, additional ...*packages.Package) (*Package, error)FromPackages lowers from an already parsed and type-checked package snapshot. It preserves root’s type identity and uses its Imports graph plus additional packages to resolve source. It never invokes a loader or the Go command; a reached package without source produces an error identifying what is missing. Packages used only through built-in grammar support (such as time.Time) do not need source. Errors are checked on each reached package; errors in an unrelated dependency do not prevent lowering an otherwise valid root.
config must describe the load that produced the snapshot and set the jsonschema tag in BuildFlags or GOFLAGS (Config.Env, or the process environment when Env is nil). Unlike LoadWithConfig, this constructor cannot add a tag to an already loaded package. Call packages.Load with at least LoadMode, Tests: false, and a parser that retains comments (the default does). All packages must belong to the same type-checking operation, with identical build settings, module selection and overlays. packages.Package does not retain those settings: their correspondence is the caller’s responsibility. Generation follows Go’s flag precedence: an explicit -tags replaces GOFLAGS tags rather than combining with them.
The caller owns the snapshot and must keep its ASTs, FileSet, Types, TypesInfo, source files and overlay resources alive and unchanged until all Lower calls finish. FromPackages does not mutate them. Do not share a Package between concurrent Lower calls, or reuse a snapshot after editing source; load a fresh snapshot for the next generation. No state is retained globally.
Production declaration admission removes jsonschema from explicit build tags; if that was the only explicit tag, production falls back to GOFLAGS tags. The jsonschema tag is removed from that production fallback as well. String-mode enum adaptation also retains the existing on-disk inspection of production JSON methods, including files excluded by jsonschema. That check does not use overlays; keep the production source view available on disk.
func Load
Section titled “func Load”func Load(dir string) (*Package, error)Load loads the Go package at dir with the jsonschema build tag, the same way the CLI does, together with the packages it references.
func LoadWithConfig
Section titled “func LoadWithConfig”func LoadWithConfig(config *packages.Config, pattern string) (*Package, error)LoadWithConfig loads pattern using the caller’s module, environment, parser, and overlay configuration. The same configuration resolves every recursively discovered type dependency. It includes the jsonschema build tag alongside explicit caller tags, overriding GOFLAGS tags as Load and the CLI do, and adds the load modes required by grammar. The caller must keep any backing files or parser resources alive until all Lower calls finish. Config and its BuildFlags are not modified. Declaration admission uses the same snapshot and production-tag rules as FromPackages, including for files supplied solely through Overlay.
func LoadWithLoader
Section titled “func LoadWithLoader”func LoadWithLoader(config *packages.Config, load goload.LoadFunc, pattern string) (*Package, error)LoadWithLoader is LoadWithConfig with a caller-owned package loading strategy. The loader serves both the initial request and dependencies reached by Lower, using the same tagged configuration. It must return ordinary go/packages data whose source, type information and positions describe that configuration.
func LoadWithSession
Section titled “func LoadWithSession”func LoadWithSession(config *packages.Config, session *goload.Session, pattern string) (*Package, error)LoadWithSession is LoadWithConfig with invocation-scoped package reuse. The session also serves recursively reached source dependencies.
func (*Package) Lower
Section titled “func (*Package) Lower”func (p *Package) Lower(roots []Root) (typegrammar.Definitions, []typegrammar.Type, error)Lower returns the validated definition graph reachable from the roots, and one grammar node per root in order. Named roots need no Declare marker.
func (*Package) Types
Section titled “func (*Package) Types”func (p *Package) Types() *types.PackageTypes is the package’s type-checked scope, for looking up the roots to lower.
type Root
Section titled “type Root”Root is one shape a caller wants lowered. Type may be anonymous; Position is reported in diagnostics because an anonymous type has no source location of its own.
type Root struct { Type types.Type Position token.Position}typegrammar
Section titled “typegrammar”import "github.com/tylergannon/polytype/typegrammar"Package typegrammar defines the accepted, resolved static type-definition grammar shared by code-generation backends. Validate is its admission boundary.
A definition describes a Go type’s JSON value structure, retaining numeric kinds, pointer/value identity, collection shape, and field-local registrations. Source loading must resolve aliases, embedding/field selection, registrations, and JSON names before constructing this model. The builder’s TypeDefinitions adapter produces this model for the TypeScript backend.
Named definitions may reference one another, including recursive and mutually recursive references through Ref edges. Inline constructor nodes still form a finite DAG: a back-edge is valid only when it passes through a named definition. Nonproductive alias loops (Ref-only cycles) are rejected. Objects are closed, ordered sets of properties. Ordinary values are non-null; absence and null are separate, direct-field constructors. Unions are field-only constructors with explicit, resolved tags, including singleton unions. There is no general anyOf, any, or map constructor. A field whose wire shape is supplied outside the grammar (a runtime schema provider or an explicit schema reference) is the Provided form: it names the field and carries no shape, so a backend must either honor the supplied schema or refuse the field by name.
This is the static structural subset of the v1 contract, not a Go-source parser, arbitrary JSON Schema grammar, or claim of codec conformance. Unresolved external types and unproved custom wire mappings must be diagnosed by lowering, not replaced with a permissive node. Backends must define their projection explicitly: for example TypeScript’s number cannot enforce all Go ranges, and its object types are not validators.
New node kinds may be added in minor versions. Consumers must not treat a type switch over the node types as exhaustive: always provide a default case that reports an unrecognized kind rather than silently ignoring it.
- type Array
- type Definition
- type Definitions
- type Enum
- type EnumMember
- type EnumMode
- type Error
- type Field
- type FieldValue
- type Name
- type Nullable
- type Object
- type Optional
- type OptionalUnion
- type Pointer
- type Provided
- type Ref
- type Required
- type Scalar
- type ScalarKind
- type Slice
- type Time
- type Type
- type Union
- type UnionSlice
- type Variant
type Array
Section titled “type Array”Array retains the Go length, including zero. It does not by itself claim that the existing JSON Schema renderer enforces that length.
type Array struct { Length int64 Element Type}type Definition
Section titled “type Definition”type Definition struct { Name Name Type Type Description string Source token.Position}type Definitions
Section titled “type Definitions”Definitions is the complete local definition graph, in source order. Every reference and union implementation must resolve here, including dependencies from supported packages. Consumers select output roots separately.
type Definitions []Definitionfunc (Definitions) Validate
Section titled “func (Definitions) Validate”func (defs Definitions) Validate() errorValidate admits exactly the constructors and compositions documented by this package. It checks all definitions, including unused ones. It neither mutates nor normalizes the graph, executes user code, nor validates runtime JSON.
Named recursion through Ref edges and union implementations is admitted: a definition may reference itself or a mutually-dependent definition provided the cycle passes through at least one productive constructor (Object, Slice, Array, Pointer). Nonproductive alias loops where every edge is a Ref are rejected. Literal cycles of constructor pointers (hand-built graphs where a node’s child pointer points back to itself) remain rejected. Sharing is permitted and checked once per relevant context.
Example
package main
import ( "fmt"
g "github.com/tylergannon/polytype/typegrammar")
func main() { payload := g.Name{PackagePath: "example.com/events", Name: "Created"} defs := g.Definitions{ {Name: payload, Type: &g.Object{Fields: []g.Field{{ GoName: "Text", JSONName: "text", Value: &g.Required{Type: &g.Scalar{Kind: g.String}}, }}}}, {Name: g.Name{PackagePath: "example.com/events", Name: "Envelope"}, Type: &g.Object{Fields: []g.Field{{ GoName: "Event", JSONName: "event", Value: &g.Union{ Interface: g.Name{PackagePath: "example.com/events", Name: "Event"}, Discriminator: "kind", Variants: []g.Variant{{Implementation: payload, Pointer: true, Tag: "created"}}, }, }}}}, } fmt.Println(defs.Validate())}Output
Section titled “Output”<nil>func (Definitions) ValidateWithRoots
Section titled “func (Definitions) ValidateWithRoots”func (defs Definitions) ValidateWithRoots(roots []Type) errorValidateWithRoots admits the definitions and, in addition, each root node. A root is a node a caller asked to have lowered directly; no definition reaches it, so Validate alone would never see it and a shape this grammar excludes could be returned unchecked.
Roots are checked as anonymous operands, because that is what they are: they have no named object owner, so the compositions that require one (a string-mode enum, most obviously) are refused in a root exactly as they are in an anonymous position inside a definition.
type Enum
Section titled “type Enum”Enum is a resolved registration, not a global adapter for GoType. The same Go type can have different mappings in different fields. Values retain exact Go constants, including integers not exactly representable by JavaScript number. Representability in a target language is a later backend obligation.
type Enum struct { GoType Name Kind ScalarKind Mode EnumMode Members []EnumMember}type EnumMember
Section titled “type EnumMember”type EnumMember struct { Name string Value constant.Value // Description is the constant's doc comment, for backends that document // members (JSON Schema folds it into the enum's description). Description string}type EnumMode
Section titled “type EnumMode”type EnumMode uint8const ( // EnumValues uses underlying string or integer constant values on the wire. EnumValues EnumMode = iota // EnumNames uses Go constant names as wire strings, for integer enums only. // It is admitted only in direct fields of named object owners (Required, // Optional or Nullable), including references to reusable enum definitions. // Pointer/collection operands and anonymous owners cannot request this // adaptation. String() methods never determine wire values. EnumNames)type Error
Section titled “type Error”Error identifies the first invalid constructor in deterministic definition, field, and variant order. Source is the nearest available source location; Path is usable even for programmatically constructed definitions without one.
type Error struct { Path string Source token.Position Message string}func (*Error) Error
Section titled “func (*Error) Error”func (e *Error) Error() stringtype Field
Section titled “type Field”type Field struct { GoName string JSONName string Value FieldValue Description string Source token.Position}type FieldValue
Section titled “type FieldValue”FieldValue is a closed sum of direct-field forms. In particular a Union is not a Type: refs, pointers, aliases and ordinary collections cannot hide one. A collection of named objects whose own fields contain unions is permitted.
type FieldValue interface { // contains filtered or unexported methods}type Name
Section titled “type Name”Name identifies a resolved Go type. PackagePath is always a full import path; pointer qualification and field-specific wire identity do not belong here.
type Name struct { PackagePath string Name string}func (Name) String
Section titled “func (Name) String”func (n Name) String() stringtype Nullable
Section titled “type Nullable”Nullable is a required key that admits null or a value. Its admitted operands are scalars/enums, objects, pointers to objects, and refs to those shapes; time.Time is also supported; collection and union operands are excluded.
type Nullable struct{ Type Type }type Object
Section titled “type Object”Object’s properties retain resolved Go field order and are closed to unknown JSON properties. An empty object is valid. Embedding is resolved before here.
type Object struct{ Fields []Field }type Optional
Section titled “type Optional”Optional is absent or a non-null value, corresponding to direct Optional[T]. Lowering must check the required json:“,omitzero” tag. It cannot occur inside collections or definitions because it does not implement Type.
type Optional struct{ Type Type }type OptionalUnion
Section titled “type OptionalUnion”OptionalUnion and UnionSlice are the only other admitted interface forms: direct Optional[I] and direct one-dimensional []I. Neither is a Type.
type OptionalUnion struct{ Union Union }type Pointer
Section titled “type Pointer”Pointer retains source indirection without introducing null into the grammar.
type Pointer struct{ Element Type }type Provided
Section titled “type Provided”Provided is a direct field whose JSON Schema is supplied outside the static grammar: by a runtime schema provider registered on the owning declaration (Ref is empty) or by an explicit reference in the field’s jsonschema tag (Ref is the reference text). It carries no Type, because the Go field’s static shape is not the wire contract. Optional reports Optional[T] with json:“,omitzero”; a Nullable wrapper is refused by lowering. Backends that cannot honor a supplied schema, such as TypeScript and devalue, refuse the field by name.
type Provided struct { Ref string Optional bool}type Ref
Section titled “type Ref”Ref is a resolved named-type edge, not an arbitrary URI or a request for a particular backend’s reference syntax (such as JSON Schema’s AsRef option).
type Ref struct{ Target Name }type Required
Section titled “type Required”Required is a required non-null field. Direct pointers and ordinary omitempty/omitzero tags are rejected during lowering; authors must state nullability or omission with Nullable or Optional.
type Required struct{ Type Type }type Scalar
Section titled “type Scalar”type Scalar struct{ Kind ScalarKind }type ScalarKind
Section titled “type ScalarKind”ScalarKind retains Go numeric width and signedness instead of prematurely projecting all JSON numbers to float64. Int and Uint remain platform-sized. byte/rune aliases normalize to Uint8/Int32. Complex and uintptr are excluded.
type ScalarKind stringconst ( Bool ScalarKind = "bool" String ScalarKind = "string" Int ScalarKind = "int" Int8 ScalarKind = "int8" Int16 ScalarKind = "int16" Int32 ScalarKind = "int32" Int64 ScalarKind = "int64" Uint ScalarKind = "uint" Uint8 ScalarKind = "uint8" Uint16 ScalarKind = "uint16" Uint32 ScalarKind = "uint32" Uint64 ScalarKind = "uint64" Float32 ScalarKind = "float32" Float64 ScalarKind = "float64")type Slice
Section titled “type Slice”Slice represents an ordinary non-null slice. Byte-like slices, whose default Go JSON representation is base64, are outside this static portable grammar.
type Slice struct{ Element Type }type Time
Section titled “type Time”Time is the renderer-owned time.Time leaf. Its wire type is string; neither date-time schema validation nor JavaScript Date precision is implied.
type Time struct{}type Type
Section titled “type Type”Type is the closed set of ordinary, non-null type constructors. Only pointer nodes implement it, allowing validation to detect cycles in hand-built graphs as well as cycles through named references. A node is admitted only after the entire Definitions value passes Validate; Go structs alone cannot enforce graph or context invariants. Do not mutate admitted graphs during consumption.
type Type interface { // contains filtered or unexported methods}type Union
Section titled “type Union”Union describes a direct registered interface field I. Its identity is the containing definition/field, not Interface alone. Tags have already been resolved from either explicit strings (including empty strings) or legacy implementation names. Discriminator is the effective, nonempty property name after applying registration defaults; whitespace is never trimmed here. Every member is a non-null object carrying the required Discriminator key with its exact Tag. A pointer registration does not imply nullable payloads.
type Union struct { Interface Name Discriminator string Variants []Variant // Source is the interface declaration's position, for diagnostics that // name the union rather than one of its variants. Source token.Position}type UnionSlice
Section titled “type UnionSlice”type UnionSlice struct{ Union Union }type Variant
Section titled “type Variant”type Variant struct { Implementation Name Pointer bool Tag string Source token.Position}typescript
Section titled “typescript”import "github.com/tylergannon/polytype/typescript"Package typescript projects the validated Go type grammar into TypeScript structural type declarations.
The input is a validated github.com/tylergannon/polytype/typegrammar definition graph, as produced by github.com/tylergannon/polytype/grammar or by the CLI’s own lowering. The output is a types.ts module declaring one exported type alias per definition, and optionally an index.ts type-only barrel. The declarations are structural: there is no runtime decoder or validator, and consumers must validate untrusted data themselves.
The CLI’s --typescript flag and a Go program calling Generate on the same definitions produce the same bytes. A generator that already knows its roots therefore needs no Declare marker and no //go:build jsonschema file: it lowers them with grammar.Load and (*grammar.Package).Lower and hands the definitions to Generate. Every root a caller wants named in the output must be a definition; an anonymous root has no alias of its own.
Emitted identifiers are collision-safe and may differ from the Go type name, so a caller writing its own imports reads them from Result.Names rather than assuming the Go name.
Constants
Section titled “Constants”GeneratedHeader identifies files owned by this generator.
const GeneratedHeader = "// Code generated by polytype. DO NOT EDIT.\n"type File
Section titled “type File”File is one generated output, named relative to whatever directory the caller writes it to.
type File struct { Name string Content []byte}type Options
Section titled “type Options”Options selects the optional outputs.
type Options struct { // Barrel adds an index.ts that re-exports every declared type, type-only. Barrel bool}type Result
Section titled “type Result”Result is the output of one Generate call.
type Result struct { // Files holds types.ts first, then index.ts when Options.Barrel is set. Files []File // Names maps every definition to the identifier its alias was emitted // under. The identifier is the Go type name unless that name is not a // legal TypeScript identifier, is reserved, or is claimed by a definition // of the same name in another package. Names map[typegrammar.Name]string}func Generate
Section titled “func Generate”func Generate(defs typegrammar.Definitions, options Options) (Result, error)Generate validates defs and renders all declarations before returning any files. It never mutates defs.
codegen
Section titled “codegen”import "github.com/tylergannon/polytype/devalue/codegen"Package codegen emits Go encoders and strict decoders that move values between Go types and the devalue value model of github.com/tylergannon/devalue/v5.
The input is a validated github.com/tylergannon/polytype/typegrammar definition graph plus the caller’s root nodes, as produced by github.com/tylergannon/polytype/grammar. The output is one Go source file holding, for every definition and every root, an encoder, a strict decoder and a Stringify/Parse convenience wrapper. The file is written for a package other than the one declaring the Go types, so the emitted functions use only exported fields.
Wire mapping
Section titled “Wire mapping”Every Go numeric kind is a JavaScript number: the encoder converts to float64 itself, so integers beyond 2^53 lose precision on the wire, whether they arrive as a scalar field or as an integer enum member. There is no BigInt. Enum members that share one underlying value are admitted: they share one wire value, which decodes to the first member declaring it. time.Time is the same string encoding/json produces, never a JavaScript Date. A required nil slice encodes as an empty array; a nil pointer where a value is required is an encode error. An absent Optional is no property at all; an absent Nullable is null. Unions encode as one object whose discriminator property holds the concrete type name.
Decoders are strict. They reject a missing required property, an unknown property, a value of the wrong kind, undefined, null where the field is not Nullable, an array whose length does not match a Go array’s, an enum non-member, an unknown union tag, and every devalue tagged form (Date, Map, Set, BigInt, RegExp, ArrayBuffer, boxed primitives), since the grammar admits none of them. Every diagnostic names a JSON-pointer-style path.
Encoders never dedupe: a fresh object and slice is built per value. Reducers and revivers are a caller concern; pass them to devalue.StringifyWith and devalue.Parse together with the generated encoder or decoder.
Limitations
Section titled “Limitations”An anonymous struct type is supported as a definition’s own type and as the direct value of a Required, Optional or Nullable field — positions the emitted code reaches through field selectors on the parent value. Anywhere else — under a slice, an array or a pointer, or as a root — it is refused with a diagnostic naming the grammar path, because the emitter would have to declare a variable of that type: Go type identity includes struct tags, and the grammar does not carry them, so a spelled type would not be assignable.
- func Generate(defs typegrammar.Definitions, roots []typegrammar.Type, opts Options) ([]byte, error)
- type Options
func Generate
Section titled “func Generate”func Generate(defs typegrammar.Definitions, roots []typegrammar.Type, opts Options) ([]byte, error)Generate emits one Go source file holding, for each definition and each root, an encoder and a strict decoder as free functions over the type’s exported fields, plus Stringify and Parse wrappers. It never mutates defs.
type Options
Section titled “type Options”Options configures the emitted file.
type Options struct { // PackageName is the package clause of the emitted file. PackageName string // ImportPath is the import path of the package the file will live in. // Types declared there are referenced unqualified, so the file never // imports itself. ImportPath string}Generated by gomarkdoc