@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.
- package/LICENSE +355 -0
- package/README.md +1 -1
- package/build/__tests__/expressions.test.js +10 -19
- package/build/__tests__/functions.test.js +8 -18
- package/build/__tests__/testHelpers.js +3 -2
- package/build/coerceType.js +11 -21
- package/build/dynamic-blocks.js +3 -3
- package/build/expressions.js +13 -22
- package/build/function-bindings/functions.generated.js +2 -2
- package/build/generation.js +24 -34
- package/build/index.js +15 -25
- package/build/iteration.js +7 -6
- package/build/jsii-rosetta-workarounds.js +6 -5
- package/build/partialCode.js +11 -20
- package/build/provider.js +4 -3
- package/build/references.js +6 -5
- package/build/schema.js +8 -18
- package/build/terraformSchema.js +4 -4
- package/build/utils.js +3 -3
- package/build/variables.js +12 -21
- package/package.json +20 -17
- package/package.sh +1 -1
- package/src/__tests__/coerceType.test.ts +207 -0
- package/src/__tests__/expressionToTs.test.ts +1167 -0
- package/src/__tests__/expressions.test.ts +541 -0
- package/src/__tests__/findExpressionType.test.ts +112 -0
- package/src/__tests__/functions.test.ts +768 -0
- package/src/__tests__/generation.test.ts +72 -0
- package/src/__tests__/jsii-rosetta-workarounds.test.ts +145 -0
- package/src/__tests__/partialCode.test.ts +432 -0
- package/src/__tests__/terraformSchema.test.ts +107 -0
- package/src/__tests__/testHelpers.ts +11 -0
- package/src/coerceType.ts +261 -0
- package/src/dynamic-blocks.ts +61 -0
- package/src/expressions.ts +968 -0
- package/src/function-bindings/functions.generated.ts +1139 -0
- package/src/function-bindings/functions.ts +104 -0
- package/src/generation.ts +1189 -0
- package/src/index.ts +584 -0
- package/src/iteration.ts +156 -0
- package/src/jsii-rosetta-workarounds.ts +145 -0
- package/src/partialCode.ts +132 -0
- package/src/provider.ts +60 -0
- package/src/references.ts +193 -0
- package/src/schema.ts +74 -0
- package/src/terraformSchema.ts +182 -0
- package/src/types.ts +58 -0
- package/src/utils.ts +19 -0
- package/src/variables.ts +214 -0
- package/test/__snapshots__/backends.test.ts.snap +70 -0
- package/test/__snapshots__/externals.test.ts.snap +37 -0
- package/test/__snapshots__/granular-imports.test.ts.snap +180 -0
- package/test/__snapshots__/imports.test.ts.snap +159 -0
- package/test/__snapshots__/iteration.test.ts.snap +532 -0
- package/test/__snapshots__/jsiiLanguage.test.ts.snap +347 -0
- package/test/__snapshots__/locals.test.ts.snap +55 -0
- package/test/__snapshots__/modules.test.ts.snap +127 -0
- package/test/__snapshots__/outputs.test.ts.snap +77 -0
- package/test/__snapshots__/partialCode.test.ts.snap +120 -0
- package/test/__snapshots__/provider.test.ts.snap +128 -0
- package/test/__snapshots__/references.test.ts.snap +376 -0
- package/test/__snapshots__/resource-meta-properties.test.ts.snap +342 -0
- package/test/__snapshots__/resources.test.ts.snap +613 -0
- package/test/__snapshots__/tfExpressions.test.ts.snap +537 -0
- package/test/__snapshots__/typeCoercion.test.ts.snap +253 -0
- package/test/__snapshots__/variables.test.ts.snap +150 -0
- package/test/backends.test.ts +75 -0
- package/test/convertProject.test.ts +257 -0
- package/test/externals.test.ts +35 -0
- package/test/globalSetup.ts +224 -0
- package/test/globalTeardown.ts +11 -0
- package/test/granular-imports.test.ts +161 -0
- package/test/hcl2cdk.test.ts +88 -0
- package/test/helpers/convert.ts +543 -0
- package/test/helpers/tmp.ts +25 -0
- package/test/imports.test.ts +141 -0
- package/test/iteration.test.ts +342 -0
- package/test/jsiiLanguage.test.ts +73 -0
- package/test/locals.test.ts +47 -0
- package/test/modules.test.ts +143 -0
- package/test/outputs.test.ts +69 -0
- package/test/partialCode.test.ts +25 -0
- package/test/provider.test.ts +106 -0
- package/test/references.test.ts +287 -0
- package/test/resource-meta-properties.test.ts +288 -0
- package/test/resources.test.ts +551 -0
- package/test/tfExpressions.test.ts +300 -0
- package/test/typeCoercion.test.ts +154 -0
- package/test/variables.test.ts +96 -0
package/src/schema.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import * as z from "zod";
|
|
4
|
+
|
|
5
|
+
const tfObject = <T extends z.ZodRawShape>(config: T) =>
|
|
6
|
+
z.array(z.object(config).partial());
|
|
7
|
+
|
|
8
|
+
const outputConfig = tfObject({
|
|
9
|
+
value: z.any(),
|
|
10
|
+
description: z.string().optional(),
|
|
11
|
+
sensitive: z.boolean().optional(),
|
|
12
|
+
depends_on: z.string().optional(),
|
|
13
|
+
});
|
|
14
|
+
export type Output = z.infer<typeof outputConfig>;
|
|
15
|
+
|
|
16
|
+
const validationConfig = z.object({
|
|
17
|
+
error_message: z.string(),
|
|
18
|
+
condition: z.any(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const variableConfig = tfObject({
|
|
22
|
+
type: z.string(),
|
|
23
|
+
default: z.any(),
|
|
24
|
+
description: z.string(),
|
|
25
|
+
sensitive: z.boolean(),
|
|
26
|
+
nullable: z.boolean().optional(),
|
|
27
|
+
validation: z.array(validationConfig).optional(),
|
|
28
|
+
});
|
|
29
|
+
export type Variable = z.infer<typeof variableConfig>;
|
|
30
|
+
|
|
31
|
+
const providerConfig = z.array(z.record(z.any()));
|
|
32
|
+
export type Provider = z.infer<typeof providerConfig>;
|
|
33
|
+
|
|
34
|
+
const moduleConfig = z.array(z.object({ source: z.string() }).nonstrict());
|
|
35
|
+
export type Module = z.infer<typeof moduleConfig>;
|
|
36
|
+
|
|
37
|
+
const resourceConfig = z.array(z.record(z.any()));
|
|
38
|
+
export type Resource = z.infer<typeof resourceConfig>;
|
|
39
|
+
export type Data = Resource;
|
|
40
|
+
|
|
41
|
+
const importConfig = z.object({
|
|
42
|
+
to: z.string(),
|
|
43
|
+
id: z.string(),
|
|
44
|
+
provider: z.any().optional(),
|
|
45
|
+
});
|
|
46
|
+
export type Import = z.infer<typeof importConfig>;
|
|
47
|
+
|
|
48
|
+
const providerSpecification = z.union([
|
|
49
|
+
z.object({ source: z.string(), version: z.string() }).partial(),
|
|
50
|
+
z.string(),
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
const terraformConfig = z
|
|
54
|
+
.object({
|
|
55
|
+
required_version: z.string(),
|
|
56
|
+
required_providers: z.array(z.record(providerSpecification)),
|
|
57
|
+
backend: z.record(z.array(z.record(z.any()))),
|
|
58
|
+
})
|
|
59
|
+
.partial();
|
|
60
|
+
export type TerraformConfig = z.infer<typeof terraformConfig>;
|
|
61
|
+
|
|
62
|
+
export const schema = z
|
|
63
|
+
.object({
|
|
64
|
+
data: z.record(z.record(resourceConfig)),
|
|
65
|
+
import: z.array(importConfig),
|
|
66
|
+
locals: z.array(z.record(z.any())),
|
|
67
|
+
module: z.record(moduleConfig),
|
|
68
|
+
output: z.record(outputConfig),
|
|
69
|
+
provider: z.record(providerConfig),
|
|
70
|
+
resource: z.record(z.record(resourceConfig)),
|
|
71
|
+
terraform: z.array(terraformConfig),
|
|
72
|
+
variable: z.record(variableConfig),
|
|
73
|
+
})
|
|
74
|
+
.partial();
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import {
|
|
4
|
+
ProviderSchema,
|
|
5
|
+
BlockType,
|
|
6
|
+
AttributeType,
|
|
7
|
+
Schema,
|
|
8
|
+
} from "@cdktn/commons";
|
|
9
|
+
import { getFullProviderName } from "./provider";
|
|
10
|
+
import { ProgramScope } from "./types";
|
|
11
|
+
|
|
12
|
+
function getResourceAtPath(schema: ProviderSchema, path: string) {
|
|
13
|
+
const parts = path.split(".");
|
|
14
|
+
|
|
15
|
+
if (parts.length < 2) {
|
|
16
|
+
// Too short to be a valid path
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const isDataSource = parts[0] === "data";
|
|
21
|
+
if (isDataSource) {
|
|
22
|
+
parts.shift();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const providerName = parts.shift() as string;
|
|
26
|
+
const resourceName = parts.shift() as string;
|
|
27
|
+
|
|
28
|
+
const fullProviderName = getFullProviderName(schema, providerName);
|
|
29
|
+
// Hack: In the case of 'external', the name of the data source 'external' doesn't have a prefix
|
|
30
|
+
// so we repeat the name as both provider prefix and the data source name
|
|
31
|
+
const fullResourceName =
|
|
32
|
+
providerName === resourceName
|
|
33
|
+
? providerName
|
|
34
|
+
: `${providerName}_${resourceName}`;
|
|
35
|
+
|
|
36
|
+
if (!fullProviderName) {
|
|
37
|
+
// No provider found with that name
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const provider = schema.provider_schemas?.[fullProviderName];
|
|
42
|
+
|
|
43
|
+
if (!provider) {
|
|
44
|
+
// Could not find provider
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (resourceName.endsWith("Provider")) {
|
|
49
|
+
// This is a provider
|
|
50
|
+
return { resource: provider.provider, parts };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const resources = isDataSource
|
|
54
|
+
? provider.data_source_schemas
|
|
55
|
+
: provider.resource_schemas;
|
|
56
|
+
|
|
57
|
+
const resource = resources[fullResourceName];
|
|
58
|
+
if (!resource) {
|
|
59
|
+
// Could not find resource
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { resource, parts };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function findType(
|
|
67
|
+
item: Schema | BlockType | AttributeType,
|
|
68
|
+
parts: string[],
|
|
69
|
+
): Schema | BlockType | AttributeType | null {
|
|
70
|
+
if (!parts.length) {
|
|
71
|
+
return item;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const [currentPart, ...otherParts] = parts;
|
|
75
|
+
|
|
76
|
+
// Promitive attributes can be returned directly
|
|
77
|
+
if (typeof item === "string") {
|
|
78
|
+
return item;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Complex attributes
|
|
82
|
+
if (Array.isArray(item)) {
|
|
83
|
+
if (item[0] === "set" || item[0] === "list") {
|
|
84
|
+
if (currentPart === "[]") {
|
|
85
|
+
return findType(item[1], otherParts);
|
|
86
|
+
}
|
|
87
|
+
// Trying to access a property on a list
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (item[0] === "object") {
|
|
92
|
+
if (currentPart === "[]") {
|
|
93
|
+
// Trying to access a property on a list
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return findType(item[1][currentPart], otherParts);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (item[0] === "map") {
|
|
101
|
+
// We don't care what the key is
|
|
102
|
+
return findType(item[1], otherParts);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Unknown type
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// If we are not in an attribute, we can ignore the [] (since max_item=1 parts don't have [], so we just ignore it)
|
|
110
|
+
if (currentPart === "[]") {
|
|
111
|
+
return findType(item, otherParts);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Block
|
|
115
|
+
if (item.block) {
|
|
116
|
+
// Find block type in block
|
|
117
|
+
if (item.block.block_types) {
|
|
118
|
+
const blockType = item.block.block_types[currentPart];
|
|
119
|
+
if (blockType) {
|
|
120
|
+
return findType(blockType, otherParts);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Find attribute in block
|
|
125
|
+
if (item.block.attributes) {
|
|
126
|
+
const attribute = item.block.attributes[currentPart];
|
|
127
|
+
if (attribute && attribute.type) {
|
|
128
|
+
return findType(attribute.type, otherParts);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Could not find the type
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function getTypeAtPath(
|
|
138
|
+
schema: ProviderSchema,
|
|
139
|
+
path: string,
|
|
140
|
+
): Schema | BlockType | AttributeType | null {
|
|
141
|
+
const resourceSchema = getResourceAtPath(schema, path);
|
|
142
|
+
|
|
143
|
+
if (!resourceSchema) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const { resource, parts } = resourceSchema;
|
|
147
|
+
return findType(resource, parts);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export const isMapAttribute = (
|
|
151
|
+
attribute: Schema | AttributeType | BlockType | null,
|
|
152
|
+
) => (Array.isArray(attribute) ? attribute[0] === "map" : false);
|
|
153
|
+
|
|
154
|
+
export function getDesiredType(
|
|
155
|
+
scope: ProgramScope,
|
|
156
|
+
path: string,
|
|
157
|
+
): AttributeType {
|
|
158
|
+
const attributeOrBlockType = getTypeAtPath(scope.providerSchema, path);
|
|
159
|
+
|
|
160
|
+
// Attribute type is not defined
|
|
161
|
+
if (!attributeOrBlockType) {
|
|
162
|
+
return "dynamic";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Primitive attribute type
|
|
166
|
+
if (typeof attributeOrBlockType === "string") {
|
|
167
|
+
return attributeOrBlockType;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Complex attribute type
|
|
171
|
+
if (Array.isArray(attributeOrBlockType)) {
|
|
172
|
+
return attributeOrBlockType;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Schema
|
|
176
|
+
if ("version" in attributeOrBlockType) {
|
|
177
|
+
return "dynamic";
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Block type
|
|
181
|
+
return "dynamic";
|
|
182
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import { TerraformProviderGenerator } from "@cdktn/provider-generator";
|
|
4
|
+
import { ProviderSchema } from "@cdktn/commons";
|
|
5
|
+
|
|
6
|
+
export type TerraformResourceBlock = unknown;
|
|
7
|
+
export type AttributePath = string;
|
|
8
|
+
export type ProgramScope = {
|
|
9
|
+
providerSchema: ProviderSchema;
|
|
10
|
+
providerGenerator: Record<string, TerraformProviderGenerator>;
|
|
11
|
+
constructs: Set<string>;
|
|
12
|
+
variables: Record<
|
|
13
|
+
string,
|
|
14
|
+
{
|
|
15
|
+
resource: string;
|
|
16
|
+
variableName: string;
|
|
17
|
+
}
|
|
18
|
+
>;
|
|
19
|
+
// Temporary flag to indicate if we need to import the cdktf library to access the token class
|
|
20
|
+
hasTokenBasedTypeCoercion: boolean;
|
|
21
|
+
nodeIds: string[]; // temporarily added until replaced
|
|
22
|
+
importables: ImportableConstruct[]; // records all imports for the conversion
|
|
23
|
+
topLevelConfig: Record<string, AttributePath>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type ResourceScope = ProgramScope & {
|
|
27
|
+
forEachIteratorName?: string; // set if a for_each is used in this resource
|
|
28
|
+
countIteratorName?: string; // set if a count is used in this resource
|
|
29
|
+
withinOverrideExpression?: boolean; // set if we are currently within an override expression
|
|
30
|
+
scopedVariables?: Record<string, string>; // set if we are currently within an dynamic block expression
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type Reference = {
|
|
34
|
+
start: number;
|
|
35
|
+
end: number;
|
|
36
|
+
referencee: { id: string; full: string }; // identifier for resource
|
|
37
|
+
useFqn?: boolean;
|
|
38
|
+
isVariable?: boolean;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type DynamicBlock = {
|
|
42
|
+
path: string;
|
|
43
|
+
for_each: string;
|
|
44
|
+
content: TerraformResourceBlock;
|
|
45
|
+
scopedVar: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type IteratorVariableReference = {
|
|
49
|
+
start: number;
|
|
50
|
+
end: number;
|
|
51
|
+
value: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type ImportableConstruct = {
|
|
55
|
+
provider: string;
|
|
56
|
+
constructName: string;
|
|
57
|
+
namespace?: string;
|
|
58
|
+
};
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import camelcase from "camelcase";
|
|
4
|
+
|
|
5
|
+
export { logger } from "@cdktn/commons";
|
|
6
|
+
|
|
7
|
+
export const fileBugCommentText = `This is likely a bug in cdktn. Please report it at https://github.com/open-constructs/cdk-terrain/issues/new?assignees=&labels=bug&template=bug-report.md&title=.`;
|
|
8
|
+
|
|
9
|
+
export const camelCase = (str: string) => camelcase(str.replace(/[-/]/g, "_"));
|
|
10
|
+
export const pascalCase = (str: string) =>
|
|
11
|
+
camelcase(str.replace(/[-/]/g, "_"), { pascalCase: true });
|
|
12
|
+
|
|
13
|
+
export function uniqueId(set: Set<string>, key: string): string {
|
|
14
|
+
if (set.has(key)) {
|
|
15
|
+
return uniqueId(set, `${key}_${set.size}`);
|
|
16
|
+
}
|
|
17
|
+
set.add(key);
|
|
18
|
+
return key;
|
|
19
|
+
}
|
package/src/variables.ts
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as t from "@babel/types";
|
|
7
|
+
import { ProgramScope, Reference } from "./types";
|
|
8
|
+
import { camelCase, pascalCase } from "./utils";
|
|
9
|
+
import { sanitizeClassOrNamespaceName } from "@cdktn/provider-generator";
|
|
10
|
+
import { getFullProviderName } from "./provider";
|
|
11
|
+
import reservedWords from "reserved-words";
|
|
12
|
+
|
|
13
|
+
export function referenceToVariableName(
|
|
14
|
+
scope: ProgramScope,
|
|
15
|
+
ref: Reference,
|
|
16
|
+
): string {
|
|
17
|
+
const parts = ref.referencee.id.split(".");
|
|
18
|
+
const resource = parts[0] === "data" ? `${parts[0]}.${parts[1]}` : parts[0];
|
|
19
|
+
const name = parts[0] === "data" ? parts[2] : parts[1];
|
|
20
|
+
return variableName(scope, resource, name);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function validVarName(name: string) {
|
|
24
|
+
if (reservedWords.check(name)) {
|
|
25
|
+
return `${name}Var`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!Number.isNaN(parseInt(name[0], 10))) {
|
|
29
|
+
return `d${name}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return name;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getUniqueName(scope: ProgramScope, provider: string, type: string) {
|
|
36
|
+
// early abort on cdktf
|
|
37
|
+
if (provider === "cdktf") {
|
|
38
|
+
return pascalCase(type.replace("cdktf_", ""));
|
|
39
|
+
}
|
|
40
|
+
// early abort on cdktn
|
|
41
|
+
if (provider === "cdktn") {
|
|
42
|
+
return pascalCase(type.replace("cdktn_", ""));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (provider === "NullProvider") {
|
|
46
|
+
return pascalCase(type.replace("NullProvider_", ""));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Special handling for provider blocks, e.g. aws_AwsProvider
|
|
50
|
+
if (type === `${pascalCase(provider)}Provider`) {
|
|
51
|
+
return sanitizeClassOrNamespaceName(type, true);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const fullProviderName = getFullProviderName(scope.providerSchema, provider);
|
|
55
|
+
if (fullProviderName && scope.providerGenerator[fullProviderName]) {
|
|
56
|
+
return scope.providerGenerator[fullProviderName]?.getClassNameForResource(
|
|
57
|
+
type,
|
|
58
|
+
);
|
|
59
|
+
} else {
|
|
60
|
+
// If we can not find the class name for a resource the caller needs to find a sensible default
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getResourceNamespace(
|
|
66
|
+
scope: ProgramScope,
|
|
67
|
+
provider: string,
|
|
68
|
+
resource: string,
|
|
69
|
+
isDataSource: boolean,
|
|
70
|
+
type: string,
|
|
71
|
+
) {
|
|
72
|
+
// happens e.g. for references to cdktn.TerraformStack (and similar) in generated code
|
|
73
|
+
if (provider === "cdktn") {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// e.g. awsProvider -> provider
|
|
78
|
+
if (
|
|
79
|
+
resource === pascalCase(`${provider}_provider`) ||
|
|
80
|
+
(provider === "NullProvider" && resource === "NullProvider")
|
|
81
|
+
) {
|
|
82
|
+
return "provider";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const fullProviderName = getFullProviderName(scope.providerSchema, provider);
|
|
86
|
+
|
|
87
|
+
if (fullProviderName && scope.providerGenerator[fullProviderName]) {
|
|
88
|
+
return camelCase(
|
|
89
|
+
scope.providerGenerator[fullProviderName]?.getNamespaceNameForResource(
|
|
90
|
+
type.replace(/\./g, "_"),
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (isDataSource) {
|
|
96
|
+
return camelCase(
|
|
97
|
+
sanitizeClassOrNamespaceName(`data_${provider}_${resource}`),
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return camelCase(sanitizeClassOrNamespaceName(resource));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function constructAst(
|
|
105
|
+
scope: ProgramScope,
|
|
106
|
+
type: string,
|
|
107
|
+
isModuleImport: boolean,
|
|
108
|
+
) {
|
|
109
|
+
if (isModuleImport) {
|
|
110
|
+
return t.memberExpression(t.identifier(type), t.identifier(type));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (type.startsWith("var.")) {
|
|
114
|
+
scope.importables.push({
|
|
115
|
+
provider: "cdktn",
|
|
116
|
+
constructName: "TerraformVariable",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return t.identifier("TerraformVariable");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (type === "terraform.data") {
|
|
123
|
+
scope.importables.push({
|
|
124
|
+
constructName: "DataResource",
|
|
125
|
+
provider: "cdktn",
|
|
126
|
+
});
|
|
127
|
+
return t.identifier("DataResource");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// resources or data sources
|
|
131
|
+
if (!type.includes("./") && type.includes(".")) {
|
|
132
|
+
const parts = type.split(".");
|
|
133
|
+
if (parts[0] === "data") {
|
|
134
|
+
const [, provider, resource] = parts;
|
|
135
|
+
|
|
136
|
+
const namespace = getResourceNamespace(
|
|
137
|
+
scope,
|
|
138
|
+
provider,
|
|
139
|
+
resource,
|
|
140
|
+
true,
|
|
141
|
+
type,
|
|
142
|
+
);
|
|
143
|
+
const resourceName =
|
|
144
|
+
getUniqueName(scope, provider, parts.join("_")) ||
|
|
145
|
+
pascalCase(
|
|
146
|
+
sanitizeClassOrNamespaceName(`data_${provider}_${resource}`),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
scope.importables.push({
|
|
150
|
+
provider: provider,
|
|
151
|
+
constructName: resourceName,
|
|
152
|
+
namespace,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (namespace) {
|
|
156
|
+
return t.identifier(resourceName); // e.g. DataAwsInstance
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return t.identifier(resourceName); // e.g. DataAwsNatGateway
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const [provider, resource] = parts;
|
|
163
|
+
const namespace = getResourceNamespace(
|
|
164
|
+
scope,
|
|
165
|
+
provider,
|
|
166
|
+
resource,
|
|
167
|
+
false,
|
|
168
|
+
type,
|
|
169
|
+
);
|
|
170
|
+
const resourceName =
|
|
171
|
+
getUniqueName(scope, provider, parts.join("_")) ||
|
|
172
|
+
pascalCase(sanitizeClassOrNamespaceName(resource));
|
|
173
|
+
|
|
174
|
+
scope.importables.push({
|
|
175
|
+
provider: provider,
|
|
176
|
+
constructName: resourceName,
|
|
177
|
+
namespace,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (namespace) {
|
|
181
|
+
return t.identifier(resourceName); // e.g. Instance
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return t.identifier(resourceName); // e.g. BigQueryTable
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return t.identifier(pascalCase(type));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function variableName(
|
|
191
|
+
scope: ProgramScope,
|
|
192
|
+
resource: string,
|
|
193
|
+
name: string,
|
|
194
|
+
): string {
|
|
195
|
+
const consistentResourceName = resource.replace(/\./g, "_");
|
|
196
|
+
// name collision, we need to prefix the name
|
|
197
|
+
if (scope.variables[name]) {
|
|
198
|
+
if (consistentResourceName === scope.variables[name].resource) {
|
|
199
|
+
return scope.variables[name].variableName;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// we only cache one per name
|
|
203
|
+
return validVarName(camelCase([resource, name].join("_")));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const variableName = validVarName(camelCase(name));
|
|
207
|
+
|
|
208
|
+
scope.variables[name] = {
|
|
209
|
+
variableName,
|
|
210
|
+
resource: consistentResourceName,
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return variableName;
|
|
214
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
|
2
|
+
|
|
3
|
+
exports[`backends local backend snapshot typescript 1`] = `
|
|
4
|
+
"import { Construct } from "constructs";
|
|
5
|
+
import { LocalBackend, TerraformStack } from "cdktn";
|
|
6
|
+
class MyConvertedCode extends TerraformStack {
|
|
7
|
+
constructor(scope: Construct, name: string) {
|
|
8
|
+
super(scope, name);
|
|
9
|
+
new LocalBackend(this, {
|
|
10
|
+
path: "relative/path/to/terraform.tfstate",
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
"
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
exports[`backends remote backend snapshot typescript 1`] = `
|
|
18
|
+
"import { Construct } from "constructs";
|
|
19
|
+
import { RemoteBackend, TerraformStack } from "cdktn";
|
|
20
|
+
class MyConvertedCode extends TerraformStack {
|
|
21
|
+
constructor(scope: Construct, name: string) {
|
|
22
|
+
super(scope, name);
|
|
23
|
+
new RemoteBackend(this, {
|
|
24
|
+
hostname: "app.terraform.io",
|
|
25
|
+
organization: "company",
|
|
26
|
+
workspaces: [
|
|
27
|
+
{
|
|
28
|
+
name: "my-app-prod",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
"
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
exports[`backends remote state snapshot typescript 1`] = `
|
|
38
|
+
"import { Construct } from "constructs";
|
|
39
|
+
import { DataTerraformRemoteState, TerraformStack } from "cdktn";
|
|
40
|
+
class MyConvertedCode extends TerraformStack {
|
|
41
|
+
constructor(scope: Construct, name: string) {
|
|
42
|
+
super(scope, name);
|
|
43
|
+
new DataTerraformRemoteState(this, "vpc", {
|
|
44
|
+
organization: "hashicorp",
|
|
45
|
+
workspaces: [
|
|
46
|
+
{
|
|
47
|
+
name: "vpc-prod",
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
"
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
exports[`backends remote state types snapshot typescript 1`] = `
|
|
57
|
+
"import { Construct } from "constructs";
|
|
58
|
+
import { DataTerraformRemoteStateS3, TerraformStack } from "cdktn";
|
|
59
|
+
class MyConvertedCode extends TerraformStack {
|
|
60
|
+
constructor(scope: Construct, name: string) {
|
|
61
|
+
super(scope, name);
|
|
62
|
+
new DataTerraformRemoteStateS3(this, "s3", {
|
|
63
|
+
bucket: "mybucket",
|
|
64
|
+
key: "path/to/my/key",
|
|
65
|
+
region: "us-east-1",
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
"
|
|
70
|
+
`;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
|
2
|
+
|
|
3
|
+
exports[`externals handle simple external data snapshot typescript 1`] = `
|
|
4
|
+
"import { Construct } from "constructs";
|
|
5
|
+
import {
|
|
6
|
+
VariableType,
|
|
7
|
+
TerraformVariable,
|
|
8
|
+
TerraformOutput,
|
|
9
|
+
Fn,
|
|
10
|
+
TerraformStack,
|
|
11
|
+
} from "cdktn";
|
|
12
|
+
/*
|
|
13
|
+
* Provider bindings are generated by running \`cdktn get\`.
|
|
14
|
+
* See https://cdktn.io/docs/concepts/providers#import-providers for more details.
|
|
15
|
+
*/
|
|
16
|
+
import { DataExternal } from "./.gen/providers/external/data-external";
|
|
17
|
+
import { ExternalProvider } from "./.gen/providers/external/provider";
|
|
18
|
+
class MyConvertedCode extends TerraformStack {
|
|
19
|
+
constructor(scope: Construct, name: string) {
|
|
20
|
+
super(scope, name);
|
|
21
|
+
/*Terraform Variables are not always the best fit for getting inputs in the context of Terraform CDK.
|
|
22
|
+
You can read more about this at https://cdktn.io/docs/concepts/variables-and-outputs#input-variables*/
|
|
23
|
+
new ExternalProvider(this, "external", {});
|
|
24
|
+
const fargateRegion = new TerraformVariable(this, "fargate_region", {
|
|
25
|
+
default: "us-east-1",
|
|
26
|
+
type: VariableType.STRING,
|
|
27
|
+
});
|
|
28
|
+
const dataExternalThumbprint = new DataExternal(this, "thumbprint", {
|
|
29
|
+
program: ["\${path.module}/oidc_thumbprint.sh", fargateRegion.value],
|
|
30
|
+
});
|
|
31
|
+
new TerraformOutput(this, "foo", {
|
|
32
|
+
value: Fn.lookupNested(dataExternalThumbprint, ["result", "thumbprint"]),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
"
|
|
37
|
+
`;
|