js-01-slugify
1.000
Challenge · difficulty 1/5
# Slugify a title
Implement an ES module **`solution.js`** exporting a single function:
```js
export function slugify(input) { /* ... */ }
```
Convert a human title string into a URL slug:
- Lowercase the whole string.
- Treat **any character that is not an ASCII letter (`a–z`) or digit (`0–9`) as a separator** —
this includes spaces, punctuation, underscores, and non-ASCII letters.
- Replace each **run** of one or more separators with a **single** hyphen (`-`).
- Strip any leading or trailing hyphens from the result.
Return the resulting slug (a string). An input made entirely of separators returns `""`.
Examples:
```js
slugify("Hello World") // => "hello-world"
slugify(" Hello, World! ") // => "hello-world"
slugify("already-clean") // => "already-clean"
slugify("Top 10 Tips") // => "top-10-tips"
slugify("a---b__c") // => "a-b-c"
slugify("@#$%") // => ""
```
tests/solution.test.js
import { test } from "node:test";
import { strict as assert } from "node:assert";
import { slugify } from "./solution.js";
test("spaces become single hyphens", () => {
assert.equal(slugify("Hello World"), "hello-world");
});
test("punctuation collapses and ends are trimmed", () => {
assert.equal(slugify(" Hello, World! "), "hello-world");
});
test("already-clean input is unchanged", () => {
assert.equal(slugify("already-clean"), "already-clean");
});
test("digits are preserved", () => {
assert.equal(slugify("Top 10 Tips"), "top-10-tips");
});
test("runs of mixed separators collapse to one hyphen", () => {
assert.equal(slugify("a---b__c"), "a-b-c");
});
test("leading and trailing junk is trimmed", () => {
assert.equal(slugify("--Foo Bar--"), "foo-bar");
});
test("all-separator input becomes empty string", () => {
assert.equal(slugify("@#$%"), "");
});
test("empty string stays empty", () => {
assert.equal(slugify(""), "");
});
test("non-ASCII letters act as separators", () => {
assert.equal(slugify("café crème"), "caf-cr-me");
});
System prompt
You are an expert programmer. Solve the task exactly as specified. Output your solution as fenced code blocks using the required file name(s) and the exact function/type signatures requested. Prefer correctness; do not include prose outside code unless asked.
Proposed solution
```js
export function slugify(input) {
// Lowercase the whole string
const lower = input.toLowerCase();
// Replace non-alphanumeric characters with a hyphen
// This handles spaces, punctuation, underscores, and non-ASCII letters
const replaced = lower.replace(/[^a-z0-9]/g, '-');
// Replace runs of separators with a single hyphen
const collapsed = replaced.replace(/-+/g, '-');
// Strip leading and trailing hyphens
return collapsed.replace(/^-+|-+$/g, '');
}
```Test output (stdout)
TAP version 13 # Subtest: spaces become single hyphens ok 1 - spaces become single hyphens --- duration_ms: 0.457534 type: 'test' ... # Subtest: punctuation collapses and ends are trimmed ok 2 - punctuation collapses and ends are trimmed --- duration_ms: 0.069361 type: 'test' ... # Subtest: already-clean input is unchanged ok 3 - already-clean input is unchanged --- duration_ms: 0.046051 type: 'test' ... # Subtest: digits are preserved ok 4 - digits are preserved --- duration_ms: 0.04168 type: 'test' ... # Subtest: runs of mixed separators collapse to one hyphen ok 5 - runs of mixed separators collapse to one hyphen --- duration_ms: 0.076061 type: 'test' ... # Subtest: leading and trailing junk is trimmed ok 6 - leading and trailing junk is trimmed --- duration_ms: 0.043281 type: 'test' ... # Subtest: all-separator input becomes empty string ok 7 - all-separator input becomes empty string --- duration_ms: 0.04101 type: 'test' ... # Subtest: empty string stays empty ok 8 - empty string stays empty --- duration_ms: 0.038101 type: 'test' ... # Subtest: non-ASCII letters act as separators ok 9 - non-ASCII letters act as separators --- duration_ms: 0.0554 type: 'test' ... 1..9 # tests 9 # suites 0 # pass 9 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 27.839813