• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ocaml / odoc / 2860

26 Feb 2025 10:42AM UTC coverage: 73.427% (+0.06%) from 73.368%
2860

Pull #1321

github

web-flow
Merge 5bdc6f16b into b8c8d99e8
Pull Request #1321: Remove unneeded code and unify "utils" modules

56 of 77 new or added lines in 12 files covered. (72.73%)

1 existing line in 1 file now uncovered.

10257 of 13969 relevant lines covered (73.43%)

9954.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.8
/src/model/reference.ml
1
type path = [ `Root of string | `Dot of path * string ]
2

3
let expected_err :
4
    (Format.formatter -> 'a -> unit) -> 'a -> Location_.span -> Error.t =
5
 fun pp_a a -> Error.make "Expected %a." pp_a a
151✔
6

7
let expected_err_str : string -> Location_.span -> Error.t =
8
  expected_err Format.pp_print_string
1,220✔
9

10
let unknown_reference_qualifier : string -> Location_.span -> Error.t =
11
  Error.make "Unknown reference qualifier '%s'."
1,220✔
12

13
let deprecated_reference_kind : string -> string -> Location_.span -> Error.t =
14
  Error.make "'%s' is deprecated, use '%s' instead."
1,220✔
15

16
let reference_kinds_do_not_match : string -> string -> Location_.span -> Error.t
17
    =
18
  Error.make "Old-style reference kind ('%s:') does not match new ('%s-')."
1,220✔
19

20
let should_not_be_empty : what:string -> Location_.span -> Error.t =
21
 fun ~what ->
22
  Error.make "%s should not be empty." (Astring.String.Ascii.capitalize what)
34✔
23

24
let not_allowed :
25
    ?suggestion:string ->
26
    what:string ->
27
    in_what:string ->
28
    Location_.span ->
29
    Error.t =
30
 fun ?suggestion ~what ~in_what ->
31
  Error.make ?suggestion "%s is not allowed in %s."
2✔
32
    (Astring.String.Ascii.capitalize what)
2✔
33
    in_what
34

35
(** Format a list in a human readable way: [A, B, or C]. *)
36
let pp_hum_comma_separated pp_a ppf lst =
37
  let rec loop hd = function
149✔
38
    | [] -> Format.fprintf ppf "or %a" pp_a hd
149✔
39
    | hd' :: tl' ->
483✔
40
        Format.fprintf ppf "%a, " pp_a hd;
41
        loop hd' tl'
483✔
42
  in
43
  match lst with [] -> () | [ a ] -> pp_a ppf a | hd :: tl -> loop hd tl
×
44

45
let deprecated_reference_kind location kind replacement =
46
  deprecated_reference_kind kind replacement location |> Error.raise_warning
8✔
47

48
(* http://caml.inria.fr/pub/docs/manual-ocaml/ocamldoc.html#sec359. *)
49
let match_ocamldoc_reference_kind (_location as loc) s :
50
    [> Paths.Reference.tag_any ] option =
51
  let d = deprecated_reference_kind in
563✔
52
  match s with
53
  | "module" -> Some `TModule
80✔
54
  | "modtype" ->
1✔
55
      d loc "modtype" "module-type";
56
      Some `TModuleType
1✔
57
  | "class" -> Some `TClass
47✔
58
  | "classtype" ->
1✔
59
      d loc "classtype" "class-type";
60
      Some `TClassType
1✔
61
  | "val" -> Some `TValue
27✔
62
  | "type" -> Some `TType
40✔
63
  | "exception" -> Some `TException
17✔
64
  | "attribute" -> None
×
65
  | "method" -> Some `TMethod
47✔
66
  | "section" -> Some `TLabel
34✔
67
  | "const" ->
1✔
68
      d loc "const" "constructor";
69
      Some `TConstructor
1✔
70
  | "recfield" ->
1✔
71
      d loc "recfield" "field";
72
      Some `TField
1✔
73
  | "childpage" -> Some `TChildPage
3✔
74
  | "childmodule" -> Some `TChildModule
5✔
75
  | _ -> None
259✔
76

77
let match_extra_odoc_reference_kind (_location as loc) s :
78
    [> Paths.Reference.tag_any ] option =
79
  let d = deprecated_reference_kind in
259✔
80
  match s with
81
  | "class-type" -> Some `TClassType
19✔
82
  | "constructor" -> Some `TConstructor
56✔
83
  | "exn" ->
1✔
84
      d loc "exn" "exception";
85
      Some `TException
1✔
86
  | "extension" -> Some `TExtension
19✔
87
  | "extension-decl" -> Some `TExtensionDecl
4✔
88
  | "field" -> Some `TField
55✔
89
  | "instance-variable" -> Some `TInstanceVariable
15✔
90
  | "label" ->
1✔
91
      d loc "label" "section";
92
      Some `TLabel
1✔
93
  | "module-type" -> Some `TModuleType
33✔
94
  | "page" -> Some `TPage
43✔
95
  | "asset" -> Some `TAsset
3✔
96
  | "value" ->
2✔
97
      d loc "value" "val";
98
      Some `TValue
2✔
99
  | _ -> None
8✔
100

101
type reference_kind = Paths.Reference.tag_any
102

103
(* Ideally, [tokenize] would call this on every reference kind annotation during
104
   tokenization, when generating the token list. However, that constrains the
105
   phantom tag type to be the same for all tokens in the list (because lists are
106
   homogeneous). So, the parser stores kinds as strings in the token list
107
   instead, and this function is called on each string at the latest possible
108
   time to prevent typing issues.
109

110
   A secondary reason to delay parsing, and store strings in the token list, is
111
   that we need the strings for user-friendly error reporting. *)
112
let match_reference_kind location s : reference_kind =
113
  match s with
1,139✔
114
  | `None -> `TUnknown
576✔
115
  | `Prefixed s | `Old_prefix s -> (
39✔
116
      let result =
117
        match match_ocamldoc_reference_kind location s with
118
        | Some _ as kind -> kind
304✔
119
        | None -> match_extra_odoc_reference_kind location s
259✔
120
      in
121
      match result with
122
      | Some kind -> kind
555✔
123
      | None -> unknown_reference_qualifier s location |> Error.raise_exception)
8✔
124

125
type token = {
126
  kind : [ `None | `Prefixed of string ];
127
  identifier : string;
128
  location : Location_.span;
129
}
130

131
type path_prefix = Path_prefix of string * Location_.span
132

133
(* The string is scanned right-to-left, because we are interested in right-most
134
   hyphens. The tokens are also returned in right-to-left order, because the
135
   traversals that consume them prefer to look at the deepest identifier
136
   first. *)
137
let tokenize location s : token list * path_prefix option =
138
  let rec scan_identifier started_at open_parenthesis_count index tokens =
698✔
139
    match s.[index] with
5,273✔
140
    | exception Invalid_argument _ ->
398✔
141
        let identifier, location = identifier_ended started_at index in
142
        ({ kind = `None; identifier; location } :: tokens, None)
379✔
143
    | '-' when open_parenthesis_count = 0 ->
537✔
144
        let identifier, location = identifier_ended started_at index in
536✔
145
        scan_kind identifier location index (index - 1) tokens
532✔
146
    | '.' when open_parenthesis_count = 0 ->
185✔
147
        let identifier, location = identifier_ended started_at index in
184✔
148
        scan_identifier index 0 (index - 1)
183✔
149
          ({ kind = `None; identifier; location } :: tokens)
150
    | '/' when open_parenthesis_count = 0 ->
83✔
151
        let identifier, location = identifier_ended started_at index in
83✔
152
        scan_path index ({ kind = `None; identifier; location } :: tokens)
75✔
153
    | ')' ->
9✔
154
        scan_identifier started_at
155
          (open_parenthesis_count + 1)
156
          (index - 1) tokens
157
    | '(' when open_parenthesis_count > 0 ->
9✔
158
        scan_identifier started_at
9✔
159
          (open_parenthesis_count - 1)
160
          (index - 1) tokens
161
    | '"' -> (
18✔
162
        try
163
          scan_identifier started_at 0
16✔
164
            (String.rindex_from s (index - 1) '"' - 1)
17✔
165
            tokens
166
        with _ ->
2✔
167
          Error.raise_exception (Error.make "Unmatched quotation!" location))
2✔
168
    | _ -> scan_identifier started_at open_parenthesis_count (index - 1) tokens
4,036✔
169
  and identifier_ended started_at index =
170
    let offset = index + 1 in
1,201✔
171
    let length = started_at - offset in
172
    let identifier = String.sub s offset length in
173
    let identifier =
1,201✔
174
      Astring.String.cuts ~sep:"\"" identifier
175
      |> List.mapi (fun i s ->
1,201✔
176
             if i mod 2 = 0 then
1,233✔
177
               Astring.String.cuts s ~sep:" " |> String.concat ""
1,217✔
178
             else s)
16✔
179
      |> String.concat ""
1,201✔
180
    in
181
    let location = Location_.in_string s ~offset ~length location in
1,201✔
182

183
    if identifier = "" then
1,201✔
184
      should_not_be_empty ~what:"Identifier in reference" location
185
      |> Error.raise_exception;
×
186

187
    (identifier, location)
1,169✔
188
  and scan_kind identifier identifier_location started_at index tokens =
189
    match s.[index] with
4,233✔
190
    | exception Invalid_argument _ ->
202✔
191
        let kind, location = kind_ended identifier_location started_at index in
192
        ({ kind; identifier; location } :: tokens, None)
202✔
193
    | '.' ->
321✔
194
        let kind, location = kind_ended identifier_location started_at index in
195
        scan_identifier index 0 (index - 1)
321✔
196
          ({ kind; identifier; location } :: tokens)
197
    | '/' ->
9✔
198
        let kind, location = kind_ended identifier_location started_at index in
199
        scan_path index ({ kind; identifier; location } :: tokens)
9✔
200
    | _ ->
3,701✔
201
        scan_kind identifier identifier_location started_at (index - 1) tokens
202
  and kind_ended identifier_location started_at index =
203
    let offset = index + 1 in
532✔
204
    let length = started_at - offset in
205
    let kind = `Prefixed (String.sub s offset length) in
532✔
206
    let location = Location_.in_string s ~offset ~length location in
207
    let location = Location_.span [ location; identifier_location ] in
532✔
208
    (kind, location)
532✔
209
  and scan_path started_at tokens =
210
    let location =
84✔
211
      Location_.in_string s ~offset:0 ~length:(started_at + 1) location
212
    in
213
    (tokens, Some (Path_prefix (String.sub s 0 (started_at + 1), location)))
84✔
214
  in
215

216
  scan_identifier (String.length s) 0 (String.length s - 1) []
698✔
217
  |> fun (toks, p) -> (List.rev toks, p)
665✔
218

219
let expected ?(expect_paths = false) allowed location =
79✔
220
  let unqualified = [ "an unqualified reference" ] in
149✔
221
  let unqualified =
222
    if expect_paths then "a path" :: unqualified else unqualified
70✔
223
  in
224
  let allowed = List.map (Printf.sprintf "'%s-'") allowed @ unqualified in
149✔
225
  expected_err (pp_hum_comma_separated Format.pp_print_string) allowed location
149✔
226

227
let parse_path whole_path_location p =
228
  let segs = Astring.String.cuts ~sep:"/" p in
89✔
229
  let check segs start =
89✔
230
    let _finish =
89✔
231
      List.fold_left
232
        (fun offset seg ->
233
          match seg with
160✔
234
          | "" ->
2✔
235
              let location =
236
                Location_.in_string p ~offset ~length:0 whole_path_location
237
              in
238
              should_not_be_empty ~what:"Identifier in path reference" location
2✔
239
              |> Error.raise_exception
2✔
240
          | seg -> offset + String.length seg + 1)
158✔
241
        start segs
242
    in
243
    ()
87✔
244
  in
245
  match segs with
246
  | "." :: segs ->
13✔
247
      check segs 2;
248
      (`TRelativePath, segs)
13✔
249
  | "" :: "" :: segs ->
27✔
250
      check segs 2;
251
      (`TCurrentPackage, segs)
26✔
252
  | "" :: segs ->
30✔
253
      check segs 1;
254
      (`TAbsolutePath, segs)
30✔
255
  | segs ->
19✔
256
      check segs 0;
257
      (`TRelativePath, segs)
18✔
258

259
let parse_path_prefix (Path_prefix (p, path_location)) identifier
260
    prefix_location =
261
  parse_path (Location_.span [ path_location; prefix_location ]) (p ^ identifier)
83✔
262

263
(* Parse references that do not contain a [/]. Raises errors and warnings. *)
264
let parse whole_reference_location s :
265
    Paths.Reference.t Error.with_errors_and_warnings =
266
  let open Paths.Reference in
698✔
267
  let open Names in
268
  let parse_from_last_component { kind; identifier; location } old_kind tokens
269
      path_prefix =
270
    let rec signature { kind; identifier; location } tokens : Signature.t =
665✔
271
      let kind = match_reference_kind location kind in
119✔
272
      match tokens with
119✔
273
      | [] -> (
96✔
274
          match path_prefix with
275
          | None -> (
96✔
276
              match kind with
277
              | (`TUnknown | `TModule | `TModuleType) as kind ->
5✔
278
                  `Root (identifier, kind)
279
              | _ ->
39✔
280
                  expected ~expect_paths:true
281
                    [ "module"; "module-type" ]
282
                    location
283
                  |> Error.raise_exception)
39✔
284
          | Some p -> (
×
285
              match kind with
286
              | `TUnknown | `TModule ->
×
287
                  `Module_path (parse_path_prefix p identifier location)
×
288
              | _ ->
×
289
                  expected ~expect_paths:true [ "module" ] location
290
                  |> Error.raise_exception))
×
291
      | next_token :: tokens -> (
23✔
292
          match kind with
293
          | `TUnknown ->
3✔
294
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
2✔
295
          | `TModule ->
4✔
296
              `Module
297
                (signature next_token tokens, ModuleName.make_std identifier)
3✔
298
          | `TModuleType ->
4✔
299
              `ModuleType
300
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
301
          | _ ->
12✔
302
              expected ~expect_paths:true [ "module"; "module-type" ] location
303
              |> Error.raise_exception)
12✔
304
    and parent { kind; identifier; location } tokens : FragmentTypeParent.t =
305
      let kind = match_reference_kind location kind in
101✔
306
      match tokens with
101✔
307
      | [] -> (
52✔
308
          match path_prefix with
309
          | None -> (
52✔
310
              match kind with
311
              | (`TUnknown | `TModule | `TModuleType | `TType) as kind ->
2✔
312
                  `Root (identifier, kind)
313
              | _ ->
27✔
314
                  expected [ "module"; "module-type"; "type" ] location
315
                  |> Error.raise_exception)
27✔
316
          | Some p -> (
×
317
              match kind with
318
              | `TUnknown | `TModule ->
×
319
                  `Module_path (parse_path_prefix p identifier location)
×
320
              | _ ->
×
321
                  expected ~expect_paths:true [ "module" ] location
322
                  |> Error.raise_exception))
×
323
      | next_token :: tokens -> (
49✔
324
          match kind with
325
          | `TUnknown ->
9✔
326
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
6✔
327
          | `TModule ->
4✔
328
              `Module
329
                (signature next_token tokens, ModuleName.make_std identifier)
3✔
330
          | `TModuleType ->
4✔
331
              `ModuleType
332
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
333
          | `TType ->
6✔
334
              `Type (signature next_token tokens, TypeName.make_std identifier)
4✔
335
          | _ ->
26✔
336
              expected [ "module"; "module-type"; "type" ] location
337
              |> Error.raise_exception)
26✔
338
    in
339

340
    let class_signature { kind; identifier; location } tokens : ClassSignature.t
341
        =
342
      let kind = match_reference_kind location kind in
40✔
343
      match tokens with
40✔
344
      | [] -> (
19✔
345
          match kind with
346
          | (`TUnknown | `TClass | `TClassType) as kind ->
1✔
347
              `Root (identifier, kind)
348
          | _ ->
14✔
349
              expected [ "class"; "class-type" ] location
350
              |> Error.raise_exception)
14✔
351
      | next_token :: tokens -> (
21✔
352
          match kind with
353
          | `TUnknown ->
3✔
354
              `Dot ((parent next_token tokens :> LabelParent.t), identifier)
2✔
355
          | `TClass ->
3✔
356
              `Class (signature next_token tokens, TypeName.make_std identifier)
2✔
357
          | `TClassType ->
3✔
358
              `ClassType
359
                (signature next_token tokens, TypeName.make_std identifier)
2✔
360
          | _ ->
12✔
361
              expected [ "class"; "class-type" ] location
362
              |> Error.raise_exception)
12✔
363
    in
364

365
    let label_parent_path kind path_prefix identifier location =
366
      match kind with
19✔
367
      | `TUnknown ->
18✔
368
          `Any_path (parse_path_prefix path_prefix identifier location)
18✔
369
      | `TModule ->
×
370
          `Module_path (parse_path_prefix path_prefix identifier location)
×
371
      | `TPage -> `Page_path (parse_path_prefix path_prefix identifier location)
1✔
372
      | _ ->
×
373
          expected ~expect_paths:true [ "module"; "page" ] location
374
          |> Error.raise_exception
×
375
    in
376

377
    let any_path kind path_prefix identifier location =
378
      match kind with
65✔
379
      | `TUnknown ->
57✔
380
          `Any_path (parse_path_prefix path_prefix identifier location)
55✔
381
      | `TModule ->
1✔
382
          `Module_path (parse_path_prefix path_prefix identifier location)
1✔
383
      | `TPage -> `Page_path (parse_path_prefix path_prefix identifier location)
3✔
384
      | `TAsset ->
3✔
385
          `Asset_path (parse_path_prefix path_prefix identifier location)
3✔
386
      | _ ->
1✔
387
          expected ~expect_paths:true [ "module"; "page" ] location
388
          |> Error.raise_exception
1✔
389
    in
390

391
    let rec label_parent { kind; identifier; location } tokens : LabelParent.t =
392
      let kind = match_reference_kind location kind in
175✔
393
      match tokens with
174✔
394
      | [] -> (
124✔
395
          match path_prefix with
396
          | None -> (
105✔
397
              match kind with
398
              | ( `TUnknown | `TModule | `TModuleType | `TType | `TClass
2✔
399
                | `TClassType | `TPage ) as kind ->
1✔
400
                  `Root (identifier, kind)
401
              | _ ->
8✔
402
                  expected ~expect_paths:true
403
                    [
404
                      "module";
405
                      "module-type";
406
                      "type";
407
                      "class";
408
                      "class-type";
409
                      "page";
410
                    ]
411
                    location
412
                  |> Error.raise_exception)
8✔
413
          | Some p -> label_parent_path kind p identifier location)
19✔
414
      | next_token :: tokens -> (
50✔
415
          match kind with
416
          | `TUnknown -> `Dot (label_parent next_token tokens, identifier)
25✔
417
          | `TModule ->
3✔
418
              `Module
419
                (signature next_token tokens, ModuleName.make_std identifier)
2✔
420
          | `TModuleType ->
3✔
421
              `ModuleType
422
                (signature next_token tokens, ModuleTypeName.make_std identifier)
2✔
423
          | `TType ->
3✔
424
              `Type (signature next_token tokens, TypeName.make_std identifier)
2✔
425
          | `TClass ->
5✔
426
              `Class (signature next_token tokens, TypeName.make_std identifier)
3✔
427
          | `TClassType ->
1✔
428
              `ClassType
429
                (signature next_token tokens, TypeName.make_std identifier)
1✔
430
          | _ ->
10✔
431
              expected ~expect_paths:true
432
                [ "module"; "module-type"; "type"; "class"; "class-type" ]
433
                location
434
              |> Error.raise_exception)
10✔
435
    in
436

437
    let start_from_last_component { kind; identifier; location } old_kind tokens
438
        =
439
      let new_kind = match_reference_kind location kind in
665✔
440
      let kind =
662✔
441
        match old_kind with
442
        | None -> new_kind
623✔
443
        | Some (old_kind_string, old_kind_location) -> (
39✔
444
            let old_kind =
445
              match_reference_kind old_kind_location
446
                (`Old_prefix old_kind_string)
447
            in
448
            match new_kind with
35✔
449
            | `TUnknown -> old_kind
32✔
450
            | _ ->
3✔
451
                (if old_kind <> new_kind then
452
                   let new_kind_string =
1✔
453
                     match kind with `None -> "" | `Prefixed s -> s
×
454
                   in
455
                   reference_kinds_do_not_match old_kind_string new_kind_string
456
                     whole_reference_location
457
                   |> Error.raise_warning);
1✔
458
                new_kind)
3✔
459
      in
460

461
      match tokens with
462
      | [] -> (
304✔
463
          match path_prefix with
464
          | None -> `Root (identifier, kind)
239✔
465
          | Some p -> any_path kind p identifier location)
65✔
466
      | next_token :: tokens -> (
354✔
467
          match kind with
468
          | `TUnknown -> `Dot (label_parent next_token tokens, identifier)
107✔
469
          | `TModule ->
30✔
470
              `Module
471
                (signature next_token tokens, ModuleName.make_std identifier)
6✔
472
          | `TModuleType ->
5✔
473
              `ModuleType
474
                (signature next_token tokens, ModuleTypeName.make_std identifier)
3✔
475
          | `TType ->
16✔
476
              `Type (signature next_token tokens, TypeName.make_std identifier)
11✔
477
          | `TConstructor ->
42✔
478
              `Constructor
479
                (parent next_token tokens, ConstructorName.make_std identifier)
18✔
480
          | `TField ->
44✔
481
              `Field (parent next_token tokens, FieldName.make_std identifier)
13✔
482
          | `TExtension ->
6✔
483
              `Extension
484
                (signature next_token tokens, ExtensionName.make_std identifier)
4✔
485
          | `TExtensionDecl ->
2✔
486
              `ExtensionDecl
487
                (signature next_token tokens, ExtensionName.make_std identifier)
2✔
488
          | `TException ->
4✔
489
              `Exception
490
                (signature next_token tokens, ExceptionName.make_std identifier)
2✔
491
          | `TValue ->
4✔
492
              `Value (signature next_token tokens, ValueName.make_std identifier)
2✔
493
          | `TClass ->
5✔
494
              `Class (signature next_token tokens, TypeName.make_std identifier)
3✔
495
          | `TClassType ->
4✔
496
              `ClassType
497
                (signature next_token tokens, TypeName.make_std identifier)
2✔
498
          | `TMethod ->
36✔
499
              `Method
500
                ( class_signature next_token tokens,
9✔
501
                  MethodName.make_std identifier )
36✔
502
          | `TInstanceVariable ->
4✔
503
              `InstanceVariable
504
                ( class_signature next_token tokens,
2✔
505
                  InstanceVariableName.make_std identifier )
4✔
506
          | `TLabel ->
19✔
507
              `Label
508
                (label_parent next_token tokens, LabelName.make_std identifier)
19✔
509
          | `TChildPage | `TChildModule ->
×
510
              let suggestion =
511
                Printf.sprintf "'child-%s' should be first." identifier
512
              in
513
              not_allowed ~what:"Child label"
×
514
                ~in_what:"the last component of a reference path" ~suggestion
515
                location
516
              |> Error.raise_exception
×
517
          | `TPage ->
2✔
518
              let suggestion =
519
                Printf.sprintf "Reference pages as '<parent_path>/%s'."
520
                  identifier
521
              in
522
              not_allowed ~what:"Page label"
2✔
523
                ~in_what:"on the right side of a dot" ~suggestion location
524
              |> Error.raise_exception
2✔
525
          | `TAsset ->
×
526
              let suggestion =
527
                Printf.sprintf "Reference assets as '<parent_path>/%s'."
528
                  identifier
529
              in
530
              not_allowed ~what:"Asset label"
×
531
                ~in_what:"on the right side of a dot" ~suggestion location
532
              |> Error.raise_exception)
×
533
    in
534
    start_from_last_component { kind; identifier; location } old_kind tokens
535
  in
536
  Error.catch_errors_and_warnings (fun () ->
537
      let old_kind, s, location =
698✔
538
        let rec find_old_reference_kind_separator index =
539
          if index < 0 then raise Not_found
657✔
540
          else
541
            match s.[index] with
9,422✔
542
            | ':' -> index
41✔
543
            | ')' -> (
15✔
544
                match String.rindex_from s index '(' with
545
                | index -> find_old_reference_kind_separator (index - 1)
15✔
546
                | exception (Not_found as exn) -> raise exn)
×
547
            | _ -> find_old_reference_kind_separator (index - 1)
9,366✔
548
        in
549
        match find_old_reference_kind_separator (String.length s - 1) with
698✔
550
        | index ->
41✔
551
            let old_kind = String.trim (String.sub s 0 index) in
41✔
552
            let old_kind_location =
41✔
553
              Location_.set_end_as_offset_from_start index
554
                whole_reference_location
555
            in
556
            let s = String.sub s (index + 1) (String.length s - (index + 1)) in
41✔
557
            let location =
41✔
558
              Location_.nudge_start (index + 1) whole_reference_location
559
            in
560
            (Some (old_kind, old_kind_location), s, location)
41✔
561
        | exception Not_found -> (None, s, whole_reference_location)
657✔
562
      in
563
      match tokenize location s with
564
      | last_token :: tokens, path_prefix ->
665✔
565
          parse_from_last_component last_token old_kind tokens path_prefix
566
      | [], _ ->
×
567
          should_not_be_empty ~what:"Reference target" whole_reference_location
568
          |> Error.raise_exception)
×
569

570
(* Parse references that do not contain a [/]. Raises errors and warnings. *)
571
let parse_asset whole_reference_location s :
572
    Paths.Reference.Asset.t Error.with_errors_and_warnings =
573
  let path = parse_path whole_reference_location s in
6✔
574
  Error.catch_errors_and_warnings (fun () -> `Asset_path path)
6✔
575

576
let read_path_longident location s =
577
  let rec loop : string -> int -> path option =
160✔
578
   fun s pos ->
579
    try
335✔
580
      let idx = String.rindex_from s pos '.' in
581
      let name = String.sub s (idx + 1) (pos - idx) in
176✔
582
      if String.length name = 0 then None
1✔
583
      else
584
        match loop s (idx - 1) with
175✔
585
        | None -> None
1✔
586
        | Some parent -> Some (`Dot (parent, name))
174✔
587
    with Not_found ->
159✔
588
      let name = String.sub s 0 (pos + 1) in
589
      if String.length name = 0 then None else Some (`Root name)
1✔
590
  in
591
  Error.catch_warnings (fun () ->
592
      match loop s (String.length s - 1) with
160✔
593
      | Some r -> Ok (r :> path)
158✔
594
      | None -> Error (expected_err_str "a valid path" location))
2✔
595

596
let read_mod_longident location lid =
597
  Error.catch_warnings (fun () ->
30✔
598
      match Error.raise_warnings (parse location lid) with
30✔
599
      | Error _ as e -> e
×
600
      | Ok p -> (
30✔
601
          match p with
602
          | (`Root (_, (`TUnknown | `TModule)) | `Dot (_, _) | `Module (_, _))
×
603
            as r ->
604
              Ok r
NEW
605
          | _ -> Error (expected_err_str "a reference to a module" location)))
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc