Skip to content

Commit

Permalink
breaking: use slugify and emoji.json
Browse files Browse the repository at this point in the history
  • Loading branch information
GreatWizard committed Jan 19, 2022
1 parent 51d4471 commit 5eb0199
Show file tree
Hide file tree
Showing 10 changed files with 1,336 additions and 1,140 deletions.
55 changes: 42 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ Library to slugify your strings within Ember.

This library uses:

- [speakingurl](https://pid.github.io/speakingurl/)
- [slugify](https://github.com/simov/slugify)
- [simple-pinyin](https://github.com/xuqingkuang/simple-pinyin)

- [emoji.json](https://github.com/amio/emoji.json)

## Compatibility

* Ember.js v3.20 or above
* Ember CLI v3.20 or above
* Node.js v12 or above
- Ember.js v3.20 or above
- Ember CLI v3.20 or above
- Node.js v12 or above

## Installation

Expand All @@ -28,26 +28,55 @@ ember install ember-slugify
### In a `js` file

```js
import slugify, { removeDiacritics } from 'ember-slugify';
import slugify, { removeDiacritics } from 'ember-slugify'

let slug = slugify('Le Théâtre')
// le-theatre

slug = slugify('I ♥ New York')
// i-love-new-york

slug = slugify("Vive l'♥", { locale: 'fr' })
// vive-lamour

slug = slugify('bonjour monsieur', { replacement: '#' })
// bonjour#monsieur

let slug = slugify('你好你怎么样 monsieur'); // ni-hao-ni-zen-me-yang-monsieur
slug = slugify('你好你怎么样 monsieur', { pinyin: true })
// ni-hao-ni-zen-me-yang-monsieur

let options = { separator: '#' }); // options for speakingurl
let slug = slugify('你好你怎么样 monsieur', options); // ni#hao#ni#zen#me#yang#monsieur
slug = slugify('🇫🇷❤️🥖➕🍷', { emoji: true })
// flag-france-red-heart-baguette-bread-plus-wine-glass

let noDiacritics = removeDiacritics('Théâtre'); // Theatre
let slug = slugify('Théâtre'); // theatre
let noDiacritics = removeDiacritics('Le Théâtre')
// Le Theatre
```

### In a template

```hbs
await render(hbs`{{slugify '你好你怎么样 monsieur'}}`)
await render(hbs`{{remove-diacritics 'Théâtre'}}`)
{{slugify 'Le Théâtre'}}
{{slugify '你好你怎么样 monsieur' (hash pinyin=true)}}
{{slugify '🇫🇷❤️🥖➕🍷' (hash emoji=true)}}
{{remove-diacritics 'Le Théâtre'}}
```

The separator option is not available on `slugify` helper.

### Options

| name | description | default value |
| ----------- | ---------------------------------------------------------- | ------------- |
| replacement | replace spaces with replacement character | `'-'` |
| lower | convert to lower case | `true` |
| locale | language code of the locale to use | `undefined` |
| trim | trim leading and trailing replacement chars | `true` |
| pinyin | replace chinese by latin character following pinyin method | `false` |
| emoji | replace unicode emoji by it's description | `false` |

## Contributing

See the [Contributing](CONTRIBUTING.md) guide for details.
Expand Down
23 changes: 21 additions & 2 deletions addon/helpers/slugify.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
import { helper } from '@ember/component/helper'
import { slugify as slugfyFunction } from 'ember-slugify'

const AVAILABLE_OPTIONS = [
'replacement', // options from slugify dependency
'remove', // options from slugify dependency
'lower', // options from slugify dependency
'strict', // options from slugify dependency
'locale', // options from slugify dependency
'trim', // options from slugify dependency
'pinyin', // replace pinyin by latin character (boolean)
'emoji', // replace emoji by english name (boolean)
]

function slugify(args) {
let [string] = args
return slugfyFunction(string)
let [string, options] = args
let opts = {}
if (options) {
AVAILABLE_OPTIONS.forEach((key) => {
if (options[key] !== undefined) {
opts[key] = options[key]
}
})
}
return slugfyFunction(string, opts)
}

export default helper(slugify)
72 changes: 62 additions & 10 deletions addon/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,70 @@
import * as slugfyFunction from 'slugify'
import simplePinyin from 'simple-pinyin'
import getSlug from 'speakingurl'
import unorm from 'unorm'
import emoji from 'emoji.json'

function removeDiacritics(str) {
// eslint-disable-next-line
return unorm.nfd(str).replace(/[\u0300-\u036f]/g, '')
const UNWANTED_OPTIONS = [
'strict', // options from slugify dependency
]

function removeDiacritics(str = '') {
return str.normalize('NFKD').replace(/[\u0300-\u036F]/g, '')
}

function _parseLocale(_locale) {
if (_locale && typeof _locale === 'string') {
if (_locale.includes('-')) {
return _locale.split('-')[0]
}
if (_locale.includes('_')) {
return _locale.split('_')[0]
}
}
return _locale
}

export default function slugify(str, options = {}) {
return getSlug(
simplePinyin(removeDiacritics(str.split('_').join('-')), {
export default function slugify(str = '', options = {}) {
UNWANTED_OPTIONS.forEach((key) => {
if (options[key] !== undefined) {
delete options[key]
}
})
let locale = _parseLocale(options.locale)
if (locale && typeof locale === 'string') {
if (locale.includes('-')) {
locale = locale.split('-')[0]
}
if (locale.includes('_')) {
locale = locale.split('_')[0]
}
}
let result = removeDiacritics(str)
if (options.pinyin) {
result = simplePinyin(result, {
matchFullText: 'original',
}).reduce((acc, b) => (b.length === 1 ? `${acc}${b}` : `${acc} ${b}`), ''),
options
}).reduce((acc, b) => (b.length === 1 ? `${acc}${b}` : `${acc} ${b}`), '')
}
if (options.emoji) {
emoji.forEach((emoji) => {
result = result.replaceAll(emoji.char, ` ${emoji.name} `)
})
}
return slugfyFunction(
result,
Object.assign(
{
replacement: '-',
lower: true,
strict: true,
locale: undefined,
trim: true,
pinyin: false,
emoji: false,
},
options,
{
locale,
}
)
)
}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
"ember-auto-import": "^1.11.3",
"ember-cli-babel": "^7.26.6",
"ember-cli-htmlbars": "^6.0.0",
"emoji.json": "^13.1.0",
"simple-pinyin": "^4.0.0",
"speakingurl": "^14.0.1",
"unorm": "^1.6.0"
"slugify": "^1.6.5"
},
"devDependencies": {
"@ember/optional-features": "^2.0.0",
Expand Down
8 changes: 8 additions & 0 deletions tests/dummy/app/styles/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.block {
margin-bottom: 40px;
}

.code {
font-weight: bold;
font-family: monospace;
}
29 changes: 27 additions & 2 deletions tests/dummy/app/templates/application.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
{{page-title "Dummy"}}
{{page-title "ember-slugify"}}

<h2 id="title">Welcome to Ember</h2>
<h2 id="title">Welcome to ember-slugify</h2>

<div class="block">
<p class="code">\{{slugify "Le Théâtre"}}</p>
<p>{{slugify "Le Théâtre"}}</p>
</div>

<div class="block">
<p class="code">\{{slugify "I ♥ New York"}}</p>
<p>{{slugify "I ♥ New York"}}</p>
</div>

<div class="block">
<p class="code">\{{slugify "你好你怎么样 monsieur" (hash pinyin=true)}}</p>
<p>{{slugify "你好你怎么样 monsieur" (hash pinyin=true)}}</p>
</div>

<div class="block">
<p class="code">\{{slugify "🇫🇷❤️🥖➕🍷" (hash emoji=true)}}</p>
<p>{{slugify "🇫🇷❤️🥖➕🍷" (hash emoji=true)}}</p>
</div>

<div class="block">
<p class="code">\{{remove-diacritics "Le Théâtre"}}</p>
<p>{{remove-diacritics "Le Théâtre"}}</p>
</div>

{{outlet}}
4 changes: 4 additions & 0 deletions tests/integration/helpers/remove-diacritics-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ module('Integration | Helper | remove-diacritics', function (hooks) {
setupRenderingTest(hooks)

test('it removes diacritics', async function (assert) {
await render(hbs`{{remove-diacritics undefined}}`)
assert.dom().hasText('')
await render(hbs`{{remove-diacritics ''}}`)
assert.dom().hasText('')
await render(hbs`{{remove-diacritics 'é è à ù ç č Ž ñ'}}`)
assert.dom().hasText('e e a u c c Z n')
await render(hbs`{{remove-diacritics 'Le Théâtre'}}`)
assert.dom().hasText('Le Theatre')
})
})
25 changes: 24 additions & 1 deletion tests/integration/helpers/slugify-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,36 @@ module('Integration | Helper | slugify', function (hooks) {
setupRenderingTest(hooks)

test('it slugifies', async function (assert) {
await render(hbs`{{slugify undefined}}`)
assert.dom().hasText('')
await render(hbs`{{slugify ''}}`)
assert.dom().hasText('')
await render(hbs`{{slugify 'bonjour'}}`)
assert.dom().hasText('bonjour')
await render(hbs`{{slugify 'annyǒng hashimnikka'}}`)
assert.dom().hasText('annyong-hashimnikka')
await render(hbs`{{slugify 'Bon jOuR Töi 1337 '}}`)
await render(hbs`{{slugify 'Bon jOuR Töi 1337 : () ? '}}`)
assert.dom().hasText('bon-jour-toi-1337')
await render(hbs`{{slugify 'I ♥ New York'}}`)
assert.dom().hasText('i-love-new-york')
})

test('it slugifies with options', async function (assert) {
await render(hbs`{{slugify 'Bon jOuR Töi 1337' (hash replacement='#')}}`)
assert.dom().hasText('bon#jour#toi#1337')
await render(hbs`{{slugify 'Bon jOuR Töi 1337' (hash lower=false)}}`)
assert.dom().hasText('Bon-jOuR-Toi-1337')
await render(hbs`{{slugify "vive l'♥" (hash locale='fr')}}`)
assert.dom().hasText('vive-lamour')
await render(hbs`{{slugify "vive l'♥" (hash locale='fr-CA')}}`)
assert.dom().hasText('vive-lamour')
await render(hbs`{{slugify "vive l'♥" (hash locale='fr_CA')}}`)
assert.dom().hasText('vive-lamour')
await render(hbs`{{slugify ' keep the spaces ' (hash trim=false)}}`)
assert.dom().hasText('-keep-the-spaces-')
await render(hbs`{{slugify '你好你怎么样 monsieur' (hash pinyin=true)}}`)
assert.dom().hasText('ni-hao-ni-zen-me-yang-monsieur')
await render(hbs`{{slugify '🇫🇷❤️🥖➕🍷' (hash emoji=true)}}`)
assert.dom().hasText('flag-france-red-heart-baguette-bread-plus-wine-glass')
})
})
30 changes: 26 additions & 4 deletions tests/unit/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,47 @@ import { module, test } from 'qunit'

module('Unit | Utility | slug', function () {
test('tests on removeDiacritics', function (assert) {
assert.strictEqual(removeDiacritics(), '')
assert.strictEqual(removeDiacritics(''), '')
assert.strictEqual(removeDiacritics('é è à ù ç č Ž ñ'), 'e e a u c c Z n')
assert.strictEqual(removeDiacritics('Le Théâtre'), 'Le Theatre')
})

test('tests on slugify', function (assert) {
assert.strictEqual(slugify(), '')
assert.strictEqual(slugify(''), '')
assert.strictEqual(slugify('bonjour'), 'bonjour')
assert.strictEqual(slugify('annyǒng hashimnikka'), 'annyong-hashimnikka')
assert.strictEqual(slugify('Bon jOuR Töi 1337 '), 'bon-jour-toi-1337')
assert.strictEqual(
slugify('你好你怎么样 monsieur'),
'ni-hao-ni-zen-me-yang-monsieur'
slugify('Bon jOuR Töi 1337 : () ? '),
'bon-jour-toi-1337'
)
assert.strictEqual(slugify('I ♥ New York'), 'i-love-new-york')
})

test('tests on slugify with options', function (assert) {
assert.strictEqual(
slugify('Bon jOuR Töi 1337', { separator: '#' }),
slugify('Bon jOuR Töi 1337', { replacement: '#' }),
'bon#jour#toi#1337'
)
assert.strictEqual(
slugify('Bon jOuR Töi 1337', { lower: false }),
'Bon-jOuR-Toi-1337'
)
assert.strictEqual(slugify("vive l'♥", { locale: 'fr' }), 'vive-lamour')
assert.strictEqual(slugify("vive l'♥", { locale: 'fr-CA' }), 'vive-lamour')
assert.strictEqual(slugify("vive l'♥", { locale: 'fr_CA' }), 'vive-lamour')
assert.strictEqual(
slugify(' keep the spaces ', { trim: false }),
'-keep-the-spaces-'
)
assert.strictEqual(
slugify('你好你怎么样 monsieur', { pinyin: true }),
'ni-hao-ni-zen-me-yang-monsieur'
)
assert.strictEqual(
slugify('🇫🇷❤️🥖➕🍷', { emoji: true }),
'flag-france-red-heart-baguette-bread-plus-wine-glass'
)
})
})
Loading

0 comments on commit 5eb0199

Please sign in to comment.