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.
302 lines
8.7 KiB
302 lines
8.7 KiB
/*! |
|
* @intlify/message-resolver v9.1.9 |
|
* (c) 2021 kazuya kawaguchi |
|
* Released under the MIT License. |
|
*/ |
|
'use strict'; |
|
|
|
Object.defineProperty(exports, '__esModule', { value: true }); |
|
|
|
/** |
|
* Original Utilities |
|
* written by kazuya kawaguchi |
|
*/ |
|
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; |
|
} |
|
|
|
exports.handleFlatJson = handleFlatJson; |
|
exports.parse = parse; |
|
exports.resolveValue = resolveValue;
|
|
|