Skip to content

Commit

Permalink
Add preserveCharacters option (#70)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
aegatlin and sindresorhus authored Jan 30, 2023
1 parent 48a9112 commit f235b34
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
19 changes: 19 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,25 @@ export interface Options {
```
*/
readonly preserveTrailingDash?: boolean;

/**
Preserve certain characters.
It cannot contain the `separator`.
For example, if you want to slugify URLs, but preserve the HTML fragment `#` character, you could set `preserveCharacters: ['#']`.
@default []
@example
```
import slugify from '@sindresorhus/slugify';
slugify('foo_bar#baz', {preserveCharacters: ['#']});
//=> 'foo-bar#baz'
```
*/
readonly preserveCharacters?: string[];
}

/**
Expand Down
21 changes: 19 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ const removeMootSeparators = (string, separator) => {
.replace(new RegExp(`^${escapedSeparator}|${escapedSeparator}$`, 'g'), '');
};

const buildPatternSlug = options => {
let negationSetPattern = 'a-z\\d';
negationSetPattern += options.lowercase ? '' : 'A-Z';

if (options.preserveCharacters.length > 0) {
for (const character of options.preserveCharacters) {
if (character === options.separator) {
throw new Error(`The separator character \`${options.separator}\` cannot be included in preserved characters: ${options.preserveCharacters}`);
}

negationSetPattern += escapeStringRegexp(character);
}
}

return new RegExp(`[^${negationSetPattern}]+`, 'g');
};

export default function slugify(string, options) {
if (typeof string !== 'string') {
throw new TypeError(`Expected a string, got \`${typeof string}\``);
Expand All @@ -34,6 +51,7 @@ export default function slugify(string, options) {
customReplacements: [],
preserveLeadingUnderscore: false,
preserveTrailingDash: false,
preserveCharacters: [],
...options
};

Expand All @@ -51,11 +69,10 @@ export default function slugify(string, options) {
string = decamelize(string);
}

let patternSlug = /[^a-zA-Z\d]+/g;
const patternSlug = buildPatternSlug(options);

if (options.lowercase) {
string = string.toLowerCase();
patternSlug = /[^a-z\d]+/g;
}

string = string.replace(patternSlug, options.separator);
Expand Down
18 changes: 18 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,24 @@ slugify('foo-bar-', {preserveTrailingDash: true});
//=> 'foo-bar-'
```

##### preserveCharacters

Type: `string[]`\
Default: `[]`

Preserve certain characters.

It cannot contain the `separator`.

For example, if you want to slugify URLs, but preserve the HTML fragment `#` character.

```js
import slugify from '@sindresorhus/slugify';

slugify('foo_bar#baz', {preserveCharacters: ['#']});
//=> 'foo-bar#baz'
```

### slugifyWithCounter()

Returns a new instance of `slugify(string, options?)` with a counter to handle multiple occurrences of the same string.
Expand Down
16 changes: 16 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,19 @@ test('counter', t => {
t.is(slugify2(''), '');
t.is(slugify2(''), '');
});

test('preserve characters', t => {
t.is(slugify('foo#bar', {preserveCharacters: []}), 'foo-bar');
t.is(slugify('foo.bar', {preserveCharacters: []}), 'foo-bar');
t.is(slugify('foo?bar ', {preserveCharacters: ['#']}), 'foo-bar');
t.is(slugify('foo#bar', {preserveCharacters: ['#']}), 'foo#bar');
t.is(slugify('foo_bar#baz', {preserveCharacters: ['#']}), 'foo-bar#baz');
t.is(slugify('foo.bar#baz-quux', {preserveCharacters: ['.', '#']}), 'foo.bar#baz-quux');
t.is(slugify('foo.bar#baz-quux', {separator: '.', preserveCharacters: ['-']}), 'foo.bar.baz-quux');
t.throws(() => {
slugify('foo', {separator: '-', preserveCharacters: ['-']});
});
t.throws(() => {
slugify('foo', {separator: '.', preserveCharacters: ['.']});
});
});

0 comments on commit f235b34

Please sign in to comment.