├── .gitignore ├── index.js ├── package.json ├── readme.md ├── src ├── bjson.js └── lib │ └── helpers.js └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = require('./src/bjson') 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bjson", 3 | "version": "1.0.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/renatorib/bjson.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/renatorib/bjson/issues" 17 | }, 18 | "homepage": "https://github.com/renatorib/bjson#readme", 19 | "dependencies": { 20 | "graceful-fs": "^4.1.2", 21 | "mkdirp": "^0.5.1", 22 | "observed": "^1.1.1", 23 | "steno": "^0.4.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | **ABANDONED 4/22/2016** Object.observe has been [removed from future versions of V8](https://github.com/v8/v8/commit/6a370a6f01b004f0b359aa0e0ce4aa90d40773d0). Therefore, this module is no longer being maintained. 2 | 3 | --- 4 | 5 | # Bind Json - "bjson" 6 | Bind Json: Reactive way to read/write json files. 7 | 8 | > **Note:** 9 | > Bind Json, called as "bjson", don't have ANY RELATIONS with [Binary Json](http://bjson.org), also called as "bjson". 10 | > These are two different projects with same abbreviation name. Sorry for this. 11 | 12 | ## How it works 13 | **When you need to edit a json file, what you do?** 14 | 15 | | Without bjson | With bjson | 16 | | ------------------------------ | -------------------------------------------------- | 17 | | Create json file if not exists | | 18 | | Read json file. | Read json file _(Will create if not exists)_ | 19 | | Deserialize json file. | | 20 | | Edit parsed object. | Edit object _(Will reactively save in json file)_ | 21 | | Serialize new object. | | 22 | | Write back into file. | | 23 | 24 | 25 | ### Examples 26 | 27 | **Editing .json file without bjson** 28 | ```js 29 | var fs = require('fs'); 30 | if(!fs.existsSync('settings.json')){ 31 | fs.writeFileSync('settings.json', '{}'); 32 | } 33 | var settingsJson = fs.readFileSync('settings.json'); 34 | var settings = JSON.parse(settingsJson); 35 | settings.foo = 'bar'; 36 | var settingsJson = JSON.stringify(settings, null, 2); 37 | fs.writeFileSync('settings.json', settingsJson); 38 | ``` 39 | 40 | **Editing .json file with bjson** 41 | ```js 42 | var bjson = require('bjson'); 43 | var settings = bjson('settings.json'); 44 | settings.foo = 'bar'; 45 | ``` 46 | 47 | ## Getting started 48 | ### Binding json 49 | *settings.json* 50 | ```json 51 | {} 52 | ``` 53 | 54 | *whatever.js* 55 | ```js 56 | var bjson = require('bjson'); 57 | var settings = bjson('settings'); // will read or create settings.json 58 | settings.prop = 'bar'; 59 | ``` 60 | 61 | *settings.json:* 62 | ```json 63 | { 64 | "prop": "bar" 65 | } 66 | ``` 67 | 68 | ### Watching changes with observe 69 | 70 | You can watch changes with a instance of `Object.observe` passed as callback argument. 71 | 72 | *settings.json:* 73 | ```json 74 | { 75 | "prop": "bar" 76 | } 77 | ``` 78 | 79 | whatever.js 80 | ```js 81 | var bjson = require('bjson'); 82 | var settings = bjson('settings', function(observe){ 83 | observe.on('change', function(changes){ 84 | console.log('Path:', changes.path); 85 | console.log('Old Value:', changes.oldValue); 86 | console.log('New Value:', changes.value); 87 | console.log('-----'); 88 | }); 89 | }); 90 | 91 | settings.prop = 'foo'; 92 | settings.otherprop = 'bar'; 93 | ``` 94 | 95 | Log output: 96 | ``` 97 | Path: prop 98 | Old Value: bar 99 | New Value: foo 100 | ----- 101 | Path: otherprop 102 | Old Value: undefined 103 | New Value: bar 104 | ----- 105 | ``` 106 | 107 | *settings.json:* 108 | ```json 109 | { 110 | "prop": "foo", 111 | "otherprop": "bar" 112 | } 113 | ``` 114 | 115 | ### Observe events 116 | 117 | ```js 118 | var bjson = require('bjson'); 119 | var settings = bjson('settings', function(observe){ 120 | observe.on('add', function(changes){}); 121 | observe.on('update', function(changes){}); 122 | observe.on('delete', function(changes){}); 123 | observe.on('reconfigure', function(changes){}); 124 | observe.on('change', function(changes){}); // fired when any of the above events are emitted 125 | }); 126 | 127 | ``` 128 | 129 | ### Observe events callback `changes` 130 | 131 | `path`: full path to the property, including nesting 132 | `name`: name of the path 133 | `type`: name of the event 134 | `object`: object 135 | `value`: current value for the given path. same as object[name] 136 | `oldValue`: previous value of the property 137 | 138 | Example: 139 | ```js 140 | var bjson = require('bjson'); 141 | var settings = bjson('settings', function(observe){ 142 | observe.on('change', function(changes){ 143 | console.log(changes); 144 | }); 145 | }); 146 | 147 | settings.foo = 'bar' 148 | 149 | //log: 150 | // { path: 'foo', 151 | // name: 'foo', 152 | // type: 'add', 153 | // object: { foo: 'bar' }, 154 | // value: 'bar', 155 | // oldValue: undefined } 156 | ``` 157 | -------------------------------------------------------------------------------- /src/bjson.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let fs = require('fs'), 4 | observed = require('observed'), 5 | steno = require('steno'), 6 | path = require('path'), 7 | mkdirp = require('mkdirp'), 8 | helpers = require('./lib/helpers'); 9 | 10 | let keepExtension = helpers.keepExtension, 11 | existsSync = helpers.existsSync, 12 | tmp = {}; 13 | 14 | 15 | let bjson = (file, cb) => { 16 | let parsed, 17 | observe; 18 | 19 | file = keepExtension(file, '.json'); 20 | if(tmp[file]) { 21 | return tmp[file]; 22 | } 23 | 24 | if(!existsSync(file)){ 25 | mkdirp.sync(path.dirname(file)); 26 | fs.writeFileSync(file, '{}'); 27 | } 28 | 29 | parsed = JSON.parse(fs.readFileSync(file)); 30 | observe = observed(parsed); 31 | 32 | observe.on('change', () => { 33 | steno.writeFileSync(file, JSON.stringify(parsed, null, '\t')); 34 | }); 35 | 36 | if(typeof cb === "function") { 37 | cb(observe); 38 | } 39 | 40 | return tmp[file] = parsed; 41 | } 42 | 43 | module.exports = bjson; 44 | -------------------------------------------------------------------------------- /src/lib/helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | module.exports = { 6 | keepExtension: (file, ext) => { 7 | return (file.indexOf(ext, file.length - ext.length) !== -1) 8 | ? file 9 | : file + ext; 10 | }, 11 | existsSync: (file) => { 12 | /** 13 | * We need this function since 14 | * fs.existsSync is deprecated. 15 | */ 16 | try { 17 | fs.accessSync(file); 18 | return true; 19 | } catch(ex) { 20 | return false; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | // TODO: 2 | // Make some mocha tests 3 | 4 | 'use strict'; 5 | 6 | let bjson = require('../index'); 7 | let file = bjson('my/deep/file'); 8 | 9 | file.foo = 'bar'; 10 | file.object = { 11 | deep: { 12 | bar: 'foo' 13 | } 14 | } 15 | --------------------------------------------------------------------------------