Skip to content

Commit ff438fa

Browse files
authored
Convert OAS property names to valid Terraform identifiers (#59)
* initial implementation * add docs to design
1 parent 067c31a commit ff438fa

File tree

17 files changed

+228
-51
lines changed

17 files changed

+228
-51
lines changed

DESIGN.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,19 @@ If the field is only present in a schema other than the `read` operation `parame
167167
| [pattern](https://json-schema.org/draft/2020-12/json-schema-validation.html#name-pattern) | [`validators`](https://developer.hashicorp.com/terraform/plugin/code-generation/specification#validators) |
168168
| [uniqueItems](https://json-schema.org/draft/2020-12/json-schema-validation.html#name-uniqueItems) | [`validators`](https://developer.hashicorp.com/terraform/plugin/code-generation/specification#validators) |
169169

170+
### Attribute Names
171+
After all attributes have been [mapped](#oas-types-to-provider-attributes) and any overrides/aliases have been applied, the attribute names mapped from the OAS will be converted (if needed) to valid [Terraform Identifiers](https://developer.hashicorp.com/terraform/language/syntax/configuration#identifiers). This [logic](https://github.com/hashicorp/terraform-plugin-codegen-openapi/blob/main/internal/mapper/util/framework_identifier.go#L25) performs the following, in order:
172+
1. Removes all characters that are NOT alphanumeric or an underscore
173+
2. Removes all leading numbers
174+
3. Inserts an underscore between any lowercase letter that is immediately followed by an uppercase letter
175+
4. Lowercases the final result
176+
177+
See the [test cases](https://github.com/hashicorp/terraform-plugin-codegen-openapi/blob/main/internal/mapper/util/framework_identifier_test.go#L15) for examples on the expectations of this conversion process.
178+
179+
This ensures all properties from an OAS are converted to valid Terraform identifiers, but can technically cause conflicts if multiple distinct OAS properties are scrubbed to the same value:
180+
- `Fake_Thing` -> `fake_thing`
181+
- `fakeThing` -> `fake_thing`
182+
170183
## Known Limitations
171184
As OpenAPI is designed to describe HTTP APIs in general, it doesn't always fully align with [Terraform Provider design principles](https://developer.hashicorp.com/terraform/plugin/best-practices/hashicorp-provider-design-principles). There are pieces of logic in this generator that make assumptions on what portions of the OAS to use when mapping to the provider code specification, however there are some limitations on what can be supported, which are documented below.
172185

internal/cmd/testdata/petstore3/generated_framework_ir.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
}
1919
},
2020
{
21-
"name": "petId",
21+
"name": "pet_id",
2222
"int64": {
2323
"computed_optional_required": "computed"
2424
}
@@ -30,7 +30,7 @@
3030
}
3131
},
3232
{
33-
"name": "shipDate",
33+
"name": "ship_date",
3434
"string": {
3535
"computed_optional_required": "computed",
3636
"description": "A field representing the date and time an order will be shipped by"
@@ -87,7 +87,7 @@
8787
}
8888
},
8989
{
90-
"name": "photoUrls",
90+
"name": "photo_urls",
9191
"list": {
9292
"computed_optional_required": "computed",
9393
"element_type": {
@@ -176,7 +176,7 @@
176176
}
177177
},
178178
{
179-
"name": "petId",
179+
"name": "pet_id",
180180
"int64": {
181181
"computed_optional_required": "computed_optional"
182182
}
@@ -188,7 +188,7 @@
188188
}
189189
},
190190
{
191-
"name": "shipDate",
191+
"name": "ship_date",
192192
"string": {
193193
"computed_optional_required": "computed_optional",
194194
"description": "A field representing the date and time an order will be shipped by"
@@ -257,7 +257,7 @@
257257
}
258258
},
259259
{
260-
"name": "photoUrls",
260+
"name": "photo_urls",
261261
"list": {
262262
"computed_optional_required": "required",
263263
"element_type": {
@@ -320,7 +320,7 @@
320320
}
321321
},
322322
{
323-
"name": "firstName",
323+
"name": "first_name",
324324
"string": {
325325
"computed_optional_required": "computed_optional"
326326
}
@@ -332,7 +332,7 @@
332332
}
333333
},
334334
{
335-
"name": "lastName",
335+
"name": "last_name",
336336
"string": {
337337
"computed_optional_required": "computed_optional"
338338
}
@@ -350,7 +350,7 @@
350350
}
351351
},
352352
{
353-
"name": "userStatus",
353+
"name": "user_status",
354354
"int64": {
355355
"computed_optional_required": "computed_optional",
356356
"description": "User Status"

internal/cmd/testdata/scaleway/generated_framework_ir.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@
311311
"computed_optional_required": "computed",
312312
"attributes": [
313313
{
314-
"name": "\u003cextra_volumeKey\u003e",
314+
"name": "extra_volume_key",
315315
"single_nested": {
316316
"computed_optional_required": "computed",
317317
"attributes": [
@@ -871,7 +871,7 @@
871871
"computed_optional_required": "computed",
872872
"attributes": [
873873
{
874-
"name": "\u003cvolumeKey\u003e",
874+
"name": "volume_key",
875875
"single_nested": {
876876
"computed_optional_required": "computed",
877877
"attributes": [
@@ -1403,7 +1403,7 @@
14031403
"computed_optional_required": "computed",
14041404
"attributes": [
14051405
{
1406-
"name": "\u003cextra_volumeKey\u003e",
1406+
"name": "extra_volume_key",
14071407
"single_nested": {
14081408
"computed_optional_required": "computed",
14091409
"attributes": [
@@ -1963,7 +1963,7 @@
19631963
"computed_optional_required": "computed",
19641964
"attributes": [
19651965
{
1966-
"name": "\u003cvolumeKey\u003e",
1966+
"name": "volume_key",
19671967
"single_nested": {
19681968
"computed_optional_required": "computed",
19691969
"attributes": [
@@ -2129,7 +2129,7 @@
21292129
"computed_optional_required": "computed_optional",
21302130
"attributes": [
21312131
{
2132-
"name": "\u003cextra_volumeKey\u003e",
2132+
"name": "extra_volume_key",
21332133
"single_nested": {
21342134
"computed_optional_required": "computed_optional",
21352135
"attributes": [
@@ -2366,7 +2366,7 @@
23662366
"computed_optional_required": "computed",
23672367
"attributes": [
23682368
{
2369-
"name": "\u003cextra_volumeKey\u003e",
2369+
"name": "extra_volume_key",
23702370
"single_nested": {
23712371
"computed_optional_required": "computed",
23722372
"attributes": [

internal/mapper/attrmapper/bool.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package attrmapper
55

66
import (
77
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
8+
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util"
89
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
910
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1011
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
@@ -38,7 +39,7 @@ func (a *ResourceBoolAttribute) ApplyOverride(override explorer.Override) (Resou
3839

3940
func (a *ResourceBoolAttribute) ToSpec() resource.Attribute {
4041
return resource.Attribute{
41-
Name: a.Name,
42+
Name: util.TerraformIdentifier(a.Name),
4243
Bool: &a.BoolAttribute,
4344
}
4445
}
@@ -71,7 +72,7 @@ func (a *DataSourceBoolAttribute) ApplyOverride(override explorer.Override) (Dat
7172

7273
func (a *DataSourceBoolAttribute) ToSpec() datasource.Attribute {
7374
return datasource.Attribute{
74-
Name: a.Name,
75+
Name: util.TerraformIdentifier(a.Name),
7576
Bool: &a.BoolAttribute,
7677
}
7778
}
@@ -84,7 +85,7 @@ type ProviderBoolAttribute struct {
8485

8586
func (a *ProviderBoolAttribute) ToSpec() provider.Attribute {
8687
return provider.Attribute{
87-
Name: a.Name,
88+
Name: util.TerraformIdentifier(a.Name),
8889
Bool: &a.BoolAttribute,
8990
}
9091
}

internal/mapper/attrmapper/float64.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package attrmapper
55

66
import (
77
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
8+
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util"
89
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
910
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1011
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
@@ -38,7 +39,7 @@ func (a *ResourceFloat64Attribute) ApplyOverride(override explorer.Override) (Re
3839

3940
func (a *ResourceFloat64Attribute) ToSpec() resource.Attribute {
4041
return resource.Attribute{
41-
Name: a.Name,
42+
Name: util.TerraformIdentifier(a.Name),
4243
Float64: &a.Float64Attribute,
4344
}
4445
}
@@ -71,7 +72,7 @@ func (a *DataSourceFloat64Attribute) ApplyOverride(override explorer.Override) (
7172

7273
func (a *DataSourceFloat64Attribute) ToSpec() datasource.Attribute {
7374
return datasource.Attribute{
74-
Name: a.Name,
75+
Name: util.TerraformIdentifier(a.Name),
7576
Float64: &a.Float64Attribute,
7677
}
7778
}
@@ -84,7 +85,7 @@ type ProviderFloat64Attribute struct {
8485

8586
func (a *ProviderFloat64Attribute) ToSpec() provider.Attribute {
8687
return provider.Attribute{
87-
Name: a.Name,
88+
Name: util.TerraformIdentifier(a.Name),
8889
Float64: &a.Float64Attribute,
8990
}
9091
}

internal/mapper/attrmapper/int64.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package attrmapper
55

66
import (
77
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
8+
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util"
89
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
910
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1011
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
@@ -38,7 +39,7 @@ func (a *ResourceInt64Attribute) ApplyOverride(override explorer.Override) (Reso
3839

3940
func (a *ResourceInt64Attribute) ToSpec() resource.Attribute {
4041
return resource.Attribute{
41-
Name: a.Name,
42+
Name: util.TerraformIdentifier(a.Name),
4243
Int64: &a.Int64Attribute,
4344
}
4445
}
@@ -71,7 +72,7 @@ func (a *DataSourceInt64Attribute) ApplyOverride(override explorer.Override) (Da
7172

7273
func (a *DataSourceInt64Attribute) ToSpec() datasource.Attribute {
7374
return datasource.Attribute{
74-
Name: a.Name,
75+
Name: util.TerraformIdentifier(a.Name),
7576
Int64: &a.Int64Attribute,
7677
}
7778
}
@@ -84,7 +85,7 @@ type ProviderInt64Attribute struct {
8485

8586
func (a *ProviderInt64Attribute) ToSpec() provider.Attribute {
8687
return provider.Attribute{
87-
Name: a.Name,
88+
Name: util.TerraformIdentifier(a.Name),
8889
Int64: &a.Int64Attribute,
8990
}
9091
}

internal/mapper/attrmapper/list.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package attrmapper
55

66
import (
77
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
8+
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util"
89
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
910
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1011
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
@@ -43,7 +44,7 @@ func (a *ResourceListAttribute) ApplyOverride(override explorer.Override) (Resou
4344

4445
func (a *ResourceListAttribute) ToSpec() resource.Attribute {
4546
return resource.Attribute{
46-
Name: a.Name,
47+
Name: util.TerraformIdentifier(a.Name),
4748
List: &a.ListAttribute,
4849
}
4950
}
@@ -81,7 +82,7 @@ func (a *DataSourceListAttribute) ApplyOverride(override explorer.Override) (Dat
8182

8283
func (a *DataSourceListAttribute) ToSpec() datasource.Attribute {
8384
return datasource.Attribute{
84-
Name: a.Name,
85+
Name: util.TerraformIdentifier(a.Name),
8586
List: &a.ListAttribute,
8687
}
8788
}
@@ -94,7 +95,7 @@ type ProviderListAttribute struct {
9495

9596
func (a *ProviderListAttribute) ToSpec() provider.Attribute {
9697
return provider.Attribute{
97-
Name: a.Name,
98+
Name: util.TerraformIdentifier(a.Name),
9899
List: &a.ListAttribute,
99100
}
100101
}

internal/mapper/attrmapper/list_nested.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package attrmapper
55

66
import (
77
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
8+
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util"
89
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
910
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1011
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
@@ -55,7 +56,7 @@ func (a *ResourceListNestedAttribute) ToSpec() resource.Attribute {
5556
}
5657

5758
return resource.Attribute{
58-
Name: a.Name,
59+
Name: util.TerraformIdentifier(a.Name),
5960
ListNested: &a.ListNestedAttribute,
6061
}
6162
}
@@ -105,7 +106,7 @@ func (a *DataSourceListNestedAttribute) ToSpec() datasource.Attribute {
105106
}
106107

107108
return datasource.Attribute{
108-
Name: a.Name,
109+
Name: util.TerraformIdentifier(a.Name),
109110
ListNested: &a.ListNestedAttribute,
110111
}
111112
}
@@ -123,7 +124,7 @@ func (a *ProviderListNestedAttribute) ToSpec() provider.Attribute {
123124
}
124125

125126
return provider.Attribute{
126-
Name: a.Name,
127+
Name: util.TerraformIdentifier(a.Name),
127128
ListNested: &a.ListNestedAttribute,
128129
}
129130
}

internal/mapper/attrmapper/map.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package attrmapper
55

66
import (
77
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
8+
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util"
89
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
910
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1011
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
@@ -43,7 +44,7 @@ func (a *ResourceMapAttribute) ApplyOverride(override explorer.Override) (Resour
4344

4445
func (a *ResourceMapAttribute) ToSpec() resource.Attribute {
4546
return resource.Attribute{
46-
Name: a.Name,
47+
Name: util.TerraformIdentifier(a.Name),
4748
Map: &a.MapAttribute,
4849
}
4950
}
@@ -81,7 +82,7 @@ func (a *DataSourceMapAttribute) ApplyOverride(override explorer.Override) (Data
8182

8283
func (a *DataSourceMapAttribute) ToSpec() datasource.Attribute {
8384
return datasource.Attribute{
84-
Name: a.Name,
85+
Name: util.TerraformIdentifier(a.Name),
8586
Map: &a.MapAttribute,
8687
}
8788
}
@@ -94,7 +95,7 @@ type ProviderMapAttribute struct {
9495

9596
func (a *ProviderMapAttribute) ToSpec() provider.Attribute {
9697
return provider.Attribute{
97-
Name: a.Name,
98+
Name: util.TerraformIdentifier(a.Name),
9899
Map: &a.MapAttribute,
99100
}
100101
}

internal/mapper/attrmapper/map_nested.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package attrmapper
55

66
import (
77
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer"
8+
"github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util"
89
"github.com/hashicorp/terraform-plugin-codegen-spec/datasource"
910
"github.com/hashicorp/terraform-plugin-codegen-spec/provider"
1011
"github.com/hashicorp/terraform-plugin-codegen-spec/resource"
@@ -55,7 +56,7 @@ func (a *ResourceMapNestedAttribute) ToSpec() resource.Attribute {
5556
}
5657

5758
return resource.Attribute{
58-
Name: a.Name,
59+
Name: util.TerraformIdentifier(a.Name),
5960
MapNested: &a.MapNestedAttribute,
6061
}
6162
}
@@ -105,7 +106,7 @@ func (a *DataSourceMapNestedAttribute) ToSpec() datasource.Attribute {
105106
}
106107

107108
return datasource.Attribute{
108-
Name: a.Name,
109+
Name: util.TerraformIdentifier(a.Name),
109110
MapNested: &a.MapNestedAttribute,
110111
}
111112
}
@@ -123,7 +124,7 @@ func (a *ProviderMapNestedAttribute) ToSpec() provider.Attribute {
123124
}
124125

125126
return provider.Attribute{
126-
Name: a.Name,
127+
Name: util.TerraformIdentifier(a.Name),
127128
MapNested: &a.MapNestedAttribute,
128129
}
129130
}

0 commit comments

Comments
 (0)