Son CV dans un terminal web en Javascript! https://terminal-cv.gregandev.fr
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

466 lines
11 KiB

'use strict';
var escapedChars = {
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
'"': '"',
'/': '/',
'\\': '\\'
};
var A_CODE = 'a'.charCodeAt();
exports.parse = function (source, _, options) {
var pointers = {};
var line = 0;
var column = 0;
var pos = 0;
var bigint = options && options.bigint && typeof BigInt != 'undefined';
return {
data: _parse('', true),
pointers: pointers
};
function _parse(ptr, topLevel) {
whitespace();
var data;
map(ptr, 'value');
var char = getChar();
switch (char) {
case 't': read('rue'); data = true; break;
case 'f': read('alse'); data = false; break;
case 'n': read('ull'); data = null; break;
case '"': data = parseString(); break;
case '[': data = parseArray(ptr); break;
case '{': data = parseObject(ptr); break;
default:
backChar();
if ('-0123456789'.indexOf(char) >= 0)
data = parseNumber();
else
unexpectedToken();
}
map(ptr, 'valueEnd');
whitespace();
if (topLevel && pos < source.length) unexpectedToken();
return data;
}
function whitespace() {
loop:
while (pos < source.length) {
switch (source[pos]) {
case ' ': column++; break;
case '\t': column += 4; break;
case '\r': column = 0; break;
case '\n': column = 0; line++; break;
default: break loop;
}
pos++;
}
}
function parseString() {
var str = '';
var char;
while (true) {
char = getChar();
if (char == '"') {
break;
} else if (char == '\\') {
char = getChar();
if (char in escapedChars)
str += escapedChars[char];
else if (char == 'u')
str += getCharCode();
else
wasUnexpectedToken();
} else {
str += char;
}
}
return str;
}
function parseNumber() {
var numStr = '';
var integer = true;
if (source[pos] == '-') numStr += getChar();
numStr += source[pos] == '0'
? getChar()
: getDigits();
if (source[pos] == '.') {
numStr += getChar() + getDigits();
integer = false;
}
if (source[pos] == 'e' || source[pos] == 'E') {
numStr += getChar();
if (source[pos] == '+' || source[pos] == '-') numStr += getChar();
numStr += getDigits();
integer = false;
}
var result = +numStr;
return bigint && integer && (result > Number.MAX_SAFE_INTEGER || result < Number.MIN_SAFE_INTEGER)
? BigInt(numStr)
: result;
}
function parseArray(ptr) {
whitespace();
var arr = [];
var i = 0;
if (getChar() == ']') return arr;
backChar();
while (true) {
var itemPtr = ptr + '/' + i;
arr.push(_parse(itemPtr));
whitespace();
var char = getChar();
if (char == ']') break;
if (char != ',') wasUnexpectedToken();
whitespace();
i++;
}
return arr;
}
function parseObject(ptr) {
whitespace();
var obj = {};
if (getChar() == '}') return obj;
backChar();
while (true) {
var loc = getLoc();
if (getChar() != '"') wasUnexpectedToken();
var key = parseString();
var propPtr = ptr + '/' + escapeJsonPointer(key);
mapLoc(propPtr, 'key', loc);
map(propPtr, 'keyEnd');
whitespace();
if (getChar() != ':') wasUnexpectedToken();
whitespace();
obj[key] = _parse(propPtr);
whitespace();
var char = getChar();
if (char == '}') break;
if (char != ',') wasUnexpectedToken();
whitespace();
}
return obj;
}
function read(str) {
for (var i=0; i<str.length; i++)
if (getChar() !== str[i]) wasUnexpectedToken();
}
function getChar() {
checkUnexpectedEnd();
var char = source[pos];
pos++;
column++; // new line?
return char;
}
function backChar() {
pos--;
column--;
}
function getCharCode() {
var count = 4;
var code = 0;
while (count--) {
code <<= 4;
var char = getChar().toLowerCase();
if (char >= 'a' && char <= 'f')
code += char.charCodeAt() - A_CODE + 10;
else if (char >= '0' && char <= '9')
code += +char;
else
wasUnexpectedToken();
}
return String.fromCharCode(code);
}
function getDigits() {
var digits = '';
while (source[pos] >= '0' && source[pos] <= '9')
digits += getChar();
if (digits.length) return digits;
checkUnexpectedEnd();
unexpectedToken();
}
function map(ptr, prop) {
mapLoc(ptr, prop, getLoc());
}
function mapLoc(ptr, prop, loc) {
pointers[ptr] = pointers[ptr] || {};
pointers[ptr][prop] = loc;
}
function getLoc() {
return {
line: line,
column: column,
pos: pos
};
}
function unexpectedToken() {
throw new SyntaxError('Unexpected token ' + source[pos] + ' in JSON at position ' + pos);
}
function wasUnexpectedToken() {
backChar();
unexpectedToken();
}
function checkUnexpectedEnd() {
if (pos >= source.length)
throw new SyntaxError('Unexpected end of JSON input');
}
};
exports.stringify = function (data, _, options) {
if (!validType(data)) return;
var wsLine = 0;
var wsPos, wsColumn;
var whitespace = typeof options == 'object'
? options.space
: options;
switch (typeof whitespace) {
case 'number':
var len = whitespace > 10
? 10
: whitespace < 0
? 0
: Math.floor(whitespace);
whitespace = len && repeat(len, ' ');
wsPos = len;
wsColumn = len;
break;
case 'string':
whitespace = whitespace.slice(0, 10);
wsPos = 0;
wsColumn = 0;
for (var j=0; j<whitespace.length; j++) {
var char = whitespace[j];
switch (char) {
case ' ': wsColumn++; break;
case '\t': wsColumn += 4; break;
case '\r': wsColumn = 0; break;
case '\n': wsColumn = 0; wsLine++; break;
default: throw new Error('whitespace characters not allowed in JSON');
}
wsPos++;
}
break;
default:
whitespace = undefined;
}
var json = '';
var pointers = {};
var line = 0;
var column = 0;
var pos = 0;
var es6 = options && options.es6 && typeof Map == 'function';
_stringify(data, 0, '');
return {
json: json,
pointers: pointers
};
function _stringify(_data, lvl, ptr) {
map(ptr, 'value');
switch (typeof _data) {
case 'number':
case 'bigint':
case 'boolean':
out('' + _data); break;
case 'string':
out(quoted(_data)); break;
case 'object':
if (_data === null) {
out('null');
} else if (typeof _data.toJSON == 'function') {
out(quoted(_data.toJSON()));
} else if (Array.isArray(_data)) {
stringifyArray();
} else if (es6) {
if (_data.constructor.BYTES_PER_ELEMENT)
stringifyArray();
else if (_data instanceof Map)
stringifyMapSet();
else if (_data instanceof Set)
stringifyMapSet(true);
else
stringifyObject();
} else {
stringifyObject();
}
}
map(ptr, 'valueEnd');
function stringifyArray() {
if (_data.length) {
out('[');
var itemLvl = lvl + 1;
for (var i=0; i<_data.length; i++) {
if (i) out(',');
indent(itemLvl);
var item = validType(_data[i]) ? _data[i] : null;
var itemPtr = ptr + '/' + i;
_stringify(item, itemLvl, itemPtr);
}
indent(lvl);
out(']');
} else {
out('[]');
}
}
function stringifyObject() {
var keys = Object.keys(_data);
if (keys.length) {
out('{');
var propLvl = lvl + 1;
for (var i=0; i<keys.length; i++) {
var key = keys[i];
var value = _data[key];
if (validType(value)) {
if (i) out(',');
var propPtr = ptr + '/' + escapeJsonPointer(key);
indent(propLvl);
map(propPtr, 'key');
out(quoted(key));
map(propPtr, 'keyEnd');
out(':');
if (whitespace) out(' ');
_stringify(value, propLvl, propPtr);
}
}
indent(lvl);
out('}');
} else {
out('{}');
}
}
function stringifyMapSet(isSet) {
if (_data.size) {
out('{');
var propLvl = lvl + 1;
var first = true;
var entries = _data.entries();
var entry = entries.next();
while (!entry.done) {
var item = entry.value;
var key = item[0];
var value = isSet ? true : item[1];
if (validType(value)) {
if (!first) out(',');
first = false;
var propPtr = ptr + '/' + escapeJsonPointer(key);
indent(propLvl);
map(propPtr, 'key');
out(quoted(key));
map(propPtr, 'keyEnd');
out(':');
if (whitespace) out(' ');
_stringify(value, propLvl, propPtr);
}
entry = entries.next();
}
indent(lvl);
out('}');
} else {
out('{}');
}
}
}
function out(str) {
column += str.length;
pos += str.length;
json += str;
}
function indent(lvl) {
if (whitespace) {
json += '\n' + repeat(lvl, whitespace);
line++;
column = 0;
while (lvl--) {
if (wsLine) {
line += wsLine;
column = wsColumn;
} else {
column += wsColumn;
}
pos += wsPos;
}
pos += 1; // \n character
}
}
function map(ptr, prop) {
pointers[ptr] = pointers[ptr] || {};
pointers[ptr][prop] = {
line: line,
column: column,
pos: pos
};
}
function repeat(n, str) {
return Array(n + 1).join(str);
}
};
var VALID_TYPES = ['number', 'bigint', 'boolean', 'string', 'object'];
function validType(data) {
return VALID_TYPES.indexOf(typeof data) >= 0;
}
var ESC_QUOTE = /"|\\/g;
var ESC_B = /[\b]/g;
var ESC_F = /\f/g;
var ESC_N = /\n/g;
var ESC_R = /\r/g;
var ESC_T = /\t/g;
function quoted(str) {
str = str.replace(ESC_QUOTE, '\\$&')
.replace(ESC_F, '\\f')
.replace(ESC_B, '\\b')
.replace(ESC_N, '\\n')
.replace(ESC_R, '\\r')
.replace(ESC_T, '\\t');
return '"' + str + '"';
}
var ESC_0 = /~/g;
var ESC_1 = /\//g;
function escapeJsonPointer(str) {
return str.replace(ESC_0, '~0')
.replace(ESC_1, '~1');
}