slugify

    Utility URL functions for MoonBit

    url
    slug
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    6 months ago
    Downloads
    18

    Dependencies

    #sennenki/slugify

    A lightweight slug utility for MoonBit.

    #Features

    • Single API entry: slugify(input, options?, rules?)
    • Rule set composition: RuleSet::new, RuleSet::extend, RuleSet::merge
    • Unicode normalization before slugging: NFKD
    • Combining marks are stripped after normalization
    • Supports supplementary Unicode characters (e.g. emoji code points)

    #Basic Usage

    assert_eq(slugify("Hello, World!"), "hello-world")
    assert_eq(slugify("Cr\u{00E8}me br\u{00FB}l\u{00E9}e"), "creme-brulee")

    #Unicode Normalization

    slugify normalizes input with NFKD and then removes combining marks.

    assert_eq(slugify("Cafe\u{0301}"), "cafe")
    assert_eq(slugify("ABC 123"), "abc-123")

    #Custom Options

    let options : SlugOptions = {
    separator: '_',
    lowercase: false,
    trim_separator: true,
    max_length: Some(7),
    ascii_only: true,
    fallback: Some("n-a"),
    }
    assert_eq(slugify("Hello MoonBit", options~), "Hello_M")
    assert_eq(slugify("中文标题", options~), "n-a")

    #Custom Rules

    let rules = RuleSet::default().extend(char_map=[('\u{2764}', "love")])
    assert_eq(slugify("I \u{2764} MoonBit", rules~), "i-love-moonbit")

    word_map supports boundary-aware phrase replacement with longest-match priority.

    let rules = RuleSet::new(word_map=[("new", "n"), ("new york", "ny")])
    assert_eq(slugify("new york city", rules~), "ny-city")
    assert_eq(slugify("concatenate cat", rules=RuleSet::new(word_map=[("cat", "feline")])) , "concatenate-feline")

    char_map uses right-hand precedence when merged.

    let base = RuleSet::new(char_map=[('\u{2764}', "love")])
    let overlay = RuleSet::new(char_map=[('\u{2764}', "heart")])
    let merged = base.merge(overlay)
    assert_eq(slugify("I \u{2764}", rules=merged), "i-heart")

    #Behavior Notes

    • Default ascii_only is true, so non-ASCII code points (for example CJK and emoji) are removed unless mapped by rules.
    • Processing order is: normalization (NFKD) -> combining-mark stripping -> word_map -> character-level rules.
    • word_map only matches at word boundaries and chooses the longest candidate when multiple keys match.
    • Normalization happens before rule matching, so decomposed and precomposed forms behave consistently.
    • If the final slug is empty, slugify returns fallback when provided, otherwise "".

    Buckets

    type Buckets[T]

    RuleSet

    pub struct RuleSet {
    raw_word_map : Array[(String, String)]
    raw_char_map : Array[(Char, String)]
    raw_drop_chars : Array[Char]
    raw_separator_chars : Array[Char]
    word_map_buckets : Buckets[(Array[Char], String)]
    char_map_buckets : Buckets[(Char, String)]
    drop_buckets : Buckets[Char]
    separator_buckets : Buckets[Char]
    }

    impl Default for RuleSet

    RuleSet::extend

    fn RuleSet::extend(self : RuleSet, word_map? : Array[(String, String)], char_map? : Array[(Char, String)], drop_chars? : Array[Char], separator_chars? : Array[Char]) -> RuleSet

    RuleSet::merge

    fn RuleSet::merge(self : RuleSet, other : RuleSet) -> RuleSet

    RuleSet::new

    fn RuleSet::new(word_map? : Array[(String, String)], char_map? : Array[(Char, String)], drop_chars? : Array[Char], separator_chars? : Array[Char]) -> RuleSet

    SlugOptions

    pub(all) struct SlugOptions {
    separator : Char
    lowercase : Bool
    trim_separator : Bool
    max_length : Int?
    ascii_only : Bool
    fallback : String?
    }

    slugify

    fn slugify(input : String, options? : SlugOptions, rules? : RuleSet) -> String

    Source Files