Nanyx

String casing

Convert between camel, pascal, kebab, snake, title and sentence case.

module casing

import nanyx/text.regex

export type Casing =
  | #camel
  | #pascal
  | #kebab
  | #snake
  | #title
  | #sentence

-- Split on case changes, underscores, dashes and whitespace
def splitWords: string -> list(string) = { input ->
  input \Regex.split('(?=[A-Z])|_|-|\s') \filter { != "" }
}

def capitalize: string -> string = { word ->
  match word \chars
    | [] -> ""
    | [first, ...rest] -> first \toUpper ++ (rest \String.join("") \toLower)
}

export def rejoin: (list(string), Casing) -> string = { words, casing ->
  match casing
    | #kebab -> words \map { .toLower } \String.join("-")
    | #snake -> words \map { .toLower } \String.join("_")
    | #pascal -> words \map(capitalize) \String.join("")
    | #title -> words \map(capitalize) \String.join(" ")
    | #camel ->
      match words
        | [] -> ""
        | [first, ...rest] -> first \toLower ++ (rest \map(capitalize) \String.join(""))
    | #sentence ->
      match words
        | [] -> ""
        | [first, ...rest] -> capitalize(first) ++ " " ++ (rest \map { .toLower } \String.join(" "))
}

export def convert: (string, Casing) -> string = { input, casing ->
  rejoin(splitWords(input), casing)
}

@entry
def main = {
  def tests = ["oneTwoThree", "one_two_three", "one-two-three", "one two three"]

  for tests | test ->
    for [#camel, #pascal, #kebab, #snake, #title, #sentence] | casing ->
      println("{test} -> {convert(test, casing)}")
}

This program lives in the repository as examples/stringTransformation.nyx.