UNPKG

kvclient-js

Version:

Oracle NoSQL Database node.js Client API.

323 lines (303 loc) 7.96 kB
var Int64 = require('node-int64'); var hex2dec = require('./Hex2Dec'); /** * based on: * https://github.com/douglascrockford/JSON-js * * Parse.js * 2012-06-20 * * Public Domain. * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. * * This file creates a parse function. * * The resulting function follows this signature: * parse(text, reviver) * This method parses a JSON text to produce an object or array. * It can throw a SyntaxError exception. * * The optional reviver parameter is a function that can filter and * transform the results. It receives each of the keys and values, * and its return value is used instead of the original value. * If it returns what it received, then the structure is not modified. * If it returns undefined then the member is deleted. * * Example: * * Parse the text. Values that look like ISO date strings will * be converted to Date objects. * * myData = parse(text, function (key, value) { * var a; * if (typeof value === 'string') { * a = * /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); * if (a) { * return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], * +a[5], +a[6])); * } * } * return value; * }); * * This is a reference implementation. You are free to copy, modify, or * redistribute. * * USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO * NOT CONTROL. */ /** * members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode, * hasOwnProperty, message, n, name, prototype, push, r, t, text */ "use strict"; // not being strict means do not generate syntax errors for "duplicate key" var strict = false; var at, // The index of the current character ch, // The current character escapee = { '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t' }, text; // Call error when something is wrong. function error (m) { throw { name: 'SyntaxError', message: m, at: at, text: text }; } // If a c parameter is provided, verify that it matches the current character. function next (c) { if (c && c !== ch) { error("Expected '" + c + "' instead of '" + ch + "'"); } // Get the next character. When there are no more characters, // return the empty string. ch = text.charAt(at); at += 1; return ch; } // Parse a number value. function number() { var number, string = ''; if (ch === '-') { string = '-'; next('-'); } while (ch >= '0' && ch <= '9') { string += ch; next(); } if (ch === '.') { string += '.'; while (next() && ch >= '0' && ch <= '9') { string += ch; } } if (ch === 'e' || ch === 'E') { string += ch; next(); if (ch === '-' || ch === '+') { string += ch; next(); } while (ch >= '0' && ch <= '9') { string += ch; next(); } } number = +string; if (!isFinite(number)) { error("Bad number"); } else { // Long numbers has stricter check: everything with length > 15 digits disallowed if (string.length > 15) if (-1 == string.indexOf(".")) { return new Int64(hex2dec.decToHex(string)); } return number; } } // Parse a string value. function string() { var hex, i, string = '', uffff; // When parsing for string values, we must look for " and \ characters. if (ch === '"') { while (next()) { if (ch === '"') { next(); return string; } if (ch === '\\') { next(); if (ch === 'u') { uffff = 0; for (i = 0; i < 4; i += 1) { hex = parseInt(next(), 16); if (!isFinite(hex)) { break; } uffff = uffff * 16 + hex; } string += String.fromCharCode(uffff); } else if (typeof escapee[ch] === 'string') { string += escapee[ch]; } else { break; } } else { string += ch; } } } error("Bad string"); } // Skip whitespace. function white() { while (ch && ch <= ' ') { next(); } } // true, false, or null. function word () { switch (ch) { case 't': next('t'); next('r'); next('u'); next('e'); return true; case 'f': next('f'); next('a'); next('l'); next('s'); next('e'); return false; case 'n': next('n'); next('u'); next('l'); next('l'); return null; } error("Unexpected '" + ch + "'"); } // Parse an array value. function array() { var array = []; if (ch === '[') { next('['); white(); if (ch === ']') { next(']'); return array; // empty array } while (ch) { array.push(value()); white(); if (ch === ']') { next(']'); return array; } next(','); white(); } } error("Bad array"); } // Parse an object value. function object() { var key, object = {}; if (ch === '{') { next('{'); white(); if (ch === '}') { next('}'); return object; // empty object } while (ch) { key = string(); white(); next(':'); if (strict && Object.hasOwnProperty.call(object, key)) { error('Duplicate key "' + key + '"'); } object[key] = value(); white(); if (ch === '}') { next('}'); return object; } next(','); white(); } } error("Bad object"); } // Parse a JSON value. It could be an object, an array, a string, a number, // or a word. function value() { white(); switch (ch) { case '{': return object(); case '[': return array(); case '"': return string(); case '-': return number(); default: return ch >= '0' && ch <= '9' ? number() : word(); } } exports.parse = function (source, reviver) { var result; text = source; at = 0; ch = ' '; result = value(); white(); if (ch) { error("Syntax error"); } // If there is a reviver function, we recursively walk the new structure, // passing each name/value pair to the reviver function for possible // transformation, starting with a temporary root object that holds the result // in an empty key. If there is not a reviver function, we simply return the // result. return typeof reviver === 'function' ? (function walk(holder, key) { var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); }({'': result}, '')) : result; };