137 lines
2.9 KiB
JavaScript
137 lines
2.9 KiB
JavaScript
const accentMap = {
|
||
à: 'a',
|
||
á: 'a',
|
||
ä: 'a',
|
||
å: 'a',
|
||
ã: 'a',
|
||
â: 'a',
|
||
æ: 'ae',
|
||
ç: 'c',
|
||
è: 'e',
|
||
é: 'e',
|
||
ë: 'e',
|
||
ẽ: 'e',
|
||
ê: 'e',
|
||
ì: 'i',
|
||
í: 'i',
|
||
ï: 'i',
|
||
ĩ: 'i',
|
||
î: 'i',
|
||
ǹ: 'n',
|
||
ń: 'n',
|
||
ñ: 'n',
|
||
ò: 'o',
|
||
ó: 'o',
|
||
ö: 'o',
|
||
õ: 'o',
|
||
ô: 'o',
|
||
ø: 'o',
|
||
œ: 'oe',
|
||
ß: 'ss',
|
||
ù: 'u',
|
||
ú: 'u',
|
||
ü: 'u',
|
||
ũ: 'u',
|
||
û: 'u',
|
||
ỳ: 'y',
|
||
ý: 'y',
|
||
ÿ: 'y',
|
||
ỹ: 'y',
|
||
};
|
||
|
||
const plainCharRegex = /[a-zA-Z0-9]/;
|
||
const defaultPunctuationRegex = /[.,?!:;&'‘’"“”…()[]{}<>\/*—-]/;
|
||
const defaultSymbolRegex = /[@$€£#%^+=\\~]/;
|
||
|
||
module.exports = function slugify(strings, delimiter = '-', {
|
||
limit = 1000,
|
||
lower = true,
|
||
encode = false,
|
||
accents: keepAccents = false,
|
||
punctuation: keepPunctuation = false,
|
||
punctuationRegex = defaultPunctuationRegex,
|
||
symbols: keepSymbols = false,
|
||
symbolRegex = defaultSymbolRegex,
|
||
} = {}) {
|
||
if (!strings || (typeof strings !== 'string' && !Array.isArray(strings))) {
|
||
return strings;
|
||
}
|
||
|
||
const string = [].concat(strings).join(' ');
|
||
|
||
const casedString = lower
|
||
? string.toLowerCase()
|
||
: string;
|
||
|
||
const normalized = casedString
|
||
.split('')
|
||
.map((char) => {
|
||
if (char === ' ') {
|
||
return char;
|
||
}
|
||
|
||
const lowChar = char.toLowerCase();
|
||
|
||
if (accentMap[lowChar]) {
|
||
if (keepAccents) {
|
||
return char;
|
||
}
|
||
|
||
// match original case after mapping
|
||
if (char === lowChar) {
|
||
return accentMap[lowChar];
|
||
}
|
||
|
||
return accentMap[lowChar].toUpperCase();
|
||
}
|
||
|
||
if (plainCharRegex.test(char)) {
|
||
return char;
|
||
}
|
||
|
||
if (punctuationRegex.test(char)) {
|
||
if (keepPunctuation === 'split') {
|
||
return ' ';
|
||
}
|
||
|
||
if (keepPunctuation) {
|
||
return char;
|
||
}
|
||
}
|
||
|
||
if (symbolRegex.test(char)) {
|
||
if (keepSymbols === 'split') {
|
||
return ' ';
|
||
}
|
||
|
||
if (keepSymbols) {
|
||
return char;
|
||
}
|
||
}
|
||
|
||
return '';
|
||
}).join('');
|
||
|
||
const components = normalized.trim().split(/\s+/).filter(Boolean);
|
||
|
||
if (components.length === 0) {
|
||
return '';
|
||
}
|
||
|
||
const slug = components.reduce((acc, component, index) => {
|
||
const accSlug = `${acc}${index > 0 ? delimiter : ''}${component}`;
|
||
|
||
if (accSlug.length < limit) {
|
||
return accSlug;
|
||
}
|
||
|
||
return acc;
|
||
}).slice(0, limit); // in case first word exceeds limit
|
||
|
||
if (encode) {
|
||
return encodeURI(slug);
|
||
}
|
||
|
||
return slug;
|
||
}
|