@unstablestudios/terraform 0.0.0
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/README.md +312 -0
- package/dist/config/backend.d.ts +118 -0
- package/dist/config/backend.d.ts.map +1 -0
- package/dist/config/backend.js +153 -0
- package/dist/config/backend.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/terraform.d.ts +157 -0
- package/dist/config/terraform.d.ts.map +1 -0
- package/dist/config/terraform.js +211 -0
- package/dist/config/terraform.js.map +1 -0
- package/dist/config/terraform.test.d.ts +2 -0
- package/dist/config/terraform.test.d.ts.map +1 -0
- package/dist/config/terraform.test.js +240 -0
- package/dist/config/terraform.test.js.map +1 -0
- package/dist/config/tfvars.d.ts +90 -0
- package/dist/config/tfvars.d.ts.map +1 -0
- package/dist/config/tfvars.js +133 -0
- package/dist/config/tfvars.js.map +1 -0
- package/dist/config/tfvars.test.d.ts +2 -0
- package/dist/config/tfvars.test.d.ts.map +1 -0
- package/dist/config/tfvars.test.js +187 -0
- package/dist/config/tfvars.test.js.map +1 -0
- package/dist/hcl/generator.d.ts +59 -0
- package/dist/hcl/generator.d.ts.map +1 -0
- package/dist/hcl/generator.js +401 -0
- package/dist/hcl/generator.js.map +1 -0
- package/dist/hcl/generator.test.d.ts +2 -0
- package/dist/hcl/generator.test.d.ts.map +1 -0
- package/dist/hcl/generator.test.js +280 -0
- package/dist/hcl/generator.test.js.map +1 -0
- package/dist/hcl/index.d.ts +5 -0
- package/dist/hcl/index.d.ts.map +1 -0
- package/dist/hcl/index.js +3 -0
- package/dist/hcl/index.js.map +1 -0
- package/dist/hcl/writer.d.ts +35 -0
- package/dist/hcl/writer.d.ts.map +1 -0
- package/dist/hcl/writer.js +154 -0
- package/dist/hcl/writer.js.map +1 -0
- package/dist/index.d.mts +970 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1283 -0
- package/dist/modules/cloudflare/d1.d.ts +39 -0
- package/dist/modules/cloudflare/d1.d.ts.map +1 -0
- package/dist/modules/cloudflare/d1.js +55 -0
- package/dist/modules/cloudflare/d1.js.map +1 -0
- package/dist/modules/cloudflare/index.d.ts +43 -0
- package/dist/modules/cloudflare/index.d.ts.map +1 -0
- package/dist/modules/cloudflare/index.js +44 -0
- package/dist/modules/cloudflare/index.js.map +1 -0
- package/dist/modules/cloudflare/kv.d.ts +57 -0
- package/dist/modules/cloudflare/kv.d.ts.map +1 -0
- package/dist/modules/cloudflare/kv.js +75 -0
- package/dist/modules/cloudflare/kv.js.map +1 -0
- package/dist/modules/cloudflare/r2.d.ts +49 -0
- package/dist/modules/cloudflare/r2.d.ts.map +1 -0
- package/dist/modules/cloudflare/r2.js +70 -0
- package/dist/modules/cloudflare/r2.js.map +1 -0
- package/dist/modules/cloudflare/worker.d.ts +104 -0
- package/dist/modules/cloudflare/worker.d.ts.map +1 -0
- package/dist/modules/cloudflare/worker.js +128 -0
- package/dist/modules/cloudflare/worker.js.map +1 -0
- package/dist/modules/index.d.ts +4 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +4 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/types.d.ts +97 -0
- package/dist/modules/types.d.ts.map +1 -0
- package/dist/modules/types.js +106 -0
- package/dist/modules/types.js.map +1 -0
- package/dist/modules/types.test.d.ts +2 -0
- package/dist/modules/types.test.d.ts.map +1 -0
- package/dist/modules/types.test.js +167 -0
- package/dist/modules/types.test.js.map +1 -0
- package/dist/types/config.d.ts +140 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +16 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/config.test.d.ts +2 -0
- package/dist/types/config.test.d.ts.map +1 -0
- package/dist/types/config.test.js +36 -0
- package/dist/types/config.test.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +27 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1283 @@
|
|
|
1
|
+
// src/types/config.ts
|
|
2
|
+
function expr(value) {
|
|
3
|
+
return { __hclExpression: true, value };
|
|
4
|
+
}
|
|
5
|
+
function isHclExpression(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && "__hclExpression" in value && value.__hclExpression === true;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/hcl/generator.ts
|
|
10
|
+
var DEFAULT_OPTIONS = {
|
|
11
|
+
indent: " ",
|
|
12
|
+
includeEmpty: false
|
|
13
|
+
};
|
|
14
|
+
function toHcl(value, options = {}) {
|
|
15
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
16
|
+
return formatValue(value, 0, opts);
|
|
17
|
+
}
|
|
18
|
+
function formatBlock(block, options = {}) {
|
|
19
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
20
|
+
const { type, labels, body, nestedBlocks } = block;
|
|
21
|
+
const labelStr = labels.map((l) => `"${l}"`).join(" ");
|
|
22
|
+
const header = labelStr ? `${type} ${labelStr}` : type;
|
|
23
|
+
const bodyLines = formatBody(body, 1, opts);
|
|
24
|
+
const nestedLines = nestedBlocks?.map((nb) => formatNestedBlock(nb, 1, opts)).join("\n") ?? "";
|
|
25
|
+
const content = [bodyLines, nestedLines].filter(Boolean).join("\n");
|
|
26
|
+
return `${header} {
|
|
27
|
+
${content}
|
|
28
|
+
}`;
|
|
29
|
+
}
|
|
30
|
+
function formatNestedBlock(block, depth, opts) {
|
|
31
|
+
const indent = opts.indent.repeat(depth);
|
|
32
|
+
const { type, labels, body, nestedBlocks } = block;
|
|
33
|
+
const labelStr = labels.map((l) => `"${l}"`).join(" ");
|
|
34
|
+
const header = labelStr ? `${type} ${labelStr}` : type;
|
|
35
|
+
const bodyLines = formatBody(body, depth + 1, opts);
|
|
36
|
+
const nestedLines = nestedBlocks?.map((nb) => formatNestedBlock(nb, depth + 1, opts)).join("\n") ?? "";
|
|
37
|
+
const content = [bodyLines, nestedLines].filter(Boolean).join("\n");
|
|
38
|
+
return `${indent}${header} {
|
|
39
|
+
${content}
|
|
40
|
+
${indent}}`;
|
|
41
|
+
}
|
|
42
|
+
function formatBody(obj, depth, opts) {
|
|
43
|
+
const indent = opts.indent.repeat(depth);
|
|
44
|
+
const lines = [];
|
|
45
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
46
|
+
if (!opts.includeEmpty && (value === null || value === void 0)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const formattedValue = formatValue(value, depth, opts);
|
|
50
|
+
lines.push(`${indent}${key} = ${formattedValue}`);
|
|
51
|
+
}
|
|
52
|
+
return lines.join("\n");
|
|
53
|
+
}
|
|
54
|
+
function formatValue(value, depth, opts) {
|
|
55
|
+
if (value === null || value === void 0) {
|
|
56
|
+
return "null";
|
|
57
|
+
}
|
|
58
|
+
if (isHclExpression(value)) {
|
|
59
|
+
return value.value;
|
|
60
|
+
}
|
|
61
|
+
if (typeof value === "string") {
|
|
62
|
+
if (value.includes("\n")) {
|
|
63
|
+
return formatHeredoc(value);
|
|
64
|
+
}
|
|
65
|
+
return `"${escapeString(value)}"`;
|
|
66
|
+
}
|
|
67
|
+
if (typeof value === "number") {
|
|
68
|
+
return value.toString();
|
|
69
|
+
}
|
|
70
|
+
if (typeof value === "boolean") {
|
|
71
|
+
return value ? "true" : "false";
|
|
72
|
+
}
|
|
73
|
+
if (Array.isArray(value)) {
|
|
74
|
+
return formatArray(value, depth, opts);
|
|
75
|
+
}
|
|
76
|
+
if (typeof value === "object") {
|
|
77
|
+
return formatObject(value, depth, opts);
|
|
78
|
+
}
|
|
79
|
+
return String(value);
|
|
80
|
+
}
|
|
81
|
+
function formatArray(arr, depth, opts) {
|
|
82
|
+
if (arr.length === 0) {
|
|
83
|
+
return "[]";
|
|
84
|
+
}
|
|
85
|
+
const allSimple = arr.every(
|
|
86
|
+
(v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean"
|
|
87
|
+
);
|
|
88
|
+
if (allSimple && arr.length <= 5) {
|
|
89
|
+
const items2 = arr.map((v) => formatValue(v, depth, opts));
|
|
90
|
+
return `[${items2.join(", ")}]`;
|
|
91
|
+
}
|
|
92
|
+
const indent = opts.indent.repeat(depth + 1);
|
|
93
|
+
const closeIndent = opts.indent.repeat(depth);
|
|
94
|
+
const items = arr.map((v) => `${indent}${formatValue(v, depth + 1, opts)}`);
|
|
95
|
+
return `[
|
|
96
|
+
${items.join(",\n")}
|
|
97
|
+
${closeIndent}]`;
|
|
98
|
+
}
|
|
99
|
+
function formatObject(obj, depth, opts) {
|
|
100
|
+
const entries = Object.entries(obj).filter(
|
|
101
|
+
([, v]) => opts.includeEmpty || v !== null && v !== void 0
|
|
102
|
+
);
|
|
103
|
+
if (entries.length === 0) {
|
|
104
|
+
return "{}";
|
|
105
|
+
}
|
|
106
|
+
const indent = opts.indent.repeat(depth + 1);
|
|
107
|
+
const closeIndent = opts.indent.repeat(depth);
|
|
108
|
+
const items = entries.map(([k, v]) => `${indent}${k} = ${formatValue(v, depth + 1, opts)}`);
|
|
109
|
+
return `{
|
|
110
|
+
${items.join("\n")}
|
|
111
|
+
${closeIndent}}`;
|
|
112
|
+
}
|
|
113
|
+
function formatHeredoc(value) {
|
|
114
|
+
return `<<-EOF
|
|
115
|
+
${value}
|
|
116
|
+
EOF`;
|
|
117
|
+
}
|
|
118
|
+
function escapeString(str) {
|
|
119
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
120
|
+
}
|
|
121
|
+
function generateVariable(name, config, opts = {}) {
|
|
122
|
+
const body = {};
|
|
123
|
+
if (config.type) body.type = { __hclExpression: true, value: config.type };
|
|
124
|
+
if (config.description) body.description = config.description;
|
|
125
|
+
if (config.default !== void 0) body.default = config.default;
|
|
126
|
+
if (config.sensitive !== void 0) body.sensitive = config.sensitive;
|
|
127
|
+
if (config.nullable !== void 0) body.nullable = config.nullable;
|
|
128
|
+
const block = {
|
|
129
|
+
type: "variable",
|
|
130
|
+
labels: [name],
|
|
131
|
+
body,
|
|
132
|
+
nestedBlocks: config.validation ? [
|
|
133
|
+
{
|
|
134
|
+
type: "validation",
|
|
135
|
+
labels: [],
|
|
136
|
+
body: {
|
|
137
|
+
condition: config.validation.condition,
|
|
138
|
+
error_message: config.validation.error_message
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
] : void 0
|
|
142
|
+
};
|
|
143
|
+
return formatBlock(block, opts);
|
|
144
|
+
}
|
|
145
|
+
function generateOutput(name, config, opts = {}) {
|
|
146
|
+
const body = {
|
|
147
|
+
value: config.value
|
|
148
|
+
};
|
|
149
|
+
if (config.description) body.description = config.description;
|
|
150
|
+
if (config.sensitive !== void 0) body.sensitive = config.sensitive;
|
|
151
|
+
if (config.depends_on) {
|
|
152
|
+
body.depends_on = { __hclExpression: true, value: `[${config.depends_on.map((d) => d.value).join(", ")}]` };
|
|
153
|
+
}
|
|
154
|
+
const block = {
|
|
155
|
+
type: "output",
|
|
156
|
+
labels: [name],
|
|
157
|
+
body
|
|
158
|
+
};
|
|
159
|
+
return formatBlock(block, opts);
|
|
160
|
+
}
|
|
161
|
+
function generateProvider(config, opts = {}) {
|
|
162
|
+
const body = { ...config.config };
|
|
163
|
+
if (config.alias) body.alias = config.alias;
|
|
164
|
+
const block = {
|
|
165
|
+
type: "provider",
|
|
166
|
+
labels: [config.provider],
|
|
167
|
+
body
|
|
168
|
+
};
|
|
169
|
+
return formatBlock(block, opts);
|
|
170
|
+
}
|
|
171
|
+
function generateResource(config, opts = {}) {
|
|
172
|
+
const body = { ...config.config };
|
|
173
|
+
if (config.depends_on) {
|
|
174
|
+
body.depends_on = { __hclExpression: true, value: `[${config.depends_on.map((d) => d.value).join(", ")}]` };
|
|
175
|
+
}
|
|
176
|
+
if (config.count !== void 0) body.count = config.count;
|
|
177
|
+
if (config.for_each !== void 0) body.for_each = config.for_each;
|
|
178
|
+
if (config.provider) body.provider = config.provider;
|
|
179
|
+
const nestedBlocks = [];
|
|
180
|
+
if (config.lifecycle) {
|
|
181
|
+
const lifecycleBody = {};
|
|
182
|
+
if (config.lifecycle.create_before_destroy !== void 0) {
|
|
183
|
+
lifecycleBody.create_before_destroy = config.lifecycle.create_before_destroy;
|
|
184
|
+
}
|
|
185
|
+
if (config.lifecycle.prevent_destroy !== void 0) {
|
|
186
|
+
lifecycleBody.prevent_destroy = config.lifecycle.prevent_destroy;
|
|
187
|
+
}
|
|
188
|
+
if (config.lifecycle.ignore_changes) {
|
|
189
|
+
lifecycleBody.ignore_changes = config.lifecycle.ignore_changes;
|
|
190
|
+
}
|
|
191
|
+
if (config.lifecycle.replace_triggered_by) {
|
|
192
|
+
lifecycleBody.replace_triggered_by = {
|
|
193
|
+
__hclExpression: true,
|
|
194
|
+
value: `[${config.lifecycle.replace_triggered_by.map((d) => d.value).join(", ")}]`
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
nestedBlocks.push({
|
|
198
|
+
type: "lifecycle",
|
|
199
|
+
labels: [],
|
|
200
|
+
body: lifecycleBody
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
const block = {
|
|
204
|
+
type: "resource",
|
|
205
|
+
labels: [config.type, config.name],
|
|
206
|
+
body,
|
|
207
|
+
nestedBlocks: nestedBlocks.length > 0 ? nestedBlocks : void 0
|
|
208
|
+
};
|
|
209
|
+
return formatBlock(block, opts);
|
|
210
|
+
}
|
|
211
|
+
function generateDataSource(config, opts = {}) {
|
|
212
|
+
const body = { ...config.config };
|
|
213
|
+
if (config.depends_on) {
|
|
214
|
+
body.depends_on = { __hclExpression: true, value: `[${config.depends_on.map((d) => d.value).join(", ")}]` };
|
|
215
|
+
}
|
|
216
|
+
if (config.count !== void 0) body.count = config.count;
|
|
217
|
+
if (config.for_each !== void 0) body.for_each = config.for_each;
|
|
218
|
+
if (config.provider) body.provider = config.provider;
|
|
219
|
+
const block = {
|
|
220
|
+
type: "data",
|
|
221
|
+
labels: [config.type, config.name],
|
|
222
|
+
body
|
|
223
|
+
};
|
|
224
|
+
return formatBlock(block, opts);
|
|
225
|
+
}
|
|
226
|
+
function generateModule(config, opts = {}) {
|
|
227
|
+
const body = {
|
|
228
|
+
source: config.source,
|
|
229
|
+
...config.config
|
|
230
|
+
};
|
|
231
|
+
if (config.version) body.version = config.version;
|
|
232
|
+
if (config.depends_on) {
|
|
233
|
+
body.depends_on = { __hclExpression: true, value: `[${config.depends_on.map((d) => d.value).join(", ")}]` };
|
|
234
|
+
}
|
|
235
|
+
if (config.count !== void 0) body.count = config.count;
|
|
236
|
+
if (config.for_each !== void 0) body.for_each = config.for_each;
|
|
237
|
+
if (config.providers) {
|
|
238
|
+
const providersObj = {};
|
|
239
|
+
for (const [key, value] of Object.entries(config.providers)) {
|
|
240
|
+
providersObj[key] = value;
|
|
241
|
+
}
|
|
242
|
+
body.providers = providersObj;
|
|
243
|
+
}
|
|
244
|
+
const block = {
|
|
245
|
+
type: "module",
|
|
246
|
+
labels: [config.name],
|
|
247
|
+
body
|
|
248
|
+
};
|
|
249
|
+
return formatBlock(block, opts);
|
|
250
|
+
}
|
|
251
|
+
function generateLocals(locals, opts = {}) {
|
|
252
|
+
const block = {
|
|
253
|
+
type: "locals",
|
|
254
|
+
labels: [],
|
|
255
|
+
body: locals
|
|
256
|
+
};
|
|
257
|
+
return formatBlock(block, opts);
|
|
258
|
+
}
|
|
259
|
+
function generateTerraformBlock(config, opts = {}) {
|
|
260
|
+
const body = {};
|
|
261
|
+
if (config.required_version) {
|
|
262
|
+
body.required_version = config.required_version;
|
|
263
|
+
}
|
|
264
|
+
const nestedBlocks = [];
|
|
265
|
+
if (config.required_providers) {
|
|
266
|
+
const providersBody = {};
|
|
267
|
+
for (const [name, provider] of Object.entries(config.required_providers)) {
|
|
268
|
+
providersBody[name] = {
|
|
269
|
+
source: provider.source,
|
|
270
|
+
...provider.version ? { version: provider.version } : {}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
nestedBlocks.push({
|
|
274
|
+
type: "required_providers",
|
|
275
|
+
labels: [],
|
|
276
|
+
body: providersBody
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
if (config.backend) {
|
|
280
|
+
nestedBlocks.push({
|
|
281
|
+
type: "backend",
|
|
282
|
+
labels: [config.backend.type],
|
|
283
|
+
body: config.backend.config
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
const block = {
|
|
287
|
+
type: "terraform",
|
|
288
|
+
labels: [],
|
|
289
|
+
body,
|
|
290
|
+
nestedBlocks: nestedBlocks.length > 0 ? nestedBlocks : void 0
|
|
291
|
+
};
|
|
292
|
+
return formatBlock(block, opts);
|
|
293
|
+
}
|
|
294
|
+
function generateTerraformConfig(config, opts = {}) {
|
|
295
|
+
const sections = [];
|
|
296
|
+
if (config.terraform) {
|
|
297
|
+
sections.push(generateTerraformBlock(config.terraform, opts));
|
|
298
|
+
}
|
|
299
|
+
if (config.providers) {
|
|
300
|
+
for (const provider of config.providers) {
|
|
301
|
+
sections.push(generateProvider(provider, opts));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (config.variables) {
|
|
305
|
+
for (const [name, variable] of Object.entries(config.variables)) {
|
|
306
|
+
sections.push(generateVariable(name, variable, opts));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (config.locals && Object.keys(config.locals).length > 0) {
|
|
310
|
+
sections.push(generateLocals(config.locals, opts));
|
|
311
|
+
}
|
|
312
|
+
if (config.dataSources) {
|
|
313
|
+
for (const dataSource of config.dataSources) {
|
|
314
|
+
sections.push(generateDataSource(dataSource, opts));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (config.resources) {
|
|
318
|
+
for (const resource of config.resources) {
|
|
319
|
+
sections.push(generateResource(resource, opts));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (config.modules) {
|
|
323
|
+
for (const module of config.modules) {
|
|
324
|
+
sections.push(generateModule(module, opts));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (config.outputs) {
|
|
328
|
+
for (const [name, output] of Object.entries(config.outputs)) {
|
|
329
|
+
sections.push(generateOutput(name, output, opts));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return sections.join("\n\n");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/hcl/writer.ts
|
|
336
|
+
var DEFAULT_HEADER = "# This file is generated. Do not edit manually.";
|
|
337
|
+
function prepareContent(content, header) {
|
|
338
|
+
if (header === void 0) {
|
|
339
|
+
return `${DEFAULT_HEADER}
|
|
340
|
+
|
|
341
|
+
${content}`;
|
|
342
|
+
}
|
|
343
|
+
if (header === "") {
|
|
344
|
+
return content;
|
|
345
|
+
}
|
|
346
|
+
return `${header}
|
|
347
|
+
|
|
348
|
+
${content}`;
|
|
349
|
+
}
|
|
350
|
+
function generateTerraformFile(config, options = {}) {
|
|
351
|
+
const content = generateTerraformConfig(config, options);
|
|
352
|
+
return prepareContent(content, options.header);
|
|
353
|
+
}
|
|
354
|
+
function generateTerraformFiles(config, options = {}) {
|
|
355
|
+
const ext = options.extension ?? ".tf";
|
|
356
|
+
const results = [];
|
|
357
|
+
const mainConfig = {
|
|
358
|
+
terraform: config.terraform,
|
|
359
|
+
providers: config.providers,
|
|
360
|
+
locals: config.locals,
|
|
361
|
+
dataSources: config.dataSources,
|
|
362
|
+
resources: config.resources,
|
|
363
|
+
modules: config.modules
|
|
364
|
+
};
|
|
365
|
+
const mainContent = generateTerraformConfig(mainConfig, options);
|
|
366
|
+
if (mainContent.trim()) {
|
|
367
|
+
results.push({
|
|
368
|
+
path: `main${ext}`,
|
|
369
|
+
content: prepareContent(mainContent, options.header)
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
if (config.variables && Object.keys(config.variables).length > 0) {
|
|
373
|
+
const varsConfig = {
|
|
374
|
+
variables: config.variables
|
|
375
|
+
};
|
|
376
|
+
const varsContent = generateTerraformConfig(varsConfig, options);
|
|
377
|
+
results.push({
|
|
378
|
+
path: `variables${ext}`,
|
|
379
|
+
content: prepareContent(varsContent, options.header)
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
if (config.outputs && Object.keys(config.outputs).length > 0) {
|
|
383
|
+
const outputsConfig = {
|
|
384
|
+
outputs: config.outputs
|
|
385
|
+
};
|
|
386
|
+
const outputsContent = generateTerraformConfig(outputsConfig, options);
|
|
387
|
+
results.push({
|
|
388
|
+
path: `outputs${ext}`,
|
|
389
|
+
content: prepareContent(outputsContent, options.header)
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
return results;
|
|
393
|
+
}
|
|
394
|
+
function createFileWriter(writeFile) {
|
|
395
|
+
return async (results, basePath = "") => {
|
|
396
|
+
for (const result of results) {
|
|
397
|
+
const fullPath = basePath ? `${basePath}/${result.path}` : result.path;
|
|
398
|
+
await writeFile(fullPath, result.content);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
function formatForTfvars(values) {
|
|
403
|
+
const lines = [];
|
|
404
|
+
for (const [key, value] of Object.entries(values)) {
|
|
405
|
+
if (value === void 0) continue;
|
|
406
|
+
if (typeof value === "string") {
|
|
407
|
+
lines.push(`${key} = "${escapeString2(value)}"`);
|
|
408
|
+
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
409
|
+
lines.push(`${key} = ${value}`);
|
|
410
|
+
} else if (value === null) {
|
|
411
|
+
lines.push(`${key} = null`);
|
|
412
|
+
} else if (Array.isArray(value)) {
|
|
413
|
+
lines.push(`${key} = ${formatArray2(value)}`);
|
|
414
|
+
} else if (typeof value === "object") {
|
|
415
|
+
lines.push(`${key} = ${formatObject2(value)}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return lines.join("\n");
|
|
419
|
+
}
|
|
420
|
+
function escapeString2(str) {
|
|
421
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
422
|
+
}
|
|
423
|
+
function formatArray2(arr, depth = 0) {
|
|
424
|
+
if (arr.length === 0) return "[]";
|
|
425
|
+
const indent = " ".repeat(depth + 1);
|
|
426
|
+
const closeIndent = " ".repeat(depth);
|
|
427
|
+
const items = arr.map((item) => {
|
|
428
|
+
if (typeof item === "string") return `${indent}"${escapeString2(item)}"`;
|
|
429
|
+
if (typeof item === "number" || typeof item === "boolean") return `${indent}${item}`;
|
|
430
|
+
if (item === null) return `${indent}null`;
|
|
431
|
+
if (Array.isArray(item)) return `${indent}${formatArray2(item, depth + 1)}`;
|
|
432
|
+
if (typeof item === "object") return `${indent}${formatObject2(item, depth + 1)}`;
|
|
433
|
+
return `${indent}${item}`;
|
|
434
|
+
});
|
|
435
|
+
return `[
|
|
436
|
+
${items.join(",\n")}
|
|
437
|
+
${closeIndent}]`;
|
|
438
|
+
}
|
|
439
|
+
function formatObject2(obj, depth = 0) {
|
|
440
|
+
const entries = Object.entries(obj);
|
|
441
|
+
if (entries.length === 0) return "{}";
|
|
442
|
+
const indent = " ".repeat(depth + 1);
|
|
443
|
+
const closeIndent = " ".repeat(depth);
|
|
444
|
+
const items = entries.map(([key, value]) => {
|
|
445
|
+
if (typeof value === "string") return `${indent}${key} = "${escapeString2(value)}"`;
|
|
446
|
+
if (typeof value === "number" || typeof value === "boolean") return `${indent}${key} = ${value}`;
|
|
447
|
+
if (value === null) return `${indent}${key} = null`;
|
|
448
|
+
if (Array.isArray(value)) return `${indent}${key} = ${formatArray2(value, depth + 1)}`;
|
|
449
|
+
if (typeof value === "object") return `${indent}${key} = ${formatObject2(value, depth + 1)}`;
|
|
450
|
+
return `${indent}${key} = ${value}`;
|
|
451
|
+
});
|
|
452
|
+
return `{
|
|
453
|
+
${items.join("\n")}
|
|
454
|
+
${closeIndent}}`;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// src/config/terraform.ts
|
|
458
|
+
var TerraformConfigBuilder = class {
|
|
459
|
+
constructor() {
|
|
460
|
+
this.config = {};
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Set required Terraform version
|
|
464
|
+
*/
|
|
465
|
+
requiredVersion(version) {
|
|
466
|
+
if (!this.config.terraform) this.config.terraform = {};
|
|
467
|
+
this.config.terraform.required_version = version;
|
|
468
|
+
return this;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Add a required provider
|
|
472
|
+
*/
|
|
473
|
+
requiredProvider(name, provider) {
|
|
474
|
+
if (!this.config.terraform) this.config.terraform = {};
|
|
475
|
+
if (!this.config.terraform.required_providers) this.config.terraform.required_providers = {};
|
|
476
|
+
this.config.terraform.required_providers[name] = provider;
|
|
477
|
+
return this;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Set backend configuration
|
|
481
|
+
*/
|
|
482
|
+
backend(backend2) {
|
|
483
|
+
if (!this.config.terraform) this.config.terraform = {};
|
|
484
|
+
this.config.terraform.backend = backend2;
|
|
485
|
+
return this;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Add a provider configuration
|
|
489
|
+
*/
|
|
490
|
+
provider(provider, config = {}, alias) {
|
|
491
|
+
if (!this.config.providers) this.config.providers = [];
|
|
492
|
+
this.config.providers.push({ provider, config, alias });
|
|
493
|
+
return this;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Add a variable
|
|
497
|
+
*/
|
|
498
|
+
variable(name, type, options = {}) {
|
|
499
|
+
if (!this.config.variables) this.config.variables = {};
|
|
500
|
+
this.config.variables[name] = {
|
|
501
|
+
type,
|
|
502
|
+
...options
|
|
503
|
+
};
|
|
504
|
+
return this;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Add locals
|
|
508
|
+
*/
|
|
509
|
+
locals(values) {
|
|
510
|
+
if (!this.config.locals) this.config.locals = {};
|
|
511
|
+
Object.assign(this.config.locals, values);
|
|
512
|
+
return this;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Add a resource
|
|
516
|
+
*/
|
|
517
|
+
resource(type, name, config) {
|
|
518
|
+
if (!this.config.resources) this.config.resources = [];
|
|
519
|
+
this.config.resources.push({ type, name, config });
|
|
520
|
+
return this;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Add a data source
|
|
524
|
+
*/
|
|
525
|
+
data(type, name, config) {
|
|
526
|
+
if (!this.config.dataSources) this.config.dataSources = [];
|
|
527
|
+
this.config.dataSources.push({ type, name, config });
|
|
528
|
+
return this;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Add a module
|
|
532
|
+
*/
|
|
533
|
+
module(name, source, config = {}, version) {
|
|
534
|
+
if (!this.config.modules) this.config.modules = [];
|
|
535
|
+
this.config.modules.push({ name, source, config, version });
|
|
536
|
+
return this;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Add an output
|
|
540
|
+
*/
|
|
541
|
+
output(name, value, options = {}) {
|
|
542
|
+
if (!this.config.outputs) this.config.outputs = {};
|
|
543
|
+
this.config.outputs[name] = { value, ...options };
|
|
544
|
+
return this;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Get the built configuration
|
|
548
|
+
*/
|
|
549
|
+
build() {
|
|
550
|
+
return this.config;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Generate HCL string
|
|
554
|
+
*/
|
|
555
|
+
toHcl(options) {
|
|
556
|
+
return generateTerraformConfig(this.config, options);
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
function terraform() {
|
|
560
|
+
return new TerraformConfigBuilder();
|
|
561
|
+
}
|
|
562
|
+
var backends = {
|
|
563
|
+
/**
|
|
564
|
+
* S3 backend configuration
|
|
565
|
+
*/
|
|
566
|
+
s3: (config) => ({
|
|
567
|
+
type: "s3",
|
|
568
|
+
config: {
|
|
569
|
+
bucket: config.bucket,
|
|
570
|
+
key: config.key,
|
|
571
|
+
region: config.region,
|
|
572
|
+
encrypt: config.encrypt ?? true,
|
|
573
|
+
...config.dynamodb_table ? { dynamodb_table: config.dynamodb_table } : {}
|
|
574
|
+
}
|
|
575
|
+
}),
|
|
576
|
+
/**
|
|
577
|
+
* GCS backend configuration
|
|
578
|
+
*/
|
|
579
|
+
gcs: (config) => ({
|
|
580
|
+
type: "gcs",
|
|
581
|
+
config: {
|
|
582
|
+
bucket: config.bucket,
|
|
583
|
+
prefix: config.prefix
|
|
584
|
+
}
|
|
585
|
+
}),
|
|
586
|
+
/**
|
|
587
|
+
* Azure backend configuration
|
|
588
|
+
*/
|
|
589
|
+
azurerm: (config) => ({
|
|
590
|
+
type: "azurerm",
|
|
591
|
+
config
|
|
592
|
+
}),
|
|
593
|
+
/**
|
|
594
|
+
* Local backend configuration
|
|
595
|
+
*/
|
|
596
|
+
local: (path) => ({
|
|
597
|
+
type: "local",
|
|
598
|
+
config: path ? { path } : {}
|
|
599
|
+
}),
|
|
600
|
+
/**
|
|
601
|
+
* Terraform Cloud backend configuration
|
|
602
|
+
*/
|
|
603
|
+
cloud: (config) => ({
|
|
604
|
+
type: "cloud",
|
|
605
|
+
config: {
|
|
606
|
+
organization: config.organization,
|
|
607
|
+
workspaces: { name: config.workspaces.name }
|
|
608
|
+
}
|
|
609
|
+
})
|
|
610
|
+
};
|
|
611
|
+
var providers = {
|
|
612
|
+
/**
|
|
613
|
+
* AWS provider
|
|
614
|
+
*/
|
|
615
|
+
aws: (region, profile) => ({
|
|
616
|
+
provider: "aws",
|
|
617
|
+
config: {
|
|
618
|
+
region,
|
|
619
|
+
...profile ? { profile } : {}
|
|
620
|
+
}
|
|
621
|
+
}),
|
|
622
|
+
/**
|
|
623
|
+
* Cloudflare provider
|
|
624
|
+
*/
|
|
625
|
+
cloudflare: (apiToken) => ({
|
|
626
|
+
provider: "cloudflare",
|
|
627
|
+
config: apiToken ? { api_token: apiToken } : {}
|
|
628
|
+
}),
|
|
629
|
+
/**
|
|
630
|
+
* Google provider
|
|
631
|
+
*/
|
|
632
|
+
google: (project, region) => ({
|
|
633
|
+
provider: "google",
|
|
634
|
+
config: { project, region }
|
|
635
|
+
}),
|
|
636
|
+
/**
|
|
637
|
+
* Azure provider
|
|
638
|
+
*/
|
|
639
|
+
azurerm: (features = {}) => ({
|
|
640
|
+
provider: "azurerm",
|
|
641
|
+
config: { features }
|
|
642
|
+
})
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
// src/config/tfvars.ts
|
|
646
|
+
function generateTfvars(config) {
|
|
647
|
+
const content = formatForTfvars(config.values);
|
|
648
|
+
if (config.header) {
|
|
649
|
+
return `${config.header}
|
|
650
|
+
|
|
651
|
+
${content}`;
|
|
652
|
+
}
|
|
653
|
+
return content;
|
|
654
|
+
}
|
|
655
|
+
function generateEnvTfvars(environment, values, options = {}) {
|
|
656
|
+
const header = options.header !== false ? `# ${environment} environment configuration` : void 0;
|
|
657
|
+
return {
|
|
658
|
+
filename: `${environment}.tfvars`,
|
|
659
|
+
content: generateTfvars({ values, header })
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
var TfvarsBuilder = class {
|
|
663
|
+
constructor() {
|
|
664
|
+
this.values = {};
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Set header comment
|
|
668
|
+
*/
|
|
669
|
+
withHeader(header) {
|
|
670
|
+
this.header = header;
|
|
671
|
+
return this;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Set a string variable
|
|
675
|
+
*/
|
|
676
|
+
string(name, value) {
|
|
677
|
+
this.values[name] = value;
|
|
678
|
+
return this;
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Set a number variable
|
|
682
|
+
*/
|
|
683
|
+
number(name, value) {
|
|
684
|
+
this.values[name] = value;
|
|
685
|
+
return this;
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Set a boolean variable
|
|
689
|
+
*/
|
|
690
|
+
bool(name, value) {
|
|
691
|
+
this.values[name] = value;
|
|
692
|
+
return this;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Set a list variable
|
|
696
|
+
*/
|
|
697
|
+
list(name, value) {
|
|
698
|
+
this.values[name] = value;
|
|
699
|
+
return this;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Set a map variable
|
|
703
|
+
*/
|
|
704
|
+
map(name, value) {
|
|
705
|
+
this.values[name] = value;
|
|
706
|
+
return this;
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Set a variable of any type
|
|
710
|
+
*/
|
|
711
|
+
set(name, value) {
|
|
712
|
+
this.values[name] = value;
|
|
713
|
+
return this;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Set multiple variables at once
|
|
717
|
+
*/
|
|
718
|
+
setAll(values) {
|
|
719
|
+
Object.assign(this.values, values);
|
|
720
|
+
return this;
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Build the tfvars content
|
|
724
|
+
*/
|
|
725
|
+
build() {
|
|
726
|
+
return generateTfvars({ values: this.values, header: this.header });
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Get the values as an object
|
|
730
|
+
*/
|
|
731
|
+
toObject() {
|
|
732
|
+
return { ...this.values };
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
function tfvars() {
|
|
736
|
+
return new TfvarsBuilder();
|
|
737
|
+
}
|
|
738
|
+
function mergeTfvars(...sources) {
|
|
739
|
+
return Object.assign({}, ...sources);
|
|
740
|
+
}
|
|
741
|
+
function tfvarsFromEnv(mapping, env) {
|
|
742
|
+
const values = {};
|
|
743
|
+
for (const [tfvarName, envName] of Object.entries(mapping)) {
|
|
744
|
+
const value = env[envName];
|
|
745
|
+
if (value !== void 0) {
|
|
746
|
+
values[tfvarName] = value;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return values;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/config/backend.ts
|
|
753
|
+
var BackendBuilder = class {
|
|
754
|
+
constructor(type) {
|
|
755
|
+
this.config = {};
|
|
756
|
+
this.type = type;
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Set a configuration option
|
|
760
|
+
*/
|
|
761
|
+
set(key, value) {
|
|
762
|
+
this.config[key] = value;
|
|
763
|
+
return this;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Set multiple configuration options
|
|
767
|
+
*/
|
|
768
|
+
setAll(config) {
|
|
769
|
+
Object.assign(this.config, config);
|
|
770
|
+
return this;
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Build the backend configuration
|
|
774
|
+
*/
|
|
775
|
+
build() {
|
|
776
|
+
return {
|
|
777
|
+
type: this.type,
|
|
778
|
+
config: this.config
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
function backend(type) {
|
|
783
|
+
return new BackendBuilder(type);
|
|
784
|
+
}
|
|
785
|
+
function s3Backend(options) {
|
|
786
|
+
const config = {
|
|
787
|
+
bucket: options.bucket,
|
|
788
|
+
key: options.key,
|
|
789
|
+
region: options.region
|
|
790
|
+
};
|
|
791
|
+
if (options.encrypt !== void 0) config.encrypt = options.encrypt;
|
|
792
|
+
if (options.dynamodb_table) config.dynamodb_table = options.dynamodb_table;
|
|
793
|
+
if (options.workspace_key_prefix) config.workspace_key_prefix = options.workspace_key_prefix;
|
|
794
|
+
if (options.acl) config.acl = options.acl;
|
|
795
|
+
if (options.skip_credentials_validation !== void 0) {
|
|
796
|
+
config.skip_credentials_validation = options.skip_credentials_validation;
|
|
797
|
+
}
|
|
798
|
+
if (options.skip_metadata_api_check !== void 0) {
|
|
799
|
+
config.skip_metadata_api_check = options.skip_metadata_api_check;
|
|
800
|
+
}
|
|
801
|
+
if (options.skip_region_validation !== void 0) {
|
|
802
|
+
config.skip_region_validation = options.skip_region_validation;
|
|
803
|
+
}
|
|
804
|
+
if (options.profile) config.profile = options.profile;
|
|
805
|
+
if (options.role_arn) config.role_arn = options.role_arn;
|
|
806
|
+
return { type: "s3", config };
|
|
807
|
+
}
|
|
808
|
+
function gcsBackend(options) {
|
|
809
|
+
const config = {
|
|
810
|
+
bucket: options.bucket
|
|
811
|
+
};
|
|
812
|
+
if (options.prefix) config.prefix = options.prefix;
|
|
813
|
+
if (options.credentials) config.credentials = options.credentials;
|
|
814
|
+
if (options.encryption_key) config.encryption_key = options.encryption_key;
|
|
815
|
+
return { type: "gcs", config };
|
|
816
|
+
}
|
|
817
|
+
function azureBackend(options) {
|
|
818
|
+
const config = {
|
|
819
|
+
resource_group_name: options.resource_group_name,
|
|
820
|
+
storage_account_name: options.storage_account_name,
|
|
821
|
+
container_name: options.container_name,
|
|
822
|
+
key: options.key
|
|
823
|
+
};
|
|
824
|
+
if (options.access_key) config.access_key = options.access_key;
|
|
825
|
+
if (options.sas_token) config.sas_token = options.sas_token;
|
|
826
|
+
if (options.use_oidc !== void 0) config.use_oidc = options.use_oidc;
|
|
827
|
+
if (options.subscription_id) config.subscription_id = options.subscription_id;
|
|
828
|
+
if (options.tenant_id) config.tenant_id = options.tenant_id;
|
|
829
|
+
if (options.client_id) config.client_id = options.client_id;
|
|
830
|
+
return { type: "azurerm", config };
|
|
831
|
+
}
|
|
832
|
+
function terraformCloudBackend(options) {
|
|
833
|
+
const config = {
|
|
834
|
+
organization: options.organization,
|
|
835
|
+
workspaces: options.workspaces
|
|
836
|
+
};
|
|
837
|
+
if (options.hostname) config.hostname = options.hostname;
|
|
838
|
+
if (options.token) config.token = options.token;
|
|
839
|
+
return { type: "cloud", config };
|
|
840
|
+
}
|
|
841
|
+
function localBackend(path) {
|
|
842
|
+
return {
|
|
843
|
+
type: "local",
|
|
844
|
+
config: path ? { path } : {}
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
function consulBackend(options) {
|
|
848
|
+
const config = {
|
|
849
|
+
address: options.address,
|
|
850
|
+
path: options.path
|
|
851
|
+
};
|
|
852
|
+
if (options.scheme) config.scheme = options.scheme;
|
|
853
|
+
if (options.datacenter) config.datacenter = options.datacenter;
|
|
854
|
+
if (options.access_token) config.access_token = options.access_token;
|
|
855
|
+
if (options.gzip !== void 0) config.gzip = options.gzip;
|
|
856
|
+
if (options.lock !== void 0) config.lock = options.lock;
|
|
857
|
+
return { type: "consul", config };
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// src/modules/types.ts
|
|
861
|
+
function defineModule(source, version) {
|
|
862
|
+
return {
|
|
863
|
+
source,
|
|
864
|
+
version,
|
|
865
|
+
inputs: {},
|
|
866
|
+
outputs: {}
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
function useModule(definition, name, inputs) {
|
|
870
|
+
const config = {
|
|
871
|
+
name,
|
|
872
|
+
source: definition.source,
|
|
873
|
+
version: definition.version,
|
|
874
|
+
config: inputs
|
|
875
|
+
};
|
|
876
|
+
return {
|
|
877
|
+
name,
|
|
878
|
+
output(key) {
|
|
879
|
+
return expr(`module.${name}.${String(key)}`);
|
|
880
|
+
},
|
|
881
|
+
config
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
function moduleOutput(moduleName, outputName) {
|
|
885
|
+
return expr(`module.${moduleName}.${outputName}`);
|
|
886
|
+
}
|
|
887
|
+
function resourceRef(type, name, attribute) {
|
|
888
|
+
return expr(`${type}.${name}.${attribute}`);
|
|
889
|
+
}
|
|
890
|
+
function dataRef(type, name, attribute) {
|
|
891
|
+
return expr(`data.${type}.${name}.${attribute}`);
|
|
892
|
+
}
|
|
893
|
+
function varRef(name) {
|
|
894
|
+
return expr(`var.${name}`);
|
|
895
|
+
}
|
|
896
|
+
function localRef(name) {
|
|
897
|
+
return expr(`local.${name}`);
|
|
898
|
+
}
|
|
899
|
+
var tf = {
|
|
900
|
+
/** file() function */
|
|
901
|
+
file: (path) => expr(`file("${path}")`),
|
|
902
|
+
/** templatefile() function */
|
|
903
|
+
templatefile: (path, vars) => expr(`templatefile("${path}", ${vars})`),
|
|
904
|
+
/** jsonencode() function */
|
|
905
|
+
jsonencode: (value) => expr(`jsonencode(${value})`),
|
|
906
|
+
/** jsondecode() function */
|
|
907
|
+
jsondecode: (value) => expr(`jsondecode(${value})`),
|
|
908
|
+
/** lookup() function */
|
|
909
|
+
lookup: (map, key, defaultValue) => defaultValue !== void 0 ? expr(`lookup(${map}, "${key}", ${defaultValue})`) : expr(`lookup(${map}, "${key}")`),
|
|
910
|
+
/** element() function */
|
|
911
|
+
element: (list, index) => expr(`element(${list}, ${index})`),
|
|
912
|
+
/** length() function */
|
|
913
|
+
length: (value) => expr(`length(${value})`),
|
|
914
|
+
/** coalesce() function */
|
|
915
|
+
coalesce: (...values) => expr(`coalesce(${values.join(", ")})`),
|
|
916
|
+
/** join() function */
|
|
917
|
+
join: (separator, list) => expr(`join("${separator}", ${list})`),
|
|
918
|
+
/** split() function */
|
|
919
|
+
split: (separator, value) => expr(`split("${separator}", ${value})`),
|
|
920
|
+
/** format() function */
|
|
921
|
+
format: (formatStr, ...args) => expr(`format("${formatStr}", ${args.join(", ")})`),
|
|
922
|
+
/** each.key */
|
|
923
|
+
eachKey: expr("each.key"),
|
|
924
|
+
/** each.value */
|
|
925
|
+
eachValue: expr("each.value"),
|
|
926
|
+
/** count.index */
|
|
927
|
+
countIndex: expr("count.index"),
|
|
928
|
+
/** self reference */
|
|
929
|
+
self: (attribute) => expr(`self.${attribute}`),
|
|
930
|
+
/** path.module */
|
|
931
|
+
pathModule: expr("path.module"),
|
|
932
|
+
/** path.root */
|
|
933
|
+
pathRoot: expr("path.root"),
|
|
934
|
+
/** path.cwd */
|
|
935
|
+
pathCwd: expr("path.cwd"),
|
|
936
|
+
/** terraform.workspace */
|
|
937
|
+
workspace: expr("terraform.workspace")
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
// src/modules/cloudflare/worker.ts
|
|
941
|
+
function cloudflareWorkerScript(config) {
|
|
942
|
+
const resourceConfig = {
|
|
943
|
+
account_id: config.accountId,
|
|
944
|
+
name: config.name,
|
|
945
|
+
content: config.content,
|
|
946
|
+
module: config.module ?? true
|
|
947
|
+
};
|
|
948
|
+
if (config.compatibilityDate) {
|
|
949
|
+
resourceConfig.compatibility_date = config.compatibilityDate;
|
|
950
|
+
}
|
|
951
|
+
if (config.compatibilityFlags?.length) {
|
|
952
|
+
resourceConfig.compatibility_flags = config.compatibilityFlags;
|
|
953
|
+
}
|
|
954
|
+
if (config.logpush !== void 0) {
|
|
955
|
+
resourceConfig.logpush = config.logpush;
|
|
956
|
+
}
|
|
957
|
+
const bindings = [];
|
|
958
|
+
if (config.kvNamespaces?.length) {
|
|
959
|
+
for (const kv of config.kvNamespaces) {
|
|
960
|
+
bindings.push({
|
|
961
|
+
type: "kv_namespace",
|
|
962
|
+
name: kv.name,
|
|
963
|
+
namespace_id: kv.namespaceId
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
if (config.d1Databases?.length) {
|
|
968
|
+
for (const d1 of config.d1Databases) {
|
|
969
|
+
bindings.push({
|
|
970
|
+
type: "d1_database",
|
|
971
|
+
name: d1.name,
|
|
972
|
+
database_id: d1.databaseId
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (config.r2Buckets?.length) {
|
|
977
|
+
for (const r2 of config.r2Buckets) {
|
|
978
|
+
bindings.push({
|
|
979
|
+
type: "r2_bucket",
|
|
980
|
+
name: r2.name,
|
|
981
|
+
bucket_name: r2.bucketName
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
if (config.plainTextBindings) {
|
|
986
|
+
for (const [name, value] of Object.entries(config.plainTextBindings)) {
|
|
987
|
+
bindings.push({
|
|
988
|
+
type: "plain_text",
|
|
989
|
+
name,
|
|
990
|
+
text: value
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
if (config.secretTextBindings) {
|
|
995
|
+
for (const [name, value] of Object.entries(config.secretTextBindings)) {
|
|
996
|
+
bindings.push({
|
|
997
|
+
type: "secret_text",
|
|
998
|
+
name,
|
|
999
|
+
text: value
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
if (config.serviceBindings?.length) {
|
|
1004
|
+
for (const svc of config.serviceBindings) {
|
|
1005
|
+
bindings.push({
|
|
1006
|
+
type: "service",
|
|
1007
|
+
name: svc.name,
|
|
1008
|
+
service: svc.service,
|
|
1009
|
+
...svc.environment ? { environment: svc.environment } : {}
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
if (bindings.length > 0) {
|
|
1014
|
+
resourceConfig.bindings = bindings;
|
|
1015
|
+
}
|
|
1016
|
+
return {
|
|
1017
|
+
type: "cloudflare_workers_script",
|
|
1018
|
+
name: config.name.replace(/-/g, "_"),
|
|
1019
|
+
config: resourceConfig
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
function cloudflareWorkerRoute(config) {
|
|
1023
|
+
const routeName = config.pattern.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
1024
|
+
return {
|
|
1025
|
+
type: "cloudflare_workers_route",
|
|
1026
|
+
name: routeName,
|
|
1027
|
+
config: {
|
|
1028
|
+
zone_id: config.zoneId,
|
|
1029
|
+
pattern: config.pattern,
|
|
1030
|
+
script_name: config.scriptName
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
function cloudflareWorkerDomain(config) {
|
|
1035
|
+
const domainName = config.hostname.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1036
|
+
return {
|
|
1037
|
+
type: "cloudflare_workers_domain",
|
|
1038
|
+
name: domainName,
|
|
1039
|
+
config: {
|
|
1040
|
+
account_id: config.accountId,
|
|
1041
|
+
zone_id: config.zoneId,
|
|
1042
|
+
hostname: config.hostname,
|
|
1043
|
+
service: config.service,
|
|
1044
|
+
environment: config.environment ?? "production"
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
function workerScriptRef(name, attribute = "id") {
|
|
1049
|
+
return expr(`cloudflare_workers_script.${name}.${attribute}`);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// src/modules/cloudflare/kv.ts
|
|
1053
|
+
function cloudflareKvNamespace(config) {
|
|
1054
|
+
const resourceName = config.title.toLowerCase().replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
1055
|
+
return {
|
|
1056
|
+
type: "cloudflare_workers_kv_namespace",
|
|
1057
|
+
name: resourceName,
|
|
1058
|
+
config: {
|
|
1059
|
+
account_id: config.accountId,
|
|
1060
|
+
title: config.title
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
function cloudflareKvPair(config) {
|
|
1065
|
+
const resourceName = config.key.toLowerCase().replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
1066
|
+
return {
|
|
1067
|
+
type: "cloudflare_workers_kv",
|
|
1068
|
+
name: resourceName,
|
|
1069
|
+
config: {
|
|
1070
|
+
account_id: config.accountId,
|
|
1071
|
+
namespace_id: config.namespaceId,
|
|
1072
|
+
key: config.key,
|
|
1073
|
+
value: config.value
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
function kvNamespaceRef(name, attribute = "id") {
|
|
1078
|
+
return expr(`cloudflare_workers_kv_namespace.${name}.${attribute}`);
|
|
1079
|
+
}
|
|
1080
|
+
function cloudflareKvNamespaces(accountId, baseName, environments = ["production", "staging", "development"]) {
|
|
1081
|
+
return environments.map((env) => ({
|
|
1082
|
+
type: "cloudflare_workers_kv_namespace",
|
|
1083
|
+
name: `${baseName.replace(/-/g, "_")}_${env}`,
|
|
1084
|
+
config: {
|
|
1085
|
+
account_id: accountId,
|
|
1086
|
+
title: `${baseName}-${env}`
|
|
1087
|
+
}
|
|
1088
|
+
}));
|
|
1089
|
+
}
|
|
1090
|
+
function cloudflareKvBulk(config) {
|
|
1091
|
+
const prefix = config.namePrefix ?? "kv";
|
|
1092
|
+
return Object.entries(config.entries).map(([key, value], index) => ({
|
|
1093
|
+
type: "cloudflare_workers_kv",
|
|
1094
|
+
name: `${prefix}_${index}`,
|
|
1095
|
+
config: {
|
|
1096
|
+
account_id: config.accountId,
|
|
1097
|
+
namespace_id: config.namespaceId,
|
|
1098
|
+
key,
|
|
1099
|
+
value
|
|
1100
|
+
}
|
|
1101
|
+
}));
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// src/modules/cloudflare/d1.ts
|
|
1105
|
+
function cloudflareD1Database(config) {
|
|
1106
|
+
const resourceName = config.name.toLowerCase().replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
1107
|
+
return {
|
|
1108
|
+
type: "cloudflare_d1_database",
|
|
1109
|
+
name: resourceName,
|
|
1110
|
+
config: {
|
|
1111
|
+
account_id: config.accountId,
|
|
1112
|
+
name: config.name
|
|
1113
|
+
}
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
function d1DatabaseRef(name, attribute = "id") {
|
|
1117
|
+
return expr(`cloudflare_d1_database.${name}.${attribute}`);
|
|
1118
|
+
}
|
|
1119
|
+
function cloudflareD1Databases(accountId, baseName, environments = ["production", "staging", "development"]) {
|
|
1120
|
+
return environments.map((env) => ({
|
|
1121
|
+
type: "cloudflare_d1_database",
|
|
1122
|
+
name: `${baseName.replace(/-/g, "_")}_${env}`,
|
|
1123
|
+
config: {
|
|
1124
|
+
account_id: accountId,
|
|
1125
|
+
name: `${baseName}-${env}`
|
|
1126
|
+
}
|
|
1127
|
+
}));
|
|
1128
|
+
}
|
|
1129
|
+
function d1DatabaseOutputs(config) {
|
|
1130
|
+
const prefix = config.prefix ?? config.resourceName;
|
|
1131
|
+
return {
|
|
1132
|
+
[`${prefix}_id`]: {
|
|
1133
|
+
value: d1DatabaseRef(config.resourceName, "id"),
|
|
1134
|
+
description: `ID of the ${config.resourceName} D1 database`
|
|
1135
|
+
},
|
|
1136
|
+
[`${prefix}_name`]: {
|
|
1137
|
+
value: d1DatabaseRef(config.resourceName, "name"),
|
|
1138
|
+
description: `Name of the ${config.resourceName} D1 database`
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
// src/modules/cloudflare/r2.ts
|
|
1144
|
+
function cloudflareR2Bucket(config) {
|
|
1145
|
+
const resourceName = config.name.toLowerCase().replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
1146
|
+
const resourceConfig = {
|
|
1147
|
+
account_id: config.accountId,
|
|
1148
|
+
name: config.name
|
|
1149
|
+
};
|
|
1150
|
+
if (config.location) {
|
|
1151
|
+
resourceConfig.location = config.location;
|
|
1152
|
+
}
|
|
1153
|
+
return {
|
|
1154
|
+
type: "cloudflare_r2_bucket",
|
|
1155
|
+
name: resourceName,
|
|
1156
|
+
config: resourceConfig
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
function r2BucketRef(name, attribute = "name") {
|
|
1160
|
+
return expr(`cloudflare_r2_bucket.${name}.${attribute}`);
|
|
1161
|
+
}
|
|
1162
|
+
function cloudflareR2Buckets(accountId, buckets) {
|
|
1163
|
+
return buckets.map((bucket) => cloudflareR2Bucket({
|
|
1164
|
+
accountId,
|
|
1165
|
+
name: bucket.name,
|
|
1166
|
+
location: bucket.location
|
|
1167
|
+
}));
|
|
1168
|
+
}
|
|
1169
|
+
function r2BucketOutputs(resourceName, prefix) {
|
|
1170
|
+
const outputPrefix = prefix ?? resourceName;
|
|
1171
|
+
return {
|
|
1172
|
+
[`${outputPrefix}_name`]: {
|
|
1173
|
+
value: r2BucketRef(resourceName, "name"),
|
|
1174
|
+
description: `Name of the ${resourceName} R2 bucket`
|
|
1175
|
+
},
|
|
1176
|
+
[`${outputPrefix}_id`]: {
|
|
1177
|
+
value: r2BucketRef(resourceName, "id"),
|
|
1178
|
+
description: `ID of the ${resourceName} R2 bucket`
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
function cloudflareR2BucketsForEnvs(accountId, baseName, environments = ["production", "staging", "development"], location) {
|
|
1183
|
+
return environments.map((env) => ({
|
|
1184
|
+
type: "cloudflare_r2_bucket",
|
|
1185
|
+
name: `${baseName.replace(/-/g, "_")}_${env}`,
|
|
1186
|
+
config: {
|
|
1187
|
+
account_id: accountId,
|
|
1188
|
+
name: `${baseName}-${env}`,
|
|
1189
|
+
...location ? { location } : {}
|
|
1190
|
+
}
|
|
1191
|
+
}));
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// src/modules/cloudflare/index.ts
|
|
1195
|
+
var cloudflareProvider = {
|
|
1196
|
+
source: "cloudflare/cloudflare",
|
|
1197
|
+
version: "~> 4.0"
|
|
1198
|
+
};
|
|
1199
|
+
var cloudflareVariables = {
|
|
1200
|
+
account_id: {
|
|
1201
|
+
type: "string",
|
|
1202
|
+
description: "Cloudflare Account ID",
|
|
1203
|
+
sensitive: true
|
|
1204
|
+
},
|
|
1205
|
+
api_token: {
|
|
1206
|
+
type: "string",
|
|
1207
|
+
description: "Cloudflare API Token",
|
|
1208
|
+
sensitive: true
|
|
1209
|
+
},
|
|
1210
|
+
zone_id: {
|
|
1211
|
+
type: "string",
|
|
1212
|
+
description: "Cloudflare Zone ID"
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
var cfAccountId = expr("var.cloudflare_account_id");
|
|
1216
|
+
var cfZoneId = expr("var.cloudflare_zone_id");
|
|
1217
|
+
export {
|
|
1218
|
+
BackendBuilder,
|
|
1219
|
+
TerraformConfigBuilder,
|
|
1220
|
+
TfvarsBuilder,
|
|
1221
|
+
azureBackend,
|
|
1222
|
+
backend,
|
|
1223
|
+
backends,
|
|
1224
|
+
cfAccountId,
|
|
1225
|
+
cfZoneId,
|
|
1226
|
+
cloudflareD1Database,
|
|
1227
|
+
cloudflareD1Databases,
|
|
1228
|
+
cloudflareKvBulk,
|
|
1229
|
+
cloudflareKvNamespace,
|
|
1230
|
+
cloudflareKvNamespaces,
|
|
1231
|
+
cloudflareKvPair,
|
|
1232
|
+
cloudflareProvider,
|
|
1233
|
+
cloudflareR2Bucket,
|
|
1234
|
+
cloudflareR2Buckets,
|
|
1235
|
+
cloudflareR2BucketsForEnvs,
|
|
1236
|
+
cloudflareVariables,
|
|
1237
|
+
cloudflareWorkerDomain,
|
|
1238
|
+
cloudflareWorkerRoute,
|
|
1239
|
+
cloudflareWorkerScript,
|
|
1240
|
+
consulBackend,
|
|
1241
|
+
createFileWriter,
|
|
1242
|
+
d1DatabaseOutputs,
|
|
1243
|
+
d1DatabaseRef,
|
|
1244
|
+
dataRef,
|
|
1245
|
+
defineModule,
|
|
1246
|
+
expr,
|
|
1247
|
+
formatBlock,
|
|
1248
|
+
formatForTfvars,
|
|
1249
|
+
gcsBackend,
|
|
1250
|
+
generateDataSource,
|
|
1251
|
+
generateEnvTfvars,
|
|
1252
|
+
generateLocals,
|
|
1253
|
+
generateModule,
|
|
1254
|
+
generateOutput,
|
|
1255
|
+
generateProvider,
|
|
1256
|
+
generateResource,
|
|
1257
|
+
generateTerraformBlock,
|
|
1258
|
+
generateTerraformConfig,
|
|
1259
|
+
generateTerraformFile,
|
|
1260
|
+
generateTerraformFiles,
|
|
1261
|
+
generateTfvars,
|
|
1262
|
+
generateVariable,
|
|
1263
|
+
isHclExpression,
|
|
1264
|
+
kvNamespaceRef,
|
|
1265
|
+
localBackend,
|
|
1266
|
+
localRef,
|
|
1267
|
+
mergeTfvars,
|
|
1268
|
+
moduleOutput,
|
|
1269
|
+
providers,
|
|
1270
|
+
r2BucketOutputs,
|
|
1271
|
+
r2BucketRef,
|
|
1272
|
+
resourceRef,
|
|
1273
|
+
s3Backend,
|
|
1274
|
+
terraform,
|
|
1275
|
+
terraformCloudBackend,
|
|
1276
|
+
tf,
|
|
1277
|
+
tfvars,
|
|
1278
|
+
tfvarsFromEnv,
|
|
1279
|
+
toHcl,
|
|
1280
|
+
useModule,
|
|
1281
|
+
varRef,
|
|
1282
|
+
workerScriptRef
|
|
1283
|
+
};
|