|
'use strict'; |
|
|
|
|
|
|
|
const {isArray} = Array; |
|
const {parse: jsonParse} = JSON; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getKey = (str, {s}) => str.replace(/"s(\d+)"/g, (_, $1) => s[$1]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getValue = (str, foreign) => jsonParse( |
|
str.replace(/(\S+?)\s*=/g, '"$1":'), |
|
(_, value) => typeof value === 'string' ? |
|
foreign[value[0]][value.slice(1)] : |
|
value |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getPath = (keys, foreign, entry, asArray) => { |
|
for (let i = 0, {length} = keys, last = length - 1; i < length; i++) { |
|
const key = getKey(keys[i], foreign); |
|
entry = entry[key] || (entry[key] = (asArray && (i === last) ? [] : {})); |
|
if (isArray(entry)) { |
|
if ((i === last) || !entry.length) |
|
entry.push({}); |
|
entry = entry.at(-1); |
|
} |
|
} |
|
return entry; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const mapForeign = (toml, strings, dates) => [ |
|
toml |
|
|
|
.replace( |
|
/(["'])(?:(?=(\\?))\2.)*?\1/g, |
|
value => `"s${strings.push(value.slice(1, -1)) - 1}"` |
|
) |
|
|
|
.replace( |
|
/\d{2,}([:-]\d{2}){2}([ T:-][\dZ:-]+)?/g, |
|
value => `"d${dates.push(new Date(value)) - 1}"` |
|
) |
|
|
|
.replace(/,\s*[\r\n]+/g, ', ') |
|
.replace(/\[\s*[\r\n]+/g, '[') |
|
.replace(/[\r\n]+\s*]/g, ']'), |
|
{s: strings, d: dates} |
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
const parse = toml => { |
|
const [text, foreign] = mapForeign(toml, [], []); |
|
const json = {}; |
|
let entry = json; |
|
for (let line of text.split(/[\r\n]+/)) { |
|
if ((line = line.trim()) && !line.startsWith('#')) { |
|
if (/^(\[+)(.*?)\]+/.test(line)) |
|
entry = getPath(RegExp.$2.trim().split('.'), foreign, json, RegExp.$1 !== '['); |
|
else if (/^(\S+?)\s*=([^#]+)/.test(line)) { |
|
const {$1: key, $2: value} = RegExp; |
|
entry[getKey(key, foreign)] = getValue(value.trim(), foreign); |
|
} |
|
} |
|
} |
|
return json; |
|
}; |
|
|
|
exports.parse = parse; |
|
|
|
|
|
|