UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

66 lines (65 loc) 2.78 kB
// Credit to (adopted from): https://github.com/sindresorhus/slugify/ export function _slugify(s, opt = {}) { opt = { separator: '-', lowercase: true, decamelize: true, preserveCharacters: [], ...opt, }; if (opt.decamelize) { s = decamelize(s); } const patternSlug = buildPatternSlug(opt); if (opt.lowercase) { s = s.toLowerCase(); } // based on https://stackoverflow.com/a/23633850/4919972 // Combining Diacritical Marks // https://www.unicode.org/charts/PDF/U0300.pdf s = s.normalize('NFKD').replaceAll(/[\u0300-\u036F]/g, ''); // Detect contractions/possessives by looking for any word followed by a `'t` // or `'s` in isolation and then remove it. s = s.replaceAll(/([a-zA-Z\d]+)'([ts])(\s|$)/g, '$1$2$3'); s = s.replace(patternSlug, opt.separator); s = s.replaceAll('\\', ''); if (opt.separator) { s = removeMootSeparators(s, opt.separator); } return s; } function buildPatternSlug(options) { let negationSetPattern = String.raw `a-z\d`; negationSetPattern += options.lowercase ? '' : 'A-Z'; if (options.preserveCharacters.length > 0) { for (const character of options.preserveCharacters) { if (character === options.separator) { throw new Error(`The separator character \`${options.separator}\` cannot be included in preserved characters: ${options.preserveCharacters}`); } negationSetPattern += escapeStringRegexp(character); } } return new RegExp(`[^${negationSetPattern}]+`, 'g'); } function removeMootSeparators(s, separator) { const escapedSeparator = escapeStringRegexp(separator); return s .replaceAll(new RegExp(`${escapedSeparator}{2,}`, 'g'), separator) .replaceAll(new RegExp(`^${escapedSeparator}|${escapedSeparator}$`, 'g'), ''); } function decamelize(s) { return (s // Separate capitalized words. .replaceAll(/([A-Z]{2,})(\d+)/g, '$1 $2') .replaceAll(/([a-z\d]+)([A-Z]{2,})/g, '$1 $2') .replaceAll(/([a-z\d])([A-Z])/g, '$1 $2') // `[a-rt-z]` matches all lowercase characters except `s`. // This avoids matching plural acronyms like `APIs`. .replaceAll(/([A-Z]+)([A-Z][a-rt-z\d]+)/g, '$1 $2')); } // based on: https://github.com/sindresorhus/escape-string-regexp/ function escapeStringRegexp(s) { // Escape characters with special meaning either inside or outside character sets. // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar. return s.replaceAll(/[|\\{}()[\]^$+*?.]/g, String.raw `\$&`).replaceAll('-', String.raw `\x2d`); }