├── .gitignore ├── .jshintrc ├── .travis.yml ├── LICENSE ├── README.md ├── brand ├── logo.png ├── logo.svg └── logoblue.svg ├── index.js ├── package.json └── test ├── assets ├── folder.json ├── folder │ ├── file.json │ ├── nested.json │ ├── nested │ │ └── list.json │ └── nonamesake │ │ └── list.json ├── second.json ├── simple.json └── third.json └── index-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "undef": true, 3 | "unused": true, 4 | "node": true, 5 | "esnext": true, 6 | "bitwise": true, 7 | "camelcase": true, 8 | "curly": true, 9 | "eqeqeq": true, 10 | "immed": true, 11 | "indent": 4, 12 | "latedef": true, 13 | "newcap": true, 14 | "noarg": true, 15 | "quotmark": "single", 16 | "regexp": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "globals": { 21 | "require": false, 22 | "module": false 23 | } 24 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jacobo Tabernero - jacobo@xarope.eu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![deep.json](https://raw.githubusercontent.com/jacoborus/deepJSON/master/brand/logo.png 'deepjson logo') 2 | ======================================================================================================== 3 | 4 | A better way to load big json config files in node.js apps. 5 | 6 | [deepjson.jacoborus.codes](http://deepjson.jacoborus.codes) 7 | 8 | [![Build Status](https://travis-ci.org/jacoborus/deep-json.svg?branch=master)](https://travis-ci.org/jacoborus/deep-json) 9 | 10 | 11 | Why 12 | --- 13 | 14 | Sometimes config files grow to sizes that are difficult to handle, therefore it is desirable to distribute information in different files and folders rather than having a single big JSON file, you can split it up across multiple files (and directories) and deep.json puts it all back together. deep.json will also extend this object with the following files (and its trees) that you have passed as arguments. 15 | 16 | 17 | Installation 18 | ------------ 19 | 20 | Install with **[npm](https://www.npmjs.org/package/deepjson)** 21 | ``` 22 | $ npm install deepjson 23 | ``` 24 | 25 | API 26 | --- 27 | 28 | ### deepjson( config1, config2, ... ) 29 | 30 | Load all the json files passed as arguments, then extend them with json files under the folders with same name. Deepjson will return a object result of extend loaded files in order. 31 | 32 | 33 | **Parameters:** 34 | 35 | - **config** *String|Object*: path to file (with or without extension) or javascript object 36 | - **Return** *Object*: extended object 37 | 38 | 39 | Example 40 | ------- 41 | 42 | .jsons and folders structure: 43 | ``` 44 | ├── config.json: {"appname": "Fruits app", "port": 3000} 45 | ├── production.json: {"port": 4444} 46 | ├── config (folder) 47 | │   ├── SEO.json: {"description": "Fresh lemmons!" } 48 | │   ├── SEO (folder) 49 | │   ├── keywords.json: ["a", "big", "array"] 50 | ``` 51 | 52 | ```js 53 | var deepjson = require( 'deepjson' ); 54 | 55 | var defaultConfig = deepjson( 'config' ); 56 | /* { 57 | appname: 'Fruits app', 58 | port: 3000, 59 | SEO: { 60 | description: 'Fresh lemmons!', 61 | keywords: ['a', 'big', 'array'] 62 | } 63 | } */ 64 | 65 | 66 | var productionConfig = deepjson( 'config', 'production' ); 67 | /* { 68 | appname: 'Fruits app', 69 | port: 4444, 70 | SEO: { 71 | description: 'Fresh lemmons!', 72 | keywords: ['a', 'big', 'array'] 73 | } 74 | } */ 75 | ``` 76 | 77 | 78 | Tests 79 | ----- 80 | 81 | ``` 82 | npm install && npm test 83 | ``` 84 | 85 |

86 | 87 | --- 88 | 89 | © 2015 [Jacobo Tabernero](http://jacoborus.codes) 90 | 91 | Released under [MIT License](https://raw.github.com/jacoborus/deep-json/master/LICENSE) 92 | -------------------------------------------------------------------------------- /brand/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacoborus/deep-json/d41f35cc67b21b87c39da42d264bbdcf891ec93c/brand/logo.png -------------------------------------------------------------------------------- /brand/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 27 | 30 | {deep.json} 43 | 44 | 45 | -------------------------------------------------------------------------------- /brand/logoblue.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 27 | 30 | 37 | {deep.json} 48 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'), 4 | path = require('path'), 5 | extend = require('extend'); 6 | 7 | // return true if path is directory 8 | var isDir = function (dir) { 9 | return fs.existsSync(dir) ? fs.lstatSync( dir ).isDirectory() : false; 10 | }; 11 | 12 | // return path of folder with same name as .json file if exists 13 | var getNamesake = function (file) { 14 | var folder = path.dirname(file) + '/' + path.basename( file, '.json' ); 15 | return fs.existsSync(folder) && isDir(folder) ? folder : false; 16 | }; 17 | 18 | // get the paths of files and folders inside a folder 19 | var getFolderElements = function (parent) { 20 | var elems = fs.readdirSync( parent ), 21 | d = { 22 | files : [], 23 | folders : [] 24 | }; 25 | 26 | // get files and folders paths 27 | elems.forEach( function (elem) { 28 | var el = parent + '/' + elem; 29 | if (!isDir( el )) { 30 | d.files.push( el ); 31 | } else if (!fs.existsSync( el + '.json')) { 32 | // add folder only if has no namesake json 33 | d.folders.push( el ); 34 | } 35 | }); 36 | 37 | return d; 38 | }; 39 | 40 | 41 | var getData = { 42 | 43 | // get file data and extend it with folder data of folder with same name 44 | file : function (file) { 45 | var config = require( file ), 46 | namesake = getNamesake( file ); 47 | 48 | return namesake ? extend( config, getData.folder( namesake )) : config; 49 | }, 50 | 51 | // get data from folders and files inside a folder 52 | folder : function (folder) { 53 | var elems = getFolderElements( folder ), 54 | result = {}; 55 | 56 | // files 57 | elems.files.forEach( function (route) { 58 | // get object name 59 | var fileName = path.basename( route, '.json' ); 60 | // assign object data from file 61 | result[ fileName ] = getData.file( route ); 62 | }); 63 | 64 | // no namesake folders 65 | elems.folders.forEach( function (route) { 66 | // get object name 67 | var fileName = path.basename( route ); 68 | // assign data from folder 69 | result[ fileName ] = extend( result[ fileName ] || {}, getData.folder( route )); 70 | }); 71 | 72 | return result; 73 | } 74 | }; 75 | 76 | 77 | module.exports = function () { 78 | var configs = [], 79 | i; 80 | 81 | if (!arguments.length) { 82 | return {}; 83 | } 84 | 85 | for (i in arguments) { 86 | if (typeof arguments[i] !== 'string') { 87 | if (typeof arguments[i] !== 'object' || typeof arguments[i].length !== 'undefined' || arguments[i] === null) { 88 | throw new Error( 'deep-json: bad file argument' ); 89 | } else { 90 | configs[i] = arguments[i]; 91 | } 92 | } else { 93 | configs[i] = getData.file( path.resolve( arguments[i] )); 94 | } 95 | 96 | } 97 | 98 | return extend.apply( {}, configs ); 99 | }; 100 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deepjson", 3 | "version": "1.1.2", 4 | "description": "A better way to load big json config files", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:jacoborus/deep-json.git" 12 | }, 13 | "keywords": [ 14 | "JSON", 15 | "config" 16 | ], 17 | "author": "Jacobo Tabernero -jacobo@xarope.eu", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/jacoborus/deep-json/issues" 21 | }, 22 | "homepage": "http://deepjson.jacoborus.codes", 23 | "devDependencies": { 24 | "chai": "^3.3.0", 25 | "mocha": "^2.3.3" 26 | }, 27 | "dependencies": { 28 | "extend": "^3.0.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/assets/folder.json: -------------------------------------------------------------------------------- 1 | {"main":1} -------------------------------------------------------------------------------- /test/assets/folder/file.json: -------------------------------------------------------------------------------- 1 | {"third": 3} -------------------------------------------------------------------------------- /test/assets/folder/nested.json: -------------------------------------------------------------------------------- 1 | {"cuatro": 4} -------------------------------------------------------------------------------- /test/assets/folder/nested/list.json: -------------------------------------------------------------------------------- 1 | [1,2] -------------------------------------------------------------------------------- /test/assets/folder/nonamesake/list.json: -------------------------------------------------------------------------------- 1 | [9,8,7] -------------------------------------------------------------------------------- /test/assets/second.json: -------------------------------------------------------------------------------- 1 | {"main":2} -------------------------------------------------------------------------------- /test/assets/simple.json: -------------------------------------------------------------------------------- 1 | {"main":1} -------------------------------------------------------------------------------- /test/assets/third.json: -------------------------------------------------------------------------------- 1 | {"main":3} -------------------------------------------------------------------------------- /test/index-test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect, 2 | deepjson = require('../index.js'), 3 | fs = require('fs'); 4 | 5 | 6 | describe( 'deepJSON', function () { 7 | 8 | it('Return an empty object if no arguments are passed', function () { 9 | expect( deepjson() ).to.be.a( 'object' ); 10 | }); 11 | it('Requires a master json file', function () { 12 | expect( function () { 13 | deepjson(4); 14 | }).to.throw( 'deep-json: bad file argument' ); 15 | }); 16 | it('Recover simple json files', function () { 17 | expect( deepjson( './test/assets/simple' ).main ).to.equal( 1 ); 18 | }); 19 | it('Extend values with folder named equal as json', function () { 20 | expect( deepjson( './test/assets/folder' ).file.third ).to.equal( 3 ); 21 | }); 22 | it('Extend values with folders with no json namesake', function () { 23 | expect( deepjson( './test/assets/folder' ).nonamesake.list[0] ).to.equal( 9 ); 24 | }); 25 | it('Extend values with folder and subfolders', function () { 26 | expect( deepjson( './test/assets/folder' ).nested.list[0] ).to.equal( 1 ); 27 | }); 28 | it('Extend first argument value with second one', function () { 29 | expect( deepjson( './test/assets/folder', './test/assets/second' ).main ).to.equal( 2 ); 30 | }); 31 | it('Extend second argument value with third one', function () { 32 | expect( deepjson( './test/assets/folder', './test/assets/second', './test/assets/third' ).main ).to.equal( 3 ); 33 | }); 34 | it('allow objects as params', function () { 35 | expect( deepjson({ secondary: 2 }, './test/assets/simple' ).secondary ).to.equal( 2 ); 36 | }); 37 | }); --------------------------------------------------------------------------------