Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fast-json

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fast-json - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

2

index.js

@@ -1,3 +0,1 @@

'use strict';
module.exports = require('./lib/FastJson');

417

lib/FastJson.js

@@ -1,53 +0,63 @@

'use strict';
const EventEmitter = require('events');
var OPEN_BRACE = '{'.charCodeAt(0);
var CLOSE_BRACE = '}'.charCodeAt(0);
var OPEN_BRACKET = '['.charCodeAt(0);
var CLOSE_BRACKET = ']'.charCodeAt(0);
var QUOTE = '"'.charCodeAt(0);
var SPACE = ' '.charCodeAt(0);
var NEW_LINE = '\n'.charCodeAt(0);
var CARRIAGE_RETURN = '\r'.charCodeAt(0);
var TAB = '\t'.charCodeAt(0);
var COLON = ':'.charCodeAt(0);
var COMMA = ','.charCodeAt(0);
var BACKSLASH = '\\'.charCodeAt(0);
const OPEN_BRACE = '{'.charCodeAt(0);
const CLOSE_BRACE = '}'.charCodeAt(0);
const OPEN_BRACKET = '['.charCodeAt(0);
const CLOSE_BRACKET = ']'.charCodeAt(0);
const QUOTE = '"'.charCodeAt(0);
const SPACE = ' '.charCodeAt(0);
const NEW_LINE = '\n'.charCodeAt(0);
const CARRIAGE_RETURN = '\r'.charCodeAt(0);
const TAB = '\t'.charCodeAt(0);
const COLON = ':'.charCodeAt(0);
const COMMA = ','.charCodeAt(0);
const BACKSLASH = '\\'.charCodeAt(0);
const TYPE_ARRAY = 1;
const TYPE_OBJECT = 2;
const SEP = '/';
class FastJson {
/**
* @param {Object} [options] The fast-json configuration object.
*/
constructor(options) {
this._options = options || {};
this._stack = new Array(16);
this._level = -1;
this._stack = [];
this._postColon = false;
this._lastString = null;
this._lastString = {};
this._skipped = false;
this._events = new EventEmitter();
this._subPaths = new Set(['/']);
this._isString = false;
this._subPaths = new Set([SEP]);
}
/**
* Adds a listener function for the provided path.
* @param {Array|String} path The JSON path to get values.
* @param {FastJson~jsonListener} listener The function called after finding the JSON path.
*/
on(path, listener) {
var processedPath = this._processPath(path);
this._addToSubPaths(processedPath);
this._events.on(processedPath, listener);
const normPath = FastJson._normalizePath(path);
this._addToSubPaths(normPath);
this._events.on(normPath, listener);
}
/**
* Start processing JSON using the defined paths in {@link FastJson#on} method.
* @param {String|Buffer} data The JSON to process.
*/
write(data) {
this._isString = typeof data === 'string';
for (var i = 0; i < data.length; i++) {
switch (this._get(data, i)) {
for (let i = 0; i < data.length && !this._skipped; i++) {
switch (FastJson._get(data, i)) {
case OPEN_BRACE:
i = this._onOpenBrace(data, i);
i = this._onOpenBlock(data, i, TYPE_OBJECT, OPEN_BRACE, CLOSE_BRACE);
break;
case OPEN_BRACKET:
i = this._onOpenBracket(data, i);
i = this._onOpenBlock(data, i, TYPE_ARRAY, OPEN_BRACKET, CLOSE_BRACKET);
break;
case CLOSE_BRACE: case CLOSE_BRACKET:
this._onCloseBraceOrBracket(data, i);
this._onCloseBlock(data, i);
break;

@@ -57,3 +67,3 @@ case QUOTE:

break;
case TAB : case CARRIAGE_RETURN : case NEW_LINE : case SPACE:
case TAB: case CARRIAGE_RETURN: case NEW_LINE: case SPACE:
break;

@@ -70,46 +80,46 @@ case COLON:

}
}
_onOpenBrace(data, index) {
this._level++;
var parent = this._resolveParentKey(data);
var path = this._resolvePath(parent);
if (!this._subPaths.has(path)) {
this._level--;
return this._skipBlock(data, index, OPEN_BRACE, CLOSE_BRACE);
if (this._skipped) {
this._skipCleanUp();
}
}
this._stack[this._level] = {
type: 'object',
start: index,
parent: parent,
path: path
};
/**
* Stop processing the last JSON provided in the {@link FastJson#write} method.
*/
skip() {
this._skipped = true;
}
_skipCleanUp() {
this._stack = [];
this._postColon = false;
return index;
this._skipped = false;
}
_onOpenBracket(data, index) {
this._level++;
var parent = this._resolveParentKey(data);
var path = this._resolvePath(parent);
/**
* @param {String|Buffer} data
* @param {Number} index
* @param {String} type
* @param {Number} openChar
* @param {Number} closeChar
* @returns {Number}
* @private
*/
_onOpenBlock(data, index, type, openChar, closeChar) {
const path = this._resolvePath(data);
if (!this._subPaths.has(path)) {
this._level--;
return this._skipBlock(data, index, OPEN_BRACKET, CLOSE_BRACKET);
return FastJson._skipBlock(data, index, openChar, closeChar);
}
this._stack[this._level] = {
type: 'array',
this._stack.push({
// General
type,
start: index,
parent: parent,
path: path,
index: 0
};
path,
// TYPE_ARRAY
index: 0,
});
this._postColon = false;

@@ -120,30 +130,38 @@

_onCloseBraceOrBracket(data, index) {
var frame = this._stack[this._level];
/**
* @param {String|Buffer} data
* @param {Number} index
* @private
*/
_onCloseBlock(data, index) {
const frame = this._stack.pop();
frame.end = index;
if (this._hasListeners(frame.path)) {
var result = data.slice(frame.start, frame.end + 1);
this._events.emit(frame.path, result);
this._events.emit(frame.path, data.slice(frame.start, frame.end + 1));
}
this._level--;
}
/**
* @param {String|Buffer} data
* @param {Number} index
* @returns {Number}
* @private
*/
_onQuote(data, index) {
var frame = this._stack[this._level];
var str = { start: index + 1, end: this._parseString(data, index) };
var path;
const frame = this._getFrame();
const strStart = index + 1;
const strEnd = FastJson._parseString(data, index);
if (this._postColon) {
path = this._resolvePathForPrimitiveObject(data);
const path = this._resolvePathForPrimitiveObject(data, frame);
if (this._hasListeners(path)) {
this._events.emit(path, data.slice(str.start, str.end));
this._events.emit(path, data.slice(strStart, strEnd));
}
} else if (frame.type === 'array') {
path = this._resolvePathForPrimitiveArray(data);
} else if (frame.type === TYPE_ARRAY) {
const path = FastJson._resolvePathForPrimitiveArray(frame);
if (this._hasListeners(path)) {
this._events.emit(path, data.slice(str.start, str.end));
this._events.emit(path, data.slice(strStart, strEnd));
}

@@ -153,10 +171,11 @@ }

this._postColon = false;
this._lastString = str;
this._lastString.start = strStart;
this._lastString.end = strEnd;
return index + (str.end - str.start + 1);
return index + ((strEnd - strStart) + 1);
}
_onComma() {
var frame = this._stack[this._level];
if (frame.type === 'array') {
const frame = this._getFrame();
if (frame.type === TYPE_ARRAY) {
frame.index++;

@@ -166,9 +185,14 @@ }

/**
* @param {String|Buffer} data
* @param {Number} index
* @returns {Number}
* @private
*/
_onPrimitive(data, index) {
var frame = this._stack[this._level];
var primEnd = this._parsePrimitive(data, index);
var path;
const frame = this._getFrame();
const primEnd = FastJson._parsePrimitive(data, index);
if (this._postColon) {
path = this._resolvePathForPrimitiveObject(data);
const path = this._resolvePathForPrimitiveObject(data, frame);

@@ -178,4 +202,4 @@ if (this._hasListeners(path)) {

}
} else if (frame.type === 'array') {
path = this._resolvePathForPrimitiveArray(data);
} else if (frame.type === TYPE_ARRAY) {
const path = FastJson._resolvePathForPrimitiveArray(frame);

@@ -192,12 +216,21 @@ if (this._hasListeners(path)) {

_skipBlock(data, index, openChar, closeChar) {
var blockDepth = 1;
index++;
/**
* @param {String|Buffer} data
* @param {Number} index
* @param {Number} openChar
* @param {Number} closeChar
* @returns {Number}
* @private
*/
static _skipBlock(data, index, openChar, closeChar) {
let blockDepth = 1;
let i = index + 1;
while (true) {
switch (this._get(data, index)) {
case QUOTE:
var strEnd = this._parseString(data, index);
index += strEnd - index;
for (; blockDepth > 0; i++) {
switch (FastJson._get(data, i)) {
case QUOTE: {
const strEnd = FastJson._parseString(data, i);
i += strEnd - i;
break;
}
case openChar:

@@ -208,101 +241,129 @@ blockDepth++;

blockDepth--;
if (blockDepth === 0) {
return index;
}
break;
default:
}
}
index++;
}
return i - 1;
}
_parseString(data, index) {
index++;
while (true) {
switch (this._get(data, index)) {
case QUOTE: return index;
case BACKSLASH: index++;
/**
* @param {String|Buffer} data
* @param {Number} index
* @returns {Number}
* @private
*/
static _parseString(data, index) {
for (let i = index + 1; ;i++) {
switch (FastJson._get(data, i)) {
case QUOTE: return i;
case BACKSLASH: i++; break;
default:
}
index++;
}
}
_parsePrimitive(data, index) {
while (true) {
switch (this._get(data, index)) {
/**
* @param {String|Buffer} data
* @param {Number} index
* @returns {Number}
* @private
*/
static _parsePrimitive(data, index) {
for (let i = index; ;i++) {
switch (FastJson._get(data, i)) {
case CLOSE_BRACKET: case CLOSE_BRACE: case COMMA:
return index;
return i;
default:
}
index++;
}
}
_resolveParentKey(data) {
if (this._level <= 0) {
return '/';
/**
* @param {String|Buffer} data
* @param {Object} frame
* @returns {String}
* @private
*/
_getParentKey(data, frame) {
if (frame.type === TYPE_ARRAY) {
return frame.index;
}
var parentType = this._stack[this._level - 1].type;
if (parentType === 'array') {
return this._stack[this._level - 1].index;
}
return this._toString(data, this._lastString.start, this._lastString.end);
return FastJson._toString(data, this._lastString.start, this._lastString.end);
}
_resolvePath(parentKey) {
if (this._level === 0) {
return parentKey;
} else if (this._level === 1) {
return this._stack[this._level - 1].path + parentKey;
/**
* @param {String|Buffer} data
* @returns {String}
* @private
*/
_resolvePath(data) {
if (this._stack.length === 0) {
return SEP;
}
return this._stack[this._level - 1].path + '/' + parentKey;
const frame = this._getFrame();
return `${frame.path}${this._getParentKey(data, frame)}${SEP}`;
}
_hasListeners(processedPath) {
return this._events.listenerCount(processedPath) > 0;
/**
* @return {Object}
* @private
*/
_getFrame() {
return this._stack[this._stack.length - 1];
}
_resolvePathForPrimitiveObject(data) {
if (this._level === 0) {
return '/' + this._toString(data, this._lastString.start, this._lastString.end);
}
return this._stack[this._level].path + '/' +
this._toString(data, this._lastString.start, this._lastString.end);
/**
* @param {String} path
* @returns {Boolean}
* @private
*/
_hasListeners(path) {
return this._events.listenerCount(path) > 0;
}
_resolvePathForPrimitiveArray(data) {
if (this._level === 0) {
return '/' + this._stack[this._level].index;
}
return this._stack[this._level].path + '/' + this._stack[this._level].index;
/**
* @param {String|Buffer} data
* @param {Object} frame
* @returns {String}
* @private
*/
_resolvePathForPrimitiveObject(data, frame) {
return `${frame.path}${
FastJson._toString(data, this._lastString.start, this._lastString.end)}${SEP}`;
}
_processPath(path) {
if (!path) {
return '/';
}
path = path.replace(/[\.\[]/g, '/');
path = path.replace(/\]/g, '');
return path[0] !== '/' ? '/' + path : path;
/**
* @param {Object} frame
* @returns {String}
* @private
*/
static _resolvePathForPrimitiveArray(frame) {
return `${frame.path}${frame.index}${SEP}`;
}
_addToSubPaths(processedPath) {
var aux = '';
var tokens = processedPath.split('/');
/**
* @param {String} path
* @private
*/
_addToSubPaths(path) {
let subPath = SEP;
const tokens = path.split(SEP);
for (var i = 1; i < tokens.length; i++) {
aux += '/' + tokens[i];
this._subPaths.add(aux);
for (let i = 1; i < tokens.length - 1; i++) {
subPath += `${tokens[i]}${SEP}`;
this._subPaths.add(subPath);
}
}
_get(data, index) {
if (this._isString) {
/**
* @param {String|Buffer} data
* @param {Number} index
* @returns {Number}
* @private
*/
static _get(data, index) {
if (typeof data === 'string') {
return data.charCodeAt(index);

@@ -314,4 +375,11 @@ }

_toString(data, start, end) {
if (this._isString) {
/**
* @param {String|Buffer} data
* @param {Number} start
* @param {Number} end
* @returns {String}
* @private
*/
static _toString(data, start, end) {
if (typeof data === 'string') {
return data.slice(start, end);

@@ -322,4 +390,25 @@ }

}
/**
* @param {Array|String} origPath
* @returns {String}
* @private
*/
static _normalizePath(origPath) {
if (Array.isArray(origPath)) {
return `${SEP}${origPath.join(SEP)}${SEP}`;
}
let path = origPath.replace(/[.[]/g, SEP);
path = path.replace(/\]/g, '') + SEP;
return !path.startsWith(SEP) ? `${SEP}${path}` : path;
}
}
module.exports = FastJson;
/**
* @callback FastJson~jsonListener
* @param {String|Buffer} value The found value type will depend of the type used in
* {@link FastJson#write}.
*/
{
"name": "fast-json",
"description": "A lightning fast on the fly JSON parser",
"version": "1.1.0",
"version": "1.2.0",
"author": "Alejandro Santiago Nieto",
"license": "MIT",
"dependencies": {},
"devDependencies": {
"chai": "3.x.x",
"jscs": "3.x.x",
"jshint": "2.x.x",
"mocha": "3.x.x"
"chai": "^4.3.4",
"eslint": "^7.26.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.22.1",
"jsdoc": "^3.6.6",
"mocha": "^8.4.0",
"nyc": "^15.1.0"
},

@@ -21,6 +23,7 @@ "main": "index.js",

"test": "mocha test/*.js",
"jshint": "jshint index.js lib/*.js test/*.js",
"jscs": "jscs index.js lib/*.js test/*.js",
"jscs:fix": "jscs --fix index.js lib/*.js test/*.js",
"check": "npm run test && npm run jshint && npm run jscs && npm outdated"
"test:cover": "nyc --reporter=lcov --reporter=text-summary npm test",
"lint": "eslint index.js lib/*.js test/*.js example/*.js",
"lint:fix": "eslint index.js lib/*.js test/*.js example/*.js --fix",
"check": "npm test && npm run lint && npm outdated",
"doc": "jsdoc ./lib/ ./package.json ./README.md -d ./doc"
},

@@ -27,0 +30,0 @@ "repository": {

@@ -6,27 +6,25 @@ fast-json

## Install
```
npm install fast-json
```
## Usage
```javascript
var FastJson = require('fast-json');
const FastJson = require('fast-json');
var data = JSON.stringify({
const data = JSON.stringify({
ireland: {
people: [{ name: 'Alex' }, { name: 'John' }, { name: 'Cian' }]
people: [{ name: 'Alex' }, { name: 'John' }, { name: 'Cian' }],
},
spain: {
people: [{ name: 'Antonio' }, { name: 'Juan' }, { name: 'Pedro' }]
}
people: [{ name: 'Antonio' }, { name: 'Juan' }, { name: 'Pedro' }],
},
'unknown.country': {
people: [{ name: 'Frank' }, { name: 'Paul' }],
},
huge_list: [1, 2, 3],
});
var fastJson = new FastJson();
const fastJson = new FastJson();
fastJson.on('ireland.people[0]', (value) => {
console.log('ireland.people[0] ->', value);
});
fastJson.on('spain', (value) => {
console.log('spain ->', value);
});
fastJson.on('ireland.people', (value) => {

@@ -40,5 +38,12 @@ console.log('ireland.people ->', value);

// Path as Array to allow keys with dots
fastJson.on(['unknown.country', 'people', '0', 'name'], (value) => {
console.log(['unknown.country', 'people', '0', 'name'], value);
// Stop parsing JSON usefull when have all we need improving performance
fastJson.skip();
});
fastJson.write(data);
// or
fastJson.write(new Buffer(data));
fastJson.write(Buffer.from(data));
```

@@ -56,4 +61,3 @@

* [**Feature**] Process wildcards in paths.
* [**Feature**] Public method to cancel actual write().
* [**Documentation**] Document public interface and create branch gh-pages using *jsdoc*.
* [**Documentation**] More real life testing and examples.
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