Files
lucky_shop/stub-app-projects/mp-harmony/entry/scripts/load-json5.js
ZF sun df9d45fc1d refactor(mp-harmony): add HAR dependency checks and debug logs
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
2026-07-30 11:43:25 +08:00

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;