UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

196 lines (195 loc) 6.1 kB
const ASCII_LOWERCASE = "abcdefghijklmnopqrstuvwxyz"; const ASCII_UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const ASCII_LETTERS = ASCII_LOWERCASE + ASCII_UPPERCASE; const HIGH_SURROGATE_BEGIN = 55296; const HIGH_SURROGATE_END = 56319; const LOW_SURROGATE_BEGIN = 56320; const LOW_SURROGATE_END = 57343; const ZERO_WIDTH_JOINER = 8205; const REGIONAL_INDICATOR_BEGIN = 127462; const REGIONAL_INDICATOR_END = 127487; const FITZPATRICK_MODIFIER_BEGIN = 127995; const FITZPATRICK_MODIFIER_END = 127999; const DIACRITICAL_MARKS_BEGIN = 8400; const DIACRITICAL_MARKS_END = 8447; const VARIATION_MODIFIER_BEGIN = 65024; const VARIATION_MODIFIER_END = 65039; function getCodePointData(string2, i = 0) { const size = string2.length; if (i < 0 || i >= size) { return null; } const first = string2.charCodeAt(i); if (size > 1 && first >= HIGH_SURROGATE_BEGIN && first <= HIGH_SURROGATE_END) { const second = string2.charCodeAt(i + 1); if (second >= LOW_SURROGATE_BEGIN && second <= LOW_SURROGATE_END) { return { code: (first - HIGH_SURROGATE_BEGIN) * 1024 + second - LOW_SURROGATE_BEGIN + 65536, long: true }; } } return { code: first, long: false }; } function isCodeBetween(string2, begin, end) { if (!string2) { return false; } const codeData = getCodePointData(string2); if (codeData) { const code = codeData.code; return code >= begin && code <= end; } return false; } function numCharsToTakeForNextSymbol(string2, index) { if (index === string2.length - 1) { return 1; } if (isCodeBetween(string2[index], HIGH_SURROGATE_BEGIN, HIGH_SURROGATE_END)) { const first = string2.substring(index, index + 2); const second = string2.substring(index + 2, index + 4); if (isCodeBetween(second, FITZPATRICK_MODIFIER_BEGIN, FITZPATRICK_MODIFIER_END) || isCodeBetween(first, REGIONAL_INDICATOR_BEGIN, REGIONAL_INDICATOR_END) && isCodeBetween(second, REGIONAL_INDICATOR_BEGIN, REGIONAL_INDICATOR_END)) { return 4; } if (isCodeBetween(second, VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { return 3; } return 2; } if (isCodeBetween(string2[index + 1], VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { return 2; } return 1; } const string = { /** * All lowercase letters. * * @type {string} */ ASCII_LOWERCASE, /** * All uppercase letters. * * @type {string} */ ASCII_UPPERCASE, /** * All ASCII letters. * * @type {string} */ ASCII_LETTERS, /** * Return a string with \{n\} replaced with the n-th argument. * * @param {string} s - The string to format. * @param {...*} args - All other arguments are substituted into the string. * @returns {string} The formatted string. * @example * const s = pc.string.format("Hello {0}", "world"); * console.log(s); // Prints "Hello world" */ format(s, ...args) { for (let i = 0; i < args.length; i++) { s = s.replace(`{${i}}`, args[i]); } return s; }, /** * Get the code point number for a character in a string. Polyfill for * [`codePointAt`]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt}. * * @param {string} string - The string to get the code point from. * @param {number} [i] - The index in the string. * @returns {number} The code point value for the character in the string. */ getCodePoint(string2, i) { const codePointData = getCodePointData(string2, i); return codePointData && codePointData.code; }, /** * Gets an array of all code points in a string. * * @param {string} string - The string to get code points from. * @returns {number[]} The code points in the string. */ getCodePoints(string2) { if (typeof string2 !== "string") { throw new TypeError("Not a string"); } let i = 0; const arr = []; let codePoint; while (!!(codePoint = getCodePointData(string2, i))) { arr.push(codePoint.code); i += codePoint.long ? 2 : 1; } return arr; }, /** * Gets an array of all grapheme clusters (visible symbols) in a string. This is needed because * some symbols (such as emoji or accented characters) are actually made up of multiple * character codes. See {@link https://mathiasbynens.be/notes/javascript-unicode here} for more * info. * * @param {string} string - The string to break into symbols. * @returns {string[]} The symbols in the string. */ getSymbols(string2) { if (typeof string2 !== "string") { throw new TypeError("Not a string"); } let index = 0; const length = string2.length; const output = []; let take = 0; let ch; while (index < length) { take += numCharsToTakeForNextSymbol(string2, index + take); ch = string2[index + take]; if (isCodeBetween(ch, DIACRITICAL_MARKS_BEGIN, DIACRITICAL_MARKS_END)) { ch = string2[index + take++]; } if (isCodeBetween(ch, VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { ch = string2[index + take++]; } if (ch && ch.charCodeAt(0) === ZERO_WIDTH_JOINER) { ch = string2[index + take++]; continue; } const char = string2.substring(index, index + take); output.push(char); index += take; take = 0; } return output; }, /** * Get the string for a given code point or set of code points. Polyfill for * [`fromCodePoint`]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint}. * * @param {...number} args - The code points to convert to a string. * @returns {string} The converted string. * @ignore */ fromCodePoint(...args) { return args.map((codePoint) => { if (codePoint > 65535) { codePoint -= 65536; return String.fromCharCode( (codePoint >> 10) + 55296, codePoint % 1024 + 56320 ); } return String.fromCharCode(codePoint); }).join(""); } }; export { string };