AK-21/Graphite-Industrial-Intelligence
0
1/**2 * @typedef CoreOptions3 * @property {ReadonlyArray<string>} [subset=[]]4 * Whether to only escape the given subset of characters.5 * @property {boolean} [escapeOnly=false]6 * Whether to only escape possibly dangerous characters.7 * Those characters are `"`, `&`, `'`, `<`, `>`, and `` ` ``.8 *9 * @typedef FormatOptions10 * @property {(code: number, next: number, options: CoreWithFormatOptions) => string} format11 * Format strategy.12 *13 * @typedef {CoreOptions & FormatOptions & import('./util/format-smart.js').FormatSmartOptions} CoreWithFormatOptions14 */15 16const defaultSubsetRegex = /["&'<>`]/g17const surrogatePairsRegex = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g18const controlCharactersRegex =19 // eslint-disable-next-line no-control-regex, unicorn/no-hex-escape20 /[\x01-\t\v\f\x0E-\x1F\x7F\x81\x8D\x8F\x90\x9D\xA0-\uFFFF]/g21const regexEscapeRegex = /[|\\{}()[\]^$+*?.]/g22 23/** @type {WeakMap<ReadonlyArray<string>, RegExp>} */24const subsetToRegexCache = new WeakMap()25 26/**27 * Encode certain characters in `value`.28 *29 * @param {string} value30 * @param {CoreWithFormatOptions} options31 * @returns {string}32 */33export function core(value, options) {34 value = value.replace(35 options.subset36 ? charactersToExpressionCached(options.subset)37 : defaultSubsetRegex,38 basic39 )40 41 if (options.subset || options.escapeOnly) {42 return value43 }44 45 return (46 value47 // Surrogate pairs.48 .replace(surrogatePairsRegex, surrogate)49 // BMP control characters (C0 except for LF, CR, SP; DEL; and some more50 // non-ASCII ones).51 .replace(controlCharactersRegex, basic)52 )53 54 /**55 * @param {string} pair56 * @param {number} index57 * @param {string} all58 */59 function surrogate(pair, index, all) {60 return options.format(61 (pair.charCodeAt(0) - 0xd800) * 0x400 +62 pair.charCodeAt(1) -63 0xdc00 +64 0x10000,65 all.charCodeAt(index + 2),66 options67 )68 }69 70 /**71 * @param {string} character72 * @param {number} index73 * @param {string} all74 */75 function basic(character, index, all) {76 return options.format(77 character.charCodeAt(0),78 all.charCodeAt(index + 1),79 options80 )81 }82}83 84/**85 * A wrapper function that caches the result of `charactersToExpression` with a WeakMap.86 * This can improve performance when tooling calls `charactersToExpression` repeatedly87 * with the same subset.88 *89 * @param {ReadonlyArray<string>} subset90 * @returns {RegExp}91 */92function charactersToExpressionCached(subset) {93 let cached = subsetToRegexCache.get(subset)94 95 if (!cached) {96 cached = charactersToExpression(subset)97 subsetToRegexCache.set(subset, cached)98 }99 100 return cached101}102 103/**104 * @param {ReadonlyArray<string>} subset105 * @returns {RegExp}106 */107function charactersToExpression(subset) {108 /** @type {Array<string>} */109 const groups = []110 let index = -1111 112 while (++index < subset.length) {113 groups.push(subset[index].replace(regexEscapeRegex, '\\$&'))114 }115 116 return new RegExp('(?:' + groups.join('|') + ')', 'g')117}118 