1 | fs = require "fs"
|
2 |
|
3 | paramNames = []
|
4 | INDENT = " "
|
5 |
|
6 | convertToArgs = (string) ->
|
7 | string.replace("[", "").replace("]", "").replace(/\n$/, "")
|
8 |
|
9 | CFN_FUNCS = {
|
10 | "Fn::Base64": (obj, level, parentIsObj) ->
|
11 | "@Base64(#{convertJson obj["Fn::Base64"], level, parentIsObj})"
|
12 |
|
13 | "Fn::FindInMap": (obj, level, parentIsObj) ->
|
14 | string = convertJson obj["Fn::FindInMap"], level, parentIsObj
|
15 | "@FindInMap(#{convertToArgs string})"
|
16 |
|
17 | "Fn::GetAtt": (obj, level, parentIsObj) ->
|
18 | string = convertJson obj["Fn::GetAtt"], level, parentIsObj
|
19 | "@GetAtt(#{convertToArgs string})"
|
20 |
|
21 | "Fn::GetAZs": (obj, level, parentIsObj) ->
|
22 | "@GetAZs(#{convertJson obj["Fn::GetAZs"], level, parentIsObj})"
|
23 |
|
24 | "Fn::Join": (obj, level, parentIsObj) ->
|
25 | join = obj["Fn::Join"]
|
26 | string = convertJson join[1], level, parentIsObj
|
27 | "@Join(\"#{escapeString join[0]}\", #{string.replace(/\n$/, "")})"
|
28 |
|
29 | "Ref": (obj) ->
|
30 | if paramNames.indexOf(obj.Ref) > -1
|
31 | "@Params.#{obj.Ref}"
|
32 | else if obj.Ref == "AWS::Region"
|
33 | "@Region"
|
34 | else if obj.Ref == "AWS::StackName"
|
35 | "@StackName"
|
36 | else
|
37 | "@Resources.#{obj.Ref}"
|
38 | }
|
39 |
|
40 |
|
41 | indent = (text, times) ->
|
42 | front = ""
|
43 | for i in [0..times]
|
44 | front += INDENT
|
45 | return front + text
|
46 |
|
47 | convertArray = (arr, level = 0, parentIsArray) ->
|
48 | if arr.length > 5 or typeof arr[0] is "object" then addNewline = true else addNewline = false
|
49 | output = "["
|
50 | if addNewline
|
51 | output += "\n"
|
52 |
|
53 | i = arr.length
|
54 | for val in arr
|
55 | if addNewline
|
56 | output += indent "#{convertJson val, level + 1, true}\n", level
|
57 | else
|
58 | if --i
|
59 | output += "#{convertJson val, level}, "
|
60 | else
|
61 | output += convertJson val, level
|
62 |
|
63 | end = "]\n"
|
64 | if parentIsArray
|
65 | end = "]"
|
66 |
|
67 | if addNewline
|
68 | end = indent(end, level - 1)
|
69 |
|
70 | output += end
|
71 |
|
72 | return output
|
73 |
|
74 | isFunction = (obj) ->
|
75 | for fun in Object.keys(CFN_FUNCS)
|
76 | return true if obj[fun]
|
77 | return false
|
78 |
|
79 | convertFunction = (obj, level, parentIsObj) ->
|
80 | output = null
|
81 | for cfn, fun of CFN_FUNCS
|
82 | if obj[cfn]
|
83 | output = fun obj, level, parentIsObj
|
84 |
|
85 | return output
|
86 |
|
87 | convertObj = (obj, level = 0, parentIsObj) ->
|
88 | return indent convertFunction(obj, level, parentIsObj) if isFunction obj
|
89 | if parentIsObj
|
90 | output = "\n"
|
91 | else
|
92 | output = ""
|
93 | keyLength = Object.keys(obj).length
|
94 | for key, val of obj
|
95 | if key.match /\W/
|
96 | key = "\"#{key}\""
|
97 | output += indent "#{key} : #{convertJson val, level + 1, true}", level
|
98 | if --keyLength
|
99 | output += "\n"
|
100 | return output
|
101 |
|
102 | escapeString = (string) ->
|
103 | string
|
104 | .replace("\n", "\\n")
|
105 | .replace(/'/g, "\\'")
|
106 | .replace(/"/g, '\\"')
|
107 |
|
108 | convertJson = (obj, level = 0, parentIsObj) ->
|
109 | if Array.isArray(obj)
|
110 | convertArray obj, level, parentIsObj
|
111 | else if typeof obj is "object"
|
112 | convertObj obj, level, parentIsObj
|
113 | else if typeof obj is "string"
|
114 |
|
115 | "\"#{escapeString obj}\""
|
116 | else if typeof obj is "number"
|
117 | obj
|
118 |
|
119 | checkForParams = (obj) ->
|
120 | if obj and Object.keys(obj).length
|
121 | true
|
122 | else
|
123 | false
|
124 |
|
125 | convertParam = (name, val) ->
|
126 | throw new Error "type is required for Param #{name}" if not val.Type
|
127 | paramNames.push name
|
128 | output = null
|
129 | if val.Description
|
130 | output =
|
131 | """
|
132 | @Param.#{val.Type} \"#{name}\", \"#{val.Description}\"
|
133 | """
|
134 | else
|
135 | output =
|
136 | """
|
137 | @Param.#{val.Type} \"#{name}\"
|
138 | """
|
139 |
|
140 | delete val.Type
|
141 | delete val.Description
|
142 | if checkForParams val
|
143 | output += ",\n"
|
144 | output += convertJson val
|
145 | return output + "\n\n"
|
146 |
|
147 | convertMapping = (name, val) ->
|
148 | output =
|
149 | """
|
150 | @Mapping \"#{name}\",
|
151 |
|
152 | """
|
153 | output += convertJson val
|
154 | return output + "\n\n"
|
155 |
|
156 | convertResource = (name, val) ->
|
157 | throw new Error "missing type for resource with #{name}" if not val.Type
|
158 | output =
|
159 | """
|
160 | @#{val.Type.replace /::/g, "."} \"#{name}\"
|
161 | """
|
162 | if val.Metadata
|
163 | delete val.Type
|
164 | if checkForParams val
|
165 | output += ",\n"
|
166 | output += convertJson val
|
167 | else
|
168 | if checkForParams val.Properties
|
169 | output += ",\n"
|
170 | output += convertJson val.Properties
|
171 |
|
172 | return output + "\n\n"
|
173 |
|
174 |
|
175 | convertOutput = (name, val) ->
|
176 | throw new Error "missing value for output with #{name}" if not val.Value
|
177 | if val.Description
|
178 | output =
|
179 | """
|
180 | @Output \"#{name}\", \"#{val.Description}\",
|
181 |
|
182 | """
|
183 | else
|
184 | output =
|
185 | """
|
186 | @Output \"#{name}\",
|
187 |
|
188 | """
|
189 |
|
190 | output += convertJson val.Value
|
191 |
|
192 | return output + "\n\n"
|
193 |
|
194 | convertCondition = (name, intrinsicfn) ->
|
195 | throw new Error "missing intrinsicfn for condition with #{name}" if not intrinsicfn
|
196 | output =
|
197 | """
|
198 | @Condition \"#{name}\",
|
199 | """
|
200 | output += convertJson intrinsicfn
|
201 | return output + "\n\n"
|
202 |
|
203 | convertTopLevel = (params, converter) ->
|
204 | output = ""
|
205 | for name, val of params
|
206 | output += converter name, val
|
207 |
|
208 | return output
|
209 |
|
210 | createForwardDeclrations = (resources) ->
|
211 | output = ""
|
212 | for res, val of resources
|
213 | output += "@DeclareResource(\"#{res}\")\n"
|
214 |
|
215 | output
|
216 |
|
217 |
|
218 | convertToCoffin = (templateObj) ->
|
219 | output = ""
|
220 | output += createForwardDeclrations templateObj.Resources
|
221 | for key, val of templateObj
|
222 | switch key
|
223 | when "AWSTemplateFormatVersion"
|
224 |
|
225 | break
|
226 | when "Description"
|
227 | output += "@Description \"#{val}\"\n\n"
|
228 | when "Parameters"
|
229 | output += convertTopLevel val, convertParam
|
230 | when "Mappings"
|
231 | output += convertTopLevel val, convertMapping
|
232 | when "Resources"
|
233 | output += convertTopLevel val, convertResource
|
234 | when "Outputs"
|
235 | output += convertTopLevel val, convertOutput
|
236 | when "Conditions"
|
237 | output += convertTopLevel val, convertCondition
|
238 | else
|
239 | console.log "don't have key #{key}"
|
240 |
|
241 | return output
|
242 |
|
243 | module.exports = convertToCoffin
|