Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

slug

Package Overview
Dependencies
Maintainers
1
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

slug - npm Package Compare versions

Comparing version 8.0.0 to 9.0.0-beta.1

10

package.json
{
"name": "slug",
"description": "slugifies even utf-8 chars!",
"version": "8.0.0",
"version": "9.0.0-beta.1",
"homepage": "https://github.com/Trott/slug",
"author": "dodo (https://github.com/dodo)",
"type": "module",
"repository": {

@@ -13,2 +14,5 @@ "type": "git",

"main": "slug.js",
"files": [
"slug.js"
],
"keywords": [

@@ -24,3 +28,3 @@ "slugify",

"scripts": {
"test": "standard && mocha test/*.mjs && nyc --reporter none mocha test/**/*.js && karma start --single-run --browsers ChromeHeadless,FirefoxHeadless .karma.config.js && nyc report --reporter=text --reporter=html && nyc check-coverage --lines 100 --branches 100 --statements 100 --functions 100",
"test": "standard && c8 --100 mocha test/**/*.js && karma start --single-run --browsers ChromeHeadless,FirefoxHeadless .karma.config.cjs",
"benchmark": "node benchmark/benchmark.js"

@@ -31,2 +35,3 @@ },

"@semantic-release/git": "^10.0.1",
"c8": "^7.11.2",
"chai": "^4.2.0",

@@ -41,3 +46,2 @@ "karma": "^6.3.19",

"mocha": "^10.0.0",
"nyc": "^15.0.1",
"semantic-release": "^19.0.1",

@@ -44,0 +48,0 @@ "standard": "^17.0.0"

@@ -9,3 +9,3 @@ # [slug](https://github.com/Trott/slug)

- No dependencies
- Works in browser (`window.slug`) and AMD/CommonJS-flavoured module loaders
- Works in the browser or in Node.js

@@ -40,3 +40,3 @@ ```

```javascript
var slug = require('slug')
import slug from 'slug'
var print = console.log.bind(console, '>')

@@ -43,0 +43,0 @@

/* global btoa */
(function (root) {
let base64
let base64
// This function's sole purpose is to help us ignore lone surrogates so that
// malformed strings don't throw in the browser while being processed
// permissively in Node.js. If we didn't care about parity, we could get rid
// of it.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt
function getWholeCharAndI (str, i) {
const code = str.charCodeAt(i)
// This function's sole purpose is to help us ignore lone surrogates so that
// malformed strings don't throw in the browser while being processed
// permissively in Node.js. If we didn't care about parity, we could get rid
// of it.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt
function getWholeCharAndI (str, i) {
const code = str.charCodeAt(i)
// This is a coherence check. `code` should never be `NaN`.
/* istanbul ignore if */
if (isNaN(code)) {
throw new RangeError('Index ' + i + ' out of range for string "' + str + '"; please open an issue at https://github.com/Trott/slug/issues/new')
}
if (code < 0xD800 || code > 0xDFFF) {
return [str.charAt(i), i] // Non-surrogate character, keeping 'i' the same
}
// This is a coherence check. `code` should never be `NaN`.
/* c8 ignore start */
if (isNaN(code)) {
throw new RangeError('Index ' + i + ' out of range for string "' + str + '"; please open an issue at https://github.com/Trott/slug/issues/new')
}
/* c8 ignore stop */
if (code < 0xD800 || code > 0xDFFF) {
return [str.charAt(i), i] // Non-surrogate character, keeping 'i' the same
}
// High surrogate
if (code >= 0xD800 && code <= 0xDBFF) {
if (str.length <= (i + 1)) {
// High surrogate without following low surrogate
return [' ', i]
}
const next = str.charCodeAt(i + 1)
if (next < 0xDC00 || next > 0xDFFF) {
// High surrogate without following low surrogate
return [' ', i]
}
return [str.charAt(i) + str.charAt(i + 1), i + 1]
// High surrogate
if (code >= 0xD800 && code <= 0xDBFF) {
if (str.length <= (i + 1)) {
// High surrogate without following low surrogate
return [' ', i]
}
// Low surrogate (0xDC00 <= code && code <= 0xDFFF)
if (i === 0) {
// Low surrogate without preceding high surrogate
const next = str.charCodeAt(i + 1)
if (next < 0xDC00 || next > 0xDFFF) {
// High surrogate without following low surrogate
return [' ', i]
}
return [str.charAt(i) + str.charAt(i + 1), i + 1]
}
const prev = str.charCodeAt(i - 1)
// Low surrogate (0xDC00 <= code && code <= 0xDFFF)
if (i === 0) {
// Low surrogate without preceding high surrogate
return [' ', i]
}
/* istanbul ignore else */
if (prev < 0xD800 || prev > 0xDBFF) {
// Low surrogate without preceding high surrogate
return [' ', i]
}
const prev = str.charCodeAt(i - 1)
/* istanbul ignore next */
throw new Error('String "' + str + '" reaches code believed to be unreachable; please open an issue at https://github.com/Trott/slug/issues/new')
if (prev < 0xD800 || prev > 0xDBFF) {
// Low surrogate without preceding high surrogate
return [' ', i]
}
/* c8 ignore next */
throw new Error('String "' + str + '" reaches code believed to be unreachable; please open an issue at https://github.com/Trott/slug/issues/new')
}
if (typeof window !== 'undefined') {
if (window.btoa) {
base64 = function (input) {
return btoa(unescape(encodeURIComponent(input)))
}
} else {
// Polyfill for environments that don't have btoa or Buffer class (notably, React Native).
// Based on https://github.com/davidchambers/Base64.js/blob/a121f75bb10c8dd5d557886c4b1069b31258d230/base64.js
base64 = function (input) {
const str = unescape(encodeURIComponent(input + ''))
let output = ''
for (
let block, charCode, idx = 0, map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
str.charAt(idx | 0) || (map = '=', idx % 1);
output += map.charAt(63 & block >> 8 - idx % 1 * 8)
) {
charCode = str.charCodeAt(idx += 3 / 4)
// This is a coherence check. The result of unescape(encodeURIComponent()) should always be
// characters with code points that fit into two bytes.
/* istanbul ignore next */
if (charCode > 0xFF) {
throw new Error("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.")
}
block = block << 8 | charCode
}
return output
}
if (typeof window !== 'undefined') {
if (window.btoa) {
base64 = function (input) {
return btoa(unescape(encodeURIComponent(input)))
}
} else {
// Polyfill for environments that don't have btoa or Buffer class (notably, React Native).
// Based on https://github.com/davidchambers/Base64.js/blob/a121f75bb10c8dd5d557886c4b1069b31258d230/base64.js
base64 = function (input) {
return Buffer.from(input).toString('base64')
const str = unescape(encodeURIComponent(input + ''))
let output = ''
for (
let block, charCode, idx = 0, map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
str.charAt(idx | 0) || (map = '=', idx % 1);
output += map.charAt(63 & block >> 8 - idx % 1 * 8)
) {
charCode = str.charCodeAt(idx += 3 / 4)
// TODO: The if condition may be guaranteed to be false. Verify and
// remove or otherwise write a test to cover it.
/* c8 ignore start */
if (charCode > 0xFF) {
throw new Error("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.")
}
/* c8 ignore stop */
block = block << 8 | charCode
}
return output
}
}
} else {
base64 = function (input) {
return Buffer.from(input).toString('base64')
}
}
function slug (string, opts) {
let result = slugify(string, opts)
const fallback = opts && opts.fallback !== undefined ? opts.fallback : slug.defaults.fallback
// If output is an empty string, try slug for base64 of string.
if (fallback === true && result === '') {
// Get rid of lone surrogates.
let input = ''
for (let i = 0; i < string.length; i++) {
const charAndI = getWholeCharAndI(string, i)
i = charAndI[1]
input += charAndI[0]
}
result = slugify(base64(input), opts)
/* c8 ignore start */
if (typeof Object.assign !== 'function') {
throw new Error('Runtime environment does not support Object.assign()')
}
/* c8 ignore stop */
function slug (string, opts) {
let result = slugify(string, opts)
const fallback = opts && opts.fallback !== undefined ? opts.fallback : slug.defaults.fallback
// If output is an empty string, try slug for base64 of string.
if (fallback === true && result === '') {
// Get rid of lone surrogates.
let input = ''
for (let i = 0; i < string.length; i++) {
const charAndI = getWholeCharAndI(string, i)
i = charAndI[1]
input += charAndI[0]
}
return result
result = slugify(base64(input), opts)
}
return result
}
const locales = {
// http://www.eki.ee/wgrs/rom1_bg.pdf
bg: { Й: 'Y', й: 'y', X: 'H', x: 'h', Ц: 'Ts', ц: 'ts', Щ: 'Sht', щ: 'sht', Ъ: 'A', ъ: 'a', Ь: 'Y', ь: 'y' },
// Need a reference URL for German, although this is pretty well-known.
de: { Ä: 'AE', ä: 'ae', Ö: 'OE', ö: 'oe', Ü: 'UE', ü: 'ue' },
// Need a reference URL for Serbian.
sr: { đ: 'dj', Đ: 'DJ' },
// https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/864314/ROMANIZATION_OF_UKRAINIAN.pdf
uk: { И: 'Y', и: 'y', Й: 'Y', й: 'y', Ц: 'Ts', ц: 'ts', Х: 'Kh', х: 'kh', Щ: 'Shch', щ: 'shch', Г: 'H', г: 'h' }
}
const locales = {
// http://www.eki.ee/wgrs/rom1_bg.pdf
bg: { Й: 'Y', й: 'y', X: 'H', x: 'h', Ц: 'Ts', ц: 'ts', Щ: 'Sht', щ: 'sht', Ъ: 'A', ъ: 'a', Ь: 'Y', ь: 'y' },
// Need a reference URL for German, although this is pretty well-known.
de: { Ä: 'AE', ä: 'ae', Ö: 'OE', ö: 'oe', Ü: 'UE', ü: 'ue' },
// Need a reference URL for Serbian.
sr: { đ: 'dj', Đ: 'DJ' },
// https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/864314/ROMANIZATION_OF_UKRAINIAN.pdf
uk: { И: 'Y', и: 'y', Й: 'Y', й: 'y', Ц: 'Ts', ц: 'ts', Х: 'Kh', х: 'kh', Щ: 'Shch', щ: 'shch', Г: 'H', г: 'h' }
}
let defaultLocale = {}
let defaultLocale = {}
function slugify (string, opts) {
if (typeof string !== 'string') {
throw new Error('slug() requires a string argument, received ' + typeof string)
}
if (typeof opts === 'string') { opts = { replacement: opts } }
opts = opts ? Object.assign({}, opts) : {}
opts.mode = opts.mode || slug.defaults.mode
const defaults = slug.defaults.modes[opts.mode]
const keys = ['replacement', 'multicharmap', 'charmap', 'remove', 'lower', 'trim']
for (let key, i = 0, l = keys.length; i < l; i++) {
key = keys[i]
opts[key] = (key in opts) ? opts[key] : defaults[key]
}
const localeMap = locales[opts.locale] || defaultLocale
function slugify (string, opts) {
if (typeof string !== 'string') {
throw new Error('slug() requires a string argument, received ' + typeof string)
}
if (typeof opts === 'string') { opts = { replacement: opts } }
opts = opts ? Object.assign({}, opts) : {}
opts.mode = opts.mode || slug.defaults.mode
const defaults = slug.defaults.modes[opts.mode]
const keys = ['replacement', 'multicharmap', 'charmap', 'remove', 'lower', 'trim']
for (let key, i = 0, l = keys.length; i < l; i++) {
key = keys[i]
opts[key] = (key in opts) ? opts[key] : defaults[key]
}
const localeMap = locales[opts.locale] || defaultLocale
let lengths = []
for (const key in opts.multicharmap) {
if (!Object.prototype.hasOwnProperty.call(opts.multicharmap, key)) { continue }
let lengths = []
for (const key in opts.multicharmap) {
if (!Object.prototype.hasOwnProperty.call(opts.multicharmap, key)) { continue }
const len = key.length
if (lengths.indexOf(len) === -1) { lengths.push(len) }
}
const len = key.length
if (lengths.indexOf(len) === -1) { lengths.push(len) }
}
// We want to match the longest string if there are multiple matches, so
// sort lengths in descending order.
lengths = lengths.sort(function (a, b) { return b - a })
// We want to match the longest string if there are multiple matches, so
// sort lengths in descending order.
lengths = lengths.sort(function (a, b) { return b - a })
const disallowedChars = opts.mode === 'rfc3986' ? /[^\w\s\-.~]/ : /[^A-Za-z0-9\s]/
const disallowedChars = opts.mode === 'rfc3986' ? /[^\w\s\-.~]/ : /[^A-Za-z0-9\s]/
let result = ''
for (let char, i = 0, l = string.length; i < l; i++) {
char = string[i]
let matchedMultichar = false
for (let j = 0; j < lengths.length; j++) {
const len = lengths[j]
const str = string.substr(i, len)
if (opts.multicharmap[str]) {
i += len - 1
char = opts.multicharmap[str]
matchedMultichar = true
break
}
let result = ''
for (let char, i = 0, l = string.length; i < l; i++) {
char = string[i]
let matchedMultichar = false
for (let j = 0; j < lengths.length; j++) {
const len = lengths[j]
const str = string.substr(i, len)
if (opts.multicharmap[str]) {
i += len - 1
char = opts.multicharmap[str]
matchedMultichar = true
break
}
if (!matchedMultichar) {
if (localeMap[char]) {
char = localeMap[char]
} else if (opts.charmap[char]) {
char = opts.charmap[char].replace(opts.replacement, ' ')
} else if (char.includes(opts.replacement)) {
// preserve the replacement character in case it is excluded by disallowedChars
char = char.replace(opts.replacement, ' ')
} else {
char = char.replace(disallowedChars, '')
}
}
if (!matchedMultichar) {
if (localeMap[char]) {
char = localeMap[char]
} else if (opts.charmap[char]) {
char = opts.charmap[char].replace(opts.replacement, ' ')
} else if (char.includes(opts.replacement)) {
// preserve the replacement character in case it is excluded by disallowedChars
char = char.replace(opts.replacement, ' ')
} else {
char = char.replace(disallowedChars, '')
}
result += char
}
if (opts.remove) {
result = result.replace(opts.remove, '')
}
if (opts.trim) {
result = result.trim()
}
result = result.replace(/\s+/g, opts.replacement) // convert spaces
if (opts.lower) {
result = result.toLowerCase()
}
return result
result += char
}
const initialMulticharmap = {
// multibyte devanagari characters (hindi, sanskrit, etc.)
फ़: 'Fi',
ग़: 'Ghi',
ख़: 'Khi',
क़: 'Qi',
ड़: 'ugDha',
ढ़: 'ugDhha',
य़: 'Yi',
ज़: 'Za',
// hebrew
// Refs: http://www.eki.ee/wgrs/rom1_he.pdf
// Refs: https://en.wikipedia.org/wiki/Niqqud
בִי: 'i',
בֵ: 'e',
בֵי: 'e',
בֶ: 'e',
בַ: 'a',
בָ: 'a',
בֹ: 'o',
וֹ: 'o',
בֻ: 'u',
וּ: 'u',
בּ: 'b',
כּ: 'k',
ךּ: 'k',
פּ: 'p',
שׁ: 'sh',
שׂ: 's',
בְ: 'e',
חֱ: 'e',
חֲ: 'a',
חֳ: 'o',
בִ: 'i'
if (opts.remove) {
result = result.replace(opts.remove, '')
}
// https://github.com/django/django/blob/master/django/contrib/admin/static/admin/js/urlify.js
const initialCharmap = {
// latin
À: 'A',
Á: 'A',
Â: 'A',
Ã: 'A',
Ä: 'A',
Å: 'A',
Æ: 'AE',
Ç: 'C',
È: 'E',
É: 'E',
Ê: 'E',
Ë: 'E',
Ì: 'I',
Í: 'I',
Î: 'I',
Ï: 'I',
Ð: 'D',
Ñ: 'N',
Ò: 'O',
Ó: 'O',
Ô: 'O',
Õ: 'O',
Ö: 'O',
Ő: 'O',
Ø: 'O',
Ō: 'O',
Ù: 'U',
Ú: 'U',
Û: 'U',
Ü: 'U',
Ű: 'U',
Ý: 'Y',
Þ: 'TH',
ß: 'ss',
à: 'a',
á: 'a',
â: 'a',
ã: 'a',
ä: 'a',
å: 'a',
æ: 'ae',
ç: 'c',
è: 'e',
é: 'e',
ê: 'e',
ë: 'e',
ì: 'i',
í: 'i',
î: 'i',
ï: 'i',
ð: 'd',
ñ: 'n',
ò: 'o',
ó: 'o',
ô: 'o',
õ: 'o',
ö: 'o',
ő: 'o',
ø: 'o',
ō: 'o',
Œ: 'OE',
œ: 'oe',
ù: 'u',
ú: 'u',
û: 'u',
ü: 'u',
ű: 'u',
ý: 'y',
þ: 'th',
ÿ: 'y',
ẞ: 'SS',
// greek
α: 'a',
β: 'b',
γ: 'g',
δ: 'd',
ε: 'e',
ζ: 'z',
η: 'h',
θ: '8',
ι: 'i',
κ: 'k',
λ: 'l',
μ: 'm',
ν: 'n',
ξ: '3',
ο: 'o',
π: 'p',
ρ: 'r',
σ: 's',
τ: 't',
υ: 'y',
φ: 'f',
χ: 'x',
ψ: 'ps',
ω: 'w',
ά: 'a',
έ: 'e',
ί: 'i',
ό: 'o',
ύ: 'y',
ή: 'h',
ώ: 'w',
ς: 's',
ϊ: 'i',
ΰ: 'y',
ϋ: 'y',
ΐ: 'i',
Α: 'A',
Β: 'B',
Γ: 'G',
Δ: 'D',
Ε: 'E',
Ζ: 'Z',
Η: 'H',
Θ: '8',
Ι: 'I',
Κ: 'K',
Λ: 'L',
Μ: 'M',
Ν: 'N',
Ξ: '3',
Ο: 'O',
Π: 'P',
Ρ: 'R',
Σ: 'S',
Τ: 'T',
Υ: 'Y',
Φ: 'F',
Χ: 'X',
Ψ: 'PS',
Ω: 'W',
Ά: 'A',
Έ: 'E',
Ί: 'I',
Ό: 'O',
Ύ: 'Y',
Ή: 'H',
Ώ: 'W',
Ϊ: 'I',
Ϋ: 'Y',
// turkish
ş: 's',
Ş: 'S',
ı: 'i',
İ: 'I',
ğ: 'g',
Ğ: 'G',
// russian
а: 'a',
б: 'b',
в: 'v',
г: 'g',
д: 'd',
е: 'e',
ё: 'yo',
ж: 'zh',
з: 'z',
и: 'i',
й: 'j',
к: 'k',
л: 'l',
м: 'm',
н: 'n',
о: 'o',
п: 'p',
р: 'r',
с: 's',
т: 't',
у: 'u',
ф: 'f',
х: 'h',
ц: 'c',
ч: 'ch',
ш: 'sh',
щ: 'sh',
ъ: 'u',
ы: 'y',
ь: '',
э: 'e',
ю: 'yu',
я: 'ya',
А: 'A',
Б: 'B',
В: 'V',
Г: 'G',
Д: 'D',
Е: 'E',
Ё: 'Yo',
Ж: 'Zh',
З: 'Z',
И: 'I',
Й: 'J',
К: 'K',
Л: 'L',
М: 'M',
Н: 'N',
О: 'O',
П: 'P',
Р: 'R',
С: 'S',
Т: 'T',
У: 'U',
Ф: 'F',
Х: 'H',
Ц: 'C',
Ч: 'Ch',
Ш: 'Sh',
Щ: 'Sh',
Ъ: 'U',
Ы: 'Y',
Ь: '',
Э: 'E',
Ю: 'Yu',
Я: 'Ya',
// ukranian
Є: 'Ye',
І: 'I',
Ї: 'Yi',
Ґ: 'G',
є: 'ye',
і: 'i',
ї: 'yi',
ґ: 'g',
// czech
č: 'c',
ď: 'd',
ě: 'e',
ň: 'n',
ř: 'r',
š: 's',
ť: 't',
ů: 'u',
ž: 'z',
Č: 'C',
Ď: 'D',
Ě: 'E',
Ň: 'N',
Ř: 'R',
Š: 'S',
Ť: 'T',
Ů: 'U',
Ž: 'Z',
// slovak
ľ: 'l',
ĺ: 'l',
ŕ: 'r',
Ľ: 'L',
Ĺ: 'L',
Ŕ: 'R',
// polish
ą: 'a',
ć: 'c',
ę: 'e',
ł: 'l',
ń: 'n',
ś: 's',
ź: 'z',
ż: 'z',
Ą: 'A',
Ć: 'C',
Ę: 'E',
Ł: 'L',
Ń: 'N',
Ś: 'S',
Ź: 'Z',
Ż: 'Z',
// latvian
ā: 'a',
ē: 'e',
ģ: 'g',
ī: 'i',
ķ: 'k',
ļ: 'l',
ņ: 'n',
ū: 'u',
Ā: 'A',
Ē: 'E',
Ģ: 'G',
Ī: 'I',
Ķ: 'K',
Ļ: 'L',
Ņ: 'N',
Ū: 'U',
// arabic
أ: 'a',
إ: 'i',
ب: 'b',
ت: 't',
ث: 'th',
ج: 'g',
ح: 'h',
خ: 'kh',
د: 'd',
ذ: 'th',
ر: 'r',
ز: 'z',
س: 's',
ش: 'sh',
ص: 's',
ض: 'd',
ط: 't',
ظ: 'th',
ع: 'aa',
غ: 'gh',
ف: 'f',
ق: 'k',
ك: 'k',
ل: 'l',
م: 'm',
ن: 'n',
ه: 'h',
و: 'o',
ي: 'y',
ء: 'aa',
ة: 'a',
// farsi
آ: 'a',
ا: 'a',
پ: 'p',
ژ: 'zh',
گ: 'g',
چ: 'ch',
ک: 'k',
ی: 'i',
// lithuanian
ė: 'e',
į: 'i',
ų: 'u',
Ė: 'E',
Į: 'I',
Ų: 'U',
// romanian
ț: 't',
Ț: 'T',
ţ: 't',
Ţ: 'T',
ș: 's',
Ș: 'S',
ă: 'a',
Ă: 'A',
// vietnamese
Ạ: 'A',
Ả: 'A',
Ầ: 'A',
Ấ: 'A',
Ậ: 'A',
Ẩ: 'A',
Ẫ: 'A',
Ằ: 'A',
Ắ: 'A',
Ặ: 'A',
Ẳ: 'A',
Ẵ: 'A',
Ẹ: 'E',
Ẻ: 'E',
Ẽ: 'E',
Ề: 'E',
Ế: 'E',
Ệ: 'E',
Ể: 'E',
Ễ: 'E',
Ị: 'I',
Ỉ: 'I',
Ĩ: 'I',
Ọ: 'O',
Ỏ: 'O',
Ồ: 'O',
Ố: 'O',
Ộ: 'O',
Ổ: 'O',
Ỗ: 'O',
Ơ: 'O',
Ờ: 'O',
Ớ: 'O',
Ợ: 'O',
Ở: 'O',
Ỡ: 'O',
Ụ: 'U',
Ủ: 'U',
Ũ: 'U',
Ư: 'U',
Ừ: 'U',
Ứ: 'U',
Ự: 'U',
Ử: 'U',
Ữ: 'U',
Ỳ: 'Y',
Ỵ: 'Y',
Ỷ: 'Y',
Ỹ: 'Y',
Đ: 'D',
ạ: 'a',
ả: 'a',
ầ: 'a',
ấ: 'a',
ậ: 'a',
ẩ: 'a',
ẫ: 'a',
ằ: 'a',
ắ: 'a',
ặ: 'a',
ẳ: 'a',
ẵ: 'a',
ẹ: 'e',
ẻ: 'e',
ẽ: 'e',
ề: 'e',
ế: 'e',
ệ: 'e',
ể: 'e',
ễ: 'e',
ị: 'i',
ỉ: 'i',
ĩ: 'i',
ọ: 'o',
ỏ: 'o',
ồ: 'o',
ố: 'o',
ộ: 'o',
ổ: 'o',
ỗ: 'o',
ơ: 'o',
ờ: 'o',
ớ: 'o',
ợ: 'o',
ở: 'o',
ỡ: 'o',
ụ: 'u',
ủ: 'u',
ũ: 'u',
ư: 'u',
ừ: 'u',
ứ: 'u',
ự: 'u',
ử: 'u',
ữ: 'u',
ỳ: 'y',
ỵ: 'y',
ỷ: 'y',
ỹ: 'y',
đ: 'd',
// kazakh
Ә: 'AE',
ә: 'ae',
Ғ: 'GH',
ғ: 'gh',
Қ: 'KH',
қ: 'kh',
Ң: 'NG',
ң: 'ng',
Ү: 'UE',
ү: 'ue',
Ұ: 'U',
ұ: 'u',
Һ: 'H',
һ: 'h',
Ө: 'OE',
ө: 'oe',
// serbian
ђ: 'dj',
ј: 'j',
љ: 'lj',
њ: 'nj',
ћ: 'c',
џ: 'dz',
Ђ: 'Dj',
Ј: 'j',
Љ: 'Lj',
Њ: 'Nj',
Ћ: 'C',
Џ: 'Dz',
nj: 'nj',
lj: 'lj',
Nj: 'NJ',
Lj: 'LJ',
// hindi
अ: 'a',
आ: 'aa',
ए: 'e',
ई: 'ii',
ऍ: 'ei',
ऎ: 'ae',
ऐ: 'ai',
इ: 'i',
ओ: 'o',
ऑ: 'oi',
ऒ: 'oii',
ऊ: 'uu',
औ: 'ou',
उ: 'u',
ब: 'B',
भ: 'Bha',
च: 'Ca',
छ: 'Chha',
ड: 'Da',
ढ: 'Dha',
फ: 'Fa',
ग: 'Ga',
घ: 'Gha',
ग़: 'Ghi',
ह: 'Ha',
ज: 'Ja',
झ: 'Jha',
क: 'Ka',
ख: 'Kha',
ख़: 'Khi',
ल: 'L',
ळ: 'Li',
ऌ: 'Li',
ऴ: 'Lii',
ॡ: 'Lii',
म: 'Ma',
न: 'Na',
ङ: 'Na',
ञ: 'Nia',
ण: 'Nae',
ऩ: 'Ni',
ॐ: 'oms',
प: 'Pa',
क़: 'Qi',
र: 'Ra',
ऋ: 'Ri',
ॠ: 'Ri',
ऱ: 'Ri',
स: 'Sa',
श: 'Sha',
ष: 'Shha',
ट: 'Ta',
त: 'Ta',
ठ: 'Tha',
द: 'Tha',
थ: 'Tha',
ध: 'Thha',
ड़: 'ugDha',
ढ़: 'ugDhha',
व: 'Va',
य: 'Ya',
य़: 'Yi',
ज़: 'Za',
// azerbaijani
ə: 'e',
Ə: 'E',
// georgian
ა: 'a',
ბ: 'b',
გ: 'g',
დ: 'd',
ე: 'e',
ვ: 'v',
ზ: 'z',
თ: 't',
ი: 'i',
კ: 'k',
ლ: 'l',
მ: 'm',
ნ: 'n',
ო: 'o',
პ: 'p',
ჟ: 'zh',
რ: 'r',
ს: 's',
ტ: 't',
უ: 'u',
ფ: 'p',
ქ: 'k',
ღ: 'gh',
ყ: 'q',
შ: 'sh',
ჩ: 'ch',
ც: 'ts',
ძ: 'dz',
წ: 'ts',
ჭ: 'ch',
ხ: 'kh',
ჯ: 'j',
ჰ: 'h',
// hebrew
ב: 'v',
גּ: 'g',
ג: 'g',
ד: 'd',
דּ: 'd',
ה: 'h',
ו: 'v',
ז: 'z',
ח: 'h',
ט: 't',
י: 'y',
כ: 'kh',
ך: 'kh',
ל: 'l',
מ: 'm',
ם: 'm',
נ: 'n',
ן: 'n',
ס: 's',
פ: 'f',
ף: 'f',
ץ: 'ts',
צ: 'ts',
ק: 'k',
ר: 'r',
תּ: 't',
ת: 't'
if (opts.trim) {
result = result.trim()
}
result = result.replace(/\s+/g, opts.replacement) // convert spaces
if (opts.lower) {
result = result.toLowerCase()
}
return result
}
slug.charmap = Object.assign({}, initialCharmap)
slug.multicharmap = Object.assign({}, initialMulticharmap)
slug.defaults = {
charmap: slug.charmap,
mode: 'pretty',
modes: {
rfc3986: {
replacement: '-',
remove: null,
lower: true,
charmap: slug.charmap,
multicharmap: slug.multicharmap,
trim: true
},
pretty: {
replacement: '-',
remove: null,
lower: true,
charmap: slug.charmap,
multicharmap: slug.multicharmap,
trim: true
}
const initialMulticharmap = {
// multibyte devanagari characters (hindi, sanskrit, etc.)
फ़: 'Fi',
ग़: 'Ghi',
ख़: 'Khi',
क़: 'Qi',
ड़: 'ugDha',
ढ़: 'ugDhha',
य़: 'Yi',
ज़: 'Za',
// hebrew
// Refs: http://www.eki.ee/wgrs/rom1_he.pdf
// Refs: https://en.wikipedia.org/wiki/Niqqud
בִי: 'i',
בֵ: 'e',
בֵי: 'e',
בֶ: 'e',
בַ: 'a',
בָ: 'a',
בֹ: 'o',
וֹ: 'o',
בֻ: 'u',
וּ: 'u',
בּ: 'b',
כּ: 'k',
ךּ: 'k',
פּ: 'p',
שׁ: 'sh',
שׂ: 's',
בְ: 'e',
חֱ: 'e',
חֲ: 'a',
חֳ: 'o',
בִ: 'i'
}
// https://github.com/django/django/blob/master/django/contrib/admin/static/admin/js/urlify.js
const initialCharmap = {
// latin
À: 'A',
Á: 'A',
Â: 'A',
Ã: 'A',
Ä: 'A',
Å: 'A',
Æ: 'AE',
Ç: 'C',
È: 'E',
É: 'E',
Ê: 'E',
Ë: 'E',
Ì: 'I',
Í: 'I',
Î: 'I',
Ï: 'I',
Ð: 'D',
Ñ: 'N',
Ò: 'O',
Ó: 'O',
Ô: 'O',
Õ: 'O',
Ö: 'O',
Ő: 'O',
Ø: 'O',
Ō: 'O',
Ù: 'U',
Ú: 'U',
Û: 'U',
Ü: 'U',
Ű: 'U',
Ý: 'Y',
Þ: 'TH',
ß: 'ss',
à: 'a',
á: 'a',
â: 'a',
ã: 'a',
ä: 'a',
å: 'a',
æ: 'ae',
ç: 'c',
è: 'e',
é: 'e',
ê: 'e',
ë: 'e',
ì: 'i',
í: 'i',
î: 'i',
ï: 'i',
ð: 'd',
ñ: 'n',
ò: 'o',
ó: 'o',
ô: 'o',
õ: 'o',
ö: 'o',
ő: 'o',
ø: 'o',
ō: 'o',
Œ: 'OE',
œ: 'oe',
ù: 'u',
ú: 'u',
û: 'u',
ü: 'u',
ű: 'u',
ý: 'y',
þ: 'th',
ÿ: 'y',
ẞ: 'SS',
// greek
α: 'a',
β: 'b',
γ: 'g',
δ: 'd',
ε: 'e',
ζ: 'z',
η: 'h',
θ: '8',
ι: 'i',
κ: 'k',
λ: 'l',
μ: 'm',
ν: 'n',
ξ: '3',
ο: 'o',
π: 'p',
ρ: 'r',
σ: 's',
τ: 't',
υ: 'y',
φ: 'f',
χ: 'x',
ψ: 'ps',
ω: 'w',
ά: 'a',
έ: 'e',
ί: 'i',
ό: 'o',
ύ: 'y',
ή: 'h',
ώ: 'w',
ς: 's',
ϊ: 'i',
ΰ: 'y',
ϋ: 'y',
ΐ: 'i',
Α: 'A',
Β: 'B',
Γ: 'G',
Δ: 'D',
Ε: 'E',
Ζ: 'Z',
Η: 'H',
Θ: '8',
Ι: 'I',
Κ: 'K',
Λ: 'L',
Μ: 'M',
Ν: 'N',
Ξ: '3',
Ο: 'O',
Π: 'P',
Ρ: 'R',
Σ: 'S',
Τ: 'T',
Υ: 'Y',
Φ: 'F',
Χ: 'X',
Ψ: 'PS',
Ω: 'W',
Ά: 'A',
Έ: 'E',
Ί: 'I',
Ό: 'O',
Ύ: 'Y',
Ή: 'H',
Ώ: 'W',
Ϊ: 'I',
Ϋ: 'Y',
// turkish
ş: 's',
Ş: 'S',
ı: 'i',
İ: 'I',
ğ: 'g',
Ğ: 'G',
// russian
а: 'a',
б: 'b',
в: 'v',
г: 'g',
д: 'd',
е: 'e',
ё: 'yo',
ж: 'zh',
з: 'z',
и: 'i',
й: 'j',
к: 'k',
л: 'l',
м: 'm',
н: 'n',
о: 'o',
п: 'p',
р: 'r',
с: 's',
т: 't',
у: 'u',
ф: 'f',
х: 'h',
ц: 'c',
ч: 'ch',
ш: 'sh',
щ: 'sh',
ъ: 'u',
ы: 'y',
ь: '',
э: 'e',
ю: 'yu',
я: 'ya',
А: 'A',
Б: 'B',
В: 'V',
Г: 'G',
Д: 'D',
Е: 'E',
Ё: 'Yo',
Ж: 'Zh',
З: 'Z',
И: 'I',
Й: 'J',
К: 'K',
Л: 'L',
М: 'M',
Н: 'N',
О: 'O',
П: 'P',
Р: 'R',
С: 'S',
Т: 'T',
У: 'U',
Ф: 'F',
Х: 'H',
Ц: 'C',
Ч: 'Ch',
Ш: 'Sh',
Щ: 'Sh',
Ъ: 'U',
Ы: 'Y',
Ь: '',
Э: 'E',
Ю: 'Yu',
Я: 'Ya',
// ukranian
Є: 'Ye',
І: 'I',
Ї: 'Yi',
Ґ: 'G',
є: 'ye',
і: 'i',
ї: 'yi',
ґ: 'g',
// czech
č: 'c',
ď: 'd',
ě: 'e',
ň: 'n',
ř: 'r',
š: 's',
ť: 't',
ů: 'u',
ž: 'z',
Č: 'C',
Ď: 'D',
Ě: 'E',
Ň: 'N',
Ř: 'R',
Š: 'S',
Ť: 'T',
Ů: 'U',
Ž: 'Z',
// slovak
ľ: 'l',
ĺ: 'l',
ŕ: 'r',
Ľ: 'L',
Ĺ: 'L',
Ŕ: 'R',
// polish
ą: 'a',
ć: 'c',
ę: 'e',
ł: 'l',
ń: 'n',
ś: 's',
ź: 'z',
ż: 'z',
Ą: 'A',
Ć: 'C',
Ę: 'E',
Ł: 'L',
Ń: 'N',
Ś: 'S',
Ź: 'Z',
Ż: 'Z',
// latvian
ā: 'a',
ē: 'e',
ģ: 'g',
ī: 'i',
ķ: 'k',
ļ: 'l',
ņ: 'n',
ū: 'u',
Ā: 'A',
Ē: 'E',
Ģ: 'G',
Ī: 'I',
Ķ: 'K',
Ļ: 'L',
Ņ: 'N',
Ū: 'U',
// arabic
أ: 'a',
إ: 'i',
ب: 'b',
ت: 't',
ث: 'th',
ج: 'g',
ح: 'h',
خ: 'kh',
د: 'd',
ذ: 'th',
ر: 'r',
ز: 'z',
س: 's',
ش: 'sh',
ص: 's',
ض: 'd',
ط: 't',
ظ: 'th',
ع: 'aa',
غ: 'gh',
ف: 'f',
ق: 'k',
ك: 'k',
ل: 'l',
م: 'm',
ن: 'n',
ه: 'h',
و: 'o',
ي: 'y',
ء: 'aa',
ة: 'a',
// farsi
آ: 'a',
ا: 'a',
پ: 'p',
ژ: 'zh',
گ: 'g',
چ: 'ch',
ک: 'k',
ی: 'i',
// lithuanian
ė: 'e',
į: 'i',
ų: 'u',
Ė: 'E',
Į: 'I',
Ų: 'U',
// romanian
ț: 't',
Ț: 'T',
ţ: 't',
Ţ: 'T',
ș: 's',
Ș: 'S',
ă: 'a',
Ă: 'A',
// vietnamese
Ạ: 'A',
Ả: 'A',
Ầ: 'A',
Ấ: 'A',
Ậ: 'A',
Ẩ: 'A',
Ẫ: 'A',
Ằ: 'A',
Ắ: 'A',
Ặ: 'A',
Ẳ: 'A',
Ẵ: 'A',
Ẹ: 'E',
Ẻ: 'E',
Ẽ: 'E',
Ề: 'E',
Ế: 'E',
Ệ: 'E',
Ể: 'E',
Ễ: 'E',
Ị: 'I',
Ỉ: 'I',
Ĩ: 'I',
Ọ: 'O',
Ỏ: 'O',
Ồ: 'O',
Ố: 'O',
Ộ: 'O',
Ổ: 'O',
Ỗ: 'O',
Ơ: 'O',
Ờ: 'O',
Ớ: 'O',
Ợ: 'O',
Ở: 'O',
Ỡ: 'O',
Ụ: 'U',
Ủ: 'U',
Ũ: 'U',
Ư: 'U',
Ừ: 'U',
Ứ: 'U',
Ự: 'U',
Ử: 'U',
Ữ: 'U',
Ỳ: 'Y',
Ỵ: 'Y',
Ỷ: 'Y',
Ỹ: 'Y',
Đ: 'D',
ạ: 'a',
ả: 'a',
ầ: 'a',
ấ: 'a',
ậ: 'a',
ẩ: 'a',
ẫ: 'a',
ằ: 'a',
ắ: 'a',
ặ: 'a',
ẳ: 'a',
ẵ: 'a',
ẹ: 'e',
ẻ: 'e',
ẽ: 'e',
ề: 'e',
ế: 'e',
ệ: 'e',
ể: 'e',
ễ: 'e',
ị: 'i',
ỉ: 'i',
ĩ: 'i',
ọ: 'o',
ỏ: 'o',
ồ: 'o',
ố: 'o',
ộ: 'o',
ổ: 'o',
ỗ: 'o',
ơ: 'o',
ờ: 'o',
ớ: 'o',
ợ: 'o',
ở: 'o',
ỡ: 'o',
ụ: 'u',
ủ: 'u',
ũ: 'u',
ư: 'u',
ừ: 'u',
ứ: 'u',
ự: 'u',
ử: 'u',
ữ: 'u',
ỳ: 'y',
ỵ: 'y',
ỷ: 'y',
ỹ: 'y',
đ: 'd',
// kazakh
Ә: 'AE',
ә: 'ae',
Ғ: 'GH',
ғ: 'gh',
Қ: 'KH',
қ: 'kh',
Ң: 'NG',
ң: 'ng',
Ү: 'UE',
ү: 'ue',
Ұ: 'U',
ұ: 'u',
Һ: 'H',
һ: 'h',
Ө: 'OE',
ө: 'oe',
// serbian
ђ: 'dj',
ј: 'j',
љ: 'lj',
њ: 'nj',
ћ: 'c',
џ: 'dz',
Ђ: 'Dj',
Ј: 'j',
Љ: 'Lj',
Њ: 'Nj',
Ћ: 'C',
Џ: 'Dz',
nj: 'nj',
lj: 'lj',
Nj: 'NJ',
Lj: 'LJ',
// hindi
अ: 'a',
आ: 'aa',
ए: 'e',
ई: 'ii',
ऍ: 'ei',
ऎ: 'ae',
ऐ: 'ai',
इ: 'i',
ओ: 'o',
ऑ: 'oi',
ऒ: 'oii',
ऊ: 'uu',
औ: 'ou',
उ: 'u',
ब: 'B',
भ: 'Bha',
च: 'Ca',
छ: 'Chha',
ड: 'Da',
ढ: 'Dha',
फ: 'Fa',
ग: 'Ga',
घ: 'Gha',
ग़: 'Ghi',
ह: 'Ha',
ज: 'Ja',
झ: 'Jha',
क: 'Ka',
ख: 'Kha',
ख़: 'Khi',
ल: 'L',
ळ: 'Li',
ऌ: 'Li',
ऴ: 'Lii',
ॡ: 'Lii',
म: 'Ma',
न: 'Na',
ङ: 'Na',
ञ: 'Nia',
ण: 'Nae',
ऩ: 'Ni',
ॐ: 'oms',
प: 'Pa',
क़: 'Qi',
र: 'Ra',
ऋ: 'Ri',
ॠ: 'Ri',
ऱ: 'Ri',
स: 'Sa',
श: 'Sha',
ष: 'Shha',
ट: 'Ta',
त: 'Ta',
ठ: 'Tha',
द: 'Tha',
थ: 'Tha',
ध: 'Thha',
ड़: 'ugDha',
ढ़: 'ugDhha',
व: 'Va',
य: 'Ya',
य़: 'Yi',
ज़: 'Za',
// azerbaijani
ə: 'e',
Ə: 'E',
// georgian
ა: 'a',
ბ: 'b',
გ: 'g',
დ: 'd',
ე: 'e',
ვ: 'v',
ზ: 'z',
თ: 't',
ი: 'i',
კ: 'k',
ლ: 'l',
მ: 'm',
ნ: 'n',
ო: 'o',
პ: 'p',
ჟ: 'zh',
რ: 'r',
ს: 's',
ტ: 't',
უ: 'u',
ფ: 'p',
ქ: 'k',
ღ: 'gh',
ყ: 'q',
შ: 'sh',
ჩ: 'ch',
ც: 'ts',
ძ: 'dz',
წ: 'ts',
ჭ: 'ch',
ხ: 'kh',
ჯ: 'j',
ჰ: 'h',
// hebrew
ב: 'v',
גּ: 'g',
ג: 'g',
ד: 'd',
דּ: 'd',
ה: 'h',
ו: 'v',
ז: 'z',
ח: 'h',
ט: 't',
י: 'y',
כ: 'kh',
ך: 'kh',
ל: 'l',
מ: 'm',
ם: 'm',
נ: 'n',
ן: 'n',
ס: 's',
פ: 'f',
ף: 'f',
ץ: 'ts',
צ: 'ts',
ק: 'k',
ר: 'r',
תּ: 't',
ת: 't'
}
slug.charmap = Object.assign({}, initialCharmap)
slug.multicharmap = Object.assign({}, initialMulticharmap)
slug.defaults = {
charmap: slug.charmap,
mode: 'pretty',
modes: {
rfc3986: {
replacement: '-',
remove: null,
lower: true,
charmap: slug.charmap,
multicharmap: slug.multicharmap,
trim: true
},
multicharmap: slug.multicharmap,
fallback: true
}
pretty: {
replacement: '-',
remove: null,
lower: true,
charmap: slug.charmap,
multicharmap: slug.multicharmap,
trim: true
}
},
multicharmap: slug.multicharmap,
fallback: true
}
slug.reset = function () {
slug.defaults.modes.rfc3986.charmap = slug.defaults.modes.pretty.charmap = slug.charmap = slug.defaults.charmap = Object.assign({}, initialCharmap)
slug.defaults.modes.rfc3986.multicharmap = slug.defaults.modes.pretty.multicharmap = slug.multicharmap = slug.defaults.multicharmap = Object.assign({}, initialMulticharmap)
defaultLocale = ''
}
slug.reset = function () {
slug.defaults.modes.rfc3986.charmap = slug.defaults.modes.pretty.charmap = slug.charmap = slug.defaults.charmap = Object.assign({}, initialCharmap)
slug.defaults.modes.rfc3986.multicharmap = slug.defaults.modes.pretty.multicharmap = slug.multicharmap = slug.defaults.multicharmap = Object.assign({}, initialMulticharmap)
defaultLocale = ''
}
slug.extend = function (customMap) {
const keys = Object.keys(customMap)
const multi = {}
const single = {}
for (let i = 0; i < keys.length; i++) {
if (keys[i].length > 1) {
multi[keys[i]] = customMap[keys[i]]
} else {
single[keys[i]] = customMap[keys[i]]
}
slug.extend = function (customMap) {
const keys = Object.keys(customMap)
const multi = {}
const single = {}
for (let i = 0; i < keys.length; i++) {
if (keys[i].length > 1) {
multi[keys[i]] = customMap[keys[i]]
} else {
single[keys[i]] = customMap[keys[i]]
}
Object.assign(slug.charmap, single)
Object.assign(slug.multicharmap, multi)
}
Object.assign(slug.charmap, single)
Object.assign(slug.multicharmap, multi)
}
slug.setLocale = function (locale) {
defaultLocale = locales[locale] || {}
}
slug.setLocale = function (locale) {
defaultLocale = locales[locale] || {}
}
if (typeof module !== 'undefined' && module.exports) { // CommonJS
module.exports = slug
} else { // Script tag
root.slug = slug
}
}(this))
export default slug
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc