package yocaml
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Core engine of the YOCaml Static Site Generator
Install
dune-project
Dependency
Authors
Maintainers
Sources
yocaml-2.0.0.tbz
sha256=fddf61500e828ac88d86ba982084cc817299302082a6e797b36787ff18235ec2
sha512=8b71a8cecd3e101df55eef0bba7a24d4dde9d66b5ecedd9f6d55834fcdc8d33fd875092ca73a398e1715664caee06cdc1bdb1b4da85bff0a687faac5c0445023
doc/src/yocaml/eff.ml.html
Source file eff.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 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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289(* YOCaml a static blog generator. Copyright (C) 2024 The Funkyworkers and The YOCaml's developers This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. *) type 'a t = unit -> 'a let return x () = x let bind f x = f (x ()) let map f x = bind (fun m -> return @@ f m) x let join x = bind (fun x -> x) x let compose f g x = bind g (f x) let rcompose f g x = bind f (g x) let apply ft xt = map (ft ()) xt let zip x y = apply (map (fun a b -> (a, b)) x) y let replace x e = map (fun _ -> x) e let void e = replace () e let select x y = bind (function | Either.Right v -> return v | Either.Left v -> map (fun f -> f v) y) x let branch s l r = let a = map Either.(map_right left) s and b = map (fun f x -> Either.right (f x)) l in select (select a b) r let map2 fu a b = apply (map fu a) b let map3 fu a b c = apply (map2 fu a b) c let map4 fu a b c d = apply (map3 fu a b c) d let map5 fu a b c d e = apply (map4 fu a b c d) e let map6 fu a b c d e f = apply (map5 fu a b c d e) f let map7 fu a b c d e f g = apply (map6 fu a b c d e f) g let map8 fu a b c d e f g h = apply (map7 fu a b c d e f g) h module List = struct let traverse f l = let rec aux acc = function | [] -> map Stdlib.List.rev acc | x :: xs -> (aux [@tailcall]) (map2 Stdlib.List.cons (f x) acc) xs in aux (return []) l let sequence l = traverse Fun.id l let filter_map f l = let rec aux acc = function | [] -> return @@ Stdlib.List.rev acc | x :: xs -> bind (function | None -> (aux [@tailcall]) acc xs | Some x -> (aux [@tailcall]) (x :: acc) xs) @@ f x in aux [] l let fold_left f default list = let rec aux acc = function | [] -> acc | x :: xs -> (aux [@tailcall]) (bind (fun m -> f acc m) x) xs in aux default list end module Infix = struct let ( <$> ) = map let ( <*> ) = apply let ( <*? ) = select let ( =<< ) = bind let ( >>= ) x f = f =<< x let ( >|= ) x f = f <$> x let ( =|< ) = map let ( >=> ) = compose let ( <=< ) = rcompose end module Syntax = struct let ( let+ ) x f = map f x let ( and+ ) = zip let ( let* ) x f = bind f x end include Infix include Syntax type filesystem = [ `Source | `Target ] type _ Effect.t += | Yocaml_log : ([ `App | `Error | `Warning | `Info | `Debug ] * string) -> unit Effect.t | Yocaml_failwith : exn -> 'a Effect.t | Yocaml_get_time : unit -> int Effect.t | Yocaml_file_exists : filesystem * Path.t -> bool Effect.t | Yocaml_read_file : filesystem * Path.t -> string Effect.t | Yocaml_get_mtime : filesystem * Path.t -> int Effect.t | Yocaml_hash_content : string -> string Effect.t | Yocaml_write_file : filesystem * Path.t * string -> unit Effect.t | Yocaml_is_directory : filesystem * Path.t -> bool Effect.t | Yocaml_read_dir : filesystem * Path.t -> Path.fragment list Effect.t | Yocaml_create_dir : filesystem * Path.t -> unit Effect.t | Yocaml_exec_command : string * string list * (int -> bool) -> string Effect.t let perform raw_effect = return @@ Effect.perform raw_effect let run handler arrow input = Effect.Deep.match_with (fun input -> arrow input ()) input handler exception File_not_exists of filesystem * Path.t exception Invalid_path of filesystem * Path.t exception File_is_a_directory of filesystem * Path.t exception Directory_is_a_file of filesystem * Path.t exception Directory_not_exists of filesystem * Path.t exception Provider_error of Required.provider_error let log ?(level = `Debug) message = perform @@ Yocaml_log (level, message) let raise exn = perform @@ Yocaml_failwith exn let failwith message = perform @@ Yocaml_failwith (Failure message) let get_time () = perform @@ Yocaml_get_time () let file_exists ~on path = perform @@ Yocaml_file_exists (on, path) let logf ?(level = `Debug) = Format.kasprintf (fun result -> log ~level result) let is_directory ~on path = perform @@ Yocaml_is_directory (on, path) let exec ?(is_success = Int.equal 0) exec_name ?(args = []) = perform @@ Yocaml_exec_command (exec_name, args, is_success) let exec_cmd ?is_success cmd = let command, args = Cmd.normalize cmd in exec ?is_success ~args command let is_file ~on path = let* file_exists = file_exists ~on path in if file_exists then let+ is_dir = is_directory ~on path in not is_dir else return false let ensure_file_exists ~on f path = let* exists = file_exists ~on path in if exists then f path else raise (File_not_exists (on, path)) let read_file ~on = ensure_file_exists ~on (fun path -> let* is_file = is_file ~on path in if is_file then perform @@ Yocaml_read_file (on, path) else raise @@ File_is_a_directory (on, path)) let read_file_as_metadata (type a) (module P : Required.DATA_PROVIDER) (module R : Required.DATA_READABLE with type t = a) ~on path = let* file = read_file ~on path in file |> Option.some |> Metadata.validate (module P) (module R) |> Result.fold ~error:(fun err -> raise @@ Provider_error err) ~ok:(fun metadata -> return metadata) let read_file_with_metadata (type a) (module P : Required.DATA_PROVIDER) (module R : Required.DATA_READABLE with type t = a) ?(extraction_strategy = Metadata.jekyll) ~on path = let* file = read_file ~on path in let raw_metadata, content = Metadata.extract_from_content ~strategy:extraction_strategy file in raw_metadata |> Metadata.validate (module P) (module R) |> Result.fold ~error:(fun err -> raise @@ Provider_error err) ~ok:(fun metadata -> return (metadata, content)) let get_mtime ~on = ensure_file_exists ~on (fun path -> perform @@ Yocaml_get_mtime (on, path)) let hash str = perform @@ Yocaml_hash_content str let create_directory ~on path = let rec aux path = let* is_file = is_file ~on path in if is_file then raise (Directory_is_a_file (on, path)) else let* is_directory = is_directory ~on path in if not is_directory then let parent = Path.dirname path in let* () = aux parent in perform @@ Yocaml_create_dir (on, path) else return () in aux path let write_file ~on path content = let parent = Path.dirname path in let* () = create_directory ~on parent in perform @@ Yocaml_write_file (on, path, content) let read_directory ~on ?(only = `Both) ?(where = fun _ -> true) path = let* is_dir = is_directory ~on path in if is_dir then let predicate child = let file = Path.(path / child) in let* exists = file_exists ~on file in let+ is_dir = is_directory ~on file in let predicate = match only with | `Files -> exists && (not is_dir) && where file | `Directories -> exists && is_dir && where file | `Both -> exists && where file in if predicate then Some file else None in let* children = perform @@ Yocaml_read_dir (on, path) in List.filter_map predicate children else let+ () = logf ~level:`Warning "%a does not exists" Path.pp path in [] let mtime ~on path = let rec aux path = let* t = get_mtime ~on path in let* d = is_directory path ~on in if d then let* children = read_directory ~on ~only:`Both path in Stdlib.List.fold_left (fun max_time f -> let* a = max_time in let+ b = aux f in Int.max a b) (return t) children else return t in aux path let get_basename source = match Path.basename source with | None -> raise (Invalid_path (`Source, source)) | Some fragment -> return fragment let copy_file into source = let* fragment = get_basename source in let dest = Path.(into / fragment) in let* content = read_file ~on:`Source source in write_file ~on:`Target dest content let copy_recursive ?new_name ~into source = let rec aux ?new_name into source = let* is_dir = is_directory ~on:`Target into in if is_dir then let* source_is_file = is_file ~on:`Source source in if source_is_file then let* () = log ~level:`Debug @@ Lexicon.copy_file ?new_name ~into source in copy_file into source else let* source_is_directory = is_directory ~on:`Source source in if source_is_directory then let* () = log ~level:`Debug @@ Lexicon.copy_directory ?new_name ~into source in let* name = get_basename source in let name = Option.value new_name ~default:name in let name = Path.(into / name) in let* () = create_directory ~on:`Target name in let* children = read_directory ~on:`Source ~only:`Both source in let* _ = List.traverse (fun child -> aux name child) children in return () else raise (File_not_exists (`Source, source)) else let* is_file = is_file ~on:`Target into in if is_file then raise (Directory_is_a_file (`Target, into)) else let* () = create_directory ~on:`Target into in aux ?new_name into source in aux ?new_name into source
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>