|
| 1 | +module String_map = Map.Make (String) |
| 2 | + |
| 3 | +let of_structure ~verbose ~filename structure stylesheet = |
| 4 | + let get_string (e : Ppxlib.expression) = |
| 5 | + match e.pexp_desc with |
| 6 | + | Pexp_constant (Pconst_string (v, _, None)) -> Some v |
| 7 | + | _ -> None |
| 8 | + in |
| 9 | + List.fold_left |
| 10 | + (fun stylesheet item -> |
| 11 | + match item with |
| 12 | + | [%stri [@@@css [%e? value]]] -> |
| 13 | + (match get_string value with |
| 14 | + | Some v -> |
| 15 | + if verbose then ( |
| 16 | + Format.eprintf "Adding %a\n" Ppxlib.Pprintast.expression value; |
| 17 | + Printf.eprintf "Adding %s\n" v); |
| 18 | + String_map.add filename v stylesheet |
| 19 | + | None -> stylesheet) |
| 20 | + | _ -> stylesheet) |
| 21 | + stylesheet structure |
| 22 | + |
| 23 | +let of_pp_ml ~verbose ~filename stylesheet = |
| 24 | + match Ppxlib.Ast_io.read_binary filename with |
| 25 | + | Error msg -> |
| 26 | + if verbose then Printf.eprintf "Error reading file %s: %s\n" filename msg; |
| 27 | + stylesheet |
| 28 | + | Ok t -> |
| 29 | + (match Ppxlib.Ast_io.get_ast t with |
| 30 | + | Impl structure -> of_structure ~verbose ~filename structure stylesheet |
| 31 | + | Intf _ -> stylesheet) |
| 32 | + |
| 33 | +let of_ml ~verbose ~filename stylesheet = |
| 34 | + try |
| 35 | + let ic = open_in filename in |
| 36 | + let len = in_channel_length ic in |
| 37 | + let content = really_input_string ic len in |
| 38 | + close_in ic; |
| 39 | + let lexbuf = Lexing.from_string content in |
| 40 | + lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = filename }; |
| 41 | + let structure = Ppxlib.Parse.implementation lexbuf in |
| 42 | + of_structure ~verbose ~filename structure stylesheet |
| 43 | + with |
| 44 | + | Sys_error msg -> |
| 45 | + if verbose then Printf.eprintf "Error reading file %s: %s\n" filename msg; |
| 46 | + stylesheet |
| 47 | + | exn -> |
| 48 | + if verbose then |
| 49 | + Printf.eprintf "Error parsing file %s: %s\n" filename |
| 50 | + (Printexc.to_string exn); |
| 51 | + stylesheet |
| 52 | + |
| 53 | +let extract_stylesheet ~verbose input_files = |
| 54 | + List.fold_left |
| 55 | + (fun stylesheet filename -> |
| 56 | + if verbose then Printf.eprintf "Processing %s...\n" filename; |
| 57 | + if String.ends_with filename ~suffix:".css" then |
| 58 | + failwith "Extracting from .css files is not supported yet" |
| 59 | + else if String.ends_with filename ~suffix:".pp.ml" then |
| 60 | + of_pp_ml ~verbose ~filename stylesheet |
| 61 | + else if String.ends_with filename ~suffix:".ml" then |
| 62 | + of_ml ~verbose ~filename stylesheet |
| 63 | + else failwith "Expected .css, .ml or .pp.ml file") |
| 64 | + String_map.empty input_files |
| 65 | + |
| 66 | +let parse_args args = |
| 67 | + let rec parse acc output_file verbose = function |
| 68 | + | "-o" :: file :: rest |
| 69 | + | "-output" :: file :: rest |
| 70 | + | "--output" :: file :: rest -> |
| 71 | + parse acc (Some file) verbose rest |
| 72 | + | "-v" :: rest | "-verbose" :: rest | "--verbose" :: rest -> |
| 73 | + parse acc output_file true rest |
| 74 | + | arg :: rest -> parse (arg :: acc) output_file verbose rest |
| 75 | + | [] -> List.rev acc, output_file, verbose |
| 76 | + in |
| 77 | + parse [] None false (Array.to_list args |> List.tl) |
| 78 | + |
| 79 | +let () = |
| 80 | + let input_files, output_file, verbose = parse_args Sys.argv in |
| 81 | + if verbose then ( |
| 82 | + Printf.eprintf "Extracting stylesheets...\n"; |
| 83 | + Printf.eprintf "Input files: %i\n" (List.length input_files)); |
| 84 | + let stylesheet = extract_stylesheet ~verbose input_files in |
| 85 | + let out_channel = |
| 86 | + match output_file with Some file -> open_out file | None -> Stdlib.stdout |
| 87 | + in |
| 88 | + Stdlib.output_string out_channel |
| 89 | + "/* This file is generated by styled-ppx, do not edit manually */\n"; |
| 90 | + String_map.iter (fun _ v -> Stdlib.output_string out_channel v) stylesheet; |
| 91 | + match output_file with Some _ -> close_out out_channel | None -> () |
0 commit comments