@cdktn/provider-generator 0.24.0-pre.5 → 0.24.0-pre.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.spec.swcrc +22 -0
- package/LICENSE +355 -0
- package/README.md +1 -1
- package/build/__tests__/edge-provider-schema/cli.js +8 -3
- package/build/get/__tests__/generator/import-style.test.d.ts +2 -0
- package/build/get/__tests__/generator/import-style.test.js +101 -0
- package/build/get/__tests__/generator/module-generator.test.js +12 -12
- package/build/get/constructs-maker.d.ts +5 -1
- package/build/get/constructs-maker.js +14 -6
- package/build/get/generator/emitter/struct-emitter.d.ts +2 -1
- package/build/get/generator/emitter/struct-emitter.js +14 -11
- package/build/get/generator/module-generator.js +3 -3
- package/build/get/generator/provider-generator.d.ts +9 -1
- package/build/get/generator/provider-generator.js +9 -6
- package/jest.config.js +16 -9
- package/package.json +24 -23
- package/package.sh +1 -1
- package/src/__tests__/__snapshots__/edge-provider-schema.test.ts.snap +8 -8
- package/src/__tests__/__snapshots__/provider.test.ts.snap +2951 -2951
- package/src/__tests__/edge-provider-schema/builder.ts +185 -0
- package/src/__tests__/edge-provider-schema/cli.ts +51 -0
- package/src/__tests__/edge-provider-schema/index.ts +161 -0
- package/src/__tests__/edge-provider-schema.test.ts +24 -0
- package/src/__tests__/provider.test.ts +180 -0
- package/src/get/__tests__/constructs-maker.test.ts +118 -0
- package/src/get/__tests__/generator/__snapshots__/complex-computed-types.test.ts.snap +5 -5
- package/src/get/__tests__/generator/__snapshots__/export-sharding.test.ts.snap +3310 -3310
- package/src/get/__tests__/generator/__snapshots__/module-generator.test.ts.snap +355 -355
- package/src/get/__tests__/generator/__snapshots__/nested-types.test.ts.snap +8 -8
- package/src/get/__tests__/generator/__snapshots__/provider.test.ts.snap +8 -8
- package/src/get/__tests__/generator/__snapshots__/resource-types.test.ts.snap +126 -126
- package/src/get/__tests__/generator/__snapshots__/skipped-attributes.test.ts.snap +17 -17
- package/src/get/__tests__/generator/__snapshots__/types.test.ts.snap +65 -65
- package/src/get/__tests__/generator/complex-computed-types.test.ts +28 -0
- package/src/get/__tests__/generator/deep-nested-attributes.test.ts +56 -0
- package/src/get/__tests__/generator/description-escaping.test.ts +84 -0
- package/src/get/__tests__/generator/empty-provider-resources.test.ts +26 -0
- package/src/get/__tests__/generator/export-sharding.test.ts +169 -0
- package/src/get/__tests__/generator/import-style.test.ts +129 -0
- package/src/get/__tests__/generator/module-generator.test.ts +528 -0
- package/src/get/__tests__/generator/nested-types.test.ts +54 -0
- package/src/get/__tests__/generator/provider.test.ts +51 -0
- package/src/get/__tests__/generator/resource-types.test.ts +118 -0
- package/src/get/__tests__/generator/skipped-attributes.test.ts +72 -0
- package/src/get/__tests__/generator/types.test.ts +611 -0
- package/src/get/__tests__/generator/versions-file.test.ts +72 -0
- package/src/get/__tests__/util.ts +75 -0
- package/src/get/constructs-maker.ts +822 -0
- package/src/get/generator/custom-defaults.ts +493 -0
- package/src/get/generator/emitter/attributes-emitter.ts +225 -0
- package/src/get/generator/emitter/index.ts +5 -0
- package/src/get/generator/emitter/resource-emitter.ts +226 -0
- package/src/get/generator/emitter/struct-emitter.ts +683 -0
- package/src/get/generator/loop-detection.ts +81 -0
- package/src/get/generator/models/attribute-model.ts +216 -0
- package/src/get/generator/models/attribute-type-model.ts +448 -0
- package/src/get/generator/models/index.ts +7 -0
- package/src/get/generator/models/resource-model.ts +161 -0
- package/src/get/generator/models/scope.ts +54 -0
- package/src/get/generator/models/struct.ts +116 -0
- package/src/get/generator/module-generator.ts +234 -0
- package/src/get/generator/provider-generator.ts +355 -0
- package/src/get/generator/resource-parser.ts +762 -0
- package/src/get/generator/sanitized-comments.ts +49 -0
- package/src/get/generator/skipped-attributes.ts +27 -0
- package/src/index.ts +40 -0
- package/src/util.ts +26 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import { Struct } from "./struct";
|
|
4
|
+
import { uppercaseFirst, downcaseFirst } from "../../../util";
|
|
5
|
+
|
|
6
|
+
export interface AttributeTypeModel {
|
|
7
|
+
readonly struct?: Struct; // complex object type contained within the type
|
|
8
|
+
readonly isComplex: boolean; // basically the same as having a struct
|
|
9
|
+
getStoredClassInitializer(name: string): string; // initializer for keeping class needed to keep track of reference access
|
|
10
|
+
readonly storedClassType: string; // used mainly by collection types to generate their stored class initializer
|
|
11
|
+
readonly inputTypeDefinition: string; // this is the type used for inputting values
|
|
12
|
+
getAttributeAccessFunction(name: string): string; // this is for getting reference for simple types
|
|
13
|
+
readonly toTerraformFunction: string; // this is for converting input values to Terraform syntax
|
|
14
|
+
readonly toHclTerraformFunction: string; // this is for converting input values to Terraform syntax in HCL
|
|
15
|
+
readonly typeModelType: string; // so we don't need to use instanceof
|
|
16
|
+
readonly hasReferenceClass: boolean; // used to determine if a stored_class getter should be used
|
|
17
|
+
readonly isTokenizable: boolean; // can the type be represented by a token type
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class SkippedAttributeTypeModel implements AttributeTypeModel {
|
|
21
|
+
constructor() {}
|
|
22
|
+
|
|
23
|
+
get typeModelType() {
|
|
24
|
+
return "simple";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get struct() {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get isComplex() {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getStoredClassInitializer(_name: string) {
|
|
36
|
+
// not used
|
|
37
|
+
return "";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get storedClassType() {
|
|
41
|
+
return "any";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get inputTypeDefinition() {
|
|
45
|
+
return "any";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getAttributeAccessFunction(name: string) {
|
|
49
|
+
return `this.interpolationForAttribute('${name}')`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get toTerraformFunction() {
|
|
53
|
+
return `cdktn.anyToTerraform`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get toHclTerraformFunction() {
|
|
57
|
+
return `cdktn.anyToHclTerraform`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get hasReferenceClass() {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get isTokenizable() {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class SimpleAttributeTypeModel implements AttributeTypeModel {
|
|
70
|
+
constructor(public readonly type: string) {}
|
|
71
|
+
|
|
72
|
+
get typeModelType() {
|
|
73
|
+
return "simple";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get struct() {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get isComplex() {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getStoredClassInitializer(_name: string) {
|
|
85
|
+
// not used
|
|
86
|
+
return "";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get storedClassType() {
|
|
90
|
+
return this.type;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
get inputTypeDefinition() {
|
|
94
|
+
if (this.type === "boolean") {
|
|
95
|
+
return "boolean | cdktn.IResolvable";
|
|
96
|
+
} else {
|
|
97
|
+
return this.type;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
getAttributeAccessFunction(name: string) {
|
|
102
|
+
return `this.get${uppercaseFirst(this.type)}Attribute('${name}')`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get toTerraformFunction() {
|
|
106
|
+
return `cdktn.${this.type}ToTerraform`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get toHclTerraformFunction() {
|
|
110
|
+
return `cdktn.${this.type}ToHclTerraform`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get hasReferenceClass() {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
get isTokenizable() {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export class StructAttributeTypeModel implements AttributeTypeModel {
|
|
123
|
+
constructor(public readonly struct: Struct) {}
|
|
124
|
+
|
|
125
|
+
get typeModelType() {
|
|
126
|
+
return "struct";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get isComplex() {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
getStoredClassInitializer(name: string) {
|
|
134
|
+
return `new ${this.struct.outputReferenceName}(this, "${name}")`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
get storedClassType() {
|
|
138
|
+
return this.struct.name;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
get inputTypeDefinition() {
|
|
142
|
+
return this.struct.name;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
getAttributeAccessFunction(name: string) {
|
|
146
|
+
// This shouln't actually be called
|
|
147
|
+
return `this.interpolationForAttribute('${name}')`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get toTerraformFunction() {
|
|
151
|
+
return `${downcaseFirst(this.struct.name)}ToTerraform`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
get toHclTerraformFunction() {
|
|
155
|
+
return `${downcaseFirst(this.struct.name)}ToHclTerraform`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get hasReferenceClass() {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
get isTokenizable() {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface CollectionAttributeTypeModel extends AttributeTypeModel {
|
|
168
|
+
elementType: AttributeTypeModel;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export class ListAttributeTypeModel implements CollectionAttributeTypeModel {
|
|
172
|
+
constructor(
|
|
173
|
+
public readonly elementType: AttributeTypeModel,
|
|
174
|
+
public readonly isSingleItem: boolean,
|
|
175
|
+
private readonly isBlock: boolean,
|
|
176
|
+
) {
|
|
177
|
+
if (this.struct) {
|
|
178
|
+
this.struct.isSingleItem = this.isSingleItem || false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
get typeModelType() {
|
|
183
|
+
return "list";
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
get struct() {
|
|
187
|
+
return this.elementType.struct;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
get isComplex() {
|
|
191
|
+
return this.elementType.isComplex;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
getStoredClassInitializer(name: string) {
|
|
195
|
+
if (this.isSingleItem) {
|
|
196
|
+
return `new ${this.elementType.storedClassType}OutputReference(this, "${name}")`;
|
|
197
|
+
} else {
|
|
198
|
+
if (this.isComplex) {
|
|
199
|
+
return `new ${this.storedClassType}(this, "${name}", false)`;
|
|
200
|
+
} else {
|
|
201
|
+
return `new cdktn.${uppercaseFirst(
|
|
202
|
+
this.storedClassType,
|
|
203
|
+
)}(this, "${name}", false)`;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
get storedClassType() {
|
|
209
|
+
return `${this.elementType.storedClassType}List`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
get inputTypeDefinition() {
|
|
213
|
+
if (this.isSingleItem) {
|
|
214
|
+
return this.elementType.inputTypeDefinition;
|
|
215
|
+
} else if (this.elementType.storedClassType === "boolean") {
|
|
216
|
+
return "Array<boolean | cdktn.IResolvable> | cdktn.IResolvable";
|
|
217
|
+
} else if (this.isComplex) {
|
|
218
|
+
return `${this.elementType.storedClassType}[] | cdktn.IResolvable`;
|
|
219
|
+
} else if (this.elementType.typeModelType !== "simple") {
|
|
220
|
+
return `${this.elementType.inputTypeDefinition}[] | cdktn.IResolvable`;
|
|
221
|
+
} else {
|
|
222
|
+
return `${this.elementType.inputTypeDefinition}[]`;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
getAttributeAccessFunction(name: string) {
|
|
227
|
+
switch (this.elementType.storedClassType) {
|
|
228
|
+
case "string":
|
|
229
|
+
return `this.getListAttribute('${name}')`;
|
|
230
|
+
case "number":
|
|
231
|
+
return `this.getNumberListAttribute('${name}')`;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return `this.interpolationForAttribute('${name}')`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
get toTerraformFunction() {
|
|
238
|
+
if (this.isSingleItem) {
|
|
239
|
+
return this.elementType.toTerraformFunction;
|
|
240
|
+
}
|
|
241
|
+
return `cdktn.listMapper(${this.elementType.toTerraformFunction}, ${this.isBlock})`;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
get toHclTerraformFunction() {
|
|
245
|
+
if (this.isSingleItem) {
|
|
246
|
+
return this.elementType.toHclTerraformFunction;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return `cdktn.listMapperHcl(${this.elementType.toHclTerraformFunction}, ${this.isBlock})`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
get hasReferenceClass() {
|
|
253
|
+
return this.isSingleItem || this.isComplex;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
get isTokenizable() {
|
|
257
|
+
switch (this.elementType.storedClassType) {
|
|
258
|
+
case "string":
|
|
259
|
+
return true;
|
|
260
|
+
case "number":
|
|
261
|
+
return true;
|
|
262
|
+
default:
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export class SetAttributeTypeModel implements CollectionAttributeTypeModel {
|
|
269
|
+
constructor(
|
|
270
|
+
public readonly elementType: AttributeTypeModel,
|
|
271
|
+
public readonly isSingleItem: boolean,
|
|
272
|
+
private readonly isBlock: boolean,
|
|
273
|
+
) {
|
|
274
|
+
if (this.struct) {
|
|
275
|
+
this.struct.isSingleItem = this.isSingleItem || false;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
get typeModelType() {
|
|
280
|
+
return "set";
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
get struct() {
|
|
284
|
+
return this.elementType.struct;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
get isComplex() {
|
|
288
|
+
return this.elementType.isComplex;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
getStoredClassInitializer(name: string) {
|
|
292
|
+
if (this.isSingleItem) {
|
|
293
|
+
return `new ${this.elementType.storedClassType}OutputReference(this, "${name}")`;
|
|
294
|
+
} else {
|
|
295
|
+
if (this.isComplex) {
|
|
296
|
+
return `new ${this.storedClassType}(this, "${name}", true)`;
|
|
297
|
+
} else {
|
|
298
|
+
return `new cdktn.${uppercaseFirst(
|
|
299
|
+
this.storedClassType,
|
|
300
|
+
)}(this, "${name}", true)`;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
get storedClassType() {
|
|
306
|
+
return `${this.elementType.storedClassType}List`;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
get inputTypeDefinition() {
|
|
310
|
+
if (this.isSingleItem) {
|
|
311
|
+
return this.elementType.inputTypeDefinition;
|
|
312
|
+
} else if (this.elementType.storedClassType === "boolean") {
|
|
313
|
+
return "Array<boolean | cdktn.IResolvable> | cdktn.IResolvable";
|
|
314
|
+
} else if (this.isComplex) {
|
|
315
|
+
return `${this.elementType.storedClassType}[] | cdktn.IResolvable`;
|
|
316
|
+
} else if (this.elementType.typeModelType !== "simple") {
|
|
317
|
+
return `${this.elementType.inputTypeDefinition}[] | cdktn.IResolvable`;
|
|
318
|
+
} else {
|
|
319
|
+
return `${this.elementType.inputTypeDefinition}[]`;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
getAttributeAccessFunction(name: string) {
|
|
324
|
+
switch (this.elementType.storedClassType) {
|
|
325
|
+
case "string":
|
|
326
|
+
return `cdktn.Fn.tolist(this.getListAttribute('${name}'))`;
|
|
327
|
+
case "number":
|
|
328
|
+
return `cdktn.Token.asNumberList(cdktn.Fn.tolist(this.getNumberListAttribute('${name}')))`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Token.asAny is required because tolist returns an Array encoded token which the listMapper
|
|
332
|
+
// would try to map over when this is passed to another resource. With Token.asAny() it is left
|
|
333
|
+
// as is by the listMapper and is later properly resolved to a reference
|
|
334
|
+
// (this only works in TypeScript currently, same as for referencing lists
|
|
335
|
+
// [see "interpolationForAttribute(...)" further below])
|
|
336
|
+
return `cdktn.Token.asAny(cdktn.Fn.tolist(this.interpolationForAttribute('${name}')))`;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
get toTerraformFunction() {
|
|
340
|
+
if (this.isSingleItem) {
|
|
341
|
+
return this.elementType.toTerraformFunction;
|
|
342
|
+
} else {
|
|
343
|
+
return `cdktn.listMapper(${this.elementType.toTerraformFunction}, ${this.isBlock})`;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
get toHclTerraformFunction() {
|
|
348
|
+
if (this.isSingleItem) {
|
|
349
|
+
return this.elementType.toHclTerraformFunction;
|
|
350
|
+
}
|
|
351
|
+
return `cdktn.listMapperHcl(${this.elementType.toHclTerraformFunction}, ${this.isBlock})`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
get hasReferenceClass() {
|
|
355
|
+
return this.isSingleItem || this.isComplex;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
get isTokenizable() {
|
|
359
|
+
switch (this.elementType.storedClassType) {
|
|
360
|
+
case "string":
|
|
361
|
+
return true;
|
|
362
|
+
case "number":
|
|
363
|
+
return true;
|
|
364
|
+
default:
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export class MapAttributeTypeModel implements CollectionAttributeTypeModel {
|
|
371
|
+
constructor(public readonly elementType: AttributeTypeModel) {}
|
|
372
|
+
|
|
373
|
+
get typeModelType() {
|
|
374
|
+
return "map";
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
get struct() {
|
|
378
|
+
return this.elementType.struct;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
get isComplex() {
|
|
382
|
+
return this.elementType.isComplex;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
getStoredClassInitializer(name: string) {
|
|
386
|
+
if (this.isComplex) {
|
|
387
|
+
return `new ${this.storedClassType}(this, "${name}")`;
|
|
388
|
+
} else {
|
|
389
|
+
return `new cdktn.${uppercaseFirst(
|
|
390
|
+
this.storedClassType,
|
|
391
|
+
)}(this, "${name}")`;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
get storedClassType() {
|
|
396
|
+
return `${this.elementType.storedClassType}Map`;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
get inputTypeDefinition() {
|
|
400
|
+
// map of booleans has token support, but booleans don't
|
|
401
|
+
if (this.elementType.storedClassType === "boolean") {
|
|
402
|
+
return `{ [key: string]: (${this.elementType.storedClassType} | cdktn.IResolvable) }`;
|
|
403
|
+
} else if (this.isComplex) {
|
|
404
|
+
return `{ [key: string]: ${this.elementType.storedClassType} } | cdktn.IResolvable`;
|
|
405
|
+
} else if (this.elementType.typeModelType !== "simple") {
|
|
406
|
+
return `{ [key: string]: ${this.elementType.inputTypeDefinition} } | cdktn.IResolvable`;
|
|
407
|
+
} else {
|
|
408
|
+
return `{ [key: string]: ${this.elementType.storedClassType} }`;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
getAttributeAccessFunction(name: string) {
|
|
413
|
+
if (!this.isComplex && this.elementType.typeModelType !== "simple") {
|
|
414
|
+
return `this.interpolationForAttribute('${name}')`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return `this.get${uppercaseFirst(
|
|
418
|
+
this.storedClassType,
|
|
419
|
+
)}Attribute('${name}')`;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
get toTerraformFunction() {
|
|
423
|
+
return `cdktn.hashMapper(${this.elementType.toTerraformFunction})`;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
get toHclTerraformFunction() {
|
|
427
|
+
return `cdktn.hashMapperHcl(${this.elementType.toHclTerraformFunction})`;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
get hasReferenceClass() {
|
|
431
|
+
return this.isComplex;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
get isTokenizable() {
|
|
435
|
+
switch (this.elementType.storedClassType) {
|
|
436
|
+
case "string":
|
|
437
|
+
return true;
|
|
438
|
+
case "number":
|
|
439
|
+
return true;
|
|
440
|
+
case "boolean":
|
|
441
|
+
return true;
|
|
442
|
+
case "any":
|
|
443
|
+
return true;
|
|
444
|
+
default:
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import { toSnakeCase } from "codemaker";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { FQPN, parseFQPN, ProviderName } from "@cdktn/provider-schema";
|
|
6
|
+
import { AttributeModel } from "./attribute-model";
|
|
7
|
+
import { Struct, ConfigStruct } from "./struct";
|
|
8
|
+
import { Schema } from "@cdktn/commons";
|
|
9
|
+
|
|
10
|
+
// Limit is 1200 to prevent stack size error.
|
|
11
|
+
// Could increase now that calculation is more accurate;
|
|
12
|
+
// however, probably better to have smaller
|
|
13
|
+
export const STRUCT_SHARDING_THRESHOLD = 400;
|
|
14
|
+
|
|
15
|
+
interface ResourceModelOptions {
|
|
16
|
+
terraformType: string;
|
|
17
|
+
className: string;
|
|
18
|
+
baseName: string;
|
|
19
|
+
fileName: string;
|
|
20
|
+
filePath: string;
|
|
21
|
+
attributes: AttributeModel[];
|
|
22
|
+
structs: Struct[];
|
|
23
|
+
fqpn: FQPN;
|
|
24
|
+
schema: Schema;
|
|
25
|
+
terraformSchemaType: string;
|
|
26
|
+
configStructName: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type DefinitionPath = string;
|
|
30
|
+
export class ResourceModel {
|
|
31
|
+
public className: string;
|
|
32
|
+
public filePath: string;
|
|
33
|
+
public terraformType: string;
|
|
34
|
+
public baseName: string;
|
|
35
|
+
public provider: ProviderName;
|
|
36
|
+
public fqpn: FQPN;
|
|
37
|
+
public providerVersionConstraint?: string;
|
|
38
|
+
public providerVersion?: string;
|
|
39
|
+
public terraformProviderSource?: string;
|
|
40
|
+
/*
|
|
41
|
+
* usually same as provider, but can be overridden if user picks a different name
|
|
42
|
+
* to be able to use two providers with the same name
|
|
43
|
+
*/
|
|
44
|
+
public terraformProviderName: string;
|
|
45
|
+
public fileName: string;
|
|
46
|
+
public attributes: AttributeModel[];
|
|
47
|
+
public schema: Schema;
|
|
48
|
+
private _structs: Struct[];
|
|
49
|
+
private dependencies: string[];
|
|
50
|
+
private terraformSchemaType: string;
|
|
51
|
+
private configStructName: string;
|
|
52
|
+
public readonly structsRequireSharding: boolean;
|
|
53
|
+
public recursiveAttributePaths: { [usagePath: string]: DefinitionPath } = {};
|
|
54
|
+
|
|
55
|
+
constructor(options: ResourceModelOptions) {
|
|
56
|
+
this.className = options.className;
|
|
57
|
+
this.filePath = options.filePath;
|
|
58
|
+
this.terraformType = options.terraformType;
|
|
59
|
+
this.baseName = options.baseName;
|
|
60
|
+
this.attributes = options.attributes;
|
|
61
|
+
this.schema = options.schema;
|
|
62
|
+
this.fqpn = options.fqpn;
|
|
63
|
+
this.provider = parseFQPN(options.fqpn).name;
|
|
64
|
+
this.terraformProviderName = this.provider;
|
|
65
|
+
this.fileName = options.fileName;
|
|
66
|
+
this._structs = options.structs;
|
|
67
|
+
this.terraformSchemaType = options.terraformSchemaType;
|
|
68
|
+
this.configStructName = options.configStructName;
|
|
69
|
+
this.dependencies = [
|
|
70
|
+
`import { Construct } from 'constructs';`,
|
|
71
|
+
`import * as cdktn from 'cdktn';`,
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
this.structsRequireSharding =
|
|
75
|
+
this._structs.reduce((partialSum, s) => partialSum + s.exportCount, 0) >
|
|
76
|
+
STRUCT_SHARDING_THRESHOLD;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public get structs(): Struct[] {
|
|
80
|
+
return [this.configStruct, ...this._structs];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public get configStruct() {
|
|
84
|
+
return new ConfigStruct(this.configStructName, this.attributes);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public get synthesizableAttributes(): AttributeModel[] {
|
|
88
|
+
return this.configStruct.assignableAttributes;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public get importStatements(): string[] {
|
|
92
|
+
return this.dependencies;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public get schemaAsJson(): string {
|
|
96
|
+
return this.escapeSchema(JSON.stringify(this.schema, undefined, 2));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public get linkToDocs(): string {
|
|
100
|
+
const { hostname, namespace, name } = parseFQPN(this.fqpn);
|
|
101
|
+
const version = this.providerVersion || "latest";
|
|
102
|
+
const base = `https://${hostname}/providers/${namespace}/${name}/${version}/docs`;
|
|
103
|
+
if (this.isProvider) return base;
|
|
104
|
+
if (this.isDataSource)
|
|
105
|
+
return `${base}/data-sources/${this.terraformDocName}`;
|
|
106
|
+
return `${base}/resources/${this.terraformDocName}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public get isProvider(): boolean {
|
|
110
|
+
return this.terraformSchemaType === "provider";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public get isDataSource(): boolean {
|
|
114
|
+
return this.terraformSchemaType === "data_source";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public get parentClassName(): string {
|
|
118
|
+
return this.isProvider
|
|
119
|
+
? "TerraformProvider"
|
|
120
|
+
: this.isDataSource
|
|
121
|
+
? "TerraformDataSource"
|
|
122
|
+
: "TerraformResource";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public get terraformResourceType(): string {
|
|
126
|
+
return this.isProvider
|
|
127
|
+
? this.terraformProviderName
|
|
128
|
+
: this.isDataSource
|
|
129
|
+
? this.terraformType.replace(/^data_/, "")
|
|
130
|
+
: this.terraformType;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public get terraformDocName(): string {
|
|
134
|
+
return toSnakeCase(
|
|
135
|
+
this.terraformResourceType.replace(
|
|
136
|
+
new RegExp(`^${this.provider}_`, "i"),
|
|
137
|
+
"",
|
|
138
|
+
),
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public get referencedTypes(): string[] {
|
|
143
|
+
return this.configStruct.referencedTypes;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public get structsFolderName(): string {
|
|
147
|
+
return `${path.basename(this.fileName, ".ts")}-structs`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public get structsFolderPath(): string {
|
|
151
|
+
return path.join(this.namespaceFolderPath, this.structsFolderName);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public get namespaceFolderPath(): string {
|
|
155
|
+
return this.filePath.split("/").slice(0, -1).join("/");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private escapeSchema(schema: string): string {
|
|
159
|
+
return schema.replace(/(\*\/)/gi, `*\\/`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
export interface ScopeProps {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly isProvider: boolean;
|
|
6
|
+
readonly isComputed?: boolean;
|
|
7
|
+
readonly isOptional?: boolean;
|
|
8
|
+
readonly isRequired?: boolean;
|
|
9
|
+
readonly inBlockType?: boolean;
|
|
10
|
+
readonly isNestedType?: boolean;
|
|
11
|
+
readonly parent?: Scope;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class Scope {
|
|
15
|
+
public readonly name: string;
|
|
16
|
+
public readonly provider?: string;
|
|
17
|
+
public readonly parent?: Scope;
|
|
18
|
+
public readonly isProvider: boolean;
|
|
19
|
+
public isComputed: boolean;
|
|
20
|
+
public isOptional: boolean;
|
|
21
|
+
public isRequired: boolean;
|
|
22
|
+
public inBlockType: boolean;
|
|
23
|
+
public isNestedType: boolean;
|
|
24
|
+
|
|
25
|
+
constructor(props: ScopeProps) {
|
|
26
|
+
this.name = props.name;
|
|
27
|
+
this.parent = props.parent;
|
|
28
|
+
this.isProvider = props.isProvider;
|
|
29
|
+
this.isComputed = props.isComputed ?? false;
|
|
30
|
+
this.isOptional = props.isOptional ?? true;
|
|
31
|
+
this.isRequired = props.isRequired ?? false;
|
|
32
|
+
this.inBlockType = props.inBlockType ?? false;
|
|
33
|
+
this.isNestedType = props.isNestedType ?? false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public fullName(attributeName: string) {
|
|
37
|
+
return `${this.baseName}.${attributeName}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public get baseName() {
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
42
|
+
let scope: Scope | undefined = this;
|
|
43
|
+
let name = "";
|
|
44
|
+
while (scope) {
|
|
45
|
+
if (name === "") {
|
|
46
|
+
name = scope.name;
|
|
47
|
+
} else {
|
|
48
|
+
name = `${scope.name}.${name}`;
|
|
49
|
+
}
|
|
50
|
+
scope = scope.parent;
|
|
51
|
+
}
|
|
52
|
+
return name;
|
|
53
|
+
}
|
|
54
|
+
}
|