Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
liquid_list.ml1 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 162 163 164 165 166 167open Base open Liquid_syntax open Syntax open Tools open Values open Helpers let compact ctx = function | List lst :: _ -> List.filter lst ~f:(Values.is_not_nil ctx) |> ok_list | other -> errc "compact accepts a list" other let concat _ = function | List a :: List b :: _ -> a @ b |> ok_list | other -> errc "concat accepts 2 lists" other let first _ = function | List (hd :: _) :: _ -> hd |> ok | other -> errc "first accepts a list" other let join ctx params = let joiner lst delim = let vs = List.map (unwrap_all ctx lst) ~f:(string_from_value ctx) in String.concat ~sep:delim vs |> ok_str in match params with | List lst :: String delim :: _ -> joiner lst delim | List lst :: _ -> joiner lst " " | other -> errc "join accepts a list and a delimiter (string)" other let last _ = function | List [] :: _ -> Nil |> ok | List lst :: _ -> lst |> List.rev |> List.hd_exn |> ok | other -> errc "last accepts a list" other let map _ = function | List lst :: String key :: _ -> let mapped = extract_key_from_object_list lst key in mapped |> ok_list | other -> errc "map accepts a list and a key (string)" other let reverse _ = function | List lst :: _ -> List.rev lst |> ok_list | other -> errc "reverse accepts a list" other let size _ = function | List lst :: _ -> lst |> List.length |> Int.to_float |> ok_num | String s :: _ -> s |> String.length |> Int.to_float |> ok_num | other -> errc "size accepts a list or a string" other let sort _ = function | List lst :: String key :: _ -> let compare_by_key a b = let extract = function | Object obj -> ( match Object.find_opt key obj with Some v -> v | None -> Nil) | v -> v in Values.compare_value (extract a) (extract b) in let sorted = List.sort lst ~compare:compare_by_key in sorted |> ok_list | List lst :: _ -> let sorted = List.sort lst ~compare:Values.compare_value in sorted |> ok_list | other -> errc "sort accepts a list an optional object key" other let sort_natural ctx params = let comp_key = function | String t -> let whitespace_exp = ~/"\\s|-|_" in Re2.rewrite_exn whitespace_exp ~template:"" t |> String.lowercase | v -> Values.string_from_value ctx v in let compare a b = String.compare (comp_key a) (comp_key b) in match params with | List lst :: String key :: _ -> let compare_by_key a b = let extract = function | Object obj -> ( match Object.find_opt key obj with Some v -> v | None -> Nil) | v -> v in String.compare (comp_key (extract a)) (comp_key (extract b)) in let sorted = List.sort lst ~compare:compare_by_key in sorted |> ok_list | List lst :: _ -> let sorted = List.sort lst ~compare in sorted |> ok_list | other -> errc "sort_natural accepts a list an optional object key" other (* TODO: Implement negative indexs *) let slice _ params = let do_slice slicer lengther lst fstart flength = let start, length = (fi fstart, fi flength) in if start >= 0 then slicer lst ~pos:start ~len:length else let cstart = lengther lst + start in slicer lst ~pos:cstart ~len:length in let do_slice_string = do_slice String.sub String.length in let do_slice_list = do_slice List.sub List.length in match params with | String s :: Number fstart :: Number flength :: _ -> do_slice_string s fstart flength |> ok_str | String s :: Number findex :: _ -> do_slice_string s findex 1. |> ok_str | List lst :: Number fstart :: Number flength :: _ -> do_slice_list lst fstart flength |> ok_list | List lst :: Number findex :: _ -> do_slice_list lst findex 1. |> ok_list | other -> errc "slice accepts a string or list as well as a start index and optional \ length" other let uniq _ = function | List lst :: _ -> let folder acc curr = if Tools.contains acc curr then acc else acc @ [ curr ] in let rl = List.fold_left lst ~init:[] ~f:folder in rl |> ok_list | other -> errc "uniq accepts a list" other let where ctx params = let do_where lst test_key check = let filterer = function | Object obj -> ( match Object.find_opt test_key obj with | Some value -> check value | _ -> false) | _ -> false in let filtered_lst = List.filter lst ~f:filterer in filtered_lst |> ok_list in match params with | List lst :: String key :: test_value :: _ -> do_where lst key (Values.eq ctx test_value) | List lst :: String key :: _ -> do_where lst key (Values.is_truthy ctx) | other -> errc "where accepts a list, a key (string) and an optional test value (any)" other let function_from_id = function | "compact" -> Some compact | "concat" -> Some concat | "first" -> Some first | "join" -> Some join | "last" -> Some last | "map" -> Some map | "reverse" -> Some reverse | "size" -> Some size | "slice" -> Some slice | "sort" -> Some sort | "sort_natural" -> Some sort_natural | "uniq" -> Some uniq | "where" -> Some where | _ -> None