Source file merge.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
open StdLabels
open Css_parser.Types
module AtRule = Map.Make (struct
type t = string * Component_value.t list
let compare at1 at2 =
let cmp = String.compare (fst at1) (fst at2) in
if cmp <> 0
then cmp
else
Comparator.compare_list
(fun l1 l2 ->
Comparator.component_value (l1, Common.location_none) (l2, Common.location_none))
(snd at1)
(snd at2)
;;
end)
type at_type =
| Empty
| Declaration of (Declaration_list.t * Location.t) list
| Stylesheet of (Merge_style.t * ats)
and at_map_content = Location.t * at_type
and ats = at_map_content AtRule.t
type t = Merge_style.t * ats
let rec add_brace_block
: Brace_block.t -> Location.t -> at_map_content option -> at_map_content option
=
fun block loc value ->
match block, value with
| Brace_block.Empty, _ -> Some (loc, Empty)
| Brace_block.Declaration_list decls, None -> Some (loc, Declaration [ decls, loc ])
| Brace_block.Declaration_list decls, Some (loc, Declaration decl2) ->
Some
(loc, Declaration (Common.update_declarations (decls, Common.location_none) decl2))
| Brace_block.Stylesheet s, None ->
let eval = add_css (Merge_style.empty, AtRule.empty) s in
Some (loc, Stylesheet eval)
| Brace_block.Stylesheet s, Some (loc, Stylesheet css) ->
let eval = add_css css s in
Some (loc, Stylesheet eval)
| _ -> None
(** Add a new @ definition *)
and add_at : Css_parser.Types.At_rule.t -> ats -> ats =
fun { name; prelude; block; loc } map ->
let prelude = List.map (fst prelude) ~f:fst in
let key = fst name, prelude in
AtRule.update key (add_brace_block block loc) map
and add_css : t -> Stylesheet.t -> t =
fun (styles, atrules) css ->
List.fold_left (fst css) ~init:(styles, atrules) ~f:(fun (styles, ats) -> function
| Rule.At_rule r -> styles, add_at r ats
| Rule.Style_rule r -> Merge_style.add_style r styles, ats)
;;
(** Helper function for retrieving the location *)
let get_loc : Rule.t -> Location.t = function
| Rule.Style_rule t -> t.Style_rule.loc
| Rule.At_rule t -> t.At_rule.loc
;;
let rec : ats -> Css_parser.Types.Rule.t Seq.t =
fun map ->
AtRule.to_seq map
|> Seq.map (fun ((name, prelude), (loc, value)) ->
let name = name, loc
and prelude = List.map ~f:(fun x -> x, loc) prelude, loc in
match value with
| Stylesheet css ->
let stylesheet = extract_css css in
let block = Brace_block.Stylesheet stylesheet in
Rule.At_rule At_rule.{ name; prelude; block; loc }
| Empty ->
let block = Brace_block.Empty in
Rule.At_rule At_rule.{ name; prelude; block; loc }
| Declaration decls ->
let declarations =
List.fold_left decls ~init:[] ~f:(fun acc (decl, _) ->
let elems = fst decl in
List.append elems acc)
in
let block = Brace_block.Declaration_list (declarations, loc) in
Rule.At_rule At_rule.{ name; prelude; block; loc })
and : t -> Stylesheet.t =
fun (styles, ats) ->
let arr =
Seq.append (extract_at ats) (Merge_style.extract_style styles) |> Array.of_seq
in
Array.fast_sort ~cmp:(fun v1 v2 -> Stdlib.compare (get_loc v1) (get_loc v2)) arr;
Array.to_list arr, Common.location_none
;;
let empty : t = Merge_style.empty, AtRule.empty