stringify.ml 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. open Types
  2. let tab = " "
  3. let indent = Str.global_replace (Str.regexp "^\\(.\\)") (tab ^ "\\1")
  4. let prefix_space = function "" -> "" | s -> " " ^ s
  5. let rec cat sep fn = function
  6. | [] -> ""
  7. | [hd] -> fn hd
  8. | hd :: tl -> fn hd ^ sep ^ cat sep fn tl
  9. let string_of_num n =
  10. if float_of_int (int_of_float n) = n
  11. then string_of_int (int_of_float n)
  12. else string_of_float n
  13. (* TODO: move this to utils *)
  14. let rec filter_none = function
  15. | [] -> []
  16. | None :: tl -> filter_none tl
  17. | Some hd :: tl -> hd :: filter_none tl
  18. (*
  19. * Pretty-printing
  20. *)
  21. let rec string_of_expr = function
  22. | Ident id -> id
  23. | Strlit str -> "\"" ^ str ^ "\""
  24. | Uri uri when String.contains uri ')' -> "url(\"" ^ uri ^ "\")"
  25. | Uri uri -> "url(" ^ uri ^ ")"
  26. | Concat values -> cat " " string_of_expr values
  27. | Number (n, None) -> string_of_num n
  28. | Number (n, Some u) -> string_of_num n ^ u
  29. | Function (name, arg) -> name ^ "(" ^ string_of_expr arg ^ ")"
  30. | Hexcolor hex -> "#" ^ hex
  31. | Unary (op, opnd) -> op ^ string_of_expr opnd
  32. | Nary (",", opnds) -> cat ", " string_of_expr opnds
  33. | Nary (op, opnds) -> cat op string_of_expr opnds
  34. let string_of_declaration (name, value, important) =
  35. let imp = if important then " !important" else "" in
  36. name ^ ": " ^ string_of_expr value ^ imp ^ ";"
  37. let rec string_of_selector = function
  38. | Simple simple -> simple
  39. | Combinator (left, " ", right) ->
  40. string_of_selector left ^ " " ^ string_of_selector right
  41. | Combinator (left, com, right) ->
  42. string_of_selector left ^ " " ^ com ^ " " ^ string_of_selector right
  43. let string_of_media_feature = function
  44. | (feature, None) -> "(" ^ feature ^ ")"
  45. | (feature, Some value) -> "(" ^ feature ^ ": " ^ string_of_expr value ^ ")"
  46. let string_of_media_query query =
  47. let features_str = cat " and " string_of_media_feature in
  48. match query with
  49. | (None, None, []) -> ""
  50. | (None, Some mtype, []) -> mtype
  51. | (Some pre, Some mtype, []) -> pre ^ " " ^ mtype
  52. | (None, None, features) -> features_str features
  53. | (None, Some mtype, features) -> mtype ^ " and " ^ features_str features
  54. | (Some pre, Some mtype, features) ->
  55. pre ^ " " ^ mtype ^ " and " ^ features_str features
  56. | (Some pre, None, _) ->
  57. failwith "unexpected media query prefix \"" ^ pre ^ "\""
  58. let block body = " {\n" ^ indent body ^ "\n}"
  59. let rec string_of_statement = function
  60. | Ruleset (selectors, decls) ->
  61. cat ", " string_of_selector selectors ^
  62. block (cat "\n" string_of_declaration decls)
  63. | Media (queries, rulesets) ->
  64. "@media" ^ prefix_space (cat ", " string_of_media_query queries) ^
  65. block (cat "\n\n" string_of_statement rulesets)
  66. | Import (target, []) ->
  67. "@import " ^ string_of_expr target ^ ";"
  68. | Import (target, queries) ->
  69. "@import " ^ string_of_expr target ^ " " ^ String.concat ", " queries ^ ";"
  70. | Charset charset ->
  71. "@charset \"" ^ charset ^ "\";"
  72. | Page (None, decls) ->
  73. "@page" ^ block (cat "\n" string_of_declaration decls)
  74. | Page (Some pseudo, decls) ->
  75. "@page :" ^ pseudo ^ block (cat "\n" string_of_declaration decls)
  76. | Fontface decls ->
  77. "@font-face " ^ block (cat "\n" string_of_declaration decls)
  78. | Namespace (None, uri) ->
  79. "@namespace \"" ^ uri ^ "\";"
  80. | Namespace (Some prefix, uri) ->
  81. "@namespace " ^ prefix ^ " \"" ^ uri ^ "\";"
  82. let string_of_stylesheet = cat "\n\n" string_of_statement
  83. (*
  84. * Minified stringification
  85. *)
  86. let rec minify_expr = function
  87. | Concat values -> cat " " minify_expr values
  88. | Function (name, arg) -> name ^ "(" ^ minify_expr arg ^ ")"
  89. | Unary (op, opnd) -> op ^ minify_expr opnd
  90. | Nary (",", opnds) -> cat "," minify_expr opnds
  91. | Nary (op, opnds) -> cat op minify_expr opnds
  92. | expr -> string_of_expr expr
  93. let minify_declaration (name, value, important) =
  94. let imp = if important then "!important" else "" in
  95. name ^ ":" ^ minify_expr value ^ imp
  96. let rec minify_selector = function
  97. | Simple simple -> simple
  98. | Combinator (left, com, right) ->
  99. minify_selector left ^ com ^ minify_selector right
  100. let minify_media_feature = function
  101. | (feature, None) -> "(" ^ feature ^ ")"
  102. | (feature, Some value) -> "(" ^ feature ^ ":" ^ minify_expr value ^ ")"
  103. let minify_media_query query =
  104. let features_str = cat "and " minify_media_feature in
  105. match query with
  106. | (None, None, features) -> features_str features
  107. | (None, Some mtype, features) -> mtype ^ " and " ^ features_str features
  108. | (Some pre, Some mtype, features) ->
  109. pre ^ " " ^ mtype ^ " and " ^ features_str features
  110. | _ -> string_of_media_query query
  111. let rec minify_statement = function
  112. | Ruleset (selectors, decls) ->
  113. cat "," minify_selector selectors ^
  114. "{" ^ (cat ";" minify_declaration decls) ^ "}"
  115. | Media (queries, rulesets) ->
  116. "@media" ^ prefix_space (cat "," minify_media_query queries) ^
  117. "{" ^ (cat "" minify_statement rulesets) ^ "}"
  118. | Import (target, []) ->
  119. "@import " ^ string_of_expr target ^ ";"
  120. | Import (target, queries) ->
  121. "@import " ^ string_of_expr target ^ " " ^ String.concat "," queries ^ ";"
  122. | Page (None, decls) ->
  123. "@page{" ^ cat "" minify_declaration decls ^ "}"
  124. | Page (Some pseudo, decls) ->
  125. "@page :" ^ pseudo ^ "{" ^ cat "" minify_declaration decls ^ "}"
  126. | Fontface decls ->
  127. "@font-face{" ^ cat "" minify_declaration decls ^ "}"
  128. | statement -> string_of_statement statement
  129. let minify_stylesheet = cat "" minify_statement