@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.
@@ -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
+ };
@@ -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
+ };