1. add debug logs for diy component lifecycle and data flow 2. add required HAR dependency declarations for mp-harmony entry module 3. add har-deps config, validation script and documentation
144 lines
3.9 KiB
JavaScript
144 lines
3.9 KiB
JavaScript
/**
|
|
* 简单 json5 解析 (支持 // 单行注释, /* 多行注释 *\/, 字符串, 转义)
|
|
* 不支持: 数字下划线, 十六进制等扩展
|
|
*/
|
|
'use strict';
|
|
|
|
function parseJson5(text) {
|
|
let i = 0;
|
|
const len = text.length;
|
|
|
|
function peek() { return text[i]; }
|
|
function next() { return text[i++]; }
|
|
|
|
function skipWsAndComments() {
|
|
while (i < len) {
|
|
const c = text[i];
|
|
if (c === ' ' || c === '\t' || c === '\n' || c === '\r') {
|
|
i++;
|
|
continue;
|
|
}
|
|
if (c === '/' && text[i + 1] === '/') {
|
|
while (i < len && text[i] !== '\n') i++;
|
|
continue;
|
|
}
|
|
if (c === '/' && text[i + 1] === '*') {
|
|
i += 2;
|
|
while (i < len && !(text[i] === '*' && text[i + 1] === '/')) i++;
|
|
i += 2;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
function readString() {
|
|
const quote = next(); // " or '
|
|
let out = '';
|
|
while (i < len) {
|
|
const c = next();
|
|
if (c === '\\') {
|
|
const esc = next();
|
|
switch (esc) {
|
|
case 'n': out += '\n'; break;
|
|
case 't': out += '\t'; break;
|
|
case 'r': out += '\r'; break;
|
|
case '\\': out += '\\'; break;
|
|
case '"': out += '"'; break;
|
|
case "'": out += "'"; break;
|
|
case '/': out += '/'; break;
|
|
case 'b': out += '\b'; break;
|
|
case 'f': out += '\f'; break;
|
|
case 'u': {
|
|
const hex = text.substr(i, 4);
|
|
i += 4;
|
|
out += String.fromCharCode(parseInt(hex, 16));
|
|
break;
|
|
}
|
|
default: out += esc;
|
|
}
|
|
continue;
|
|
}
|
|
if (c === quote) return out;
|
|
out += c;
|
|
}
|
|
throw new Error('unterminated string');
|
|
}
|
|
|
|
function readValue() {
|
|
skipWsAndComments();
|
|
const c = peek();
|
|
if (c === '"' || c === "'") return readString();
|
|
if (c === '{') return readObject();
|
|
if (c === '[') return readArray();
|
|
if (c === 't' || c === 'f') return readBoolOrNull();
|
|
if (c === 'n') return readBoolOrNull();
|
|
if (c === '-' || (c >= '0' && c <= '9')) return readNumber();
|
|
throw new Error(`unexpected char '${c}' at ${i}`);
|
|
}
|
|
|
|
function readObject() {
|
|
next(); // {
|
|
const obj = {};
|
|
while (true) {
|
|
skipWsAndComments();
|
|
if (peek() === '}') { next(); return obj; }
|
|
// key
|
|
let key;
|
|
if (peek() === '"' || peek() === "'") key = readString();
|
|
else {
|
|
// bareword (json5 allows unquoted keys)
|
|
let s = '';
|
|
while (i < len && /[A-Za-z0-9_$-]/.test(text[i])) s += text[i++];
|
|
key = s;
|
|
}
|
|
skipWsAndComments();
|
|
if (next() !== ':') throw new Error(`expected ':' at ${i}`);
|
|
obj[key] = readValue();
|
|
skipWsAndComments();
|
|
const nc = next();
|
|
if (nc === ',') continue;
|
|
if (nc === '}') return obj;
|
|
throw new Error(`expected , or } at ${i}`);
|
|
}
|
|
}
|
|
|
|
function readArray() {
|
|
next(); // [
|
|
const arr = [];
|
|
while (true) {
|
|
skipWsAndComments();
|
|
if (peek() === ']') { next(); return arr; }
|
|
arr.push(readValue());
|
|
skipWsAndComments();
|
|
const nc = next();
|
|
if (nc === ',') continue;
|
|
if (nc === ']') return arr;
|
|
throw new Error(`expected , or ] at ${i}`);
|
|
}
|
|
}
|
|
|
|
function readBoolOrNull() {
|
|
if (text.substr(i, 4) === 'true') { i += 4; return true; }
|
|
if (text.substr(i, 5) === 'false') { i += 5; return false; }
|
|
if (text.substr(i, 4) === 'null') { i += 4; return null; }
|
|
throw new Error(`bad literal at ${i}`);
|
|
}
|
|
|
|
function readNumber() {
|
|
let s = '';
|
|
if (peek() === '-') s += next();
|
|
while (i < len && /[0-9.eE+-]/.test(text[i])) s += next();
|
|
const n = parseFloat(s);
|
|
if (isNaN(n)) throw new Error(`bad number '${s}'`);
|
|
return n;
|
|
}
|
|
|
|
skipWsAndComments();
|
|
const result = readValue();
|
|
skipWsAndComments();
|
|
if (i < len) throw new Error(`trailing chars at ${i}: ${text.substr(i, 30)}`);
|
|
return result;
|
|
}
|
|
|
|
module.exports = parseJson5; |