@cdktn/provider-generator 0.24.0-pre.71 → 0.24.0-pre.73

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.
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveStoredClassName = void 0;
4
+ // Copyright (c) HashiCorp, Inc
5
+ // SPDX-License-Identifier: MPL-2.0
6
+ const util_1 = require("../../../util");
7
+ // The core cdktn package (packages/cdktn/src/complex-computed-list.ts) only hand-writes
8
+ // this fixed set of wrapper classes for computed, non-complex collection attributes.
9
+ // Arbitrarily deep nestings of list/set/map (e.g. map(map(list(string)))) compose a
10
+ // storedClassType (e.g. "stringListMapMap") that has no corresponding class. Rather than
11
+ // falling back straight to a plain, untyped getter, resolveStoredClassName below first
12
+ // looks for the nearest typed "Any"-wrapper that still exists in this set, collapsing the
13
+ // unsupported inner shape into an untyped boundary while preserving typed navigation for
14
+ // the outer layers (see https://github.com/open-constructs/cdk-terrain/issues/11).
15
+ const SUPPORTED_STORED_CLASSES = new Set([
16
+ "StringMap",
17
+ "NumberMap",
18
+ "BooleanMap",
19
+ "AnyMap",
20
+ "StringMapMap",
21
+ "NumberMapMap",
22
+ "BooleanMapMap",
23
+ "AnyMapMap",
24
+ "BooleanList",
25
+ "StringListList",
26
+ "NumberListList",
27
+ "BooleanListList",
28
+ "AnyListList",
29
+ "StringMapList",
30
+ "NumberMapList",
31
+ "BooleanMapList",
32
+ "AnyMapList",
33
+ "StringListMap",
34
+ "NumberListMap",
35
+ "BooleanListMap",
36
+ "AnyListMap",
37
+ ]);
38
+ // Resolves the composed stored class name to use for a collection attribute (list/set/map)
39
+ // whose element is itself a non-complex collection (or simple type).
40
+ //
41
+ // `ownStoredClassType` is this type's own composed storedClassType (e.g. "stringListMapMap"
42
+ // for map(map(list(string)))) and `elementTypeModelType` is the element's typeModelType
43
+ // ("list" | "set" | "map" | "simple" | ...).
44
+ //
45
+ // Resolution order:
46
+ // 1. The own composed name (e.g. "StringListMapMap") - used as-is when it refers to a
47
+ // class that is hand-written in the core package (not collapsed).
48
+ // 2. Otherwise, the nearest typed "Any"-wrapper that still encodes the outer two layers
49
+ // (this type's own layer and its element's layer), e.g. "AnyMapMap" - collapsing the
50
+ // unsupported inner shape into an untyped boundary while preserving typed navigation
51
+ // for the outer layers.
52
+ // 3. Otherwise (defensively; every depth should resolve via 1 or 2), undefined - the
53
+ // caller must fall back to a plain, untyped getter.
54
+ function resolveStoredClassName(ownStoredClassType, elementTypeModelType) {
55
+ const candidate1 = (0, util_1.uppercaseFirst)(ownStoredClassType);
56
+ if (SUPPORTED_STORED_CLASSES.has(candidate1)) {
57
+ return { name: candidate1, collapsed: false };
58
+ }
59
+ let ownLayer;
60
+ if (ownStoredClassType.endsWith("List")) {
61
+ ownLayer = "List";
62
+ }
63
+ else if (ownStoredClassType.endsWith("Map")) {
64
+ ownLayer = "Map";
65
+ }
66
+ if (!ownLayer) {
67
+ return undefined;
68
+ }
69
+ let innerLayer;
70
+ if (elementTypeModelType === "list" || elementTypeModelType === "set") {
71
+ innerLayer = "List";
72
+ }
73
+ else if (elementTypeModelType === "map") {
74
+ innerLayer = "Map";
75
+ }
76
+ if (!innerLayer) {
77
+ return undefined;
78
+ }
79
+ const candidate2 = `Any${innerLayer}${ownLayer}`;
80
+ if (SUPPORTED_STORED_CLASSES.has(candidate2)) {
81
+ return { name: candidate2, collapsed: true };
82
+ }
83
+ return undefined;
84
+ }
85
+ exports.resolveStoredClassName = resolveStoredClassName;
86
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VwcG9ydGVkLXN0b3JlZC1jbGFzc2VzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2dldC9nZW5lcmF0b3IvbW9kZWxzL3N1cHBvcnRlZC1zdG9yZWQtY2xhc3Nlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsbUNBQW1DO0FBQ25DLHdDQUErQztBQUUvQyx3RkFBd0Y7QUFDeEYscUZBQXFGO0FBQ3JGLG9GQUFvRjtBQUNwRix5RkFBeUY7QUFDekYsdUZBQXVGO0FBQ3ZGLDBGQUEwRjtBQUMxRix5RkFBeUY7QUFDekYsbUZBQW1GO0FBQ25GLE1BQU0sd0JBQXdCLEdBQUcsSUFBSSxHQUFHLENBQUM7SUFDdkMsV0FBVztJQUNYLFdBQVc7SUFDWCxZQUFZO0lBQ1osUUFBUTtJQUNSLGNBQWM7SUFDZCxjQUFjO0lBQ2QsZUFBZTtJQUNmLFdBQVc7SUFDWCxhQUFhO0lBQ2IsZ0JBQWdCO0lBQ2hCLGdCQUFnQjtJQUNoQixpQkFBaUI7SUFDakIsYUFBYTtJQUNiLGVBQWU7SUFDZixlQUFlO0lBQ2YsZ0JBQWdCO0lBQ2hCLFlBQVk7SUFDWixlQUFlO0lBQ2YsZUFBZTtJQUNmLGdCQUFnQjtJQUNoQixZQUFZO0NBQ2IsQ0FBQyxDQUFDO0FBRUgsMkZBQTJGO0FBQzNGLHFFQUFxRTtBQUNyRSxFQUFFO0FBQ0YsNEZBQTRGO0FBQzVGLHdGQUF3RjtBQUN4Riw2Q0FBNkM7QUFDN0MsRUFBRTtBQUNGLG9CQUFvQjtBQUNwQix3RkFBd0Y7QUFDeEYsdUVBQXVFO0FBQ3ZFLDBGQUEwRjtBQUMxRiwwRkFBMEY7QUFDMUYsMEZBQTBGO0FBQzFGLDZCQUE2QjtBQUM3Qix1RkFBdUY7QUFDdkYseURBQXlEO0FBQ3pELFNBQWdCLHNCQUFzQixDQUNwQyxrQkFBMEIsRUFDMUIsb0JBQTRCO0lBRTVCLE1BQU0sVUFBVSxHQUFHLElBQUEscUJBQWMsRUFBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ3RELElBQUksd0JBQXdCLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDN0MsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDO0lBQ2hELENBQUM7SUFFRCxJQUFJLFFBQW9DLENBQUM7SUFDekMsSUFBSSxrQkFBa0IsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztRQUN4QyxRQUFRLEdBQUcsTUFBTSxDQUFDO0lBQ3BCLENBQUM7U0FBTSxJQUFJLGtCQUFrQixDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzlDLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDbkIsQ0FBQztJQUNELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNkLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRCxJQUFJLFVBQXNDLENBQUM7SUFDM0MsSUFBSSxvQkFBb0IsS0FBSyxNQUFNLElBQUksb0JBQW9CLEtBQUssS0FBSyxFQUFFLENBQUM7UUFDdEUsVUFBVSxHQUFHLE1BQU0sQ0FBQztJQUN0QixDQUFDO1NBQU0sSUFBSSxvQkFBb0IsS0FBSyxLQUFLLEVBQUUsQ0FBQztRQUMxQyxVQUFVLEdBQUcsS0FBSyxDQUFDO0lBQ3JCLENBQUM7SUFDRCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEIsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUVELE1BQU0sVUFBVSxHQUFHLE1BQU0sVUFBVSxHQUFHLFFBQVEsRUFBRSxDQUFDO0lBQ2pELElBQUksd0JBQXdCLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDN0MsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDO0lBQy9DLENBQUM7SUFFRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBbkNELHdEQW1DQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgSGFzaGlDb3JwLCBJbmNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNUEwtMi4wXG5pbXBvcnQgeyB1cHBlcmNhc2VGaXJzdCB9IGZyb20gXCIuLi8uLi8uLi91dGlsXCI7XG5cbi8vIFRoZSBjb3JlIGNka3RuIHBhY2thZ2UgKHBhY2thZ2VzL2Nka3RuL3NyYy9jb21wbGV4LWNvbXB1dGVkLWxpc3QudHMpIG9ubHkgaGFuZC13cml0ZXNcbi8vIHRoaXMgZml4ZWQgc2V0IG9mIHdyYXBwZXIgY2xhc3NlcyBmb3IgY29tcHV0ZWQsIG5vbi1jb21wbGV4IGNvbGxlY3Rpb24gYXR0cmlidXRlcy5cbi8vIEFyYml0cmFyaWx5IGRlZXAgbmVzdGluZ3Mgb2YgbGlzdC9zZXQvbWFwIChlLmcuIG1hcChtYXAobGlzdChzdHJpbmcpKSkpIGNvbXBvc2UgYVxuLy8gc3RvcmVkQ2xhc3NUeXBlIChlLmcuIFwic3RyaW5nTGlzdE1hcE1hcFwiKSB0aGF0IGhhcyBubyBjb3JyZXNwb25kaW5nIGNsYXNzLiBSYXRoZXIgdGhhblxuLy8gZmFsbGluZyBiYWNrIHN0cmFpZ2h0IHRvIGEgcGxhaW4sIHVudHlwZWQgZ2V0dGVyLCByZXNvbHZlU3RvcmVkQ2xhc3NOYW1lIGJlbG93IGZpcnN0XG4vLyBsb29rcyBmb3IgdGhlIG5lYXJlc3QgdHlwZWQgXCJBbnlcIi13cmFwcGVyIHRoYXQgc3RpbGwgZXhpc3RzIGluIHRoaXMgc2V0LCBjb2xsYXBzaW5nIHRoZVxuLy8gdW5zdXBwb3J0ZWQgaW5uZXIgc2hhcGUgaW50byBhbiB1bnR5cGVkIGJvdW5kYXJ5IHdoaWxlIHByZXNlcnZpbmcgdHlwZWQgbmF2aWdhdGlvbiBmb3Jcbi8vIHRoZSBvdXRlciBsYXllcnMgKHNlZSBodHRwczovL2dpdGh1Yi5jb20vb3Blbi1jb25zdHJ1Y3RzL2Nkay10ZXJyYWluL2lzc3Vlcy8xMSkuXG5jb25zdCBTVVBQT1JURURfU1RPUkVEX0NMQVNTRVMgPSBuZXcgU2V0KFtcbiAgXCJTdHJpbmdNYXBcIixcbiAgXCJOdW1iZXJNYXBcIixcbiAgXCJCb29sZWFuTWFwXCIsXG4gIFwiQW55TWFwXCIsXG4gIFwiU3RyaW5nTWFwTWFwXCIsXG4gIFwiTnVtYmVyTWFwTWFwXCIsXG4gIFwiQm9vbGVhbk1hcE1hcFwiLFxuICBcIkFueU1hcE1hcFwiLFxuICBcIkJvb2xlYW5MaXN0XCIsXG4gIFwiU3RyaW5nTGlzdExpc3RcIixcbiAgXCJOdW1iZXJMaXN0TGlzdFwiLFxuICBcIkJvb2xlYW5MaXN0TGlzdFwiLFxuICBcIkFueUxpc3RMaXN0XCIsXG4gIFwiU3RyaW5nTWFwTGlzdFwiLFxuICBcIk51bWJlck1hcExpc3RcIixcbiAgXCJCb29sZWFuTWFwTGlzdFwiLFxuICBcIkFueU1hcExpc3RcIixcbiAgXCJTdHJpbmdMaXN0TWFwXCIsXG4gIFwiTnVtYmVyTGlzdE1hcFwiLFxuICBcIkJvb2xlYW5MaXN0TWFwXCIsXG4gIFwiQW55TGlzdE1hcFwiLFxuXSk7XG5cbi8vIFJlc29sdmVzIHRoZSBjb21wb3NlZCBzdG9yZWQgY2xhc3MgbmFtZSB0byB1c2UgZm9yIGEgY29sbGVjdGlvbiBhdHRyaWJ1dGUgKGxpc3Qvc2V0L21hcClcbi8vIHdob3NlIGVsZW1lbnQgaXMgaXRzZWxmIGEgbm9uLWNvbXBsZXggY29sbGVjdGlvbiAob3Igc2ltcGxlIHR5cGUpLlxuLy9cbi8vIGBvd25TdG9yZWRDbGFzc1R5cGVgIGlzIHRoaXMgdHlwZSdzIG93biBjb21wb3NlZCBzdG9yZWRDbGFzc1R5cGUgKGUuZy4gXCJzdHJpbmdMaXN0TWFwTWFwXCJcbi8vIGZvciBtYXAobWFwKGxpc3Qoc3RyaW5nKSkpKSBhbmQgYGVsZW1lbnRUeXBlTW9kZWxUeXBlYCBpcyB0aGUgZWxlbWVudCdzIHR5cGVNb2RlbFR5cGVcbi8vIChcImxpc3RcIiB8IFwic2V0XCIgfCBcIm1hcFwiIHwgXCJzaW1wbGVcIiB8IC4uLikuXG4vL1xuLy8gUmVzb2x1dGlvbiBvcmRlcjpcbi8vICAgMS4gVGhlIG93biBjb21wb3NlZCBuYW1lIChlLmcuIFwiU3RyaW5nTGlzdE1hcE1hcFwiKSAtIHVzZWQgYXMtaXMgd2hlbiBpdCByZWZlcnMgdG8gYVxuLy8gICAgICBjbGFzcyB0aGF0IGlzIGhhbmQtd3JpdHRlbiBpbiB0aGUgY29yZSBwYWNrYWdlIChub3QgY29sbGFwc2VkKS5cbi8vICAgMi4gT3RoZXJ3aXNlLCB0aGUgbmVhcmVzdCB0eXBlZCBcIkFueVwiLXdyYXBwZXIgdGhhdCBzdGlsbCBlbmNvZGVzIHRoZSBvdXRlciB0d28gbGF5ZXJzXG4vLyAgICAgICh0aGlzIHR5cGUncyBvd24gbGF5ZXIgYW5kIGl0cyBlbGVtZW50J3MgbGF5ZXIpLCBlLmcuIFwiQW55TWFwTWFwXCIgLSBjb2xsYXBzaW5nIHRoZVxuLy8gICAgICB1bnN1cHBvcnRlZCBpbm5lciBzaGFwZSBpbnRvIGFuIHVudHlwZWQgYm91bmRhcnkgd2hpbGUgcHJlc2VydmluZyB0eXBlZCBuYXZpZ2F0aW9uXG4vLyAgICAgIGZvciB0aGUgb3V0ZXIgbGF5ZXJzLlxuLy8gICAzLiBPdGhlcndpc2UgKGRlZmVuc2l2ZWx5OyBldmVyeSBkZXB0aCBzaG91bGQgcmVzb2x2ZSB2aWEgMSBvciAyKSwgdW5kZWZpbmVkIC0gdGhlXG4vLyAgICAgIGNhbGxlciBtdXN0IGZhbGwgYmFjayB0byBhIHBsYWluLCB1bnR5cGVkIGdldHRlci5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlU3RvcmVkQ2xhc3NOYW1lKFxuICBvd25TdG9yZWRDbGFzc1R5cGU6IHN0cmluZyxcbiAgZWxlbWVudFR5cGVNb2RlbFR5cGU6IHN0cmluZyxcbik6IHsgbmFtZTogc3RyaW5nOyBjb2xsYXBzZWQ6IGJvb2xlYW4gfSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGNhbmRpZGF0ZTEgPSB1cHBlcmNhc2VGaXJzdChvd25TdG9yZWRDbGFzc1R5cGUpO1xuICBpZiAoU1VQUE9SVEVEX1NUT1JFRF9DTEFTU0VTLmhhcyhjYW5kaWRhdGUxKSkge1xuICAgIHJldHVybiB7IG5hbWU6IGNhbmRpZGF0ZTEsIGNvbGxhcHNlZDogZmFsc2UgfTtcbiAgfVxuXG4gIGxldCBvd25MYXllcjogXCJMaXN0XCIgfCBcIk1hcFwiIHwgdW5kZWZpbmVkO1xuICBpZiAob3duU3RvcmVkQ2xhc3NUeXBlLmVuZHNXaXRoKFwiTGlzdFwiKSkge1xuICAgIG93bkxheWVyID0gXCJMaXN0XCI7XG4gIH0gZWxzZSBpZiAob3duU3RvcmVkQ2xhc3NUeXBlLmVuZHNXaXRoKFwiTWFwXCIpKSB7XG4gICAgb3duTGF5ZXIgPSBcIk1hcFwiO1xuICB9XG4gIGlmICghb3duTGF5ZXIpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgbGV0IGlubmVyTGF5ZXI6IFwiTGlzdFwiIHwgXCJNYXBcIiB8IHVuZGVmaW5lZDtcbiAgaWYgKGVsZW1lbnRUeXBlTW9kZWxUeXBlID09PSBcImxpc3RcIiB8fCBlbGVtZW50VHlwZU1vZGVsVHlwZSA9PT0gXCJzZXRcIikge1xuICAgIGlubmVyTGF5ZXIgPSBcIkxpc3RcIjtcbiAgfSBlbHNlIGlmIChlbGVtZW50VHlwZU1vZGVsVHlwZSA9PT0gXCJtYXBcIikge1xuICAgIGlubmVyTGF5ZXIgPSBcIk1hcFwiO1xuICB9XG4gIGlmICghaW5uZXJMYXllcikge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBjYW5kaWRhdGUyID0gYEFueSR7aW5uZXJMYXllcn0ke293bkxheWVyfWA7XG4gIGlmIChTVVBQT1JURURfU1RPUkVEX0NMQVNTRVMuaGFzKGNhbmRpZGF0ZTIpKSB7XG4gICAgcmV0dXJuIHsgbmFtZTogY2FuZGlkYXRlMiwgY29sbGFwc2VkOiB0cnVlIH07XG4gIH1cblxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuIl19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdktn/provider-generator",
3
- "version": "0.24.0-pre.71",
3
+ "version": "0.24.0-pre.73",
4
4
  "description": "Exposes API to generate Terraform CDK provider bindings",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -32,12 +32,12 @@
32
32
  "codemaker": "1.128.0",
33
33
  "constructs": "10.6.0",
34
34
  "fs-extra": "8.1.0",
35
- "glob": "10.5.0",
35
+ "glob": "13.0.6",
36
36
  "jsii": "~5.9.0",
37
37
  "jsii-pacmak": "1.128.0",
38
- "@cdktn/commons": "0.24.0-pre.71",
39
- "@cdktn/provider-schema": "0.24.0-pre.71",
40
- "cdktn": "0.24.0-pre.71"
38
+ "@cdktn/commons": "0.24.0-pre.73",
39
+ "@cdktn/provider-schema": "0.24.0-pre.73",
40
+ "cdktn": "0.24.0-pre.73"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/fs-extra": "8.1.5",
@@ -2172,6 +2172,155 @@ export class ComputedOptionalComplex extends cdktn.TerraformResource {
2172
2172
  "
2173
2173
  `;
2174
2174
 
2175
+ exports[`deeply nested (unsupported) collection attribute types 1`] = `
2176
+ "// https://registry.terraform.io/providers/hashicorp/test/latest/docs/data-sources/deeply_nested_collections
2177
+ // generated from terraform resource schema
2178
+
2179
+ import { Construct } from 'constructs';
2180
+ import * as cdktn from 'cdktn';
2181
+
2182
+ // Configuration
2183
+
2184
+ export interface DataDeeplyNestedCollectionsConfig extends cdktn.TerraformMetaArguments {
2185
+ }
2186
+
2187
+ /**
2188
+ * Represents a {@link https://registry.terraform.io/providers/hashicorp/test/latest/docs/data-sources/deeply_nested_collections deeply_nested_collections}
2189
+ */
2190
+ export class DataDeeplyNestedCollections extends cdktn.TerraformDataSource {
2191
+
2192
+ // =================
2193
+ // STATIC PROPERTIES
2194
+ // =================
2195
+ public static readonly tfResourceType = "deeply_nested_collections";
2196
+
2197
+ // ==============
2198
+ // STATIC Methods
2199
+ // ==============
2200
+ /**
2201
+ * Generates CDKTN code for importing a DataDeeplyNestedCollections resource upon running "cdktn plan <stack-name>"
2202
+ * @param scope The scope in which to define this construct
2203
+ * @param importToId The construct id used in the generated config for the DataDeeplyNestedCollections to import
2204
+ * @param importFromId The id of the existing DataDeeplyNestedCollections that should be imported. Refer to the {@link https://registry.terraform.io/providers/hashicorp/test/latest/docs/data-sources/deeply_nested_collections#import import section} in the documentation of this resource for the id to use
2205
+ * @param provider? Optional instance of the provider where the DataDeeplyNestedCollections to import is found
2206
+ */
2207
+ public static generateConfigForImport(scope: Construct, importToId: string, importFromId: string, provider?: cdktn.TerraformProvider) {
2208
+ return new cdktn.ImportableResource(scope, importToId, { terraformResourceType: "deeply_nested_collections", importId: importFromId, provider });
2209
+ }
2210
+
2211
+ // ===========
2212
+ // INITIALIZER
2213
+ // ===========
2214
+
2215
+ /**
2216
+ * Create a new {@link https://registry.terraform.io/providers/hashicorp/test/latest/docs/data-sources/deeply_nested_collections deeply_nested_collections} Data Source
2217
+ *
2218
+ * @param scope The scope in which to define this construct
2219
+ * @param id The scoped construct ID. Must be unique amongst siblings in the same scope
2220
+ * @param options DataDeeplyNestedCollectionsConfig = {}
2221
+ */
2222
+ public constructor(scope: Construct, id: string, config: DataDeeplyNestedCollectionsConfig = {}) {
2223
+ super(scope, id, {
2224
+ terraformResourceType: 'deeply_nested_collections',
2225
+ terraformGeneratorMetadata: {
2226
+ providerName: 'test'
2227
+ },
2228
+ provider: config.provider,
2229
+ dependsOn: config.dependsOn,
2230
+ count: config.count,
2231
+ lifecycle: config.lifecycle,
2232
+ provisioners: config.provisioners,
2233
+ connection: config.connection,
2234
+ forEach: config.forEach
2235
+ });
2236
+ }
2237
+
2238
+ // ==========
2239
+ // ATTRIBUTES
2240
+ // ==========
2241
+
2242
+ // map_map_list_string - computed: true, optional: false, required: false
2243
+ private _mapMapListString = new cdktn.AnyMapMap(this, "map_map_list_string");
2244
+ /**
2245
+ * Terraform type: \`map(map(list(string)))\`.
2246
+ * This nesting is deeper than the typed wrapper classes in the core cdktn package; it is exposed as \`AnyMapMap\` and values below that boundary are untyped tokens.
2247
+ */
2248
+ public get mapMapListString() {
2249
+ return this._mapMapListString;
2250
+ }
2251
+
2252
+ // list_map_map_string - computed: true, optional: false, required: false
2253
+ private _listMapMapString = new cdktn.AnyMapList(this, "list_map_map_string", false);
2254
+ /**
2255
+ * Terraform type: \`list(map(map(string)))\`.
2256
+ * This nesting is deeper than the typed wrapper classes in the core cdktn package; it is exposed as \`AnyMapList\` and values below that boundary are untyped tokens.
2257
+ */
2258
+ public get listMapMapString() {
2259
+ return this._listMapMapString;
2260
+ }
2261
+
2262
+ // set_map_list_number - computed: true, optional: false, required: false
2263
+ private _setMapListNumber = new cdktn.AnyMapList(this, "set_map_list_number", true);
2264
+ /**
2265
+ * Terraform type: \`set(map(list(number)))\`.
2266
+ * This nesting is deeper than the typed wrapper classes in the core cdktn package; it is exposed as \`AnyMapList\` and values below that boundary are untyped tokens.
2267
+ */
2268
+ public get setMapListNumber() {
2269
+ return this._setMapListNumber;
2270
+ }
2271
+
2272
+ // map_list_string - computed: true, optional: false, required: false
2273
+ private _mapListString = new cdktn.StringListMap(this, "map_list_string");
2274
+ public get mapListString() {
2275
+ return this._mapListString;
2276
+ }
2277
+
2278
+ // map_map_number - computed: true, optional: false, required: false
2279
+ private _mapMapNumber = new cdktn.NumberMapMap(this, "map_map_number");
2280
+ public get mapMapNumber() {
2281
+ return this._mapMapNumber;
2282
+ }
2283
+
2284
+ // map_map_bool - computed: true, optional: false, required: false
2285
+ private _mapMapBool = new cdktn.BooleanMapMap(this, "map_map_bool");
2286
+ public get mapMapBool() {
2287
+ return this._mapMapBool;
2288
+ }
2289
+
2290
+ // map_map_string - computed: true, optional: false, required: false
2291
+ private _mapMapString = new cdktn.StringMapMap(this, "map_map_string");
2292
+ public get mapMapString() {
2293
+ return this._mapMapString;
2294
+ }
2295
+
2296
+ // map_map_map_list_string - computed: true, optional: false, required: false
2297
+ private _mapMapMapListString = new cdktn.AnyMapMap(this, "map_map_map_list_string");
2298
+ /**
2299
+ * Terraform type: \`map(map(map(list(string))))\`.
2300
+ * This nesting is deeper than the typed wrapper classes in the core cdktn package; it is exposed as \`AnyMapMap\` and values below that boundary are untyped tokens.
2301
+ */
2302
+ public get mapMapMapListString() {
2303
+ return this._mapMapMapListString;
2304
+ }
2305
+
2306
+ // =========
2307
+ // SYNTHESIS
2308
+ // =========
2309
+
2310
+ protected synthesizeAttributes(): { [name: string]: any } {
2311
+ return {
2312
+ };
2313
+ }
2314
+
2315
+ protected synthesizeHclAttributes(): { [name: string]: any } {
2316
+ const attrs = {
2317
+ };
2318
+ return attrs;
2319
+ }
2320
+ }
2321
+ "
2322
+ `;
2323
+
2175
2324
  exports[`deeply nested block types 1`] = `
2176
2325
  "// https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/deeply_nested_block_types
2177
2326
  // generated from terraform resource schema
@@ -0,0 +1,129 @@
1
+ {
2
+ "format_version": "1.0",
3
+ "provider_schemas": {
4
+ "registry.terraform.io/hashicorp/test": {
5
+ "data_source_schemas": {
6
+ "deeply_nested_collections": {
7
+ "version": 0,
8
+ "block": {
9
+ "attributes": {
10
+ "map_map_list_string": {
11
+ "type": [
12
+ "map",
13
+ [
14
+ "map",
15
+ [
16
+ "list",
17
+ "string"
18
+ ]
19
+ ]
20
+ ],
21
+ "description": "map(map(list(string))) - unsupported triple nesting, reproduces open-constructs/cdk-terrain#11.",
22
+ "description_kind": "plain",
23
+ "computed": true
24
+ },
25
+ "list_map_map_string": {
26
+ "type": [
27
+ "list",
28
+ [
29
+ "map",
30
+ [
31
+ "map",
32
+ "string"
33
+ ]
34
+ ]
35
+ ],
36
+ "description": "list(map(map(string))) - unsupported triple nesting.",
37
+ "description_kind": "plain",
38
+ "computed": true
39
+ },
40
+ "set_map_list_number": {
41
+ "type": [
42
+ "set",
43
+ [
44
+ "map",
45
+ [
46
+ "list",
47
+ "number"
48
+ ]
49
+ ]
50
+ ],
51
+ "description": "set(map(list(number))) - unsupported triple nesting.",
52
+ "description_kind": "plain",
53
+ "computed": true
54
+ },
55
+ "map_list_string": {
56
+ "type": [
57
+ "map",
58
+ [
59
+ "list",
60
+ "string"
61
+ ]
62
+ ],
63
+ "description": "map(list(string)) - supported double nesting, must still emit cdktn.StringListMap.",
64
+ "description_kind": "plain",
65
+ "computed": true
66
+ },
67
+ "map_map_number": {
68
+ "type": [
69
+ "map",
70
+ [
71
+ "map",
72
+ "number"
73
+ ]
74
+ ],
75
+ "description": "map(map(number)) - now directly supported via cdktn.NumberMapMap.",
76
+ "description_kind": "plain",
77
+ "computed": true
78
+ },
79
+ "map_map_bool": {
80
+ "type": [
81
+ "map",
82
+ [
83
+ "map",
84
+ "bool"
85
+ ]
86
+ ],
87
+ "description": "map(map(bool)) - now directly supported via cdktn.BooleanMapMap.",
88
+ "description_kind": "plain",
89
+ "computed": true
90
+ },
91
+ "map_map_string": {
92
+ "type": [
93
+ "map",
94
+ [
95
+ "map",
96
+ "string"
97
+ ]
98
+ ],
99
+ "description": "map(map(string)) - pre-existing support via cdktn.StringMapMap, unchanged.",
100
+ "description_kind": "plain",
101
+ "computed": true
102
+ },
103
+ "map_map_map_list_string": {
104
+ "type": [
105
+ "map",
106
+ [
107
+ "map",
108
+ [
109
+ "map",
110
+ [
111
+ "list",
112
+ "string"
113
+ ]
114
+ ]
115
+ ]
116
+ ],
117
+ "description": "map(map(map(list(string)))) - unsupported quadruple nesting, collapses to cdktn.AnyMapMap.",
118
+ "description_kind": "plain",
119
+ "computed": true
120
+ }
121
+ },
122
+ "description": "Data source used to verify deeply nested collection attribute types are handled without generating references to non-existent cdktn classes.",
123
+ "description_kind": "plain"
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
@@ -0,0 +1,147 @@
1
+ // Copyright (c) HashiCorp, Inc
2
+ // SPDX-License-Identifier: MPL-2.0
3
+ import { logger } from "@cdktn/commons";
4
+ import { resolveStoredClassName } from "../../generator/models/supported-stored-classes";
5
+ import {
6
+ AttributeModel,
7
+ AttributeTypeModel,
8
+ MapAttributeTypeModel,
9
+ } from "../../generator/models";
10
+
11
+ describe("resolveStoredClassName", () => {
12
+ test("own composed name resolves as-is when supported (not collapsed)", () => {
13
+ expect(resolveStoredClassName("stringListMap", "list")).toEqual({
14
+ name: "StringListMap",
15
+ collapsed: false,
16
+ });
17
+ expect(resolveStoredClassName("stringMapMap", "map")).toEqual({
18
+ name: "StringMapMap",
19
+ collapsed: false,
20
+ });
21
+ expect(resolveStoredClassName("numberMapMap", "map")).toEqual({
22
+ name: "NumberMapMap",
23
+ collapsed: false,
24
+ });
25
+ expect(resolveStoredClassName("booleanMapMap", "map")).toEqual({
26
+ name: "BooleanMapMap",
27
+ collapsed: false,
28
+ });
29
+ });
30
+
31
+ test("unsupported own composed name collapses to nearest Any-wrapper", () => {
32
+ // map(map(list(string))) - own "stringListMapMap" unsupported, element is a map
33
+ expect(resolveStoredClassName("stringListMapMap", "map")).toEqual({
34
+ name: "AnyMapMap",
35
+ collapsed: true,
36
+ });
37
+ // list(map(map(string))) - own "stringMapMapList" unsupported, element is a map
38
+ expect(resolveStoredClassName("stringMapMapList", "map")).toEqual({
39
+ name: "AnyMapList",
40
+ collapsed: true,
41
+ });
42
+ // set(map(list(number))) - own "numberListMapList" unsupported, element is a map
43
+ expect(resolveStoredClassName("numberListMapList", "map")).toEqual({
44
+ name: "AnyMapList",
45
+ collapsed: true,
46
+ });
47
+ // map(map(map(list(string)))) - own "stringListMapMapMap" unsupported, element is a map
48
+ expect(resolveStoredClassName("stringListMapMapMap", "map")).toEqual({
49
+ name: "AnyMapMap",
50
+ collapsed: true,
51
+ });
52
+ });
53
+
54
+ test("returns undefined when neither the own name nor a collapsed Any-wrapper exists", () => {
55
+ // Own name doesn't end in List/Map at all.
56
+ expect(resolveStoredClassName("somethingWeird", "map")).toBeUndefined();
57
+ // Own name ends in Map, but the element isn't itself a list/set/map, so there is no
58
+ // "AnyXMap" candidate to fall back to.
59
+ expect(resolveStoredClassName("weirdMap", "struct")).toBeUndefined();
60
+ expect(resolveStoredClassName("weirdMap", "simple")).toBeUndefined();
61
+ });
62
+ });
63
+
64
+ // A minimal stand-in for a non-complex, non-collection AttributeTypeModel whose
65
+ // typeModelType is neither "list", "set", "map", nor "simple"/"struct" - i.e. a shape the
66
+ // generator's collapse logic has no candidate class name for. Used to exercise the
67
+ // defensive plain-getter fallback in AttributeModel.getterType without needing a real
68
+ // (currently nonexistent) unsupported shape.
69
+ class UnresolvableStubTypeModel implements AttributeTypeModel {
70
+ get struct() {
71
+ return undefined;
72
+ }
73
+ get isComplex() {
74
+ return false;
75
+ }
76
+ getStoredClassInitializer(_name: string) {
77
+ return "";
78
+ }
79
+ get storedClassType() {
80
+ return "unresolvable";
81
+ }
82
+ get inputTypeDefinition() {
83
+ return "any";
84
+ }
85
+ getAttributeAccessFunction(name: string) {
86
+ return `this.interpolationForAttribute('${name}')`;
87
+ }
88
+ get toTerraformFunction() {
89
+ return "cdktn.anyToTerraform";
90
+ }
91
+ get toHclTerraformFunction() {
92
+ return "cdktn.anyToHclTerraform";
93
+ }
94
+ get typeModelType() {
95
+ return "unresolvable-shape";
96
+ }
97
+ get hasReferenceClass() {
98
+ return false;
99
+ }
100
+ get isTokenizable() {
101
+ return false;
102
+ }
103
+ get isStoredClassUnavailable() {
104
+ return false;
105
+ }
106
+ }
107
+
108
+ describe("AttributeModel.getterType loud fallback", () => {
109
+ test("falls back to a plain getter and logs a debug breadcrumb when no stored class (not even a collapsed Any-wrapper) is available", () => {
110
+ const debugSpy = jest.spyOn(logger, "debug").mockImplementation();
111
+
112
+ try {
113
+ // A map whose element is itself an unrecognized shape: own composed name
114
+ // ("unresolvableMap") isn't in the supported set, and the element's typeModelType
115
+ // isn't "list"/"set"/"map", so there is no "AnyXMap" candidate either.
116
+ const type = new MapAttributeTypeModel(new UnresolvableStubTypeModel());
117
+ expect(type.isStoredClassUnavailable).toBe(true);
118
+
119
+ const attribute = new AttributeModel({
120
+ storageName: "_weirdAttribute",
121
+ name: "weirdAttribute",
122
+ type,
123
+ optional: false,
124
+ computed: true,
125
+ terraformName: "weird_attribute",
126
+ terraformFullName: "test_resource.weird_attribute",
127
+ provider: false,
128
+ required: false,
129
+ });
130
+
131
+ expect(attribute.getterType).toEqual({ _type: "plain" });
132
+ expect(attribute.storedClassBoundaryKind).toEqual("fallback");
133
+
134
+ expect(debugSpy).toHaveBeenCalledTimes(1);
135
+ const [message] = debugSpy.mock.calls[0];
136
+ expect(message).toContain("test_resource.weird_attribute");
137
+ expect(message).toContain("unresolvableMap");
138
+
139
+ // Repeated access must not spam the logger.
140
+ void attribute.getterType;
141
+ void attribute.getterType;
142
+ expect(debugSpy).toHaveBeenCalledTimes(1);
143
+ } finally {
144
+ debugSpy.mockRestore();
145
+ }
146
+ });
147
+ });
@@ -609,3 +609,78 @@ test("case-insensitive base name collision", async () => {
609
609
  expect(output).toMatchSnapshot(file);
610
610
  }
611
611
  });
612
+
613
+ test("deeply nested (unsupported) collection attribute types", async () => {
614
+ // Regression test for https://github.com/open-constructs/cdk-terrain/issues/11:
615
+ // computed attributes whose type nests list/set/map more than two levels deep (e.g.
616
+ // map(map(list(string)))) must not generate a reference to a "cdktn.*" stored class
617
+ // that doesn't exist (e.g. "StringListMapMap"). Instead of falling straight back to a
618
+ // plain, untyped getter, the generator collapses these into the nearest typed
619
+ // "Any"-wrapper that does exist (e.g. "AnyMapMap"), preserving typed navigation for the
620
+ // outer layers. Only shapes with no available stored class at all fall back to a plain
621
+ // getter.
622
+ const code = new CodeMaker();
623
+ const workdir = tmp("deeply-nested-collections.test");
624
+ const spec = JSON.parse(
625
+ fs.readFileSync(
626
+ path.join(
627
+ __dirname,
628
+ "fixtures",
629
+ "deeply-nested-collections.test.fixture.json",
630
+ ),
631
+ "utf-8",
632
+ ),
633
+ );
634
+ new TerraformProviderGenerator(code, spec).generateAll();
635
+ await code.save(workdir);
636
+
637
+ const output = fs.readFileSync(
638
+ path.join(
639
+ workdir,
640
+ "providers/test/data-deeply-nested-collections/index.ts",
641
+ ),
642
+ "utf-8",
643
+ );
644
+ expect(output).toMatchSnapshot();
645
+
646
+ // None of the unsupported nested attributes should reference a non-existent "cdktn.*"
647
+ // wrapper class.
648
+ expect(output).not.toContain("StringListMapMap");
649
+ expect(output).not.toContain("StringMapMapList");
650
+ expect(output).not.toContain("NumberListMapList");
651
+ expect(output).not.toContain("StringListMapMapMap");
652
+
653
+ // Unsupported triple nestings collapse to the nearest typed "Any"-wrapper instead of
654
+ // falling back to a plain getter.
655
+ expect(output).toContain('new cdktn.AnyMapMap(this, "map_map_list_string")');
656
+ expect(output).toContain(
657
+ 'new cdktn.AnyMapList(this, "list_map_map_string", false)',
658
+ );
659
+ expect(output).toContain(
660
+ 'new cdktn.AnyMapList(this, "set_map_list_number", true)',
661
+ );
662
+ expect(output).toContain(
663
+ 'new cdktn.AnyMapMap(this, "map_map_map_list_string")',
664
+ );
665
+
666
+ // A supported double nesting (map(list(string))) must still emit its stored class.
667
+ expect(output).toContain('new cdktn.StringListMap(this, "map_list_string")');
668
+
669
+ // map(map(number)) / map(map(bool)) are now directly supported by new core classes.
670
+ expect(output).toContain('new cdktn.NumberMapMap(this, "map_map_number")');
671
+ expect(output).toContain('new cdktn.BooleanMapMap(this, "map_map_bool")');
672
+
673
+ // map(map(string)) is pre-existing, unchanged support.
674
+ expect(output).toContain('new cdktn.StringMapMap(this, "map_map_string")');
675
+
676
+ // Collapsed getters get a JSDoc documenting the Terraform type and the collapse
677
+ // boundary.
678
+ expect(output).toContain("Terraform type: `map(map(list(string)))`");
679
+ expect(output).toContain(
680
+ "it is exposed as `AnyMapMap` and values below that boundary are untyped tokens",
681
+ );
682
+
683
+ // Supported, non-collapsed attributes must NOT get this JSDoc (avoids snapshot churn).
684
+ expect(output).not.toContain("Terraform type: `map(list(string))`");
685
+ expect(output).not.toContain("Terraform type: `map(map(string))`");
686
+ });