Skip to content

Commit

Permalink
feat(Utils): Move json-bigint implementation to utils (#486)
Browse files Browse the repository at this point in the history
  • Loading branch information
nduchak authored Jun 13, 2019
1 parent 85391e5 commit 1538867
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 12 deletions.
4 changes: 2 additions & 2 deletions es/utils/http.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios from 'axios'
import JSONbig from 'json-bigint'
import JsonBig from './json-big'
import * as R from 'ramda'
import stampit from '@stamp/it'

Expand Down Expand Up @@ -59,7 +59,7 @@ const Http = stampit({
headers: { 'Content-Type': 'application/json' },
transformResponse: [(data) => {
try {
return JSONbig({ 'storeAsString': true }).parse(data)
return JsonBig.parse(data)
} catch (e) {
return data
}
Expand Down
317 changes: 317 additions & 0 deletions es/utils/json-big.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
/* eslint-disable */
export default {
parse: ((options) => {
// This is a function that can parse a JSON text, producing a JavaScript
// data structure. It is a simple, recursive descent parser. It does not use
// eval or regular expressions, so it can be used as a model for implementing
// a JSON parser in other languages.

// We are defining the function inside of another function to avoid creating
// global letiables.

// Default options one can override by passing options to the parse()
const _options = {
'strict': false, // not being strict means do not generate syntax errors for "duplicate key"
'storeAsString': false // toggles whether the values should be stored as BigNumber (default) or a string
}

const escapee = {
'"': '"',
'\\': '\\',
'/': '/',
b: '\b',
f: '\f',
n: '\n',
r: '\r',
t: '\t'
}

// If there are options, then use them to override the default _options
if (options !== undefined && options !== null) {
if (options.strict === true) {
_options.strict = true
}
if (options.storeAsString === true) {
_options.storeAsString = true
}
}

let at
// The index of the current character

let ch
// The current character

let text

let error = function (m) {
// Call error when something is wrong.

throw {
name: 'SyntaxError',
message: m,
at: at,
text: text
}
}

let next = function (c) {
// If a c parameter is provided, verify that it matches the current character.

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
}

let number = function () {
// Parse a number value.

let number

let 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 {
// if (number > 9007199254740992 || number < -9007199254740992)
// Bignumber has stricter check: everything with length > 15 digits disallowed
if (string.length > 15) { return string }
return number
}
}

let string = function () {
// Parse a string value.

let hex

let i

let string = ''

let 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')
}

let white = function () {
// Skip whitespace.

while (ch && ch <= ' ') {
next()
}
}

let word = function () {
// true, false, or null.

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 + '\'')
}

let value
// Place holder for the value function.

let array = function () {
// Parse an array value.

let 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')
}

let object = function () {
// Parse an object value.

let key

let object = {}

if (ch === '{') {
next('{')
white()
if (ch === '}') {
next('}')
return object // empty object
}
while (ch) {
key = string()
white()
next(':')
if (_options.strict === true && Object.hasOwnProperty.call(object, key)) {
error('Duplicate key "' + key + '"')
}
object[key] = value()
white()
if (ch === '}') {
next('}')
return object
}
next(',')
white()
}
}
error('Bad object')
}

value = function () {
// Parse a JSON value. It could be an object, an array, a string, a number,
// or a word.

white()
switch (ch) {
case '{':
return object()
case '[':
return array()
case '"':
return string()
case '-':
return number()
default:
return ch >= '0' && ch <= '9' ? number() : word()
}
}

// Return the json_parse function. It will have access to all of the above
// functions and letiables.

return function (source, reviver) {
let 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) {
let k; let v; let value = holder[key]
if (value && typeof value === 'object') {
Object.keys(value).forEach(function (k) {
v = walk(value, k)
if (v !== undefined) {
value[k] = v
} else {
delete value[k]
}
})
}
return reviver.call(holder, key, value)
}({ '': result }, ''))
: result
}
})()
}
4 changes: 2 additions & 2 deletions es/utils/swagger.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* @example import Swagger from '@aeternity/aepp-sdk/es/utils/swagger'
*/

import JSONbig from 'json-bigint'
import JsonBig from './json-big'
import stampit from '@stamp/it'
import AsyncInit from './async-init'
import axios from 'axios'
Expand Down Expand Up @@ -194,7 +194,7 @@ const httpConfig = {
headers: { 'Content-Type': 'application/json' },
transformResponse: [(data) => {
try {
return JSONbig({ 'storeAsString': true }).parse(data)
return JsonBig.parse(data)
} catch (e) {
return data
}
Expand Down
7 changes: 0 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
"bs58check": "^2.1.1",
"commander": "^2.14.1",
"joi-browser": "^13.4.0",
"json-bigint": "davidyuk/json-bigint",
"libsodium-wrappers-sumo": "0.7.3",
"ramda": "^0.25.0",
"rlp": "2.1.0",
Expand Down

0 comments on commit 1538867

Please sign in to comment.