dotfiles/vscode/.vscode/extensions/randomfractalsinc.vscode-data-preview-2.3.0/node_modules/hjson/lib/hjson-parse.js
Errol Sancaktar ff17c17e23 vscode
2024-06-14 09:31:58 -06:00

456 lines
13 KiB
JavaScript

/* Hjson http://hjson.org */
"use strict";
module.exports = function(source, opt) {
var common = require("./hjson-common");
var dsf = require("./hjson-dsf");
var text;
var at; // The index of the current character
var ch; // The current character
var escapee = {
'"': '"',
"'": "'",
'\\': '\\',
'/': '/',
b: '\b',
f: '\f',
n: '\n',
r: '\r',
t: '\t'
};
var keepComments;
var runDsf; // domain specific formats
function resetAt() {
at = 0;
ch = ' ';
}
function isPunctuatorChar(c) {
return c === '{' || c === '}' || c === '[' || c === ']' || c === ',' || c === ':';
}
// Call error when something is wrong.
function error(m) {
var i, col=0, line=1;
for (i = at-1; i > 0 && text[i] !== '\n'; i--, col++) {}
for (; i > 0; i--) if (text[i] === '\n') line++;
throw new Error(m + " at line " + line + "," + col + " >>>" + text.substr(at-col, 20) + " ...");
}
function next() {
// get the next character.
ch = text.charAt(at);
at++;
return ch;
}
function peek(offs) {
// range check is not required
return text.charAt(at + offs);
}
function string(allowML) {
// Parse a string value.
// callers make sure that (ch === '"' || ch === "'")
var string = '';
// When parsing for string values, we must look for "/' and \ characters.
var exitCh = ch;
while (next()) {
if (ch === exitCh) {
next();
if (allowML && exitCh === "'" && ch === "'" && string.length === 0) {
// ''' indicates a multiline string
next();
return mlString();
} else return string;
}
if (ch === '\\') {
next();
if (ch === 'u') {
var uffff = 0;
for (var i = 0; i < 4; i++) {
next();
var c = ch.charCodeAt(0), hex;
if (ch >= '0' && ch <= '9') hex = c - 48;
else if (ch >= 'a' && ch <= 'f') hex = c - 97 + 0xa;
else if (ch >= 'A' && ch <= 'F') hex = c - 65 + 0xa;
else error("Bad \\u char " + ch);
uffff = uffff * 16 + hex;
}
string += String.fromCharCode(uffff);
} else if (typeof escapee[ch] === 'string') {
string += escapee[ch];
} else break;
} else if (ch === '\n' || ch === '\r') {
error("Bad string containing newline");
} else {
string += ch;
}
}
error("Bad string");
}
function mlString() {
// Parse a multiline string value.
var string = '', triple = 0;
// we are at ''' +1 - get indent
var indent = 0;
for (;;) {
var c=peek(-indent-5);
if (!c || c === '\n') break;
indent++;
}
function skipIndent() {
var skip = indent;
while (ch && ch <= ' ' && ch !== '\n' && skip-- > 0) next();
}
// skip white/to (newline)
while (ch && ch <= ' ' && ch !== '\n') next();
if (ch === '\n') { next(); skipIndent(); }
// When parsing multiline string values, we must look for ' characters.
for (;;) {
if (!ch) {
error("Bad multiline string");
} else if (ch === '\'') {
triple++;
next();
if (triple === 3) {
if (string.slice(-1) === '\n') string=string.slice(0, -1); // remove last EOL
return string;
} else continue;
} else {
while (triple > 0) {
string += '\'';
triple--;
}
}
if (ch === '\n') {
string += '\n';
next();
skipIndent();
} else {
if (ch !== '\r') string += ch;
next();
}
}
}
function keyname() {
// quotes for keys are optional in Hjson
// unless they include {}[],: or whitespace.
if (ch === '"' || ch === "'") return string(false);
var name = "", start = at, space = -1;
for (;;) {
if (ch === ':') {
if (!name) error("Found ':' but no key name (for an empty key name use quotes)");
else if (space >=0 && space !== name.length) { at = start + space; error("Found whitespace in your key name (use quotes to include)"); }
return name;
} else if (ch <= ' ') {
if (!ch) error("Found EOF while looking for a key name (check your syntax)");
else if (space < 0) space = name.length;
} else if (isPunctuatorChar(ch)) {
error("Found '" + ch + "' where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)");
} else {
name += ch;
}
next();
}
}
function white() {
while (ch) {
// Skip whitespace.
while (ch && ch <= ' ') next();
// Hjson allows comments
if (ch === '#' || ch === '/' && peek(0) === '/') {
while (ch && ch !== '\n') next();
} else if (ch === '/' && peek(0) === '*') {
next(); next();
while (ch && !(ch === '*' && peek(0) === '/')) next();
if (ch) { next(); next(); }
} else break;
}
}
function tfnns() {
// Hjson strings can be quoteless
// returns string, true, false, or null.
var value = ch;
if (isPunctuatorChar(ch))
error("Found a punctuator character '" + ch + "' when expecting a quoteless string (check your syntax)");
for(;;) {
next();
// (detection of ml strings was moved to string())
var isEol = ch === '\r' || ch === '\n' || ch === '';
if (isEol ||
ch === ',' || ch === '}' || ch === ']' ||
ch === '#' ||
ch === '/' && (peek(0) === '/' || peek(0) === '*')
) {
// this tests for the case of {true|false|null|num}
// followed by { ',' | '}' | ']' | '#' | '//' | '/*' }
// which needs to be parsed as the specified value
var chf = value[0];
switch (chf) {
case 'f': if (value.trim() === "false") return false; break;
case 'n': if (value.trim() === "null") return null; break;
case 't': if (value.trim() === "true") return true; break;
default:
if (chf === '-' || chf >= '0' && chf <= '9') {
var n = common.tryParseNumber(value);
if (n !== undefined) return n;
}
}
if (isEol) {
// remove any whitespace at the end (ignored in quoteless strings)
value = value.trim();
var dsfValue = runDsf(value);
return dsfValue !== undefined ? dsfValue : value;
}
}
value += ch;
}
}
function getComment(cAt, first) {
var i;
cAt--;
// remove trailing whitespace
// but only up to EOL
for (i = at - 2; i > cAt && text[i] <= ' ' && text[i] !== '\n'; i--);
if (text[i] === '\n') i--;
if (text[i] === '\r') i--;
var res = text.substr(cAt, i-cAt+1);
// return if we find anything other than whitespace
for (i = 0; i < res.length; i++) {
if (res[i] > ' ') {
var j = res.indexOf('\n');
if (j >= 0) {
var c = [res.substr(0, j), res.substr(j+1)];
if (first && c[0].trim().length === 0) c.shift();
return c;
} else return [res];
}
}
return [];
}
function errorClosingHint(value) {
function search(value, ch) {
var i, k, length, res;
switch (typeof value) {
case 'string':
if (value.indexOf(ch) >= 0) res = value;
break;
case 'object':
if (Object.prototype.toString.apply(value) === '[object Array]') {
for (i = 0, length = value.length; i < length; i++) {
res=search(value[i], ch) || res;
}
} else {
for (k in value) {
if (!Object.prototype.hasOwnProperty.call(value, k)) continue;
res=search(value[k], ch) || res;
}
}
}
return res;
}
function report(ch) {
var possibleErr=search(value, ch);
if (possibleErr) {
return "found '"+ch+"' in a string value, your mistake could be with:\n"+
" > "+possibleErr+"\n"+
" (unquoted strings contain everything up to the next line!)";
} else return "";
}
return report('}') || report(']');
}
function array() {
// Parse an array value.
// assuming ch === '['
var array = [];
var comments, cAt, nextComment;
try {
if (keepComments) comments = common.createComment(array, { a: [] });
next();
cAt = at;
white();
if (comments) nextComment = getComment(cAt, true).join('\n');
if (ch === ']') {
next();
if (comments) comments.e = [nextComment];
return array; // empty array
}
while (ch) {
array.push(value());
cAt = at;
white();
// in Hjson the comma is optional and trailing commas are allowed
// note that we do not keep comments before the , if there are any
if (ch === ',') { next(); cAt = at; white(); }
if (comments) {
var c = getComment(cAt);
comments.a.push([nextComment||"", c[0]||""]);
nextComment = c[1];
}
if (ch === ']') {
next();
if (comments) comments.a[comments.a.length-1][1] += nextComment||"";
return array;
}
white();
}
error("End of input while parsing an array (missing ']')");
} catch (e) {
e.hint=e.hint||errorClosingHint(array);
throw e;
}
}
function object(withoutBraces) {
// Parse an object value.
var key = "", object = {};
var comments, cAt, nextComment;
try {
if (keepComments) comments = common.createComment(object, { c: {}, o: [] });
if (!withoutBraces) {
// assuming ch === '{'
next();
cAt = at;
} else cAt = 1;
white();
if (comments) nextComment = getComment(cAt, true).join('\n');
if (ch === '}' && !withoutBraces) {
if (comments) comments.e = [nextComment];
next();
return object; // empty object
}
while (ch) {
key = keyname();
white();
if (ch !== ':') error("Expected ':' instead of '" + ch + "'");
next();
// duplicate keys overwrite the previous value
object[key] = value();
cAt = at;
white();
// in Hjson the comma is optional and trailing commas are allowed
// note that we do not keep comments before the , if there are any
if (ch === ',') { next(); cAt = at; white(); }
if (comments) {
var c = getComment(cAt);
comments.c[key] = [nextComment||"", c[0]||""];
nextComment = c[1];
comments.o.push(key);
}
if (ch === '}' && !withoutBraces) {
next();
if (comments) comments.c[key][1] += nextComment||"";
return object;
}
white();
}
if (withoutBraces) return object;
else error("End of input while parsing an object (missing '}')");
} catch (e) {
e.hint=e.hint||errorClosingHint(object);
throw e;
}
}
function value() {
// Parse a Hjson 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 "'":
case '"': return string(true);
default: return tfnns();
}
}
function checkTrailing(v, c) {
var cAt = at;
white();
if (ch) error("Syntax error, found trailing characters");
if (keepComments) {
var b = c.join('\n'), a = getComment(cAt).join('\n');
if (a || b) {
var comments = common.createComment(v, common.getComment(v));
comments.r = [b, a];
}
}
return v;
}
function rootValue() {
white();
var c = keepComments ? getComment(1) : null;
switch (ch) {
case '{': return checkTrailing(object(), c);
case '[': return checkTrailing(array(), c);
default: return checkTrailing(value(), c);
}
}
function legacyRootValue() {
// Braces for the root object are optional
white();
var c = keepComments ? getComment(1) : null;
switch (ch) {
case '{': return checkTrailing(object(), c);
case '[': return checkTrailing(array(), c);
}
try {
// assume we have a root object without braces
return checkTrailing(object(true), c);
} catch (e) {
// test if we are dealing with a single JSON value instead (true/false/null/num/"")
resetAt();
try { return checkTrailing(value(), c); }
catch (e2) { throw e; } // throw original error
}
}
if (typeof source!=="string") throw new Error("source is not a string");
var dsfDef = null;
var legacyRoot = true;
if (opt && typeof opt === 'object') {
keepComments = opt.keepWsc;
dsfDef = opt.dsf;
legacyRoot = opt.legacyRoot !== false; // default true
}
runDsf = dsf.loadDsf(dsfDef, "parse");
text = source;
resetAt();
return legacyRoot ? legacyRootValue() : rootValue();
};