diff --git a/index.d.ts b/index.d.ts index d2501a4..7d359a5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -112,6 +112,26 @@ export interface Options { ``` */ readonly preserveLeadingUnderscore?: boolean; + + /** + If your string ends with a dash, it will be preserved in the slugified string. + + For example, using slugify on an input field would allow for validation while not preventing the user from writing a slug. + + @default false + + @example + ``` + import slugify from '@sindresorhus/slugify'; + + slugify('foo-bar-'); + //=> 'foo-bar' + + slugify('foo-bar-', {preserveTrailingDash: true}); + //=> 'foo-bar-' + ``` + */ + readonly preserveTrailingDash?: boolean; } /** diff --git a/index.js b/index.js index b6fcbb0..9172636 100644 --- a/index.js +++ b/index.js @@ -31,10 +31,12 @@ export default function slugify(string, options) { decamelize: true, customReplacements: [], preserveLeadingUnderscore: false, + preserveTrailingDash: false, ...options }; const shouldPrependUnderscore = options.preserveLeadingUnderscore && string.startsWith('_'); + const shouldAppendDash = options.preserveTrailingDash && string.endsWith('-'); const customReplacements = new Map([ ...builtinOverridableReplacements, @@ -64,6 +66,10 @@ export default function slugify(string, options) { string = `_${string}`; } + if (shouldAppendDash) { + string = `${string}-`; + } + return string; } diff --git a/index.test-d.ts b/index.test-d.ts index a6f7af5..f36ac61 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -7,6 +7,7 @@ expectType(slugify('Déjà Vu!', {lowercase: false})); expectType(slugify('fooBar', {decamelize: false})); expectType(slugify('I ♥ 🦄 & 🐶', {customReplacements: [['🐶', 'dog']]})); expectType(slugify('_foo_bar', {preserveLeadingUnderscore: true})); +expectType(slugify('foo-bar-', {preserveTrailingDash: true})); // Counter expectType(slugifyWithCounter()('I ♥ Dogs')); diff --git a/readme.md b/readme.md index d95edca..8ffde15 100644 --- a/readme.md +++ b/readme.md @@ -167,6 +167,25 @@ slugify('_foo_bar', {preserveLeadingUnderscore: true}); //=> '_foo-bar' ``` +##### preserveTrailingDash + +Type: `boolean`\ +Default: `false` + +If your string ends with a dash, it will be preserved in the slugified string. + +For example, using slugify on an input field would allow for validation while not preventing the user from writing a slug. + +```js +import slugify from '@sindresorhus/slugify'; + +slugify('foo-bar-'); +//=> 'foo-bar' + +slugify('foo-bar-', {preserveTrailingDash: true}); +//=> 'foo-bar-' +``` + ### slugifyWithCounter() Returns a new instance of `slugify(string, options?)` with a counter to handle multiple occurrences of the same string. diff --git a/test.js b/test.js index 10370a3..201ee6c 100644 --- a/test.js +++ b/test.js @@ -133,6 +133,14 @@ test('leading underscore', t => { t.is(slugify('____-___foo__bar', {preserveLeadingUnderscore: true}), '_foo-bar'); }); +test('trailing dash', t => { + t.is(slugify('foo bar-', {preserveTrailingDash: true}), 'foo-bar-'); + t.is(slugify('foo-bar--', {preserveTrailingDash: true}), 'foo-bar-'); + t.is(slugify('foo-bar -', {preserveTrailingDash: true}), 'foo-bar-'); + t.is(slugify('foo-bar - ', {preserveTrailingDash: true}), 'foo-bar'); + t.is(slugify('foo-bar ', {preserveTrailingDash: true}), 'foo-bar'); +}); + test('counter', t => { const slugify = slugifyWithCounter(); t.is(slugify('foo bar'), 'foo-bar');