@ttoss/cloudformation 0.2.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/dist/esm/index.js +221 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +246 -0
- package/package.json +33 -0
- package/src/cloudFormationTemplate.ts +185 -0
- package/src/findAndReadCloudFormationTemplate.ts +52 -0
- package/src/index.ts +1 -0
- package/src/readCloudFormationYamlTemplate.ts +43 -0
- package/src/readObjectFile.ts +48 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined")
|
|
6
|
+
return require.apply(this, arguments);
|
|
7
|
+
throw new Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
// src/findAndReadCloudFormationTemplate.ts
|
|
11
|
+
import * as fs3 from "fs";
|
|
12
|
+
import * as path2 from "path";
|
|
13
|
+
|
|
14
|
+
// src/readCloudFormationYamlTemplate.ts
|
|
15
|
+
import * as fs from "fs";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
|
|
18
|
+
// src/cloudFormationTemplate.ts
|
|
19
|
+
import yaml from "js-yaml";
|
|
20
|
+
var cloudFormationTypes = [
|
|
21
|
+
{
|
|
22
|
+
tag: "!Equals",
|
|
23
|
+
options: {
|
|
24
|
+
kind: "sequence",
|
|
25
|
+
construct: (data) => {
|
|
26
|
+
return { "Fn::Equals": data };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
tag: "!FindInMap",
|
|
32
|
+
options: {
|
|
33
|
+
kind: "sequence",
|
|
34
|
+
construct: (data) => {
|
|
35
|
+
return { "Fn::FindInMap": data };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
tag: "!GetAtt",
|
|
41
|
+
options: {
|
|
42
|
+
kind: "scalar",
|
|
43
|
+
construct: (data) => {
|
|
44
|
+
return { "Fn::GetAtt": data.split(".") };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
tag: "!GetAtt",
|
|
50
|
+
options: {
|
|
51
|
+
kind: "sequence",
|
|
52
|
+
construct: (data) => {
|
|
53
|
+
return { "Fn::GetAtt": data };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
tag: "!If",
|
|
59
|
+
options: {
|
|
60
|
+
kind: "sequence",
|
|
61
|
+
construct: (data) => {
|
|
62
|
+
return { "Fn::If": data };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
tag: "!ImportValue",
|
|
68
|
+
options: {
|
|
69
|
+
kind: "scalar",
|
|
70
|
+
construct: (data) => {
|
|
71
|
+
return { "Fn::ImportValue": data };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
tag: "!Join",
|
|
77
|
+
options: {
|
|
78
|
+
kind: "sequence",
|
|
79
|
+
construct: (data) => {
|
|
80
|
+
return { "Fn::Join": data };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
tag: "!Not",
|
|
86
|
+
options: {
|
|
87
|
+
kind: "sequence",
|
|
88
|
+
construct: (data) => {
|
|
89
|
+
return { "Fn::Not": data };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
tag: "!Ref",
|
|
95
|
+
options: {
|
|
96
|
+
kind: "scalar",
|
|
97
|
+
construct: (data) => {
|
|
98
|
+
return { Ref: data };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
tag: "!Sub",
|
|
104
|
+
options: {
|
|
105
|
+
kind: "scalar",
|
|
106
|
+
construct: (data) => {
|
|
107
|
+
return { "Fn::Sub": data };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
tag: "!Sub",
|
|
113
|
+
options: {
|
|
114
|
+
kind: "sequence",
|
|
115
|
+
construct: (data) => {
|
|
116
|
+
return { "Fn::Sub": data };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
];
|
|
121
|
+
var getYamlTypes = (tagAndTypeArr) => {
|
|
122
|
+
return tagAndTypeArr.map(({ tag, options }) => {
|
|
123
|
+
return new yaml.Type(tag, options);
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
var getSchema = (tagAndTypeArr = []) => {
|
|
127
|
+
return yaml.DEFAULT_SCHEMA.extend(
|
|
128
|
+
getYamlTypes([...tagAndTypeArr, ...cloudFormationTypes])
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
var loadCloudFormationTemplate = (template, tagAndTypeArr = []) => {
|
|
132
|
+
return yaml.load(template, { schema: getSchema(tagAndTypeArr) });
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/readCloudFormationYamlTemplate.ts
|
|
136
|
+
var getTypes = () => {
|
|
137
|
+
return [
|
|
138
|
+
{
|
|
139
|
+
tag: `!SubString`,
|
|
140
|
+
options: {
|
|
141
|
+
kind: "scalar",
|
|
142
|
+
construct: (filePath) => {
|
|
143
|
+
return fs.readFileSync(path.resolve(process.cwd(), filePath)).toString();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
];
|
|
148
|
+
};
|
|
149
|
+
var readCloudFormationYamlTemplate = ({
|
|
150
|
+
templatePath
|
|
151
|
+
}) => {
|
|
152
|
+
const template = fs.readFileSync(templatePath).toString();
|
|
153
|
+
const parsed = loadCloudFormationTemplate(template, getTypes());
|
|
154
|
+
if (!parsed || typeof parsed === "string") {
|
|
155
|
+
throw new Error("Cannot parse CloudFormation template.");
|
|
156
|
+
}
|
|
157
|
+
return parsed;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// src/readObjectFile.ts
|
|
161
|
+
import fs2 from "fs";
|
|
162
|
+
import yaml2 from "js-yaml";
|
|
163
|
+
var readYaml = ({ path: path3 }) => {
|
|
164
|
+
const template = fs2.readFileSync(path3, "utf8") || JSON.stringify({});
|
|
165
|
+
return yaml2.load(template);
|
|
166
|
+
};
|
|
167
|
+
var readObjectFile = ({ path: path3 }) => {
|
|
168
|
+
if (!fs2.existsSync(path3)) {
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
const extension = path3.split(".").pop();
|
|
172
|
+
if (extension === "ts") {
|
|
173
|
+
__require("ts-node").register({
|
|
174
|
+
compilerOptions: { module: "commonjs" },
|
|
175
|
+
transpileOnly: true
|
|
176
|
+
});
|
|
177
|
+
const tsObj = __require(path3);
|
|
178
|
+
const obj = tsObj.default || tsObj;
|
|
179
|
+
return typeof obj === "function" ? obj() : obj;
|
|
180
|
+
}
|
|
181
|
+
if (extension === "js") {
|
|
182
|
+
const obj = __require(path3);
|
|
183
|
+
return typeof obj === "function" ? obj() : obj;
|
|
184
|
+
}
|
|
185
|
+
if (extension === "json") {
|
|
186
|
+
return __require(path3);
|
|
187
|
+
}
|
|
188
|
+
if (extension === "yml" || extension === "yaml") {
|
|
189
|
+
return readYaml({ path: path3 });
|
|
190
|
+
}
|
|
191
|
+
return {};
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// src/findAndReadCloudFormationTemplate.ts
|
|
195
|
+
var defaultTemplatePaths = ["ts", "js", "yaml", "yml", "json"].map(
|
|
196
|
+
(extension) => {
|
|
197
|
+
return `./src/cloudformation.${extension}`;
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
var findAndReadCloudFormationTemplate = ({
|
|
201
|
+
templatePath: defaultTemplatePath
|
|
202
|
+
}) => {
|
|
203
|
+
const templatePath = defaultTemplatePath || defaultTemplatePaths.reduce((acc, cur) => {
|
|
204
|
+
if (acc) {
|
|
205
|
+
return acc;
|
|
206
|
+
}
|
|
207
|
+
return fs3.existsSync(path2.resolve(process.cwd(), cur)) ? cur : acc;
|
|
208
|
+
}, "");
|
|
209
|
+
if (!templatePath) {
|
|
210
|
+
throw new Error("Cannot find a CloudFormation template.");
|
|
211
|
+
}
|
|
212
|
+
const extension = templatePath?.split(".").pop();
|
|
213
|
+
const fullPath = path2.resolve(process.cwd(), templatePath);
|
|
214
|
+
if (["yaml", "yml"].includes(extension)) {
|
|
215
|
+
return readCloudFormationYamlTemplate({ templatePath });
|
|
216
|
+
}
|
|
217
|
+
return readObjectFile({ path: fullPath });
|
|
218
|
+
};
|
|
219
|
+
export {
|
|
220
|
+
findAndReadCloudFormationTemplate
|
|
221
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
interface Parameter {
|
|
2
|
+
AllowedValues?: string[];
|
|
3
|
+
Default?: string | number;
|
|
4
|
+
Description?: string;
|
|
5
|
+
Type: string;
|
|
6
|
+
NoEcho?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface Resource {
|
|
9
|
+
Type: string;
|
|
10
|
+
DeletionPolicy?: 'Delete' | 'Retain';
|
|
11
|
+
Description?: string;
|
|
12
|
+
DependsOn?: string[] | string;
|
|
13
|
+
Condition?: string;
|
|
14
|
+
Properties: any;
|
|
15
|
+
}
|
|
16
|
+
type Output = {
|
|
17
|
+
Description?: string;
|
|
18
|
+
Value: string | any;
|
|
19
|
+
Export?: {
|
|
20
|
+
Name: string | any;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
interface CloudFormationTemplate {
|
|
24
|
+
AWSTemplateFormatVersion: '2010-09-09';
|
|
25
|
+
Transform?: 'AWS::Serverless-2016-10-31';
|
|
26
|
+
Mappings?: any;
|
|
27
|
+
Conditions?: any;
|
|
28
|
+
Parameters?: {
|
|
29
|
+
[key: string]: Parameter;
|
|
30
|
+
};
|
|
31
|
+
Resources: {
|
|
32
|
+
[key: string]: Resource;
|
|
33
|
+
};
|
|
34
|
+
Outputs?: {
|
|
35
|
+
[key: string]: Output;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare const findAndReadCloudFormationTemplate: ({ templatePath: defaultTemplatePath, }: {
|
|
40
|
+
templatePath?: string;
|
|
41
|
+
}) => CloudFormationTemplate;
|
|
42
|
+
|
|
43
|
+
export { findAndReadCloudFormationTemplate };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
26
|
+
|
|
27
|
+
// src/index.ts
|
|
28
|
+
var src_exports = {};
|
|
29
|
+
__export(src_exports, {
|
|
30
|
+
findAndReadCloudFormationTemplate: () => findAndReadCloudFormationTemplate
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(src_exports);
|
|
33
|
+
|
|
34
|
+
// src/findAndReadCloudFormationTemplate.ts
|
|
35
|
+
var fs3 = __toESM(require("fs"));
|
|
36
|
+
var path2 = __toESM(require("path"));
|
|
37
|
+
|
|
38
|
+
// src/readCloudFormationYamlTemplate.ts
|
|
39
|
+
var fs = __toESM(require("fs"));
|
|
40
|
+
var path = __toESM(require("path"));
|
|
41
|
+
|
|
42
|
+
// src/cloudFormationTemplate.ts
|
|
43
|
+
var import_js_yaml = __toESM(require("js-yaml"));
|
|
44
|
+
var cloudFormationTypes = [
|
|
45
|
+
{
|
|
46
|
+
tag: "!Equals",
|
|
47
|
+
options: {
|
|
48
|
+
kind: "sequence",
|
|
49
|
+
construct: (data) => {
|
|
50
|
+
return { "Fn::Equals": data };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
tag: "!FindInMap",
|
|
56
|
+
options: {
|
|
57
|
+
kind: "sequence",
|
|
58
|
+
construct: (data) => {
|
|
59
|
+
return { "Fn::FindInMap": data };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
tag: "!GetAtt",
|
|
65
|
+
options: {
|
|
66
|
+
kind: "scalar",
|
|
67
|
+
construct: (data) => {
|
|
68
|
+
return { "Fn::GetAtt": data.split(".") };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
tag: "!GetAtt",
|
|
74
|
+
options: {
|
|
75
|
+
kind: "sequence",
|
|
76
|
+
construct: (data) => {
|
|
77
|
+
return { "Fn::GetAtt": data };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
tag: "!If",
|
|
83
|
+
options: {
|
|
84
|
+
kind: "sequence",
|
|
85
|
+
construct: (data) => {
|
|
86
|
+
return { "Fn::If": data };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
tag: "!ImportValue",
|
|
92
|
+
options: {
|
|
93
|
+
kind: "scalar",
|
|
94
|
+
construct: (data) => {
|
|
95
|
+
return { "Fn::ImportValue": data };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
tag: "!Join",
|
|
101
|
+
options: {
|
|
102
|
+
kind: "sequence",
|
|
103
|
+
construct: (data) => {
|
|
104
|
+
return { "Fn::Join": data };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
tag: "!Not",
|
|
110
|
+
options: {
|
|
111
|
+
kind: "sequence",
|
|
112
|
+
construct: (data) => {
|
|
113
|
+
return { "Fn::Not": data };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
tag: "!Ref",
|
|
119
|
+
options: {
|
|
120
|
+
kind: "scalar",
|
|
121
|
+
construct: (data) => {
|
|
122
|
+
return { Ref: data };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
tag: "!Sub",
|
|
128
|
+
options: {
|
|
129
|
+
kind: "scalar",
|
|
130
|
+
construct: (data) => {
|
|
131
|
+
return { "Fn::Sub": data };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
tag: "!Sub",
|
|
137
|
+
options: {
|
|
138
|
+
kind: "sequence",
|
|
139
|
+
construct: (data) => {
|
|
140
|
+
return { "Fn::Sub": data };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
];
|
|
145
|
+
var getYamlTypes = (tagAndTypeArr) => {
|
|
146
|
+
return tagAndTypeArr.map(({ tag, options }) => {
|
|
147
|
+
return new import_js_yaml.default.Type(tag, options);
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
var getSchema = (tagAndTypeArr = []) => {
|
|
151
|
+
return import_js_yaml.default.DEFAULT_SCHEMA.extend(
|
|
152
|
+
getYamlTypes([...tagAndTypeArr, ...cloudFormationTypes])
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
var loadCloudFormationTemplate = (template, tagAndTypeArr = []) => {
|
|
156
|
+
return import_js_yaml.default.load(template, { schema: getSchema(tagAndTypeArr) });
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/readCloudFormationYamlTemplate.ts
|
|
160
|
+
var getTypes = () => {
|
|
161
|
+
return [
|
|
162
|
+
{
|
|
163
|
+
tag: `!SubString`,
|
|
164
|
+
options: {
|
|
165
|
+
kind: "scalar",
|
|
166
|
+
construct: (filePath) => {
|
|
167
|
+
return fs.readFileSync(path.resolve(process.cwd(), filePath)).toString();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
];
|
|
172
|
+
};
|
|
173
|
+
var readCloudFormationYamlTemplate = ({
|
|
174
|
+
templatePath
|
|
175
|
+
}) => {
|
|
176
|
+
const template = fs.readFileSync(templatePath).toString();
|
|
177
|
+
const parsed = loadCloudFormationTemplate(template, getTypes());
|
|
178
|
+
if (!parsed || typeof parsed === "string") {
|
|
179
|
+
throw new Error("Cannot parse CloudFormation template.");
|
|
180
|
+
}
|
|
181
|
+
return parsed;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// src/readObjectFile.ts
|
|
185
|
+
var import_fs = __toESM(require("fs"));
|
|
186
|
+
var import_js_yaml2 = __toESM(require("js-yaml"));
|
|
187
|
+
var readYaml = ({ path: path3 }) => {
|
|
188
|
+
const template = import_fs.default.readFileSync(path3, "utf8") || JSON.stringify({});
|
|
189
|
+
return import_js_yaml2.default.load(template);
|
|
190
|
+
};
|
|
191
|
+
var readObjectFile = ({ path: path3 }) => {
|
|
192
|
+
if (!import_fs.default.existsSync(path3)) {
|
|
193
|
+
return {};
|
|
194
|
+
}
|
|
195
|
+
const extension = path3.split(".").pop();
|
|
196
|
+
if (extension === "ts") {
|
|
197
|
+
require("ts-node").register({
|
|
198
|
+
compilerOptions: { module: "commonjs" },
|
|
199
|
+
transpileOnly: true
|
|
200
|
+
});
|
|
201
|
+
const tsObj = require(path3);
|
|
202
|
+
const obj = tsObj.default || tsObj;
|
|
203
|
+
return typeof obj === "function" ? obj() : obj;
|
|
204
|
+
}
|
|
205
|
+
if (extension === "js") {
|
|
206
|
+
const obj = require(path3);
|
|
207
|
+
return typeof obj === "function" ? obj() : obj;
|
|
208
|
+
}
|
|
209
|
+
if (extension === "json") {
|
|
210
|
+
return require(path3);
|
|
211
|
+
}
|
|
212
|
+
if (extension === "yml" || extension === "yaml") {
|
|
213
|
+
return readYaml({ path: path3 });
|
|
214
|
+
}
|
|
215
|
+
return {};
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// src/findAndReadCloudFormationTemplate.ts
|
|
219
|
+
var defaultTemplatePaths = ["ts", "js", "yaml", "yml", "json"].map(
|
|
220
|
+
(extension) => {
|
|
221
|
+
return `./src/cloudformation.${extension}`;
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
var findAndReadCloudFormationTemplate = ({
|
|
225
|
+
templatePath: defaultTemplatePath
|
|
226
|
+
}) => {
|
|
227
|
+
const templatePath = defaultTemplatePath || defaultTemplatePaths.reduce((acc, cur) => {
|
|
228
|
+
if (acc) {
|
|
229
|
+
return acc;
|
|
230
|
+
}
|
|
231
|
+
return fs3.existsSync(path2.resolve(process.cwd(), cur)) ? cur : acc;
|
|
232
|
+
}, "");
|
|
233
|
+
if (!templatePath) {
|
|
234
|
+
throw new Error("Cannot find a CloudFormation template.");
|
|
235
|
+
}
|
|
236
|
+
const extension = templatePath?.split(".").pop();
|
|
237
|
+
const fullPath = path2.resolve(process.cwd(), templatePath);
|
|
238
|
+
if (["yaml", "yml"].includes(extension)) {
|
|
239
|
+
return readCloudFormationYamlTemplate({ templatePath });
|
|
240
|
+
}
|
|
241
|
+
return readObjectFile({ path: fullPath });
|
|
242
|
+
};
|
|
243
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
244
|
+
0 && (module.exports = {
|
|
245
|
+
findAndReadCloudFormationTemplate
|
|
246
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ttoss/cloudformation",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "CloudFormation utils.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"author": "ttoss",
|
|
7
|
+
"contributors": [
|
|
8
|
+
"Pedro Arantes <pedro@arantespp.com> (https://arantespp.com)"
|
|
9
|
+
],
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"module": "dist/esm/index.js",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"src"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"test": "echo test"
|
|
19
|
+
},
|
|
20
|
+
"typings": "dist/index.d.ts",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"js-yaml": "^4.1.0",
|
|
23
|
+
"ts-node": "^10.9.1"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@ttoss/config": "^1.25.0"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [],
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"gitHead": "9ad8b28e9ca906af04b2e0c3743bf453b8701429"
|
|
33
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import yaml from 'js-yaml';
|
|
2
|
+
|
|
3
|
+
interface Parameter {
|
|
4
|
+
AllowedValues?: string[];
|
|
5
|
+
Default?: string | number;
|
|
6
|
+
Description?: string;
|
|
7
|
+
Type: string;
|
|
8
|
+
NoEcho?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Resource {
|
|
12
|
+
Type: string;
|
|
13
|
+
DeletionPolicy?: 'Delete' | 'Retain';
|
|
14
|
+
Description?: string;
|
|
15
|
+
DependsOn?: string[] | string;
|
|
16
|
+
Condition?: string;
|
|
17
|
+
Properties: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type Output = {
|
|
21
|
+
Description?: string;
|
|
22
|
+
Value: string | any;
|
|
23
|
+
Export?: {
|
|
24
|
+
Name: string | any;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export interface CloudFormationTemplate {
|
|
29
|
+
AWSTemplateFormatVersion: '2010-09-09';
|
|
30
|
+
Transform?: 'AWS::Serverless-2016-10-31';
|
|
31
|
+
Mappings?: any;
|
|
32
|
+
Conditions?: any;
|
|
33
|
+
Parameters?: { [key: string]: Parameter };
|
|
34
|
+
Resources: { [key: string]: Resource };
|
|
35
|
+
Outputs?: { [key: string]: Output };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface TagAndType {
|
|
39
|
+
tag: string;
|
|
40
|
+
options: yaml.TypeConstructorOptions;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const cloudFormationTypes: TagAndType[] = [
|
|
44
|
+
{
|
|
45
|
+
tag: '!Equals',
|
|
46
|
+
options: {
|
|
47
|
+
kind: 'sequence',
|
|
48
|
+
construct: (data: any) => {
|
|
49
|
+
return { 'Fn::Equals': data };
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
tag: '!FindInMap',
|
|
55
|
+
options: {
|
|
56
|
+
kind: 'sequence',
|
|
57
|
+
construct: (data: any) => {
|
|
58
|
+
return { 'Fn::FindInMap': data };
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
tag: '!GetAtt',
|
|
64
|
+
options: {
|
|
65
|
+
kind: 'scalar',
|
|
66
|
+
construct: (data: any) => {
|
|
67
|
+
return { 'Fn::GetAtt': data.split('.') };
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
tag: '!GetAtt',
|
|
73
|
+
options: {
|
|
74
|
+
kind: 'sequence',
|
|
75
|
+
construct: (data: any) => {
|
|
76
|
+
return { 'Fn::GetAtt': data };
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
tag: '!If',
|
|
82
|
+
options: {
|
|
83
|
+
kind: 'sequence',
|
|
84
|
+
construct: (data: any) => {
|
|
85
|
+
return { 'Fn::If': data };
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
tag: '!ImportValue',
|
|
91
|
+
options: {
|
|
92
|
+
kind: 'scalar',
|
|
93
|
+
construct: (data: any) => {
|
|
94
|
+
return { 'Fn::ImportValue': data };
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
tag: '!Join',
|
|
100
|
+
options: {
|
|
101
|
+
kind: 'sequence',
|
|
102
|
+
construct: (data: any) => {
|
|
103
|
+
return { 'Fn::Join': data };
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
tag: '!Not',
|
|
109
|
+
options: {
|
|
110
|
+
kind: 'sequence',
|
|
111
|
+
construct: (data: any) => {
|
|
112
|
+
return { 'Fn::Not': data };
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
tag: '!Ref',
|
|
118
|
+
options: {
|
|
119
|
+
kind: 'scalar',
|
|
120
|
+
construct: (data: any) => {
|
|
121
|
+
return { Ref: data };
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
tag: '!Sub',
|
|
127
|
+
options: {
|
|
128
|
+
kind: 'scalar',
|
|
129
|
+
construct: (data: any) => {
|
|
130
|
+
return { 'Fn::Sub': data };
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
tag: '!Sub',
|
|
136
|
+
options: {
|
|
137
|
+
kind: 'sequence',
|
|
138
|
+
construct: (data: any) => {
|
|
139
|
+
return { 'Fn::Sub': data };
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
const getYamlTypes = (tagAndTypeArr: TagAndType[]) => {
|
|
146
|
+
return tagAndTypeArr.map(({ tag, options }) => {
|
|
147
|
+
return new yaml.Type(tag, options);
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Transform CloudFormation directives in objects. For example, transform
|
|
153
|
+
* !Ref Something in { Ref: Something }.
|
|
154
|
+
*/
|
|
155
|
+
export const getSchema = (tagAndTypeArr: TagAndType[] = []) => {
|
|
156
|
+
return yaml.DEFAULT_SCHEMA.extend(
|
|
157
|
+
getYamlTypes([...tagAndTypeArr, ...cloudFormationTypes])
|
|
158
|
+
);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Transform a JSON in a YAML string.
|
|
163
|
+
*
|
|
164
|
+
* @param cloudFormationTemplate JSON CloudFormation template
|
|
165
|
+
* @returns YAML as string
|
|
166
|
+
*/
|
|
167
|
+
export const dumpToYamlCloudFormationTemplate = (
|
|
168
|
+
cloudFormationTemplate: CloudFormationTemplate
|
|
169
|
+
) => {
|
|
170
|
+
return yaml.dump(cloudFormationTemplate, { schema: getSchema() });
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Transform YAML string in JSON object.
|
|
175
|
+
*
|
|
176
|
+
* @param template template in String format.
|
|
177
|
+
* @param tagAndTypeArr YAML types.
|
|
178
|
+
* @returns JSON template.
|
|
179
|
+
*/
|
|
180
|
+
export const loadCloudFormationTemplate = (
|
|
181
|
+
template: string,
|
|
182
|
+
tagAndTypeArr: TagAndType[] = []
|
|
183
|
+
) => {
|
|
184
|
+
return yaml.load(template, { schema: getSchema(tagAndTypeArr) });
|
|
185
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { CloudFormationTemplate } from './cloudFormationTemplate';
|
|
4
|
+
import { readCloudFormationYamlTemplate } from './readCloudFormationYamlTemplate';
|
|
5
|
+
import { readObjectFile } from './readObjectFile';
|
|
6
|
+
|
|
7
|
+
export const defaultTemplatePaths = ['ts', 'js', 'yaml', 'yml', 'json'].map(
|
|
8
|
+
(extension) => {
|
|
9
|
+
return `./src/cloudformation.${extension}`;
|
|
10
|
+
}
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const findAndReadCloudFormationTemplate = ({
|
|
14
|
+
templatePath: defaultTemplatePath,
|
|
15
|
+
}: {
|
|
16
|
+
templatePath?: string;
|
|
17
|
+
}): CloudFormationTemplate => {
|
|
18
|
+
const templatePath =
|
|
19
|
+
defaultTemplatePath ||
|
|
20
|
+
defaultTemplatePaths
|
|
21
|
+
/**
|
|
22
|
+
* Iterate over extensions. If the template of the current extension is
|
|
23
|
+
* found, we save it on the accumulator and return it every time until
|
|
24
|
+
* the loop ends.
|
|
25
|
+
*/
|
|
26
|
+
.reduce((acc, cur) => {
|
|
27
|
+
if (acc) {
|
|
28
|
+
return acc;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return fs.existsSync(path.resolve(process.cwd(), cur)) ? cur : acc;
|
|
32
|
+
}, '');
|
|
33
|
+
|
|
34
|
+
if (!templatePath) {
|
|
35
|
+
throw new Error('Cannot find a CloudFormation template.');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const extension = templatePath?.split('.').pop() as string;
|
|
39
|
+
|
|
40
|
+
const fullPath = path.resolve(process.cwd(), templatePath);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* We need to read Yaml first because CloudFormation specific tags aren't
|
|
44
|
+
* recognized when parsing a simple Yaml file. I.e., a possible error:
|
|
45
|
+
* "Error message: "unknown tag !<!Ref> at line 21, column 34:\n"
|
|
46
|
+
*/
|
|
47
|
+
if (['yaml', 'yml'].includes(extension)) {
|
|
48
|
+
return readCloudFormationYamlTemplate({ templatePath });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return readObjectFile({ path: fullPath });
|
|
52
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { findAndReadCloudFormationTemplate } from './findAndReadCloudFormationTemplate';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import {
|
|
4
|
+
CloudFormationTemplate,
|
|
5
|
+
TagAndType,
|
|
6
|
+
loadCloudFormationTemplate,
|
|
7
|
+
} from './cloudFormationTemplate';
|
|
8
|
+
|
|
9
|
+
const getTypes = (): TagAndType[] => {
|
|
10
|
+
return [
|
|
11
|
+
{
|
|
12
|
+
tag: `!SubString`,
|
|
13
|
+
options: {
|
|
14
|
+
kind: 'scalar',
|
|
15
|
+
construct: (filePath: string) => {
|
|
16
|
+
return fs
|
|
17
|
+
.readFileSync(path.resolve(process.cwd(), filePath))
|
|
18
|
+
.toString();
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* CloudFormation
|
|
27
|
+
* @param param0
|
|
28
|
+
*/
|
|
29
|
+
export const readCloudFormationYamlTemplate = ({
|
|
30
|
+
templatePath,
|
|
31
|
+
}: {
|
|
32
|
+
templatePath: string;
|
|
33
|
+
}): CloudFormationTemplate => {
|
|
34
|
+
const template = fs.readFileSync(templatePath).toString();
|
|
35
|
+
|
|
36
|
+
const parsed = loadCloudFormationTemplate(template, getTypes());
|
|
37
|
+
|
|
38
|
+
if (!parsed || typeof parsed === 'string') {
|
|
39
|
+
throw new Error('Cannot parse CloudFormation template.');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return parsed as CloudFormationTemplate;
|
|
43
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
|
|
5
|
+
export const readYaml = ({ path }: { path: string }) => {
|
|
6
|
+
const template = fs.readFileSync(path, 'utf8') || JSON.stringify({});
|
|
7
|
+
return yaml.load(template);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* If your file is `.ts`, you must you must export the final object
|
|
12
|
+
* `export default { ... }`. If your file is `.js`, you must you must export
|
|
13
|
+
* the final object `module.exports = { ... }`. `.json` and `.yml/yaml` must
|
|
14
|
+
* define the resources in [JSON](https://www.json.org/json-en.html) and
|
|
15
|
+
* [YAML](https://yaml.org/) format respectively.
|
|
16
|
+
*/
|
|
17
|
+
export const readObjectFile = ({ path }: { path: string }) => {
|
|
18
|
+
if (!fs.existsSync(path)) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const extension = path.split('.').pop();
|
|
23
|
+
|
|
24
|
+
if (extension === 'ts') {
|
|
25
|
+
require('ts-node').register({
|
|
26
|
+
compilerOptions: { module: 'commonjs' },
|
|
27
|
+
transpileOnly: true,
|
|
28
|
+
});
|
|
29
|
+
const tsObj = require(path);
|
|
30
|
+
const obj = tsObj.default || tsObj;
|
|
31
|
+
return typeof obj === 'function' ? obj() : obj;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (extension === 'js') {
|
|
35
|
+
const obj = require(path);
|
|
36
|
+
return typeof obj === 'function' ? obj() : obj;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (extension === 'json') {
|
|
40
|
+
return require(path);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (extension === 'yml' || extension === 'yaml') {
|
|
44
|
+
return readYaml({ path });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {};
|
|
48
|
+
};
|