@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.
Files changed (124) hide show
  1. package/.spec.swcrc +22 -0
  2. package/LICENSE +355 -0
  3. package/README.md +1 -1
  4. package/build/__tests__/edge-provider-schema/builder.d.ts +9 -3
  5. package/build/__tests__/edge-provider-schema/builder.js +6 -3
  6. package/build/__tests__/edge-provider-schema/cli.js +8 -3
  7. package/build/__tests__/edge-provider-schema/index.js +119 -1
  8. package/build/__tests__/provider.test.js +4 -1
  9. package/build/get/__tests__/generator/ephemeral-resources.test.d.ts +2 -0
  10. package/build/get/__tests__/generator/ephemeral-resources.test.js +49 -0
  11. package/build/get/__tests__/generator/module-generator.test.js +12 -12
  12. package/build/get/__tests__/generator/provider-functions.test.d.ts +2 -0
  13. package/build/get/__tests__/generator/provider-functions.test.js +176 -0
  14. package/build/get/__tests__/generator/provider-source-matching.test.d.ts +2 -0
  15. package/build/get/__tests__/generator/provider-source-matching.test.js +45 -0
  16. package/build/get/__tests__/generator/provider.test.js +9 -1
  17. package/build/get/__tests__/generator/supported-stored-classes.test.d.ts +2 -0
  18. package/build/get/__tests__/generator/supported-stored-classes.test.js +137 -0
  19. package/build/get/__tests__/generator/types.test.js +44 -1
  20. package/build/get/__tests__/generator/write-only.test.d.ts +2 -0
  21. package/build/get/__tests__/generator/write-only.test.js +65 -0
  22. package/build/get/__tests__/target-versions.test.d.ts +2 -0
  23. package/build/get/__tests__/target-versions.test.js +171 -0
  24. package/build/get/constructs-maker.d.ts +8 -1
  25. package/build/get/constructs-maker.js +46 -10
  26. package/build/get/generator/emitter/attributes-emitter.d.ts +13 -2
  27. package/build/get/generator/emitter/attributes-emitter.js +71 -5
  28. package/build/get/generator/emitter/index.d.ts +1 -0
  29. package/build/get/generator/emitter/index.js +2 -1
  30. package/build/get/generator/emitter/provider-functions-emitter.d.ts +11 -0
  31. package/build/get/generator/emitter/provider-functions-emitter.js +94 -0
  32. package/build/get/generator/emitter/resource-emitter.d.ts +5 -1
  33. package/build/get/generator/emitter/resource-emitter.js +83 -7
  34. package/build/get/generator/emitter/struct-emitter.js +10 -10
  35. package/build/get/generator/models/attribute-model.d.ts +4 -0
  36. package/build/get/generator/models/attribute-model.js +50 -4
  37. package/build/get/generator/models/attribute-type-model.d.ts +24 -0
  38. package/build/get/generator/models/attribute-type-model.js +91 -5
  39. package/build/get/generator/models/index.d.ts +1 -0
  40. package/build/get/generator/models/index.js +2 -1
  41. package/build/get/generator/models/provider-function-model.d.ts +102 -0
  42. package/build/get/generator/models/provider-function-model.js +667 -0
  43. package/build/get/generator/models/resource-model.d.ts +3 -0
  44. package/build/get/generator/models/resource-model.js +13 -4
  45. package/build/get/generator/models/struct.d.ts +2 -0
  46. package/build/get/generator/models/struct.js +6 -2
  47. package/build/get/generator/models/supported-stored-classes.d.ts +5 -0
  48. package/build/get/generator/models/supported-stored-classes.js +86 -0
  49. package/build/get/generator/module-generator.js +3 -3
  50. package/build/get/generator/provider-generator.d.ts +2 -0
  51. package/build/get/generator/provider-generator.js +41 -6
  52. package/build/get/generator/resource-parser.js +3 -1
  53. package/jest.config.js +16 -9
  54. package/package.json +28 -27
  55. package/package.sh +1 -1
  56. package/src/__tests__/__snapshots__/edge-provider-schema.test.ts.snap +4 -0
  57. package/src/__tests__/__snapshots__/provider.test.ts.snap +2828 -2828
  58. package/src/__tests__/edge-provider-schema/builder.ts +201 -0
  59. package/src/__tests__/edge-provider-schema/cli.ts +51 -0
  60. package/src/__tests__/edge-provider-schema/index.ts +284 -0
  61. package/src/__tests__/edge-provider-schema.test.ts +24 -0
  62. package/src/__tests__/provider.test.ts +183 -0
  63. package/src/get/__tests__/constructs-maker.test.ts +118 -0
  64. package/src/get/__tests__/generator/__snapshots__/complex-computed-types.test.ts.snap +5 -5
  65. package/src/get/__tests__/generator/__snapshots__/ephemeral-resources.test.ts.snap +524 -0
  66. package/src/get/__tests__/generator/__snapshots__/export-sharding.test.ts.snap +3310 -3310
  67. package/src/get/__tests__/generator/__snapshots__/module-generator.test.ts.snap +355 -355
  68. package/src/get/__tests__/generator/__snapshots__/nested-types.test.ts.snap +8 -8
  69. package/src/get/__tests__/generator/__snapshots__/provider-functions.test.ts.snap +444 -0
  70. package/src/get/__tests__/generator/__snapshots__/provider.test.ts.snap +8 -8
  71. package/src/get/__tests__/generator/__snapshots__/resource-types.test.ts.snap +126 -126
  72. package/src/get/__tests__/generator/__snapshots__/skipped-attributes.test.ts.snap +17 -17
  73. package/src/get/__tests__/generator/__snapshots__/types.test.ts.snap +201 -52
  74. package/src/get/__tests__/generator/__snapshots__/write-only.test.ts.snap +262 -0
  75. package/src/get/__tests__/generator/complex-computed-types.test.ts +28 -0
  76. package/src/get/__tests__/generator/deep-nested-attributes.test.ts +56 -0
  77. package/src/get/__tests__/generator/description-escaping.test.ts +84 -0
  78. package/src/get/__tests__/generator/empty-provider-resources.test.ts +26 -0
  79. package/src/get/__tests__/generator/ephemeral-resources.test.ts +46 -0
  80. package/src/get/__tests__/generator/export-sharding.test.ts +169 -0
  81. package/src/get/__tests__/generator/fixtures/deeply-nested-collections.test.fixture.json +129 -0
  82. package/src/get/__tests__/generator/fixtures/ephemeral-resources.test.fixture.json +160 -0
  83. package/src/get/__tests__/generator/fixtures/provider-functions-collision.test.fixture.json +31 -0
  84. package/src/get/__tests__/generator/fixtures/provider-functions-synthetic.test.fixture.json +192 -0
  85. package/src/get/__tests__/generator/fixtures/provider-functions.test.fixture.json +170 -0
  86. package/src/get/__tests__/generator/fixtures/write-only.test.fixture.json +58 -0
  87. package/src/get/__tests__/generator/import-style.test.ts +129 -0
  88. package/src/get/__tests__/generator/module-generator.test.ts +528 -0
  89. package/src/get/__tests__/generator/nested-types.test.ts +54 -0
  90. package/src/get/__tests__/generator/provider-functions.test.ts +262 -0
  91. package/src/get/__tests__/generator/provider-source-matching.test.ts +84 -0
  92. package/src/get/__tests__/generator/provider.test.ts +59 -0
  93. package/src/get/__tests__/generator/resource-types.test.ts +118 -0
  94. package/src/get/__tests__/generator/skipped-attributes.test.ts +72 -0
  95. package/src/get/__tests__/generator/supported-stored-classes.test.ts +147 -0
  96. package/src/get/__tests__/generator/types.test.ts +686 -0
  97. package/src/get/__tests__/generator/versions-file.test.ts +72 -0
  98. package/src/get/__tests__/generator/write-only.test.ts +71 -0
  99. package/src/get/__tests__/target-versions.test.ts +206 -0
  100. package/src/get/__tests__/util.ts +75 -0
  101. package/src/get/constructs-maker.ts +885 -0
  102. package/src/get/generator/custom-defaults.ts +493 -0
  103. package/src/get/generator/emitter/attributes-emitter.ts +316 -0
  104. package/src/get/generator/emitter/index.ts +6 -0
  105. package/src/get/generator/emitter/provider-functions-emitter.ts +117 -0
  106. package/src/get/generator/emitter/resource-emitter.ts +330 -0
  107. package/src/get/generator/emitter/struct-emitter.ts +683 -0
  108. package/src/get/generator/loop-detection.ts +81 -0
  109. package/src/get/generator/models/attribute-model.ts +273 -0
  110. package/src/get/generator/models/attribute-type-model.ts +560 -0
  111. package/src/get/generator/models/index.ts +8 -0
  112. package/src/get/generator/models/provider-function-model.ts +872 -0
  113. package/src/get/generator/models/resource-model.ts +183 -0
  114. package/src/get/generator/models/scope.ts +54 -0
  115. package/src/get/generator/models/struct.ts +124 -0
  116. package/src/get/generator/models/supported-stored-classes.ts +88 -0
  117. package/src/get/generator/module-generator.ts +234 -0
  118. package/src/get/generator/provider-generator.ts +428 -0
  119. package/src/get/generator/resource-parser.ts +764 -0
  120. package/src/get/generator/sanitized-comments.ts +49 -0
  121. package/src/get/generator/skipped-attributes.ts +27 -0
  122. package/src/index.ts +40 -0
  123. package/src/util.ts +26 -0
  124. 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,6 @@
1
+ // Copyright (c) HashiCorp, Inc
2
+ // SPDX-License-Identifier: MPL-2.0
3
+ export * from "./attributes-emitter";
4
+ export * from "./provider-functions-emitter";
5
+ export * from "./resource-emitter";
6
+ export * from "./struct-emitter";
@@ -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
+ }