/** * @typedef FormatSmartOptions * @property {boolean} [useNamedReferences=false] * Prefer named character references (`&`) where possible. * @property {boolean} [useShortestReferences=false] * Prefer the shortest possible reference, if that results in less bytes. * **Note**: `useNamedReferences` can be omitted when using `useShortestReferences`. * @property {boolean} [omitOptionalSemicolons=false] * Whether to omit semicolons when possible. * **Note**: This creates what HTML calls “parse errors” but is otherwise still valid HTML — don’t use this except when building a minifier. * Omitting semicolons is possible for certain named and numeric references in some cases. * @property {boolean} [attribute=false] * Create character references which don’t fail in attributes. * **Note**: `attribute` only applies when operating dangerously with * `omitOptionalSemicolons: true`. */ import {toHexadecimal} from './to-hexadecimal.js' import {toDecimal} from './to-decimal.js' import {toNamed} from './to-named.js' /** * Configurable ways to encode a character yielding pretty or small results. * * @param {number} code * @param {number} next * @param {FormatSmartOptions} options * @returns {string} */ export function formatSmart(code, next, options) { let numeric = toHexadecimal(code, next, options.omitOptionalSemicolons) /** @type {string|undefined} */ let named if (options.useNamedReferences || options.useShortestReferences) { named = toNamed( code, next, options.omitOptionalSemicolons, options.attribute ) } // Use the shortest numeric reference when requested. // A simple algorithm would use decimal for all code points under 100, as // those are shorter than hexadecimal: // // * `c` vs `c` (decimal shorter) // * `d` vs `d` (equal) // // However, because we take `next` into consideration when `omit` is used, // And it would be possible that decimals are shorter on bigger values as // well if `next` is hexadecimal but not decimal, we instead compare both. if ( (options.useShortestReferences || !named) && options.useShortestReferences ) { const decimal = toDecimal(code, next, options.omitOptionalSemicolons) if (decimal.length < numeric.length) { numeric = decimal } } return named && (!options.useShortestReferences || named.length < numeric.length) ? named : numeric }