UNPKG

custom-ident

Version:
84 lines 2.54 kB
export class CustomIdentError extends Error { constructor(message) { super(message); this.name = "CustomIdentError"; } } /** * Turns a list of values into a CSS <custom-ident>. * Escapes invalid characters. * * @warning Spaces are mapped to hyphens. * * @example * ```ts * import { customIdent } from "custom-ident"; * * const result = customIdent("my", "custom", "ident"); * console.log(result); // "my-custom-ident" * * @param args - The values to be concatenated into a custom-ident. * @returns A string representing the custom-ident. */ export function customIdent(...args) { let result = customIdentWithPotentiallyInvalidFirstChar(...args); // > the first character must not be a decimal digit, // > nor a hyphen (-) followed by a decimal digit. if (/^[0-9]/.test(result) || /^-([0-9])/.test(result)) { result = "c" + result; } if (result.length === 0) { throw new CustomIdentError("customIdent must not be empty"); } return result; } function customIdentWithPotentiallyInvalidFirstChar(...args) { let parts = []; for (const arg of args) { if (Array.isArray(arg)) { parts.push(customIdentWithPotentiallyInvalidFirstChar(...arg)); } else if (typeof arg === "object" && arg !== null) { const part = Object.entries(arg) .toSorted(([a], [b]) => a.charCodeAt(0) - b.charCodeAt(0)) .filter(([, value]) => value) .map(([key]) => escapeValue(key)) .filter((key) => key.length > 0) .join("_"); if (part.length > 0) { parts.push(part); } } else { const part = escapeValue(arg); if (part.length > 0) { parts.push(part); } } } return parts.join("_"); } function escapeValue(value) { const valueString = String(value); const chars = valueString.split(""); let result = ""; for (const char of chars) { if (isValidCustomIdentCharacter(char)) { result += char; } else if (char === " ") { result += "_"; } else if ([".", "?"].includes(char)) { result += `\\${char}`; } else { result += `\\${char.charCodeAt(0).toString(16)}`; } } return result; } function isValidCustomIdentCharacter(char) { return /^[a-zA-Z0-9-_]/.test(char); } //# sourceMappingURL=index.js.map