Source file casing.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
module ForTesting = struct
  let is_lower c = c = Char.lowercase_ascii c

  let trim_trailing_underscores s =
    let rec loop found idx =
      if idx < 0 then (found, -1)
      else if s.[idx] = '_' then loop true (pred idx)
      else (found, idx)
    in
    let found, last_nonunderscore = loop false (pred (String.length s)) in
    if found then String.sub s 0 (succ last_nonunderscore) else s

  let next_pascal_or_camel_index s offset =
    let rec loop quit idx =
      match is_lower s.[idx] with
      | true -> loop true (succ idx)
      | false -> if quit then idx else loop false (succ idx)
      | exception _e -> idx
      (* out of string index *)
    in
    loop false offset

  let decompose_pascal_or_camel s =
    let rec loop acc idx =
      match next_pascal_or_camel_index s idx - idx with
      | 0 -> List.rev acc
      | len ->
          loop
            (trim_trailing_underscores (String.sub s idx len) :: acc)
            (len + idx)
    in
    loop [] 0

  let decompose_snake s =
    (* Cut on [_] and remove any empty segments *)
    String.split_on_char '_' s |> List.filter (fun s -> String.length s > 0)

  let pascalize terms =
    List.map
      (fun s ->
        let open String in
        capitalize_ascii (lowercase_ascii s))
      terms
    |> String.concat ""

  let camelize terms =
    List.mapi
      (fun i s ->
        let open String in
        if i = 0 then String.lowercase_ascii s
        else capitalize_ascii (lowercase_ascii s))
      terms
    |> String.concat ""

  let snakize terms = List.map String.lowercase_ascii terms |> String.concat "_"

  let kebabize terms =
    List.map String.lowercase_ascii terms |> String.concat "-"
end

open ForTesting

let pascal_to_snake_case s = decompose_pascal_or_camel s |> snakize
let pascal_to_kebab_case s = decompose_pascal_or_camel s |> kebabize
let camel_to_snake_case s = decompose_pascal_or_camel s |> snakize
let camel_to_kebab_case s = decompose_pascal_or_camel s |> kebabize
let pascal_to_camel_case s = decompose_pascal_or_camel s |> camelize
let camel_to_pascal_case s = decompose_pascal_or_camel s |> pascalize
let snake_to_camel_case s = decompose_snake s |> camelize