|
1 | 1 | open Lib; |
2 | 2 |
|
3 | | -module StringMap = Map.Make(String); |
4 | | - |
5 | | -let messages = ref(StringMap.empty); |
6 | | - |
7 | | -let duplicatesAreAllowed = ref(false); |
8 | | - |
9 | | -let iterator = |
10 | | - ExtractionIterator.getIterator(message => { |
11 | | - let {Message.id, defaultMessage} = message; |
12 | | - switch (messages^ |> StringMap.find_opt(id)) { |
13 | | - | None => messages := messages^ |> StringMap.add(id, message) |
14 | | - | Some(existingMessage) when duplicatesAreAllowed^ && defaultMessage == existingMessage.defaultMessage => |
15 | | - messages := messages^ |> StringMap.add(id, message) |
16 | | - | Some(existingMessage) when duplicatesAreAllowed^ && defaultMessage != existingMessage.defaultMessage => |
17 | | - Printf.eprintf("Error: duplicate message id: %s with different default messages\n", id); |
18 | | - exit(3); |
19 | | - | Some(_) => |
20 | | - Printf.eprintf("Error: duplicate message id: %s\n", id); |
21 | | - exit(3); |
22 | | - }; |
23 | | - }); |
24 | | - |
25 | | -let extractMessages = ast => iterator.structure(iterator, ast); |
26 | | - |
27 | | -let processReasonFile = path => { |
28 | | - let channel = open_in_bin(path); |
29 | | - let lexbuf = Lexing.from_channel(channel); |
30 | | - let ast = Reason_toolchain.(RE.implementation(lexbuf) |> To_current.copy_structure); |
31 | | - close_in(channel); |
32 | | - |
33 | | - extractMessages(ast); |
34 | | -}; |
35 | | - |
36 | | -let rec processPath = path => { |
37 | | - if (!Sys.file_exists(path)) { |
| 3 | +let extract = (~duplicatesAllowed, paths) => |
| 4 | + try({ |
| 5 | + let messages = Extractor.extract(~duplicatesAllowed, paths); |
| 6 | + |
| 7 | + `List(messages |> List.map(Message.toJson)) |> Yojson.Basic.pretty_to_channel(stdout); |
| 8 | + print_newline(); |
| 9 | + }) { |
| 10 | + | Extractor.PathNotFound(path) => |
38 | 11 | Printf.eprintf("Error: file or directory does not exist: %s\n", path); |
39 | 12 | exit(1); |
40 | | - }; |
41 | 13 |
|
42 | | - if (Sys.is_directory(path)) { |
43 | | - Sys.readdir(path) |> Array.iter(filename => processPath(Filename.concat(path, filename))); |
44 | | - } else if (Filename.extension(path) == ".re") { |
45 | | - processReasonFile(path); |
46 | | - }; |
47 | | -}; |
48 | | - |
49 | | -let outputJson = () => { |
50 | | - let sortedJsonObjects = |
51 | | - messages^ |
52 | | - |> StringMap.bindings |
53 | | - |> List.map(((_id, message)) => message) |
54 | | - |> List.sort(Message.compare) |
55 | | - |> List.map(Message.toJson); |
56 | | - |
57 | | - Yojson.Basic.pretty_to_channel(stdout, `List(sortedJsonObjects)); |
58 | | - print_newline(); |
59 | | -}; |
| 14 | + | Extractor.DuplicateMessageId(id) => |
| 15 | + Printf.eprintf("Error: duplicate message id: %s\n", id); |
| 16 | + exit(2); |
60 | 17 |
|
61 | | -let inputFilenames = ref([]); |
| 18 | + | Extractor.DefaultMessageNotMatching(id) => |
| 19 | + Printf.eprintf("Error: duplicate message id: %s with different default messages\n", id); |
| 20 | + exit(3); |
62 | 21 |
|
63 | | -let processInputFilename = filename => inputFilenames := [filename, ...inputFilenames^]; |
| 22 | + | exn => |
| 23 | + Printf.eprintf("Unexpected error: %s\n", Printexc.to_string(exn)); |
| 24 | + exit(10); |
| 25 | + }; |
64 | 26 |
|
65 | | -let showVersion = () => { |
66 | | - print_endline(Version.version); |
67 | | - exit(0); |
| 27 | +type options = { |
| 28 | + showVersion: bool, |
| 29 | + paths: list(string), |
| 30 | + duplicatesAllowed: bool, |
68 | 31 | }; |
69 | 32 |
|
70 | | -let allowDuplicates = () => duplicatesAreAllowed := true; |
| 33 | +let run = () => { |
| 34 | + let options = ref({showVersion: false, paths: [], duplicatesAllowed: false}); |
| 35 | + |
| 36 | + let processInputFilename = filename => options := {...options^, paths: [filename, ...options^.paths]}; |
| 37 | + let allowDuplicates = () => options := {...options^, duplicatesAllowed: true}; |
| 38 | + let showVersion = () => options := {...options^, showVersion: true}; |
71 | 39 |
|
72 | | -let args = [ |
73 | | - ("-v", Arg.Unit(showVersion), "shows the program version"), |
74 | | - ( |
75 | | - "--allow-duplicates", |
76 | | - Arg.Unit(allowDuplicates), |
77 | | - "allows messages with identical `id` props if `defaultMessage` props are identical as well", |
78 | | - ), |
79 | | -]; |
| 40 | + let args = [ |
| 41 | + ("-v", Arg.Unit(showVersion), "shows the program version"), |
| 42 | + ( |
| 43 | + "--allow-duplicates", |
| 44 | + Arg.Unit(allowDuplicates), |
| 45 | + "allows messages with identical `id` props if `defaultMessage` props are identical as well", |
| 46 | + ), |
| 47 | + ]; |
80 | 48 |
|
81 | | -let usage = "Usage: " ++ Sys.argv[0] ++ " [path...]"; |
| 49 | + let usage = "Usage: " ++ Sys.argv[0] ++ " [path...]"; |
82 | 50 |
|
83 | | -Arg.parse(args, processInputFilename, usage); |
| 51 | + Arg.parse(args, processInputFilename, usage); |
84 | 52 |
|
85 | | -switch (inputFilenames^) { |
86 | | -| [] => Arg.usage(args, usage) |
87 | | -| filenames => |
88 | | - filenames |> List.rev |> List.iter(processPath); |
89 | | - outputJson(); |
| 53 | + switch (options^) { |
| 54 | + | {showVersion: true} => print_endline(Version.version) |
| 55 | + | {paths: []} => Arg.usage(args, usage) |
| 56 | + | {paths, duplicatesAllowed} => extract(~duplicatesAllowed, paths) |
| 57 | + }; |
90 | 58 | }; |
| 59 | + |
| 60 | +run(); |
0 commit comments