Documentation
¶
Overview ¶
Package codegen loads OpenAPI/GraphQL specs plus a per-operation overlay and emits Aileron connector scaffolding (action.md, manifest.toml, typed clients).
The exported surface is small on purpose: Spec, Operation, Parameter, RequestBody plus the LoadSpec / LoadOverlay / Generate entry points. The OpenAPI and GraphQL parsers live in sibling files and feed into the same Operation shape so the emitter stays format-agnostic.
Index ¶
- func Generate(opts Options) error
- type ActionEmitter
- type ConnectorOverlay
- type CredentialOverlay
- type DispatchEmitter
- type Emitter
- type HandlerEmitter
- type ManifestEmitter
- type NetworkOverlay
- type Operation
- type OperationOverlay
- type Options
- type Overlay
- type Parameter
- type RequestBody
- type ReturnField
- type Spec
- type SuiteEmitter
- type SuiteOverlay
- type TransportEmitter
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type ActionEmitter ¶
type ActionEmitter struct{}
ActionEmitter renders one action.md per Spec Operation into actions/<name>/ under outDir. The emitted file is the TOML front-matter only; prose body generation lands in a follow-up PR.
The `0.0.0-dev` and `sha256:bound-at-release` strings in the template are load-bearing placeholders, not bugs. The release workflow substitutes them per ADR-0002 (connector identity + content-addressed hash); the generator emits the placeholders verbatim so that substitution stays idempotent against an unchanged template.
func (ActionEmitter) Emit ¶
func (ActionEmitter) Emit(spec Spec, overlay Overlay, outDir string) error
Emit writes actions/<name>/action.md for every operation in spec, less the ones in overlay.Exclude. Each emission is driven by the kind-based governance defaults (Query / GET / HEAD / PUT / Subscription → idempotent + approval none; Mutation / POST / PATCH / DELETE → non-idempotent + approval required), with overlay.Operations[op.ID] applied as field-by-field overrides when present.
Overlay entries (in Operations or Exclude) whose op id does not appear in the spec are rejected as typos, surfacing renames or removed-but-not-cleaned-up overlays at emission time rather than silently dropping the action like the pre-#7 behavior did.
type ConnectorOverlay ¶
type ConnectorOverlay struct {
Name string
Publisher string
// Endpoint is the absolute URL the connector POSTs to for every
// op (the GraphQL endpoint for GraphQL connectors; the base URL
// for REST). Required for transport-file emission
// (`connector/graphql.go`); when empty TransportEmitter is a no-op.
Endpoint string
Credential CredentialOverlay
Network NetworkOverlay
}
ConnectorOverlay names the connector and declares its credential + network surface.
Credential is connector-scoped because Aileron connectors mediate exactly one credential per WASM binary; per-operation credential would invite surface-area drift.
type CredentialOverlay ¶
type CredentialOverlay struct {
Kind string
// api_key kind fields. Defaults applied at emission time:
// Header = "Authorization"
// Format = "Bearer {key}"
// These defaults match the aileron runtime's current hard-coded
// injection (internal/sandbox/host.go), so existing connectors that
// don't set them keep working once the runtime reads them.
Header string
Format string
// oauth2 kind fields. Render under [capabilities.credential.oauth2]
// per the Google connector's existing manifest shape.
AuthorizeURL string
TokenURL string
ClientID string
ClientSecret string
Scopes []string
}
CredentialOverlay declares the credential kind plus the per-kind config the manifest emitter renders.
Fields are flat by design — yaml.v3 doesn't support tagged unions cleanly. The kind decides which fields render into the emitted manifest.toml: api_key uses Header/Format; oauth2 uses AuthorizeURL/TokenURL/ClientID/ClientSecret/Scopes.
type DispatchEmitter ¶
type DispatchEmitter struct{}
DispatchEmitter renders connector/dispatch.go. Contains the JSON I/O types (input, output, outputError), the Transport function type that HandlerEmitter's handlers reference, the knownOps map derived from the emittable ops, the run() entry point, the per-op dispatch switch, and the writeError / writeSuccess / classify helpers.
No-op when there are no GraphQL operations to dispatch — keeps OpenAPI-only test cases unaffected. Output passes through go/format so it matches `gofmt` byte-for-byte.
type Emitter ¶
Emitter writes connector scaffolding derived from a Spec and Overlay into an output directory. One implementation per output kind: ActionEmitter + ManifestEmitter + SuiteEmitter today, with typed Go client emission to follow.
Each emitter is responsible for deciding whether to act on a given (Spec, Overlay) pair. ManifestEmitter no-ops when overlay lacks the connector + credential + network fields; SuiteEmitter no-ops when overlay.Suite is nil. That keeps small / partial overlays building just the actions they need without forcing every connector to declare every block.
type HandlerEmitter ¶
type HandlerEmitter struct{}
HandlerEmitter renders connector/handlers.go from the spec + overlay. One per-op function plus the shared arg-extraction helpers. Each handler builds a GraphQL query string (with the selection set derived from Operation.ReturnScalarFields), validates required args, rebuilds any input-object wrapping the loader flattened, and calls the connector's `graphqlCall` transport.
The emitted file assumes the connector also has a hand-written (or later codegen-emitted) `dispatch.go` defining `Transport` and a `graphql.go` defining `graphqlCall` in the same package.
Skipped silently when the spec has no GraphQL operations (every op's Method falls outside QUERY / MUTATION / SUBSCRIPTION) — keeps OpenAPI test cases green while OpenAPI handler emission lands later.
type ManifestEmitter ¶
type ManifestEmitter struct{}
ManifestEmitter renders connector/manifest.toml from the overlay's connector + credential + network blocks. Skipped silently when the overlay doesn't carry enough to render a runnable manifest — see shouldEmitManifest below — so existing test cases that only configure actions stay unchanged.
The `0.0.0-dev` and `sha256:bound-at-release` placeholders the action.md emitter follows apply here too; the release workflow substitutes them per ADR-0002.
type NetworkOverlay ¶
type NetworkOverlay struct {
Hosts []string
}
NetworkOverlay enumerates the host:port pairs the connector is allowed to dial. Renders into [capabilities.network] in the emitted manifest.
type Operation ¶
type Operation struct {
// ID is the canonical operation identifier — drives every downstream
// Go identifier (handler name, query const) and emitted artifact name
// (action directory, snake_case op string). For OpenAPI this is the
// operationId. For GraphQL this is the root-field name, suffixed with
// "Mutation" when the same field name also appears on type Query (and
// similarly with "Subscription" for three-way collisions) so that the
// emitted Go and action names stay unique. The raw GraphQL field name
// (which the emitted query string must use to call the field) lives in
// FieldName.
ID string
// FieldName is the raw GraphQL root-field name for GraphQL operations.
// Empty for OpenAPI. The handler emitter uses this when writing the
// GraphQL document so the field invocation matches the schema even
// when ID has been suffixed to disambiguate a Query/Mutation collision.
FieldName string
// Method is "GET"/"POST"/... for OpenAPI or "QUERY"/"MUTATION" for
// GraphQL.
Method string
// Path is the OpenAPI URL path (empty for GraphQL operations).
Path string
// Summary is the human-readable one-line description (OpenAPI summary
// or GraphQL field description).
Summary string
// Parameters are out-of-body inputs (OpenAPI query/path/header params
// or GraphQL field arguments).
Parameters []Parameter
// RequestBody is the JSON body schema for OpenAPI operations; nil when
// absent or for GraphQL.
RequestBody *RequestBody
// ReturnType is the named GraphQL return type (e.g. "Issue") or the
// OpenAPI response schema name (when populated by the loader). Lists
// and non-null wrappers are unwrapped to the inner named type;
// empty when the loader cannot determine one (OpenAPI today).
ReturnType string
// ReturnTypeIsScalar is true when ReturnType is a GraphQL scalar /
// enum / built-in (String, Int, Boolean, ID, custom DateTime, etc).
// Handler emitters use this to skip building a selection set and
// just request the value directly.
ReturnTypeIsScalar bool
// ReturnFields is the (sorted) selection tree for the return type.
// Scalar fields appear as leaves (Nested empty); fields whose own
// type is itself an OBJECT / INTERFACE recurse exactly one level —
// their scalar fields are surfaced as Nested entries so handler
// queries get the canonical Linear-style "wrapper { success,
// lastSyncId, entity { id, ... } }" shape. Empty for scalar
// returns, unions, and unknown types.
ReturnFields []ReturnField
// ArgTypes maps each GraphQL field argument name to its full GraphQL
// type string (e.g., "String!", "IssueCreateInput!", "[String!]").
// Used by the handler emitter to build the variables declaration in
// the emitted GraphQL query string. Empty for OpenAPI ops.
ArgTypes map[string]string
}
Operation is one spec operation surfaced to the emitter. For OpenAPI this is one HTTP method + path; for GraphQL one Query/Mutation root field.
type OperationOverlay ¶
type OperationOverlay struct {
// Idempotent (when non-nil) overrides whether retries are safe
// (ADR-0010). Nil means use the default for the operation's method.
Idempotent *bool
// Approval is "required" to gate per-call (ADR-0009), "none" to
// relax. Empty means use the default for the operation's method.
Approval string
// Capabilities is the capability identifier list this operation
// needs. Empty means default to [snake_case(operationId)].
Capabilities []string
// Intent overrides the spec's operation summary when set.
Intent string
// ActionName overrides the kebab-cased operationId when set.
ActionName string
// ExecuteID overrides the first-word default for the [[execute]] id.
ExecuteID string
}
OperationOverlay carries per-operation overrides on top of the kind-based governance defaults (Query/Subscription/GET/HEAD/PUT → idempotent, no approval; Mutation/POST/PATCH/DELETE → non-idempotent, approval-required). Every field is optional: an empty field means "use the default."
Booleans use a pointer to distinguish "user explicitly set this" from "user did not set this" — yaml.v3 leaves a *bool nil when the key is absent and points at the parsed value when present.
type Options ¶
type Options struct {
// SpecPath points at an OpenAPI YAML or GraphQL schema file.
SpecPath string
// OverlayPath points at the gen.yaml overlay describing per-operation
// governance metadata.
OverlayPath string
// OutDir is the directory into which scaffolding is written. It is
// created if it does not exist.
OutDir string
}
Options configures a Generate call.
type Overlay ¶
type Overlay struct {
Connector ConnectorOverlay
// Operations are governance overrides keyed by spec operationId.
// An entry here is an override on top of the kind-based defaults
// (Query/Subscription/GET/HEAD/PUT → idempotent, non-write;
// Mutation/POST/PATCH/DELETE → non-idempotent, approval-required).
// Operations not declared here still emit, using the defaults. An
// entry whose operationId does not appear in the spec is a typo
// and is rejected at emission time.
Operations map[string]OperationOverlay
// Exclude drops specific spec operations from emission. Use for
// introspection helpers, deprecated endpoints, admin/destructive
// paths the connector deliberately doesn't surface, etc. Listing
// an operationId here that the spec doesn't define is a typo and
// is rejected at emission time.
Exclude []string
// Suite is optional. When absent, SuiteEmitter is a no-op (some
// connectors prefer per-action installability without a top-level
// suite).
Suite *SuiteOverlay
}
Overlay is the parsed gen.yaml — connector-level metadata plus a per-operation map keyed by OpenAPI operationId (or GraphQL field name in future loaders).
The shape is provisional until two greenfield connectors have shipped without breaking-change releases (acceptance criterion in ALRubinger/aileron#893).
func LoadOverlay ¶
LoadOverlay reads a gen.yaml file at path and parses it into Overlay.
type Parameter ¶
type Parameter struct {
Name string
Type string
Description string
Required bool
// WrappedIn names the original GraphQL argument when this Parameter
// came from flattening a GraphQL input object (e.g. `input` for
// `issueCreate(input: IssueCreateInput!)`). Empty when the param
// was a direct scalar arg. The action.md emitter ignores it; the
// handler emitter uses it to rebuild the wrapping JSON shape the
// API expects.
WrappedIn string
}
Parameter is one input surfaced as an [[inputs]] block in the emitted action.md.
type RequestBody ¶
type RequestBody struct {
Fields []Parameter
}
RequestBody captures the JSON body schema for an OpenAPI operation. Nil for operations without one and for all GraphQL operations.
type ReturnField ¶
type ReturnField struct {
Name string
Nested []ReturnField
}
ReturnField is one entry in the GraphQL selection set for an operation's return type. Leaves (scalars / enums) have Nested empty; object-typed fields have Nested populated with their own scalar leaves. Recursion stops at one level (Nested entries cannot themselves have Nested entries) — deeper recursion blows up query payloads and risks server-side depth limits. Connectors that need deeper selection can declare it per-op via overlay in a future PR.
type Spec ¶
type Spec struct {
Operations []Operation
}
Spec is the parsed representation of an OpenAPI or GraphQL specification — operation-by-operation, with only the fields consumed by the emitters.
type SuiteEmitter ¶
type SuiteEmitter struct{}
SuiteEmitter renders suite.toml at the repo root from the overlay's Suite block plus the same operation-filter ActionEmitter uses, so the suite stays in sync by construction. No-op when overlay.Suite is nil.
type SuiteOverlay ¶
SuiteOverlay drives the top-level suite.toml. Action paths are computed at emission time from the same filter ActionEmitter applies, so the suite stays in sync with the emitted actions/.
type TransportEmitter ¶
type TransportEmitter struct{}
TransportEmitter renders connector/graphql.go — the GraphQL POST envelope wrapper, response parser, and the *graphqlErrors error type that DispatchEmitter's classify() inspects. Templated against the overlay's connector.endpoint URL and credential.kind.
No-op when overlay.Connector.Endpoint is empty (transport URL is load-bearing; without it the emitted file would compile but the connector would dial the wrong host).