package sherlodoc

  1. Overview
  2. Docs

Source file entry.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
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 =
  (* to protect against `ancient` segfaulting on statically allocated values *)
  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
  }
OCaml

Innovation. Community. Security.