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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
let empty_string = String.make 0 '_'
let non_empty_string s =
if s = "" then empty_string else s
module Kind = struct
type t =
| Doc (** Standalone doc comment *)
| Page (** Mld page *)
| Impl (** Source page *)
| Module
| Module_type
| Class
| Class_type
| Method
| Val of Typexpr.t
| Type_decl of string option
| Type_extension
| Extension_constructor of Typexpr.t
| Exception of Typexpr.t
| Constructor of Typexpr.t
| Field of Typexpr.t
let equal = ( = )
let get_type t =
match t with
| Val typ | Extension_constructor typ | Exception typ | Constructor typ | Field typ ->
Some typ
| Doc | Page | Impl | Module | Module_type | Class | Class_type | Method | Type_decl _
| Type_extension ->
None
end
module Package = struct
type t =
{ name : string
; version : string
}
let v ~name ~version =
{ name = non_empty_string name; version = non_empty_string version }
let compare a b = String.compare a.name b.name
let link { name; version } = "https://ocaml.org/p/" ^ name ^ "/" ^ version
end
type t =
{ name : string
; rhs : string option
; url : string
; kind : Kind.t
; cost : int
; doc_html : string
; pkg : Package.t
}
let pp fmt { name; rhs; url; kind = _; cost; doc_html; pkg = _ } =
Format.fprintf
fmt
"{ name = %s ; rhs = %a ; url = %s ; kind = . ; cost = %d ; doc_html = %s ; pkg = . }\n"
name
(Fmt.option Fmt.string)
rhs
url
cost
doc_html
let string_compare_shorter a b =
match Int.compare (String.length a) (String.length b) with
| 0 -> String.compare a b
| c -> c
let structural_compare a b =
match string_compare_shorter a.name b.name with
| 0 -> begin
match Package.compare a.pkg b.pkg with
| 0 -> begin
match Stdlib.compare a.kind b.kind with
| 0 -> begin
match string_compare_shorter a.doc_html b.doc_html with
| 0 -> String.compare a.url b.url
| c -> c
end
| c -> c
end
| c -> c
end
| c -> c
let compare a b =
if a == b
then 0
else begin
match Int.compare a.cost b.cost with
| 0 -> structural_compare a b
| cmp -> cmp
end
let equal a b = compare a b = 0
let stdlib_link ~name t =
let path, hashref =
match List.rev name, String.index_opt t.url '#' with
| _ :: path, Some idx ->
let idx = idx + 1 in
let tgt =
match String.index_from_opt t.url idx '-' with
| None -> String.sub t.url idx (String.length t.url - idx)
| Some jdx ->
let kind = String.sub t.url idx (jdx - idx) in
let jdx = jdx + 1 in
let target = String.sub t.url jdx (String.length t.url - jdx) in
String.uppercase_ascii kind ^ target
in
path, "#" ^ tgt
| path, _ -> path, ""
in
let path = String.concat "." (List.rev path) in
"https://v2.ocaml.org/releases/5.1/api/" ^ path ^ ".html" ^ hashref
let link t =
let fullname = String.split_on_char '.' t.name in
match fullname with
| "Stdlib" :: name -> stdlib_link ~name t
| _ ->
let pkg_link = Package.link t.pkg in
let rec align n ys =
match ys with
| _ when n = 0 -> []
| [] -> []
| y :: ys -> y :: align (n - 1) ys
in
let length = List.length fullname in
let length =
match String.index_opt t.url '#' with
| None -> length + 1
| Some idx ->
let tgt = String.sub t.url idx (String.length t.url - idx) in
let count = ref 0 in
String.iter
(function
| '.' -> incr count
| _ -> ())
tgt ;
length - !count
in
let path = align length (List.rev (String.split_on_char '/' t.url)) in
let path = String.concat "/" (List.rev path) in
pkg_link ^ "/doc/" ^ path
let v ~name ~kind ~cost ~rhs ~doc_html ~url ~pkg () =
{ name = non_empty_string name
; kind
; url = non_empty_string url
; cost
; doc_html = non_empty_string doc_html
; pkg
; rhs = Option.map non_empty_string rhs
}