]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/config-chain/index.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / node_modules / config-chain / index.js
1 var ProtoList = require('proto-list')
2   , path = require('path')
3   , fs = require('fs')
4   , ini = require('ini')
5   , EE = require('events').EventEmitter
6   , url = require('url')
7   , http = require('http')
8
9 var exports = module.exports = function () {
10   var args = [].slice.call(arguments)
11     , conf = new ConfigChain()
12
13   while(args.length) {
14     var a = args.shift()
15     if(a) conf.push
16           ( 'string' === typeof a
17             ? json(a)
18             : a )
19   }
20
21   return conf
22 }
23
24 //recursively find a file...
25
26 var find = exports.find = function () {
27   var rel = path.join.apply(null, [].slice.call(arguments))
28
29   function find(start, rel) {
30     var file = path.join(start, rel)
31     try {
32       fs.statSync(file)
33       return file
34     } catch (err) {
35       if(path.dirname(start) !== start) // root
36         return find(path.dirname(start), rel)
37     }
38   }
39   return find(__dirname, rel)
40 }
41
42 var parse = exports.parse = function (content, file, type) {
43   content = '' + content
44   // if we don't know what it is, try json and fall back to ini
45   // if we know what it is, then it must be that.
46   if (!type) {
47     try { return JSON.parse(content) }
48     catch (er) { return ini.parse(content) }
49   } else if (type === 'json') {
50     if (this.emit) {
51       try { return JSON.parse(content) }
52       catch (er) { this.emit('error', er) }
53     } else {
54       return JSON.parse(content)
55     }
56   } else {
57     return ini.parse(content)
58   }
59 }
60
61 var json = exports.json = function () {
62   var args = [].slice.call(arguments).filter(function (arg) { return arg != null })
63   var file = path.join.apply(null, args)
64   var content
65   try {
66     content = fs.readFileSync(file,'utf-8')
67   } catch (err) {
68     return
69   }
70   return parse(content, file, 'json')
71 }
72
73 var env = exports.env = function (prefix, env) {
74   env = env || process.env
75   var obj = {}
76   var l = prefix.length
77   for(var k in env) {
78     if(k.indexOf(prefix) === 0)
79       obj[k.substring(l)] = env[k]
80   }
81
82   return obj
83 }
84
85 exports.ConfigChain = ConfigChain
86 function ConfigChain () {
87   EE.apply(this)
88   ProtoList.apply(this, arguments)
89   this._awaiting = 0
90   this._saving = 0
91   this.sources = {}
92 }
93
94 // multi-inheritance-ish
95 var extras = {
96   constructor: { value: ConfigChain }
97 }
98 Object.keys(EE.prototype).forEach(function (k) {
99   extras[k] = Object.getOwnPropertyDescriptor(EE.prototype, k)
100 })
101 ConfigChain.prototype = Object.create(ProtoList.prototype, extras)
102
103 ConfigChain.prototype.del = function (key, where) {
104   // if not specified where, then delete from the whole chain, scorched
105   // earth style
106   if (where) {
107     var target = this.sources[where]
108     target = target && target.data
109     if (!target) {
110       return this.emit('error', new Error('not found '+where))
111     }
112     delete target[key]
113   } else {
114     for (var i = 0, l = this.list.length; i < l; i ++) {
115       delete this.list[i][key]
116     }
117   }
118   return this
119 }
120
121 ConfigChain.prototype.set = function (key, value, where) {
122   var target
123
124   if (where) {
125     target = this.sources[where]
126     target = target && target.data
127     if (!target) {
128       return this.emit('error', new Error('not found '+where))
129     }
130   } else {
131     target = this.list[0]
132     if (!target) {
133       return this.emit('error', new Error('cannot set, no confs!'))
134     }
135   }
136   target[key] = value
137   return this
138 }
139
140 ConfigChain.prototype.get = function (key, where) {
141   if (where) {
142     where = this.sources[where]
143     if (where) where = where.data
144     if (where && Object.hasOwnProperty.call(where, key)) return where[key]
145     return undefined
146   }
147   return this.list[0][key]
148 }
149
150 ConfigChain.prototype.save = function (where, type, cb) {
151   if (typeof type === 'function') cb = type, type = null
152   var target = this.sources[where]
153   if (!target || !(target.path || target.source) || !target.data) {
154     // TODO: maybe save() to a url target could be a PUT or something?
155     // would be easy to swap out with a reddis type thing, too
156     return this.emit('error', new Error('bad save target: '+where))
157   }
158
159   if (target.source) {
160     var pref = target.prefix || ''
161     Object.keys(target.data).forEach(function (k) {
162       target.source[pref + k] = target.data[k]
163     })
164     return this
165   }
166
167   var type = type || target.type
168   var data = target.data
169   if (target.type === 'json') {
170     data = JSON.stringify(data)
171   } else {
172     data = ini.stringify(data)
173   }
174
175   this._saving ++
176   fs.writeFile(target.path, data, 'utf8', function (er) {
177     this._saving --
178     if (er) {
179       if (cb) return cb(er)
180       else return this.emit('error', er)
181     }
182     if (this._saving === 0) {
183       if (cb) cb()
184       this.emit('save')
185     }
186   }.bind(this))
187   return this
188 }
189
190 ConfigChain.prototype.addFile = function (file, type, name) {
191   name = name || file
192   var marker = {__source__:name}
193   this.sources[name] = { path: file, type: type }
194   this.push(marker)
195   this._await()
196   fs.readFile(file, 'utf8', function (er, data) {
197     if (er) this.emit('error', er)
198     this.addString(data, file, type, marker)
199   }.bind(this))
200   return this
201 }
202
203 ConfigChain.prototype.addEnv = function (prefix, env, name) {
204   name = name || 'env'
205   var data = exports.env(prefix, env)
206   this.sources[name] = { data: data, source: env, prefix: prefix }
207   return this.add(data, name)
208 }
209
210 ConfigChain.prototype.addUrl = function (req, type, name) {
211   this._await()
212   var href = url.format(req)
213   name = name || href
214   var marker = {__source__:name}
215   this.sources[name] = { href: href, type: type }
216   this.push(marker)
217   http.request(req, function (res) {
218     var c = []
219     var ct = res.headers['content-type']
220     if (!type) {
221       type = ct.indexOf('json') !== -1 ? 'json'
222            : ct.indexOf('ini') !== -1 ? 'ini'
223            : href.match(/\.json$/) ? 'json'
224            : href.match(/\.ini$/) ? 'ini'
225            : null
226       marker.type = type
227     }
228
229     res.on('data', c.push.bind(c))
230     .on('end', function () {
231       this.addString(Buffer.concat(c), href, type, marker)
232     }.bind(this))
233     .on('error', this.emit.bind(this, 'error'))
234
235   }.bind(this))
236   .on('error', this.emit.bind(this, 'error'))
237   .end()
238
239   return this
240 }
241
242 ConfigChain.prototype.addString = function (data, file, type, marker) {
243   data = this.parse(data, file, type)
244   this.add(data, marker)
245   return this
246 }
247
248 ConfigChain.prototype.add = function (data, marker) {
249   if (marker && typeof marker === 'object') {
250     var i = this.list.indexOf(marker)
251     if (i === -1) {
252       return this.emit('error', new Error('bad marker'))
253     }
254     this.splice(i, 1, data)
255     marker = marker.__source__
256     this.sources[marker] = this.sources[marker] || {}
257     this.sources[marker].data = data
258     // we were waiting for this.  maybe emit 'load'
259     this._resolve()
260   } else {
261     if (typeof marker === 'string') {
262       this.sources[marker] = this.sources[marker] || {}
263       this.sources[marker].data = data
264     }
265     // trigger the load event if nothing was already going to do so.
266     this._await()
267     this.push(data)
268     process.nextTick(this._resolve.bind(this))
269   }
270   return this
271 }
272
273 ConfigChain.prototype.parse = exports.parse
274
275 ConfigChain.prototype._await = function () {
276   this._awaiting++
277 }
278
279 ConfigChain.prototype._resolve = function () {
280   this._awaiting--
281   if (this._awaiting === 0) this.emit('load', this)
282 }