pax_global_header00006660000000000000000000000064117056743000014515gustar00rootroot0000000000000052 comment=a40a65eb7b030e4f1ce2d54173d89be57fabbbc1 dodo-node-jsconfig-a40a65e/000077500000000000000000000000001170567430000155745ustar00rootroot00000000000000dodo-node-jsconfig-a40a65e/.gitignore000066400000000000000000000000531170567430000175620ustar00rootroot00000000000000*~ *.swp lib/* .lock-wscript node_modules/ dodo-node-jsconfig-a40a65e/.npmignore000066400000000000000000000000161170567430000175700ustar00rootroot00000000000000Cakefile src/ dodo-node-jsconfig-a40a65e/Cakefile000066400000000000000000000005351170567430000172250ustar00rootroot00000000000000path = require 'path' { run, compileScript } = require 'muffin' task 'build', 'compile coffeescript → javascript', (options) -> run options:options files:[ "./src/**/*.coffee" ] map: 'src/(.+).coffee': (m) -> compileScript m[0], path.join("lib" ,"#{m[1]}.js"), options dodo-node-jsconfig-a40a65e/LICENSE000066400000000000000000000020501170567430000165760ustar00rootroot00000000000000Copyright (c) 2011 ▟ ▖▟ ▖(dodo) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. dodo-node-jsconfig-a40a65e/README.md000066400000000000000000000046631170567430000170640ustar00rootroot00000000000000# jsconfig loading configs from javascript files with default configs and cli support ## installation npm install jsconfig ## usage jsconfig can load config file formats whatever [node.js can require](http://nodejs.org/docs/latest/api/modules.html#file_Modules): * by default it's always possible to load `*.js` files * if you want to use coffee-script config files, just do a require('coffee-script') before and you're able to require `*.coffee` files as well * since node.js 0.5.x it's even possible to require `.*json` files * if you're hardcore you can write your config in cpp and compile them to `*.node` files ```javascript var config = require('jsconfig'); config.load('./config.js', function () { console.log(config); }); // in another file config = require('jsconfig'); // this is filled after config.load call ``` a normal config file structures looks like this: ```javascript module.exports = {}; ``` ### config.load ```javascript config.load('./db-config.js', './server-config.js'/*, […]*/); console.log(config); // or config.load('./db-config.js', './server-config.js'/*, […]*/, function () { console.log(config); }); ``` load all config files and fills config with all settings. __required__ ### config.defaults ```javascript config.defaults('./db-config.default.js', './server-config.default.js'/*, […]*/); ``` load some default config files. ### config.set ```javascript config.set('ignore unknown', true); // default is false ``` ignore all nonexisting config files and options. does not apply on default config files. ```javascript config.set('env', {USER: 'user.name'}); // similar to config.user.name = process.env.USER ``` define all environment variables, that should be included into config. this overwrites config file values (default config files too). ### config.cli ```javascript config.cli({ user: ['user.name', ['u', "user name", 'string']], debug: [false, "debug mode", 'bool'], }); // results only in config.user.name = opts.user (after config.load call) ``` this sets up the command line interface. its basicly [node-cli](https://github.com/chriso/cli) with on little change: if cli result should be saved in config, the cli-array should be packed into a second (outer) array as second element (the first is the position in the config object). ### config.merge ```javascript config.merge({user:{name:'foo'}}); // or config.merge('./hot-config.js'); ``` deep copy new values into config. dodo-node-jsconfig-a40a65e/example/000077500000000000000000000000001170567430000172275ustar00rootroot00000000000000dodo-node-jsconfig-a40a65e/example/cli.js000066400000000000000000000007421170567430000203370ustar00rootroot00000000000000 var config = require('../jsconfig'); config.defaults(__dirname+'/config.default.js'); config.set('env', { TEST: 'type', PORT: ['http.port', parseInt], }); config.set('ignore unknown', true); config.set('opts', { test: 'type', }); config.cli({ port: ['http.port', ['p', "give me a port!", 'int']], test: [false, "change the config type!", 'string'], }); config.load(__dirname+'/config.js', function (args, opts) { console.log(args, opts, config); }); dodo-node-jsconfig-a40a65e/example/config.default.js000066400000000000000000000000541170567430000224540ustar00rootroot00000000000000 module.exports = { type: "default", }; dodo-node-jsconfig-a40a65e/example/config.js000066400000000000000000000000571170567430000210340ustar00rootroot00000000000000 module.exports = { type: "production", }; dodo-node-jsconfig-a40a65e/example/simple.js000066400000000000000000000002501170567430000210530ustar00rootroot00000000000000 var config = require('../jsconfig'); config.defaults(__dirname+'/config.default.js'); config.load(__dirname+'/config.js', function () { console.log(config); }); dodo-node-jsconfig-a40a65e/example/sync.js000066400000000000000000000003431170567430000205410ustar00rootroot00000000000000 var config = require('../jsconfig'); config.defaults(__dirname+'/config.default.js'); config.set('env', { TEST: 'type', PORT: ['http.port', parseInt], }); config.load(__dirname+'/config.js'); console.log(config); dodo-node-jsconfig-a40a65e/jsconfig.js000066400000000000000000000000541170567430000177330ustar00rootroot00000000000000 module.exports = require('./lib/jsconfig') dodo-node-jsconfig-a40a65e/package.json000066400000000000000000000012551170567430000200650ustar00rootroot00000000000000{ "name": "jsconfig" , "description": "async configuration loader with cli support" , "version": "0.2.0" , "homepage": "https://github.com/dodo/node-jsconfig" , "author": "dodo (https://github.com/dodo)" , "repository": {"type": "git", "url": "git://github.com/dodo/node-jsconfig.git"} , "main": "jsconfig.js" , "engines": {"node": ">= 0.4.x"} , "keywords": ["configure", "configuration", "async"] , "scripts": { "prepublish": "cake build"} , "dependencies": { "cli": ">= 0.3.7"} , "devDependencies": { "muffin": ">= 0.2.6", "coffee-script": ">= 1.1.2"} , "licenses" : [ { "type": "MIT" , "url": "http://github.com/dodo/node-jsconfig/raw/master/LICENSE"} ] } dodo-node-jsconfig-a40a65e/src/000077500000000000000000000000001170567430000163635ustar00rootroot00000000000000dodo-node-jsconfig-a40a65e/src/jsconfig.coffee000066400000000000000000000131151170567430000213370ustar00rootroot00000000000000cli = require 'cli' { deep_merge, deep_set, deep_get, inplace_merge, load_files, ruthless_load_files } = require './util' { isArray } = Array defaults = {} map = env:{}, opts:{}, args:[] options = 'cli': no 'cli parse': no 'ignore unknown':no module.exports = config = merge: (more) -> files = undefined # check if a filename or a list of filenames is applied if typeof more is 'string' files = [more] else if isArray(more) files = more # load files if files? if options['ignore unknown'] more = ruthless_load_files files... else more = load_files files... # merge into config inplace_merge config, more return this defaults: (files...) -> if options['ignore unknown'] defaults = deep_merge defaults, ruthless_load_files files... else defaults = deep_merge defaults, load_files files... return this set: (key, value) -> if map[key]? map[key] = value else options[key] = value return this cli: (opts) -> if typeof opts is 'function' options['cli'] = opts else options['cli'] = yes if options['cli'] is no if isArray(opts) options['cli parse'] = [] if options['cli parse'] is no options['cli parse'] = options['cli parse'].concat opts else options['cli parse'] = {} if options['cli parse'] is no inplace_merge options['cli parse'], opts return this load: (files..., callback) -> # when no callback given then it's a file unless typeof callback is 'function' files.push callback callback = undefined # when cli is enabled we totally need a callback if options['cli'] and not callback? throw new Error 'if you want to use cli you have to provide a callback.' # load environment ontop of defaults for key, target of map.env continue unless process.env[key]? if isArray(target) # do something special with env value, e.g. parsing it deep_set defaults, target[0], target[1](process.env[key]) else deep_set defaults, target, process.env[key] # copy defaults conf = deep_merge {}, defaults # callback for when cli is ready or sync call finish = (args, opts) => # environment has higher priority .. so we put it on top again for key, target of map.env continue unless process.env[key]? if isArray(target) # do something special with env value, e.g. parsing it deep_set conf, target[0], target[1](process.env[key]) else deep_set conf, target, process.env[key] # these contains all options that differ from their default value optsdiff = {} if opts? # merge options into config for key, target of map.opts continue unless opts[key] # only set when differs from defaults continue if opts[key] is deep_get(defaults, target) deep_set optsdiff, target, opts[key] deep_set conf, target, opts[key] # remove loader code for key in ['defaults', 'set', 'cli', 'load'] delete config[key] # delete old defaults defaults = {} # insert all loaded values inplace_merge config, conf # monkey patch merge to apply set opts to config again old_merge = @merge @merge = -> result = old_merge(arguments...) inplace_merge config, optsdiff return result # when sync call, callback is undefined callback?.apply this, arguments load_configs = (args...) -> # put configs ontop of defaults if options['ignore unknown'] conf = deep_merge conf, ruthless_load_files files... else conf = deep_merge conf, load_files files... finish args... # set a default cli invoke when enabled andnot function is given unless options['cli'] is no or typeof options['cli'] is 'function' options['cli'] = (callback) -> cli.main callback if options['cli'] if options['ignore unknown'] # ignore all unknown arguments and options # the user will try to use on cli cli.fatal = (msg, type) -> type = 'error' if type is 'fatal' cli.status(msg, type) if options['cli parse']? for key, value of options['cli parse'] if isArray(value) and isArray(value[1]) # explicit mapping map.opts[key] = value[0] options['cli parse'][key] = value = value[1] if map.opts[key]? and value.length is 3 # if no default value for cli is given, # we predict it from default config value.push deep_get conf, map.opts[key] cli.parse options['cli parse'] # async call options['cli'] load_configs return else # sync call return load_configs() dodo-node-jsconfig-a40a65e/src/util.coffee000066400000000000000000000025531170567430000205160ustar00rootroot00000000000000{ isArray } = Array deep_merge = (objs...) -> objs = objs[0] if isArray(objs[0]) res = {} for obj in objs for k, v of obj if typeof(v) is 'object' and not isArray(v) res[k] = deep_merge(res[k] or {}, v) else res[k] = v res deep_set = (obj, target, value) -> pointer = obj target = target.split('.') key = target.pop() for part in target pointer[part] = {} unless pointer[part]? pointer = pointer[part] pointer[key] = value obj deep_get = (obj, target) -> target = target.split('.') key = target.pop() for part in target obj = obj[part] return unless obj? obj[key] inplace_merge = (target, obj) -> for k, v of obj target[k] = v target _load_files = (files, callback) -> conf = {} for file in files continue unless file?.length conf = deep_merge conf, (callback(file) or {}) conf load_files = (files...) -> _load_files files, (file) -> require(file) ruthless_load_files = (files...) -> _load_files files, (file) -> try return require(file) catch err console.error("Cannot find config '#{file}'.") module.exports = { deep_merge, deep_set, deep_get, inplace_merge, load_files, ruthless_load_files, }