diff --git a/.changes/unreleased/BUG FIXES-20240410-154619.yaml b/.changes/unreleased/BUG FIXES-20240410-154619.yaml new file mode 100644 index 00000000..4302f892 --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20240410-154619.yaml @@ -0,0 +1,6 @@ +kind: BUG FIXES +body: 'generate: fixed a bug where incorrect attribute titles were being generated + for certain nested schemas' +time: 2024-04-10T15:46:19.65146-04:00 +custom: + Issue: "350" diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_nested_blocks.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_nested_blocks.txtar new file mode 100644 index 00000000..ff93eef6 --- /dev/null +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_nested_blocks.txtar @@ -0,0 +1,744 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# Successful run of tfplugindocs on a Framework provider with a resource schema that contains nested types +[!unix] skip +exec tfplugindocs --provider-name=terraform-provider-scaffolding --providers-schema=schema.json +cmp stdout expected-output.txt +cmp docs/index.md expected-index.md +cmp docs/resources/example.md expected-resource.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 missing provider content +generating new template for "terraform-provider-scaffolding" +rendering static website +cleaning rendered website dir +rendering templated website to static markdown +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 + +- `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: |- + A certificate issued via a private certificate authority +--- + +# scaffolding_example (Resource) + +A certificate issued via a private certificate authority + + + + +## Schema + +### Required + +- `certificate_authority_arn` (String) +- `certificate_signing_request` (String) The certificate signing request (CSR) for the Certificate. +- `signing_algorithm` (String) The name of the algorithm that will be used to sign the Certificate. +- `validity` (Attributes) Validity for a certificate. (see [below for nested schema](#nestedatt--validity)) + +### Optional + +- `api_passthrough` (Attributes) Structure that specifies fields to be overridden in a certificate at the time of issuance. These requires an API Passthrough template be used or they will be ignored. (see [below for nested schema](#nestedatt--api_passthrough)) +- `template_arn` (String) +- `validity_not_before` (Attributes) Validity for a certificate. (see [below for nested schema](#nestedatt--validity_not_before)) + +### Read-Only + +- `arn` (String) +- `certificate` (String) The issued certificate in base 64 PEM-encoded format. +- `id` (String) Uniquely identifies the resource. + + +### Nested Schema for `validity` + +Required: + +- `type` (String) +- `value` (Number) + + + +### Nested Schema for `api_passthrough` + +Optional: + +- `extensions` (Attributes) Structure that contains X.500 extensions for a Certificate. (see [below for nested schema](#nestedatt--api_passthrough--extensions)) +- `subject` (Attributes) Structure that contains X.500 distinguished name information. (see [below for nested schema](#nestedatt--api_passthrough--subject)) + + +### Nested Schema for `api_passthrough.extensions` + +Optional: + +- `certificate_policies` (Attributes List) (see [below for nested schema](#nestedatt--api_passthrough--extensions--certificate_policies)) +- `extended_key_usage` (Attributes List) (see [below for nested schema](#nestedatt--api_passthrough--extensions--extended_key_usage)) +- `key_usage` (Attributes) Structure that contains X.509 KeyUsage information. (see [below for nested schema](#nestedatt--api_passthrough--extensions--key_usage)) +- `subject_alternative_names` (Attributes List) (see [below for nested schema](#nestedatt--api_passthrough--extensions--subject_alternative_names)) + + +### Nested Schema for `api_passthrough.extensions.certificate_policies` + +Required: + +- `cert_policy_id` (String) String that contains X.509 ObjectIdentifier information. + +Optional: + +- `policy_qualifiers` (Attributes List) (see [below for nested schema](#nestedatt--api_passthrough--extensions--certificate_policies--policy_qualifiers)) + + +### Nested Schema for `api_passthrough.extensions.certificate_policies.policy_qualifiers` + +Required: + +- `policy_qualifier_id` (String) +- `qualifier` (Attributes) Structure that contains a X.509 policy qualifier. (see [below for nested schema](#nestedatt--api_passthrough--extensions--certificate_policies--policy_qualifiers--qualifier)) + + +### Nested Schema for `api_passthrough.extensions.certificate_policies.policy_qualifiers.qualifier` + +Required: + +- `cps_uri` (String) + + + + + +### Nested Schema for `api_passthrough.extensions.extended_key_usage` + +Optional: + +- `extended_key_usage_object_identifier` (String) String that contains X.509 ObjectIdentifier information. +- `extended_key_usage_type` (String) + + + +### Nested Schema for `api_passthrough.extensions.key_usage` + +Optional: + +- `crl_sign` (Boolean) +- `data_encipherment` (Boolean) +- `decipher_only` (Boolean) +- `digital_signature` (Boolean) +- `encipher_only` (Boolean) +- `key_agreement` (Boolean) +- `key_cert_sign` (Boolean) +- `key_encipherment` (Boolean) +- `non_repudiation` (Boolean) + + + +### Nested Schema for `api_passthrough.extensions.subject_alternative_names` + +Optional: + +- `directory_name` (Attributes) Structure that contains X.500 distinguished name information. (see [below for nested schema](#nestedatt--api_passthrough--extensions--subject_alternative_names--directory_name)) +- `dns_name` (String) String that contains X.509 DnsName information. +- `edi_party_name` (Attributes) Structure that contains X.509 EdiPartyName information. (see [below for nested schema](#nestedatt--api_passthrough--extensions--subject_alternative_names--edi_party_name)) +- `ip_address` (String) String that contains X.509 IpAddress information. +- `other_name` (Attributes) Structure that contains X.509 OtherName information. (see [below for nested schema](#nestedatt--api_passthrough--extensions--subject_alternative_names--other_name)) +- `registered_id` (String) String that contains X.509 ObjectIdentifier information. +- `rfc_822_name` (String) String that contains X.509 Rfc822Name information. +- `uniform_resource_identifier` (String) String that contains X.509 UniformResourceIdentifier information. + + +### Nested Schema for `api_passthrough.extensions.subject_alternative_names.directory_name` + +Optional: + +- `common_name` (String) +- `country` (String) +- `distinguished_name_qualifier` (String) +- `generation_qualifier` (String) +- `given_name` (String) +- `initials` (String) +- `locality` (String) +- `organization` (String) +- `organizational_unit` (String) +- `pseudonym` (String) +- `serial_number` (String) +- `state` (String) +- `surname` (String) +- `title` (String) + + + +### Nested Schema for `api_passthrough.extensions.subject_alternative_names.edi_party_name` + +Required: + +- `name_assigner` (String) +- `party_name` (String) + + + +### Nested Schema for `api_passthrough.extensions.subject_alternative_names.other_name` + +Required: + +- `type_id` (String) String that contains X.509 ObjectIdentifier information. +- `value` (String) + + + + + +### Nested Schema for `api_passthrough.subject` + +Optional: + +- `common_name` (String) +- `country` (String) +- `distinguished_name_qualifier` (String) +- `generation_qualifier` (String) +- `given_name` (String) +- `initials` (String) +- `locality` (String) +- `organization` (String) +- `organizational_unit` (String) +- `pseudonym` (String) +- `serial_number` (String) +- `state` (String) +- `surname` (String) +- `title` (String) + + + + +### Nested Schema for `validity_not_before` + +Required: + +- `type` (String) +- `value` (Number) +-- 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": { + "block": { + "attributes": { + "api_passthrough": { + "computed": true, + "description": "Structure that specifies fields to be overridden in a certificate at the time of issuance. These requires an API Passthrough template be used or they will be ignored.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "extensions": { + "description": "Structure that contains X.500 extensions for a Certificate.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "certificate_policies": { + "description_kind": "plain", + "nested_type": { + "attributes": { + "cert_policy_id": { + "description": "String that contains X.509 ObjectIdentifier information.", + "description_kind": "plain", + "required": true, + "type": "string" + }, + "policy_qualifiers": { + "description_kind": "plain", + "nested_type": { + "attributes": { + "policy_qualifier_id": { + "description_kind": "plain", + "required": true, + "type": "string" + }, + "qualifier": { + "description": "Structure that contains a X.509 policy qualifier.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "cps_uri": { + "description_kind": "plain", + "required": true, + "type": "string" + } + }, + "nesting_mode": "single" + }, + "required": true + } + }, + "nesting_mode": "list" + }, + "optional": true + } + }, + "nesting_mode": "list" + }, + "optional": true + }, + "extended_key_usage": { + "description_kind": "plain", + "nested_type": { + "attributes": { + "extended_key_usage_object_identifier": { + "description": "String that contains X.509 ObjectIdentifier information.", + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "extended_key_usage_type": { + "description_kind": "plain", + "optional": true, + "type": "string" + } + }, + "nesting_mode": "list" + }, + "optional": true + }, + "key_usage": { + "description": "Structure that contains X.509 KeyUsage information.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "crl_sign": { + "description_kind": "plain", + "optional": true, + "type": "bool" + }, + "data_encipherment": { + "description_kind": "plain", + "optional": true, + "type": "bool" + }, + "decipher_only": { + "description_kind": "plain", + "optional": true, + "type": "bool" + }, + "digital_signature": { + "description_kind": "plain", + "optional": true, + "type": "bool" + }, + "encipher_only": { + "description_kind": "plain", + "optional": true, + "type": "bool" + }, + "key_agreement": { + "description_kind": "plain", + "optional": true, + "type": "bool" + }, + "key_cert_sign": { + "description_kind": "plain", + "optional": true, + "type": "bool" + }, + "key_encipherment": { + "description_kind": "plain", + "optional": true, + "type": "bool" + }, + "non_repudiation": { + "description_kind": "plain", + "optional": true, + "type": "bool" + } + }, + "nesting_mode": "single" + }, + "optional": true + }, + "subject_alternative_names": { + "description_kind": "plain", + "nested_type": { + "attributes": { + "directory_name": { + "description": "Structure that contains X.500 distinguished name information.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "common_name": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "country": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "distinguished_name_qualifier": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "generation_qualifier": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "given_name": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "initials": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "locality": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "organization": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "organizational_unit": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "pseudonym": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "serial_number": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "state": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "surname": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "title": { + "description_kind": "plain", + "optional": true, + "type": "string" + } + }, + "nesting_mode": "single" + }, + "optional": true + }, + "dns_name": { + "description": "String that contains X.509 DnsName information.", + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "edi_party_name": { + "description": "Structure that contains X.509 EdiPartyName information.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "name_assigner": { + "description_kind": "plain", + "required": true, + "type": "string" + }, + "party_name": { + "description_kind": "plain", + "required": true, + "type": "string" + } + }, + "nesting_mode": "single" + }, + "optional": true + }, + "ip_address": { + "description": "String that contains X.509 IpAddress information.", + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "other_name": { + "description": "Structure that contains X.509 OtherName information.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "type_id": { + "description": "String that contains X.509 ObjectIdentifier information.", + "description_kind": "plain", + "required": true, + "type": "string" + }, + "value": { + "description_kind": "plain", + "required": true, + "type": "string" + } + }, + "nesting_mode": "single" + }, + "optional": true + }, + "registered_id": { + "description": "String that contains X.509 ObjectIdentifier information.", + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "rfc_822_name": { + "description": "String that contains X.509 Rfc822Name information.", + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "uniform_resource_identifier": { + "description": "String that contains X.509 UniformResourceIdentifier information.", + "description_kind": "plain", + "optional": true, + "type": "string" + } + }, + "nesting_mode": "list" + }, + "optional": true + } + }, + "nesting_mode": "single" + }, + "optional": true + }, + "subject": { + "description": "Structure that contains X.500 distinguished name information.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "common_name": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "country": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "distinguished_name_qualifier": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "generation_qualifier": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "given_name": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "initials": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "locality": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "organization": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "organizational_unit": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "pseudonym": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "serial_number": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "state": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "surname": { + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "title": { + "description_kind": "plain", + "optional": true, + "type": "string" + } + }, + "nesting_mode": "single" + }, + "optional": true + } + }, + "nesting_mode": "single" + }, + "optional": true + }, + "arn": { + "computed": true, + "description_kind": "plain", + "type": "string" + }, + "certificate": { + "computed": true, + "description": "The issued certificate in base 64 PEM-encoded format.", + "description_kind": "plain", + "type": "string" + }, + "certificate_authority_arn": { + "description_kind": "plain", + "required": true, + "type": "string" + }, + "certificate_signing_request": { + "description": "The certificate signing request (CSR) for the Certificate.", + "description_kind": "plain", + "required": true, + "type": "string" + }, + "id": { + "computed": true, + "description": "Uniquely identifies the resource.", + "description_kind": "plain", + "type": "string" + }, + "signing_algorithm": { + "description": "The name of the algorithm that will be used to sign the Certificate.", + "description_kind": "plain", + "required": true, + "type": "string" + }, + "template_arn": { + "computed": true, + "description_kind": "plain", + "optional": true, + "type": "string" + }, + "validity": { + "description": "Validity for a certificate.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "type": { + "description_kind": "plain", + "required": true, + "type": "string" + }, + "value": { + "description_kind": "plain", + "required": true, + "type": "number" + } + }, + "nesting_mode": "single" + }, + "required": true + }, + "validity_not_before": { + "computed": true, + "description": "Validity for a certificate.", + "description_kind": "plain", + "nested_type": { + "attributes": { + "type": { + "description_kind": "plain", + "required": true, + "type": "string" + }, + "value": { + "description_kind": "plain", + "required": true, + "type": "number" + } + }, + "nesting_mode": "single" + }, + "optional": true + } + }, + "description": "A certificate issued via a private certificate authority", + "description_kind": "plain" + }, + "version": 1 + } + } + } + } +} \ No newline at end of file diff --git a/schemamd/render.go b/schemamd/render.go index 90617d86..77e575d4 100644 --- a/schemamd/render.go +++ b/schemamd/render.go @@ -57,11 +57,12 @@ var ( ) type nestedType struct { - anchorID string - path []string - block *tfjson.SchemaBlock - object *cty.Type - attrs *tfjson.SchemaNestedAttributeType + anchorID string + pathTitle string + path []string + block *tfjson.SchemaBlock + object *cty.Type + attrs *tfjson.SchemaNestedAttributeType group groupFilter } @@ -87,6 +88,7 @@ func writeAttribute(w io.Writer, path []string, att *tfjson.SchemaAttribute, gro } anchorID := "nestedatt--" + strings.Join(path, "--") + pathTitle := strings.Join(path, ".") nestedTypes := []nestedType{} switch { case att.AttributeNestedType != nil: @@ -96,9 +98,10 @@ func writeAttribute(w io.Writer, path []string, att *tfjson.SchemaAttribute, gro } nestedTypes = append(nestedTypes, nestedType{ - anchorID: anchorID, - path: path, - attrs: att.AttributeNestedType, + anchorID: anchorID, + pathTitle: pathTitle, + path: path, + attrs: att.AttributeNestedType, group: group, }) @@ -109,9 +112,10 @@ func writeAttribute(w io.Writer, path []string, att *tfjson.SchemaAttribute, gro } nestedTypes = append(nestedTypes, nestedType{ - anchorID: anchorID, - path: path, - object: &att.AttributeType, + anchorID: anchorID, + pathTitle: pathTitle, + path: path, + object: &att.AttributeType, group: group, }) @@ -123,9 +127,10 @@ func writeAttribute(w io.Writer, path []string, att *tfjson.SchemaAttribute, gro nt := att.AttributeType.ElementType() nestedTypes = append(nestedTypes, nestedType{ - anchorID: anchorID, - path: path, - object: &nt, + anchorID: anchorID, + pathTitle: pathTitle, + path: path, + object: &nt, group: group, }) @@ -153,10 +158,12 @@ func writeBlockType(w io.Writer, path []string, block *tfjson.SchemaBlockType) ( } anchorID := "nestedblock--" + strings.Join(path, "--") + pathTitle := strings.Join(path, ".") nt := nestedType{ - anchorID: anchorID, - path: path, - block: block.Block, + anchorID: anchorID, + pathTitle: pathTitle, + path: path, + block: block.Block, } _, err = io.WriteString(w, " (see [below for nested schema](#"+anchorID+"))") @@ -344,7 +351,7 @@ func writeNestedTypes(w io.Writer, nestedTypes []nestedType) error { return err } - _, err = io.WriteString(w, "### Nested Schema for `"+strings.Join(nt.path, ".")+"`\n\n") + _, err = io.WriteString(w, "### Nested Schema for `"+nt.pathTitle+"`\n\n") if err != nil { return err } diff --git a/schemamd/testdata/awscc_acmpca_certificate.md b/schemamd/testdata/awscc_acmpca_certificate.md index 2d5b36a3..73bc8880 100644 --- a/schemamd/testdata/awscc_acmpca_certificate.md +++ b/schemamd/testdata/awscc_acmpca_certificate.md @@ -115,7 +115,7 @@ Optional: - `uniform_resource_identifier` (String) String that contains X.509 UniformResourceIdentifier information. -### Nested Schema for `api_passthrough.extensions.subject_alternative_names.uniform_resource_identifier` +### Nested Schema for `api_passthrough.extensions.subject_alternative_names.directory_name` Optional: @@ -136,7 +136,7 @@ Optional: -### Nested Schema for `api_passthrough.extensions.subject_alternative_names.uniform_resource_identifier` +### Nested Schema for `api_passthrough.extensions.subject_alternative_names.edi_party_name` Required: @@ -145,7 +145,7 @@ Required: -### Nested Schema for `api_passthrough.extensions.subject_alternative_names.uniform_resource_identifier` +### Nested Schema for `api_passthrough.extensions.subject_alternative_names.other_name` Required: