@cdktn/hcl2cdk 0.24.0-pre.45 → 0.24.0-pre.47

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 (89) hide show
  1. package/LICENSE +355 -0
  2. package/README.md +1 -1
  3. package/build/__tests__/expressions.test.js +10 -19
  4. package/build/__tests__/functions.test.js +8 -18
  5. package/build/__tests__/testHelpers.js +3 -2
  6. package/build/coerceType.js +11 -21
  7. package/build/dynamic-blocks.js +3 -3
  8. package/build/expressions.js +13 -22
  9. package/build/function-bindings/functions.generated.js +2 -2
  10. package/build/generation.js +24 -34
  11. package/build/index.js +15 -25
  12. package/build/iteration.js +7 -6
  13. package/build/jsii-rosetta-workarounds.js +6 -5
  14. package/build/partialCode.js +11 -20
  15. package/build/provider.js +4 -3
  16. package/build/references.js +6 -5
  17. package/build/schema.js +8 -18
  18. package/build/terraformSchema.js +4 -4
  19. package/build/utils.js +3 -3
  20. package/build/variables.js +12 -21
  21. package/package.json +20 -17
  22. package/package.sh +1 -1
  23. package/src/__tests__/coerceType.test.ts +207 -0
  24. package/src/__tests__/expressionToTs.test.ts +1167 -0
  25. package/src/__tests__/expressions.test.ts +541 -0
  26. package/src/__tests__/findExpressionType.test.ts +112 -0
  27. package/src/__tests__/functions.test.ts +768 -0
  28. package/src/__tests__/generation.test.ts +72 -0
  29. package/src/__tests__/jsii-rosetta-workarounds.test.ts +145 -0
  30. package/src/__tests__/partialCode.test.ts +432 -0
  31. package/src/__tests__/terraformSchema.test.ts +107 -0
  32. package/src/__tests__/testHelpers.ts +11 -0
  33. package/src/coerceType.ts +261 -0
  34. package/src/dynamic-blocks.ts +61 -0
  35. package/src/expressions.ts +968 -0
  36. package/src/function-bindings/functions.generated.ts +1139 -0
  37. package/src/function-bindings/functions.ts +104 -0
  38. package/src/generation.ts +1189 -0
  39. package/src/index.ts +584 -0
  40. package/src/iteration.ts +156 -0
  41. package/src/jsii-rosetta-workarounds.ts +145 -0
  42. package/src/partialCode.ts +132 -0
  43. package/src/provider.ts +60 -0
  44. package/src/references.ts +193 -0
  45. package/src/schema.ts +74 -0
  46. package/src/terraformSchema.ts +182 -0
  47. package/src/types.ts +58 -0
  48. package/src/utils.ts +19 -0
  49. package/src/variables.ts +214 -0
  50. package/test/__snapshots__/backends.test.ts.snap +70 -0
  51. package/test/__snapshots__/externals.test.ts.snap +37 -0
  52. package/test/__snapshots__/granular-imports.test.ts.snap +180 -0
  53. package/test/__snapshots__/imports.test.ts.snap +159 -0
  54. package/test/__snapshots__/iteration.test.ts.snap +532 -0
  55. package/test/__snapshots__/jsiiLanguage.test.ts.snap +347 -0
  56. package/test/__snapshots__/locals.test.ts.snap +55 -0
  57. package/test/__snapshots__/modules.test.ts.snap +127 -0
  58. package/test/__snapshots__/outputs.test.ts.snap +77 -0
  59. package/test/__snapshots__/partialCode.test.ts.snap +120 -0
  60. package/test/__snapshots__/provider.test.ts.snap +128 -0
  61. package/test/__snapshots__/references.test.ts.snap +376 -0
  62. package/test/__snapshots__/resource-meta-properties.test.ts.snap +342 -0
  63. package/test/__snapshots__/resources.test.ts.snap +613 -0
  64. package/test/__snapshots__/tfExpressions.test.ts.snap +537 -0
  65. package/test/__snapshots__/typeCoercion.test.ts.snap +253 -0
  66. package/test/__snapshots__/variables.test.ts.snap +150 -0
  67. package/test/backends.test.ts +75 -0
  68. package/test/convertProject.test.ts +257 -0
  69. package/test/externals.test.ts +35 -0
  70. package/test/globalSetup.ts +224 -0
  71. package/test/globalTeardown.ts +11 -0
  72. package/test/granular-imports.test.ts +161 -0
  73. package/test/hcl2cdk.test.ts +88 -0
  74. package/test/helpers/convert.ts +543 -0
  75. package/test/helpers/tmp.ts +25 -0
  76. package/test/imports.test.ts +141 -0
  77. package/test/iteration.test.ts +342 -0
  78. package/test/jsiiLanguage.test.ts +73 -0
  79. package/test/locals.test.ts +47 -0
  80. package/test/modules.test.ts +143 -0
  81. package/test/outputs.test.ts +69 -0
  82. package/test/partialCode.test.ts +25 -0
  83. package/test/provider.test.ts +106 -0
  84. package/test/references.test.ts +287 -0
  85. package/test/resource-meta-properties.test.ts +288 -0
  86. package/test/resources.test.ts +551 -0
  87. package/test/tfExpressions.test.ts +300 -0
  88. package/test/typeCoercion.test.ts +154 -0
  89. package/test/variables.test.ts +96 -0
@@ -0,0 +1,541 @@
1
+ // Copyright (c) HashiCorp, Inc
2
+ // SPDX-License-Identifier: MPL-2.0
3
+ import generate from "@babel/generator";
4
+ import * as t from "@babel/types";
5
+ import { dynamicVariableToAst } from "../expressions";
6
+ import { ProgramScope, Reference } from "../types";
7
+ import {
8
+ extractReferencesFromExpression,
9
+ referenceToVariableName,
10
+ } from "../references";
11
+ import { getExpressionAst } from "@cdktn/hcl2json";
12
+ import { TFExpressionSyntaxTree as tex } from "@cdktn/hcl2json";
13
+ import { camelCase } from "../utils";
14
+
15
+ const nodeIds = [
16
+ "var.input",
17
+ "module.vpc",
18
+ "data.aws_s3_bucket.examplebucket",
19
+ "aws_s3_bucket.examplebucket",
20
+ "aws_s3_bucket.otherbucket",
21
+ "var.users",
22
+ "aws_kms_key.key",
23
+ "local.service_name",
24
+ ];
25
+
26
+ // Transforms a path with segments into literals describing the path
27
+ function getPropertyAccessPath(input: string): string[] {
28
+ return input
29
+ .split(/(\[|\]|\.)/g)
30
+ .filter((p) => p.length > 0 && p !== "." && p !== "[" && p !== "]")
31
+ .map((p) => (p.startsWith(`"`) && p.endsWith(`"`) ? p.slice(1, -1) : p));
32
+ }
33
+
34
+ export function referenceToAst(scope: ProgramScope, ref: Reference) {
35
+ const [resource, , ...selector] = ref.referencee.full.split(".");
36
+
37
+ const variableReference = t.identifier(
38
+ camelCase(referenceToVariableName(scope, ref)),
39
+ );
40
+
41
+ if (resource === "data") {
42
+ selector.shift(); // remove the data part so that the name is not used in the selector
43
+ }
44
+
45
+ const accessor = selector.reduce(
46
+ (carry, member, index) =>
47
+ t.memberExpression(
48
+ carry,
49
+ t.identifier(
50
+ index === 0 && resource === "module"
51
+ ? camelCase(member + "Output")
52
+ : camelCase(member),
53
+ ),
54
+ ),
55
+ variableReference as t.Expression,
56
+ );
57
+
58
+ if (ref.useFqn) {
59
+ return t.memberExpression(accessor, t.identifier("fqn"));
60
+ }
61
+
62
+ if (ref.isVariable) {
63
+ return t.memberExpression(accessor, t.identifier("value"));
64
+ }
65
+ return accessor;
66
+ }
67
+
68
+ describe("expressions", () => {
69
+ describe("#extractReferencesFromExpression", () => {
70
+ it("finds no references in literals", () => {
71
+ return expect(
72
+ extractReferencesFromExpression("nothingtobeseen", nodeIds),
73
+ ).resolves.toEqual([]);
74
+ });
75
+
76
+ it("finds no references in literals with functions", () => {
77
+ return expect(
78
+ extractReferencesFromExpression("${foo(nothingtobeseen)}", nodeIds),
79
+ ).resolves.toEqual([]);
80
+ });
81
+
82
+ it("finds no references in literals with functions and artihmetics", () => {
83
+ return expect(
84
+ extractReferencesFromExpression(
85
+ "${foo(nothingtobeseen - 2) + 3}",
86
+ nodeIds,
87
+ ),
88
+ ).resolves.toEqual([]);
89
+ });
90
+
91
+ it("finds plain var reference", () => {
92
+ return expect(
93
+ extractReferencesFromExpression("${var.input}", nodeIds),
94
+ ).resolves.toEqual([
95
+ {
96
+ referencee: { id: "var.input", full: "var.input" },
97
+ useFqn: false,
98
+ isVariable: true,
99
+ start: 2,
100
+ end: 11,
101
+ },
102
+ ]);
103
+ });
104
+
105
+ it("finds plain module reference", () => {
106
+ return expect(
107
+ extractReferencesFromExpression(
108
+ "${module.vpc.public_subnets}",
109
+ nodeIds,
110
+ ),
111
+ ).resolves.toEqual([
112
+ {
113
+ referencee: {
114
+ id: "module.vpc",
115
+ full: "module.vpc.public_subnets",
116
+ },
117
+ useFqn: false,
118
+ isVariable: false,
119
+ start: 2,
120
+ end: 27,
121
+ },
122
+ ]);
123
+ });
124
+
125
+ it("finds plain data reference", () => {
126
+ return expect(
127
+ extractReferencesFromExpression(
128
+ "${data.aws_s3_bucket.examplebucket.arn}",
129
+ nodeIds,
130
+ ),
131
+ ).resolves.toEqual([
132
+ {
133
+ referencee: {
134
+ id: "data.aws_s3_bucket.examplebucket",
135
+ full: "data.aws_s3_bucket.examplebucket.arn",
136
+ },
137
+ useFqn: false,
138
+ isVariable: false,
139
+ start: 2,
140
+ end: 38,
141
+ },
142
+ ]);
143
+ });
144
+
145
+ it("finds plain local reference", () => {
146
+ return expect(
147
+ extractReferencesFromExpression("${local.service_name}", nodeIds),
148
+ ).resolves.toEqual([
149
+ {
150
+ referencee: {
151
+ id: "local.service_name",
152
+ full: "local.service_name",
153
+ },
154
+ useFqn: false,
155
+ isVariable: false,
156
+ start: 2,
157
+ end: 20,
158
+ },
159
+ ]);
160
+ });
161
+
162
+ it("finds plain resource reference", () => {
163
+ return expect(
164
+ extractReferencesFromExpression(
165
+ "${aws_s3_bucket.examplebucket.id}",
166
+ nodeIds,
167
+ ),
168
+ ).resolves.toEqual([
169
+ {
170
+ referencee: {
171
+ id: "aws_s3_bucket.examplebucket",
172
+ full: "aws_s3_bucket.examplebucket.id",
173
+ },
174
+ useFqn: false,
175
+ isVariable: false,
176
+ start: 2,
177
+ end: 32,
178
+ },
179
+ ]);
180
+ });
181
+
182
+ it("finds plain resource references in artihmetics", () => {
183
+ return expect(
184
+ extractReferencesFromExpression(
185
+ "${aws_s3_bucket.examplebucket.count + aws_s3_bucket.otherbucket.count }",
186
+ nodeIds,
187
+ ),
188
+ ).resolves.toEqual([
189
+ {
190
+ referencee: {
191
+ id: "aws_s3_bucket.examplebucket",
192
+ full: "aws_s3_bucket.examplebucket.count",
193
+ },
194
+ useFqn: false,
195
+ isVariable: false,
196
+ start: 2,
197
+ end: 35,
198
+ },
199
+ {
200
+ referencee: {
201
+ id: "aws_s3_bucket.otherbucket",
202
+ full: "aws_s3_bucket.otherbucket.count",
203
+ },
204
+ useFqn: false,
205
+ isVariable: false,
206
+ start: 38,
207
+ end: 69,
208
+ },
209
+ ]);
210
+ });
211
+
212
+ it("use fqn for splat reference", () => {
213
+ return expect(
214
+ extractReferencesFromExpression(
215
+ "${aws_s3_bucket.examplebucket.*.id}",
216
+ nodeIds,
217
+ ),
218
+ ).resolves.toEqual([
219
+ {
220
+ referencee: {
221
+ id: "aws_s3_bucket.examplebucket",
222
+ full: "aws_s3_bucket.examplebucket",
223
+ },
224
+ useFqn: true,
225
+ isVariable: false,
226
+ start: 2,
227
+ end: 29,
228
+ },
229
+ ]);
230
+ });
231
+
232
+ it("use no fqn if property is present on numeric access", () => {
233
+ return expect(
234
+ extractReferencesFromExpression(
235
+ "${aws_s3_bucket.examplebucket.network_interface.0.access_config.0.assigned_nat_ip}",
236
+ nodeIds,
237
+ ),
238
+ ).resolves.toEqual([
239
+ {
240
+ referencee: {
241
+ id: "aws_s3_bucket.examplebucket",
242
+ full: "aws_s3_bucket.examplebucket",
243
+ },
244
+ useFqn: true,
245
+ isVariable: false,
246
+ start: 2,
247
+ end: 81,
248
+ },
249
+ ]);
250
+ });
251
+
252
+ it("detect splat reference within function", () => {
253
+ return expect(
254
+ extractReferencesFromExpression(
255
+ "${toset(aws_s3_bucket.examplebucket.*)}",
256
+ nodeIds,
257
+ ),
258
+ ).resolves.toEqual([
259
+ {
260
+ referencee: {
261
+ id: "aws_s3_bucket.examplebucket",
262
+ full: "aws_s3_bucket.examplebucket",
263
+ },
264
+ useFqn: true,
265
+ isVariable: false,
266
+ start: 8,
267
+ end: 35,
268
+ },
269
+ ]);
270
+ });
271
+
272
+ it("finds all resources in conditional", () => {
273
+ return expect(
274
+ extractReferencesFromExpression(
275
+ "${aws_kms_key.key.deletion_window_in_days > 3 ? aws_s3_bucket.examplebucket.id : []}",
276
+ nodeIds,
277
+ ),
278
+ ).resolves.toEqual([
279
+ {
280
+ referencee: {
281
+ id: "aws_kms_key.key",
282
+ full: "aws_kms_key.key.deletion_window_in_days",
283
+ },
284
+ useFqn: false,
285
+ isVariable: false,
286
+ start: 2,
287
+ end: 41,
288
+ },
289
+ {
290
+ referencee: {
291
+ id: "aws_s3_bucket.examplebucket",
292
+ full: "aws_s3_bucket.examplebucket.id",
293
+ },
294
+ useFqn: false,
295
+ isVariable: false,
296
+ start: 48,
297
+ end: 78,
298
+ },
299
+ ]);
300
+ });
301
+
302
+ it("finds all resources in functions", () => {
303
+ return expect(
304
+ extractReferencesFromExpression(
305
+ "${element(aws_s3_bucket.examplebucket, 0).id}",
306
+ nodeIds,
307
+ ),
308
+ ).resolves.toEqual([
309
+ {
310
+ referencee: {
311
+ id: "aws_s3_bucket.examplebucket",
312
+ full: "aws_s3_bucket.examplebucket",
313
+ },
314
+ useFqn: false,
315
+ isVariable: false,
316
+ start: 10,
317
+ end: 37,
318
+ },
319
+ ]);
320
+ });
321
+
322
+ it("finds all resources in functions with splat", () => {
323
+ return expect(
324
+ extractReferencesFromExpression(
325
+ "${element(aws_s3_bucket.examplebucket.*.id, 0)}",
326
+ nodeIds,
327
+ ),
328
+ ).resolves.toEqual([
329
+ {
330
+ referencee: {
331
+ id: "aws_s3_bucket.examplebucket",
332
+ full: "aws_s3_bucket.examplebucket",
333
+ },
334
+ useFqn: true,
335
+ isVariable: false,
336
+ start: 10,
337
+ end: 37,
338
+ },
339
+ ]);
340
+ });
341
+
342
+ it("finds all resources in for loops", () => {
343
+ return expect(
344
+ extractReferencesFromExpression(
345
+ "${{ for name, user in var.users : user.role => name...}}",
346
+ nodeIds,
347
+ ),
348
+ ).resolves.toEqual([
349
+ {
350
+ referencee: { id: "var.users", full: "var.users" },
351
+ useFqn: false,
352
+ isVariable: true,
353
+ start: 22,
354
+ end: 31,
355
+ },
356
+ ]);
357
+ });
358
+
359
+ it("finds resources with property access", () => {
360
+ return expect(
361
+ extractReferencesFromExpression(
362
+ "${aws_s3_bucket.examplebucket[0].id}",
363
+ nodeIds,
364
+ ),
365
+ ).resolves.toEqual([
366
+ {
367
+ referencee: {
368
+ id: "aws_s3_bucket.examplebucket",
369
+ full: "aws_s3_bucket.examplebucket",
370
+ },
371
+ useFqn: true,
372
+ isVariable: false,
373
+ start: 2,
374
+ end: 35,
375
+ },
376
+ ]);
377
+ });
378
+
379
+ it("finds references within functions that use arrays and comments", () => {
380
+ return expect(
381
+ extractReferencesFromExpression(
382
+ `\${compact([
383
+ # The example "bucket"
384
+ aws_s3_bucket.examplebucket,
385
+
386
+ # The "Learn" single page application. This is not configured in all environments.
387
+ var.input,
388
+ ])}`,
389
+ nodeIds,
390
+ ),
391
+ ).resolves.toEqual([
392
+ {
393
+ referencee: {
394
+ id: "aws_s3_bucket.examplebucket",
395
+ full: "aws_s3_bucket.examplebucket",
396
+ },
397
+ useFqn: false,
398
+ isVariable: false,
399
+ start: 59,
400
+ end: 86,
401
+ },
402
+ {
403
+ referencee: {
404
+ id: "var.input",
405
+ full: "var.input",
406
+ },
407
+ useFqn: false,
408
+ isVariable: true,
409
+ start: 204,
410
+ end: 213,
411
+ },
412
+ ]);
413
+ });
414
+
415
+ it("finds references for same referencees", () => {
416
+ return expect(
417
+ extractReferencesFromExpression(
418
+ `\${var.input == "test" ? "azure-ad-int" : "azure-ad-\${var.input}"}`,
419
+ nodeIds,
420
+ ),
421
+ ).resolves.toEqual([
422
+ {
423
+ referencee: {
424
+ id: "var.input",
425
+ full: "var.input",
426
+ },
427
+ useFqn: false,
428
+ isVariable: true,
429
+ start: 2,
430
+ end: 11,
431
+ },
432
+ {
433
+ referencee: {
434
+ id: "var.input",
435
+ full: "var.input",
436
+ },
437
+ useFqn: false,
438
+ isVariable: true,
439
+ start: 53,
440
+ end: 62,
441
+ },
442
+ ]);
443
+ });
444
+ });
445
+
446
+ describe("#referenceToAst", () => {
447
+ it("property access", () => {
448
+ const scope: ProgramScope = {
449
+ providerSchema: { format_version: "0.1" },
450
+ providerGenerator: {},
451
+ constructs: new Set<string>(),
452
+ variables: {},
453
+ hasTokenBasedTypeCoercion: false,
454
+ nodeIds: [],
455
+ importables: [],
456
+ topLevelConfig: {},
457
+ };
458
+ expect(
459
+ generate(
460
+ t.program([
461
+ t.expressionStatement(
462
+ referenceToAst(scope, {
463
+ start: 0,
464
+ end: 0,
465
+ useFqn: false,
466
+ isVariable: false,
467
+ referencee: {
468
+ id: "aws_kms_key.key",
469
+ full: "aws_kms_key.key.deletion_window_in_days",
470
+ },
471
+ }),
472
+ ),
473
+ ]) as any,
474
+ ).code,
475
+ ).toMatchInlineSnapshot(`"key.deletionWindowInDays;"`);
476
+ });
477
+ });
478
+
479
+ describe("#iteratorVariableToAst", () => {
480
+ async function run(value: string) {
481
+ const scope: ProgramScope = {
482
+ providerSchema: { format_version: "0.1" },
483
+ providerGenerator: {},
484
+ constructs: new Set<string>(),
485
+ variables: {},
486
+ hasTokenBasedTypeCoercion: false,
487
+ nodeIds: [],
488
+ importables: [],
489
+ topLevelConfig: {},
490
+ };
491
+ const ast = await getExpressionAst("main.tf", value);
492
+ return generate(
493
+ t.program([
494
+ t.expressionStatement(
495
+ dynamicVariableToAst(
496
+ scope,
497
+ ast!.children[0] as tex.ScopeTraversalExpression,
498
+ "myIterator",
499
+ ),
500
+ ),
501
+ ]) as any,
502
+ ).code;
503
+ }
504
+
505
+ it("should convert iterator key accessor", async () => {
506
+ expect(await run('"${each.key}"')).toMatchInlineSnapshot(
507
+ `"myIterator.key;"`,
508
+ );
509
+ });
510
+
511
+ it("should convert iterator value accessor", async () => {
512
+ expect(await run('"${each.value}"')).toMatchInlineSnapshot(
513
+ `"myIterator.value;"`,
514
+ );
515
+ });
516
+
517
+ it("should convert iterator value deep accessor", async () => {
518
+ expect(await run('"${each.value.list.map.name}"')).toMatchInlineSnapshot(
519
+ `"Fn.lookupNested(myIterator.value, ["list", "map", "name"]);"`,
520
+ );
521
+ });
522
+
523
+ it("should convert iterator value with map access", async () => {
524
+ expect(
525
+ await run('"${each.value[0]["map"]["name"]}"'),
526
+ ).toMatchInlineSnapshot(
527
+ `"Fn.lookupNested(myIterator.value, ["[0]", "[\\"map\\"]", "[\\"name\\"]"]);"`,
528
+ );
529
+ });
530
+ });
531
+
532
+ describe("#getPropertyAccessPath", () => {
533
+ it.each([
534
+ [".list.map.name", ["list", "map", "name"]],
535
+ [`[0]["map"]["name"]`, ["0", "map", "name"]],
536
+ [`[0].map["name"]`, ["0", "map", "name"]],
537
+ ])("should return the correct path for %s", (input, expected) => {
538
+ expect(getPropertyAccessPath(input)).toEqual(expected);
539
+ });
540
+ });
541
+ });
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Copyright (c) HashiCorp, Inc.
3
+ * SPDX-License-Identifier: MPL-2.0
4
+ */
5
+
6
+ import { convertTerraformExpressionToTs } from "../expressions";
7
+ import { findExpressionType } from "../coerceType";
8
+
9
+ const s3BucketSchema = {
10
+ format_version: "1.0",
11
+ provider_schemas: {
12
+ "registry.terraform.io/hashicorp/aws": {
13
+ provider: {},
14
+ resource_schemas: {
15
+ aws_s3_bucket: {
16
+ version: 0,
17
+ block: {
18
+ attributes: {
19
+ bucket: {
20
+ type: "string",
21
+ description_kind: "plain",
22
+ optional: true,
23
+ computed: true,
24
+ },
25
+ id: {
26
+ type: "string",
27
+ description_kind: "plain",
28
+ optional: true,
29
+ computed: true,
30
+ },
31
+ tags: {
32
+ type: ["map", "string"],
33
+ description_kind: "plain",
34
+ optional: true,
35
+ },
36
+ website_domain: {
37
+ type: "string",
38
+ description_kind: "plain",
39
+ deprecated: true,
40
+ computed: true,
41
+ },
42
+ website_endpoint: {
43
+ type: "string",
44
+ description_kind: "plain",
45
+ deprecated: true,
46
+ computed: true,
47
+ },
48
+ },
49
+ block_types: {
50
+ cors_rule: {
51
+ nesting_mode: "list",
52
+ block: {
53
+ attributes: {
54
+ allowed_headers: {
55
+ type: ["list", "string"],
56
+ description_kind: "plain",
57
+ optional: true,
58
+ },
59
+ },
60
+ description_kind: "plain",
61
+ deprecated: true,
62
+ },
63
+ },
64
+ },
65
+ },
66
+ },
67
+ },
68
+ data_source_schemas: {},
69
+ },
70
+ },
71
+ };
72
+
73
+ const variable = (fullName: string) => {
74
+ const [resource, variableName] = fullName.split(".");
75
+ return {
76
+ [variableName]: {
77
+ resource,
78
+ variableName,
79
+ },
80
+ };
81
+ };
82
+
83
+ const variables = {
84
+ ...variable("var.test"),
85
+ ...variable("aws_s3_bucket.examplebucket"),
86
+ };
87
+
88
+ describe("findExpressionType", () => {
89
+ it.each([
90
+ ['"${each.key}"', "string"],
91
+ ['"${each.value}"', "string"],
92
+ ['"${var.test}"', "dynamic"],
93
+ ['"${var.test}"', "dynamic"],
94
+ ["22", "number"],
95
+ ["true", "bool"],
96
+ ['"hello"', "string"],
97
+ ['"${aws_s3_bucket.examplebucket.bucket}"', "string"],
98
+ ])("finds type for %s as %s", async (input, expected) => {
99
+ const scope = {
100
+ variables,
101
+ providerSchema: s3BucketSchema,
102
+ };
103
+ const ast = await convertTerraformExpressionToTs(
104
+ scope as any,
105
+ input,
106
+ () => "dynamic",
107
+ );
108
+ const result = findExpressionType(scope as any, ast);
109
+
110
+ expect(result).toEqual(expected);
111
+ });
112
+ });