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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
type 'a validated = ('a, Required.provider_error) result
let regular char = Regular char
let jekyll = regular '-'
let custom f = Custom f
let consume content len ~until i =
let buf = Buffer.create 1 in
let rec aux i =
if i >= len then None
else
let () = Buffer.add_char buf content.[i] in
if content.[i] = until then Some (succ i, buf) else aux (succ i)
in
aux i
let delim content =
let len = String.length content in
if len <= 4 then (None, content)
else
let consume = consume content len ~until:'\n' in
if
List.for_all (Char.equal delim) [ content.[0]; content.[1]; content.[2] ]
&& Char.equal '\n' content.[3]
then
let buf = Buffer.create 1 in
let rec aux i =
if i >= len then (None, content)
else
match content.[i] with
| c
when len > i + 3
&& List.for_all (Char.equal delim)
[ c; content.[i + 1]; content.[i + 2] ]
&& Char.equal '\n' content.[3] ->
let metadata = buf |> Buffer.to_bytes |> Bytes.to_string in
let remaining = String.sub content (i + 4) (len - (i + 4)) in
(Some metadata, remaining)
| _ -> (
match consume i with
| None -> (None, content)
| Some (new_index, other_buf) ->
let () = Buffer.add_buffer buf other_buf in
aux new_index)
in
aux 4
else (None, content)
let ~strategy content =
match strategy with
| Custom f -> f content
| Regular delim -> extract_regular delim content
let validate (type a) (module P : Required.DATA_PROVIDER)
(module R : Required.DATA_READABLE with type t = a) value =
value
|> Option.map P.from_string
|> Option.map (Result.map P.normalize)
|> Option.fold ~none:R.neutral ~some:(fun normalized ->
Result.bind normalized (fun value ->
value
|> R.validate
|> Result.map_error (fun error ->
Required.Validation_error { entity = R.entity_name; error })))
let required entity = Error (Required.Required_metadata { entity })