@terraforge/terraform 0.0.7 → 0.0.8
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/cli/build-package.ts +41 -44
- package/dist/index.d.ts +19 -19
- package/dist/index.js +414 -400
- package/package.json +9 -2
package/cli/build-package.ts
CHANGED
|
@@ -1,61 +1,64 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import { parseArgs } from 'util'
|
|
4
3
|
import { createLazyPlugin } from '../src/lazy-plugin'
|
|
5
4
|
import { Version } from '../src/plugin/registry'
|
|
6
5
|
import { generateTypes } from '../src/type-gen'
|
|
7
6
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
strict: true,
|
|
19
|
-
allowPositionals: true,
|
|
20
|
-
})
|
|
7
|
+
const packageData = (await Bun.file('./package.json').json()) as {
|
|
8
|
+
version?: string
|
|
9
|
+
provider?: {
|
|
10
|
+
version?: Version
|
|
11
|
+
org?: string
|
|
12
|
+
type?: string
|
|
13
|
+
}
|
|
14
|
+
}
|
|
21
15
|
|
|
22
|
-
if (!
|
|
23
|
-
console.error('
|
|
16
|
+
if (!packageData || !packageData.provider) {
|
|
17
|
+
console.error('Failed to read package.json')
|
|
24
18
|
process.exit(1)
|
|
25
19
|
}
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
const providerData = packageData.provider
|
|
22
|
+
|
|
23
|
+
if (!providerData.version) {
|
|
24
|
+
console.error('Missing required arguments: version')
|
|
29
25
|
process.exit(1)
|
|
30
26
|
}
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (!packageData) {
|
|
35
|
-
console.error('Failed to read package.json')
|
|
28
|
+
if (!providerData.org) {
|
|
29
|
+
console.error('Missing required arguments: org')
|
|
36
30
|
process.exit(1)
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
if (!
|
|
40
|
-
console.error('Missing required arguments:
|
|
33
|
+
if (!providerData.type) {
|
|
34
|
+
console.error('Missing required arguments: type')
|
|
41
35
|
process.exit(1)
|
|
42
36
|
}
|
|
43
37
|
|
|
44
|
-
const org =
|
|
45
|
-
const type =
|
|
46
|
-
const version =
|
|
38
|
+
const org = providerData.org
|
|
39
|
+
const type = providerData.type
|
|
40
|
+
const version = providerData.version
|
|
47
41
|
|
|
48
|
-
console.log('
|
|
49
|
-
console.log('
|
|
50
|
-
console.log('
|
|
42
|
+
console.log('')
|
|
43
|
+
console.log('Package version: ', packageData.version)
|
|
44
|
+
console.log('')
|
|
45
|
+
console.log('Provider org: ', org)
|
|
46
|
+
console.log('Provider type: ', type)
|
|
47
|
+
console.log('Provider version: ', version)
|
|
48
|
+
console.log('')
|
|
51
49
|
|
|
52
50
|
const ok = confirm('Continue?')
|
|
53
51
|
|
|
54
52
|
if (!ok) {
|
|
55
|
-
|
|
53
|
+
console.log('')
|
|
54
|
+
process.exit(1)
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
const load = createLazyPlugin({ org, type, version })
|
|
58
|
+
|
|
59
|
+
console.log('')
|
|
60
|
+
console.log('Loading provider plugin...')
|
|
61
|
+
|
|
59
62
|
const plugin = await load()
|
|
60
63
|
const schema = plugin.schema()
|
|
61
64
|
const types = generateTypes(
|
|
@@ -68,24 +71,18 @@ const types = generateTypes(
|
|
|
68
71
|
|
|
69
72
|
await plugin.stop()
|
|
70
73
|
|
|
71
|
-
await Bun.write(`./
|
|
72
|
-
|
|
74
|
+
await Bun.write(`./dist/index.d.ts`, types)
|
|
73
75
|
await Bun.write(
|
|
74
|
-
`./
|
|
76
|
+
`./dist/index.js`,
|
|
75
77
|
`
|
|
76
78
|
import { createTerraformAPI } from '@terraforge/terraform'
|
|
77
|
-
import { root } from './types.ts'
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
export const ${type} = createTerraformAPI<typeof root.${type}>({
|
|
80
|
+
export const ${type} = createTerraformAPI({
|
|
81
81
|
namespace: '${type}',
|
|
82
82
|
provider: { org: '${org}', type: '${type}', version: '${version}' },
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
declare module '@terraforge/${type}' {
|
|
86
|
-
import ${type} = root.${type}
|
|
87
|
-
// @ts-ignore
|
|
88
|
-
export { ${type} }
|
|
89
|
-
}
|
|
83
|
+
})
|
|
90
84
|
`
|
|
91
85
|
)
|
|
86
|
+
|
|
87
|
+
console.log('Done.')
|
|
88
|
+
process.exit(0)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,5 @@
|
|
|
1
1
|
import { Provider, State as State$1, GetProps, CreateProps, UpdateProps, DeleteProps, GetDataProps } from '@terraforge/core';
|
|
2
2
|
|
|
3
|
-
type Version = `${number}.${number}.${number}` | 'latest';
|
|
4
|
-
|
|
5
|
-
type TerraformProviderConfig = {
|
|
6
|
-
id?: string;
|
|
7
|
-
location?: string;
|
|
8
|
-
};
|
|
9
|
-
type InstallProps = {
|
|
10
|
-
location?: string;
|
|
11
|
-
};
|
|
12
|
-
declare const createTerraformAPI: <T>(props: {
|
|
13
|
-
namespace: string;
|
|
14
|
-
provider: {
|
|
15
|
-
org: string;
|
|
16
|
-
type: string;
|
|
17
|
-
version: Version;
|
|
18
|
-
};
|
|
19
|
-
}) => T;
|
|
20
|
-
|
|
21
3
|
type Property = {
|
|
22
4
|
description?: string;
|
|
23
5
|
required?: boolean;
|
|
@@ -89,4 +71,22 @@ declare class TerraformProvider implements Provider {
|
|
|
89
71
|
}>;
|
|
90
72
|
}
|
|
91
73
|
|
|
92
|
-
|
|
74
|
+
type Version = `${number}.${number}.${number}` | 'latest';
|
|
75
|
+
|
|
76
|
+
type TerraformProviderConfig = {
|
|
77
|
+
id?: string;
|
|
78
|
+
location?: string;
|
|
79
|
+
};
|
|
80
|
+
type InstallProps = {
|
|
81
|
+
location?: string;
|
|
82
|
+
};
|
|
83
|
+
declare const createTerraformProxy: (props: {
|
|
84
|
+
namespace: string;
|
|
85
|
+
provider: {
|
|
86
|
+
org: string;
|
|
87
|
+
type: string;
|
|
88
|
+
version: Version;
|
|
89
|
+
};
|
|
90
|
+
}) => () => void;
|
|
91
|
+
|
|
92
|
+
export { type InstallProps, TerraformProvider, type TerraformProviderConfig, createTerraformProxy, generateTypes };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,313 @@
|
|
|
1
|
+
// src/type-gen.ts
|
|
2
|
+
import { camelCase, pascalCase } from "change-case";
|
|
3
|
+
var tab = (indent) => {
|
|
4
|
+
return " ".repeat(indent);
|
|
5
|
+
};
|
|
6
|
+
var generateTypes = (providers, resources, dataSources) => {
|
|
7
|
+
return [
|
|
8
|
+
generateImport("c", "@terraforge/core"),
|
|
9
|
+
generateImport("t", "@terraforge/terraform"),
|
|
10
|
+
"type _Record<T> = Record<string, T>",
|
|
11
|
+
generateInstallFunction(providers),
|
|
12
|
+
generateNamespace(providers, (name, prop, indent) => {
|
|
13
|
+
const typeName = name.toLowerCase();
|
|
14
|
+
return `${tab(indent)}export declare function ${typeName}(props: ${generatePropertyInputConst(prop, indent)}, config?: t.TerraformProviderConfig): t.TerraformProvider`;
|
|
15
|
+
}),
|
|
16
|
+
generateNamespace(resources, (name, prop, indent) => {
|
|
17
|
+
const typeName = pascalCase(name);
|
|
18
|
+
return [
|
|
19
|
+
// `${tab(indent)}export type ${typeName}Input = ${generatePropertyInputType(prop, indent)}`,
|
|
20
|
+
// `${tab(indent)}export type ${typeName}Output = ${generatePropertyOutputType(prop, indent)}`,
|
|
21
|
+
// `${tab(indent)}export declare const ${typeName}: ResourceClass<${typeName}Input, ${typeName}Output>`,
|
|
22
|
+
`${tab(indent)}export type ${typeName}Input = ${generatePropertyInputType(prop, indent)}`,
|
|
23
|
+
`${tab(indent)}export type ${typeName}Output = ${generatePropertyOutputType(prop, indent)}`,
|
|
24
|
+
`${tab(indent)}export class ${typeName} {`,
|
|
25
|
+
`${tab(indent + 1)}constructor(parent: c.Group, id: string, props: ${typeName}Input, config?:c.ResourceConfig)`,
|
|
26
|
+
// `${tab(indent + 1)}readonly $: c.ResourceMeta<${typeName}Input, ${typeName}Output>`,
|
|
27
|
+
generateClassProperties(prop, indent + 1),
|
|
28
|
+
`${tab(indent)}}`
|
|
29
|
+
].join("\n\n");
|
|
30
|
+
}),
|
|
31
|
+
generateNamespace(dataSources, (name, prop, indent) => {
|
|
32
|
+
const typeName = pascalCase(name);
|
|
33
|
+
return [
|
|
34
|
+
`${tab(indent)}export type Get${typeName}Input = ${generatePropertyInputType(prop, indent)}`,
|
|
35
|
+
`${tab(indent)}export type Get${typeName}Output = ${generatePropertyOutputType(prop, indent)}`,
|
|
36
|
+
`${tab(indent)}export const get${typeName}:c.DataSourceFunction<Get${typeName}Input, Get${typeName}Output>`
|
|
37
|
+
].join("\n\n");
|
|
38
|
+
})
|
|
39
|
+
].join("\n\n");
|
|
40
|
+
};
|
|
41
|
+
var generateImport = (name, from) => {
|
|
42
|
+
return `import * as ${name} from '${from}'`;
|
|
43
|
+
};
|
|
44
|
+
var generateInstallFunction = (resources) => {
|
|
45
|
+
return generateNamespace(resources, (name, _prop, indent) => {
|
|
46
|
+
const typeName = name.toLowerCase();
|
|
47
|
+
return `${tab(indent)}export declare namespace ${typeName} { export function install(props?: t.InstallProps): Promise<void> }`;
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
var generatePropertyInputConst = (prop, indent) => {
|
|
51
|
+
return generateValue(prop, {
|
|
52
|
+
depth: 0,
|
|
53
|
+
indent: indent + 1,
|
|
54
|
+
wrap: (v, _, ctx) => {
|
|
55
|
+
return `${v}${ctx.depth === 1 ? "," : ""}`;
|
|
56
|
+
},
|
|
57
|
+
filter: () => true,
|
|
58
|
+
optional: (p) => p.optional ?? false
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
var generatePropertyInputType = (prop, indent) => {
|
|
62
|
+
return generateValue(prop, {
|
|
63
|
+
depth: 0,
|
|
64
|
+
indent: indent + 1,
|
|
65
|
+
wrap: (v, p, ctx) => {
|
|
66
|
+
return ctx.depth > 0 ? p.optional ? `c.OptionalInput<${v}>` : `c.Input<${v}>` : v;
|
|
67
|
+
},
|
|
68
|
+
filter: (prop2) => !(prop2.computed && typeof prop2.optional === "undefined" && typeof prop2.required === "undefined"),
|
|
69
|
+
optional: (p) => p.optional ?? false
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
var generatePropertyOutputType = (prop, indent) => {
|
|
73
|
+
return generateValue(prop, {
|
|
74
|
+
indent: indent + 1,
|
|
75
|
+
depth: 0,
|
|
76
|
+
wrap: (v, p, ctx) => ctx.depth === 1 ? p.optional && !p.computed ? `c.OptionalOutput<${v}>` : `c.Output<${v}>` : v,
|
|
77
|
+
filter: () => true,
|
|
78
|
+
readonly: true,
|
|
79
|
+
// required: true,
|
|
80
|
+
optional: (p, ctx) => ctx.depth > 1 && p.optional && !p.computed || false
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
var generateClassProperties = (prop, indent) => {
|
|
84
|
+
if (prop.type !== "object") {
|
|
85
|
+
return "";
|
|
86
|
+
}
|
|
87
|
+
return Object.entries(prop.properties).map(([name, prop2]) => {
|
|
88
|
+
return [
|
|
89
|
+
prop2.description ? [`
|
|
90
|
+
`, ` `.repeat(indent), `/** `, prop2.description.trim(), " */", "\n"].join("") : "",
|
|
91
|
+
` `.repeat(indent),
|
|
92
|
+
"readonly ",
|
|
93
|
+
camelCase(name),
|
|
94
|
+
// ctx.optional(prop, ctx) ? '?' : '',
|
|
95
|
+
": ",
|
|
96
|
+
generateValue(prop2, {
|
|
97
|
+
readonly: true,
|
|
98
|
+
filter: () => true,
|
|
99
|
+
optional: (p, ctx) => ctx.depth > 1 && p.optional && !p.computed || false,
|
|
100
|
+
wrap: (v, p, ctx) => {
|
|
101
|
+
return ctx.depth === 1 ? p.optional && !p.computed ? `c.OptionalOutput<${v}>` : `c.Output<${v}>` : v;
|
|
102
|
+
},
|
|
103
|
+
// ctx.depth === 1 ? `c.Output<${p.optional && !p.computed ? `${v} | undefined` : v}>` : v,
|
|
104
|
+
indent: indent + 1,
|
|
105
|
+
depth: 1
|
|
106
|
+
})
|
|
107
|
+
].join("");
|
|
108
|
+
}).join("\n");
|
|
109
|
+
};
|
|
110
|
+
var groupByNamespace = (resources, minLevel, maxLevel) => {
|
|
111
|
+
const grouped = {};
|
|
112
|
+
const types = Object.keys(resources).sort();
|
|
113
|
+
for (const type of types) {
|
|
114
|
+
const names = type.split("_");
|
|
115
|
+
if (names.length < minLevel) {
|
|
116
|
+
throw new Error(`Resource not properly namespaced: ${type}`);
|
|
117
|
+
}
|
|
118
|
+
let current = grouped;
|
|
119
|
+
let count = Math.min(maxLevel, names.length - 1);
|
|
120
|
+
while (count--) {
|
|
121
|
+
const ns = camelCase(names.shift());
|
|
122
|
+
if (!current[ns]) {
|
|
123
|
+
current[ns] = {};
|
|
124
|
+
}
|
|
125
|
+
current = current[ns];
|
|
126
|
+
}
|
|
127
|
+
const name = pascalCase(names.join("_"));
|
|
128
|
+
current[name] = type;
|
|
129
|
+
}
|
|
130
|
+
return grouped;
|
|
131
|
+
};
|
|
132
|
+
var generateNamespace = (resources, render) => {
|
|
133
|
+
const grouped = groupByNamespace(resources, 1, 2);
|
|
134
|
+
const renderNamespace = (name, group, indent) => {
|
|
135
|
+
if (name === "default") {
|
|
136
|
+
name = "$default";
|
|
137
|
+
}
|
|
138
|
+
if (typeof group === "string") {
|
|
139
|
+
return render(name, resources[group], indent);
|
|
140
|
+
}
|
|
141
|
+
return [
|
|
142
|
+
`${tab(indent)}export ${indent === 0 ? "declare " : ""}namespace ${name.toLowerCase()} {`,
|
|
143
|
+
Object.entries(group).map(([name2, entry]) => {
|
|
144
|
+
if (typeof entry !== "string") {
|
|
145
|
+
return renderNamespace(name2, entry, indent + 1);
|
|
146
|
+
} else {
|
|
147
|
+
return render(name2, resources[entry], indent + 1);
|
|
148
|
+
}
|
|
149
|
+
}).join("\n"),
|
|
150
|
+
`${tab(indent)}}`
|
|
151
|
+
].join("\n");
|
|
152
|
+
};
|
|
153
|
+
return Object.entries(grouped).map(([name, entry]) => {
|
|
154
|
+
return renderNamespace(name, entry, 0);
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
var generateValue = (prop, ctx) => {
|
|
158
|
+
if (["string", "number", "boolean", "unknown"].includes(prop.type)) {
|
|
159
|
+
return ctx.wrap(prop.type, prop, ctx);
|
|
160
|
+
}
|
|
161
|
+
if (prop.type === "array") {
|
|
162
|
+
const type = generateValue(prop.item, { ...ctx, depth: ctx.depth + 1 });
|
|
163
|
+
const array = ctx.readonly ? `ReadonlyArray<${type}>` : `Array<${type}>`;
|
|
164
|
+
return ctx.wrap(array, prop, ctx);
|
|
165
|
+
}
|
|
166
|
+
if (prop.type === "record") {
|
|
167
|
+
const type = generateValue(prop.item, { ...ctx, depth: ctx.depth + 1 });
|
|
168
|
+
const record = ctx.readonly ? `Readonly<_Record<${type}>>` : `_Record<${type}>`;
|
|
169
|
+
return ctx.wrap(record, prop, ctx);
|
|
170
|
+
}
|
|
171
|
+
if (prop.type === "object" || prop.type === "array-object") {
|
|
172
|
+
const type = [
|
|
173
|
+
"{",
|
|
174
|
+
Object.entries(prop.properties).filter(([_, p]) => ctx.filter(p)).map(
|
|
175
|
+
([name, prop2]) => [
|
|
176
|
+
prop2.description ? [`
|
|
177
|
+
`, ` `.repeat(ctx.indent), `/** `, prop2.description.trim(), " */", "\n"].join("") : "",
|
|
178
|
+
` `.repeat(ctx.indent),
|
|
179
|
+
// ctx.readonly ? "readonly " : "",
|
|
180
|
+
camelCase(name),
|
|
181
|
+
ctx.optional(prop2, ctx) ? "?" : "",
|
|
182
|
+
": ",
|
|
183
|
+
generateValue(prop2, { ...ctx, indent: ctx.indent + 1, depth: ctx.depth + 1 })
|
|
184
|
+
].join("")
|
|
185
|
+
).join("\n"),
|
|
186
|
+
`${` `.repeat(ctx.indent - 1)}}`
|
|
187
|
+
].join("\n");
|
|
188
|
+
const object = ctx.readonly ? `Readonly<${type}>` : type;
|
|
189
|
+
return ctx.wrap(object, prop, ctx);
|
|
190
|
+
}
|
|
191
|
+
throw new Error(`Unknown property type: ${prop.type}`);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// src/provider.ts
|
|
195
|
+
import {
|
|
196
|
+
ResourceNotFound
|
|
197
|
+
} from "@terraforge/core";
|
|
198
|
+
var TerraformProvider = class {
|
|
199
|
+
constructor(type, id, createPlugin, config) {
|
|
200
|
+
this.type = type;
|
|
201
|
+
this.id = id;
|
|
202
|
+
this.createPlugin = createPlugin;
|
|
203
|
+
this.config = config;
|
|
204
|
+
}
|
|
205
|
+
configured;
|
|
206
|
+
plugin;
|
|
207
|
+
async configure() {
|
|
208
|
+
const plugin = await this.prepare();
|
|
209
|
+
if (!this.configured) {
|
|
210
|
+
this.configured = plugin.configure(this.config);
|
|
211
|
+
}
|
|
212
|
+
await this.configured;
|
|
213
|
+
return plugin;
|
|
214
|
+
}
|
|
215
|
+
prepare() {
|
|
216
|
+
if (!this.plugin) {
|
|
217
|
+
this.plugin = this.createPlugin();
|
|
218
|
+
}
|
|
219
|
+
return this.plugin;
|
|
220
|
+
}
|
|
221
|
+
async destroy() {
|
|
222
|
+
if (this.plugin) {
|
|
223
|
+
const plugin = await this.plugin;
|
|
224
|
+
plugin.stop();
|
|
225
|
+
this.plugin = void 0;
|
|
226
|
+
this.configured = void 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
ownResource(id) {
|
|
230
|
+
return `terraform:${this.type}:${this.id}` === id;
|
|
231
|
+
}
|
|
232
|
+
async getResource({ type, state }) {
|
|
233
|
+
const plugin = await this.configure();
|
|
234
|
+
const newState = await plugin.readResource(type, state);
|
|
235
|
+
if (!newState) {
|
|
236
|
+
throw new ResourceNotFound();
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
version: 0,
|
|
240
|
+
state: newState
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async createResource({ type, state }) {
|
|
244
|
+
const plugin = await this.configure();
|
|
245
|
+
const newState = await plugin.applyResourceChange(type, null, state);
|
|
246
|
+
return {
|
|
247
|
+
version: 0,
|
|
248
|
+
state: newState
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
async updateResource({ type, priorState, proposedState }) {
|
|
252
|
+
const plugin = await this.configure();
|
|
253
|
+
const { requiresReplace } = await plugin.planResourceChange(type, priorState, proposedState);
|
|
254
|
+
if (requiresReplace.length > 0) {
|
|
255
|
+
const formattedAttrs = requiresReplace.map((p) => p.join(".")).join('", "');
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Updating the "${formattedAttrs}" properties for the "${type}" resource will require the resource to be replaced.`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
const newState = await plugin.applyResourceChange(type, priorState, proposedState);
|
|
261
|
+
return {
|
|
262
|
+
version: 0,
|
|
263
|
+
state: newState
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
async deleteResource({ type, state }) {
|
|
267
|
+
const plugin = await this.configure();
|
|
268
|
+
try {
|
|
269
|
+
await plugin.applyResourceChange(type, state, null);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
try {
|
|
272
|
+
const newState = await plugin.readResource(type, state);
|
|
273
|
+
if (!newState) {
|
|
274
|
+
throw new ResourceNotFound();
|
|
275
|
+
}
|
|
276
|
+
} catch (_) {
|
|
277
|
+
}
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async getData({ type, state }) {
|
|
282
|
+
const plugin = await this.configure();
|
|
283
|
+
const data = await plugin.readDataSource(type, state);
|
|
284
|
+
if (!data) {
|
|
285
|
+
throw new Error(`Data source not found ${type}`);
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
state: data
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
// async generateTypes(dir: string) {
|
|
292
|
+
// const plugin = await this.prepare()
|
|
293
|
+
// const schema = plugin.schema()
|
|
294
|
+
// const types = generateTypes(
|
|
295
|
+
// {
|
|
296
|
+
// [`${this.type}_provider`]: schema.provider,
|
|
297
|
+
// },
|
|
298
|
+
// schema.resources,
|
|
299
|
+
// schema.dataSources
|
|
300
|
+
// )
|
|
301
|
+
// await mkdir(dir, { recursive: true })
|
|
302
|
+
// await writeFile(join(dir, `${this.type}.d.ts`), types)
|
|
303
|
+
// await this.destroy()
|
|
304
|
+
// }
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
// src/proxy.ts
|
|
308
|
+
import { createMeta, nodeMetaSymbol } from "@terraforge/core";
|
|
309
|
+
import { snakeCase as snakeCase2 } from "change-case";
|
|
310
|
+
|
|
1
311
|
// src/plugin/client.ts
|
|
2
312
|
import { credentials, loadPackageDefinition } from "@grpc/grpc-js";
|
|
3
313
|
import { fromJSON } from "@grpc/proto-loader";
|
|
@@ -1090,7 +1400,7 @@ var parseType = (type) => {
|
|
|
1090
1400
|
};
|
|
1091
1401
|
|
|
1092
1402
|
// src/plugin/version/util.ts
|
|
1093
|
-
import { camelCase, snakeCase } from "change-case";
|
|
1403
|
+
import { camelCase as camelCase2, snakeCase } from "change-case";
|
|
1094
1404
|
import { pack, unpack } from "msgpackr";
|
|
1095
1405
|
var encodeDynamicValue = (value) => {
|
|
1096
1406
|
return {
|
|
@@ -1184,7 +1494,7 @@ var formatInputState = (schema, state, includeSchemaFields = true, path = []) =>
|
|
|
1184
1494
|
const object = {};
|
|
1185
1495
|
if (includeSchemaFields) {
|
|
1186
1496
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1187
|
-
const value = state[
|
|
1497
|
+
const value = state[camelCase2(key)];
|
|
1188
1498
|
object[key] = formatInputState(prop, value, true, [...path, key]);
|
|
1189
1499
|
}
|
|
1190
1500
|
} else {
|
|
@@ -1229,7 +1539,7 @@ var formatOutputState = (schema, state, path = []) => {
|
|
|
1229
1539
|
const object = {};
|
|
1230
1540
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1231
1541
|
const value = state[key];
|
|
1232
|
-
object[
|
|
1542
|
+
object[camelCase2(key)] = formatOutputState(prop, value, [...path, key]);
|
|
1233
1543
|
}
|
|
1234
1544
|
return object;
|
|
1235
1545
|
}
|
|
@@ -1241,7 +1551,7 @@ var formatOutputState = (schema, state, path = []) => {
|
|
|
1241
1551
|
const object = {};
|
|
1242
1552
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1243
1553
|
const value = state[0][key];
|
|
1244
|
-
object[
|
|
1554
|
+
object[camelCase2(key)] = formatOutputState(prop, value, [...path, key]);
|
|
1245
1555
|
}
|
|
1246
1556
|
return object;
|
|
1247
1557
|
} else {
|
|
@@ -1474,133 +1784,37 @@ var retry = async (tries, cb) => {
|
|
|
1474
1784
|
throw latestError;
|
|
1475
1785
|
};
|
|
1476
1786
|
|
|
1477
|
-
// src/
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
configured;
|
|
1489
|
-
plugin;
|
|
1490
|
-
async configure() {
|
|
1491
|
-
const plugin = await this.prepare();
|
|
1492
|
-
if (!this.configured) {
|
|
1493
|
-
this.configured = plugin.configure(this.config);
|
|
1494
|
-
}
|
|
1495
|
-
await this.configured;
|
|
1496
|
-
return plugin;
|
|
1497
|
-
}
|
|
1498
|
-
prepare() {
|
|
1499
|
-
if (!this.plugin) {
|
|
1500
|
-
this.plugin = this.createPlugin();
|
|
1501
|
-
}
|
|
1502
|
-
return this.plugin;
|
|
1503
|
-
}
|
|
1504
|
-
async destroy() {
|
|
1505
|
-
if (this.plugin) {
|
|
1506
|
-
const plugin = await this.plugin;
|
|
1507
|
-
plugin.stop();
|
|
1508
|
-
this.plugin = void 0;
|
|
1509
|
-
this.configured = void 0;
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
ownResource(id) {
|
|
1513
|
-
return `terraform:${this.type}:${this.id}` === id;
|
|
1514
|
-
}
|
|
1515
|
-
async getResource({ type, state }) {
|
|
1516
|
-
const plugin = await this.configure();
|
|
1517
|
-
const newState = await plugin.readResource(type, state);
|
|
1518
|
-
if (!newState) {
|
|
1519
|
-
throw new ResourceNotFound();
|
|
1520
|
-
}
|
|
1521
|
-
return {
|
|
1522
|
-
version: 0,
|
|
1523
|
-
state: newState
|
|
1524
|
-
};
|
|
1525
|
-
}
|
|
1526
|
-
async createResource({ type, state }) {
|
|
1527
|
-
const plugin = await this.configure();
|
|
1528
|
-
const newState = await plugin.applyResourceChange(type, null, state);
|
|
1529
|
-
return {
|
|
1530
|
-
version: 0,
|
|
1531
|
-
state: newState
|
|
1532
|
-
};
|
|
1533
|
-
}
|
|
1534
|
-
async updateResource({ type, priorState, proposedState }) {
|
|
1535
|
-
const plugin = await this.configure();
|
|
1536
|
-
const { requiresReplace } = await plugin.planResourceChange(type, priorState, proposedState);
|
|
1537
|
-
if (requiresReplace.length > 0) {
|
|
1538
|
-
const formattedAttrs = requiresReplace.map((p) => p.join(".")).join('", "');
|
|
1539
|
-
throw new Error(
|
|
1540
|
-
`Updating the "${formattedAttrs}" properties for the "${type}" resource will require the resource to be replaced.`
|
|
1541
|
-
);
|
|
1542
|
-
}
|
|
1543
|
-
const newState = await plugin.applyResourceChange(type, priorState, proposedState);
|
|
1544
|
-
return {
|
|
1545
|
-
version: 0,
|
|
1546
|
-
state: newState
|
|
1547
|
-
};
|
|
1548
|
-
}
|
|
1549
|
-
async deleteResource({ type, state }) {
|
|
1550
|
-
const plugin = await this.configure();
|
|
1551
|
-
try {
|
|
1552
|
-
await plugin.applyResourceChange(type, state, null);
|
|
1553
|
-
} catch (error) {
|
|
1554
|
-
try {
|
|
1555
|
-
const newState = await plugin.readResource(type, state);
|
|
1556
|
-
if (!newState) {
|
|
1557
|
-
throw new ResourceNotFound();
|
|
1787
|
+
// src/proxy.ts
|
|
1788
|
+
var createResourceProxy = (cb) => {
|
|
1789
|
+
return new Proxy(
|
|
1790
|
+
{},
|
|
1791
|
+
{
|
|
1792
|
+
get(_, key) {
|
|
1793
|
+
return cb(key);
|
|
1794
|
+
},
|
|
1795
|
+
set(_, key) {
|
|
1796
|
+
if (typeof key === "string") {
|
|
1797
|
+
throw new Error(`Cannot set property ${key} on read-only object.`);
|
|
1558
1798
|
}
|
|
1559
|
-
|
|
1799
|
+
throw new Error(`This object is read-only.`);
|
|
1560
1800
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
}
|
|
1564
|
-
async getData({ type, state }) {
|
|
1565
|
-
const plugin = await this.configure();
|
|
1566
|
-
const data = await plugin.readDataSource(type, state);
|
|
1567
|
-
if (!data) {
|
|
1568
|
-
throw new Error(`Data source not found ${type}`);
|
|
1569
|
-
}
|
|
1570
|
-
return {
|
|
1571
|
-
state: data
|
|
1572
|
-
};
|
|
1573
|
-
}
|
|
1574
|
-
// async generateTypes(dir: string) {
|
|
1575
|
-
// const plugin = await this.prepare()
|
|
1576
|
-
// const schema = plugin.schema()
|
|
1577
|
-
// const types = generateTypes(
|
|
1578
|
-
// {
|
|
1579
|
-
// [`${this.type}_provider`]: schema.provider,
|
|
1580
|
-
// },
|
|
1581
|
-
// schema.resources,
|
|
1582
|
-
// schema.dataSources
|
|
1583
|
-
// )
|
|
1584
|
-
// await mkdir(dir, { recursive: true })
|
|
1585
|
-
// await writeFile(join(dir, `${this.type}.d.ts`), types)
|
|
1586
|
-
// await this.destroy()
|
|
1587
|
-
// }
|
|
1801
|
+
}
|
|
1802
|
+
);
|
|
1588
1803
|
};
|
|
1589
|
-
|
|
1590
|
-
// src/resource.ts
|
|
1591
|
-
import { createMeta, nodeMetaSymbol } from "@terraforge/core";
|
|
1592
|
-
import { snakeCase as snakeCase2 } from "change-case";
|
|
1593
|
-
var createNamespaceProxy = (cb, scb) => {
|
|
1804
|
+
var createNamespaceProxy = (cb) => {
|
|
1594
1805
|
const cache = /* @__PURE__ */ new Map();
|
|
1595
1806
|
return new Proxy(
|
|
1596
1807
|
{},
|
|
1597
1808
|
{
|
|
1598
1809
|
get(_, key) {
|
|
1599
|
-
if (
|
|
1600
|
-
|
|
1601
|
-
|
|
1810
|
+
if (typeof key === "string") {
|
|
1811
|
+
if (!cache.has(key)) {
|
|
1812
|
+
const value = cb(key);
|
|
1813
|
+
cache.set(key, value);
|
|
1814
|
+
}
|
|
1815
|
+
return cache.get(key);
|
|
1602
1816
|
}
|
|
1603
|
-
return
|
|
1817
|
+
return;
|
|
1604
1818
|
},
|
|
1605
1819
|
set(_, key) {
|
|
1606
1820
|
if (typeof key === "string") {
|
|
@@ -1611,6 +1825,25 @@ var createNamespaceProxy = (cb, scb) => {
|
|
|
1611
1825
|
}
|
|
1612
1826
|
);
|
|
1613
1827
|
};
|
|
1828
|
+
var createRootProxy = (apply, get) => {
|
|
1829
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1830
|
+
return new Proxy(() => {
|
|
1831
|
+
}, {
|
|
1832
|
+
apply(_, _this, args) {
|
|
1833
|
+
return apply(...args);
|
|
1834
|
+
},
|
|
1835
|
+
get(_, key) {
|
|
1836
|
+
if (typeof key === "string") {
|
|
1837
|
+
if (!cache.has(key)) {
|
|
1838
|
+
const value = get(key);
|
|
1839
|
+
cache.set(key, value);
|
|
1840
|
+
}
|
|
1841
|
+
return cache.get(key);
|
|
1842
|
+
}
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
});
|
|
1846
|
+
};
|
|
1614
1847
|
var createClassProxy = (construct, get) => {
|
|
1615
1848
|
return new Proxy(class {
|
|
1616
1849
|
}, {
|
|
@@ -1628,307 +1861,88 @@ var createClassProxy = (construct, get) => {
|
|
|
1628
1861
|
});
|
|
1629
1862
|
};
|
|
1630
1863
|
var createRecursiveProxy = ({
|
|
1864
|
+
provider,
|
|
1865
|
+
install,
|
|
1631
1866
|
resource,
|
|
1632
1867
|
dataSource
|
|
1633
1868
|
}) => {
|
|
1634
|
-
const
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
});
|
|
1869
|
+
const findNextProxy = (ns, name) => {
|
|
1870
|
+
if (name === name.toLowerCase()) {
|
|
1871
|
+
return createNamespaceProxy((key) => {
|
|
1872
|
+
return findNextProxy([...ns, name], key);
|
|
1873
|
+
});
|
|
1874
|
+
} else if (name.startsWith("get")) {
|
|
1875
|
+
return (...args) => {
|
|
1876
|
+
return dataSource([...ns, name.substring(3)], ...args);
|
|
1877
|
+
};
|
|
1878
|
+
} else {
|
|
1879
|
+
return createClassProxy(
|
|
1880
|
+
(...args) => {
|
|
1881
|
+
return resource([...ns, name], ...args);
|
|
1882
|
+
},
|
|
1883
|
+
(...args) => {
|
|
1884
|
+
return dataSource([...ns, name], ...args);
|
|
1885
|
+
}
|
|
1886
|
+
);
|
|
1887
|
+
}
|
|
1654
1888
|
};
|
|
1655
|
-
return
|
|
1889
|
+
return createRootProxy(provider, (key) => {
|
|
1890
|
+
if (key === "install") {
|
|
1891
|
+
return install;
|
|
1892
|
+
}
|
|
1893
|
+
return findNextProxy([], key);
|
|
1894
|
+
});
|
|
1656
1895
|
};
|
|
1657
|
-
var
|
|
1896
|
+
var createTerraformProxy = (props) => {
|
|
1658
1897
|
return createRecursiveProxy({
|
|
1898
|
+
provider(input, config) {
|
|
1899
|
+
return new TerraformProvider(
|
|
1900
|
+
props.namespace,
|
|
1901
|
+
config?.id ?? "default",
|
|
1902
|
+
createLazyPlugin({
|
|
1903
|
+
...props.provider,
|
|
1904
|
+
location: config?.location
|
|
1905
|
+
}),
|
|
1906
|
+
input
|
|
1907
|
+
);
|
|
1908
|
+
},
|
|
1909
|
+
async install(installProps) {
|
|
1910
|
+
await downloadPlugin({ ...props.provider, ...installProps });
|
|
1911
|
+
},
|
|
1659
1912
|
resource: (ns, parent, id, input, config) => {
|
|
1660
|
-
const type = snakeCase2(
|
|
1661
|
-
const provider = `terraform:${
|
|
1913
|
+
const type = snakeCase2([props.namespace, ...ns].join("_"));
|
|
1914
|
+
const provider = `terraform:${props.namespace}:${config?.provider ?? "default"}`;
|
|
1662
1915
|
const meta = createMeta("resource", provider, parent, type, id, input, config);
|
|
1663
|
-
const resource =
|
|
1664
|
-
(key)
|
|
1916
|
+
const resource = createResourceProxy((key) => {
|
|
1917
|
+
if (typeof key === "string") {
|
|
1665
1918
|
return meta.output((data) => data[key]);
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
if (key === nodeMetaSymbol) {
|
|
1669
|
-
return meta;
|
|
1670
|
-
}
|
|
1671
|
-
return;
|
|
1919
|
+
} else if (key === nodeMetaSymbol) {
|
|
1920
|
+
return meta;
|
|
1672
1921
|
}
|
|
1673
|
-
|
|
1922
|
+
return;
|
|
1923
|
+
});
|
|
1674
1924
|
parent.add(resource);
|
|
1675
1925
|
return resource;
|
|
1676
1926
|
},
|
|
1677
|
-
// external: (ns: string[], id: string, input: State, config?: ResourceConfig) => {
|
|
1678
|
-
// const type = snakeCase(ns.join('_'))
|
|
1679
|
-
// const provider = `terraform:${ns[0]}:${config?.provider ?? 'default'}`
|
|
1680
|
-
// const $ = createResourceMeta(provider, type, id, input, config)
|
|
1681
|
-
// const resource = createNamespaceProxy(
|
|
1682
|
-
// key => {
|
|
1683
|
-
// if (key === '$') {
|
|
1684
|
-
// return $
|
|
1685
|
-
// }
|
|
1686
|
-
// return $.output(data => data[key])
|
|
1687
|
-
// },
|
|
1688
|
-
// { $ }
|
|
1689
|
-
// ) as Resource
|
|
1690
|
-
// parent.add(resource)
|
|
1691
|
-
// return resource
|
|
1692
|
-
// },
|
|
1693
|
-
// (ns: string[], parent: Group, id: string, input: State, config?: ResourceConfig)
|
|
1694
1927
|
dataSource: (ns, parent, id, input, config) => {
|
|
1695
|
-
const type = snakeCase2(
|
|
1696
|
-
const provider = `terraform:${
|
|
1928
|
+
const type = snakeCase2([props.namespace, ...ns].join("_"));
|
|
1929
|
+
const provider = `terraform:${props.namespace}:${config?.provider ?? "default"}`;
|
|
1697
1930
|
const meta = createMeta("data", provider, parent, type, id, input, config);
|
|
1698
|
-
const dataSource =
|
|
1699
|
-
(key)
|
|
1931
|
+
const dataSource = createResourceProxy((key) => {
|
|
1932
|
+
if (typeof key === "string") {
|
|
1700
1933
|
return meta.output((data) => data[key]);
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
if (key === nodeMetaSymbol) {
|
|
1704
|
-
return meta;
|
|
1705
|
-
}
|
|
1706
|
-
return;
|
|
1934
|
+
} else if (key === nodeMetaSymbol) {
|
|
1935
|
+
return meta;
|
|
1707
1936
|
}
|
|
1708
|
-
|
|
1937
|
+
return;
|
|
1938
|
+
});
|
|
1709
1939
|
parent.add(dataSource);
|
|
1710
1940
|
return dataSource;
|
|
1711
1941
|
}
|
|
1712
1942
|
});
|
|
1713
1943
|
};
|
|
1714
|
-
|
|
1715
|
-
// src/api.ts
|
|
1716
|
-
var createTerraformAPI = (props) => {
|
|
1717
|
-
const resource = createResourceProxy(props.namespace);
|
|
1718
|
-
const install = async (installProps) => {
|
|
1719
|
-
await downloadPlugin({ ...props.provider, ...installProps });
|
|
1720
|
-
};
|
|
1721
|
-
const createPlugin = (pluginProps) => {
|
|
1722
|
-
return createLazyPlugin({ ...props.provider, ...pluginProps });
|
|
1723
|
-
};
|
|
1724
|
-
return new Proxy(() => {
|
|
1725
|
-
}, {
|
|
1726
|
-
apply(_, _this, [input, config]) {
|
|
1727
|
-
return new TerraformProvider(
|
|
1728
|
-
props.namespace,
|
|
1729
|
-
config?.id ?? "default",
|
|
1730
|
-
createPlugin({ location: config?.location }),
|
|
1731
|
-
input
|
|
1732
|
-
);
|
|
1733
|
-
},
|
|
1734
|
-
get(_, prop) {
|
|
1735
|
-
if (prop === "install") {
|
|
1736
|
-
return install;
|
|
1737
|
-
}
|
|
1738
|
-
return resource;
|
|
1739
|
-
}
|
|
1740
|
-
});
|
|
1741
|
-
};
|
|
1742
|
-
|
|
1743
|
-
// src/type-gen.ts
|
|
1744
|
-
import { camelCase as camelCase2, pascalCase } from "change-case";
|
|
1745
|
-
var tab = (indent) => {
|
|
1746
|
-
return " ".repeat(indent);
|
|
1747
|
-
};
|
|
1748
|
-
var generateTypes = (providers, resources, dataSources) => {
|
|
1749
|
-
return [
|
|
1750
|
-
generateImport("c", "@terraforge/core"),
|
|
1751
|
-
generateImport("t", "@terraforge/terraform"),
|
|
1752
|
-
"type _Record<T> = Record<string, T>",
|
|
1753
|
-
generateInstallFunction(providers),
|
|
1754
|
-
generateNamespace(providers, (name, prop, indent) => {
|
|
1755
|
-
const typeName = name.toLowerCase();
|
|
1756
|
-
return `${tab(indent)}export function ${typeName}(props: ${generatePropertyInputConst(prop, indent)}, config?: t.TerraformProviderConfig): t.TerraformProvider`;
|
|
1757
|
-
}),
|
|
1758
|
-
generateNamespace(resources, (name, prop, indent) => {
|
|
1759
|
-
const typeName = pascalCase(name);
|
|
1760
|
-
return [
|
|
1761
|
-
// `${tab(indent)}export type ${typeName}Input = ${generatePropertyInputType(prop, indent)}`,
|
|
1762
|
-
// `${tab(indent)}export type ${typeName}Output = ${generatePropertyOutputType(prop, indent)}`,
|
|
1763
|
-
// `${tab(indent)}export declare const ${typeName}: ResourceClass<${typeName}Input, ${typeName}Output>`,
|
|
1764
|
-
`${tab(indent)}export type ${typeName}Input = ${generatePropertyInputType(prop, indent)}`,
|
|
1765
|
-
`${tab(indent)}export type ${typeName}Output = ${generatePropertyOutputType(prop, indent)}`,
|
|
1766
|
-
`${tab(indent)}export class ${typeName} {`,
|
|
1767
|
-
`${tab(indent + 1)}constructor(parent: c.Group, id: string, props: ${typeName}Input, config?:c.ResourceConfig)`,
|
|
1768
|
-
// `${tab(indent + 1)}readonly $: c.ResourceMeta<${typeName}Input, ${typeName}Output>`,
|
|
1769
|
-
generateClassProperties(prop, indent + 1),
|
|
1770
|
-
`${tab(indent)}}`
|
|
1771
|
-
].join("\n\n");
|
|
1772
|
-
}),
|
|
1773
|
-
generateNamespace(dataSources, (name, prop, indent) => {
|
|
1774
|
-
const typeName = pascalCase(name);
|
|
1775
|
-
return [
|
|
1776
|
-
`${tab(indent)}export type Get${typeName}Input = ${generatePropertyInputType(prop, indent)}`,
|
|
1777
|
-
`${tab(indent)}export type Get${typeName}Output = ${generatePropertyOutputType(prop, indent)}`,
|
|
1778
|
-
`${tab(indent)}export const get${typeName}:c.DataSourceFunction<Get${typeName}Input, Get${typeName}Output>`
|
|
1779
|
-
].join("\n\n");
|
|
1780
|
-
})
|
|
1781
|
-
].join("\n\n");
|
|
1782
|
-
};
|
|
1783
|
-
var generateImport = (name, from) => {
|
|
1784
|
-
return `import * as ${name} from '${from}'`;
|
|
1785
|
-
};
|
|
1786
|
-
var generateInstallFunction = (resources) => {
|
|
1787
|
-
return generateNamespace(resources, (name, _prop, indent) => {
|
|
1788
|
-
const typeName = name.toLowerCase();
|
|
1789
|
-
return `${tab(indent)}export namespace ${typeName} { export function install(props?: t.InstallProps): Promise<void> }`;
|
|
1790
|
-
});
|
|
1791
|
-
};
|
|
1792
|
-
var generatePropertyInputConst = (prop, indent) => {
|
|
1793
|
-
return generateValue(prop, {
|
|
1794
|
-
depth: 0,
|
|
1795
|
-
indent: indent + 1,
|
|
1796
|
-
wrap: (v, _, ctx) => {
|
|
1797
|
-
return `${v}${ctx.depth === 1 ? "," : ""}`;
|
|
1798
|
-
},
|
|
1799
|
-
filter: () => true,
|
|
1800
|
-
optional: (p) => p.optional ?? false
|
|
1801
|
-
});
|
|
1802
|
-
};
|
|
1803
|
-
var generatePropertyInputType = (prop, indent) => {
|
|
1804
|
-
return generateValue(prop, {
|
|
1805
|
-
depth: 0,
|
|
1806
|
-
indent: indent + 1,
|
|
1807
|
-
wrap: (v, p, ctx) => {
|
|
1808
|
-
return ctx.depth > 0 ? p.optional ? `c.OptionalInput<${v}>` : `c.Input<${v}>` : v;
|
|
1809
|
-
},
|
|
1810
|
-
filter: (prop2) => !(prop2.computed && typeof prop2.optional === "undefined" && typeof prop2.required === "undefined"),
|
|
1811
|
-
optional: (p) => p.optional ?? false
|
|
1812
|
-
});
|
|
1813
|
-
};
|
|
1814
|
-
var generatePropertyOutputType = (prop, indent) => {
|
|
1815
|
-
return generateValue(prop, {
|
|
1816
|
-
indent: indent + 1,
|
|
1817
|
-
depth: 0,
|
|
1818
|
-
wrap: (v, p, ctx) => ctx.depth === 1 ? p.optional && !p.computed ? `c.OptionalOutput<${v}>` : `c.Output<${v}>` : v,
|
|
1819
|
-
filter: () => true,
|
|
1820
|
-
readonly: true,
|
|
1821
|
-
// required: true,
|
|
1822
|
-
optional: (p, ctx) => ctx.depth > 1 && p.optional && !p.computed || false
|
|
1823
|
-
});
|
|
1824
|
-
};
|
|
1825
|
-
var generateClassProperties = (prop, indent) => {
|
|
1826
|
-
if (prop.type !== "object") {
|
|
1827
|
-
return "";
|
|
1828
|
-
}
|
|
1829
|
-
return Object.entries(prop.properties).map(([name, prop2]) => {
|
|
1830
|
-
return [
|
|
1831
|
-
prop2.description ? [`
|
|
1832
|
-
`, ` `.repeat(indent), `/** `, prop2.description.trim(), " */", "\n"].join("") : "",
|
|
1833
|
-
` `.repeat(indent),
|
|
1834
|
-
"readonly ",
|
|
1835
|
-
camelCase2(name),
|
|
1836
|
-
// ctx.optional(prop, ctx) ? '?' : '',
|
|
1837
|
-
": ",
|
|
1838
|
-
generateValue(prop2, {
|
|
1839
|
-
readonly: true,
|
|
1840
|
-
filter: () => true,
|
|
1841
|
-
optional: (p, ctx) => ctx.depth > 1 && p.optional && !p.computed || false,
|
|
1842
|
-
wrap: (v, p, ctx) => {
|
|
1843
|
-
return ctx.depth === 1 ? p.optional && !p.computed ? `c.OptionalOutput<${v}>` : `c.Output<${v}>` : v;
|
|
1844
|
-
},
|
|
1845
|
-
// ctx.depth === 1 ? `c.Output<${p.optional && !p.computed ? `${v} | undefined` : v}>` : v,
|
|
1846
|
-
indent: indent + 1,
|
|
1847
|
-
depth: 1
|
|
1848
|
-
})
|
|
1849
|
-
].join("");
|
|
1850
|
-
}).join("\n");
|
|
1851
|
-
};
|
|
1852
|
-
var groupByNamespace = (resources, minLevel, maxLevel) => {
|
|
1853
|
-
const grouped = {};
|
|
1854
|
-
const types = Object.keys(resources).sort();
|
|
1855
|
-
for (const type of types) {
|
|
1856
|
-
const names = type.split("_");
|
|
1857
|
-
if (names.length < minLevel) {
|
|
1858
|
-
throw new Error(`Resource not properly namespaced: ${type}`);
|
|
1859
|
-
}
|
|
1860
|
-
let current = grouped;
|
|
1861
|
-
let count = Math.min(maxLevel, names.length - 1);
|
|
1862
|
-
while (count--) {
|
|
1863
|
-
const ns = camelCase2(names.shift());
|
|
1864
|
-
if (!current[ns]) {
|
|
1865
|
-
current[ns] = {};
|
|
1866
|
-
}
|
|
1867
|
-
current = current[ns];
|
|
1868
|
-
}
|
|
1869
|
-
const name = pascalCase(names.join("_"));
|
|
1870
|
-
current[name] = type;
|
|
1871
|
-
}
|
|
1872
|
-
return grouped;
|
|
1873
|
-
};
|
|
1874
|
-
var generateNamespace = (resources, render) => {
|
|
1875
|
-
const grouped = groupByNamespace(resources, 1, 2);
|
|
1876
|
-
const renderNamespace = (name, group, indent) => {
|
|
1877
|
-
if (name === "default") {
|
|
1878
|
-
name = "$default";
|
|
1879
|
-
}
|
|
1880
|
-
return [
|
|
1881
|
-
`${tab(indent)}export ${indent === 0 ? "declare " : ""}namespace ${name.toLowerCase()} {`,
|
|
1882
|
-
Object.entries(group).map(([name2, entry]) => {
|
|
1883
|
-
if (typeof entry !== "string") {
|
|
1884
|
-
return renderNamespace(name2, entry, indent + 1);
|
|
1885
|
-
} else {
|
|
1886
|
-
return render(name2, resources[entry], indent + 1);
|
|
1887
|
-
}
|
|
1888
|
-
}).join("\n"),
|
|
1889
|
-
`${tab(indent)}}`
|
|
1890
|
-
].join("\n");
|
|
1891
|
-
};
|
|
1892
|
-
return renderNamespace("root", grouped, 0);
|
|
1893
|
-
};
|
|
1894
|
-
var generateValue = (prop, ctx) => {
|
|
1895
|
-
if (["string", "number", "boolean", "unknown"].includes(prop.type)) {
|
|
1896
|
-
return ctx.wrap(prop.type, prop, ctx);
|
|
1897
|
-
}
|
|
1898
|
-
if (prop.type === "array") {
|
|
1899
|
-
const type = generateValue(prop.item, { ...ctx, depth: ctx.depth + 1 });
|
|
1900
|
-
const array = ctx.readonly ? `ReadonlyArray<${type}>` : `Array<${type}>`;
|
|
1901
|
-
return ctx.wrap(array, prop, ctx);
|
|
1902
|
-
}
|
|
1903
|
-
if (prop.type === "record") {
|
|
1904
|
-
const type = generateValue(prop.item, { ...ctx, depth: ctx.depth + 1 });
|
|
1905
|
-
const record = ctx.readonly ? `Readonly<_Record<${type}>>` : `_Record<${type}>`;
|
|
1906
|
-
return ctx.wrap(record, prop, ctx);
|
|
1907
|
-
}
|
|
1908
|
-
if (prop.type === "object" || prop.type === "array-object") {
|
|
1909
|
-
const type = [
|
|
1910
|
-
"{",
|
|
1911
|
-
Object.entries(prop.properties).filter(([_, p]) => ctx.filter(p)).map(
|
|
1912
|
-
([name, prop2]) => [
|
|
1913
|
-
prop2.description ? [`
|
|
1914
|
-
`, ` `.repeat(ctx.indent), `/** `, prop2.description.trim(), " */", "\n"].join("") : "",
|
|
1915
|
-
` `.repeat(ctx.indent),
|
|
1916
|
-
// ctx.readonly ? "readonly " : "",
|
|
1917
|
-
camelCase2(name),
|
|
1918
|
-
ctx.optional(prop2, ctx) ? "?" : "",
|
|
1919
|
-
": ",
|
|
1920
|
-
generateValue(prop2, { ...ctx, indent: ctx.indent + 1, depth: ctx.depth + 1 })
|
|
1921
|
-
].join("")
|
|
1922
|
-
).join("\n"),
|
|
1923
|
-
`${` `.repeat(ctx.indent - 1)}}`
|
|
1924
|
-
].join("\n");
|
|
1925
|
-
const object = ctx.readonly ? `Readonly<${type}>` : type;
|
|
1926
|
-
return ctx.wrap(object, prop, ctx);
|
|
1927
|
-
}
|
|
1928
|
-
throw new Error(`Unknown property type: ${prop.type}`);
|
|
1929
|
-
};
|
|
1930
1944
|
export {
|
|
1931
1945
|
TerraformProvider,
|
|
1932
|
-
|
|
1946
|
+
createTerraformProxy,
|
|
1933
1947
|
generateTypes
|
|
1934
1948
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@terraforge/terraform",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/terraforge-js/terraforge.git"
|
|
8
|
+
},
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/terraforge-js/terraforge/issues"
|
|
11
|
+
},
|
|
5
12
|
"module": "./dist/index.js",
|
|
6
13
|
"types": "./dist/index.d.ts",
|
|
7
14
|
"bin": {
|
|
@@ -19,7 +26,7 @@
|
|
|
19
26
|
"test": "bun test"
|
|
20
27
|
},
|
|
21
28
|
"peerDependencies": {
|
|
22
|
-
"@terraforge/core": "0.0.
|
|
29
|
+
"@terraforge/core": "0.0.5"
|
|
23
30
|
},
|
|
24
31
|
"dependencies": {
|
|
25
32
|
"@grpc/grpc-js": "1.12.6",
|