Help us shape the future of Go! Take the 2026 Go Developer Survey

parser

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const SensitiveMark = "sensitive"

SensitiveMark is the cty mark on values that come from a sensitive variable. HCL carries it through expressions and function calls, so anything computed from such a value is marked too. The engine marks values only where it looks for the mark (plan output, component inputs) and unmarks them before they reach a provider.

Variables

View Source
var RepetitionSchema = &hcl.BodySchema{
	Attributes: []hcl.AttributeSchema{{Name: "count"}, {Name: "for_each"}},
}

RepetitionSchema names the attributes ExpandInstances consumes.

Functions

func Functions

func Functions() map[string]function.Function

Functions returns the complete set of HCL functions Orchard exposes to expressions. Delegates to language.Map() which builds the function map from the unified registry — the single source of truth for function implementations and metadata.

All callers (parser, engine, plan-time validators, teardown) use this function to populate EvalContext.Functions.

func MarkSensitive added in v0.2.0

func MarkSensitive(vars map[string]cty.Value, names map[string]bool) map[string]cty.Value

MarkSensitive returns vars with the variables names marks sensitive carrying SensitiveMark. vars itself is left alone.

func ResolveVariableType

func ResolveVariableType(v *VariableBlock) (cty.Type, error)

ResolveVariableType parses the variable's `type` HCL expression (e.g. `string`, `list(number)`, `object({id=number})`) into a cty.Type. A variable with no declared type is treated as cty.DynamicPseudoType — any value shape is accepted.

func ValidateComponentInputs

func ValidateComponentInputs(comp *ParsedComponent) error

ValidateComponentInputs runs plan-time checks on a component ref against its declared variables. Two invariants:

  • Every input key must correspond to a declared variable on the component. A typo like `inputs = { naem = var.x }` is caught here, not at execution time.
  • Every required variable (no declared default) must be present as an input key.

The value expressions themselves are NOT evaluated — they may reference action outputs that only exist at runtime. Type coercion of input values stays with the engine's runtime pass.

When the inputs expression is not a literal object (e.g. a function call producing a map), key-set inspection is skipped gracefully and the engine's runtime pass covers it. Required- variable checks still run if the inputs body has no `inputs` attribute at all.

func VariableDefault

func VariableDefault(v *VariableBlock) (hcl.Expression, error)

VariableDefault returns the variable's default-value expression, or nil if the variable declared no default. A variable that explicitly sets `default = null` is treated as having a default (typed null); only genuinely-absent defaults return nil.

func VariableSensitive added in v0.2.0

func VariableSensitive(v *VariableBlock) (bool, error)

VariableSensitive reports whether v is declared `sensitive = true`.

Types

type ActionBlock

type ActionBlock struct {
	Type   string   `hcl:"type,label"`
	Name   string   `hcl:"name,label"`
	Remain hcl.Body `hcl:",remain"`
}

ActionBlock represents: action "<type>" "<name>" { ... }

type ComponentDefBlock

type ComponentDefBlock struct {
	Name        string           `hcl:"name,label"`
	Description string           `hcl:"description,optional"`
	Tags        []string         `hcl:"tags,optional"`
	Variables   []*VariableBlock `hcl:"variable,block"`
	Actions     []*ActionBlock   `hcl:"action,block"`
	Outputs     []*OutputBlock   `hcl:"output,block"`
}

ComponentDefBlock defines a reusable component: component "name" { ... }

Description and Tags mirror the scenario-level fields: free-form metadata surfaced by tooling, ignored by the engine.

type ComponentFile

type ComponentFile struct {
	Component *ComponentDefBlock `hcl:"component,block"`
}

ComponentFile is the top-level HCL structure for a component definition file.

type ComponentRef

type ComponentRef struct {
	Type   string   `hcl:"type,label"`
	Name   string   `hcl:"name,label"`
	Source string   `hcl:"source,attr"`
	Inputs hcl.Body `hcl:",remain"`
}

ComponentRef is a component instance within a scenario. component "<type>" "<name>" { source = "..." inputs = { ... } }

type Instance

type Instance struct {
	Key   cty.Value
	Value cty.Value
}

Instance identifies one copy of an action or component expanded by `count` or `for_each`. Key is a number index for count and a string key for for_each; Value is for_each's element (unset for count).

func ExpandInstances

func ExpandInstances(body hcl.Body, vars map[string]cty.Value, seed uint64, scope string) ([]*Instance, hcl.Body, error)

ExpandInstances pulls `count` / `for_each` off body, evaluates it against the scenario's variables, and returns one Instance per copy plus the body with those attributes hidden.

A body with neither attribute returns []*Instance{nil}: a single, unexpanded block. count = 0 or an empty for_each returns an empty slice.

Both attributes must be known before anything runs, so they may only reference var.* and functions — never action or component outputs.

seed and scope (the block's address) seed any random functions the expression calls.

func (*Instance) Suffix

func (i *Instance) Suffix() string

Suffix renders the instance address appended to node IDs and component keys: `[0]` for count, `["key"]` for for_each.

func (*Instance) Vars

func (i *Instance) Vars() map[string]cty.Value

Vars returns the eval-context namespace the instance exposes: `count.index` for count, `each.key` / `each.value` for for_each.

type Option

type Option func(*loadConfig)

Option changes how a scenario loads.

func WithOverrides added in v0.2.0

func WithOverrides(vars map[string]string) Option

WithOverrides layers --var style overrides over the values LoadScenarioValues is given; teardown uses it to take sensitive variables, which records leave out.

func WithSeed

func WithSeed(seed uint64) Option

WithSeed sets the run's seed, overriding the scenario's own.

type OutputBlock

type OutputBlock struct {
	Name  string         `hcl:"name,label"`
	Value hcl.Expression `hcl:"value"`
}

OutputBlock represents: output "name" { value = <expr> }

type ParsedComponent

type ParsedComponent struct {
	Ref *ComponentRef
	Def *ComponentDefBlock
	// Instance is set when the ref uses count / for_each; nil for a
	// plain single component. Its count.* / each.* namespace is in
	// scope for the ref's inputs.
	Instance *Instance
}

ParsedComponent holds a resolved component definition alongside its instance ref.

type ParsedScenario

type ParsedScenario struct {
	Scenario   *ScenarioBlock
	Components map[string]*ParsedComponent // keyed by "type.name"
	Variables  map[string]cty.Value

	// RequiredProviders maps a provider name to its declared source,
	// e.g. "postgres" → {Source: "builtin/postgres"}. Populated from
	// the scenario's required_providers block. Empty when absent.
	RequiredProviders map[string]RequiredProviderSpec

	// ProviderConfigs maps a provider name to the evaluated attribute
	// values from its `provider "<name>" {}` block. These are passed
	// to provider.Registry.Configure. Providers without a config
	// block receive an empty map rather than being absent, matching
	// the Configure contract that lets providers start up with
	// default or zero configuration.
	ProviderConfigs map[string]map[string]cty.Value

	// ScenarioDir is the absolute directory containing the scenario
	// file. The engine uses it to resolve `file` attributes on
	// action bodies to absolute paths before dispatching to
	// providers — the same convention as component source paths and
	// exec: provider sources, extended to any action that reads a
	// file.
	ScenarioDir string

	// Sensitive names the scenario variables declared
	// `sensitive = true`. Run records keep a hash of each, not its
	// value.
	Sensitive map[string]bool

	// Seed drives every random function in the run: --seed, else the
	// scenario's seed attribute, else a fresh random one. The run
	// record keeps it so a run can be repeated.
	Seed uint64
}

ParsedScenario holds the structurally-decoded scenario with deferred expressions.

func LoadScenario

func LoadScenario(path, name string, vars map[string]string, opts ...Option) (*ParsedScenario, error)

LoadScenario parses a scenario HCL file, picks the scenario block matching name, resolves component sources, and merges CLI variable overrides with defaults.

An empty name selects the sole scenario when the file contains exactly one — a convenience that keeps `orchard run foo.hcl` ergonomic for the single-scenario case. When a file has multiple scenarios and name is empty, the error lists the available names so the caller can retry with --scenario.

func LoadScenarioValues

func LoadScenarioValues(path, name string, values map[string]cty.Value, opts ...Option) (*ParsedScenario, error)

LoadScenarioValues is LoadScenario with typed variable values in place of CLI override strings: the resolved variables a run record holds. Teardown reloads a scenario this way so count / for_each expansion, provider configs and variables without a default all see what the recorded run saw. Variables the scenario declares but values lacks fall back to their defaults.

type ProviderConfigBlock

type ProviderConfigBlock struct {
	Name   string   `hcl:"name,label"`
	Remain hcl.Body `hcl:",remain"`
}

ProviderConfigBlock represents: provider "<name>" { <config attributes> }. The body is captured for deferred evaluation against the scenario's variable context.

type RequiredProviderSpec

type RequiredProviderSpec struct {
	Source string
}

RequiredProviderSpec captures the declared source of a provider. Version and explicit configuration-alias fields land here when we add them; the struct form lets us evolve without breaking callers.

type RequiredProvidersBlock

type RequiredProvidersBlock struct {
	Body hcl.Body `hcl:",remain"`
}

RequiredProvidersBlock declares the providers a scenario needs. The body is a flat attribute set where each attribute is a provider name assigned to an object describing the source:

required_providers {
  postgres = { source = "builtin/postgres" }
  http     = { source = "builtin/http" }
}

The body is captured as hcl.Body so each entry's object can be decoded dynamically — gohcl cannot flatten a "remaining-attribute- set-of-objects" shape into a typed struct.

type ScenarioBlock

type ScenarioBlock struct {
	Name              string                  `hcl:"name,label"`
	Description       string                  `hcl:"description,optional"`
	Tags              []string                `hcl:"tags,optional"`
	Seed              *uint64                 `hcl:"seed,optional"`
	RequiredProviders *RequiredProvidersBlock `hcl:"required_providers,block"`
	Providers         []*ProviderConfigBlock  `hcl:"provider,block"`
	Variables         []*VariableBlock        `hcl:"variable,block"`
	Components        []*ComponentRef         `hcl:"component,block"`
	Actions           []*ActionBlock          `hcl:"action,block"`
	Outputs           []*OutputBlock          `hcl:"output,block"`
}

ScenarioBlock represents: scenario "name" { ... }

Description and Tags are optional metadata surfaced by `orchard list` and reserved for future search / categorisation tooling. They have no effect on execution and are ignored by the engine.

type ScenarioFile

type ScenarioFile struct {
	Scenarios []*ScenarioBlock `hcl:"scenario,block"`
}

ScenarioFile is the top-level HCL structure for a scenario file.

Scenarios is a slice so a single file can hold multiple scenario blocks — useful for grouping related scenarios (e.g. all UAT cases for a feature) without proliferating files. Callers pick one by name via LoadScenario's scenario parameter; a file containing a single scenario can still pass "" and have it auto-selected.

type VariableBlock

type VariableBlock struct {
	Name string   `hcl:"name,label"`
	Body hcl.Body `hcl:",remain"`
}

VariableBlock represents: variable "name" { type = <typeexpr>, default = <value>, description = "..." }.

Body captures the block's attributes as-is (via gohcl's `,remain`). We decode type/default/description manually in the parser rather than relying on gohcl's optional hcl.Expression handling, which synthesizes a cty.NullVal placeholder for absent optional fields — making "absent default" and "default = null" indistinguishable.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL