• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2
3var Parser = require('jsonparse')
4  , through = require('through')
5
6var bufferFrom = Buffer.from && Buffer.from !== Uint8Array.from
7
8/*
9
10  the value of this.stack that creationix's jsonparse has is weird.
11
12  it makes this code ugly, but his problem is way harder that mine,
13  so i'll forgive him.
14
15*/
16
17exports.parse = function (path, map) {
18  var header, footer
19  var parser = new Parser()
20  var stream = through(function (chunk) {
21    if('string' === typeof chunk)
22      chunk = bufferFrom ? Buffer.from(chunk) : new Buffer(chunk)
23    parser.write(chunk)
24  },
25  function (data) {
26    if(data)
27      stream.write(data)
28    if (header)
29        stream.emit('header', header)
30    if (footer)
31      stream.emit('footer', footer)
32    stream.queue(null)
33  })
34
35  if('string' === typeof path)
36    path = path.split('.').map(function (e) {
37      if (e === '$*')
38        return {emitKey: true}
39      else if (e === '*')
40        return true
41      else if (e === '') // '..'.split('.') returns an empty string
42        return {recurse: true}
43      else
44        return e
45    })
46
47
48  var count = 0, _key
49  if(!path || !path.length)
50    path = null
51
52  parser.onValue = function (value) {
53    if (!this.root)
54      stream.root = value
55
56    if(! path) return
57
58    var i = 0 // iterates on path
59    var j  = 0 // iterates on stack
60    var emitKey = false;
61    var emitPath = false;
62    while (i < path.length) {
63      var key = path[i]
64      var c
65      j++
66
67      if (key && !key.recurse) {
68        c = (j === this.stack.length) ? this : this.stack[j]
69        if (!c) return
70        if (! check(key, c.key)) {
71          setHeaderFooter(c.key, value)
72          return
73        }
74        emitKey = !!key.emitKey;
75        emitPath = !!key.emitPath;
76        i++
77      } else {
78        i++
79        var nextKey = path[i]
80        if (! nextKey) return
81        while (true) {
82          c = (j === this.stack.length) ? this : this.stack[j]
83          if (!c) return
84          if (check(nextKey, c.key)) {
85            i++;
86            if (!Object.isFrozen(this.stack[j]))
87              this.stack[j].value = null
88            break
89          } else {
90            setHeaderFooter(c.key, value)
91          }
92          j++
93        }
94      }
95
96    }
97
98    // emit header
99    if (header) {
100      stream.emit('header', header);
101      header = false;
102    }
103    if (j !== this.stack.length) return
104
105    count ++
106    var actualPath = this.stack.slice(1).map(function(element) { return element.key }).concat([this.key])
107    var data = value
108    if(null != data)
109      if(null != (data = map ? map(data, actualPath) : data)) {
110        if (emitKey || emitPath) {
111          data = { value: data };
112          if (emitKey)
113            data["key"] = this.key;
114          if (emitPath)
115            data["path"] = actualPath;
116        }
117
118        stream.queue(data)
119      }
120    if (this.value) delete this.value[this.key]
121    for(var k in this.stack)
122      if (!Object.isFrozen(this.stack[k]))
123        this.stack[k].value = null
124  }
125  parser._onToken = parser.onToken;
126
127  parser.onToken = function (token, value) {
128    parser._onToken(token, value);
129    if (this.stack.length === 0) {
130      if (stream.root) {
131        if(!path)
132          stream.queue(stream.root)
133        count = 0;
134        stream.root = null;
135      }
136    }
137  }
138
139  parser.onError = function (err) {
140    if(err.message.indexOf("at position") > -1)
141      err.message = "Invalid JSON (" + err.message + ")";
142    stream.emit('error', err)
143  }
144
145  return stream
146
147  function setHeaderFooter(key, value) {
148    // header has not been emitted yet
149    if (header !== false) {
150      header = header || {}
151      header[key] = value
152    }
153
154    // footer has not been emitted yet but header has
155    if (footer !== false && header === false) {
156      footer = footer || {}
157      footer[key] = value
158    }
159  }
160}
161
162function check (x, y) {
163  if ('string' === typeof x)
164    return y == x
165  else if (x && 'function' === typeof x.exec)
166    return x.exec(y)
167  else if ('boolean' === typeof x || 'object' === typeof x)
168    return x
169  else if ('function' === typeof x)
170    return x(y)
171  return false
172}
173
174exports.stringify = function (op, sep, cl, indent) {
175  indent = indent || 0
176  if (op === false){
177    op = ''
178    sep = '\n'
179    cl = ''
180  } else if (op == null) {
181
182    op = '[\n'
183    sep = '\n,\n'
184    cl = '\n]\n'
185
186  }
187
188  //else, what ever you like
189
190  var stream
191    , first = true
192    , anyData = false
193  stream = through(function (data) {
194    anyData = true
195    try {
196      var json = JSON.stringify(data, null, indent)
197    } catch (err) {
198      return stream.emit('error', err)
199    }
200    if(first) { first = false ; stream.queue(op + json)}
201    else stream.queue(sep + json)
202  },
203  function (data) {
204    if(!anyData)
205      stream.queue(op)
206    stream.queue(cl)
207    stream.queue(null)
208  })
209
210  return stream
211}
212
213exports.stringifyObject = function (op, sep, cl, indent) {
214  indent = indent || 0
215  if (op === false){
216    op = ''
217    sep = '\n'
218    cl = ''
219  } else if (op == null) {
220
221    op = '{\n'
222    sep = '\n,\n'
223    cl = '\n}\n'
224
225  }
226
227  //else, what ever you like
228
229  var first = true
230  var anyData = false
231  var stream = through(function (data) {
232    anyData = true
233    var json = JSON.stringify(data[0]) + ':' + JSON.stringify(data[1], null, indent)
234    if(first) { first = false ; this.queue(op + json)}
235    else this.queue(sep + json)
236  },
237  function (data) {
238    if(!anyData) this.queue(op)
239    this.queue(cl)
240
241    this.queue(null)
242  })
243
244  return stream
245}
246
247
248