UNPKG

3.08 kBJavaScriptView Raw
1
2exports.parse = exports.decode = decode
3exports.stringify = exports.encode = encode
4
5exports.safe = safe
6exports.unsafe = unsafe
7
8var eol = process.platform === "win32" ? "\r\n" : "\n"
9
10function encode (obj, section) {
11 var children = []
12 , out = ""
13
14 Object.keys(obj).forEach(function (k, _, __) {
15 var val = obj[k]
16 if (val && typeof val === "object") {
17 children.push(k)
18 } else {
19 out += safe(k) + " = " + safe(val) + eol
20 }
21 })
22
23 if (section && out.length) {
24 out = "[" + safe(section) + "]" + eol + out
25 }
26
27 children.forEach(function (k, _, __) {
28 var nk = dotSplit(k).join('\\.')
29 var child = encode(obj[k], (section ? section + "." : "") + nk)
30 if (out.length && child.length) {
31 out += eol
32 }
33 out += child
34 })
35
36 return out
37}
38
39function dotSplit (str) {
40 return str.replace(/\1/g, '\2LITERAL\\1LITERAL\2')
41 .replace(/\\\./g, '\1')
42 .split(/\./).map(function (part) {
43 return part.replace(/\1/g, '\\.')
44 .replace(/\2LITERAL\\1LITERAL\2/g, '\1')
45 })
46}
47
48function decode (str) {
49 var out = {}
50 , p = out
51 , section = null
52 , state = "START"
53 // section |key = value
54 , re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i
55 , lines = str.split(/[\r\n]+/g)
56 , section = null
57
58 lines.forEach(function (line, _, __) {
59 //line = line
60 var rem = line.indexOf(";")
61 if (rem !== -1) line = line.substr(0, rem)//.trim()
62 if (!line) return
63 var match = line.match(re)
64 if (!match) return
65 if (match[1] !== undefined) {
66 section = unsafe(match[1])
67 p = out[section] = out[section] || {}
68 return
69 }
70 var key = unsafe(match[2])
71 , value = match[3] ? unsafe((match[4] || "")) : true
72 switch (value) {
73 case 'true':
74 case 'false':
75 case 'null': value = JSON.parse(value)
76 }
77 p[key] = value
78 })
79
80 // {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}}
81 // use a filter to return the keys that have to be deleted.
82 Object.keys(out).filter(function (k, _, __) {
83 if (!out[k] || typeof out[k] !== "object") return false
84 // see if the parent section is also an object.
85 // if so, add it to that, and mark this one for deletion
86 var parts = dotSplit(k)
87 , p = out
88 , l = parts.pop()
89 , nl = l.replace(/\\\./g, '.')
90 parts.forEach(function (part, _, __) {
91 if (!p[part] || typeof p[part] !== "object") p[part] = {}
92 p = p[part]
93 })
94 if (p === out && nl === l) return false
95 p[nl] = out[k]
96 return true
97 }).forEach(function (del, _, __) {
98 delete out[del]
99 })
100
101 return out
102}
103
104function safe (val) {
105 return ( typeof val !== "string"
106 || val.match(/[\r\n]/)
107 || val.match(/^\[/)
108 || (val.length > 1
109 && val.charAt(0) === "\""
110 && val.slice(-1) === "\"")
111 || val !== val.trim() ) ? JSON.stringify(val) : val
112}
113
114function unsafe (val) {
115 val = (val || "").trim()
116 if (val.charAt(0) === "\"" && val.slice(-1) === "\"") {
117 try { val = JSON.parse(val) } catch (_) {}
118 }
119 return val
120}