first commit

This commit is contained in:
Alexander Navarro 2025-04-11 16:01:28 -04:00
commit 817b7cf4bc
838 changed files with 730686 additions and 0 deletions

341
node_modules/slug/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,341 @@
# [10.0.0](https://github.com/Trott/slug/compare/v9.1.0...v10.0.0) (2024-10-17)
* ESM only + move to webtestrunnner ([#467](https://github.com/Trott/slug/issues/467)) ([a8db3ed](https://github.com/Trott/slug/commit/a8db3edebf0dad4b44f6ba5396accca60a7db084))
### BREAKING CHANGES
* This module only supports ESM. CommonJS and non-ESM
script tags are no longer supported.
* chore: add web-test-runner
* chore: add coverage reporting for CLI tests
* chore: fail CLI tests if coverage is not 100%
# [9.1.0](https://github.com/Trott/slug/compare/v9.0.0...v9.1.0) (2024-05-24)
### Features
* add `remove` option field to playground ([#445](https://github.com/Trott/slug/issues/445)) ([8888d69](https://github.com/Trott/slug/commit/8888d69455671bfbe990ae13755735a2a38fa504))
# [9.0.0](https://github.com/Trott/slug/compare/v8.2.3...v9.0.0) (2024-03-07)
### chore
* refresh package-lock.json ([#426](https://github.com/Trott/slug/issues/426)) ([c86632c](https://github.com/Trott/slug/commit/c86632cfc1c1254ac026fd8a29acf28fe2ea59a1))
### BREAKING CHANGES
* Drop support for Node.js older than 18.x
## [8.2.3](https://github.com/Trott/slug/compare/v8.2.2...v8.2.3) (2023-07-18)
### Bug Fixes
* fix output example in README ([#393](https://github.com/Trott/slug/issues/393)) ([3165852](https://github.com/Trott/slug/commit/3165852d527737bbfaac8ab3f18b2868665024b6))
## [8.2.2](https://github.com/Trott/slug/compare/v8.2.1...v8.2.2) (2022-10-02)
### Bug Fixes
* slugify θ as th ([#354](https://github.com/Trott/slug/issues/354)) ([19e8ca1](https://github.com/Trott/slug/commit/19e8ca111453988d15a09572b8fd3b5336822cd4))
## [8.2.1](https://github.com/Trott/slug/compare/v8.2.0...v8.2.1) (2022-10-02)
### Bug Fixes
* use correct path for CLI ([#352](https://github.com/Trott/slug/issues/352)) ([f163bd2](https://github.com/Trott/slug/commit/f163bd2be141390358b52fa80261d66dfe5ed71d))
# [8.2.0](https://github.com/Trott/slug/compare/v8.1.0...v8.2.0) (2022-10-02)
### Features
* add a minimal CLI ([#351](https://github.com/Trott/slug/issues/351)) ([92004e7](https://github.com/Trott/slug/commit/92004e7421a145023983eeb956015243f0098ee9))
# [8.1.0](https://github.com/Trott/slug/compare/v8.0.0...v8.1.0) (2022-10-02)
### Features
* add a (painfully minimal) web playground ([#350](https://github.com/Trott/slug/issues/350)) ([4e1aa40](https://github.com/Trott/slug/commit/4e1aa408032e36c59b906464da43888972cc9037))
# [8.0.0](https://github.com/Trott/slug/compare/v7.0.0...v8.0.0) (2022-08-31)
### chore
* remove AMD support ([#345](https://github.com/Trott/slug/issues/345)) ([2f30cd9](https://github.com/Trott/slug/commit/2f30cd9b1f226753cc7728f258975a0986125229))
### BREAKING CHANGES
* Loading via AMD will no longer work out-of-the-box.
# [7.0.0](https://github.com/Trott/slug/compare/v6.1.0...v7.0.0) (2022-08-31)
### chore
* drop support for Node.js 12.x and 17.x ([#344](https://github.com/Trott/slug/issues/344)) ([a109d37](https://github.com/Trott/slug/commit/a109d3740dc4f0776b313b7033f7de87229dcfcd))
### BREAKING CHANGES
* Drop support for Node.js earlier than 14.x.
# [6.1.0](https://github.com/Trott/slug/compare/v6.0.0...v6.1.0) (2022-08-31)
### Features
* add fallback option ([#342](https://github.com/Trott/slug/issues/342)) ([b703043](https://github.com/Trott/slug/commit/b703043ff369392b141fb6d44d6b554516d9fc69)), closes [#341](https://github.com/Trott/slug/issues/341)
# [6.0.0](https://github.com/Trott/slug/compare/v5.3.0...v6.0.0) (2022-08-16)
### chore
* drop support for IE11 ([9927860](https://github.com/Trott/slug/commit/99278607be3bfe52dea8fcba9e699f5c7f05931d))
### BREAKING CHANGES
* drop support for IE11
# [5.3.0](https://github.com/Trott/slug/compare/v5.2.0...v5.3.0) (2022-03-04)
### Features
* add bugs entry to package.json ([ca72836](https://github.com/Trott/slug/commit/ca72836f3f2b25ac9476e3f1ebcb997db1ba0f26))
# [5.2.0](https://github.com/Trott/slug/compare/v5.1.1...v5.2.0) (2021-12-27)
### Features
* add ability to set default locale via setLocale() ([#269](https://github.com/Trott/slug/issues/269)) ([add368d](https://github.com/Trott/slug/commit/add368dbe5065f953d450f4f917fced42a08bf87))
## [5.1.1](https://github.com/Trott/slug/compare/v5.1.0...v5.1.1) (2021-12-13)
### Bug Fixes
* consolidate replacement chars from extend() ([#267](https://github.com/Trott/slug/issues/267)) ([df7a488](https://github.com/Trott/slug/commit/df7a488a183477c4851868e94eaeab7830a07ff3))
# [5.1.0](https://github.com/Trott/slug/compare/v5.0.1...v5.1.0) (2021-06-15)
### Features
* add "trim" option ([#230](https://github.com/Trott/slug/issues/230)) ([00493cc](https://github.com/Trott/slug/commit/00493cc0ecd1db447397658fa6c23fff74d7290d))
## [5.0.1](https://github.com/Trott/slug/compare/v5.0.0...v5.0.1) (2021-05-09)
### Bug Fixes
* enable characters composed of multiple code points in .extend() ([#217](https://github.com/Trott/slug/issues/217)) ([5919b6d](https://github.com/Trott/slug/commit/5919b6d407b08d58f4ed1ea65d3d01736e0f37a5))
# [5.0.0](https://github.com/Trott/slug/compare/v4.1.0...v5.0.0) (2021-05-03)
### chore
* drop support for Node.js 10.x ([#209](https://github.com/Trott/slug/issues/209)) ([e2ee1b8](https://github.com/Trott/slug/commit/e2ee1b8e4ff8285eebbda3375314e2418c8948e4))
### BREAKING CHANGES
* Drop support for Node.js 10.x which is now EOL.
# [4.1.0](https://github.com/Trott/slug/compare/v4.0.4...v4.1.0) (2021-05-03)
### Features
* add Ukrainian locale ([#207](https://github.com/Trott/slug/issues/207)) ([58467f9](https://github.com/Trott/slug/commit/58467f9b7f2489c743906f04184cf84d9dbfd081))
## [4.0.4](https://github.com/Trott/slug/compare/v4.0.3...v4.0.4) (2021-04-16)
### Bug Fixes
* honor special character replacements in charmap ([f5e18c9](https://github.com/Trott/slug/commit/f5e18c9ff8e21e5c5bc636f34b811b4b73e1b204))
## [4.0.3](https://github.com/Trott/slug/compare/v4.0.2...v4.0.3) (2021-02-24)
### Bug Fixes
* add arabic letter إ i ([ce9ce2f](https://github.com/Trott/slug/commit/ce9ce2fe27ad7caefe557c55eeb9740de52d1e1e))
## [4.0.2](https://github.com/Trott/slug/compare/v4.0.1...v4.0.2) (2020-10-30)
### Bug Fixes
* update from deprecated license specification ([bc16c49](https://github.com/Trott/slug/commit/bc16c4917e2303a71c0767166156351d3b3c6369))
## [4.0.1](https://github.com/Trott/slug/compare/v4.0.0...v4.0.1) (2020-10-22)
### Bug Fixes
* add Œ/œ ([5abe081](https://github.com/Trott/slug/commit/5abe081a633a2905257e861292d43923c900939a))
# [4.0.0](https://github.com/Trott/slug/compare/v3.5.2...v4.0.0) (2020-10-21)
### chore
* remove symbols ([853ad52](https://github.com/Trott/slug/commit/853ad52816c4ee4910ec4a7ab5497b5d530de242))
### BREAKING CHANGES
* symbols are removed
## [3.5.2](https://github.com/Trott/slug/compare/v3.5.1...v3.5.2) (2020-10-20)
### Bug Fixes
* correct errors in code samples ([f74890f](https://github.com/Trott/slug/commit/f74890ffd3d7d85e99a2bd71be19f36a2d5aa97f))
## [3.5.1](https://github.com/Trott/slug/compare/v3.5.0...v3.5.1) (2020-10-13)
### Bug Fixes
* add ة،ء missing Arabic characters ([#1](https://github.com/Trott/slug/issues/1)) ([0366d3a](https://github.com/Trott/slug/commit/0366d3a7b67d60f656d76e12c1a5eaba6f49a9de))
## [3.5.0](https://github.com/Trott/slug/compare/v3.4.0...v3.5.0) (2020-10-11)
### Features
* add support for React Native ([7962f8b](https://github.com/Trott/slug/commit/7962f8b52ed00c3114e745a804664aa1956d59d4))
## [3.4.0](https://github.com/Trott/slug/compare/v3.3.6...v3.4.0) (2020-10-11)
### Features
* add support for Hebrew ([04851c4](https://github.com/Trott/slug/commit/04851c47f82c5c3c695070956ae687041d963c8a))
## [3.3.6](https://github.com/Trott/slug/compare/v3.3.5...v3.3.6) (2020-10-11)
### Bug Fixes
* reset() should reset all multicharmap defaults ([a429809](https://github.com/Trott/slug/commit/a429809aed4f13b80664e866436931646043e124))
## 3.3.5 (https://github.com/Trott/slug/compare/v3.3.4...v3.3.5) (2020-09-29)
### Bug Fixes
* prevent slug function from mutating option object (41916a3 (https://github.com/Trott/slug/commit/41916a32c6a6cdd3af1fe2405224e8b91c7760d4))
## 3.3.4 (https://github.com/Trott/slug/compare/v3.3.3...v3.3.4)
### Bug Fixes
* fix: add German locale for parity with slugify
## 3.3.3
chore: add missing Latin/Greek char
## 3.3.2
fix: remove template strings for IE11 compatibility
## 3.3.1
fix: use let for ie11 compat
chore: move regex to improve performance
chore: add documentation and tests for remove option
## 3.3.0
feat: make Base64 fallback in browser far more robust
fix: disregard lone surrogates in Node.js, as in the browser
fix: enable browser compatibility for all code points
## 3.2.0
feat: add support for Azerbaijani characters
feat: add support for Slovak characters
## 3.1.0
feat: add support for Georgian characters
feat: add locale sr (Serbian)
feat: support locale bg (Bulgarian)
fix: repair markdown layout for README file
## 3.0.1
fix: remove erroneous "bin" entry in package.json
## 3.0.0
BREAKING CHANGE: make output lowercase by default (#43)
BREAKING CHANGE: more aggressively remove punctuation by default (#39)
BREAKING CHANGE: do not load/use unicode symbol table (#50)
BREAKING CHANGE: require first argument to be a string (#32)
BREAKING CHANGE: remove CLI (#52)
feat: support Devanagari for Hindi, Sanskrit, and other languages (#55)
feat: add Kazakh characters (#42)
feat: add Serbian transliterations (#45)
feat: add ruble, bitcoin, tenge (#47)
feat: implement .extend() (#51)
feat: implement .reset() and browser testing (#53)
## 2.1.1
Restore IE 11 support by removing arrow functions.
## 2.1.0
Fallback to base64 if slug is empty. This allows minimal out-of-the-box support
for character sets not in the default mappings.
## 2.0.0
Add support for Farsi. (Thanks, @hassan-jahan!)
This is being released as a breaking change because it changes some of
the slugs for Arabic strings. It probably won't break anything, but just
in case....

7
node_modules/slug/LICENSE generated vendored Normal file
View file

@ -0,0 +1,7 @@
Copyright (c) 2014 ▟ ▖▟ ▖(dodo)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

135
node_modules/slug/README.md generated vendored Normal file
View file

@ -0,0 +1,135 @@
# [slug](https://github.com/Trott/slug)
Slugifies strings, even when they contain Unicode.
Make strings URL-safe.
- Respects [RFC 3986](https://tools.ietf.org/html/rfc3986)
- No dependencies
- Works in the browser or in Node.js
```
npm install slug
```
If you are using TypeScript you can install the accompanying types
```
npm install --save-dev @types/slug
```
## Example
```javascript
import slug from 'slug'
var print = console.log.bind(console, '>')
print(slug('i love unicode'))
// > i-love-unicode
print(slug('i love unicode', '_')) // If you prefer something else than `-` as separator
// > i_love_unicode
slug.charmap['♥'] = 'freaking love' // change default charmap or use option {charmap:{…}} as 2. argument
print(slug('I ♥ UNICODE'))
// > i-freaking-love-unicode
// To reset modifications to slug.charmap, use slug.reset():
slug.reset()
print(slug('I ♥ UNICODE'))
// > i-unicode
print(slug('Telephone-Number')) // lower case by default
// > telephone-number
print(slug('Telephone-Number', {lower: false})) // If you want to preserve case
// > Telephone-Number
// We try to provide sensible defaults.
// So Cyrillic text will be transliterated as if it were Russian:
print(slug('маленький подъезд'))
// > malenkij-poduezd
// But maybe you know it's Bulgarian:
print(slug('маленький подъезд', { locale: 'bg' }))
// > malenykiy-podaezd
// To set the default locale:
slug.setLocale('bg')
print(slug('маленький подъезд'))
// > malenykiy-podaezd
print(slug('unicode is ☢'))
// > unicode-is
slug.extend({'☢': 'radioactive'})
print(slug('unicode ♥ is ☢'))
// > unicode-is-radioactive
// slug.extend() modifies the default charmap for the entire process.
// If you need to reset charmap, multicharmap, and the default locale, use slug.reset():
slug.reset()
print(slug('unicode ♥ is ☢'))
// > unicode-is
// Custom removal of characters from resulting slug. Let's say that we want to
// remove all numbers for some reason.
print(slug('one 1 two 2 three 3'))
// > one-1-two-2-three-3
print(slug('one 1 two 2 three 3', { remove: /[0-9]/g }))
// > one-two-three
```
## options
```javascript
// options is either object or replacement (sets options.replacement)
slug('string', [{options} || 'replacement']);
```
```javascript
slug.defaults.mode ='pretty';
slug.defaults.modes['rfc3986'] = {
replacement: '-', // replace spaces with replacement
remove: null, // (optional) regex to remove characters
lower: true, // result in lower case
charmap: slug.charmap, // replace special characters
multicharmap: slug.multicharmap, // replace multiple code unit characters
trim: true, // trim leading and trailing replacement chars
fallback: true // use base64 to generate slug for empty results
};
slug.defaults.modes['pretty'] = {
replacement: '-',
remove: null,
lower: false,
charmap: slug.charmap,
multicharmap: slug.multicharmap,
trim: true,
fallback: true
};
```
## Differences between `slug` and `slugify` packages
Here are some key differences between this package and [`slugify`](https://github.com/simov/slugify).
- **Stability:** `slug` is ESM-only.
`slugify` supports CommonJS and ESM.
- **Defaults:** `slug` has the `lower` option enabled by default, lowercasing all slugs
(`'On SALE'` becomes `'on-sale'`).
`slugify` has the `lower` option disabled by default (`'On SALE'` becomes `'On-SALE'`).
- **Symbols:** `slug` removes unrecognized symbols (`'$100'` becomes `'100'`, `'<5'` becomes `'5'`, etc.).
`slugify` maps them to words (`'$100'` becomes `'dollar100'`, `'<5'` becomes `'less5'`, etc.).
- **Empty Output:** `slug` will return a short, predictable hash (`' '` becomes `'icag'` and `'🎉'` becomes `'8joiq'`).
`slugify` will return an empty string (`' '` and `'🎉'` become `''`).
## Playground
A (painfully minimal) web playground is available at
https://trott.github.io/slug/. It doesn't allow you to specify options, so it's utility is minimal. Pull requests welcome to add the ability to
specify options.
There is also a (similarly minimal) CLI tool available via `npx slug`.
As with the web playground, it doesn't allow you to specify options, so
it's utility is minimal.

10
node_modules/slug/cli.js generated vendored Executable file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env node
import slug from './slug.js'
if (process.argv.length < 3) {
console.log('Usage: slug <string>')
process.exit(1)
}
console.log(slug(process.argv[2]))

71
node_modules/slug/package.json generated vendored Normal file
View file

@ -0,0 +1,71 @@
{
"name": "slug",
"description": "slugifies even utf-8 chars!",
"version": "10.0.0",
"type": "module",
"homepage": "https://github.com/Trott/slug",
"author": "dodo (https://github.com/dodo)",
"repository": {
"type": "git",
"url": "git://github.com/Trott/slug.git"
},
"bugs": "https://github.com/Trott/slug/issues",
"main": "slug.js",
"bin": {
"slug": "cli.js"
},
"keywords": [
"slugify",
"slug",
"string",
"utf8",
"utf-8",
"unicode",
"url"
],
"scripts": {
"test": "standard && c8 --100 mocha test/**/*.js && web-test-runner test/**/*.js --node-resolve",
"benchmark": "node benchmark/benchmark.js"
},
"devDependencies": {
"@esm-bundle/chai": "^4.3.4-fix.0",
"@semantic-release/changelog": "^6.0.1",
"@semantic-release/git": "^10.0.1",
"@web/test-runner": "^0.19.0",
"c8": "^10.1.2",
"mocha": "^10.0.0",
"semantic-release": "^24.0.0",
"standard": "^17.1.0"
},
"license": "MIT",
"release": {
"branches": [
"main",
{
"name": "beta",
"prerelease": true
}
],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md"
}
],
"@semantic-release/npm",
[
"@semantic-release/git",
{
"assets": [
"CHANGELOG.md",
"package.json"
],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
]
]
}
}

40
node_modules/slug/playground.js generated vendored Normal file
View file

@ -0,0 +1,40 @@
const form = document.getElementById('form')
form.addEventListener('submit', function (e) {
e.preventDefault()
if (form === null) {
console.error('form element not found')
return
}
const fd = new FormData(form)
const replacement = fd.get('replacement')
const lowercase = fd.get('lowercase')
const trim = fd.get('trim')
const fallback = fd.get('fallback')
const remove = fd.get('remove')
const regexG = fd.get('regex_g') === null ? '' : 'g'
const regexI = fd.get('regex_i') === null ? '' : 'i'
const opts = {}
if (replacement.length > 0) {
opts.replacement = replacement
}
if (remove !== null && remove.length > 0) {
const regex = new RegExp(`/${remove}/${regexG}${regexI}`)
opts.remove = regex
}
opts.lower = lowercase !== null
opts.trim = trim !== null
opts.fallback = fallback !== null
const output = window.slug(document.getElementById('input').value, opts)
document.getElementById('slugOutput').innerText = output
})

887
node_modules/slug/slug.js generated vendored Normal file
View file

@ -0,0 +1,887 @@
/* global btoa */
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 is a coherence check. `code` should never be `NaN`.
/* c8 ignore next 3 */
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
}
// 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]
}
// Low surrogate (0xDC00 <= code && code <= 0xDFFF)
if (i === 0) {
// Low surrogate without preceding high surrogate
return [' ', i]
}
const prev = str.charCodeAt(i - 1)
/* c8 ignore next */
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') {
// Browser environment. We don't yet merge coverage with CLI tests.
/* c8 ignore next 4 */
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.
/* c8 ignore next 3 */
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
}
}
} 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)
}
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' }
}
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
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) }
}
// 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]/
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, '')
}
}
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
}
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',
θ: 'th',
ι: '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',
Θ: 'Th',
Ι: '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
},
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.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)
}
slug.setLocale = function (locale) {
defaultLocale = locales[locale] || {}
}
export default slug