@cdktn/provider-generator 0.24.0-pre.9 → 0.24.0-pre.91
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/builder.d.ts +9 -3
- package/build/__tests__/edge-provider-schema/builder.js +6 -3
- package/build/__tests__/edge-provider-schema/cli.js +8 -3
- package/build/__tests__/edge-provider-schema/index.js +119 -1
- package/build/__tests__/provider.test.js +4 -1
- package/build/get/__tests__/generator/ephemeral-resources.test.d.ts +2 -0
- package/build/get/__tests__/generator/ephemeral-resources.test.js +49 -0
- package/build/get/__tests__/generator/module-generator.test.js +12 -12
- package/build/get/__tests__/generator/provider-functions.test.d.ts +2 -0
- package/build/get/__tests__/generator/provider-functions.test.js +176 -0
- package/build/get/__tests__/generator/provider-source-matching.test.d.ts +2 -0
- package/build/get/__tests__/generator/provider-source-matching.test.js +45 -0
- package/build/get/__tests__/generator/provider.test.js +9 -1
- package/build/get/__tests__/generator/supported-stored-classes.test.d.ts +2 -0
- package/build/get/__tests__/generator/supported-stored-classes.test.js +137 -0
- package/build/get/__tests__/generator/types.test.js +44 -1
- package/build/get/__tests__/generator/write-only.test.d.ts +2 -0
- package/build/get/__tests__/generator/write-only.test.js +65 -0
- package/build/get/__tests__/target-versions.test.d.ts +2 -0
- package/build/get/__tests__/target-versions.test.js +171 -0
- package/build/get/constructs-maker.d.ts +8 -1
- package/build/get/constructs-maker.js +46 -10
- package/build/get/generator/emitter/attributes-emitter.d.ts +13 -2
- package/build/get/generator/emitter/attributes-emitter.js +71 -5
- package/build/get/generator/emitter/index.d.ts +1 -0
- package/build/get/generator/emitter/index.js +2 -1
- package/build/get/generator/emitter/provider-functions-emitter.d.ts +11 -0
- package/build/get/generator/emitter/provider-functions-emitter.js +94 -0
- package/build/get/generator/emitter/resource-emitter.d.ts +5 -1
- package/build/get/generator/emitter/resource-emitter.js +83 -7
- package/build/get/generator/emitter/struct-emitter.js +10 -10
- package/build/get/generator/models/attribute-model.d.ts +4 -0
- package/build/get/generator/models/attribute-model.js +50 -4
- package/build/get/generator/models/attribute-type-model.d.ts +24 -0
- package/build/get/generator/models/attribute-type-model.js +91 -5
- package/build/get/generator/models/index.d.ts +1 -0
- package/build/get/generator/models/index.js +2 -1
- package/build/get/generator/models/provider-function-model.d.ts +102 -0
- package/build/get/generator/models/provider-function-model.js +667 -0
- package/build/get/generator/models/resource-model.d.ts +3 -0
- package/build/get/generator/models/resource-model.js +13 -4
- package/build/get/generator/models/struct.d.ts +2 -0
- package/build/get/generator/models/struct.js +6 -2
- package/build/get/generator/models/supported-stored-classes.d.ts +5 -0
- package/build/get/generator/models/supported-stored-classes.js +86 -0
- package/build/get/generator/module-generator.js +3 -3
- package/build/get/generator/provider-generator.d.ts +2 -0
- package/build/get/generator/provider-generator.js +41 -6
- package/build/get/generator/resource-parser.js +3 -1
- package/jest.config.js +16 -9
- package/package.json +28 -27
- package/package.sh +1 -1
- package/src/__tests__/__snapshots__/edge-provider-schema.test.ts.snap +4 -0
- package/src/__tests__/__snapshots__/provider.test.ts.snap +2828 -2828
- package/src/__tests__/edge-provider-schema/builder.ts +201 -0
- package/src/__tests__/edge-provider-schema/cli.ts +51 -0
- package/src/__tests__/edge-provider-schema/index.ts +284 -0
- package/src/__tests__/edge-provider-schema.test.ts +24 -0
- package/src/__tests__/provider.test.ts +183 -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__/ephemeral-resources.test.ts.snap +524 -0
- 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-functions.test.ts.snap +444 -0
- 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 +201 -52
- package/src/get/__tests__/generator/__snapshots__/write-only.test.ts.snap +262 -0
- 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/ephemeral-resources.test.ts +46 -0
- package/src/get/__tests__/generator/export-sharding.test.ts +169 -0
- package/src/get/__tests__/generator/fixtures/deeply-nested-collections.test.fixture.json +129 -0
- package/src/get/__tests__/generator/fixtures/ephemeral-resources.test.fixture.json +160 -0
- package/src/get/__tests__/generator/fixtures/provider-functions-collision.test.fixture.json +31 -0
- package/src/get/__tests__/generator/fixtures/provider-functions-synthetic.test.fixture.json +192 -0
- package/src/get/__tests__/generator/fixtures/provider-functions.test.fixture.json +170 -0
- package/src/get/__tests__/generator/fixtures/write-only.test.fixture.json +58 -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-functions.test.ts +262 -0
- package/src/get/__tests__/generator/provider-source-matching.test.ts +84 -0
- package/src/get/__tests__/generator/provider.test.ts +59 -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/supported-stored-classes.test.ts +147 -0
- package/src/get/__tests__/generator/types.test.ts +686 -0
- package/src/get/__tests__/generator/versions-file.test.ts +72 -0
- package/src/get/__tests__/generator/write-only.test.ts +71 -0
- package/src/get/__tests__/target-versions.test.ts +206 -0
- package/src/get/__tests__/util.ts +75 -0
- package/src/get/constructs-maker.ts +885 -0
- package/src/get/generator/custom-defaults.ts +493 -0
- package/src/get/generator/emitter/attributes-emitter.ts +316 -0
- package/src/get/generator/emitter/index.ts +6 -0
- package/src/get/generator/emitter/provider-functions-emitter.ts +117 -0
- package/src/get/generator/emitter/resource-emitter.ts +330 -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 +273 -0
- package/src/get/generator/models/attribute-type-model.ts +560 -0
- package/src/get/generator/models/index.ts +8 -0
- package/src/get/generator/models/provider-function-model.ts +872 -0
- package/src/get/generator/models/resource-model.ts +183 -0
- package/src/get/generator/models/scope.ts +54 -0
- package/src/get/generator/models/struct.ts +124 -0
- package/src/get/generator/models/supported-stored-classes.ts +88 -0
- package/src/get/generator/module-generator.ts +234 -0
- package/src/get/generator/provider-generator.ts +428 -0
- package/src/get/generator/resource-parser.ts +764 -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
- package/tsconfig.json +1 -2
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import { CodeMaker } from "codemaker";
|
|
4
|
+
import {
|
|
5
|
+
AttributeModel,
|
|
6
|
+
CollectionAttributeTypeModel,
|
|
7
|
+
describeTerraformType,
|
|
8
|
+
} from "../models";
|
|
9
|
+
import { CUSTOM_DEFAULTS } from "../custom-defaults";
|
|
10
|
+
import { sanitizedComment } from "../sanitized-comments";
|
|
11
|
+
|
|
12
|
+
function titleCase(value: string) {
|
|
13
|
+
return value[0].toUpperCase() + value.slice(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class AttributesEmitter {
|
|
17
|
+
constructor(private code: CodeMaker) {}
|
|
18
|
+
|
|
19
|
+
public emit(att: AttributeModel, escapeReset: boolean, escapeInput: boolean) {
|
|
20
|
+
this.code.line();
|
|
21
|
+
this.code.line(
|
|
22
|
+
`// ${att.terraformName} - computed: ${att.computed}, optional: ${att.isOptional}, required: ${att.isRequired}`,
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const isStored = att.isStored;
|
|
26
|
+
const hasResetMethod =
|
|
27
|
+
isStored && !att.isRequired && att.setterType._type !== "none";
|
|
28
|
+
const hasInputMethod = isStored && att.setterType._type !== "none";
|
|
29
|
+
|
|
30
|
+
const getterType = att.getterType;
|
|
31
|
+
|
|
32
|
+
if (getterType._type === "stored_class") {
|
|
33
|
+
this.code.line(
|
|
34
|
+
`private ${att.storageName} = ${this.storedClassInit(att)};`,
|
|
35
|
+
);
|
|
36
|
+
} else if (isStored) {
|
|
37
|
+
this.code.line(
|
|
38
|
+
`private ${att.storageName}?: ${att.type.inputTypeDefinition}; `,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.emitStoredClassBoundaryDoc(att);
|
|
43
|
+
|
|
44
|
+
switch (getterType._type) {
|
|
45
|
+
case "plain":
|
|
46
|
+
this.emitWriteOnlyGetterDeprecationNotice(att);
|
|
47
|
+
this.code.openBlock(`public get ${att.name}()`);
|
|
48
|
+
this.code.line(`return ${this.determineGetAttCall(att)};`);
|
|
49
|
+
this.code.closeBlock();
|
|
50
|
+
break;
|
|
51
|
+
|
|
52
|
+
case "args":
|
|
53
|
+
this.emitWriteOnlyGetterDeprecationNotice(att);
|
|
54
|
+
this.code.openBlock(
|
|
55
|
+
`public ${att.name}(${getterType.args})${
|
|
56
|
+
getterType.returnType ? ": " + getterType.returnType : ""
|
|
57
|
+
}`,
|
|
58
|
+
);
|
|
59
|
+
this.code.line(`return ${getterType.returnStatement};`);
|
|
60
|
+
this.code.closeBlock();
|
|
61
|
+
break;
|
|
62
|
+
|
|
63
|
+
case "stored_class":
|
|
64
|
+
this.emitWriteOnlyGetterDeprecationNotice(att);
|
|
65
|
+
this.code.openBlock(`public get ${att.name}()`);
|
|
66
|
+
this.code.line(`return this.${att.storageName};`);
|
|
67
|
+
this.code.closeBlock();
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const setterType = att.setterType;
|
|
72
|
+
|
|
73
|
+
// Write-only usage is registered at resolve time instead (see
|
|
74
|
+
// #emitToTerraform/#emitToHclTerraform and
|
|
75
|
+
// TerraformResource#markWriteOnlyAttribute), so setters intentionally
|
|
76
|
+
// emit no registration call here: they only store the value.
|
|
77
|
+
switch (setterType._type) {
|
|
78
|
+
case "set":
|
|
79
|
+
this.code.openBlock(
|
|
80
|
+
`public set ${att.name}(value: ${setterType.type})`,
|
|
81
|
+
);
|
|
82
|
+
this.code.line(`this.${att.storageName} = value;`);
|
|
83
|
+
this.code.closeBlock();
|
|
84
|
+
break;
|
|
85
|
+
|
|
86
|
+
case "put":
|
|
87
|
+
this.code.openBlock(
|
|
88
|
+
`public put${titleCase(att.name)}(value: ${setterType.type})`,
|
|
89
|
+
);
|
|
90
|
+
this.code.line(`this.${att.storageName} = value;`);
|
|
91
|
+
this.code.closeBlock();
|
|
92
|
+
break;
|
|
93
|
+
|
|
94
|
+
case "stored_class":
|
|
95
|
+
this.code.openBlock(
|
|
96
|
+
`public put${titleCase(att.name)}(value: ${setterType.type})`,
|
|
97
|
+
);
|
|
98
|
+
this.code.line(`this.${att.storageName}.internalValue = value;`);
|
|
99
|
+
this.code.closeBlock();
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (hasResetMethod) {
|
|
104
|
+
this.code.openBlock(
|
|
105
|
+
`public ${this.getResetName(att.name, escapeReset)}()`,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (setterType._type === "stored_class") {
|
|
109
|
+
this.code.line(`this.${att.storageName}.internalValue = undefined;`);
|
|
110
|
+
} else {
|
|
111
|
+
this.code.line(`this.${att.storageName} = undefined;`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.code.closeBlock();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (hasInputMethod) {
|
|
118
|
+
this.code.line(`// Temporarily expose input value. Use with caution.`);
|
|
119
|
+
this.code.openBlock(
|
|
120
|
+
`public get ${this.getInputName(att, escapeInput)}()`,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (setterType._type === "stored_class") {
|
|
124
|
+
this.code.line(`return this.${att.storageName}.internalValue;`);
|
|
125
|
+
} else {
|
|
126
|
+
this.code.line(`return this.${att.storageName};`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
this.code.closeBlock();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// emits a @deprecated JSDoc block above a write-only attribute's getter:
|
|
134
|
+
// providers never persist/return write-only values, so the state-backed
|
|
135
|
+
// getter always reads back null by protocol contract
|
|
136
|
+
private emitWriteOnlyGetterDeprecationNotice(att: AttributeModel) {
|
|
137
|
+
if (!att.isWriteOnly) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const comment = sanitizedComment(this.code);
|
|
142
|
+
comment.line(
|
|
143
|
+
"@deprecated Write-only: the provider never returns this value; reading it always yields null by protocol contract. The getter remains for compatibility and will be removed in a future prebuilt-provider major.",
|
|
144
|
+
);
|
|
145
|
+
comment.end();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// returns an invocation of a stored class, e.g. 'new DeplotmentMetadataOutputReference(this, "metadata")'
|
|
149
|
+
private storedClassInit(att: AttributeModel) {
|
|
150
|
+
return att.type.getStoredClassInitializer(att.terraformName);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Emits a JSDoc block documenting the Terraform type immediately before getters whose
|
|
154
|
+
// stored class either collapsed a deeper, unsupported nesting into the nearest typed
|
|
155
|
+
// "Any"-wrapper, or fell all the way back to a plain, untyped getter because no stored
|
|
156
|
+
// class (not even a collapsed one) is available. Normal, fully-supported getters get no
|
|
157
|
+
// such doc, to limit snapshot churn.
|
|
158
|
+
private emitStoredClassBoundaryDoc(att: AttributeModel) {
|
|
159
|
+
const boundaryKind = att.storedClassBoundaryKind;
|
|
160
|
+
if (!boundaryKind) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const comment = sanitizedComment(this.code);
|
|
165
|
+
comment.line(`Terraform type: \`${describeTerraformType(att.type)}\`.`);
|
|
166
|
+
|
|
167
|
+
if (boundaryKind === "collapsed") {
|
|
168
|
+
const collapsedName = (att.type as CollectionAttributeTypeModel)
|
|
169
|
+
.resolvedStoredClass!.name;
|
|
170
|
+
comment.line(
|
|
171
|
+
`This nesting is deeper than the typed wrapper classes in the core cdktn package; it is exposed as \`${collapsedName}\` and values below that boundary are untyped tokens.`,
|
|
172
|
+
);
|
|
173
|
+
} else {
|
|
174
|
+
comment.line(
|
|
175
|
+
`No typed wrapper class for this shape exists in the core cdktn package; the value is returned as an untyped token (IResolvable).`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
comment.end();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public determineGetAttCall(att: AttributeModel): string {
|
|
183
|
+
if (att.isProvider) {
|
|
184
|
+
return `this.${att.storageName}`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return att.type.getAttributeAccessFunction(att.terraformName);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public needsInputEscape(
|
|
191
|
+
att: AttributeModel,
|
|
192
|
+
attributes: AttributeModel[],
|
|
193
|
+
): boolean {
|
|
194
|
+
return (
|
|
195
|
+
attributes.find((a) =>
|
|
196
|
+
a.terraformName.match(`^${att.terraformName}_input$`),
|
|
197
|
+
) instanceof AttributeModel
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public getInputName(att: AttributeModel, escape: boolean) {
|
|
202
|
+
if (escape) {
|
|
203
|
+
return `${att.name}TfInput`;
|
|
204
|
+
} else {
|
|
205
|
+
return `${att.name}Input`;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public needsResetEscape(
|
|
210
|
+
att: AttributeModel,
|
|
211
|
+
attributes: AttributeModel[],
|
|
212
|
+
): boolean {
|
|
213
|
+
return (
|
|
214
|
+
attributes.find((a) =>
|
|
215
|
+
a.terraformName.match(`^reset_${att.terraformName}$`),
|
|
216
|
+
) instanceof AttributeModel
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public getResetName(name: string, escape: boolean) {
|
|
221
|
+
if (!name) return name;
|
|
222
|
+
if (escape) {
|
|
223
|
+
return `resetTf${titleCase(name)}`;
|
|
224
|
+
} else {
|
|
225
|
+
return `reset${titleCase(name)}`;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* @param canRegisterProviderFeatureUsage Whether this attribute's mapped
|
|
231
|
+
* value should be wrapped in `this.markWriteOnlyAttribute(...)` when it is
|
|
232
|
+
* write-only. Only true for attributes emitted on classes that extend
|
|
233
|
+
* TerraformResource (managed resources) - struct-level `xToTerraform`/
|
|
234
|
+
* `xToHclTerraform` functions are standalone functions with no `this` of
|
|
235
|
+
* that type, so they never pass this (see ResourceEmitter's
|
|
236
|
+
* `supportsWriteOnlyRegistration`).
|
|
237
|
+
*/
|
|
238
|
+
public emitToHclTerraform(
|
|
239
|
+
att: AttributeModel,
|
|
240
|
+
isStruct: boolean,
|
|
241
|
+
canRegisterProviderFeatureUsage = false,
|
|
242
|
+
) {
|
|
243
|
+
const type = att.type;
|
|
244
|
+
const context = isStruct ? "struct!" : "this";
|
|
245
|
+
const name = isStruct ? att.name : att.storageName;
|
|
246
|
+
const customDefault = CUSTOM_DEFAULTS[att.terraformFullName];
|
|
247
|
+
|
|
248
|
+
const varReference = `${context}.${name}${
|
|
249
|
+
!isStruct &&
|
|
250
|
+
type.isComplex &&
|
|
251
|
+
!att.isProvider &&
|
|
252
|
+
(type.struct?.isClass || att.getterType._type === "stored_class")
|
|
253
|
+
? ".internalValue"
|
|
254
|
+
: ""
|
|
255
|
+
}`;
|
|
256
|
+
const defaultCheck =
|
|
257
|
+
customDefault !== undefined
|
|
258
|
+
? `${varReference} === undefined ? ${customDefault} : `
|
|
259
|
+
: "";
|
|
260
|
+
|
|
261
|
+
const mappedValue = `${defaultCheck}${type.toHclTerraformFunction}(${varReference})`;
|
|
262
|
+
// markWriteOnlyAttribute() passes `undefined`/`null` straight through
|
|
263
|
+
// unwrapped, so this keeps the "remove undefined attributes" filter in
|
|
264
|
+
// the caller (which checks `value.value !== undefined`) working exactly
|
|
265
|
+
// as before for unset/cleared write-only attributes.
|
|
266
|
+
const value =
|
|
267
|
+
att.isWriteOnly && canRegisterProviderFeatureUsage
|
|
268
|
+
? `this.markWriteOnlyAttribute(${mappedValue})`
|
|
269
|
+
: mappedValue;
|
|
270
|
+
const isBlock = att.type.isComplex;
|
|
271
|
+
const tt = att.type.typeModelType;
|
|
272
|
+
|
|
273
|
+
this.code.open(`${att.terraformName}: {`);
|
|
274
|
+
this.code.line(`value: ${value},`);
|
|
275
|
+
this.code.line(`isBlock: ${isBlock},`);
|
|
276
|
+
this.code.line(`type: "${tt}",`);
|
|
277
|
+
this.code.line(`storageClassType: "${att.type.storedClassType}",`);
|
|
278
|
+
this.code.close("},");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
public emitToTerraform(
|
|
282
|
+
att: AttributeModel,
|
|
283
|
+
isStruct: boolean,
|
|
284
|
+
canRegisterProviderFeatureUsage = false,
|
|
285
|
+
) {
|
|
286
|
+
const type = att.type;
|
|
287
|
+
const context = isStruct ? "struct!" : "this";
|
|
288
|
+
const name = isStruct ? att.name : att.storageName;
|
|
289
|
+
const customDefault = CUSTOM_DEFAULTS[att.terraformFullName];
|
|
290
|
+
|
|
291
|
+
const varReference = `${context}.${name}${
|
|
292
|
+
!isStruct &&
|
|
293
|
+
type.isComplex &&
|
|
294
|
+
!att.isProvider &&
|
|
295
|
+
(type.struct?.isClass || att.getterType._type === "stored_class")
|
|
296
|
+
? ".internalValue"
|
|
297
|
+
: ""
|
|
298
|
+
}`;
|
|
299
|
+
const defaultCheck =
|
|
300
|
+
customDefault !== undefined
|
|
301
|
+
? `${varReference} === undefined ? ${customDefault} : `
|
|
302
|
+
: "";
|
|
303
|
+
|
|
304
|
+
const mappedValue = `${defaultCheck}${type.toTerraformFunction}(${varReference})`;
|
|
305
|
+
// markWriteOnlyAttribute() passes `undefined`/`null` straight through
|
|
306
|
+
// unwrapped, so an unset/cleared write-only attribute still vanishes
|
|
307
|
+
// from the returned object exactly as before (see the "skip undefined"
|
|
308
|
+
// step in tokens/private/resolve.ts).
|
|
309
|
+
const value =
|
|
310
|
+
att.isWriteOnly && canRegisterProviderFeatureUsage
|
|
311
|
+
? `this.markWriteOnlyAttribute(${mappedValue})`
|
|
312
|
+
: mappedValue;
|
|
313
|
+
|
|
314
|
+
this.code.line(`${att.terraformName}: ${value},`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import { CodeMaker } from "codemaker";
|
|
4
|
+
import {
|
|
5
|
+
ProviderFunctionModel,
|
|
6
|
+
ProviderFunctionsModel,
|
|
7
|
+
} from "../models/provider-function-model";
|
|
8
|
+
import { sanitizedComment } from "../sanitized-comments";
|
|
9
|
+
|
|
10
|
+
const PROVIDER_LOCAL_NAME_JSDOC =
|
|
11
|
+
"The local name of the provider in required_providers; defaults to the registry short name. Override when the provider is declared under a different local name — aliases do not change the namespace, local names do.";
|
|
12
|
+
|
|
13
|
+
export class ProviderFunctionsEmitter {
|
|
14
|
+
constructor(private readonly code: CodeMaker) {}
|
|
15
|
+
|
|
16
|
+
public emit(model: ProviderFunctionsModel) {
|
|
17
|
+
this.code.line(`import * as cdktn from 'cdktn';`);
|
|
18
|
+
this.code.line();
|
|
19
|
+
this.emitClass(model);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private emitClass(model: ProviderFunctionsModel) {
|
|
23
|
+
const comment = sanitizedComment(this.code);
|
|
24
|
+
comment.line(
|
|
25
|
+
`Provider-defined functions of the ${model.providerName} provider.`,
|
|
26
|
+
);
|
|
27
|
+
comment.end();
|
|
28
|
+
this.code.openBlock(`export class ${model.className}`);
|
|
29
|
+
|
|
30
|
+
this.emitConstructor();
|
|
31
|
+
|
|
32
|
+
for (const fn of model.functions) {
|
|
33
|
+
this.emitMethod(fn);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.code.closeBlock();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private emitConstructor() {
|
|
40
|
+
// A TypeScript parameter property (`constructor(private readonly x: T)`)
|
|
41
|
+
// requires the compiler to synthesize a `this.x = x;` assignment - that's
|
|
42
|
+
// a real transform, not a type-only erasure, so it isn't recognized by
|
|
43
|
+
// Node's native type-stripping (`node file.ts` with no bundler/transpiler,
|
|
44
|
+
// e.g. `--experimental-strip-types`), which throws
|
|
45
|
+
// `ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX` on sight of one. Declare the field
|
|
46
|
+
// and assign it in the constructor body instead, which strips cleanly.
|
|
47
|
+
this.code.line(`private readonly providerLocalName: string;`);
|
|
48
|
+
this.code.line();
|
|
49
|
+
const comment = sanitizedComment(this.code);
|
|
50
|
+
comment.line(`@param providerLocalName ${PROVIDER_LOCAL_NAME_JSDOC}`);
|
|
51
|
+
comment.end();
|
|
52
|
+
this.code.openBlock(`constructor(providerLocalName: string)`);
|
|
53
|
+
this.code.line(`this.providerLocalName = providerLocalName;`);
|
|
54
|
+
this.code.closeBlock();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private emitMethod(fn: ProviderFunctionModel) {
|
|
58
|
+
this.code.line();
|
|
59
|
+
|
|
60
|
+
const comment = sanitizedComment(this.code);
|
|
61
|
+
const description = fn.description ?? fn.summary;
|
|
62
|
+
if (description) comment.line(description);
|
|
63
|
+
if (fn.deprecationMessage) {
|
|
64
|
+
comment.line(`@deprecated ${fn.deprecationMessage}`);
|
|
65
|
+
}
|
|
66
|
+
// The variadic parameter's docstringType is already wrapped in
|
|
67
|
+
// `Array<...>` by buildFunctionModel (see provider-function-model.ts),
|
|
68
|
+
// so it shares this one `@param` emission path with every fixed
|
|
69
|
+
// parameter instead of needing its own wrapping here.
|
|
70
|
+
const allParameters = fn.variadicParameter
|
|
71
|
+
? [...fn.parameters, fn.variadicParameter]
|
|
72
|
+
: fn.parameters;
|
|
73
|
+
for (const param of allParameters) {
|
|
74
|
+
// Official JSDoc grammar: only the type expression goes inside the
|
|
75
|
+
// braces; prose (the schema description plus any generated
|
|
76
|
+
// list/set/nullability guidance - see the model's `docstringNote`)
|
|
77
|
+
// follows the parameter name after ` - `.
|
|
78
|
+
const prose = [param.description, param.docstringNote]
|
|
79
|
+
.filter(Boolean)
|
|
80
|
+
.join(" ");
|
|
81
|
+
comment.line(
|
|
82
|
+
`@param {${param.docstringType}} ${param.name}${prose ? ` - ${prose}` : ""}`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
comment.line(
|
|
86
|
+
`@returns {${fn.returnDocstringType}}${fn.returnDocstringNote ? ` ${fn.returnDocstringNote}` : ""}`,
|
|
87
|
+
);
|
|
88
|
+
comment.end();
|
|
89
|
+
|
|
90
|
+
const methodParams = [
|
|
91
|
+
...fn.parameters.map(
|
|
92
|
+
(p) => `${p.name}${p.optional ? "?" : ""}: ${p.tsType}`,
|
|
93
|
+
),
|
|
94
|
+
...(fn.variadicParameter
|
|
95
|
+
? // `Array<T>` rather than `T[]`: for a union element type (e.g.
|
|
96
|
+
// `boolean | cdktn.IResolvable`), bare `T[]` binds as `boolean |
|
|
97
|
+
// (cdktn.IResolvable[])` instead of `(boolean | cdktn.IResolvable)[]`.
|
|
98
|
+
[
|
|
99
|
+
`${fn.variadicParameter.name}: Array<${fn.variadicParameter.tsType}>`,
|
|
100
|
+
]
|
|
101
|
+
: []),
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const invokeArgs = [
|
|
105
|
+
...fn.parameters.map((p) => p.name),
|
|
106
|
+
...(fn.variadicParameter ? [`...${fn.variadicParameter.name}`] : []),
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
const invokeExpression = `cdktn.TerraformProviderFunction.invoke(this.providerLocalName, "${fn.terraformName}", [${invokeArgs.join(", ")}])`;
|
|
110
|
+
|
|
111
|
+
this.code.openBlock(
|
|
112
|
+
`public ${fn.methodName}(${methodParams.join(", ")}): ${fn.returnTsType}`,
|
|
113
|
+
);
|
|
114
|
+
this.code.line(`return ${fn.wrapReturn(invokeExpression)};`);
|
|
115
|
+
this.code.closeBlock();
|
|
116
|
+
}
|
|
117
|
+
}
|