Tizen 2.0 Release
[platform/framework/web/web-ui-fw.git] / libs / js / jquery-mobile-1.2.0 / node_modules / grunt / node_modules / nodeunit / node_modules / tap / node_modules / yamlish / yamlish.js
1 exports.encode = encode
2 exports.decode = decode
3
4 var seen = []
5 function encode (obj, indent) {
6   var deep = arguments[2]
7   if (!indent) indent = "  "
8
9   if (obj instanceof String ||
10       Object.prototype.toString.call(obj) === "[object String]") {
11     obj = obj.toString()
12   }
13
14   if (obj instanceof Number ||
15       Object.prototype.toString.call(obj) === "[object Number]") {
16     obj = obj.valueOf()
17   }
18
19   // take out the easy ones.
20   switch (typeof obj) {
21     case "string":
22       obj = obj.trim()
23       if (obj.indexOf("\n") !== -1) {
24         return "|\n" + indent + obj.split(/\r?\n/).join("\n"+indent)
25       } else {
26         return (obj)
27       }
28
29     case "number":
30       return obj.toString(10)
31
32     case "function":
33       return encode(obj.toString(), indent, true)
34
35     case "boolean":
36       return obj.toString()
37
38     case "undefined":
39       // fallthrough
40     case "object":
41       // at this point we know it types as an object
42       if (!obj) return "~"
43
44       if (obj instanceof Date ||
45           Object.prototype.toString.call(obj) === "[object Date]") {
46         return JSON.stringify("[Date " + obj.toISOString() + "]")
47       }
48
49       if (obj instanceof RegExp ||
50           Object.prototype.toString.call(obj) === "[object RegExp]") {
51         return JSON.stringify(obj.toString())
52       }
53
54       if (obj instanceof Boolean ||
55           Object.prototype.toString.call(obj) === "[object Boolean]") {
56         return obj.toString()
57       }
58
59       if (seen.indexOf(obj) !== -1) {
60         return "[Circular]"
61       }
62       seen.push(obj)
63
64       if (typeof Buffer === "function" &&
65           typeof Buffer.isBuffer === "function" &&
66           Buffer.isBuffer(obj)) return obj.inspect()
67
68       if (obj instanceof Error) {
69         var o = { name: obj.name
70                 , message: obj.message
71                 , type: obj.type }
72
73         if (obj.code) o.code = obj.code
74         if (obj.errno) o.errno = obj.errno
75         if (obj.type) o.type = obj.type
76         obj = o
77       }
78
79       var out = ""
80
81       if (Array.isArray(obj)) {
82         var out = "\n" + indent + "- " +obj.map(function (item) {
83           return encode(item, indent + "  ", true)
84         }).join("\n"+indent + "- ")
85         break
86       }
87
88       // an actual object
89       var keys = Object.keys(obj)
90         , niceKeys = keys.map(function (k) {
91             return (k.match(/^[a-zA-Z0-9_]+$/) ? k : JSON.stringify(k)) + ": "
92           })
93       //console.error(keys, niceKeys, obj)
94       var maxLength = Math.max.apply(Math, niceKeys.map(function (k) {
95             return k.length
96           }).concat(0))
97       //console.error(niceKeys, maxLength)
98
99       var spaces = new Array(maxLength + 1).join(" ")
100
101       if (!deep) indent += "  "
102       out = "\n" + indent + keys.map(function (k, i) {
103         var niceKey = niceKeys[i]
104         return niceKey + spaces.substr(niceKey.length)
105                        + encode(obj[k], indent + "  ", true)
106       }).join("\n" + indent)
107       break
108
109     default: return ""
110   }
111   if (!deep) seen.length = 0
112   return out
113 }
114
115 function decode (str) {
116   var v = str.trim()
117     , d
118     , dateRe = /^\[Date ([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}(?::[0-9]{2})?(?:\.[0-9]{3})?(?:[A-Z]+)?)\]$/
119
120   if (v === "~") return null
121
122   try {
123     var jp = JSON.parse(str)
124   } catch (e) {
125     var jp = ""
126   }
127
128   if (jp &&
129       typeof jp === "string" &&
130       (d = jp.match(dateRe)) &&
131       (d = Date.parse(d[1]))) {
132     return new Date(d)
133   }
134
135   if (typeof jp === "boolean") return jp
136   if (v && !isNaN(v)) return parseInt(v, 10)
137
138   // something interesting.
139   var lines = str.split(/\r?\n/)
140   // check if it's some kind of string or something.
141   // if the first line is > or | then it's a wrapping indented string.
142   // if the first line is blank, and there are many lines,
143   // then it's an array or object.
144   // otherwise, it's just ""
145   var first = lines.shift().trim()
146   if (lines.length) lines = undent(lines)
147   switch (first) {
148     case "|":
149       return lines.join("\n")
150     case ">":
151       return lines.join("\n").split(/\n{2,}/).map(function (l) {
152         return l.split(/\n/).join(" ")
153       }).join("\n")
154     default:
155       if (!lines.length) return first
156       // array or object.
157       // the first line will be either "- value" or "key: value"
158       return lines[0].charAt(0) === "-" ? decodeArr(lines) : decodeObj(lines)
159   }
160 }
161
162 function decodeArr (lines) {
163   var out = []
164     , key = 0
165     , val = []
166   for (var i = 0, l = lines.length; i < l; i ++) {
167     // if it starts with a -, then it's a new thing
168     var line = lines[i]
169     if (line.charAt(0) === "-") {
170       if (val.length) {
171         out[key ++] = decode(val.join("\n"))
172         val.length = 0
173       }
174       val.push(line.substr(1).trim())
175     } else if (line.charAt(0) === " ") {
176       val.push(line)
177     } else return []
178   }
179   if (val.length) {
180     out[key ++] = decode(val.join("\n"))
181   }
182   return out
183 }
184
185 function decodeObj (lines) {
186   var out = {}
187     , val = []
188     , key = null
189
190   for (var i = 0, l = lines.length; i < l; i ++) {
191     var line = lines[i]
192     if (line.charAt(0) === " ") {
193       val.push(line)
194       continue
195     }
196     // some key:val
197     if (val.length) {
198       out[key] = decode(val.join("\n"))
199       val.length = 0
200     }
201     // parse out the quoted key
202     var first
203     if (line.charAt(0) === "\"") {
204       for (var ii = 1, ll = line.length, esc = false; ii < ll; ii ++) {
205         var c = line.charAt(ii)
206         if (c === "\\") {
207           esc = !esc
208         } else if (c === "\"" && !esc) {
209           break
210         }
211       }
212       key = JSON.parse(line.substr(0, ii + 1))
213       line = line.substr(ii + 1)
214       first = line.substr(line.indexOf(":") + 1).trim()
215     } else {
216       var kv = line.split(":")
217       key = kv.shift()
218       first = kv.join(":").trim()
219     }
220     // now we've set a key, and "first" has the first line of the value.
221     val.push(first.trim())
222   }
223   if (val.length) out[key] = decode(val.join("\n"))
224   return out
225 }
226
227 function undent (lines) {
228   var i = lines[0].match(/^\s*/)[0].length
229   return lines.map(function (line) {
230     return line.substr(i)
231   })
232 }
233
234
235 // XXX Turn this into proper tests.
236 if (require.main === module) {
237 var obj = [{"bigstring":new Error().stack}
238           ,{ar:[{list:"of"},{some:"objects"}]}
239           ,{date:new Date()}
240           ,{"super huge string":new Error().stack}
241           ]
242
243 Date.prototype.toJSON = function (k, val) {
244   console.error(k, val, this)
245   return this.toISOString() + " (it's a date)"
246 }
247
248 var enc = encode(obj)
249   , dec = decode(enc)
250   , encDec = encode(dec)
251
252 console.error(JSON.stringify({ obj : obj
253                              , enc : enc.split(/\n/)
254                              , dec : dec }, null, 2), encDec === enc)
255
256 var num = 100
257   , encNum = encode(num)
258   , decEncNum = decode(encNum)
259 console.error([num, encNum, decEncNum])
260 }