298 lines
8.6 KiB
JavaScript
298 lines
8.6 KiB
JavaScript
|
/*!
|
||
|
* @intlify/message-resolver v9.1.9
|
||
|
* (c) 2021 kazuya kawaguchi
|
||
|
* Released under the MIT License.
|
||
|
*/
|
||
|
/**
|
||
|
* Original Utilities
|
||
|
* written by kazuya kawaguchi
|
||
|
*/
|
||
|
if ((process.env.NODE_ENV !== 'production')) ;
|
||
|
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
||
|
function hasOwn(obj, key) {
|
||
|
return hasOwnProperty.call(obj, key);
|
||
|
}
|
||
|
const isObject = (val) => // eslint-disable-line
|
||
|
val !== null && typeof val === 'object';
|
||
|
|
||
|
const pathStateMachine = [];
|
||
|
pathStateMachine[0 /* BEFORE_PATH */] = {
|
||
|
["w" /* WORKSPACE */]: [0 /* BEFORE_PATH */],
|
||
|
["i" /* IDENT */]: [3 /* IN_IDENT */, 0 /* APPEND */],
|
||
|
["[" /* LEFT_BRACKET */]: [4 /* IN_SUB_PATH */],
|
||
|
["o" /* END_OF_FAIL */]: [7 /* AFTER_PATH */]
|
||
|
};
|
||
|
pathStateMachine[1 /* IN_PATH */] = {
|
||
|
["w" /* WORKSPACE */]: [1 /* IN_PATH */],
|
||
|
["." /* DOT */]: [2 /* BEFORE_IDENT */],
|
||
|
["[" /* LEFT_BRACKET */]: [4 /* IN_SUB_PATH */],
|
||
|
["o" /* END_OF_FAIL */]: [7 /* AFTER_PATH */]
|
||
|
};
|
||
|
pathStateMachine[2 /* BEFORE_IDENT */] = {
|
||
|
["w" /* WORKSPACE */]: [2 /* BEFORE_IDENT */],
|
||
|
["i" /* IDENT */]: [3 /* IN_IDENT */, 0 /* APPEND */],
|
||
|
["0" /* ZERO */]: [3 /* IN_IDENT */, 0 /* APPEND */]
|
||
|
};
|
||
|
pathStateMachine[3 /* IN_IDENT */] = {
|
||
|
["i" /* IDENT */]: [3 /* IN_IDENT */, 0 /* APPEND */],
|
||
|
["0" /* ZERO */]: [3 /* IN_IDENT */, 0 /* APPEND */],
|
||
|
["w" /* WORKSPACE */]: [1 /* IN_PATH */, 1 /* PUSH */],
|
||
|
["." /* DOT */]: [2 /* BEFORE_IDENT */, 1 /* PUSH */],
|
||
|
["[" /* LEFT_BRACKET */]: [4 /* IN_SUB_PATH */, 1 /* PUSH */],
|
||
|
["o" /* END_OF_FAIL */]: [7 /* AFTER_PATH */, 1 /* PUSH */]
|
||
|
};
|
||
|
pathStateMachine[4 /* IN_SUB_PATH */] = {
|
||
|
["'" /* SINGLE_QUOTE */]: [5 /* IN_SINGLE_QUOTE */, 0 /* APPEND */],
|
||
|
["\"" /* DOUBLE_QUOTE */]: [6 /* IN_DOUBLE_QUOTE */, 0 /* APPEND */],
|
||
|
["[" /* LEFT_BRACKET */]: [
|
||
|
4 /* IN_SUB_PATH */,
|
||
|
2 /* INC_SUB_PATH_DEPTH */
|
||
|
],
|
||
|
["]" /* RIGHT_BRACKET */]: [1 /* IN_PATH */, 3 /* PUSH_SUB_PATH */],
|
||
|
["o" /* END_OF_FAIL */]: 8 /* ERROR */,
|
||
|
["l" /* ELSE */]: [4 /* IN_SUB_PATH */, 0 /* APPEND */]
|
||
|
};
|
||
|
pathStateMachine[5 /* IN_SINGLE_QUOTE */] = {
|
||
|
["'" /* SINGLE_QUOTE */]: [4 /* IN_SUB_PATH */, 0 /* APPEND */],
|
||
|
["o" /* END_OF_FAIL */]: 8 /* ERROR */,
|
||
|
["l" /* ELSE */]: [5 /* IN_SINGLE_QUOTE */, 0 /* APPEND */]
|
||
|
};
|
||
|
pathStateMachine[6 /* IN_DOUBLE_QUOTE */] = {
|
||
|
["\"" /* DOUBLE_QUOTE */]: [4 /* IN_SUB_PATH */, 0 /* APPEND */],
|
||
|
["o" /* END_OF_FAIL */]: 8 /* ERROR */,
|
||
|
["l" /* ELSE */]: [6 /* IN_DOUBLE_QUOTE */, 0 /* APPEND */]
|
||
|
};
|
||
|
/**
|
||
|
* Check if an expression is a literal value.
|
||
|
*/
|
||
|
const literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
|
||
|
function isLiteral(exp) {
|
||
|
return literalValueRE.test(exp);
|
||
|
}
|
||
|
/**
|
||
|
* Strip quotes from a string
|
||
|
*/
|
||
|
function stripQuotes(str) {
|
||
|
const a = str.charCodeAt(0);
|
||
|
const b = str.charCodeAt(str.length - 1);
|
||
|
return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str;
|
||
|
}
|
||
|
/**
|
||
|
* Determine the type of a character in a keypath.
|
||
|
*/
|
||
|
function getPathCharType(ch) {
|
||
|
if (ch === undefined || ch === null) {
|
||
|
return "o" /* END_OF_FAIL */;
|
||
|
}
|
||
|
const code = ch.charCodeAt(0);
|
||
|
switch (code) {
|
||
|
case 0x5b: // [
|
||
|
case 0x5d: // ]
|
||
|
case 0x2e: // .
|
||
|
case 0x22: // "
|
||
|
case 0x27: // '
|
||
|
return ch;
|
||
|
case 0x5f: // _
|
||
|
case 0x24: // $
|
||
|
case 0x2d: // -
|
||
|
return "i" /* IDENT */;
|
||
|
case 0x09: // Tab (HT)
|
||
|
case 0x0a: // Newline (LF)
|
||
|
case 0x0d: // Return (CR)
|
||
|
case 0xa0: // No-break space (NBSP)
|
||
|
case 0xfeff: // Byte Order Mark (BOM)
|
||
|
case 0x2028: // Line Separator (LS)
|
||
|
case 0x2029: // Paragraph Separator (PS)
|
||
|
return "w" /* WORKSPACE */;
|
||
|
}
|
||
|
return "i" /* IDENT */;
|
||
|
}
|
||
|
/**
|
||
|
* Format a subPath, return its plain form if it is
|
||
|
* a literal string or number. Otherwise prepend the
|
||
|
* dynamic indicator (*).
|
||
|
*/
|
||
|
function formatSubPath(path) {
|
||
|
const trimmed = path.trim();
|
||
|
// invalid leading 0
|
||
|
if (path.charAt(0) === '0' && isNaN(parseInt(path))) {
|
||
|
return false;
|
||
|
}
|
||
|
return isLiteral(trimmed)
|
||
|
? stripQuotes(trimmed)
|
||
|
: "*" /* ASTARISK */ + trimmed;
|
||
|
}
|
||
|
/**
|
||
|
* Parse a string path into an array of segments
|
||
|
*/
|
||
|
function parse(path) {
|
||
|
const keys = [];
|
||
|
let index = -1;
|
||
|
let mode = 0 /* BEFORE_PATH */;
|
||
|
let subPathDepth = 0;
|
||
|
let c;
|
||
|
let key; // eslint-disable-line
|
||
|
let newChar;
|
||
|
let type;
|
||
|
let transition;
|
||
|
let action;
|
||
|
let typeMap;
|
||
|
const actions = [];
|
||
|
actions[0 /* APPEND */] = () => {
|
||
|
if (key === undefined) {
|
||
|
key = newChar;
|
||
|
}
|
||
|
else {
|
||
|
key += newChar;
|
||
|
}
|
||
|
};
|
||
|
actions[1 /* PUSH */] = () => {
|
||
|
if (key !== undefined) {
|
||
|
keys.push(key);
|
||
|
key = undefined;
|
||
|
}
|
||
|
};
|
||
|
actions[2 /* INC_SUB_PATH_DEPTH */] = () => {
|
||
|
actions[0 /* APPEND */]();
|
||
|
subPathDepth++;
|
||
|
};
|
||
|
actions[3 /* PUSH_SUB_PATH */] = () => {
|
||
|
if (subPathDepth > 0) {
|
||
|
subPathDepth--;
|
||
|
mode = 4 /* IN_SUB_PATH */;
|
||
|
actions[0 /* APPEND */]();
|
||
|
}
|
||
|
else {
|
||
|
subPathDepth = 0;
|
||
|
if (key === undefined) {
|
||
|
return false;
|
||
|
}
|
||
|
key = formatSubPath(key);
|
||
|
if (key === false) {
|
||
|
return false;
|
||
|
}
|
||
|
else {
|
||
|
actions[1 /* PUSH */]();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
function maybeUnescapeQuote() {
|
||
|
const nextChar = path[index + 1];
|
||
|
if ((mode === 5 /* IN_SINGLE_QUOTE */ &&
|
||
|
nextChar === "'" /* SINGLE_QUOTE */) ||
|
||
|
(mode === 6 /* IN_DOUBLE_QUOTE */ &&
|
||
|
nextChar === "\"" /* DOUBLE_QUOTE */)) {
|
||
|
index++;
|
||
|
newChar = '\\' + nextChar;
|
||
|
actions[0 /* APPEND */]();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
while (mode !== null) {
|
||
|
index++;
|
||
|
c = path[index];
|
||
|
if (c === '\\' && maybeUnescapeQuote()) {
|
||
|
continue;
|
||
|
}
|
||
|
type = getPathCharType(c);
|
||
|
typeMap = pathStateMachine[mode];
|
||
|
transition = typeMap[type] || typeMap["l" /* ELSE */] || 8 /* ERROR */;
|
||
|
// check parse error
|
||
|
if (transition === 8 /* ERROR */) {
|
||
|
return;
|
||
|
}
|
||
|
mode = transition[0];
|
||
|
if (transition[1] !== undefined) {
|
||
|
action = actions[transition[1]];
|
||
|
if (action) {
|
||
|
newChar = c;
|
||
|
if (action() === false) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// check parse finish
|
||
|
if (mode === 7 /* AFTER_PATH */) {
|
||
|
return keys;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// path token cache
|
||
|
const cache = new Map();
|
||
|
function resolveValue(obj, path) {
|
||
|
// check object
|
||
|
if (!isObject(obj)) {
|
||
|
return null;
|
||
|
}
|
||
|
// parse path
|
||
|
let hit = cache.get(path);
|
||
|
if (!hit) {
|
||
|
hit = parse(path);
|
||
|
if (hit) {
|
||
|
cache.set(path, hit);
|
||
|
}
|
||
|
}
|
||
|
// check hit
|
||
|
if (!hit) {
|
||
|
return null;
|
||
|
}
|
||
|
// resolve path value
|
||
|
const len = hit.length;
|
||
|
let last = obj;
|
||
|
let i = 0;
|
||
|
while (i < len) {
|
||
|
const val = last[hit[i]];
|
||
|
if (val === undefined) {
|
||
|
return null;
|
||
|
}
|
||
|
last = val;
|
||
|
i++;
|
||
|
}
|
||
|
return last;
|
||
|
}
|
||
|
/**
|
||
|
* Transform flat json in obj to normal json in obj
|
||
|
*/
|
||
|
function handleFlatJson(obj) {
|
||
|
// check obj
|
||
|
if (!isObject(obj)) {
|
||
|
return obj;
|
||
|
}
|
||
|
for (const key in obj) {
|
||
|
// check key
|
||
|
if (!hasOwn(obj, key)) {
|
||
|
continue;
|
||
|
}
|
||
|
// handle for normal json
|
||
|
if (!key.includes("." /* DOT */)) {
|
||
|
// recursive process value if value is also a object
|
||
|
if (isObject(obj[key])) {
|
||
|
handleFlatJson(obj[key]);
|
||
|
}
|
||
|
}
|
||
|
// handle for flat json, transform to normal json
|
||
|
else {
|
||
|
// go to the last object
|
||
|
const subKeys = key.split("." /* DOT */);
|
||
|
const lastIndex = subKeys.length - 1;
|
||
|
let currentObj = obj;
|
||
|
for (let i = 0; i < lastIndex; i++) {
|
||
|
if (!(subKeys[i] in currentObj)) {
|
||
|
currentObj[subKeys[i]] = {};
|
||
|
}
|
||
|
currentObj = currentObj[subKeys[i]];
|
||
|
}
|
||
|
// update last object value, delete old property
|
||
|
currentObj[subKeys[lastIndex]] = obj[key];
|
||
|
delete obj[key];
|
||
|
// recursive process value if value is also a object
|
||
|
if (isObject(currentObj[subKeys[lastIndex]])) {
|
||
|
handleFlatJson(currentObj[subKeys[lastIndex]]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
export { handleFlatJson, parse, resolveValue };
|