hclparse

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Apr 20, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package hclparse provides two-phase HCL parsing for stack files with support for autoinclude blocks and deferred evaluation.

Index

Constants

View Source
const (
	// AutoIncludeFile is the filename for generated autoinclude files.
	AutoIncludeFile = "terragrunt.autoinclude.hcl"
)
View Source
const (
	// StackDir is the directory name where generated stack components are placed.
	StackDir = ".terragrunt-stack"
)

Variables

This section is empty.

Functions

func AutoIncludeDependencyPaths

func AutoIncludeDependencyPaths(fs vfs.FS, unitDir string) ([]string, error)

AutoIncludeDependencyPaths reads the terragrunt.autoinclude.hcl file in unitDir and returns resolved dependency config_path values. Returns (nil, nil) if the file does not exist or has no dependencies.

func AutoIncludeKey

func AutoIncludeKey(kind, name string) string

AutoIncludeKey returns the map key for an autoinclude entry, namespaced by component kind to prevent collisions between same-name units and stacks.

func BuildAutoIncludeEvalContext

func BuildAutoIncludeEvalContext(unitRefs, stackRefs []ComponentRef) *hcl.EvalContext

BuildAutoIncludeEvalContext creates an HCL evaluation context with unit and stack path references for resolving autoinclude blocks.

The context provides:

  • unit.<name>.path - resolved path of each unit in the stack
  • unit.<name>.name - name label of each unit
  • stack.<name>.path - resolved path of each stack in the stack
  • stack.<name>.name - name label of each stack

Additional variables (locals, values) can be merged into the returned context by the caller.

func BuildComponentRefMap

func BuildComponentRefMap(refs []ComponentRef) cty.Value

BuildComponentRefMap creates a cty.Value map from a slice of ComponentRef. The resulting value is an object like:

{
  "unit_name": { "path": "../relative/path", "name": "unit_name" }
}

For stack refs with children, it also includes nested unit refs:

{
  "stack_name": {
    "path": "/abs/path",
    "name": "stack_name",
    "unit_name": { "path": "/abs/path/to/unit", "name": "unit_name" }
  }
}

This is injected into the HCL eval context as the `unit` or `stack` variable.

func CommentTokens

func CommentTokens(text string) hclwrite.Tokens

CommentTokens creates a comment token for hclwrite.

func FindBlock

func FindBlock(body *hclsyntax.Body, blockType, label string) *hclsyntax.Block

FindBlock finds a block by type and first label in the AST body. Exported for reuse by callers that need to locate specific blocks in parsed HCL bodies.

func GenerateAutoIncludeFile

func GenerateAutoIncludeFile(fs vfs.FS, resolved *AutoIncludeResolved, targetDir string, srcBytes []byte, evalCtx *hcl.EvalContext) error

GenerateAutoIncludeFile writes a terragrunt.autoinclude.hcl file in the given directory from a resolved autoinclude.

The generated file contains:

  • dependency blocks with resolved config_path and all other attributes (mock_outputs, mock_outputs_allowed_terraform_commands, etc.) copied from the original AST source bytes.
  • All non-dependency content (inputs, retry blocks, etc.) copied verbatim from the original AST source bytes: dependency.*.outputs.* references are preserved without evaluation.

srcBytes is the original terragrunt.stack.hcl file content, used to extract source text for expressions via byte ranges.

func HCLStringContent

func HCLStringContent(s string) []byte

HCLStringContent returns the inner content of an HCL-escaped string (without surrounding quotes). Uses hclwrite.TokensForValue for correct escaping of all HCL special characters.

func IsPure

func IsPure(expr hclsyntax.Expression, deferred map[string]bool) bool

IsPure returns true if the expression has no references to deferred root names.

func PartialEval

func PartialEval(expr hclsyntax.Expression, args *EvalArgs) []byte

PartialEval walks an hclsyntax.Expression tree and returns HCL source text. Pure expressions (no deferred refs) are fully evaluated to literals. Mixed expressions get per-child treatment: evaluable parts become literals, deferred parts keep their original source text.

func RangeBytes

func RangeBytes(src []byte, r hcl.Range) []byte

RangeBytes extracts the source bytes for the given range.

func RawTokens

func RawTokens(b []byte) hclwrite.Tokens

RawTokens wraps raw bytes as a single hclwrite token. hclwrite.Format will handle the final formatting of the output.

func SortedAttributes

func SortedAttributes(attrs hclsyntax.Attributes) []*hclsyntax.Attribute

SortedAttributes returns attributes in a deterministic order by source position.

func UnitPathsFromStackDir

func UnitPathsFromStackDir(fs vfs.FS, stackDir string) []string

UnitPathsFromStackDir parses the stack file in stackDir and returns absolute paths to each unit's generated directory under .terragrunt-stack/. Returns nil if the file does not exist or cannot be parsed.

func ValueToHCLBytes

func ValueToHCLBytes(val cty.Value) []byte

ValueToHCLBytes converts a cty.Value to HCL source text bytes.

Types

type AutoIncludeDependency

type AutoIncludeDependency struct {
	// Block is the original HCL block, preserved for serialization.
	Block      *hcl.Block
	Name       string
	ConfigPath string
}

AutoIncludeDependency represents a resolved dependency block from autoinclude. config_path has been evaluated (e.g. unit.vpc.path → "/abs/path/to/.terragrunt-stack/vpc"). The original HCL block is preserved for writing all attributes (mock_outputs, etc.) into the generated file.

type AutoIncludeHCL

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

AutoIncludeHCL represents the first-phase parse of an autoinclude block. The entire body is captured as remain because it may contain references to unit.*.path / stack.*.path variables that are only available after the first parsing pass extracts all unit/stack names and paths.

Example HCL:

autoinclude {
  dependency "vpc" {
    config_path = unit.vpc.path
  }
  inputs = {
    vpc_id = dependency.vpc.outputs.vpc_id
  }
}

func (*AutoIncludeHCL) Resolve

Resolve evaluates the autoinclude body using the provided eval context, which must contain unit.* and stack.* variables for path resolution.

The resolution follows three levels:

  1. First parse: autoinclude body captured as Remain (unit.*.path not yet available)
  2. This method (second parse): dependency.config_path evaluated using unit/stack context. All other dependency attributes (mock_outputs, etc.) are preserved as raw HCL.
  3. inputs and other non-dependency content: NOT evaluated here. They contain dependency.*.outputs.* which is runtime-only. The RawBody is preserved so the generator can copy these from the AST.

type AutoIncludeResolved

type AutoIncludeResolved struct {
	// EvalCtx is the HCL evaluation context used during resolution,
	// preserved so the generator can evaluate non-deferred expressions.
	EvalCtx *hcl.EvalContext
	// RawBody is the original autoinclude HCL body, preserved so
	// the generator can write non-dependency content (inputs, etc.)
	// directly from the AST without evaluating dependency.* references.
	RawBody      hcl.Body
	Dependencies []AutoIncludeDependency
}

AutoIncludeResolved represents the second-phase resolved autoinclude content.

After the first parse extracts unit/stack names and paths, the autoinclude body is partially evaluated:

  • dependency.config_path is resolved (references unit.*.path)
  • dependency remain (mock_outputs etc) is preserved for generation
  • inputs and other blocks are partially evaluated (local.* resolved, dependency.* preserved)

The RawBody is preserved for serializing the generated terragrunt.autoinclude.hcl file.

type ComponentRef

type ComponentRef struct {
	Name string
	Path string
	// ChildRefs holds nested unit refs for stack components.
	// When a stack block references a source with a terragrunt.stack.hcl,
	// the child units within that stack are parsed and stored here.
	// This enables stack.stack_name.unit_name.path references.
	ChildRefs []ComponentRef
}

ComponentRef holds the path and name metadata for a unit or stack block, used to build the evaluation context for the second parsing phase.

func DiscoverStackChildUnits

func DiscoverStackChildUnits(fs vfs.FS, stackSourceDir, stackGenDir string) []ComponentRef

DiscoverStackChildUnits parses a stack's source directory to find the terragrunt.stack.hcl within it and extracts unit paths. This enables stack.stack_name.unit_name.path references in autoinclude blocks.

stackSourceDir is the directory where the stack's source files live (or will be generated). stackGenDir is the absolute path where this stack's units will be generated (.terragrunt-stack/stack_path/).

func ExtractStackRefs

func ExtractStackRefs(stacks []*StackBlockHCL) []ComponentRef

ExtractStackRefs extracts ComponentRef values from parsed StackBlockHCL slices.

func ExtractUnitRefs

func ExtractUnitRefs(units []*UnitBlockHCL) []ComponentRef

ExtractUnitRefs extracts ComponentRef values from parsed UnitBlockHCL slices.

type Copier

type Copier struct {
	// contains filtered or unexported fields
}

Copier copies HCL blocks from AST source to hclwrite output. When an eval context is set, attributes are partially evaluated (local.* resolved, dependency.* preserved). Without it, attributes are copied verbatim from source bytes.

func NewCopier

func NewCopier() *Copier

NewCopier creates a Copier that copies blocks verbatim.

func (*Copier) CopyBlock

func (c *Copier) CopyBlock(outBody *hclwrite.Body, block *hclsyntax.Block, srcBytes []byte)

CopyBlock copies a block from the original AST to hclwrite output.

func (*Copier) WithEvalCtx

func (c *Copier) WithEvalCtx(evalCtx *hcl.EvalContext) *Copier

WithEvalCtx returns the Copier with partial evaluation enabled.

type DirCreateError

type DirCreateError struct {
	Err     error
	DirPath string
}

DirCreateError indicates a failure to create a directory.

func (DirCreateError) Error

func (e DirCreateError) Error() string

func (DirCreateError) Unwrap

func (e DirCreateError) Unwrap() error

type DuplicateStackNameError

type DuplicateStackNameError struct {
	Name string
}

DuplicateStackNameError indicates that multiple stacks with the same name were found after merging include blocks.

func (DuplicateStackNameError) Error

func (e DuplicateStackNameError) Error() string

type DuplicateUnitNameError

type DuplicateUnitNameError struct {
	Name string
}

DuplicateUnitNameError indicates that multiple units with the same name were found after merging include blocks.

func (DuplicateUnitNameError) Error

func (e DuplicateUnitNameError) Error() string

type EvalArgs

type EvalArgs struct {
	EvalCtx  *hcl.EvalContext
	Deferred map[string]bool
	SrcBytes []byte
}

EvalArgs bundles the shared arguments for partial evaluation functions.

type FileDecodeError

type FileDecodeError struct {
	Name   string
	Detail string
}

FileDecodeError indicates a failure to decode an HCL file into a struct.

func (FileDecodeError) Error

func (e FileDecodeError) Error() string

type FileParseError

type FileParseError struct {
	FilePath string
	Detail   string
}

FileParseError indicates a failure to parse an HCL file.

func (FileParseError) Error

func (e FileParseError) Error() string

type FileReadError

type FileReadError struct {
	Err      error
	FilePath string
}

FileReadError indicates a failure to read a file from the filesystem.

func (FileReadError) Error

func (e FileReadError) Error() string

func (FileReadError) Unwrap

func (e FileReadError) Unwrap() error

type FileWriteError

type FileWriteError struct {
	Err      error
	FilePath string
}

FileWriteError indicates a failure to write a file to the filesystem.

func (FileWriteError) Error

func (e FileWriteError) Error() string

func (FileWriteError) Unwrap

func (e FileWriteError) Unwrap() error

type IncludeValidationError

type IncludeValidationError struct {
	IncludeName string
	Reason      string
}

IncludeValidationError indicates that an included stack file violates constraints (e.g. defines locals or nested includes).

func (IncludeValidationError) Error

func (e IncludeValidationError) Error() string

type LocalEvalError

type LocalEvalError struct {
	Name   string
	Detail string
}

LocalEvalError indicates a failure to evaluate a local variable.

func (LocalEvalError) Error

func (e LocalEvalError) Error() string

type LocalsCycleError

type LocalsCycleError struct {
	Names []string
}

LocalsCycleError indicates that locals have circular dependencies.

func (LocalsCycleError) Error

func (e LocalsCycleError) Error() string

type LocalsHCL

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

LocalsHCL captures the locals block body for iterative evaluation.

type LocalsMaxIterError

type LocalsMaxIterError struct {
	MaxIterations int
	Remaining     int
}

LocalsMaxIterError indicates that locals evaluation exceeded the maximum iterations.

func (LocalsMaxIterError) Error

func (e LocalsMaxIterError) Error() string

type ParseResult

type ParseResult struct {
	// AutoIncludes maps component name → resolved autoinclude (only for units/stacks
	// that had an autoinclude block). Dependencies have config_path resolved.
	AutoIncludes map[string]*AutoIncludeResolved
	// Units from the first-pass parse (name, source, path, values decoded).
	Units []*UnitBlockHCL
	// Stacks from the first-pass parse.
	Stacks []*StackBlockHCL
}

ParseResult holds the output of a two-pass parse of a terragrunt.stack.hcl file.

func ParseStackFile

func ParseStackFile(fs vfs.FS, input *ParseStackFileInput) (*ParseResult, error)

ParseStackFile performs a two-pass parse of a terragrunt.stack.hcl file.

Pass 1: Parse unit/stack blocks to extract names, sources, and paths. The autoinclude body is captured as hcl.Body via remain (not evaluated).

Between passes: Build eval context with unit.<name>.path and stack.<name>.path variables. Paths are resolved to absolute paths under .terragrunt-stack/.

Pass 2: For each unit/stack with an autoinclude block, resolve the autoinclude body using the eval context. dependency.config_path is evaluated (references unit.*.path), while inputs are left unevaluated (contain dependency.*.outputs.*).

func ParseStackFileFromPath

func ParseStackFileFromPath(fs vfs.FS, stackDir string) (*ParseResult, error)

ParseStackFileFromPath reads stackDir/terragrunt.stack.hcl from disk and performs a two-pass parse. Returns nil, nil if the file does not exist.

type ParseStackFileInput

type ParseStackFileInput struct {
	Values   *cty.Value
	Filename string
	StackDir string
	Src      []byte
}

ParseStackFileInput holds the input for ParseStackFile.

type StackBlockHCL

type StackBlockHCL struct {
	AutoInclude  *AutoIncludeHCL `hcl:"autoinclude,block"`
	NoStack      *bool           `hcl:"no_dot_terragrunt_stack,attr"`
	NoValidation *bool           `hcl:"no_validation,attr"`
	Values       *cty.Value      `hcl:"values,attr"`
	Name         string          `hcl:",label"`
	Source       string          `hcl:"source,attr"`
	Path         string          `hcl:"path,attr"`
}

StackBlockHCL represents the first-phase parse of a stack block. Same remain pattern as UnitBlockHCL.

type StackFileHCL

type StackFileHCL struct {
	Locals   *LocalsHCL         `hcl:"locals,block"`
	Includes []*StackIncludeHCL `hcl:"include,block"`
	Stacks   []*StackBlockHCL   `hcl:"stack,block"`
	Units    []*UnitBlockHCL    `hcl:"unit,block"`
}

StackFileHCL represents the first-phase parse of a terragrunt.stack.hcl file. The autoinclude body inside each unit/stack block is captured as hcl.Body via remain, allowing deferred evaluation once unit/stack path variables are available.

type StackIncludeHCL

type StackIncludeHCL struct {
	Name string `hcl:",label"`
	Path string `hcl:"path,attr"`
}

StackIncludeHCL represents an include block in a terragrunt.stack.hcl file. The path is evaluated immediately during the first parse pass.

type UnexpectedBodyTypeError

type UnexpectedBodyTypeError struct {
	FilePath string
}

UnexpectedBodyTypeError indicates that an HCL file body was not the expected *hclsyntax.Body type. This typically occurs with JSON-format HCL files.

func (UnexpectedBodyTypeError) Error

func (e UnexpectedBodyTypeError) Error() string

type UnitBlockHCL

type UnitBlockHCL struct {
	AutoInclude  *AutoIncludeHCL `hcl:"autoinclude,block"`
	NoStack      *bool           `hcl:"no_dot_terragrunt_stack,attr"`
	NoValidation *bool           `hcl:"no_validation,attr"`
	Values       *cty.Value      `hcl:"values,attr"`
	Name         string          `hcl:",label"`
	Source       string          `hcl:"source,attr"`
	Path         string          `hcl:"path,attr"`
}

UnitBlockHCL represents the first-phase parse of a unit block. Known attributes are decoded directly. The autoinclude block body is captured in Remain for second-phase evaluation.

Jump to

Keyboard shortcuts

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