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
|
open StdLabels
open Css.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 * Css.Location.t) list
| Stylesheet of (Merge_style.t * ats)
and at_map_content = (Css.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 -> Css.Location.t -> at_map_content option -> at_map_content option
= fun block loc value ->
begin match block, value with
(* Empty element, update the existing one if any *)
| Brace_block.Empty, _ ->
Some
( loc
, Empty )
(* New declarationList, juste add it *)
| 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 )
(* Othe cases are not handled *)
| _ -> None
end
(** Add a new @ definition *)
and add_at
: Css.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 -> Css.Location.t
= function
| Rule.Style_rule t -> t.Style_rule.loc
| Rule.At_rule t -> t.At_rule.loc
let rec extract_at
: ats -> Css.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 extract_css
: t -> Stylesheet.t
= fun (styles, ats) ->
let arr =
Seq.append
(extract_at ats)
(Merge_style.extract_style styles)
|> Array.of_seq in
(* Sort the declaration in initial ordering (using the location attribute) *)
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
|