Projekt

Obecné

Profil

Stáhnout (4.66 KB) Statistiky
| Větev: | Revize:
1
exports.parse = exports.decode = decode
2

    
3
exports.stringify = exports.encode = encode
4

    
5
exports.safe = safe
6
exports.unsafe = unsafe
7

    
8
var eol = typeof process !== 'undefined' &&
9
  process.platform === 'win32' ? '\r\n' : '\n'
10

    
11
function encode (obj, opt) {
12
  var children = []
13
  var out = ''
14

    
15
  if (typeof opt === 'string') {
16
    opt = {
17
      section: opt,
18
      whitespace: false
19
    }
20
  } else {
21
    opt = opt || {}
22
    opt.whitespace = opt.whitespace === true
23
  }
24

    
25
  var separator = opt.whitespace ? ' = ' : '='
26

    
27
  Object.keys(obj).forEach(function (k, _, __) {
28
    var val = obj[k]
29
    if (val && Array.isArray(val)) {
30
      val.forEach(function (item) {
31
        out += safe(k + '[]') + separator + safe(item) + '\n'
32
      })
33
    } else if (val && typeof val === 'object') {
34
      children.push(k)
35
    } else {
36
      out += safe(k) + separator + safe(val) + eol
37
    }
38
  })
39

    
40
  if (opt.section && out.length) {
41
    out = '[' + safe(opt.section) + ']' + eol + out
42
  }
43

    
44
  children.forEach(function (k, _, __) {
45
    var nk = dotSplit(k).join('\\.')
46
    var section = (opt.section ? opt.section + '.' : '') + nk
47
    var child = encode(obj[k], {
48
      section: section,
49
      whitespace: opt.whitespace
50
    })
51
    if (out.length && child.length) {
52
      out += eol
53
    }
54
    out += child
55
  })
56

    
57
  return out
58
}
59

    
60
function dotSplit (str) {
61
  return str.replace(/\1/g, '\u0002LITERAL\\1LITERAL\u0002')
62
    .replace(/\\\./g, '\u0001')
63
    .split(/\./).map(function (part) {
64
      return part.replace(/\1/g, '\\.')
65
      .replace(/\2LITERAL\\1LITERAL\2/g, '\u0001')
66
    })
67
}
68

    
69
function decode (str) {
70
  var out = {}
71
  var p = out
72
  var section = null
73
  //          section     |key      = value
74
  var re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i
75
  var lines = str.split(/[\r\n]+/g)
76

    
77
  lines.forEach(function (line, _, __) {
78
    if (!line || line.match(/^\s*[;#]/)) return
79
    var match = line.match(re)
80
    if (!match) return
81
    if (match[1] !== undefined) {
82
      section = unsafe(match[1])
83
      p = out[section] = out[section] || {}
84
      return
85
    }
86
    var key = unsafe(match[2])
87
    var value = match[3] ? unsafe(match[4]) : true
88
    switch (value) {
89
      case 'true':
90
      case 'false':
91
      case 'null': value = JSON.parse(value)
92
    }
93

    
94
    // Convert keys with '[]' suffix to an array
95
    if (key.length > 2 && key.slice(-2) === '[]') {
96
      key = key.substring(0, key.length - 2)
97
      if (!p[key]) {
98
        p[key] = []
99
      } else if (!Array.isArray(p[key])) {
100
        p[key] = [p[key]]
101
      }
102
    }
103

    
104
    // safeguard against resetting a previously defined
105
    // array by accidentally forgetting the brackets
106
    if (Array.isArray(p[key])) {
107
      p[key].push(value)
108
    } else {
109
      p[key] = value
110
    }
111
  })
112

    
113
  // {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}}
114
  // use a filter to return the keys that have to be deleted.
115
  Object.keys(out).filter(function (k, _, __) {
116
    if (!out[k] ||
117
      typeof out[k] !== 'object' ||
118
      Array.isArray(out[k])) {
119
      return false
120
    }
121
    // see if the parent section is also an object.
122
    // if so, add it to that, and mark this one for deletion
123
    var parts = dotSplit(k)
124
    var p = out
125
    var l = parts.pop()
126
    var nl = l.replace(/\\\./g, '.')
127
    parts.forEach(function (part, _, __) {
128
      if (!p[part] || typeof p[part] !== 'object') p[part] = {}
129
      p = p[part]
130
    })
131
    if (p === out && nl === l) {
132
      return false
133
    }
134
    p[nl] = out[k]
135
    return true
136
  }).forEach(function (del, _, __) {
137
    delete out[del]
138
  })
139

    
140
  return out
141
}
142

    
143
function isQuoted (val) {
144
  return (val.charAt(0) === '"' && val.slice(-1) === '"') ||
145
    (val.charAt(0) === "'" && val.slice(-1) === "'")
146
}
147

    
148
function safe (val) {
149
  return (typeof val !== 'string' ||
150
    val.match(/[=\r\n]/) ||
151
    val.match(/^\[/) ||
152
    (val.length > 1 &&
153
     isQuoted(val)) ||
154
    val !== val.trim())
155
      ? JSON.stringify(val)
156
      : val.replace(/;/g, '\\;').replace(/#/g, '\\#')
157
}
158

    
159
function unsafe (val, doUnesc) {
160
  val = (val || '').trim()
161
  if (isQuoted(val)) {
162
    // remove the single quotes before calling JSON.parse
163
    if (val.charAt(0) === "'") {
164
      val = val.substr(1, val.length - 2)
165
    }
166
    try { val = JSON.parse(val) } catch (_) {}
167
  } else {
168
    // walk the val to find the first not-escaped ; character
169
    var esc = false
170
    var unesc = ''
171
    for (var i = 0, l = val.length; i < l; i++) {
172
      var c = val.charAt(i)
173
      if (esc) {
174
        if ('\\;#'.indexOf(c) !== -1) {
175
          unesc += c
176
        } else {
177
          unesc += '\\' + c
178
        }
179
        esc = false
180
      } else if (';#'.indexOf(c) !== -1) {
181
        break
182
      } else if (c === '\\') {
183
        esc = true
184
      } else {
185
        unesc += c
186
      }
187
    }
188
    if (esc) {
189
      unesc += '\\'
190
    }
191
    return unesc.trim()
192
  }
193
  return val
194
}
(3-3/4)