Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(text/unstable): add slugify() function #5646

Merged
merged 16 commits into from
Aug 14, 2024
1 change: 1 addition & 0 deletions text/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"./closest-string": "./closest_string.ts",
"./compare-similarity": "./compare_similarity.ts",
"./levenshtein-distance": "./levenshtein_distance.ts",
"./slugify": "./slugify.ts",
"./to-camel-case": "./to_camel_case.ts",
"./to-constant-case": "./to_constant_case.ts",
"./to-kebab-case": "./to_kebab_case.ts",
Expand Down
1 change: 1 addition & 0 deletions text/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ export * from "./to_constant_case.ts";
export * from "./to_kebab_case.ts";
export * from "./to_pascal_case.ts";
export * from "./to_snake_case.ts";
export * from "./slugify.ts";
30 changes: 30 additions & 0 deletions text/slugify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

/**
* **UNSTABLE**: New API, yet to be vetted.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future reference, this being the first paragraph means it's used as the summary for this symbol. Please ensure the description is always first for symbols.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same as what CLI does. https://docs.deno.com/api/deno/all_symbols

If you suggest something different, I think you should also suggest the same to CLI docs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*
* Converts a string into {@link https://en.wikipedia.org/wiki/Clean_URL#Slug a slug}.
*
* @example Usage
* ```ts
* import { slugify } from "@std/text/slugify";
* import { assertEquals } from "@std/assert";
*
* assertEquals(slugify("hello world"), "hello-world");
* assertEquals(slugify("déjà vu"), "deja-vu");
* ```
*
* @param input The string that is going to be converted into a slug
* @returns The string as a slug
*
* @experimental
*/
export function slugify(input: string): string {
return input
.trim()
.normalize("NFD")
.replaceAll(/[^a-zA-Z0-9\s-]/g, "")
.replaceAll(/\s+|-+/g, "-")
.replaceAll(/^-+|-+$/g, "")
.toLowerCase();
}
58 changes: 58 additions & 0 deletions text/slugify_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "@std/assert/equals";
import { slugify } from "./slugify.ts";

Deno.test("slugify() returns kebabcase", () => {
assertEquals(slugify("hello world"), "hello-world");
});
Deno.test("slugify() returns lowercase", () => {
assertEquals(slugify("Hello World"), "hello-world");
});

Deno.test("slugify() handles whitespaces", () => {
assertEquals(slugify(" Hello World "), "hello-world");
assertEquals(slugify("Hello\tWorld"), "hello-world");
assertEquals(slugify("Hello\nWorld"), "hello-world");
assertEquals(slugify("Hello\r\nWorld"), "hello-world");
});

Deno.test("slugify() replaces diacritic characters", () => {
assertEquals(slugify("déjà vu"), "deja-vu");
assertEquals(slugify("Cliché"), "cliche");
assertEquals(slugify("façade"), "facade");
assertEquals(slugify("résumé"), "resume");
});

Deno.test("slugify() handles dashes", () => {
assertEquals(slugify("-Hello-World-"), "hello-world");
assertEquals(slugify("--Hello--World--"), "hello-world");
});

Deno.test("slugify() handles empty String", () => {
assertEquals(slugify(""), "");
});

Deno.test("slugify() removes unknown special characters", () => {
assertEquals(slugify("hello ~ world"), "hello-world");

assertEquals(
slugify("Elon Musk considers move to Mars"),
"elon-musk-considers-move-to-mars",
);
assertEquals(
slugify("Fintech startups raised $34B in 2019"),
"fintech-startups-raised-34b-in-2019",
);
assertEquals(
slugify("Shopify joins Facebook’s cryptocurrency Libra Association"),
"shopify-joins-facebooks-cryptocurrency-libra-association",
);
assertEquals(
slugify("What is a slug and how to optimize it?"),
"what-is-a-slug-and-how-to-optimize-it",
);
assertEquals(
slugify("Bitcoin soars past $33,000, its highest ever"),
"bitcoin-soars-past-33000-its-highest-ever",
);
});