From b66d8c6ef5388e2a2270b0551ba2ce5edb6aa08b Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Tue, 19 Sep 2023 08:41:21 +0100 Subject: [PATCH 1/2] decoder: Decouple validators & make them pluggable via PathContext --- decoder/internal/walker/walker.go | 7 ++++--- decoder/path_context.go | 2 ++ decoder/validate.go | 17 +++-------------- decoder/validate_test.go | 14 ++++++++++++++ .../schemahelper => schemacontext}/context.go | 2 +- .../attribute_deprecated.go | 0 .../attribute_missing_required.go | 0 .../attribute_unexpected.go | 4 ++-- .../validator => validator}/block_deprecated.go | 0 .../block_labels_length.go | 0 .../validator => validator}/block_max_items.go | 4 ++-- .../validator => validator}/block_min_items.go | 6 +++--- .../validator => validator}/block_unexpected.go | 4 ++-- .../validator => validator}/validators.go | 0 14 files changed, 33 insertions(+), 27 deletions(-) rename {decoder/internal/schemahelper => schemacontext}/context.go (98%) rename {decoder/internal/validator => validator}/attribute_deprecated.go (100%) rename {decoder/internal/validator => validator}/attribute_missing_required.go (100%) rename {decoder/internal/validator => validator}/attribute_unexpected.go (88%) rename {decoder/internal/validator => validator}/block_deprecated.go (100%) rename {decoder/internal/validator => validator}/block_labels_length.go (100%) rename {decoder/internal/validator => validator}/block_max_items.go (90%) rename {decoder/internal/validator => validator}/block_min_items.go (89%) rename {decoder/internal/validator => validator}/block_unexpected.go (88%) rename {decoder/internal/validator => validator}/validators.go (100%) diff --git a/decoder/internal/walker/walker.go b/decoder/internal/walker/walker.go index e495f207..a90bbb42 100644 --- a/decoder/internal/walker/walker.go +++ b/decoder/internal/walker/walker.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/hcl-lang/decoder/internal/schemahelper" "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl-lang/schemacontext" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" ) @@ -74,8 +75,8 @@ func Walk(ctx context.Context, node hclsyntax.Node, nodeSchema schema.Schema, w diags = diags.Extend(Walk(ctx, block, blockSchema, w)) } } - ctx = schemahelper.WithFoundBlocks(ctx, foundBlocks) - ctx = schemahelper.WithDynamicBlocks(ctx, dynamicBlocks) + ctx = schemacontext.WithFoundBlocks(ctx, foundBlocks) + ctx = schemacontext.WithDynamicBlocks(ctx, dynamicBlocks) diags = diags.Extend(w.Visit(ctx, node, nodeSchema)) @@ -89,7 +90,7 @@ func Walk(ctx context.Context, node hclsyntax.Node, nodeSchema schema.Schema, w if ok && bSchema.Body != nil { mergedSchema, ok := schemahelper.MergeBlockBodySchemas(nodeType.AsHCLBlock(), bSchema) if !ok { - ctx = schemahelper.WithUnknownSchema(ctx) + ctx = schemacontext.WithUnknownSchema(ctx) } blockBodySchema = mergedSchema } diff --git a/decoder/path_context.go b/decoder/path_context.go index b916e16e..8471e6ca 100644 --- a/decoder/path_context.go +++ b/decoder/path_context.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/hcl-lang/reference" "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl-lang/validator" "github.com/hashicorp/hcl/v2" ) @@ -20,6 +21,7 @@ type PathContext struct { ReferenceTargets reference.Targets Files map[string]*hcl.File Functions map[string]schema.FunctionSignature + Validators []validator.Validator } type pathCtxKey struct{} diff --git a/decoder/validate.go b/decoder/validate.go index c9f68b62..7d9edae3 100644 --- a/decoder/validate.go +++ b/decoder/validate.go @@ -6,25 +6,14 @@ package decoder import ( "context" - "github.com/hashicorp/hcl-lang/decoder/internal/validator" "github.com/hashicorp/hcl-lang/decoder/internal/walker" "github.com/hashicorp/hcl-lang/lang" "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl-lang/validator" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" ) -var builtinValidators = []validator.Validator{ - validator.BlockLabelsLength{}, - validator.DeprecatedAttribute{}, - validator.DeprecatedBlock{}, - validator.MaxBlocks{}, - validator.MinBlocks{}, - validator.MissingRequiredAttribute{}, - validator.UnexpectedAttribute{}, - validator.UnexpectedBlock{}, -} - // Validate returns a set of Diagnostics for all known files func (d *PathDecoder) Validate(ctx context.Context) (lang.DiagnosticsMap, error) { diags := make(lang.DiagnosticsMap) @@ -41,7 +30,7 @@ func (d *PathDecoder) Validate(ctx context.Context) (lang.DiagnosticsMap, error) } diags[filename] = walker.Walk(ctx, body, d.pathCtx.Schema, validationWalker{ - validators: builtinValidators, + validators: d.pathCtx.Validators, }) } @@ -65,7 +54,7 @@ func (d *PathDecoder) ValidateFile(ctx context.Context, filename string) (hcl.Di } return walker.Walk(ctx, body, d.pathCtx.Schema, validationWalker{ - validators: builtinValidators, + validators: d.pathCtx.Validators, }), nil } diff --git a/decoder/validate_test.go b/decoder/validate_test.go index abeb2905..4fdf4f10 100644 --- a/decoder/validate_test.go +++ b/decoder/validate_test.go @@ -12,6 +12,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/hcl-lang/lang" "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl-lang/validator" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/zclconf/go-cty/cty" @@ -951,6 +952,7 @@ wakka = 2 Files: map[string]*hcl.File{ "test.tf": f, }, + Validators: testValidators, }) ctx := context.Background() @@ -1026,6 +1028,7 @@ func TestValidate_schema_SingleFile(t *testing.T) { Files: map[string]*hcl.File{ tc.filename: f, }, + Validators: testValidators, }) ctx := context.Background() @@ -1049,3 +1052,14 @@ func sortDiagnostics(diags hcl.Diagnostics) { diags[i].Summary < diags[j].Summary }) } + +var testValidators = []validator.Validator{ + validator.BlockLabelsLength{}, + validator.DeprecatedAttribute{}, + validator.DeprecatedBlock{}, + validator.MaxBlocks{}, + validator.MinBlocks{}, + validator.MissingRequiredAttribute{}, + validator.UnexpectedAttribute{}, + validator.UnexpectedBlock{}, +} diff --git a/decoder/internal/schemahelper/context.go b/schemacontext/context.go similarity index 98% rename from decoder/internal/schemahelper/context.go rename to schemacontext/context.go index b18ecd97..c83d6b27 100644 --- a/decoder/internal/schemahelper/context.go +++ b/schemacontext/context.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package schemahelper +package schemacontext import "context" diff --git a/decoder/internal/validator/attribute_deprecated.go b/validator/attribute_deprecated.go similarity index 100% rename from decoder/internal/validator/attribute_deprecated.go rename to validator/attribute_deprecated.go diff --git a/decoder/internal/validator/attribute_missing_required.go b/validator/attribute_missing_required.go similarity index 100% rename from decoder/internal/validator/attribute_missing_required.go rename to validator/attribute_missing_required.go diff --git a/decoder/internal/validator/attribute_unexpected.go b/validator/attribute_unexpected.go similarity index 88% rename from decoder/internal/validator/attribute_unexpected.go rename to validator/attribute_unexpected.go index bdadfe30..ad7a8d18 100644 --- a/decoder/internal/validator/attribute_unexpected.go +++ b/validator/attribute_unexpected.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - "github.com/hashicorp/hcl-lang/decoder/internal/schemahelper" "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl-lang/schemacontext" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" ) @@ -16,7 +16,7 @@ import ( type UnexpectedAttribute struct{} func (v UnexpectedAttribute) Visit(ctx context.Context, node hclsyntax.Node, nodeSchema schema.Schema) (diags hcl.Diagnostics) { - if schemahelper.HasUnknownSchema(ctx) { + if schemacontext.HasUnknownSchema(ctx) { // Avoid checking for unexpected attributes // if we cannot tell which ones are expected. return diff --git a/decoder/internal/validator/block_deprecated.go b/validator/block_deprecated.go similarity index 100% rename from decoder/internal/validator/block_deprecated.go rename to validator/block_deprecated.go diff --git a/decoder/internal/validator/block_labels_length.go b/validator/block_labels_length.go similarity index 100% rename from decoder/internal/validator/block_labels_length.go rename to validator/block_labels_length.go diff --git a/decoder/internal/validator/block_max_items.go b/validator/block_max_items.go similarity index 90% rename from decoder/internal/validator/block_max_items.go rename to validator/block_max_items.go index 27acc6f3..7f2f1882 100644 --- a/decoder/internal/validator/block_max_items.go +++ b/validator/block_max_items.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - "github.com/hashicorp/hcl-lang/decoder/internal/schemahelper" "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl-lang/schemacontext" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" ) @@ -25,7 +25,7 @@ func (v MaxBlocks) Visit(ctx context.Context, node hclsyntax.Node, nodeSchema sc return } - foundBlocks := schemahelper.FoundBlocks(ctx) + foundBlocks := schemacontext.FoundBlocks(ctx) bodySchema := nodeSchema.(*schema.BodySchema) for name, blockSchema := range bodySchema.Blocks { diff --git a/decoder/internal/validator/block_min_items.go b/validator/block_min_items.go similarity index 89% rename from decoder/internal/validator/block_min_items.go rename to validator/block_min_items.go index f1db1027..5ff3df5d 100644 --- a/decoder/internal/validator/block_min_items.go +++ b/validator/block_min_items.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - "github.com/hashicorp/hcl-lang/decoder/internal/schemahelper" "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl-lang/schemacontext" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" ) @@ -25,8 +25,8 @@ func (v MinBlocks) Visit(ctx context.Context, node hclsyntax.Node, nodeSchema sc return } - foundBlocks := schemahelper.FoundBlocks(ctx) - dynamicBlocks := schemahelper.DynamicBlocks(ctx) + foundBlocks := schemacontext.FoundBlocks(ctx) + dynamicBlocks := schemacontext.DynamicBlocks(ctx) bodySchema := nodeSchema.(*schema.BodySchema) for name, blockSchema := range bodySchema.Blocks { diff --git a/decoder/internal/validator/block_unexpected.go b/validator/block_unexpected.go similarity index 88% rename from decoder/internal/validator/block_unexpected.go rename to validator/block_unexpected.go index 16a94c7b..66cd00f7 100644 --- a/decoder/internal/validator/block_unexpected.go +++ b/validator/block_unexpected.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - "github.com/hashicorp/hcl-lang/decoder/internal/schemahelper" "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl-lang/schemacontext" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" ) @@ -16,7 +16,7 @@ import ( type UnexpectedBlock struct{} func (v UnexpectedBlock) Visit(ctx context.Context, node hclsyntax.Node, nodeSchema schema.Schema) (diags hcl.Diagnostics) { - if schemahelper.HasUnknownSchema(ctx) { + if schemacontext.HasUnknownSchema(ctx) { // Avoid checking for unexpected blocks // if we cannot tell which ones are expected. return diff --git a/decoder/internal/validator/validators.go b/validator/validators.go similarity index 100% rename from decoder/internal/validator/validators.go rename to validator/validators.go From 791378a6c0ff9eebea2e87c7957d3ce2b82f41ca Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Tue, 19 Sep 2023 11:11:39 +0100 Subject: [PATCH 2/2] add check for empty validation slices --- decoder/validate.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/decoder/validate.go b/decoder/validate.go index 7d9edae3..edb684b9 100644 --- a/decoder/validate.go +++ b/decoder/validate.go @@ -21,6 +21,10 @@ func (d *PathDecoder) Validate(ctx context.Context) (lang.DiagnosticsMap, error) return diags, &NoSchemaError{} } + if len(d.pathCtx.Validators) == 0 { + return diags, nil + } + // Validate module files per schema for filename, f := range d.pathCtx.Files { body, ok := f.Body.(*hclsyntax.Body) @@ -43,6 +47,10 @@ func (d *PathDecoder) ValidateFile(ctx context.Context, filename string) (hcl.Di return hcl.Diagnostics{}, &NoSchemaError{} } + if len(d.pathCtx.Validators) == 0 { + return hcl.Diagnostics{}, nil + } + f, err := d.fileByName(filename) if err != nil { return hcl.Diagnostics{}, err