New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

self-reload-json

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

self-reload-json - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

261

index.js

@@ -1,129 +0,200 @@

(function() {
var fs = require('fs'),
path = require('path'),
util = require('util'),
EventEmitter = require('events').EventEmitter,
_ = require('underscore');
(() => {
'use strict';
const fs = require('fs');
const path = require('path');
const util = require('util');
const EventEmitter = require('events').EventEmitter;
var omitKeys = _.allKeys(new EventEmitter());
omitKeys.push('stop', 'resume', 'save', 'forceUpdate');
const privateProps = Symbol('private');
const fileChanged = Symbol('onFileChange');
var SelfReloadJSON = function SelfReloadJSON(options) {
EventEmitter.call(this);
function deleteAll(obj, keys) {
for(const key of keys)
if(key in obj)
delete obj[key];
return obj;
}
switch(typeof options) {
case 'string': options = { fileName: options }; break;
case 'object': case 'undefined': break;
default: throw new Error('Invalid options type.');
}
function getAllProperties(obj, output) {
output = output || [];
if(!obj) return output;
Array.prototype.push.apply(output, Object.getOwnPropertyNames(obj));
return getAllProperties(Object.getPrototypeOf(obj), output);
}
var updateFile, onFileChange, stop, resume, save;
var content, updateFileLock, fileName, watcher;
class SelfReloadJSON extends EventEmitter {
constructor(options) {
super();
content = this;
switch(typeof options) {
case 'string': options = { fileName: options }; break;
case 'object': case 'undefined': break;
default: throw new Error('Invalid options type.');
}
options = _.defaults(options || {}, {
fileName: '',
encoding: 'utf8',
additive: false,
method: 'native',
interval: 5000,
reviver: null,
replacer: null
});
// Recursive fetch all property names even in prototype
// which will be omitted from fetched JSON object.
const localOmitKeys = getAllProperties(this);
content.stop = stop = function stop() {
if(watcher) {
if(typeof watcher === 'string')
fs.unwatchFile(watcher, onFileChange);
else
watcher.close();
watcher = null;
// Convert all internal values to non-enumerable,
// prevents those values exposed by save function.
for(let key in this) {
const value = this[key];
delete this[key];
Object.defineProperty(this, key, {
value,
enumerable: false,
configurable: true,
writable: true
});
}
};
content.resume = resume = function resume() {
stop();
this[privateProps] = {
keys: [],
fileName: '',
watcher: null,
content: null,
fileChanged: this[fileChanged].bind(this),
omitKeys: localOmitKeys,
options: Object.assign({
fileName: '',
encoding: 'utf8',
additive: false,
method: 'native',
interval: 5000,
reviver: null,
replacer: null
}, options || {})
};
this.resume();
}
stop() {
const internals = this[privateProps];
if(!internals.watcher) return;
if(typeof internals.watcher === 'string')
fs.unwatchFile(internals.watcher, internals.fileChanged);
else
internals.watcher.close();
internals.watcher = null;
}
resume() {
this.stop();
const internals = this[privateProps];
const options = internals.options;
if(internals.retryTimer) {
clearImmediate(internals.retryTimer);
delete internals.retryTimer;
}
options.fileName = path.resolve(options.fileName);
fileName = path.basename(options.fileName);
internals.fileName = path.basename(options.fileName);
switch(options.method) {
case 'native':
watcher = fs.watch(options.fileName, {
encoding: options.encoding
}, onFileChange);
internals.watcher = fs.watch(
options.fileName,
{ encoding: options.encoding },
internals.fileChanged
);
break;
case 'polling':
watcher = options.fileName;
fs.watchFile(options.fileName, {
interval: options.interval
}, onFileChange);
internals.watcher = options.fileName;
fs.watchFile(
options.fileName,
{ interval: options.interval },
internals.fileChanged
);
break;
}
updateFile();
};
this.forceUpdate();
}
content.save = save = function save(opts) {
opts = _.defaults(opts || {}, {
encoding: options.encoding,
replacer: options.replacer,
space: null
});
updateFileLock = true;
[fileChanged](a, b) {
try {
fs.writeFileSync(
options.fileName,
JSON.stringify(_.omit(content, function(v, k) {
return _.contains(omitKeys, k);
}), opts.replacer, opts.space),
_.omit(opts, 'replacer', 'space')
);
} finally {
updateFileLock = false;
}
};
onFileChange = function onFileChange(a, b) {
try {
if(a instanceof fs.Stats) {
if(a.mtime === b.mtime) return;
updateFile();
} else {
if(b !== fileName) return;
updateFile();
if(b !== this[privateProps].fileName) return;
}
this.forceUpdate();
} catch(err) {
console.log(err.stack ? err.stack : err);
console.log(err.stack || err);
}
};
}
content.forceUpdate = updateFile = function updateFile() {
if(updateFileLock) return;
updateFileLock = true;
save(options) {
const internals = this[privateProps];
options = Object.assign(
{ space: null },
internals.options,
options || {}
);
internals.updateFileLock = true;
try {
var rawFile = fs.readFileSync(options.fileName, {
encoding: options.encoding
});
var newContent = _.omit(JSON.parse(rawFile, options.reviver), function(v, k) {
return _.contains(omitKeys, k);
});
if(!options.additive) {
var removeList = _.chain(content).keys().difference(omitKeys).value();
for(var i = 0, l = removeList.length; i < l; i++)
delete content[removeList[i]];
const json = JSON.stringify(this, options.replacer, options.space);
fs.writeFileSync(internals.options.fileName, json, options);
internals.raw = json;
} finally {
internals.updateFileLock = false;
}
}
forceUpdate() {
const internals = this[privateProps];
const options = internals.options;
if(internals.updateFileLock) return;
internals.updateFileLock = true;
if(internals.retryTimer) {
clearImmediate(internals.retryTimer);
delete internals.retryTimer;
}
try {
const rawContent = fs.readFileSync(options.fileName, { encoding: options.encoding });
if(internals.raw === rawContent) return;
internals.raw = rawContent;
let newContent = JSON.parse(rawContent, options.reviver);
if(typeof newContent !== 'object')
newContent = { value: newContent };
// Ignore all values which defined internally
const safeContent = deleteAll(Object.assign({}, newContent), internals.omitKeys);
if(options.additive) {
Object.assign(this, safeContent);
Object.assign(internals.newContent, newContent);
} else {
deleteAll(this, internals.keys);
Object.assign(this, safeContent);
internals.newContent = newContent;
}
_.extendOwn(content, newContent);
content.emit('updated');
internals.keys = Object.keys(internals.newContent);
} catch(err) {
console.log(err.stack ? err.stack : err);
content.emit('error', err);
switch(err && err.code) {
case 'EBUSY':
case 'EAGAIN':
internals.retryTimer = setImmediate(this.forceUpdate.bind(this));
return;
}
console.error(err.stack || err);
this.emit('error', err);
return;
} finally {
updateFileLock = false;
internals.updateFileLock = false;
}
};
resume();
};
this.emit('updated', internals.newContent);
}
}
util.inherits(SelfReloadJSON, EventEmitter);
module.exports = SelfReloadJSON;
})();
{
"name": "self-reload-json",
"version": "0.2.0",
"version": "0.3.0",
"description": "Self reloading JSON handler",

@@ -23,5 +23,3 @@ "main": "index.js",

"homepage": "https://github.com/JLChnToZ/selfreloadjson#readme",
"dependencies": {
"underscore": "^1.8.3"
}
"dependencies": {}
}

@@ -12,3 +12,5 @@ Self Reload JSON

With NPM:
`npm install self-reload-json`
```sh
$ npm install self-reload-json
```

@@ -28,2 +30,4 @@ Then in script file:

The `SelfReloadJSON` class itself inherits [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter).
### Methods

@@ -60,4 +64,4 @@ #### `new SelfReloadJSON(options | fileName)`

#### `on('updated', function() { ... })`
This event will be emitted after the JSON content refreshed.
#### `on('updated', function(json) { ... })`
This event will be emitted after the JSON content refreshed. The `json` parameter is the raw parsed JSON object (not the SelfReloadJSON instance itself).

@@ -69,3 +73,3 @@ #### `on('error', function(err) { ... })`

-----
If a property name conflicts with the function names described above, they will be ignored.
If a property name conflicts with the function names described above, they will be ignored. To get those values you should use `updated` event listener instead.

@@ -72,0 +76,0 @@ license

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc