BOC v1.0: RS256 auth, Ledger integration, Prometheus metrics, CI/CD, backup
This commit is contained in:
+1114
@@ -0,0 +1,1114 @@
|
||||
const util = require('./util')
|
||||
|
||||
let source
|
||||
let parseState
|
||||
let stack
|
||||
let pos
|
||||
let line
|
||||
let column
|
||||
let token
|
||||
let key
|
||||
let root
|
||||
|
||||
module.exports = function parse (text, reviver) {
|
||||
source = String(text)
|
||||
parseState = 'start'
|
||||
stack = []
|
||||
pos = 0
|
||||
line = 1
|
||||
column = 0
|
||||
token = undefined
|
||||
key = undefined
|
||||
root = undefined
|
||||
|
||||
do {
|
||||
token = lex()
|
||||
|
||||
// This code is unreachable.
|
||||
// if (!parseStates[parseState]) {
|
||||
// throw invalidParseState()
|
||||
// }
|
||||
|
||||
parseStates[parseState]()
|
||||
} while (token.type !== 'eof')
|
||||
|
||||
if (typeof reviver === 'function') {
|
||||
return internalize({'': root}, '', reviver)
|
||||
}
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
function internalize (holder, name, reviver) {
|
||||
const value = holder[name]
|
||||
if (value != null && typeof value === 'object') {
|
||||
if (Array.isArray(value)) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const key = String(i)
|
||||
const replacement = internalize(value, key, reviver)
|
||||
if (replacement === undefined) {
|
||||
delete value[key]
|
||||
} else {
|
||||
Object.defineProperty(value, key, {
|
||||
value: replacement,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const key in value) {
|
||||
const replacement = internalize(value, key, reviver)
|
||||
if (replacement === undefined) {
|
||||
delete value[key]
|
||||
} else {
|
||||
Object.defineProperty(value, key, {
|
||||
value: replacement,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reviver.call(holder, name, value)
|
||||
}
|
||||
|
||||
let lexState
|
||||
let buffer
|
||||
let doubleQuote
|
||||
let sign
|
||||
let c
|
||||
|
||||
function lex () {
|
||||
lexState = 'default'
|
||||
buffer = ''
|
||||
doubleQuote = false
|
||||
sign = 1
|
||||
|
||||
for (;;) {
|
||||
c = peek()
|
||||
|
||||
// This code is unreachable.
|
||||
// if (!lexStates[lexState]) {
|
||||
// throw invalidLexState(lexState)
|
||||
// }
|
||||
|
||||
const token = lexStates[lexState]()
|
||||
if (token) {
|
||||
return token
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function peek () {
|
||||
if (source[pos]) {
|
||||
return String.fromCodePoint(source.codePointAt(pos))
|
||||
}
|
||||
}
|
||||
|
||||
function read () {
|
||||
const c = peek()
|
||||
|
||||
if (c === '\n') {
|
||||
line++
|
||||
column = 0
|
||||
} else if (c) {
|
||||
column += c.length
|
||||
} else {
|
||||
column++
|
||||
}
|
||||
|
||||
if (c) {
|
||||
pos += c.length
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
const lexStates = {
|
||||
default () {
|
||||
switch (c) {
|
||||
case '\t':
|
||||
case '\v':
|
||||
case '\f':
|
||||
case ' ':
|
||||
case '\u00A0':
|
||||
case '\uFEFF':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\u2028':
|
||||
case '\u2029':
|
||||
read()
|
||||
return
|
||||
|
||||
case '/':
|
||||
read()
|
||||
lexState = 'comment'
|
||||
return
|
||||
|
||||
case undefined:
|
||||
read()
|
||||
return newToken('eof')
|
||||
}
|
||||
|
||||
if (util.isSpaceSeparator(c)) {
|
||||
read()
|
||||
return
|
||||
}
|
||||
|
||||
// This code is unreachable.
|
||||
// if (!lexStates[parseState]) {
|
||||
// throw invalidLexState(parseState)
|
||||
// }
|
||||
|
||||
return lexStates[parseState]()
|
||||
},
|
||||
|
||||
comment () {
|
||||
switch (c) {
|
||||
case '*':
|
||||
read()
|
||||
lexState = 'multiLineComment'
|
||||
return
|
||||
|
||||
case '/':
|
||||
read()
|
||||
lexState = 'singleLineComment'
|
||||
return
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
multiLineComment () {
|
||||
switch (c) {
|
||||
case '*':
|
||||
read()
|
||||
lexState = 'multiLineCommentAsterisk'
|
||||
return
|
||||
|
||||
case undefined:
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
read()
|
||||
},
|
||||
|
||||
multiLineCommentAsterisk () {
|
||||
switch (c) {
|
||||
case '*':
|
||||
read()
|
||||
return
|
||||
|
||||
case '/':
|
||||
read()
|
||||
lexState = 'default'
|
||||
return
|
||||
|
||||
case undefined:
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
read()
|
||||
lexState = 'multiLineComment'
|
||||
},
|
||||
|
||||
singleLineComment () {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\u2028':
|
||||
case '\u2029':
|
||||
read()
|
||||
lexState = 'default'
|
||||
return
|
||||
|
||||
case undefined:
|
||||
read()
|
||||
return newToken('eof')
|
||||
}
|
||||
|
||||
read()
|
||||
},
|
||||
|
||||
value () {
|
||||
switch (c) {
|
||||
case '{':
|
||||
case '[':
|
||||
return newToken('punctuator', read())
|
||||
|
||||
case 'n':
|
||||
read()
|
||||
literal('ull')
|
||||
return newToken('null', null)
|
||||
|
||||
case 't':
|
||||
read()
|
||||
literal('rue')
|
||||
return newToken('boolean', true)
|
||||
|
||||
case 'f':
|
||||
read()
|
||||
literal('alse')
|
||||
return newToken('boolean', false)
|
||||
|
||||
case '-':
|
||||
case '+':
|
||||
if (read() === '-') {
|
||||
sign = -1
|
||||
}
|
||||
|
||||
lexState = 'sign'
|
||||
return
|
||||
|
||||
case '.':
|
||||
buffer = read()
|
||||
lexState = 'decimalPointLeading'
|
||||
return
|
||||
|
||||
case '0':
|
||||
buffer = read()
|
||||
lexState = 'zero'
|
||||
return
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
buffer = read()
|
||||
lexState = 'decimalInteger'
|
||||
return
|
||||
|
||||
case 'I':
|
||||
read()
|
||||
literal('nfinity')
|
||||
return newToken('numeric', Infinity)
|
||||
|
||||
case 'N':
|
||||
read()
|
||||
literal('aN')
|
||||
return newToken('numeric', NaN)
|
||||
|
||||
case '"':
|
||||
case "'":
|
||||
doubleQuote = (read() === '"')
|
||||
buffer = ''
|
||||
lexState = 'string'
|
||||
return
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
identifierNameStartEscape () {
|
||||
if (c !== 'u') {
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
read()
|
||||
const u = unicodeEscape()
|
||||
switch (u) {
|
||||
case '$':
|
||||
case '_':
|
||||
break
|
||||
|
||||
default:
|
||||
if (!util.isIdStartChar(u)) {
|
||||
throw invalidIdentifier()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
buffer += u
|
||||
lexState = 'identifierName'
|
||||
},
|
||||
|
||||
identifierName () {
|
||||
switch (c) {
|
||||
case '$':
|
||||
case '_':
|
||||
case '\u200C':
|
||||
case '\u200D':
|
||||
buffer += read()
|
||||
return
|
||||
|
||||
case '\\':
|
||||
read()
|
||||
lexState = 'identifierNameEscape'
|
||||
return
|
||||
}
|
||||
|
||||
if (util.isIdContinueChar(c)) {
|
||||
buffer += read()
|
||||
return
|
||||
}
|
||||
|
||||
return newToken('identifier', buffer)
|
||||
},
|
||||
|
||||
identifierNameEscape () {
|
||||
if (c !== 'u') {
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
read()
|
||||
const u = unicodeEscape()
|
||||
switch (u) {
|
||||
case '$':
|
||||
case '_':
|
||||
case '\u200C':
|
||||
case '\u200D':
|
||||
break
|
||||
|
||||
default:
|
||||
if (!util.isIdContinueChar(u)) {
|
||||
throw invalidIdentifier()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
buffer += u
|
||||
lexState = 'identifierName'
|
||||
},
|
||||
|
||||
sign () {
|
||||
switch (c) {
|
||||
case '.':
|
||||
buffer = read()
|
||||
lexState = 'decimalPointLeading'
|
||||
return
|
||||
|
||||
case '0':
|
||||
buffer = read()
|
||||
lexState = 'zero'
|
||||
return
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
buffer = read()
|
||||
lexState = 'decimalInteger'
|
||||
return
|
||||
|
||||
case 'I':
|
||||
read()
|
||||
literal('nfinity')
|
||||
return newToken('numeric', sign * Infinity)
|
||||
|
||||
case 'N':
|
||||
read()
|
||||
literal('aN')
|
||||
return newToken('numeric', NaN)
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
zero () {
|
||||
switch (c) {
|
||||
case '.':
|
||||
buffer += read()
|
||||
lexState = 'decimalPoint'
|
||||
return
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
buffer += read()
|
||||
lexState = 'decimalExponent'
|
||||
return
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
buffer += read()
|
||||
lexState = 'hexadecimal'
|
||||
return
|
||||
}
|
||||
|
||||
return newToken('numeric', sign * 0)
|
||||
},
|
||||
|
||||
decimalInteger () {
|
||||
switch (c) {
|
||||
case '.':
|
||||
buffer += read()
|
||||
lexState = 'decimalPoint'
|
||||
return
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
buffer += read()
|
||||
lexState = 'decimalExponent'
|
||||
return
|
||||
}
|
||||
|
||||
if (util.isDigit(c)) {
|
||||
buffer += read()
|
||||
return
|
||||
}
|
||||
|
||||
return newToken('numeric', sign * Number(buffer))
|
||||
},
|
||||
|
||||
decimalPointLeading () {
|
||||
if (util.isDigit(c)) {
|
||||
buffer += read()
|
||||
lexState = 'decimalFraction'
|
||||
return
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
decimalPoint () {
|
||||
switch (c) {
|
||||
case 'e':
|
||||
case 'E':
|
||||
buffer += read()
|
||||
lexState = 'decimalExponent'
|
||||
return
|
||||
}
|
||||
|
||||
if (util.isDigit(c)) {
|
||||
buffer += read()
|
||||
lexState = 'decimalFraction'
|
||||
return
|
||||
}
|
||||
|
||||
return newToken('numeric', sign * Number(buffer))
|
||||
},
|
||||
|
||||
decimalFraction () {
|
||||
switch (c) {
|
||||
case 'e':
|
||||
case 'E':
|
||||
buffer += read()
|
||||
lexState = 'decimalExponent'
|
||||
return
|
||||
}
|
||||
|
||||
if (util.isDigit(c)) {
|
||||
buffer += read()
|
||||
return
|
||||
}
|
||||
|
||||
return newToken('numeric', sign * Number(buffer))
|
||||
},
|
||||
|
||||
decimalExponent () {
|
||||
switch (c) {
|
||||
case '+':
|
||||
case '-':
|
||||
buffer += read()
|
||||
lexState = 'decimalExponentSign'
|
||||
return
|
||||
}
|
||||
|
||||
if (util.isDigit(c)) {
|
||||
buffer += read()
|
||||
lexState = 'decimalExponentInteger'
|
||||
return
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
decimalExponentSign () {
|
||||
if (util.isDigit(c)) {
|
||||
buffer += read()
|
||||
lexState = 'decimalExponentInteger'
|
||||
return
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
decimalExponentInteger () {
|
||||
if (util.isDigit(c)) {
|
||||
buffer += read()
|
||||
return
|
||||
}
|
||||
|
||||
return newToken('numeric', sign * Number(buffer))
|
||||
},
|
||||
|
||||
hexadecimal () {
|
||||
if (util.isHexDigit(c)) {
|
||||
buffer += read()
|
||||
lexState = 'hexadecimalInteger'
|
||||
return
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
hexadecimalInteger () {
|
||||
if (util.isHexDigit(c)) {
|
||||
buffer += read()
|
||||
return
|
||||
}
|
||||
|
||||
return newToken('numeric', sign * Number(buffer))
|
||||
},
|
||||
|
||||
string () {
|
||||
switch (c) {
|
||||
case '\\':
|
||||
read()
|
||||
buffer += escape()
|
||||
return
|
||||
|
||||
case '"':
|
||||
if (doubleQuote) {
|
||||
read()
|
||||
return newToken('string', buffer)
|
||||
}
|
||||
|
||||
buffer += read()
|
||||
return
|
||||
|
||||
case "'":
|
||||
if (!doubleQuote) {
|
||||
read()
|
||||
return newToken('string', buffer)
|
||||
}
|
||||
|
||||
buffer += read()
|
||||
return
|
||||
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw invalidChar(read())
|
||||
|
||||
case '\u2028':
|
||||
case '\u2029':
|
||||
separatorChar(c)
|
||||
break
|
||||
|
||||
case undefined:
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
buffer += read()
|
||||
},
|
||||
|
||||
start () {
|
||||
switch (c) {
|
||||
case '{':
|
||||
case '[':
|
||||
return newToken('punctuator', read())
|
||||
|
||||
// This code is unreachable since the default lexState handles eof.
|
||||
// case undefined:
|
||||
// return newToken('eof')
|
||||
}
|
||||
|
||||
lexState = 'value'
|
||||
},
|
||||
|
||||
beforePropertyName () {
|
||||
switch (c) {
|
||||
case '$':
|
||||
case '_':
|
||||
buffer = read()
|
||||
lexState = 'identifierName'
|
||||
return
|
||||
|
||||
case '\\':
|
||||
read()
|
||||
lexState = 'identifierNameStartEscape'
|
||||
return
|
||||
|
||||
case '}':
|
||||
return newToken('punctuator', read())
|
||||
|
||||
case '"':
|
||||
case "'":
|
||||
doubleQuote = (read() === '"')
|
||||
lexState = 'string'
|
||||
return
|
||||
}
|
||||
|
||||
if (util.isIdStartChar(c)) {
|
||||
buffer += read()
|
||||
lexState = 'identifierName'
|
||||
return
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
afterPropertyName () {
|
||||
if (c === ':') {
|
||||
return newToken('punctuator', read())
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
beforePropertyValue () {
|
||||
lexState = 'value'
|
||||
},
|
||||
|
||||
afterPropertyValue () {
|
||||
switch (c) {
|
||||
case ',':
|
||||
case '}':
|
||||
return newToken('punctuator', read())
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
beforeArrayValue () {
|
||||
if (c === ']') {
|
||||
return newToken('punctuator', read())
|
||||
}
|
||||
|
||||
lexState = 'value'
|
||||
},
|
||||
|
||||
afterArrayValue () {
|
||||
switch (c) {
|
||||
case ',':
|
||||
case ']':
|
||||
return newToken('punctuator', read())
|
||||
}
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
|
||||
end () {
|
||||
// This code is unreachable since it's handled by the default lexState.
|
||||
// if (c === undefined) {
|
||||
// read()
|
||||
// return newToken('eof')
|
||||
// }
|
||||
|
||||
throw invalidChar(read())
|
||||
},
|
||||
}
|
||||
|
||||
function newToken (type, value) {
|
||||
return {
|
||||
type,
|
||||
value,
|
||||
line,
|
||||
column,
|
||||
}
|
||||
}
|
||||
|
||||
function literal (s) {
|
||||
for (const c of s) {
|
||||
const p = peek()
|
||||
|
||||
if (p !== c) {
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
read()
|
||||
}
|
||||
}
|
||||
|
||||
function escape () {
|
||||
const c = peek()
|
||||
switch (c) {
|
||||
case 'b':
|
||||
read()
|
||||
return '\b'
|
||||
|
||||
case 'f':
|
||||
read()
|
||||
return '\f'
|
||||
|
||||
case 'n':
|
||||
read()
|
||||
return '\n'
|
||||
|
||||
case 'r':
|
||||
read()
|
||||
return '\r'
|
||||
|
||||
case 't':
|
||||
read()
|
||||
return '\t'
|
||||
|
||||
case 'v':
|
||||
read()
|
||||
return '\v'
|
||||
|
||||
case '0':
|
||||
read()
|
||||
if (util.isDigit(peek())) {
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
return '\0'
|
||||
|
||||
case 'x':
|
||||
read()
|
||||
return hexEscape()
|
||||
|
||||
case 'u':
|
||||
read()
|
||||
return unicodeEscape()
|
||||
|
||||
case '\n':
|
||||
case '\u2028':
|
||||
case '\u2029':
|
||||
read()
|
||||
return ''
|
||||
|
||||
case '\r':
|
||||
read()
|
||||
if (peek() === '\n') {
|
||||
read()
|
||||
}
|
||||
|
||||
return ''
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
throw invalidChar(read())
|
||||
|
||||
case undefined:
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
return read()
|
||||
}
|
||||
|
||||
function hexEscape () {
|
||||
let buffer = ''
|
||||
let c = peek()
|
||||
|
||||
if (!util.isHexDigit(c)) {
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
buffer += read()
|
||||
|
||||
c = peek()
|
||||
if (!util.isHexDigit(c)) {
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
buffer += read()
|
||||
|
||||
return String.fromCodePoint(parseInt(buffer, 16))
|
||||
}
|
||||
|
||||
function unicodeEscape () {
|
||||
let buffer = ''
|
||||
let count = 4
|
||||
|
||||
while (count-- > 0) {
|
||||
const c = peek()
|
||||
if (!util.isHexDigit(c)) {
|
||||
throw invalidChar(read())
|
||||
}
|
||||
|
||||
buffer += read()
|
||||
}
|
||||
|
||||
return String.fromCodePoint(parseInt(buffer, 16))
|
||||
}
|
||||
|
||||
const parseStates = {
|
||||
start () {
|
||||
if (token.type === 'eof') {
|
||||
throw invalidEOF()
|
||||
}
|
||||
|
||||
push()
|
||||
},
|
||||
|
||||
beforePropertyName () {
|
||||
switch (token.type) {
|
||||
case 'identifier':
|
||||
case 'string':
|
||||
key = token.value
|
||||
parseState = 'afterPropertyName'
|
||||
return
|
||||
|
||||
case 'punctuator':
|
||||
// This code is unreachable since it's handled by the lexState.
|
||||
// if (token.value !== '}') {
|
||||
// throw invalidToken()
|
||||
// }
|
||||
|
||||
pop()
|
||||
return
|
||||
|
||||
case 'eof':
|
||||
throw invalidEOF()
|
||||
}
|
||||
|
||||
// This code is unreachable since it's handled by the lexState.
|
||||
// throw invalidToken()
|
||||
},
|
||||
|
||||
afterPropertyName () {
|
||||
// This code is unreachable since it's handled by the lexState.
|
||||
// if (token.type !== 'punctuator' || token.value !== ':') {
|
||||
// throw invalidToken()
|
||||
// }
|
||||
|
||||
if (token.type === 'eof') {
|
||||
throw invalidEOF()
|
||||
}
|
||||
|
||||
parseState = 'beforePropertyValue'
|
||||
},
|
||||
|
||||
beforePropertyValue () {
|
||||
if (token.type === 'eof') {
|
||||
throw invalidEOF()
|
||||
}
|
||||
|
||||
push()
|
||||
},
|
||||
|
||||
beforeArrayValue () {
|
||||
if (token.type === 'eof') {
|
||||
throw invalidEOF()
|
||||
}
|
||||
|
||||
if (token.type === 'punctuator' && token.value === ']') {
|
||||
pop()
|
||||
return
|
||||
}
|
||||
|
||||
push()
|
||||
},
|
||||
|
||||
afterPropertyValue () {
|
||||
// This code is unreachable since it's handled by the lexState.
|
||||
// if (token.type !== 'punctuator') {
|
||||
// throw invalidToken()
|
||||
// }
|
||||
|
||||
if (token.type === 'eof') {
|
||||
throw invalidEOF()
|
||||
}
|
||||
|
||||
switch (token.value) {
|
||||
case ',':
|
||||
parseState = 'beforePropertyName'
|
||||
return
|
||||
|
||||
case '}':
|
||||
pop()
|
||||
}
|
||||
|
||||
// This code is unreachable since it's handled by the lexState.
|
||||
// throw invalidToken()
|
||||
},
|
||||
|
||||
afterArrayValue () {
|
||||
// This code is unreachable since it's handled by the lexState.
|
||||
// if (token.type !== 'punctuator') {
|
||||
// throw invalidToken()
|
||||
// }
|
||||
|
||||
if (token.type === 'eof') {
|
||||
throw invalidEOF()
|
||||
}
|
||||
|
||||
switch (token.value) {
|
||||
case ',':
|
||||
parseState = 'beforeArrayValue'
|
||||
return
|
||||
|
||||
case ']':
|
||||
pop()
|
||||
}
|
||||
|
||||
// This code is unreachable since it's handled by the lexState.
|
||||
// throw invalidToken()
|
||||
},
|
||||
|
||||
end () {
|
||||
// This code is unreachable since it's handled by the lexState.
|
||||
// if (token.type !== 'eof') {
|
||||
// throw invalidToken()
|
||||
// }
|
||||
},
|
||||
}
|
||||
|
||||
function push () {
|
||||
let value
|
||||
|
||||
switch (token.type) {
|
||||
case 'punctuator':
|
||||
switch (token.value) {
|
||||
case '{':
|
||||
value = {}
|
||||
break
|
||||
|
||||
case '[':
|
||||
value = []
|
||||
break
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case 'null':
|
||||
case 'boolean':
|
||||
case 'numeric':
|
||||
case 'string':
|
||||
value = token.value
|
||||
break
|
||||
|
||||
// This code is unreachable.
|
||||
// default:
|
||||
// throw invalidToken()
|
||||
}
|
||||
|
||||
if (root === undefined) {
|
||||
root = value
|
||||
} else {
|
||||
const parent = stack[stack.length - 1]
|
||||
if (Array.isArray(parent)) {
|
||||
parent.push(value)
|
||||
} else {
|
||||
Object.defineProperty(parent, key, {
|
||||
value,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (value !== null && typeof value === 'object') {
|
||||
stack.push(value)
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
parseState = 'beforeArrayValue'
|
||||
} else {
|
||||
parseState = 'beforePropertyName'
|
||||
}
|
||||
} else {
|
||||
const current = stack[stack.length - 1]
|
||||
if (current == null) {
|
||||
parseState = 'end'
|
||||
} else if (Array.isArray(current)) {
|
||||
parseState = 'afterArrayValue'
|
||||
} else {
|
||||
parseState = 'afterPropertyValue'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pop () {
|
||||
stack.pop()
|
||||
|
||||
const current = stack[stack.length - 1]
|
||||
if (current == null) {
|
||||
parseState = 'end'
|
||||
} else if (Array.isArray(current)) {
|
||||
parseState = 'afterArrayValue'
|
||||
} else {
|
||||
parseState = 'afterPropertyValue'
|
||||
}
|
||||
}
|
||||
|
||||
// This code is unreachable.
|
||||
// function invalidParseState () {
|
||||
// return new Error(`JSON5: invalid parse state '${parseState}'`)
|
||||
// }
|
||||
|
||||
// This code is unreachable.
|
||||
// function invalidLexState (state) {
|
||||
// return new Error(`JSON5: invalid lex state '${state}'`)
|
||||
// }
|
||||
|
||||
function invalidChar (c) {
|
||||
if (c === undefined) {
|
||||
return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
|
||||
}
|
||||
|
||||
return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
|
||||
}
|
||||
|
||||
function invalidEOF () {
|
||||
return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
|
||||
}
|
||||
|
||||
// This code is unreachable.
|
||||
// function invalidToken () {
|
||||
// if (token.type === 'eof') {
|
||||
// return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
|
||||
// }
|
||||
|
||||
// const c = String.fromCodePoint(token.value.codePointAt(0))
|
||||
// return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
|
||||
// }
|
||||
|
||||
function invalidIdentifier () {
|
||||
column -= 5
|
||||
return syntaxError(`JSON5: invalid identifier character at ${line}:${column}`)
|
||||
}
|
||||
|
||||
function separatorChar (c) {
|
||||
console.warn(`JSON5: '${formatChar(c)}' in strings is not valid ECMAScript; consider escaping`)
|
||||
}
|
||||
|
||||
function formatChar (c) {
|
||||
const replacements = {
|
||||
"'": "\\'",
|
||||
'"': '\\"',
|
||||
'\\': '\\\\',
|
||||
'\b': '\\b',
|
||||
'\f': '\\f',
|
||||
'\n': '\\n',
|
||||
'\r': '\\r',
|
||||
'\t': '\\t',
|
||||
'\v': '\\v',
|
||||
'\0': '\\0',
|
||||
'\u2028': '\\u2028',
|
||||
'\u2029': '\\u2029',
|
||||
}
|
||||
|
||||
if (replacements[c]) {
|
||||
return replacements[c]
|
||||
}
|
||||
|
||||
if (c < ' ') {
|
||||
const hexString = c.charCodeAt(0).toString(16)
|
||||
return '\\x' + ('00' + hexString).substring(hexString.length)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
function syntaxError (message) {
|
||||
const err = new SyntaxError(message)
|
||||
err.lineNumber = line
|
||||
err.columnNumber = column
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user