[OCaml] Mobile-friendly clone of cgit.
1
(** Parsing commit messages and Conventional Commits metadata.
2
3
Extracted from the view layer so that both handlers (for filtering) and
4
views (for display) can use it without a layer violation. *)
5
6
type t = { summary : string; body : string }
7
8
let parse = function
9
| None -> { summary = ""; body = "" }
10
| Some message -> (
11
match String.split_on_char '\n' message with
12
| [] -> { summary = ""; body = "" }
13
| summary :: rest ->
14
{ summary; body = String.concat "\n" rest |> String.trim })
15
16
let conventional_commit_types =
17
[
18
"feat";
19
"fix";
20
"docs";
21
"style";
22
"refactor";
23
"perf";
24
"test";
25
"build";
26
"ci";
27
"chore";
28
"revert";
29
"remove";
30
]
31
32
(** Split a Conventional Commits subject into its type and the remaining title.
33
An unrecognised prefix is left in the title untouched, so non-conforming
34
histories still read correctly. *)
35
let parse_conventional summary =
36
match String.index_opt summary ':' with
37
| None -> (None, summary)
38
| Some colon_pos ->
39
let prefix = String.sub summary 0 colon_pos in
40
let type_name =
41
match String.index_opt prefix '(' with
42
| Some paren_pos -> String.sub prefix 0 paren_pos
43
| None -> prefix
44
in
45
let type_lower = String.lowercase_ascii type_name in
46
if List.mem type_lower conventional_commit_types then
47
let rest =
48
String.sub summary (colon_pos + 1)
49
(String.length summary - colon_pos - 1)
50
|> String.trim
51
in
52
(Some type_lower, rest)
53
else (None, summary)
54