Documentation
¶
Overview ¶
Package semantic — @default literal validation: type/element support, primitive-kind map, helpers.
Binding type-shape rules: which field types may ride @path / @query / @header / @cookie / @form, and the human-readable type description used in their diagnostics.
Numeric-bound sanity checks: unsigned vs negative bounds, integer capacity overflow, fractional literals on integer targets, and numeric-decorator targeting rules.
Collection shape checks: map-key comparability/marshalability and @uniqueItems element comparability, including generic-argument substitution.
Cross-decorator combination rules (defaults, bindings, single-binding, passthrough body) + ref walking helpers.
Symbol-table population + cross-file package-name check + extend-service merge.
Decorator duplicate / scope / conflict / sensitive checks.
Diagnostic code constants + helper builders.
`file` placement checks: uploads must sit at the top level of a request body where the multipart binder can reach them.
Method-level combination checks: request body type, body-verb rules, @status(204) bodies, and @passthrough constraints.
Path-binding checks: auto-@path promotion, duplicate path variables (method-local and @prefix-crossing), and the full-route path-variable set the request auto-binding rule reads.
Decorator placement checks (decl, field, scope).
Project-level declaration checks: cross-package extend orphans, service / middleware name uniqueness, and @middlewares / @errors reference resolution against the full project.
Project-level field checks: @default / @example literal validation with cross-package scalar and enum resolution.
Project-level mixin expansion checks: cross-package mixin resolution, duplicate-embed rejection, and promoted-field collision detection.
Resolved field IR: the single, LAYER-AGNOSTIC view of a field's resolved facts — what the field MEANS in the DSL (its category, underlying primitive, home package, nilability), independent of how Go renders it. The LSP and the semantic checks read these directly; codegen derives the Go-specific bits (the *T pointer wrap, the json tag, the Go type string) from them. Computing each fact ONCE here is what stops the recurring "semantic resolves a scalar one way, codegen another" drift (e.g. the cross-package-promoted scalar nilability gap).
Package semantic performs whole-package validation on parsed ast.File values and produces a merged, name-indexed Package for downstream tools.
Responsibilities:
- Package-name consistency across files.
- Symbol tables for types, enums, errors, scalars, middlewares.
- Primary / `extend service` merge.
- Duplicate names (top-level, fields, methods, routes) and uniform enum value kinds.
- Decorator placement, arity, argument literal types, value-set enums, cross-references (errors / middlewares / security schemes / requiresOneOf field idents), and value-range checks.
- Field-type compatibility for validator decorators (string validators only on strings, etc.).
- Mixin field expansion: cycle, conflict, and generic-arity detection.
- Generic instantiation: arg arity, non-generic-with-args, and type-parameter scoping.
Single-package Analyze uses a folder-merge import model and rejects qualified names; AnalyzeProject resolves cross-package qualified refs against the project's package set. Diagnostics carry stable lexer.Diagnostic.Code identifiers (`decorator/arity`, `mixin/conflict`, `generic/arity`, …) so the LSP and docs site can reference each rule individually.
Service-method shape checks (uniqueness, route collisions) + PathString helper.
Wire-name and binding-decorator combination checks: duplicate wire names (explicit and auto-bound), single-binding, and overlapping bound forms.
Index ¶
- Constants
- Variables
- func Analyze(files []*ast.File) (*Package, []Diagnostic)
- func AnalyzeProject(files []*ast.File, opts Options) (*Project, []Diagnostic)
- func AnalyzeWith(files []*ast.File, opts Options) (*Package, []Diagnostic)
- func MethodNameCounts(pkg *Package) map[string]int
- func MethodRoutePathVars(m *ast.Method, services map[string]*ServiceInfo) map[string]bool
- func NilableScalarPrimitive(prim string) bool
- func OperationBaseName(svcName string, m *ast.Method, counts map[string]int) string
- func OperationID(m *ast.Method, base string) string
- func PathShape(p *ast.Path) string
- type ArgKind
- type ArgsRule
- type Diagnostic
- type FieldCategory
- type Level
- type Options
- type Package
- type Prims
- type Project
- type ResolvedField
- type ServiceInfo
- type Spec
Constants ¶
const ( // CodeDecoratorUnknown fires when `@name` is not in the registry. // Decorators are a closed set by design (no escape-hatch). CodeDecoratorUnknown = "decorator/unknown" // CodeDecoratorPlacement fires when a known decorator appears at a // site outside its declared [Spec.Levels]. CodeDecoratorPlacement = "decorator/placement" // CodeDecoratorDuplicate fires when the same `@name` appears twice // in the same scope. Args do not disambiguate. CodeDecoratorDuplicate = "decorator/duplicate" // CodeDecoratorArity fires when the count of arguments to `@name` // is below ArgMin or above ArgMax. CodeDecoratorArity = "decorator/arity" // CodeDecoratorArgType fires when an argument literal kind does // not match the expected ArgKind for the position. CodeDecoratorArgType = "decorator/argtype" // CodeDecoratorArgValue fires when an argument value falls outside // the allowed enum set (e.g. `@format(garbage)`). CodeDecoratorArgValue = "decorator/argvalue" // CodeDecoratorRange fires when a numeric pair is out of order // (e.g. `@length(20, 5)`) or violates a per-decorator bound. CodeDecoratorRange = "decorator/range" // CodeDecoratorTypeMismatch fires when a validator decorator is // applied to an incompatible field/scalar primitive (e.g. // `@length` on `int`). CodeDecoratorTypeMismatch = "decorator/typemismatch" // CodeDecoratorRef fires when a decorator argument names an entity // (error / middleware / field / security scheme) that does not // exist in scope. CodeDecoratorRef = "decorator/ref" // CodeDecoratorRedundant fires when two decorators say the same // thing redundantly (warning, not error). Example: `@nullable` // on a `T?` field. CodeDecoratorRedundant = "decorator/redundant" // CodeDecoratorConflict fires when two decorators on the same site // have semantics that contradict. Example: `@sensitive` paired with // a wire-shaping validator like `@length` (sensitive fields never // cross the wire so wire-level constraints are meaningless). CodeDecoratorConflict = "decorator/conflict" // CodeDefaultNeedsOptional fires (severity warning) when `@default` is // placed on a non-optional, non-`@path` field. The default fires when the // value is absent, so the field is conceptually optional; `craftgo fmt` // adds the `?` on save, after which types.go, validate.go, and the OpenAPI // agree (optional + nullable). Until then the artifacts can disagree. CodeDefaultNeedsOptional = "decorator/default-needs-optional" // CodeFlagEmptyParens fires (severity warning) when a Flag // decorator (one that never takes arguments) is written with empty // parens — `@positive()` instead of `@positive`. Warning only: // `craftgo fmt` strips the parens on save so canonical form is // parens-free. CodeFlagEmptyParens = "decorator/flag-empty-parens" // CodeArgPreferIdent fires (severity warning) when a decorator // argument names a registered identifier (format name, security // scheme, ...) but the source spells it as a quoted string. The // canonical form is bare ident — `@format(email)` not // `@format("email")`. `craftgo fmt` rewrites on save. CodeArgPreferIdent = "decorator/arg-prefer-ident" // CodeBoundOverflow fires when a numeric bound literal exceeds // the field type's capacity. `int8 @lte(300)` — 300 overflows // int8 (max 127). Without this check codegen emits an untyped // integer literal that fails to compile against the typed field. CodeBoundOverflow = "decorator/bound-overflow" // CodeBoundEmptyRange fires when two comparison decorators on the // same field define an empty value set. `@gt(5) @lt(5)`, // `@gte(N) @lt(N)`, and `@gt(N) @lte(N)` all reject every value. CodeBoundEmptyRange = "decorator/empty-range" // CodeMutExSingleField fires when `@mutuallyExclusive` is given // fewer than 2 fields. The runtime check (`n > 1`) is provably // unreachable. CodeMutExSingleField = "decorator/single-field-mutex" // CodeDuplicateGroupField fires when a cross-field validator // (`@requiresOneOf`, `@mutuallyExclusive`) lists the same field // name twice. Codegen would emit `v.A == nil && v.A == nil` which // `go vet` rejects as a redundant boolean expression. CodeDuplicateGroupField = "decorator/duplicate-group-field" // CodeCrossFieldNotOptional fires when a cross-field validator // (`@requiresOneOf`, `@mutuallyExclusive`) references a field that // is neither optional (`?`) nor `@nullable`. Presence is then // ambiguous: OpenAPI expresses the group with key-presence // (`required` / `not.required`) while the runtime validator falls // back to zero-value emptiness (`== ""` / `== 0`), so the spec and // the server disagree on whether an empty-but-present value counts. // Requiring pointer-backed fields makes "present" mean the same // thing on both sides. CodeCrossFieldNotOptional = "decorator/cross-field-not-optional" // CodeMapKeyType fires when a map key type is not a usable, JSON- // serialisable map key. A generic type-parameter or a non-comparable // type fails to compile; a bool / float / struct key compiles but // json.Marshal cannot serialise it (JSON object keys are strings). Only // a string / int* / uint* key, or a scalar / enum over one, is allowed. CodeMapKeyType = "type/map-key" // CodeDuplicatePathVar fires when a route template repeats a path // variable name (`/items/{id}/x/{id}`). net/http's ServeMux panics on // a duplicate wildcard at registration. CodeDuplicatePathVar = "route/duplicate-path-var" // CodeDuplicateWireName fires when two request fields bind to the same // wire parameter name on the same source (`a @query("x") b // @query("x")`). The OpenAPI emits a duplicate (name, in) parameter // (an invalid spec) and the binder reads the same value into both. CodeDuplicateWireName = "binding/duplicate-wire-name" // CodePackageMismatch fires when files disagree on the `package` // name. CodePackageMismatch = "decl/package-mismatch" // CodeDuplicateDecl fires when two top-level declarations share a // name across the merged package. CodeDuplicateDecl = "decl/duplicate" // CodeDeclBuiltinName fires when a type / enum / scalar / error is // named after a built-in type spelling (`int`, `string`, `any`, ...). // The generated Go type would shadow the built-in and fail to compile. CodeDeclBuiltinName = "decl/builtin-name" // CodeDeclNameCase fires (severity warning) when a top-level decl // - type / error / enum / service / middleware / scalar - does // not start with an uppercase letter. Lower-case decl names are // emitted verbatim by codegen, producing UNEXPORTED Go types // that cannot be imported across packages. CodeDeclNameCase = "decl/name-case" // CodeFieldNameCollision fires (severity warning) when two field // names in the same type / error body normalise to the same Go // identifier under [internal/idents.GoFieldName] (e.g. `user_id` // and `userId` both → `UserID`). Codegen still emits the struct // using `_2`, `_3`, ... suffixes so the result compiles, but // the JSON wire shape carries both DSL names verbatim - a quiet // schema duplication the user almost certainly did not intend. CodeFieldNameCollision = "field/name-collision" // CodeEnumValueCollision fires (severity warning) when two enum // values in the same enum normalise to the same Go const name // (e.g. `created` and `Created` both → `<Enum>Created`). // Codegen emits the trailing duplicates with `_2`, `_3`, ... // suffixes so the package compiles, but the wire payload // (string or int) of both values stays distinct - a quiet // duplication the user usually did not intend. CodeEnumValueCollision = "enum/value-collision" // CodeDeclGoNameCollision fires (severity ERROR) when two // top-level decls in the same package produce the same Go // identifier under codegen's name-mangling rules. Examples // caught by this rule: // // - `type FooErr` + `error Foo` - both emit `type FooErr` // - `type FooBody` + `error Foo { ... }` - both emit `type FooBody` // - `type FooMiddleware` + `middleware Foo` - same // // Auto-suffixing decls would silently rename a symbol the user // references in their own Go code, so this is a hard error // rather than the soft warning used for FIELD-level dedup. CodeDeclGoNameCollision = "decl/go-name-collision" // CodeDuplicateField fires when two fields in the same type / error // body share a name. CodeDuplicateField = "field/duplicate" // CodeInvalidGoName fires when a field name maps to an invalid Go // identifier — empty (e.g. `_`, `__`) or digit-leading (e.g. `_2`, // which normalises to `2`). Codegen would emit uncompilable / unexported // Go, so reject at design time with a clean message instead. CodeInvalidGoName = "field/invalid-go-name" // CodeEnumDuplicateName fires for two enum values with the same // identifier. CodeEnumDuplicateName = "enum/duplicate-name" // CodeEnumMixedTypes fires when an enum mixes bare / int / string // values. CodeEnumMixedTypes = "enum/mixed-types" // CodeEnumDuplicateLiteral fires when two enum values share an // int or string literal. CodeEnumDuplicateLiteral = "enum/duplicate-literal" // CodeEnumEmpty fires when an `enum X { }` has zero values. An // empty enum has no value that passes validation and emits // `enum: []` which violates JSON Schema 2020-12. CodeEnumEmpty = "enum/empty-values" // CodeServiceDuplicate fires for two primary `service` decls of // the same name. CodeServiceDuplicate = "service/duplicate" // CodeServiceExtendOrphan fires when an `extend service` has no // primary declaration in the package. CodeServiceExtendOrphan = "service/extend-orphan" // CodeExtendDecoratorNotMethod fires when an `extend service` block // carries a decorator that has no method-level form (e.g. `@prefix`). // Such decorators must sit on the primary service declaration; // putting them on an extend block would propagate to every method // in the block, which is meaningless for service-only directives. CodeExtendDecoratorNotMethod = "service/extend-decorator-not-method" // CodeServiceDuplicateMethod fires for two methods sharing a name // inside one service (after extends merge). CodeServiceDuplicateMethod = "service/duplicate-method" // CodeServiceDuplicateRoute fires for two methods sharing the // same VERB+path tuple (after extends merge). CodeServiceDuplicateRoute = "service/duplicate-route" // CodeBindingConflict fires when a field has more than one of // `@path / @query / @header / @cookie / @body / @form`. CodeBindingConflict = "binding/conflict" // CodeBindingType fires when `@path`, `@header`, or `@cookie` is // applied to a field whose type is not a non-array, non-optional // `string`. The wire formats those decorators target carry only // strings (URL segments, header values, cookie values), and the // codegen would otherwise silently skip the field at gen time - // surfacing the mismatch at design time gives the author an // actionable error. CodeBindingType = "binding/type" // CodeBindingVerb fires when `@body` or `@form` sits on a request // field of a non-body verb (GET / HEAD / DELETE / OPTIONS). Those // handlers decode no request body, so the field would be silently // dropped at gen time — surfacing it at design time prevents the // silent data loss. CodeBindingVerb = "binding/verb" // CodeFilePosition fires when a `file` field appears where the // multipart binder cannot reach it: inside a response type, or nested // below the top level of a request body. The form-binding codegen scans // only the resolved top-level request fields, so a `file` elsewhere is // silently emitted as a JSON-encoded `*multipart.FileHeader` the server // can never populate. `file` is valid only as a top-level request field // (directly or carried in via a mixin). CodeFilePosition = "binding/file-position" // CodeServiceCollision fires when two packages in the same // project both declare a primary `service` of the same name. // The generated codegen layout keys output directories by // service name (`internal/routes/<svc>/`, `internal/handler/<svc>/`), // so a collision would silently overwrite one package's // scaffolds with the other's. Surface every conflicting // declaration so the author can rename one. CodeServiceCollision = "service/collision" // CodeMiddlewareCollision fires when two packages in the same // project both declare a `middleware` of the same name. Cross- // package middleware references are global by design, so a // collision would make `@middlewares(Name)` ambiguous - the // resolver picks the first match silently. The diagnostic // surfaces every conflicting declaration so the author can // rename or consolidate. CodeMiddlewareCollision = "middleware/collision" // CodePassthroughBody fires when a method tagged `@passthrough` // declares a `request` or `response` block. Passthrough endpoints // hand the raw `http.ResponseWriter` and `*http.Request` to logic; // any framework-side request/response shape would be ignored, so // the analyser rejects the mistake up front. CodePassthroughBody = "passthrough/has-body" // CodeQualifiedRef fires for a `pkg.Type` reference. The current // resolver uses folder-merge imports and rejects qualified names. CodeQualifiedRef = "ref/qualified" // CodeMixinUnresolved fires when a mixin reference does not name // a type declared in the package. CodeMixinUnresolved = "mixin/unresolved" // CodeMixinNonType fires when a mixin reference resolves to a // non-type entity (enum, error, scalar, middleware). CodeMixinNonType = "mixin/non-type" // CodeMixinCycle fires when expanding a mixin would loop back // onto a type already on the expansion stack. CodeMixinCycle = "mixin/cycle" // CodeMixinConflict fires when expansion produces two fields // with the same name (mixin vs host or mixin vs mixin). CodeMixinConflict = "mixin/conflict" // CodeMixinArity fires when a generic mixin's argument count // disagrees with the target's TypeParams count. CodeMixinArity = "mixin/arity" // CodeGenericArity fires when a generic instance's argument count // disagrees with the target decl's TypeParams. CodeGenericArity = "generic/arity" // CodeGenericNonGeneric fires when a non-generic type is referenced // with `<...>` arguments. CodeGenericNonGeneric = "generic/non-generic" // CodeGenericOptionalArg fires when a generic type argument carries a // trailing `?` (`Page<Item?>`). The optionality has no single, well- // defined position once the argument is substituted into the decl's // body, so the Go type and the OpenAPI schema disagree about whether it // applies to the element or the surrounding collection. Declare the // nullability on a concrete field of the generic instead. CodeGenericOptionalArg = "generic/optional-arg" // CodePathBaseFormat warns when [Options.BasePath] is malformed - // missing leading slash, trailing slash, or contains `//`. Code- // gen normalises these so this is a warning, not an error. CodePathBaseFormat = "path/base-format" // CodePathCollision fires when two methods (across any service) // resolve to the same VERB + final-path tuple. CodePathCollision = "path/collision" // CodeDuplicateOperation fires when two methods resolve to the same // OpenAPI operationId — auto-prefixing removes same-method-name // collisions, so a survivor comes from an explicit `@operationId(...)` // that two methods share (or that equals another method's auto id), // which would emit an invalid spec. CodeDuplicateOperation = "operation/duplicate-id" // CodePathParamMissing fires when a `{name}` segment in the // resolved route has no corresponding field binding in the // method's request type. CodePathParamMissing = "path/param-missing" // CodePathParamOrphan fires when a request field uses `@path` / // `@path("name")` but the resolved route has no matching // `{name}` segment. CodePathParamOrphan = "path/param-orphan" // CodePathHealthConflict fires when a user-declared method's // resolved route equals one of the runtime-reserved health paths // (`/healthz`, `/readyz` by default). CodePathHealthConflict = "path/health-conflict" // CodeImportUnresolved fires when `import "path"` does not // correspond to a folder under the design root. CodeImportUnresolved = "import/unresolved" // CodeImportEscape fires when an import path uses `..` or starts // with `/` to escape the design root. CodeImportEscape = "import/escape" // CodeImportDuplicate fires when one file imports the same path // twice (with or without matching aliases) - a clear redundancy // the parser cannot detect without per-file context. CodeImportDuplicate = "import/duplicate" // CodeImportAliasConflict fires when two imports in the same // file resolve to the same alias (explicit or implicit), making // later qualified references like `alias.Type` ambiguous. CodeImportAliasConflict = "import/alias-conflict" // CodeImportSelf fires when a file imports a folder whose files // share its own `package X` declaration - the import is a no-op // since the analyser already merges them by package name. CodeImportSelf = "import/self" // CodeRefUnknownPackage fires when `pkg.Type` references a // package whose `package X` declaration doesn't appear anywhere // in the project. CodeRefUnknownPackage = "ref/unknown-package" // CodeRefUnknownSymbol fires when the package resolves correctly // but doesn't declare the named type. CodeRefUnknownSymbol = "ref/unknown-symbol" // CodeScalarBadPrimitive fires when a `scalar Name Primitive` // declaration uses a non-builtin word in the primitive slot // (e.g. another type name, a typo, or the scalar's own name). // The scalar's underlying type must be a primitive the framework // knows how to validate; user-defined types in this slot would // silently break inheritance and produce invalid Go. CodeScalarBadPrimitive = "scalar/bad-primitive" )
Variables ¶
var Registry = map[string]Spec{ "doc": { Name: "doc", Levels: LvlFile | LvlType | LvlField | LvlService | LvlMethod | LvlEnum | LvlEnumValue | LvlError | LvlScalar | LvlMiddleware | LvlErrorField, Doc: "Free-form documentation surfaced in OpenAPI and IDE hover.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgString}}, }, "deprecated": { Name: "deprecated", Levels: LvlFile | LvlType | LvlField | LvlService | LvlMethod | LvlEnumValue | LvlMiddleware | LvlErrorField, Doc: "Marks the construct as deprecated; OpenAPI emits the deprecated flag.", Args: ArgsRule{Min: 0, Max: 1, Kinds: []ArgKind{ArgString}}, }, "example": { Name: "example", Levels: LvlField | LvlErrorField, Doc: "Example value rendered in the OpenAPI schema for this field. Argument is a literal (string / int / float / bool / null) or an array of those. Object examples are not accepted — a struct example is composed from each field's own @example; document a free-form any/map field's shape with @doc.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgAny}}, }, "version": { Name: "version", Levels: LvlFile, Doc: "OpenAPI document version (overrides craftgo.design.yaml openapi.version).", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgString}}, }, "requiresOneOf": { Name: "requiresOneOf", Levels: LvlType, Doc: "At least one of the listed fields must be present. Args: variadic idents/strings or a single array literal.", Args: ArgsRule{ Min: 1, Max: -1, Variadic: ArgStringOrIdent, AllowArrayShortcut: true, }, }, "mutuallyExclusive": { Name: "mutuallyExclusive", Levels: LvlType, Doc: "At most one of the listed fields may be present. Args: variadic idents/strings or a single array literal.", Args: ArgsRule{ Min: 1, Max: -1, Variadic: ArgStringOrIdent, AllowArrayShortcut: true, }, }, "length": { Name: "length", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Exact or [min,max] length for strings.", Args: ArgsRule{Min: 1, Max: 2, Kinds: []ArgKind{ArgInt, ArgInt}}, AppliesTo: PrimString, }, "minLength": { Name: "minLength", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Minimum string length.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgInt}}, AppliesTo: PrimString, }, "maxLength": { Name: "maxLength", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Maximum string length.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgInt}}, AppliesTo: PrimString, }, "pattern": { Name: "pattern", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "RE2 regex the value must match.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgString}}, AppliesTo: PrimString, }, "format": { Name: "format", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Named format constraint (e.g. email, uuid, datetime).", Args: ArgsRule{ Min: 1, Max: 1, Kinds: []ArgKind{ArgStringOrIdent}, Enum: formatValues, }, AppliesTo: PrimString, }, "gt": { Name: "gt", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Value must be strictly greater than N (x > N).", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgNumber}}, AppliesTo: PrimNumber, }, "gte": { Name: "gte", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Value must be greater than or equal to N (x >= N).", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgNumber}}, AppliesTo: PrimNumber, }, "lt": { Name: "lt", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Value must be strictly less than N (x < N).", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgNumber}}, AppliesTo: PrimNumber, }, "lte": { Name: "lte", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Value must be less than or equal to N (x <= N).", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgNumber}}, AppliesTo: PrimNumber, }, "range": { Name: "range", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Numeric range [min, max] — both bounds inclusive.", Args: ArgsRule{Min: 2, Max: 2, Kinds: []ArgKind{ArgNumber, ArgNumber}}, AppliesTo: PrimNumber, }, "positive": {Name: "positive", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Value must be > 0.", AppliesTo: PrimNumber, Flag: true}, "negative": {Name: "negative", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Value must be < 0.", AppliesTo: PrimNumber, Flag: true}, "multipleOf": { Name: "multipleOf", Levels: LvlField | LvlScalar | LvlErrorField, Doc: "Value must be a multiple of N.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgNumber}}, AppliesTo: PrimNumber, }, "minItems": { Name: "minItems", Levels: LvlField | LvlErrorField, Doc: "Minimum array / map length.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgInt}}, AppliesTo: PrimArray, }, "maxItems": { Name: "maxItems", Levels: LvlField | LvlErrorField, Doc: "Maximum array / map length.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgInt}}, AppliesTo: PrimArray, }, "uniqueItems": {Name: "uniqueItems", Levels: LvlField | LvlErrorField, Doc: "Array elements must be unique.", AppliesTo: PrimArray, Flag: true}, "maxSize": { Name: "maxSize", Levels: LvlField, Doc: "Upload size cap (bytes / KB / MB / GB).", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgSize}}, AppliesTo: PrimFile, }, "mimeTypes": { Name: "mimeTypes", Levels: LvlField, Doc: "Allowed Content-Type list for uploads. Args: variadic strings or a single array literal.", Args: ArgsRule{Min: 1, Max: -1, Variadic: ArgString, AllowArrayShortcut: true}, AppliesTo: PrimFile, }, "default": { Name: "default", Levels: LvlField | LvlErrorField, Doc: "Default value applied when field absent.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgAny}}, }, "nullable": {Name: "nullable", Levels: LvlField | LvlErrorField, Doc: "Marks the field as accepting an explicit JSON null.", Flag: true}, "sensitive": { Name: "sensitive", Levels: LvlField | LvlErrorField, Flag: true, Doc: "Server-only field: tagged `json:\"-\"` so neither the request decoder nor the response encoder touches it, and skipped entirely from OpenAPI. Cannot combine with any wire-shaping decorator: validators (@length / @gt / @gte / @lt / @lte / @range / @pattern / @format / @minItems / @maxItems / @multipleOf / @positive / @negative / @uniqueItems / @requiresOneOf / @mutuallyExclusive), nullability / defaults (@nullable / @default), or any binding (@body / @path / @query / @header / @cookie / @form). The field stays as a Go struct member that server logic populates / reads internally.", }, "path": {Name: "path", Levels: LvlField, Doc: "Bind from URL path parameter.", Args: ArgsRule{Min: 0, Max: 1, Kinds: []ArgKind{ArgString}}}, "query": {Name: "query", Levels: LvlField, Doc: "Bind from URL query string.", Args: ArgsRule{Min: 0, Max: 1, Kinds: []ArgKind{ArgString}}}, "header": {Name: "header", Levels: LvlField | LvlErrorField, Doc: "Bind from HTTP request header (request fields) or write to response header (error fields).", Args: ArgsRule{Min: 0, Max: 1, Kinds: []ArgKind{ArgString}}}, "cookie": {Name: "cookie", Levels: LvlField | LvlErrorField, Doc: "Bind from HTTP cookie (request fields) or set a response cookie (error fields).", Args: ArgsRule{Min: 0, Max: 1, Kinds: []ArgKind{ArgString}}}, "body": {Name: "body", Levels: LvlField, Doc: "Bind from request body.", Args: ArgsRule{Min: 0, Max: 1, Kinds: []ArgKind{ArgString}}}, "form": {Name: "form", Levels: LvlField, Doc: "Bind from multipart form field.", Args: ArgsRule{Min: 0, Max: 1, Kinds: []ArgKind{ArgString}}}, "prefix": { Name: "prefix", Levels: LvlService, Doc: "Path prefix prepended to every method route.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgString}}, }, "group": { Name: "group", Levels: LvlService, Doc: "Nests the service's generated handlers and service stubs under <service>/<group>/ on disk and adds its value as an OpenAPI tag on every method; does not affect the route or OpenAPI path. Accepts a nested path like \"admin/ops\".", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgString}}, }, "middlewares": { Name: "middlewares", Levels: LvlService | LvlMethod, Doc: "Apply named middlewares; method-level appends to service-level chain. Args: variadic idents or a single array literal.", Args: ArgsRule{Min: 1, Max: -1, Variadic: ArgIdent, AllowArrayShortcut: true}, Repeatable: true, }, "tags": { Name: "tags", Levels: LvlService | LvlMethod, Doc: "OpenAPI tags. Method-level appends to service-level. Args: variadic idents/strings or a single array literal.", Args: ArgsRule{Min: 1, Max: -1, Variadic: ArgStringOrIdent, AllowArrayShortcut: true}, Repeatable: true, }, "security": { Name: "security", Levels: LvlService | LvlMethod, Doc: "Security scheme requirements (OpenAPI metadata). Args: variadic scheme idents or a single array literal. Within one decorator the schemes AND-combine; multiple `@security(...)` decorators OR-combine.", Args: ArgsRule{Min: 1, Max: -1, Variadic: ArgIdent, AllowArrayShortcut: true}, Repeatable: true, }, "ignoreMiddleware": { Name: "ignoreMiddleware", Levels: LvlMethod, Doc: "Clear the inherited @middlewares chain on this method. Method-level @middlewares(...) then start from empty instead of appending to the service-level chain.", Args: ArgsRule{Min: 0, Max: 0}, }, "ignoreSecurity": { Name: "ignoreSecurity", Levels: LvlMethod, Doc: "Clear the inherited @security chain on this method. Useful for public endpoints inside an otherwise-authenticated service.", Args: ArgsRule{Min: 0, Max: 0}, }, "ignoreTags": { Name: "ignoreTags", Levels: LvlMethod, Doc: "Clear the inherited @tags list on this method. Method-level @tags(...) then start from empty.", Args: ArgsRule{Min: 0, Max: 0}, }, "summary": {Name: "summary", Levels: LvlMethod, Doc: "One-line OpenAPI operation summary.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgString}}}, "operationId": {Name: "operationId", Levels: LvlMethod, Doc: "Override OpenAPI operationId.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgString}}}, "errors": {Name: "errors", Levels: LvlMethod, Doc: "Declared error responses for OpenAPI. Args: variadic error idents or a single array literal.", Args: ArgsRule{Min: 1, Max: -1, Variadic: ArgIdent, AllowArrayShortcut: true}, Repeatable: true}, "status": {Name: "status", Levels: LvlMethod, Doc: "Override default success status code.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgInt}}}, "passthrough": {Name: "passthrough", Levels: LvlMethod, Doc: "Bypass framework parsing - logic receives the raw http.ResponseWriter and *http.Request and writes the response directly.", Flag: true}, "timeout": {Name: "timeout", Levels: LvlMethod, Doc: "Cap the handler's execution time. Returns 503 + cancels context when the deadline elapses.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgDuration}}}, "maxBodySize": {Name: "maxBodySize", Levels: LvlMethod, Doc: "Cap the request body size in bytes. Two enforcement points fire: Content-Length pre-check returns 413 immediately when the declared size exceeds the cap, and MaxBytesReader wraps r.Body so reads past the cap surface as a 400 Read error. Multipart parsers also lift their in-memory budget to this value.", Args: ArgsRule{Min: 1, Max: 1, Kinds: []ArgKind{ArgSize}}}, }
Registry is the closed set of decorators the framework recognises. A `@name` not present here is reported as `decorator/unknown` - there is no escape-hatch by design (see README §"Triết lý").
Levels mirror the table in README §"Decorator compatibility matrix"; keep the two in sync. When in doubt the README table wins, because users read it first.
Functions ¶
func Analyze ¶
func Analyze(files []*ast.File) (*Package, []Diagnostic)
Analyze validates the supplied AST files as a single package and returns the merged Package together with every diagnostic found. The Package value is always non-nil even when diagnostics were reported, so callers (codegen, LSP) can do best-effort downstream work.
Equivalent to AnalyzeWith(files, Options{}).
func AnalyzeProject ¶
func AnalyzeProject(files []*ast.File, opts Options) (*Project, []Diagnostic)
AnalyzeProject parses files into packages keyed by their location under [Options.DesignRoot] and validates cross-package qualified references. The returned Project is always non-nil; consumers may inspect partial results even when diagnostics are reported.
When [Options.DesignRoot] is empty, AnalyzeProject delegates to AnalyzeWith and returns a single-package Project under key "". That makes it safe for the LSP to call AnalyzeProject unconditionally without pre-checking layout.
func AnalyzeWith ¶
func AnalyzeWith(files []*ast.File, opts Options) (*Package, []Diagnostic)
AnalyzeWith is the Analyze variant that accepts cross-reference truth sources. CLI / codegen invocations supply the project's `craftgo.design.yaml` data here; the LSP either supplies the same (when it has read the manifest) or leaves it empty for syntax-only validation.
func MethodNameCounts ¶ added in v1.2.0
MethodNameCounts counts how many times each method name appears across every service. A name shared by two services must be service-qualified in the emitted operationId / component names so they stay globally unique.
func MethodRoutePathVars ¶ added in v1.4.0
MethodRoutePathVars returns the path-variable names in method m's full registered route — its owning service's @prefix variables PLUS the method path variables. The auto-binding rule ([RequestFieldBinding]) and the auto-@path / body-verb checks read this rather than the method path alone, so they agree with the route that actually registers: a field whose name matches a @prefix variable auto-binds to @path exactly like one matching a method-path variable (without it, the field would wrongly fall through to @query on a GET or @body on a POST, and the path value would never bind). services is the analysed package's service table (pkg.Services), used to find m's owning service for its prefix.
func NilableScalarPrimitive ¶ added in v1.3.0
NilableScalarPrimitive reports whether a scalar's underlying primitive lowers to a Go type that already holds nil (so a scalar over it renders without a pointer wrap): the `bytes` slice and the `any` interface. It is the single authority both the resolved IR (ResolveField) and codegen's pointer-wrap decision cite, so the two layers can't disagree on whether a scalar field needs a `*T`.
func OperationBaseName ¶ added in v1.2.0
OperationBaseName is the collision-free base for a method's component schema names (`<base>ReqBody`, `<base>RespBody`) and its default operationId: bare when the method name is unique project-wide, service-prefixed when shared.
func OperationID ¶ added in v1.2.0
OperationID returns a method's operationId: an explicit, non-empty `@operationId("...")` override when present, otherwise base.
func PathShape ¶
PathShape is PathString with every {param} replaced by `{}`. Two routes that route to the same HTTP destination have the same shape even when their parameter names differ — e.g. `/u/{id}` and `/u/{userId}` both reduce to `/u/{}`. Collision-detection keys MUST use this rather than PathString, otherwise a parameter rename silently bypasses the duplicate guard and net/http's mux panics at boot when both routes try to register against the same pattern.
Types ¶
type ArgKind ¶
type ArgKind uint8
ArgKind classifies the literal shape expected at a positional argument slot. The argument-validation pass maps an ast.Expr to one of these kinds and rejects mismatches with CodeDecoratorArgType.
const ( // ArgAny accepts any expression. Use sparingly - prefer a tighter // kind so the IDE can give a useful "expected X" hint. ArgAny ArgKind = iota // ArgString matches a [ast.StringLit] (regular or raw). ArgString // ArgInt matches a [ast.IntLit]. ArgInt // ArgNumber matches int OR float. ArgNumber // ArgBool matches a [ast.BoolLit]. ArgBool // ArgIdent matches a bare identifier ([ast.IdentExpr]). ArgIdent // ArgDuration matches a [ast.DurationLit] (`5s`, `100ms`, ...). ArgDuration // ArgSize matches a [ast.SizeLit] (`1MB`, `8KB`, ...). ArgSize // ArgStringOrIdent accepts either, used by `@tags` where humans // commonly write `@tags(users)` and `@tags("user-mgmt")` // interchangeably. ArgStringOrIdent )
type ArgsRule ¶
type ArgsRule struct {
// Min is the minimum number of positional arguments. 0 allows the
// no-args form (`@deprecated`).
Min int
// Max is the maximum number of positional arguments; -1 means
// unbounded (variadic).
Max int
// Kinds is the per-position expected kind. When the actual arg
// count exceeds len(Kinds), [Variadic] applies to the remainder.
Kinds []ArgKind
// Variadic is the kind for arguments beyond len(Kinds). Only
// meaningful when Max < 0 or Max > len(Kinds).
Variadic ArgKind
// Enum, when non-empty, restricts the first positional argument
// value (string OR ident) to this set. Used by `@format` to
// constrain string formats (`email`, `uuid`, ...).
Enum []string
// AllowArrayShortcut treats a single array-literal positional arg
// as variadic-equivalent. Used by `@requiresOneOf(["a","b"])`,
// `@mimeTypes(["a/b","c/d"])` etc., where humans naturally write
// the list in brackets. The array's elements are validated against
// [Variadic]; element count must still satisfy [Min]..[Max].
AllowArrayShortcut bool
}
ArgsRule captures the positional argument shape of a decorator. Named arguments (`name: value`), nested decorators, and object literals are validated by per-decorator hooks in [analyzer.checkArgsCustom] and do not appear here.
type Diagnostic ¶
type Diagnostic = lexer.Diagnostic
Diagnostic re-exports lexer.Diagnostic so semantic-layer callers do not need to import the lexer package directly.
type FieldCategory ¶ added in v1.3.0
type FieldCategory int
FieldCategory classifies a field's resolved type independent of Go syntax.
const ( CatUnknown FieldCategory = iota CatPrimitive // string / int* / uint* / float* / bool CatBytes // the `bytes` builtin (Go []byte) CatAny // the `any` builtin (Go interface{}) CatFile // the `file` builtin (Go *multipart.FileHeader) CatScalar // a `scalar Name <prim>` defined type CatEnum // an `enum Name { ... }` defined type CatStruct // a `type Name { ... }` struct CatArray // an array of any of the above CatMap // a map )
type Level ¶
type Level uint16
Level is a bitmask of declaration sites where a decorator may appear. A Spec OR-s the levels it accepts; the placement check passes when at least one bit overlaps with the current site. Single-bit values are used for diagnostic rendering - never combine bits when calling Level.Name.
const ( // LvlFile is a file-header decorator, before `package`. Examples: // `@doc("...")`, `@deprecated`. LvlFile Level = 1 << iota // LvlType is a `type Name { ... }` declaration. LvlType // LvlField is a field inside a `type` body. Fields inside an // `error` body use [LvlErrorField] instead so request-only and // validator decorators are rejected on server-emitted payloads. LvlField // LvlService is a `service Name { ... }` (primary only - `extend // service` rejects service-level decorators upstream). LvlService // LvlMethod is a method inside a service body. LvlMethod // LvlEnum is an `enum Name { ... }` declaration. LvlEnum // LvlEnumValue is a single value inside an enum body. LvlEnumValue // LvlError is an `error Cat Name [{ ... }]` declaration. LvlError // LvlScalar is a `scalar Name Primitive` declaration. LvlScalar // LvlMiddleware is a `middleware Name(...)` declaration. LvlMiddleware // LvlErrorField is a field inside an `error` body. Distinct from // [LvlField] because errors are server-emitted, so request-only // decorators (`@path`, `@query`, `@body`, `@form`, `@maxSize`, // `@mimeTypes`) are rejected. Schema validators (`@minLength`, // `@maxLength`, `@pattern`, `@gte`, ...) are accepted but // contribute only to OpenAPI schema constraints - codegen does // not generate a runtime `Validate()` for ErrorDecl types. LvlErrorField )
func (Level) Name ¶
Name returns the label for a single-bit level. It returns "unknown" for the zero value or a multi-bit mask - callers rendering a multi-bit mask should use Level.String instead.
type Options ¶
type Options struct {
// SecuritySchemes lists names declared in the OpenAPI manifest
// (`craftgo.design.yaml` openapi.securitySchemes). When nil the
// `@security(name)` reference check is skipped - there is no
// authoritative list to compare against. When non-nil, every
// scheme name must appear here or produce a [CodeDecoratorRef]
// diagnostic. To opt out of inherited security on a public
// endpoint use `@ignoreSecurity` (not a sentinel scheme name).
SecuritySchemes []string
// BasePath is the project's `openapi.basePath` from the manifest.
// Used by the path-resolution pass to compute final routes for
// cross-service collision detection and to surface `path/format`
// warnings on a malformed value. Empty disables basePath checks
// (as if no basePath were declared).
BasePath string
// HealthPaths overrides the default `/healthz`, `/readyz` reserved
// path set. Empty slice = default; nil also = default. A
// user-declared method matching one of these paths produces a
// `path/health-conflict` diagnostic.
HealthPaths []string
// DesignRoot is the absolute filesystem path of the project's
// design folder. When non-empty, [AnalyzeProject] splits files by
// subdirectory into separate packages and resolves cross-package
// qualified refs against each file's `import` declarations. When
// empty (or when calling [Analyze] / [AnalyzeWith]) the analyser
// behaves as a single-package merge.
DesignRoot string
// contains filtered or unexported fields
}
Options configure the analyser's optional cross-reference checks. Pass an empty Options for the default (no truth source for security schemes); the corresponding refs are then silently allowed.
type Package ¶
type Package struct {
// Name is the package name agreed on by every file with a `package`
// declaration. Empty when no file has one.
Name string
// Types maps `type Name { ... }` declarations by name.
Types map[string]*ast.TypeDecl
// Enums maps `enum Name { ... }` declarations by name.
Enums map[string]*ast.EnumDecl
// Errors maps `error Cat Name [{ ... }]` declarations by name.
Errors map[string]*ast.ErrorDecl
// Scalars maps `scalar Name Primitive` declarations by name.
Scalars map[string]*ast.ScalarDecl
// Middlewares maps `middleware Name(...)` declarations by name.
Middlewares map[string]*ast.MiddlewareDecl
// Services maps service names to the merged primary + extends bundle.
Services map[string]*ServiceInfo
}
Package is the merged result of analysing one or more ast.File from the same logical package. The maps are keyed by the unqualified declaration name; cross-package references are resolved by AnalyzeProject.
type Prims ¶
type Prims uint8
Prims is a bitmask of primitive type categories a validator decorator can target. Used by the field-type compatibility check (`@length` only makes sense on strings, `@uniqueItems` only on arrays, etc.). A zero value means "no constraint" - applies to anything, used by metadata decorators like `@doc`.
const ( // PrimString covers `string` and any scalar whose primitive is // string. Bytes/format/uri all reduce to this category. PrimString Prims = 1 << iota // PrimNumber covers signed/unsigned integers and floats. PrimNumber // PrimBool covers `bool`. PrimBool // PrimArray covers `T[]` and `map<K,V>` field shapes (arrays and // maps share validation: count, uniqueness). PrimArray // PrimFile covers the `file` primitive (multipart upload). PrimFile // PrimAny matches any field type - used by validator-style // decorators that don't care about primitive (e.g. `@example`). PrimAny Prims = 0 )
func PrimFromName ¶ added in v1.2.0
PrimFromName maps a built-in primitive name to its Prims category. Returns 0 for names this layer can't classify (custom types, `any`, `object` - those are handled by the caller). Exported so the LSP reuses the one classification instead of keeping its own copy.
type Project ¶
type Project struct {
// Root is the absolute design folder used for filesystem
// validation of `import "path"`. Empty when AnalyzeProject was
// called without [Options.DesignRoot] - in that case Packages
// holds the same single-package result as [Analyze].
Root string
// Packages maps `package X` name → analysed [Package].
Packages map[string]*Package
// FileImports maps file path → alias → relative import path
// (path is the value the user wrote in `import "path"`).
FileImports map[string]map[string]string
}
Project is the cross-package analysis result. Packages is keyed by the package's `package X` declaration name (the value of [Package.Name]), so files in any folder sharing the same name merge into a single entry. FileImports retains the per-file import metadata for LSP "go-to-definition" - at the analysis layer resolution uses package names directly, but the IDE benefits from knowing which folder each `import "path"` referred to.
type ResolvedField ¶ added in v1.3.0
type ResolvedField struct {
// Field is the source field (post generic-substitution / mixin
// promotion); stages needing the raw decorators or type ref read it here.
Field *ast.Field
DSLName string // the source field identifier (wire/json base name)
Category FieldCategory // the resolved type category
// ResolvedPrim is the underlying DSL primitive: the primitive itself for
// a primitive/bytes/any field, or the `scalar`'s primitive for a scalar
// field. "" for enum / struct / array / map / file / unresolved.
ResolvedPrim string
// HomePkg is the package the field's named type lives in — the qualifier
// of a `lib.X` ref, or the package a bare ref was resolved against (which,
// for a field promoted across a package boundary, is the mixin's home, NOT
// the using package). "" for a builtin primitive or an unresolved ref.
HomePkg string
// IsNilable reports whether the Go type holds nil directly (slice, map,
// bytes, any, file, or a scalar over a nilable primitive), so an optional
// `?` / `@nullable` use of it needs no redundant pointer wrap. This is the
// fact codegen's `*T` decision and the cross-field presence check must
// agree on.
IsNilable bool
}
ResolvedField is the layer-agnostic resolved view of one field. It is the floor every stage stands on: a fact read from here cannot disagree with another stage's, because it was computed once.
func ResolveField ¶ added in v1.3.0
func ResolveField(f *ast.Field, pkg *Package, proj *Project) ResolvedField
ResolveField computes the layer-agnostic facts for a single field. pkg is the field's HOME package — for a bare named ref it is resolved against pkg, so a field promoted from a sibling-package mixin must be resolved with that mixin's package as pkg (not the using package). proj resolves a qualified `lib.X` ref against its named package.
type ServiceInfo ¶
type ServiceInfo struct {
Primary *ast.ServiceDecl
Extends []*ast.ServiceDecl
Methods []*ast.Method
}
ServiceInfo bundles the primary `service` declaration with every `extend service` continuation that targets the same name. Methods is the merged list in source order.
type Spec ¶
type Spec struct {
// Name is the bare decorator name (no leading `@`). Stored so callers
// holding a *Spec can render diagnostics without a separate lookup.
Name string
// Levels is the OR of every site where `@Name` is legal. The
// placement check fails when the current site bit is not set.
Levels Level
// Doc is a one-line description shown in LSP hover. Keep it short -
// the README is the long-form reference.
Doc string
// Args is the positional argument shape; the zero value means
// "no args expected".
Args ArgsRule
// AppliesTo restricts the decorator to fields / scalars whose
// primitive type is in the listed categories. Zero (PrimAny)
// means no constraint - used by metadata-style decorators. The
// field-type compatibility check reads this when LvlField or
// LvlScalar is the current site.
AppliesTo Prims
// Flag reports whether the decorator never accepts arguments. It
// is a presentation hint, not a parser rule:
//
// - LSP completion inserts `@positive` (no parens) for Flag
// decorators and `@range($1, $2)` (snippet placeholders) for
// the rest.
// - `craftgo fmt` strips empty parens (`@positive()` →
// `@positive`) so canonical form is parens-free.
// - The parser emits [CodeFlagEmptyParens] (warning) when a Flag
// decorator is written with empty `()`. Warning only — the
// formatter rewrites it on save.
//
// The invariant is `Flag == true ⇒ Args.Max == 0`.
Flag bool
// Repeatable reports whether multiple `@Name` occurrences on one site
// are the intended idiom (each adds to an aggregate: tags merge,
// middlewares chain, security OR-alternatives, errors accumulate) rather
// than a duplicate. The duplicate-decorator check reads this so the rule
// lives ONCE here instead of a separate hardcoded list that drifts.
Repeatable bool
}
Spec describes one decorator: its canonical name, every site it may appear, a short doc string for IDE hover, and the positional argument shape. Every decorator validates through the generic [analyzer.checkPositionalArgs] path - there are no per-decorator argument shape hooks.
Source Files
¶
- args.go
- args_default.go
- binding_types.go
- bindings_project.go
- bounds_numeric.go
- collections_checks.go
- combination_checks.go
- decl_collisions.go
- decls.go
- decorator_checks.go
- decorators.go
- diagnostics.go
- enum_collisions.go
- field_collisions.go
- file_checks.go
- generics.go
- imports.go
- local_refs.go
- method_checks.go
- mixin.go
- name_case.go
- operations.go
- path_binding_checks.go
- paths.go
- placement.go
- project.go
- project_decl_checks.go
- project_field_checks.go
- project_mixin_checks.go
- ranges.go
- refs.go
- resolved.go
- semantic.go
- service_shapes.go
- types_compat.go
- wire_name_checks.go