@@ -29,6 +29,8 @@ const (
2929 ConfigTypeUnit ConfigType = "unit"
3030 // ConfigTypeStack is the type of Terragrunt configuration for a stack.
3131 ConfigTypeStack ConfigType = "stack"
32+
33+ skipOutputDiagnostics = "output"
3234)
3335
3436// ConfigType is the type of Terragrunt configuration.
@@ -116,6 +118,9 @@ type Discovery struct {
116118
117119 // excludeByDefault determines whether to exclude configurations by default (triggered by include flags).
118120 excludeByDefault bool
121+
122+ // parserOptions are custom HCL parser options to use when parsing during discovery
123+ parserOptions []hclparse.Option
119124}
120125
121126// DiscoveryOption is a function that modifies a Discovery.
@@ -140,6 +145,26 @@ func NewDiscovery(dir string, opts ...DiscoveryOption) *Discovery {
140145 return discovery
141146}
142147
148+ // parseOptionsProvider is a narrow interface used to extract parser options from
149+ // option values without introducing a dependency on runner or stack packages.
150+ type parseOptionsProvider interface {
151+ GetParseOptions () ([]hclparse.Option , bool )
152+ }
153+
154+ // WithOptions applies any provided options that expose parser options.
155+ // Accepts any option types; only those implementing GetParseOptions are used.
156+ func (d * Discovery ) WithOptions (opts ... any ) * Discovery { //nolint: revive
157+ for _ , opt := range opts {
158+ if provider , ok := opt .(parseOptionsProvider ); ok {
159+ if parseOpts , ok := provider .GetParseOptions (); ok {
160+ d = d .WithParserOptions (parseOpts )
161+ }
162+ }
163+ }
164+
165+ return d
166+ }
167+
143168// WithHidden sets the Hidden flag to true.
144169func (d * Discovery ) WithHidden () * Discovery {
145170 d .hidden = true
@@ -243,6 +268,12 @@ func (d *Discovery) WithExcludeByDefault() *Discovery {
243268 return d
244269}
245270
271+ // WithParserOptions sets custom parser options to be used when parsing configs during discovery.
272+ func (d * Discovery ) WithParserOptions (options []hclparse.Option ) * Discovery {
273+ d .parserOptions = options
274+ return d
275+ }
276+
246277// String returns a string representation of a DiscoveredConfig.
247278func (c * DiscoveredConfig ) String () string {
248279 return c .Path
@@ -265,7 +296,7 @@ func (c *DiscoveredConfig) ContainsDependencyInAncestry(path string) bool {
265296}
266297
267298// Parse parses the discovered configurations.
268- func (c * DiscoveredConfig ) Parse (ctx context.Context , l log.Logger , opts * options.TerragruntOptions , suppressParseErrors bool ) error {
299+ func (c * DiscoveredConfig ) Parse (ctx context.Context , l log.Logger , opts * options.TerragruntOptions , suppressParseErrors bool , parserOptions []hclparse. Option ) error {
269300 parseOpts := opts .Clone ()
270301 parseOpts .WorkingDir = c .Path
271302
@@ -292,15 +323,20 @@ func (c *DiscoveredConfig) Parse(ctx context.Context, l log.Logger, opts *option
292323 config .ExcludeBlock ,
293324 )
294325
326+ // Apply any custom parser options first
327+ if len (parserOptions ) > 0 {
328+ parsingCtx = parsingCtx .WithParseOption (append (parsingCtx .ParserOptions , parserOptions ... ))
329+ }
330+
295331 if suppressParseErrors {
296332 // If suppressing parse errors, we want to filter diagnostics that contain references to outputs,
297333 // while leaving other diagnostics as is.
298334 parseOptions := append (parsingCtx .ParserOptions , hclparse .WithDiagnosticsHandler (func (file * hcl.File , hclDiags hcl.Diagnostics ) (hcl.Diagnostics , error ) {
299335 filteredDiags := hcl.Diagnostics {}
300336
301337 for _ , hclDiag := range hclDiags {
302- containsOutputRef := strings .Contains (strings .ToLower (hclDiag .Summary ), "output" ) ||
303- strings .Contains (strings .ToLower (hclDiag .Detail ), "output" )
338+ containsOutputRef := strings .Contains (strings .ToLower (hclDiag .Summary ), skipOutputDiagnostics ) ||
339+ strings .Contains (strings .ToLower (hclDiag .Detail ), skipOutputDiagnostics )
304340
305341 if ! containsOutputRef {
306342 filteredDiags = append (filteredDiags , hclDiag )
@@ -557,7 +593,7 @@ func (d *Discovery) Discover(ctx context.Context, l log.Logger, opts *options.Te
557593 continue
558594 }
559595
560- err := cfg .Parse (ctx , l , opts , d .suppressParseErrors )
596+ err := cfg .Parse (ctx , l , opts , d .suppressParseErrors , d . parserOptions )
561597 if err != nil {
562598 errs = append (errs , errors .New (err ))
563599 }
@@ -585,6 +621,10 @@ func (d *Discovery) Discover(ctx context.Context, l log.Logger, opts *options.Te
585621 dependencyDiscovery = dependencyDiscovery .WithSuppressParseErrors ()
586622 }
587623
624+ if len (d .parserOptions ) > 0 {
625+ dependencyDiscovery = dependencyDiscovery .WithParserOptions (d .parserOptions )
626+ }
627+
588628 // Pass include patterns and strict mode to dependency discovery
589629 if len (d .includeDirs ) > 0 {
590630 dependencyDiscovery = dependencyDiscovery .WithIncludeDirs (d .includeDirs )
@@ -647,6 +687,7 @@ type DependencyDiscovery struct {
647687 discoverExternal bool
648688 suppressParseErrors bool
649689 strictInclude bool
690+ parserOptions []hclparse.Option
650691}
651692
652693// DependencyDiscoveryOption is a function that modifies a DependencyDiscovery.
@@ -691,6 +732,12 @@ func (d *DependencyDiscovery) WithStrictInclude() *DependencyDiscovery {
691732 return d
692733}
693734
735+ // WithParserOptions sets custom parser options to be used when parsing dependency configs during discovery.
736+ func (d * DependencyDiscovery ) WithParserOptions (options []hclparse.Option ) * DependencyDiscovery {
737+ d .parserOptions = options
738+ return d
739+ }
740+
694741// matchesIncludePatterns returns true if the path matches any of the include directory patterns.
695742func (d * DependencyDiscovery ) matchesIncludePatterns (path string ) bool {
696743 if len (d .includeDirs ) == 0 {
@@ -752,7 +799,7 @@ func (d *DependencyDiscovery) DiscoverDependencies(ctx context.Context, l log.Lo
752799
753800 // This should only happen if we're discovering an ancestor dependency.
754801 if dCfg .Parsed == nil {
755- err := dCfg .Parse (ctx , l , opts , d .suppressParseErrors )
802+ err := dCfg .Parse (ctx , l , opts , d .suppressParseErrors , d . parserOptions )
756803 if err != nil {
757804 return errors .New (err )
758805 }
0 commit comments