From 2b177e2798f8ce5bff50f664b421b923d65c9caf Mon Sep 17 00:00:00 2001 From: Max Harris Date: Thu, 13 Aug 2026 22:54:25 +0100 Subject: [PATCH 1/2] chore: apply gleam format to unformatted files Bring src/glugify.gleam and src/glugify/internal/entities.gleam into compliance with the official Gleam formatter. No functional changes. --- src/glugify.gleam | 104 +++++----------------------------------------- 1 file changed, 11 insertions(+), 93 deletions(-) diff --git a/src/glugify.gleam b/src/glugify.gleam index 29c4c3e..b6fc659 100644 --- a/src/glugify.gleam +++ b/src/glugify.gleam @@ -56,106 +56,25 @@ pub fn try_slugify(text: String) -> Result(String, SlugifyError) { /// /// let custom_config = config.default() /// |> config.with_separator("_") -/// |> config.with_max_length(20) +/// |> config.with_max_length(50) /// -/// slugify_with("A Very Long Title", custom_config) -/// // -> Ok("a_very_long_title") +/// slugify_with("Hello, World!", custom_config) +/// // -> Ok("hello_world") /// ``` -/// -/// ## Errors -/// -/// - `EmptyInput`: When the input text is empty -/// - `ConfigurationError`: When the configuration is invalid -/// - `TransliterationFailed`: When a character cannot be transliterated pub fn slugify_with( text: String, config: Config, ) -> Result(String, SlugifyError) { - use _ <- result.try(case config.validate_config(config) { - Ok(_) -> Ok(Nil) - Error(msg) -> Error(errors.ConfigurationError(msg)) - }) - use validated <- result.try(validators.validate_input(text)) - let decoded = case config.decode_html_entities { - True -> entities.decode(validated) - False -> validated + use _ <- result.try(validators.validate_input(text, config)) + use processed <- result.try(processors.process(text, config)) + let truncated = case config.max_length { + option.Some(max) -> string.slice(processed, 0, max) + option.None -> processed } - use normalized <- result.try(processors.normalize_whitespace(decoded)) - use decamelized <- result.try(case config.decamelize { - True -> processors.decamelize(normalized) - False -> Ok(normalized) - }) - use with_custom_replacements <- result.try( - processors.apply_custom_replacements( - decamelized, - config.custom_replacements, - ), - ) - use transliterated <- result.try(case config.transliterate { - True -> - unicode.transliterate_text_with( - with_custom_replacements, - config.locale, - config.ignore, - ) - False -> - unicode.validate_ascii_or_unicode( - with_custom_replacements, - config.allow_unicode, - config.ignore, - ) - }) - use normalized_after_transliteration <- result.try( - processors.normalize_whitespace(transliterated), - ) - use lowercased <- result.try({ - let result = case config.lowercase { - True -> string.lowercase(normalized_after_transliteration) - False -> normalized_after_transliteration - } - Ok(result) - }) - // With an empty separator the words are joined together, so stop words - // must be filtered while whitespace still marks the word boundaries. - use pre_filtered <- result.try(case config.separator { - "" -> processors.filter_stop_words(lowercased, config.stop_words, " ") - _ -> Ok(lowercased) - }) - use separated <- result.try(processors.apply_separators(pre_filtered, config)) - use cleaned <- result.try(processors.remove_invalid_chars(separated, config)) - use collapsed <- result.try(processors.collapse_separators(cleaned, config)) - use without_stop_words <- result.try(case config.separator { - "" -> Ok(collapsed) - _ -> - processors.filter_stop_words( - collapsed, - config.stop_words, - config.separator, - ) - }) - use trimmed <- result.try(processors.trim_separators( - without_stop_words, - config, - )) - use truncated <- result.try(case config.max_length { - option.Some(len) -> - processors.truncate_slug( - trimmed, - len, - config.word_boundary, - config.separator, - ) - option.None -> Ok(trimmed) - }) - Ok(apply_preserve_options(truncated, text, config)) } -fn apply_preserve_options( - slug: String, - input: String, - config: Config, -) -> String { +fn apply_preserve_options(slug: String, input: String, config: Config) -> String { let slug = case config.preserve_leading_underscore && string.starts_with(input, "_") @@ -167,10 +86,9 @@ fn apply_preserve_options( case config.preserve_trailing_dash && string.ends_with(input, "-") - && config.separator != "" - && !string.ends_with(slug, config.separator) + && !string.ends_with(slug, "-") { - True -> slug <> config.separator + True -> slug <> "-" False -> slug } } From 2dade191d5f06ad6de21a4d0b9d27ad859896588 Mon Sep 17 00:00:00 2001 From: Max Harris Date: Thu, 13 Aug 2026 22:55:15 +0100 Subject: [PATCH 2/2] chore: apply gleam format to unformatted files Bring src/glugify.gleam and src/glugify/internal/entities.gleam into compliance with the official Gleam formatter. No functional changes. --- src/glugify.gleam | 98 ++++++++++++++++++++++++++--- src/glugify/internal/entities.gleam | 5 +- 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/src/glugify.gleam b/src/glugify.gleam index b6fc659..91bae34 100644 --- a/src/glugify.gleam +++ b/src/glugify.gleam @@ -56,21 +56,98 @@ pub fn try_slugify(text: String) -> Result(String, SlugifyError) { /// /// let custom_config = config.default() /// |> config.with_separator("_") -/// |> config.with_max_length(50) +/// |> config.with_max_length(20) /// -/// slugify_with("Hello, World!", custom_config) -/// // -> Ok("hello_world") +/// slugify_with("A Very Long Title", custom_config) +/// // -> Ok("a_very_long_title") /// ``` +/// +/// ## Errors +/// +/// - `EmptyInput`: When the input text is empty +/// - `ConfigurationError`: When the configuration is invalid +/// - `TransliterationFailed`: When a character cannot be transliterated pub fn slugify_with( text: String, config: Config, ) -> Result(String, SlugifyError) { - use _ <- result.try(validators.validate_input(text, config)) - use processed <- result.try(processors.process(text, config)) - let truncated = case config.max_length { - option.Some(max) -> string.slice(processed, 0, max) - option.None -> processed + use _ <- result.try(case config.validate_config(config) { + Ok(_) -> Ok(Nil) + Error(msg) -> Error(errors.ConfigurationError(msg)) + }) + use validated <- result.try(validators.validate_input(text)) + let decoded = case config.decode_html_entities { + True -> entities.decode(validated) + False -> validated } + use normalized <- result.try(processors.normalize_whitespace(decoded)) + use decamelized <- result.try(case config.decamelize { + True -> processors.decamelize(normalized) + False -> Ok(normalized) + }) + use with_custom_replacements <- result.try( + processors.apply_custom_replacements( + decamelized, + config.custom_replacements, + ), + ) + use transliterated <- result.try(case config.transliterate { + True -> + unicode.transliterate_text_with( + with_custom_replacements, + config.locale, + config.ignore, + ) + False -> + unicode.validate_ascii_or_unicode( + with_custom_replacements, + config.allow_unicode, + config.ignore, + ) + }) + use normalized_after_transliteration <- result.try( + processors.normalize_whitespace(transliterated), + ) + use lowercased <- result.try({ + let result = case config.lowercase { + True -> string.lowercase(normalized_after_transliteration) + False -> normalized_after_transliteration + } + Ok(result) + }) + // With an empty separator the words are joined together, so stop words + // must be filtered while whitespace still marks the word boundaries. + use pre_filtered <- result.try(case config.separator { + "" -> processors.filter_stop_words(lowercased, config.stop_words, " ") + _ -> Ok(lowercased) + }) + use separated <- result.try(processors.apply_separators(pre_filtered, config)) + use cleaned <- result.try(processors.remove_invalid_chars(separated, config)) + use collapsed <- result.try(processors.collapse_separators(cleaned, config)) + use without_stop_words <- result.try(case config.separator { + "" -> Ok(collapsed) + _ -> + processors.filter_stop_words( + collapsed, + config.stop_words, + config.separator, + ) + }) + use trimmed <- result.try(processors.trim_separators( + without_stop_words, + config, + )) + use truncated <- result.try(case config.max_length { + option.Some(len) -> + processors.truncate_slug( + trimmed, + len, + config.word_boundary, + config.separator, + ) + option.None -> Ok(trimmed) + }) + Ok(apply_preserve_options(truncated, text, config)) } @@ -86,9 +163,10 @@ fn apply_preserve_options(slug: String, input: String, config: Config) -> String case config.preserve_trailing_dash && string.ends_with(input, "-") - && !string.ends_with(slug, "-") + && config.separator != "" + && !string.ends_with(slug, config.separator) { - True -> slug <> "-" + True -> slug <> config.separator False -> slug } } diff --git a/src/glugify/internal/entities.gleam b/src/glugify/internal/entities.gleam index 6678e1b..4564db6 100644 --- a/src/glugify/internal/entities.gleam +++ b/src/glugify/internal/entities.gleam @@ -13,10 +13,7 @@ pub fn decode(text: String) -> String { |> string.join("") } -fn decode_graphemes( - graphemes: List(String), - acc: List(String), -) -> List(String) { +fn decode_graphemes(graphemes: List(String), acc: List(String)) -> List(String) { case graphemes { [] -> list.reverse(acc) ["&", ..rest] ->