@senx/discovery-widgets
Version:
Discovery Widgets Elements
273 lines (272 loc) • 8.08 kB
JavaScript
/*
* Copyright 2022-2025 SenX S.A.S.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// adapted from Canop's JSON,parseMore https://github.com/Canop/JSON.parseMore/
export class JsonLib {
constructor() {
this.escapee = {
'"': '"',
'\\': '\\',
'/': '/',
b: '\b',
f: '\f',
n: '\n',
r: '\r',
t: '\t'
};
}
error(m) {
throw {
name: 'SyntaxError',
message: m,
at: this.at,
text: this.text
};
}
next() {
return this.ch = this.text.charAt(this.at++);
}
check(c) {
if (c !== this.ch) {
this.error(`Expected '${c}' instead of '${this.ch}'`);
}
this.ch = this.text.charAt(this.at++);
}
parseNumber() {
let str = '';
if (this.ch === '-') {
str = '-';
this.check('-');
}
if (this.ch === 'I') {
this.check('I');
this.check('n');
this.check('f');
this.check('i');
this.check('n');
this.check('i');
this.check('t');
this.check('y');
return -Infinity;
}
while (this.ch >= '0' && this.ch <= '9') {
str += this.ch;
this.next();
}
if (this.ch === '.') {
str += '.';
while (this.next() && this.ch >= '0' && this.ch <= '9') {
str += this.ch;
}
}
if (this.ch === 'e' || this.ch === 'E') {
str += this.ch;
this.next();
// @ts-ignore
if (this.ch === '-' || this.ch === '+') {
str += this.ch;
this.next();
}
while (this.ch >= '0' && this.ch <= '9') {
str += this.ch;
this.next();
}
}
return +str;
}
parseString() {
let hex;
let str = '';
let uffff;
if (this.ch === '"') {
while (this.next()) {
if (this.ch === '"') {
this.next();
return str;
}
if (this.ch === '\\') {
this.next();
if (this.ch === 'u') {
uffff = 0;
for (let i = 0; i < 4; i++) {
hex = parseInt(this.next(), 16);
if (!isFinite(hex)) {
break;
}
uffff = uffff * 16 + hex;
}
str += String.fromCharCode(uffff);
}
else if (this.escapee[this.ch]) {
str += this.escapee[this.ch];
}
else {
break;
}
}
else {
str += this.ch;
}
}
}
this.error('Bad string');
}
white() {
while (this.ch && this.ch <= ' ') {
this.next();
}
}
word() {
switch (this.ch) {
case 't':
this.check('t');
this.check('r');
this.check('u');
this.check('e');
return true;
case 'f':
this.check('f');
this.check('a');
this.check('l');
this.check('s');
this.check('e');
return false;
case 'n':
this.check('n');
this.check('u');
this.check('l');
this.check('l');
return null;
case 'N':
this.check('N');
this.check('a');
this.check('N');
return NaN;
case 'I':
this.check('I');
this.check('n');
this.check('f');
this.check('i');
this.check('n');
this.check('i');
this.check('t');
this.check('y');
return Infinity;
}
this.error(`Unexpected '${this.ch}'`);
}
array() {
const array = [];
if (this.ch === '[') {
this.check('[');
this.white();
// @ts-ignore
if (this.ch === ']') {
this.check(']');
return array; // empty array
}
while (this.ch !== undefined) {
array.push(this.value());
this.white();
// @ts-ignore
if (this.ch === ']') {
this.check(']');
return array;
}
this.check(',');
this.white();
}
}
this.error('Bad array');
}
object() {
let key;
const object = {};
if (this.ch === '{') {
this.check('{');
this.white();
// @ts-ignore
if (this.ch === '}') {
this.check('}');
return object; // empty object
}
while (this.ch) {
key = this.parseString();
this.white();
this.check(':');
if (object.hasOwnProperty(key)) {
this.error(`Duplicate key '${key}'`);
}
object[key] = this.value();
this.white();
// @ts-ignore
if (this.ch === '}') {
this.check('}');
return object;
}
this.check(',');
this.white();
}
}
this.error('Bad object');
}
value() {
this.white();
switch (this.ch) {
case '{':
return this.object();
case '[':
return this.array();
case '"':
return this.parseString();
case '-':
return this.parseNumber();
default:
return this.ch >= '0' && this.ch <= '9' ? this.parseNumber() : this.word();
}
}
parse(source, reviver) {
this.text = source;
this.at = 0;
this.ch = ' ';
const result = this.value();
this.white();
if (this.ch) {
this.error('Syntax error');
}
return typeof reviver === 'function'
? (function walk(holder, key) {
let k;
let v;
const value = holder[key];
if (value !== undefined && typeof value === 'object') {
for (k in value) {
if (value.hasOwnProperty(k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
}
else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}({ '': result }, ''))
: result;
}
}
//# sourceMappingURL=jsonLib.js.map