diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_all_framework_types_blocks_section.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_all_framework_types_blocks_section.txtar
new file mode 100644
index 0000000..f74165a
--- /dev/null
+++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_all_framework_types_blocks_section.txtar
@@ -0,0 +1,644 @@
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
+# Successful run of tfplugindocs on a Framework provider with a resource and function schema containing all framework types
+[!unix] skip
+exec tfplugindocs --provider-name=terraform-provider-scaffolding --providers-schema=schema.json --blocks-section
+cmp stdout expected-output.txt
+cmp docs/index.md expected-index.md
+cmp docs/resources/example.md expected-resource.md
+cmp docs/functions/scaffolding.md expected-function.md
+
+-- expected-output.txt --
+rendering website for provider "terraform-provider-scaffolding" (as "terraform-provider-scaffolding")
+exporting schema from JSON file
+getting provider schema
+generating missing templates
+generating missing resource content
+generating new template for "scaffolding_example"
+generating missing data source content
+generating missing function content
+generating new template for function "scaffolding"
+generating missing provider content
+generating new template for "terraform-provider-scaffolding"
+rendering static website
+cleaning rendered website dir
+rendering templated website to static markdown
+rendering "functions/scaffolding.md.tmpl"
+rendering "index.md.tmpl"
+rendering "resources/example.md.tmpl"
+-- expected-index.md --
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "scaffolding Provider"
+subcategory: ""
+description: |-
+ Example provider
+---
+
+# scaffolding Provider
+
+Example provider
+
+
+
+
+## Schema
+
+### Optional Attributes
+
+- `endpoint` (String) Example provider attribute
+-- expected-resource.md --
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "scaffolding_example Resource - terraform-provider-scaffolding"
+subcategory: ""
+description: |-
+ example resource
+---
+
+# scaffolding_example (Resource)
+
+example resource
+
+
+
+
+## Schema
+
+### Optional Attributes
+
+- `bool_attribute` (Boolean) example bool attribute
+- `float64_attribute` (Number) example float64 attribute
+- `int64_attribute` (Number) example int64 attribute
+- `list_attribute` (List of String) example list attribute
+- `map_attribute` (Map of String) example map attribute
+- `number_attribute` (Number) example number attribute
+- `object_attribute` (Object) example object attribute (see [below for nested schema](#nestedatt--object_attribute))
+- `object_attribute_with_nested_object_attribute` (Object) example object attribute with nested object attribute (see [below for nested schema](#nestedatt--object_attribute_with_nested_object_attribute))
+- `sensitive_bool_attribute` (Boolean, Sensitive) example sensitive bool attribute
+- `sensitive_float64_attribute` (Number, Sensitive) example sensitive float64 attribute
+- `sensitive_int64_attribute` (Number, Sensitive) example sensitive int64 attribute
+- `sensitive_list_attribute` (List of String, Sensitive) example sensitive list attribute
+- `sensitive_map_attribute` (Map of String, Sensitive) example sensitive map attribute
+- `sensitive_number_attribute` (Number, Sensitive) example sensitive number attribute
+- `sensitive_object_attribute` (Object, Sensitive) example sensitive object attribute (see [below for nested schema](#nestedatt--sensitive_object_attribute))
+- `sensitive_set_attribute` (Set of String, Sensitive) example sensitive set attribute
+- `sensitive_string_attribute` (String, Sensitive) example sensitive string attribute
+- `set_attribute` (Set of String) example set attribute
+- `string_attribute` (String) example string attribute
+
+### Blocks
+
+- `list_nested_block` (Block List) example list nested block (see [below for nested schema](#nestedblock--list_nested_block))
+- `list_nested_block_sensitive_nested_attribute` (Block List) (see [below for nested schema](#nestedblock--list_nested_block_sensitive_nested_attribute))
+- `set_nested_block` (Block Set) example set nested block (see [below for nested schema](#nestedblock--set_nested_block))
+- `single_nested_block` (Block, Optional) example single nested block (see [below for nested schema](#nestedblock--single_nested_block))
+- `single_nested_block_sensitive_nested_attribute` (Block, Optional) example sensitive single nested block (see [below for nested schema](#nestedblock--single_nested_block_sensitive_nested_attribute))
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+- `set_nested_block_sensitive_nested_attribute` (Block Set) example sensitive set nested block (see [below for nested schema](#nestedblock--set_nested_block_sensitive_nested_attribute))
+
+
+### Nested Schema for `object_attribute`
+
+Optional Attributes:
+
+- `object_attribute_attribute` (String)
+
+
+
+### Nested Schema for `object_attribute_with_nested_object_attribute`
+
+Optional Attributes:
+
+- `nested_object` (Object) (see [below for nested schema](#nestedobjatt--object_attribute_with_nested_object_attribute--nested_object))
+- `object_attribute_attribute` (String)
+
+
+### Nested Schema for `object_attribute_with_nested_object_attribute.nested_object`
+
+Optional Attributes:
+
+- `nested_object_attribute` (String)
+
+
+
+
+### Nested Schema for `sensitive_object_attribute`
+
+Optional Attributes:
+
+- `object_attribute_attribute` (String)
+
+
+
+### Nested Schema for `list_nested_block`
+
+Optional Attributes:
+
+- `list_nested_block_attribute` (String) example list nested block attribute
+- `list_nested_block_attribute_with_default` (String) example list nested block attribute with default
+
+Blocks:
+
+- `nested_list_block` (Block List) (see [below for nested schema](#nestedblock--list_nested_block--nested_list_block))
+
+
+### Nested Schema for `list_nested_block.nested_list_block`
+
+Optional Attributes:
+
+- `nested_block_string_attribute` (String) example nested block string attribute
+
+
+
+
+### Nested Schema for `list_nested_block_sensitive_nested_attribute`
+
+Optional Attributes:
+
+- `list_nested_block_attribute` (String) example list nested block attribute
+- `list_nested_block_sensitive_attribute` (String, Sensitive) example sensitive list nested block attribute
+
+
+
+### Nested Schema for `set_nested_block`
+
+Optional Attributes:
+
+- `set_nested_block_attribute` (String) example set nested block attribute
+
+
+
+### Nested Schema for `single_nested_block`
+
+Optional Attributes:
+
+- `single_nested_block_attribute` (String) example single nested block attribute
+
+
+
+### Nested Schema for `single_nested_block_sensitive_nested_attribute`
+
+Optional Attributes:
+
+- `single_nested_block_attribute` (String) example single nested block attribute
+- `single_nested_block_sensitive_attribute` (String, Sensitive) example sensitive single nested block attribute
+
+
+
+### Nested Schema for `set_nested_block_sensitive_nested_attribute`
+
+Read-Only:
+
+- `set_nested_block_attribute` (String) example set nested block attribute
+- `set_nested_block_sensitive_attribute` (String, Sensitive) example sensitive set nested block attribute
+-- expected-function.md --
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "scaffolding function - terraform-provider-scaffolding"
+subcategory: ""
+description: |-
+ Echo a string test test
+---
+
+# function: scaffolding
+
+Given a string value, returns the same value.
+
+
+
+## Signature
+
+
+```text
+scaffolding(stringInput string, boolInput bool, float64Input number, int64Input number, listStringInput list of string, mapStringInput map of string, numberInput number, objectInput object, setStringInput set of string, variadicParam string...) string
+```
+
+## Arguments
+
+
+1. `stringInput` (String) Value to echo testing
+1. `boolInput` (Boolean) Value to echo testing
+1. `float64Input` (Number) Float64 Value to echo
+1. `int64Input` (Number) Int64 Value to echo
+1. `listStringInput` (List of String) List of strings to echo
+1. `mapStringInput` (Map of String) Map of strings to echo
+1. `numberInput` (Number) Number to echo
+1. `objectInput` (Object) Object to echo
+1. `setStringInput` (Set of String) Set of strings to echo
+
+1. `variadicParam` (Variadic, String) Value to echo
+-- schema.json --
+{
+ "format_version": "1.0",
+ "provider_schemas": {
+ "registry.terraform.io/hashicorp/scaffolding": {
+ "provider": {
+ "version": 0,
+ "block": {
+ "attributes": {
+ "endpoint": {
+ "type": "string",
+ "description": "Example provider attribute",
+ "description_kind": "markdown",
+ "optional": true
+ }
+ },
+ "description": "Example provider",
+ "description_kind": "markdown"
+ }
+ },
+ "resource_schemas": {
+ "scaffolding_example": {
+ "version": 0,
+ "block": {
+ "attributes": {
+ "bool_attribute": {
+ "type": "bool",
+ "description": "example bool attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "float64_attribute": {
+ "type": "number",
+ "description": "example float64 attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "id": {
+ "type": "string",
+ "description_kind": "plain",
+ "computed": true
+ },
+ "int64_attribute": {
+ "type": "number",
+ "description": "example int64 attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "list_attribute": {
+ "type": [
+ "list",
+ "string"
+ ],
+ "description": "example list attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "map_attribute": {
+ "type": [
+ "map",
+ "string"
+ ],
+ "description": "example map attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "number_attribute": {
+ "type": "number",
+ "description": "example number attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "object_attribute": {
+ "type": [
+ "object",
+ {
+ "object_attribute_attribute": "string"
+ }
+ ],
+ "description": "example object attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "object_attribute_with_nested_object_attribute": {
+ "type": [
+ "object",
+ {
+ "nested_object": [
+ "object",
+ {
+ "nested_object_attribute": "string"
+ }
+ ],
+ "object_attribute_attribute": "string"
+ }
+ ],
+ "description": "example object attribute with nested object attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "sensitive_bool_attribute": {
+ "type": "bool",
+ "description": "example sensitive bool attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "sensitive_float64_attribute": {
+ "type": "number",
+ "description": "example sensitive float64 attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "sensitive_int64_attribute": {
+ "type": "number",
+ "description": "example sensitive int64 attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "sensitive_list_attribute": {
+ "type": [
+ "list",
+ "string"
+ ],
+ "description": "example sensitive list attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "sensitive_map_attribute": {
+ "type": [
+ "map",
+ "string"
+ ],
+ "description": "example sensitive map attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "sensitive_number_attribute": {
+ "type": "number",
+ "description": "example sensitive number attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "sensitive_object_attribute": {
+ "type": [
+ "object",
+ {
+ "object_attribute_attribute": "string"
+ }
+ ],
+ "description": "example sensitive object attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "sensitive_set_attribute": {
+ "type": [
+ "set",
+ "string"
+ ],
+ "description": "example sensitive set attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "sensitive_string_attribute": {
+ "type": "string",
+ "description": "example sensitive string attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ },
+ "set_attribute": {
+ "type": [
+ "set",
+ "string"
+ ],
+ "description": "example set attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "string_attribute": {
+ "type": "string",
+ "description": "example string attribute",
+ "description_kind": "markdown",
+ "optional": true
+ }
+ },
+ "block_types": {
+ "list_nested_block": {
+ "nesting_mode": "list",
+ "block": {
+ "attributes": {
+ "list_nested_block_attribute": {
+ "type": "string",
+ "description": "example list nested block attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "list_nested_block_attribute_with_default": {
+ "type": "string",
+ "description": "example list nested block attribute with default",
+ "description_kind": "markdown",
+ "optional": true,
+ "computed": true
+ }
+ },
+ "block_types": {
+ "nested_list_block": {
+ "nesting_mode": "list",
+ "block": {
+ "attributes": {
+ "nested_block_string_attribute": {
+ "type": "string",
+ "description": "example nested block string attribute",
+ "description_kind": "markdown",
+ "optional": true
+ }
+ },
+ "description_kind": "plain"
+ }
+ }
+ },
+ "description": "example list nested block",
+ "description_kind": "markdown"
+ }
+ },
+ "list_nested_block_sensitive_nested_attribute": {
+ "nesting_mode": "list",
+ "block": {
+ "attributes": {
+ "list_nested_block_attribute": {
+ "type": "string",
+ "description": "example list nested block attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "list_nested_block_sensitive_attribute": {
+ "type": "string",
+ "description": "example sensitive list nested block attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ }
+ },
+ "description_kind": "plain"
+ }
+ },
+ "set_nested_block": {
+ "nesting_mode": "set",
+ "block": {
+ "attributes": {
+ "set_nested_block_attribute": {
+ "type": "string",
+ "description": "example set nested block attribute",
+ "description_kind": "markdown",
+ "optional": true
+ }
+ },
+ "description": "example set nested block",
+ "description_kind": "markdown"
+ }
+ },
+ "set_nested_block_sensitive_nested_attribute": {
+ "nesting_mode": "set",
+ "block": {
+ "attributes": {
+ "set_nested_block_attribute": {
+ "type": "string",
+ "description": "example set nested block attribute",
+ "description_kind": "markdown",
+ "computed": true
+ },
+ "set_nested_block_sensitive_attribute": {
+ "type": "string",
+ "description": "example sensitive set nested block attribute",
+ "description_kind": "markdown",
+ "computed": true,
+ "sensitive": true
+ }
+ },
+ "description": "example sensitive set nested block",
+ "description_kind": "markdown"
+ }
+ },
+ "single_nested_block": {
+ "nesting_mode": "single",
+ "block": {
+ "attributes": {
+ "single_nested_block_attribute": {
+ "type": "string",
+ "description": "example single nested block attribute",
+ "description_kind": "markdown",
+ "optional": true
+ }
+ },
+ "description": "example single nested block",
+ "description_kind": "markdown"
+ }
+ },
+ "single_nested_block_sensitive_nested_attribute": {
+ "nesting_mode": "single",
+ "block": {
+ "attributes": {
+ "single_nested_block_attribute": {
+ "type": "string",
+ "description": "example single nested block attribute",
+ "description_kind": "markdown",
+ "optional": true
+ },
+ "single_nested_block_sensitive_attribute": {
+ "type": "string",
+ "description": "example sensitive single nested block attribute",
+ "description_kind": "markdown",
+ "optional": true,
+ "sensitive": true
+ }
+ },
+ "description": "example sensitive single nested block",
+ "description_kind": "markdown"
+ }
+ }
+ },
+ "description": "example resource",
+ "description_kind": "plain"
+ }
+ }
+ },
+ "functions": {
+ "scaffolding": {
+ "description": "Given a string value, returns the same value.",
+ "summary": "Echo a string test test",
+ "return_type": "string",
+ "parameters": [
+ {
+ "name": "stringInput",
+ "description": "Value to echo testing",
+ "type": "string"
+ },
+ {
+ "name": "boolInput",
+ "description": "Value to echo testing",
+ "type": "bool"
+ },
+ {
+ "name": "float64Input",
+ "description": "Float64 Value to echo",
+ "type": "number"
+ },
+ {
+ "name": "int64Input",
+ "description": "Int64 Value to echo",
+ "type": "number"
+ },
+ {
+ "name": "listStringInput",
+ "description": "List of strings to echo",
+ "type": [
+ "list",
+ "string"
+ ]
+ },
+ {
+ "name": "mapStringInput",
+ "description": "Map of strings to echo",
+ "type": [
+ "map",
+ "string"
+ ]
+ },
+ {
+ "name": "numberInput",
+ "description": "Number to echo",
+ "type": "number"
+ },
+ {
+ "name": "objectInput",
+ "description": "Object to echo",
+ "type": [
+ "object",
+ {
+ "attr1": "string",
+ "attr2": "number"
+ }
+ ]
+ },
+ {
+ "name": "setStringInput",
+ "description": "Set of strings to echo",
+ "type": [
+ "set",
+ "string"
+ ]
+ }
+ ],
+ "variadic_parameter": {
+ "name": "variadicParam",
+ "description": "Value to echo",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/internal/cmd/generate.go b/internal/cmd/generate.go
index 77dbc96..c7ba937 100644
--- a/internal/cmd/generate.go
+++ b/internal/cmd/generate.go
@@ -19,6 +19,7 @@ type generateCmd struct {
flagProviderName string
flagRenderedProviderName string
+ flagBlocksSection bool
flagProviderDir string
flagProvidersSchema string
flagRenderedWebsiteDir string
@@ -72,6 +73,7 @@ func (cmd *generateCmd) Help() string {
func (cmd *generateCmd) Flags() *flag.FlagSet {
fs := flag.NewFlagSet("generate", flag.ExitOnError)
+ fs.BoolVar(&cmd.flagBlocksSection, "blocks-section", false, "render blocks in a separate section instead of including them with attributes in the required and optional sections.")
fs.StringVar(&cmd.flagProviderName, "provider-name", "", "provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)")
fs.StringVar(&cmd.flagProviderDir, "provider-dir", "", "relative or absolute path to the root provider code directory when running the command outside the root provider code directory")
fs.StringVar(&cmd.flagProvidersSchema, "providers-schema", "", "path to the providers schema JSON file, which contains the output of the terraform providers schema -json command. Setting this flag will skip building the provider and calling Terraform CLI")
@@ -109,6 +111,7 @@ func (cmd *generateCmd) runInternal() error {
cmd.flagWebsiteSourceDir,
cmd.tfVersion,
cmd.flagIgnoreDeprecated,
+ cmd.flagBlocksSection,
)
if err != nil {
return fmt.Errorf("unable to generate website: %w", err)
diff --git a/internal/provider/generate.go b/internal/provider/generate.go
index d0c3c96..1325d78 100644
--- a/internal/provider/generate.go
+++ b/internal/provider/generate.go
@@ -79,6 +79,7 @@ var (
)
type generator struct {
+ blocksSection bool
ignoreDeprecated bool
tfVersion string
@@ -104,7 +105,7 @@ func (g *generator) warnf(format string, a ...interface{}) {
g.ui.Warn(fmt.Sprintf(format, a...))
}
-func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, renderedProviderName, renderedWebsiteDir, examplesDir, websiteTmpDir, templatesDir, tfVersion string, ignoreDeprecated bool) error {
+func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, renderedProviderName, renderedWebsiteDir, examplesDir, websiteTmpDir, templatesDir, tfVersion string, ignoreDeprecated, blocksSection bool) error {
// Ensure provider directory is resolved absolute path
if providerDir == "" {
wd, err := os.Getwd()
@@ -136,6 +137,7 @@ func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, rendere
}
g := &generator{
+ blocksSection: blocksSection,
ignoreDeprecated: ignoreDeprecated,
tfVersion: tfVersion,
@@ -231,7 +233,7 @@ func (g *generator) Generate(ctx context.Context) error {
}
g.infof("rendering static website")
- err = g.renderStaticWebsite(providerSchema)
+ err = g.renderStaticWebsite(providerSchema, g.blocksSection)
if err != nil {
return fmt.Errorf("error rendering static website: %w", err)
}
@@ -442,7 +444,7 @@ func (g *generator) generateMissingTemplates(providerSchema *tfjson.ProviderSche
return nil
}
-func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) error {
+func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema, blocksSection bool) error {
g.infof("cleaning rendered website dir")
dirEntry, err := os.ReadDir(g.ProviderDocsDir())
if err != nil && !os.IsNotExist(err) {
@@ -532,7 +534,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
if resSchema != nil {
tmpl := resourceTemplate(tmplData)
- render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Data Source", exampleFilePath, "", resSchema)
+ render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Data Source", exampleFilePath, "", resSchema, blocksSection)
if err != nil {
return fmt.Errorf("unable to render data source template %q: %w", rel, err)
}
@@ -550,7 +552,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
if resSchema != nil {
tmpl := resourceTemplate(tmplData)
- render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Resource", exampleFilePath, importFilePath, resSchema)
+ render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Resource", exampleFilePath, importFilePath, resSchema, blocksSection)
if err != nil {
return fmt.Errorf("unable to render resource template %q: %w", rel, err)
}
@@ -583,7 +585,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
if relFile == "index.md.tmpl" {
tmpl := providerTemplate(tmplData)
exampleFilePath := filepath.Join(g.ProviderExamplesDir(), "provider", "provider.tf")
- render, err := tmpl.Render(g.providerDir, g.providerName, g.renderedProviderName, exampleFilePath, providerSchema.ConfigSchema)
+ render, err := tmpl.Render(g.providerDir, g.providerName, g.renderedProviderName, exampleFilePath, providerSchema.ConfigSchema, blocksSection)
if err != nil {
return fmt.Errorf("unable to render provider template %q: %w", rel, err)
}
diff --git a/internal/provider/template.go b/internal/provider/template.go
index 5876648..63baa59 100644
--- a/internal/provider/template.go
+++ b/internal/provider/template.go
@@ -120,9 +120,9 @@ func (t docTemplate) Render(providerDir string, out io.Writer) error {
return renderTemplate(providerDir, "docTemplate", s, out, nil)
}
-func (t providerTemplate) Render(providerDir, providerName, renderedProviderName, exampleFile string, schema *tfjson.Schema) (string, error) {
+func (t providerTemplate) Render(providerDir, providerName, renderedProviderName, exampleFile string, schema *tfjson.Schema, blocksSection bool) (string, error) {
schemaBuffer := bytes.NewBuffer(nil)
- err := schemamd.Render(schema, schemaBuffer)
+ err := schemamd.Render(schema, schemaBuffer, blocksSection)
if err != nil {
return "", fmt.Errorf("unable to render schema: %w", err)
}
@@ -158,9 +158,9 @@ func (t providerTemplate) Render(providerDir, providerName, renderedProviderName
})
}
-func (t resourceTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile, importFile string, schema *tfjson.Schema) (string, error) {
+func (t resourceTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile, importFile string, schema *tfjson.Schema, blocksSection bool) (string, error) {
schemaBuffer := bytes.NewBuffer(nil)
- err := schemamd.Render(schema, schemaBuffer)
+ err := schemamd.Render(schema, schemaBuffer, blocksSection)
if err != nil {
return "", fmt.Errorf("unable to render schema: %w", err)
}
diff --git a/internal/provider/template_test.go b/internal/provider/template_test.go
index 82bcc3b..cdd0af3 100644
--- a/internal/provider/template_test.go
+++ b/internal/provider/template_test.go
@@ -93,7 +93,7 @@ provider "scaffolding" {
},
}
- result, err := tpl.Render("testdata/test-provider-dir", "testTemplate", "test-provider", "test-provider", "Resource", "provider.tf", "provider.tf", &schema)
+ result, err := tpl.Render("testdata/test-provider-dir", "testTemplate", "test-provider", "test-provider", "Resource", "provider.tf", "provider.tf", &schema, false)
if err != nil {
t.Error(err)
}
@@ -133,7 +133,7 @@ provider "scaffolding" {
},
}
- result, err := tpl.Render("testdata/test-provider-dir", "testTemplate", "test-provider", "provider.tf", &schema)
+ result, err := tpl.Render("testdata/test-provider-dir", "testTemplate", "test-provider", "provider.tf", &schema, false)
if err != nil {
t.Error(err)
}
diff --git a/internal/schemamd/behaviors.go b/internal/schemamd/behaviors.go
index f0006ef..f56403d 100644
--- a/internal/schemamd/behaviors.go
+++ b/internal/schemamd/behaviors.go
@@ -77,3 +77,11 @@ func childBlockIsReadOnly(block *tfjson.SchemaBlockType) bool {
return true
}
+
+func childBlockIsWritable(block *tfjson.SchemaBlockType) bool {
+ return !childBlockIsReadOnly(block)
+}
+
+func omitChild[T *tfjson.SchemaAttribute | *tfjson.SchemaBlockType](_ T) bool {
+ return false
+}
diff --git a/internal/schemamd/render.go b/internal/schemamd/render.go
index a459d0b..3cf20ec 100644
--- a/internal/schemamd/render.go
+++ b/internal/schemamd/render.go
@@ -21,13 +21,13 @@ import (
// },
// "version": 0
// },
-func Render(schema *tfjson.Schema, w io.Writer) error {
+func Render(schema *tfjson.Schema, w io.Writer, blocksSection bool) error {
_, err := io.WriteString(w, "## Schema\n\n")
if err != nil {
return err
}
- err = writeRootBlock(w, schema.Block)
+ err = writeRootBlock(w, schema.Block, blocksSection)
if err != nil {
return fmt.Errorf("unable to render schema: %w", err)
}
@@ -49,13 +49,29 @@ var (
// * Required
// * Optional
// * Read-Only
- groupFilters = []groupFilter{
+ defaultGroupFilters = []groupFilter{
{"### Required", "Required:", childAttributeIsRequired, childBlockIsRequired},
{"### Optional", "Optional:", childAttributeIsOptional, childBlockIsOptional},
{"### Read-Only", "Read-Only:", childAttributeIsReadOnly, childBlockIsReadOnly},
}
+
+ // When --blocks-section is enabled, blocks are rendered in a separate section regardless of their optional or required characteristics.
+ blocksSectionGroupFilters = []groupFilter{
+ {"### Required Attributes", "Required Attributes:", childAttributeIsRequired, omitChild[*tfjson.SchemaBlockType]},
+ {"### Optional Attributes", "Optional Attributes:", childAttributeIsOptional, omitChild[*tfjson.SchemaBlockType]},
+ {"### Blocks", "Blocks:", omitChild[*tfjson.SchemaAttribute], childBlockIsWritable},
+ {"### Read-Only", "Read-Only:", childAttributeIsReadOnly, childBlockIsReadOnly},
+ }
)
+func getGroupFilters(blocksSection bool) []groupFilter {
+ if blocksSection {
+ return blocksSectionGroupFilters
+ }
+
+ return defaultGroupFilters
+}
+
type nestedType struct {
anchorID string
pathTitle string
@@ -179,8 +195,8 @@ func writeBlockType(w io.Writer, path []string, block *tfjson.SchemaBlockType) (
return []nestedType{nt}, nil
}
-func writeRootBlock(w io.Writer, block *tfjson.SchemaBlock) error {
- return writeBlockChildren(w, nil, block, true)
+func writeRootBlock(w io.Writer, block *tfjson.SchemaBlock, blocksSection bool) error {
+ return writeBlockChildren(w, nil, block, true, blocksSection)
}
// A Block contains:
@@ -210,7 +226,7 @@ func writeRootBlock(w io.Writer, block *tfjson.SchemaBlock) error {
// },
// "description_kind": "plain"
// },
-func writeBlockChildren(w io.Writer, parents []string, block *tfjson.SchemaBlock, root bool) error {
+func writeBlockChildren(w io.Writer, parents []string, block *tfjson.SchemaBlock, root bool, blocksSection bool) error {
names := []string{}
for n := range block.Attributes {
names = append(names, n)
@@ -221,6 +237,7 @@ func writeBlockChildren(w io.Writer, parents []string, block *tfjson.SchemaBlock
groups := map[int][]string{}
+ groupFilters := getGroupFilters(blocksSection)
// Group Attributes/Blocks by characteristics.
nameLoop:
for _, n := range names {
@@ -336,7 +353,7 @@ nameLoop:
}
}
- err := writeNestedTypes(w, nestedTypes)
+ err := writeNestedTypes(w, nestedTypes, blocksSection)
if err != nil {
return err
}
@@ -344,7 +361,7 @@ nameLoop:
return nil
}
-func writeNestedTypes(w io.Writer, nestedTypes []nestedType) error {
+func writeNestedTypes(w io.Writer, nestedTypes []nestedType, blocksSection bool) error {
for _, nt := range nestedTypes {
_, err := io.WriteString(w, "\n")
if err != nil {
@@ -358,17 +375,17 @@ func writeNestedTypes(w io.Writer, nestedTypes []nestedType) error {
switch {
case nt.block != nil:
- err = writeBlockChildren(w, nt.path, nt.block, false)
+ err = writeBlockChildren(w, nt.path, nt.block, false, blocksSection)
if err != nil {
return err
}
case nt.object != nil:
- err = writeObjectChildren(w, nt.path, *nt.object, nt.group)
+ err = writeObjectChildren(w, nt.path, *nt.object, nt.group, blocksSection)
if err != nil {
return err
}
case nt.attrs != nil:
- err = writeNestedAttributeChildren(w, nt.path, nt.attrs, nt.group)
+ err = writeNestedAttributeChildren(w, nt.path, nt.attrs, nt.group, blocksSection)
if err != nil {
return err
}
@@ -450,7 +467,7 @@ func writeObjectAttribute(w io.Writer, path []string, att cty.Type, group groupF
return nestedTypes, nil
}
-func writeObjectChildren(w io.Writer, parents []string, ty cty.Type, group groupFilter) error {
+func writeObjectChildren(w io.Writer, parents []string, ty cty.Type, group groupFilter, blocksSection bool) error {
_, err := io.WriteString(w, group.nestedTitle+"\n\n")
if err != nil {
return err
@@ -483,7 +500,7 @@ func writeObjectChildren(w io.Writer, parents []string, ty cty.Type, group group
return err
}
- err = writeNestedTypes(w, nestedTypes)
+ err = writeNestedTypes(w, nestedTypes, blocksSection)
if err != nil {
return err
}
@@ -491,13 +508,14 @@ func writeObjectChildren(w io.Writer, parents []string, ty cty.Type, group group
return nil
}
-func writeNestedAttributeChildren(w io.Writer, parents []string, nestedAttributes *tfjson.SchemaNestedAttributeType, group groupFilter) error {
+func writeNestedAttributeChildren(w io.Writer, parents []string, nestedAttributes *tfjson.SchemaNestedAttributeType, group groupFilter, blocksSection bool) error {
sortedNames := []string{}
for n := range nestedAttributes.Attributes {
sortedNames = append(sortedNames, n)
}
sort.Strings(sortedNames)
+ groupFilters := getGroupFilters(blocksSection)
groups := map[int][]string{}
for _, name := range sortedNames {
att := nestedAttributes.Attributes[name]
@@ -542,7 +560,7 @@ func writeNestedAttributeChildren(w io.Writer, parents []string, nestedAttribute
}
}
- err := writeNestedTypes(w, nestedTypes)
+ err := writeNestedTypes(w, nestedTypes, blocksSection)
if err != nil {
return err
}
diff --git a/internal/schemamd/render_test.go b/internal/schemamd/render_test.go
index 1770be4..f698ea3 100644
--- a/internal/schemamd/render_test.go
+++ b/internal/schemamd/render_test.go
@@ -19,40 +19,60 @@ func TestRender(t *testing.T) {
t.Parallel()
for _, c := range []struct {
- name string
- inputFile string
- expectedFile string
+ name string
+ inputFile string
+ expectedFile string
+ blocksSection bool
}{
{
"aws_route_table_association",
"testdata/aws_route_table_association.schema.json",
"testdata/aws_route_table_association.md",
+ false,
},
{
"aws_acm_certificate",
"testdata/aws_acm_certificate.schema.json",
"testdata/aws_acm_certificate.md",
+ false,
},
{
"awscc_logs_log_group",
"testdata/awscc_logs_log_group.schema.json",
"testdata/awscc_logs_log_group.md",
+ false,
},
{
"awscc_acmpca_certificate",
"testdata/awscc_acmpca_certificate.schema.json",
"testdata/awscc_acmpca_certificate.md",
+ false,
},
{
"framework_types",
"testdata/framework_types.schema.json",
"testdata/framework_types.md",
+ false,
+ },
+ {
+ "framework_types_blocks_section",
+ "testdata/framework_types.schema.json",
+ "testdata/framework_types_blocks_section.md",
+ true,
},
{
// Reference: https://github.com/hashicorp/terraform-plugin-docs/issues/380
"deep_nested_attributes",
"testdata/deep_nested_attributes.schema.json",
"testdata/deep_nested_attributes.md",
+ false,
+ },
+ {
+ // Reference: https://github.com/hashicorp/terraform-plugin-docs/issues/380
+ "deep_nested_attributes_blocks_section",
+ "testdata/deep_nested_attributes.schema.json",
+ "testdata/deep_nested_attributes_blocks_section.md",
+ true,
},
} {
c := c
@@ -77,7 +97,7 @@ func TestRender(t *testing.T) {
}
b := &strings.Builder{}
- err = schemamd.Render(&schema, b)
+ err = schemamd.Render(&schema, b, c.blocksSection)
if err != nil {
t.Fatal(err)
}
diff --git a/internal/schemamd/testdata/deep_nested_attributes_blocks_section.md b/internal/schemamd/testdata/deep_nested_attributes_blocks_section.md
new file mode 100644
index 0000000..74641a1
--- /dev/null
+++ b/internal/schemamd/testdata/deep_nested_attributes_blocks_section.md
@@ -0,0 +1,46 @@
+## Schema
+
+### Required Attributes
+
+- `level_one` (Attributes) (see [below for nested schema](#nestedatt--level_one))
+
+### Read-Only
+
+- `id` (String) Example identifier
+
+
+### Nested Schema for `level_one`
+
+Optional Attributes:
+
+- `level_two` (Attributes) (see [below for nested schema](#nestedatt--level_one--level_two))
+
+
+### Nested Schema for `level_one.level_two`
+
+Optional Attributes:
+
+- `level_three` (Attributes) (see [below for nested schema](#nestedatt--level_one--level_two--level_three))
+
+
+### Nested Schema for `level_one.level_two.level_three`
+
+Optional Attributes:
+
+- `level_four_primary` (Attributes) (see [below for nested schema](#nestedatt--level_one--level_two--level_three--level_four_primary))
+- `level_four_secondary` (String)
+
+
+### Nested Schema for `level_one.level_two.level_three.level_four_primary`
+
+Optional Attributes:
+
+- `level_five` (Attributes) Parent should be level_one.level_two.level_three.level_four_primary. (see [below for nested schema](#nestedatt--level_one--level_two--level_three--level_four_primary--level_five))
+- `level_four_primary_string` (String) Parent should be level_one.level_two.level_three.level_four_primary.
+
+
+### Nested Schema for `level_one.level_two.level_three.level_four_primary.level_five`
+
+Optional Attributes:
+
+- `level_five_string` (String) Parent should be level_one.level_two.level_three.level_four_primary.level_five.
diff --git a/internal/schemamd/testdata/framework_types_blocks_section.md b/internal/schemamd/testdata/framework_types_blocks_section.md
new file mode 100644
index 0000000..6601fab
--- /dev/null
+++ b/internal/schemamd/testdata/framework_types_blocks_section.md
@@ -0,0 +1,132 @@
+## Schema
+
+### Optional Attributes
+
+- `bool_attribute` (Boolean) example bool attribute
+- `float64_attribute` (Number) example float64 attribute
+- `int64_attribute` (Number) example int64 attribute
+- `list_attribute` (List of String) example list attribute
+- `map_attribute` (Map of String) example map attribute
+- `number_attribute` (Number) example number attribute
+- `object_attribute` (Object) example object attribute (see [below for nested schema](#nestedatt--object_attribute))
+- `object_attribute_with_nested_object_attribute` (Object) example object attribute with nested object attribute (see [below for nested schema](#nestedatt--object_attribute_with_nested_object_attribute))
+- `sensitive_bool_attribute` (Boolean, Sensitive) example sensitive bool attribute
+- `sensitive_float64_attribute` (Number, Sensitive) example sensitive float64 attribute
+- `sensitive_int64_attribute` (Number, Sensitive) example sensitive int64 attribute
+- `sensitive_list_attribute` (List of String, Sensitive) example sensitive list attribute
+- `sensitive_map_attribute` (Map of String, Sensitive) example sensitive map attribute
+- `sensitive_number_attribute` (Number, Sensitive) example sensitive number attribute
+- `sensitive_object_attribute` (Object, Sensitive) example sensitive object attribute (see [below for nested schema](#nestedatt--sensitive_object_attribute))
+- `sensitive_set_attribute` (Set of String, Sensitive) example sensitive set attribute
+- `sensitive_string_attribute` (String, Sensitive) example sensitive string attribute
+- `set_attribute` (Set of String) example set attribute
+- `string_attribute` (String) example string attribute
+
+### Blocks
+
+- `list_nested_block` (Block List) example list nested block (see [below for nested schema](#nestedblock--list_nested_block))
+- `list_nested_block_sensitive_nested_attribute` (Block List) (see [below for nested schema](#nestedblock--list_nested_block_sensitive_nested_attribute))
+- `set_nested_block` (Block Set) example set nested block (see [below for nested schema](#nestedblock--set_nested_block))
+- `single_nested_block` (Block, Optional) example single nested block (see [below for nested schema](#nestedblock--single_nested_block))
+- `single_nested_block_sensitive_nested_attribute` (Block, Optional) example sensitive single nested block (see [below for nested schema](#nestedblock--single_nested_block_sensitive_nested_attribute))
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+- `set_nested_block_sensitive_nested_attribute` (Block Set) example sensitive set nested block (see [below for nested schema](#nestedblock--set_nested_block_sensitive_nested_attribute))
+
+
+### Nested Schema for `object_attribute`
+
+Optional Attributes:
+
+- `object_attribute_attribute` (String)
+
+
+
+### Nested Schema for `object_attribute_with_nested_object_attribute`
+
+Optional Attributes:
+
+- `nested_object` (Object) (see [below for nested schema](#nestedobjatt--object_attribute_with_nested_object_attribute--nested_object))
+- `object_attribute_attribute` (String)
+
+
+### Nested Schema for `object_attribute_with_nested_object_attribute.nested_object`
+
+Optional Attributes:
+
+- `nested_object_attribute` (String)
+
+
+
+
+### Nested Schema for `sensitive_object_attribute`
+
+Optional Attributes:
+
+- `object_attribute_attribute` (String)
+
+
+
+### Nested Schema for `list_nested_block`
+
+Optional Attributes:
+
+- `list_nested_block_attribute` (String) example list nested block attribute
+- `list_nested_block_attribute_with_default` (String) example list nested block attribute with default
+
+Blocks:
+
+- `nested_list_block` (Block List) (see [below for nested schema](#nestedblock--list_nested_block--nested_list_block))
+
+
+### Nested Schema for `list_nested_block.nested_list_block`
+
+Optional Attributes:
+
+- `nested_block_string_attribute` (String) example nested block string attribute
+
+
+
+
+### Nested Schema for `list_nested_block_sensitive_nested_attribute`
+
+Optional Attributes:
+
+- `list_nested_block_attribute` (String) example list nested block attribute
+- `list_nested_block_sensitive_attribute` (String, Sensitive) example sensitive list nested block attribute
+
+
+
+### Nested Schema for `set_nested_block`
+
+Optional Attributes:
+
+- `set_nested_block_attribute` (String) example set nested block attribute
+
+
+
+### Nested Schema for `single_nested_block`
+
+Optional Attributes:
+
+- `single_nested_block_attribute` (String) example single nested block attribute
+
+
+
+### Nested Schema for `single_nested_block_sensitive_nested_attribute`
+
+Optional Attributes:
+
+- `single_nested_block_attribute` (String) example single nested block attribute
+- `single_nested_block_sensitive_attribute` (String, Sensitive) example sensitive single nested block attribute
+
+
+
+### Nested Schema for `set_nested_block_sensitive_nested_attribute`
+
+Read-Only:
+
+- `set_nested_block_attribute` (String) example set nested block attribute
+- `set_nested_block_sensitive_attribute` (String, Sensitive) example sensitive set nested block attribute