UNPKG

@cruncheevos/core

Version:

Parse and generate achievements and leaderboards for RetroAchievements.org

167 lines (166 loc) 4.97 kB
// TODO: figure out typings if possible, Record<X, Y> => Record<Y, X> export function invertObject(obj) { return Object.entries(obj).reduce((prev, cur) => { prev[cur[1]] = cur[0]; return prev; }, {}); } export function capitalizeWord(word) { return word[0].toUpperCase() + word.slice(1); } export function formatNumberAsHex(num, upperCase = false) { let rvalue = Math.abs(num).toString(16); if (upperCase) { rvalue = rvalue.toUpperCase(); } return `${num < 0 ? '-' : ''}0x` + rvalue; } export function eatSymbols(str, ...args) { return str .map((x, i) => { let arg = args[i]; if (typeof arg === 'string') { arg = `"${arg}"`; } else if (typeof arg === 'symbol') { arg = String(arg); } else if (i >= args.length) { arg = ''; } return x + arg; }) .join(''); } export function isObject(val) { return Object.prototype.toString.call(val) === '[object Object]'; } export function isNumber(val, opts = {}) { if (val === null || typeof val === 'symbol' || typeof val === 'boolean' || (typeof val === 'string' && val.trim().length === 0)) { return false; } val = Number(val); if (Number.isNaN(val) || Number.isFinite(val) === false) { return false; } if (opts.isInteger && Number.isInteger(val) === false) { return false; } if (opts.isPositive && val < 0) { return false; } return true; } export function deepFreeze(obj) { for (const key in obj) { const value = obj[key]; if (isObject(value)) { deepFreeze(value); } else if (Array.isArray(value)) { for (const x of value) { if (isObject(x) || Array.isArray(x)) { deepFreeze(x); } } Object.freeze(value); } } return Object.freeze(obj); } export function deepObjectCopy(obj) { const copy = {}; for (const key in obj) { const value = obj[key]; copy[key] = isObject(value) ? deepObjectCopy(value) : value; } return copy; } export function wrappedError(err, message) { const wrappedError = new Error(message); wrappedError.cause = err; return wrappedError; } // based on: https://stackoverflow.com/a/14991797 export function parseCSV(str) { const arr = []; let inQuotes = false; let col = 0; for (let i = 0; i < str.length; i++) { const cur = str[i]; arr[col] = arr[col] || ''; if (inQuotes && cur == '\\' && str[i + 1] == '"') { arr[col] += '"'; i++; continue; } if (cur == '"') { inQuotes = !inQuotes; continue; } if (cur == ':' && !inQuotes) { col++; continue; } arr[col] += cur; } return arr; } export function quoteIfHaveTo(str) { return str.match(/[:"]/g) ? `"${str.replace(/"/g, '\\"')}"` : str; } export const validate = { andNormalizeId(id, propertyName = 'id') { const origId = id; if (typeof id === 'string') { if (id.trim().length === 0) { throw new Error(`expected ${propertyName} as unsigned integer, but got ""`); } id = Number(id); } if (Number.isInteger(id) === false) { throw new Error(`expected ${propertyName} as unsigned integer, but got ` + eatSymbols `${origId}`); } if (id < 0 || id >= Number.MAX_SAFE_INTEGER) { throw new Error(`expected ${propertyName} to be within the range of 0x0 .. 0xFFFFFFFF, but got ` + eatSymbols `${origId}`); } return id; }, string(input, propertyName = 'title') { if (typeof input !== 'string') { throw new Error(`expected ${propertyName} as string, but got ` + eatSymbols `${input}`); } }, nonEmptyString(input, propertyName = 'title') { if (typeof input !== 'string' || input.trim().length === 0) { throw new Error(`expected ${propertyName} as non-empty string, but got ` + eatSymbols `${input}`); } }, }; export function indexToConditionGroupName(index) { return index === 0 ? 'Core' : `Alt ${index}`; } /** * Splits string into numeric chunks, little endian * * @example * stringToNumberLE('abcde') // [ 1684234849, 101 ] * // abcd = 0x64636261 = 1684234849 * // e = 0x65 = 101 */ export function stringToNumberLE(input) { const bytes = new TextEncoder().encode(input); const values = []; for (let i = 0; i < bytes.length; i += 4) { const value = [...bytes.slice(i, i + 4)] .reverse() .map(x => x.toString(16).padStart(2, '0')) .join(''); values.push(parseInt(value, 16)); } return values; }