Skip to content

Commit 0f6081c

Browse files
committed
feat: add ejs support
1 parent 39a029f commit 0f6081c

File tree

8 files changed

+167
-76
lines changed

8 files changed

+167
-76
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"devDependencies": {
3737
"@eslint/js": "^9.9.0",
3838
"@types/jest": "^29.5.12",
39+
"@types/ejs": "^3.1.5",
3940
"eslint": "^9.9.0",
4041
"globals": "^15.9.0",
4142
"jest": "^29.7.0",
@@ -49,7 +50,8 @@
4950
"dependencies": {
5051
"@types/node": "^20.16.3",
5152
"typescript": "^5.5.4",
52-
"handlebars": "^4.7.6"
53+
"handlebars": "^4.7.6",
54+
"ejs": "^3.1.10"
5355
},
5456
"bin": {
5557
"tfgen": "./bin/tfgen",

src/generators/v1.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import {enriched_layer_config, layer_region_config} from '../types';
2-
import replaceVars from '../utils/replaceVars';
2+
import replace from '../utils/replaceVars';
33

44
export default async (
55
source: string,
66
{
77
regions,
88
defaultRegion,
9-
}: {regions: Record<string, layer_region_config>; defaultRegion: string},
9+
format,
10+
}: {
11+
regions: Record<string, layer_region_config>;
12+
defaultRegion: string;
13+
format: string;
14+
},
1015
vars: Record<string, unknown>,
1116
_: enriched_layer_config,
1217
) => {
@@ -15,15 +20,19 @@ export default async (
1520
const isMain = (r?.id || rCode) === defaultRegion;
1621
return [
1722
`main${(r?.id || rCode) === defaultRegion ? '' : `_${rCode.replace(/-/g, '_')}`}.tf`,
18-
replaceVars(source, {
19-
...vars,
20-
region: r?.id || rCode,
21-
is_main: isMain,
22-
is_default_region: isMain,
23-
rsuffix: isMain ? '' : `-${rCode}`,
24-
...r,
25-
...(vars?.id ? {id: vars.id} : {}),
26-
}) as unknown as string,
23+
replace(
24+
source,
25+
{
26+
...vars,
27+
region: r?.id || rCode,
28+
is_main: isMain,
29+
is_default_region: isMain,
30+
rsuffix: isMain ? '' : `-${rCode}`,
31+
...r,
32+
...(vars?.id ? {id: vars.id} : {}),
33+
},
34+
{format},
35+
) as unknown as string,
2736
];
2837
},
2938
) as [string, string][];

src/generators/v2.ts

Lines changed: 106 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,51 +6,93 @@ export default async (
66
{
77
regions,
88
defaultRegion,
9-
}: {regions: Record<string, layer_region_config>; defaultRegion: string},
9+
format,
10+
}: {
11+
regions: Record<string, layer_region_config>;
12+
defaultRegion: string;
13+
format: string;
14+
},
1015
vars: Record<string, unknown>,
1116
_: enriched_layer_config,
1217
) => {
18+
const defaultVars = {
19+
region: '',
20+
is_default_outputs: false,
21+
is_outputs_file: false,
22+
is_default_region: false,
23+
is_terraform_file: false,
24+
is_data_file: false,
25+
is_locals_file: false,
26+
is_variables_file: false,
27+
is_providers_file: false,
28+
is_main: false,
29+
is_default_main: false,
30+
is_main_file: false,
31+
is_sub: false,
32+
is_default_sub: false,
33+
is_sub_file: false,
34+
extra_providers: [],
35+
psuffix: '',
36+
rsuffix: '',
37+
};
38+
vars = {...vars, ...defaultVars};
1339
return [
14-
[`terraform.tf`, replace(s, {...vars, is_terraform_file: true})],
15-
[`data.tf`, replace(s, {...vars, is_data_file: true})],
16-
[`locals.tf`, replace(s, {...vars, is_locals_file: true})],
17-
[`variables.tf`, replace(s, {...vars, is_variables_file: true})],
40+
[
41+
`terraform.tf`,
42+
replace(s, {...vars, is_terraform_file: true}, {format}),
43+
],
44+
[`data.tf`, replace(s, {...vars, is_data_file: true}, {format})],
45+
[`locals.tf`, replace(s, {...vars, is_locals_file: true}, {format})],
46+
[
47+
`variables.tf`,
48+
replace(s, {...vars, is_variables_file: true}, {format}),
49+
],
1850
[
1951
`providers.tf`,
20-
replace(s, {
21-
...vars,
22-
extra_providers: Object.entries(regions)
23-
.map(([rCode, r]: [string, layer_region_config]) => {
24-
const region = r?.id || rCode;
25-
const isMain = region === defaultRegion;
26-
return isMain
27-
? undefined
28-
: {type: 'aws', alias: rCode, region};
29-
})
30-
.filter(x => !!x)
31-
.sort((a, b) =>
32-
(a?.alias as string).localeCompare(b?.alias as string),
33-
),
34-
is_providers_file: true,
35-
}) as unknown as string,
52+
replace(
53+
s,
54+
{
55+
...vars,
56+
extra_providers: Object.entries(regions)
57+
.map(([rCode, r]: [string, layer_region_config]) => {
58+
const region = r?.id || rCode;
59+
const isMain = region === defaultRegion;
60+
return isMain
61+
? undefined
62+
: {type: 'aws', alias: rCode, region};
63+
})
64+
.filter(x => !!x)
65+
.sort((a, b) =>
66+
(a?.alias as string).localeCompare(
67+
b?.alias as string,
68+
),
69+
),
70+
is_providers_file: true,
71+
},
72+
{format},
73+
) as unknown as string,
3674
],
3775
// region outputs files
3876
...Object.entries(regions).map(
3977
([rCode, r]: [string, layer_region_config]) => {
4078
const isDefault = (r?.id || rCode) === defaultRegion;
4179
return [
4280
`outputs${isDefault ? '' : `_${rCode.replace(/-/g, '_')}`}.tf`,
43-
replace(s, {
44-
...vars,
45-
region: r?.id || rCode,
46-
is_default_outputs: isDefault,
47-
is_outputs_file: true,
48-
is_default_region: isDefault,
49-
psuffix: isDefault ? '' : `.${rCode}`,
50-
rsuffix: isDefault ? '' : `-${rCode}`,
51-
...r,
52-
...(vars?.id ? {id: vars.id} : {}),
53-
}) as unknown as string,
81+
replace(
82+
s,
83+
{
84+
...vars,
85+
region: r?.id || rCode,
86+
is_default_outputs: isDefault,
87+
is_outputs_file: true,
88+
is_default_region: isDefault,
89+
psuffix: isDefault ? '' : `.${rCode}`,
90+
rsuffix: isDefault ? '' : `-${rCode}`,
91+
...r,
92+
...(vars?.id ? {id: vars.id} : {}),
93+
},
94+
{format},
95+
) as unknown as string,
5496
];
5597
},
5698
),
@@ -60,18 +102,22 @@ export default async (
60102
const isMain = (r?.id || rCode) === defaultRegion;
61103
return [
62104
`main${(r?.id || rCode) === defaultRegion ? '' : `_${rCode.replace(/-/g, '_')}`}.tf`,
63-
replace(s, {
64-
...vars,
65-
region: r?.id || rCode,
66-
is_main: isMain,
67-
is_default_main: isMain,
68-
is_main_file: true,
69-
is_default_region: isMain,
70-
psuffix: isMain ? '' : `.${rCode}`,
71-
rsuffix: isMain ? '' : `-${rCode}`,
72-
...r,
73-
...(vars?.id ? {id: vars.id} : {}),
74-
}) as unknown as string,
105+
replace(
106+
s,
107+
{
108+
...vars,
109+
region: r?.id || rCode,
110+
is_main: isMain,
111+
is_default_main: isMain,
112+
is_main_file: true,
113+
is_default_region: isMain,
114+
psuffix: isMain ? '' : `.${rCode}`,
115+
rsuffix: isMain ? '' : `-${rCode}`,
116+
...r,
117+
...(vars?.id ? {id: vars.id} : {}),
118+
},
119+
{format},
120+
) as unknown as string,
75121
];
76122
},
77123
),
@@ -81,18 +127,22 @@ export default async (
81127
const isSub = (r?.id || rCode) === defaultRegion;
82128
return [
83129
`sub${(r?.id || rCode) === defaultRegion ? '' : `_${rCode.replace(/-/g, '_')}`}.tf`,
84-
replace(s, {
85-
...vars,
86-
region: r?.id || rCode,
87-
is_sub: isSub,
88-
is_default_sub: isSub,
89-
is_sub_file: true,
90-
is_default_region: isSub,
91-
psuffix: isSub ? '' : `.${rCode}`,
92-
rsuffix: isSub ? '' : `-${rCode}`,
93-
...r,
94-
...(vars?.id ? {id: vars.id} : {}),
95-
}) as unknown as string,
130+
replace(
131+
s,
132+
{
133+
...vars,
134+
region: r?.id || rCode,
135+
is_sub: isSub,
136+
is_default_sub: isSub,
137+
is_sub_file: true,
138+
is_default_region: isSub,
139+
psuffix: isSub ? '' : `.${rCode}`,
140+
rsuffix: isSub ? '' : `-${rCode}`,
141+
...r,
142+
...(vars?.id ? {id: vars.id} : {}),
143+
},
144+
{format},
145+
) as unknown as string,
96146
];
97147
},
98148
),

src/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ export type layer_config = {
2121
export type generated_file = [string, string];
2222
export type generator = (
2323
source: string,
24-
ctx: {regions: Record<string, layer_region_config>; defaultRegion: string},
24+
ctx: {
25+
regions: Record<string, layer_region_config>;
26+
defaultRegion: string;
27+
format: string;
28+
},
2529
vars: Record<string, unknown>,
2630
layerConfig: enriched_layer_config,
2731
) => Promise<generated_file[]> | generated_file[];
@@ -33,6 +37,7 @@ export type enriched_layer_config = {
3337
defaultRegion: string;
3438
regions?: Record<string, layer_region_config>;
3539
format?: string;
40+
version?: string;
3641
};
3742

3843
export type loggable = {

src/utils/fetchLayers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ export const fetchLayers = async (
55
sourceDir: string,
66
): Promise<fetched_layer[]> => {
77
return readdirSync(sourceDir, {withFileTypes: true})
8-
.filter(e => !e.isDirectory() && /.tmpl.tf$/.test(e.name))
8+
.filter(e => !e.isDirectory() && /\.(tf\.ejs|tmpl\.tf)$/.test(e.name))
99
.map(e => ({
10-
name: e.name.replace(/\.tmpl\.tf$/, ''),
10+
name: e.name.replace(/(\.tmpl\.tf|\.tf\.ejs)$/, ''),
1111
file: e.name,
1212
filePath: `${sourceDir}/${e.name}`,
1313
}));

src/utils/generateEnvLayerFromFile.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ export const generateEnvLayerFromFile = async (
1313
const defaultRegion = layerConfig.defaultRegion;
1414
const regions: Record<string, layer_region_config> =
1515
layerConfig.regions || {};
16-
const format = layerConfig.format || 'v1';
17-
const generator = (generators as Record<string, generator>)[format];
16+
const format = layerConfig.format || 'handlebars';
17+
const version = layerConfig.version || 'v1';
18+
const generator = (generators as Record<string, generator>)[version];
1819

19-
if (!generator) throw new Error(`Unsupported layer format '${format}'`);
20+
if (!generator)
21+
throw new Error(`Unsupported layer generator version '${version}'`);
2022

2123
const files = await generator(
2224
readFileSync(sourceFile, 'utf8') as string,
@@ -29,6 +31,7 @@ export const generateEnvLayerFromFile = async (
2931
layer_region_config
3032
>),
3133
defaultRegion,
34+
format,
3235
},
3336
vars,
3437
layerConfig,

src/utils/replaceVars.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
import Handlebars from 'handlebars';
2+
import ejs from 'ejs';
3+
24
Handlebars.registerHelper('slugify', s => s.replace(/[^a-z0-9_]+/g, '-'));
35

4-
export const replaceVars = (a: unknown, b: Record<string, unknown>) => {
6+
const replaceHandlebars = (a: unknown, b: unknown) => Handlebars.compile(a)(b);
7+
const replaceEjs = (a: string, b: Record<string, unknown>) =>
8+
ejs.render(a, b, {debug: false});
9+
10+
const defaultFormat = 'handlebars';
11+
export const replaceVars = (
12+
a: unknown,
13+
b: Record<string, unknown>,
14+
{format = defaultFormat} = {},
15+
) => {
516
if (Array.isArray(a)) {
617
a.forEach((v, i) => {
718
a[i] = replaceVars(v, b);
@@ -17,7 +28,13 @@ export const replaceVars = (a: unknown, b: Record<string, unknown>) => {
1728
a as Record<string, unknown>,
1829
);
1930
}
20-
return Handlebars.compile(a)(b);
31+
switch (format) {
32+
case 'ejs':
33+
return replaceEjs(a as string, b);
34+
default:
35+
case 'handlebars':
36+
return replaceHandlebars(a, b);
37+
}
2138
};
2239

2340
export default replaceVars;

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,11 @@
11571157
dependencies:
11581158
"@babel/types" "^7.20.7"
11591159

1160+
"@types/ejs@^3.1.5":
1161+
version "3.1.5"
1162+
resolved "https://registry.yarnpkg.com/@types/ejs/-/ejs-3.1.5.tgz#49d738257cc73bafe45c13cb8ff240683b4d5117"
1163+
integrity sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==
1164+
11601165
"@types/graceful-fs@^4.1.3":
11611166
version "4.1.9"
11621167
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4"

0 commit comments

Comments
 (0)