Skip to content

Commit 685301d

Browse files
committed
extract manifest parsing
1 parent f6574e4 commit 685301d

File tree

7 files changed

+420
-17
lines changed

7 files changed

+420
-17
lines changed

jscomp/bsb/bsb_manifest.ml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
let ( // ) = Ext_path.combine
2+
3+
let ( |? ) m (key, cb) = m |> Ext_json.test key cb
4+
let ( .?() ) = Map_string.find_opt
5+
6+
let load_json ~(per_proj_dir : string) ~(warn_legacy_manifest : bool) : string * string * Ext_json_types.t =
7+
let filename, absolute_path, in_chan =
8+
let filename = Literals.rescript_json in
9+
let absolute_path = (per_proj_dir // filename) in
10+
match open_in absolute_path
11+
with
12+
| in_chan -> (filename, absolute_path, in_chan)
13+
| exception e ->
14+
let filename = Literals.bsconfig_json in
15+
let absolute_path = (per_proj_dir // filename) in
16+
match open_in absolute_path
17+
with
18+
| in_chan -> (filename, absolute_path, in_chan)
19+
| exception _ -> raise e (* forward error from rescript.json *)
20+
in
21+
if warn_legacy_manifest && filename = Literals.bsconfig_json then
22+
print_endline "TODO: deprecation warning" ;
23+
match
24+
Ext_json_parse.parse_json_from_chan filename in_chan
25+
with
26+
| v -> close_in in_chan ; (filename, absolute_path, v)
27+
| exception e -> close_in in_chan ; raise e
28+
29+
let parse ~(filename : string) ~(json : Ext_json_types.t) : Bsb_manifest_types.t =
30+
match json with
31+
| Obj { map } -> (
32+
let open Bsb_manifest_fields in
33+
let package_name, namespace = extract_package_name_and_namespace map in
34+
let suffix = extract_suffix map in
35+
{
36+
package_name;
37+
namespace;
38+
warning = extract_warning map;
39+
external_includes = extract_string_list map Bsb_build_schemas.bs_external_includes;
40+
bsc_flags = extract_string_list map Bsb_build_schemas.bsc_flags;
41+
generators = extract_generators map;
42+
bs_dependencies = extract_string_list map Bsb_build_schemas.bs_dependencies |> Set_string.of_list;
43+
bs_dev_dependencies = extract_string_list map Bsb_build_schemas.bs_dev_dependencies |> Set_string.of_list;
44+
pinned_dependencies = extract_string_list map Bsb_build_schemas.pinned_dependencies |> Set_string.of_list;
45+
ppx_specs = extract_ppx_specs map;
46+
pp_file = extract_string map Bsb_build_schemas.pp_flags;
47+
js_post_build_cmd = extract_js_post_build map;
48+
ignored_dirs = extract_string_list map Bsb_build_schemas.ignored_dirs;
49+
package_specs = extract_package_specs map ~suffix;
50+
use_stdlib = extract_boolean map Bsb_build_schemas.use_stdlib true;
51+
external_stdlib = extract_string map Bsb_build_schemas.external_stdlib;
52+
suffix;
53+
reason_react = extract_reason_react map;
54+
jsx = extract_jsx map;
55+
cut_generators = extract_boolean map Bsb_build_schemas.cut_generators false;
56+
uncurried = extract_boolean map Bsb_build_schemas.uncurried true;
57+
}
58+
)
59+
| _ -> Bsb_exception.invalid_spec (filename ^ " expect a json object {}")

jscomp/bsb/bsb_manifest_fields.ml

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
let ( |? ) m (key, cb) = m |> Ext_json.test key cb
2+
let ( .?() ) = Map_string.find_opt
3+
4+
let get_list_string_acc (s : Ext_json_types.t array) acc =
5+
Ext_array.to_list_map_acc s acc (function
6+
| Str x -> Some x.str
7+
| _ -> None)
8+
9+
let get_list_string s = get_list_string_acc s []
10+
11+
type json_map = Ext_json_types.t Map_string.t
12+
13+
let extract_string (map : json_map) (field : string) =
14+
match map.?(field) with
15+
| None -> None
16+
| Some (Str { str }) -> Some(str)
17+
| Some config -> Bsb_exception.config_error config (field ^ " expects a string")
18+
19+
let extract_boolean (map : json_map) (field : string) (default : bool) : bool =
20+
match map.?(field) with
21+
| None -> default
22+
| Some (True _) -> true
23+
| Some (False _) -> false
24+
| Some config ->
25+
Bsb_exception.config_error config (field ^ " expects a boolean")
26+
27+
(* return an empty array if not found *)
28+
let extract_string_list (map : json_map) (field : string) =
29+
30+
match map.?(field) with
31+
| None -> []
32+
| Some (Arr { content = s }) -> get_list_string s
33+
| Some config -> Bsb_exception.config_error config (field ^ " expects an array of string")
34+
35+
let extract_package_name_and_namespace (map : json_map) : string * string option
36+
=
37+
let package_name =
38+
match map.?(Bsb_build_schemas.name) with
39+
| Some (Str { str = "_" } as config) ->
40+
Bsb_exception.config_error config "_ is a reserved package name"
41+
| Some (Str { str = name }) -> name
42+
| Some config ->
43+
Bsb_exception.config_error config "name expect a string field"
44+
| None -> Bsb_exception.invalid_spec "field name is required"
45+
in
46+
let namespace =
47+
match map.?(Bsb_build_schemas.namespace) with
48+
| None | Some (False _) -> None
49+
| Some (True _) ->
50+
Some (Ext_namespace.namespace_of_package_name package_name)
51+
| Some (Str { str }) ->
52+
(*TODO : check the validity of namespace *)
53+
Some (Ext_namespace.namespace_of_package_name str)
54+
| Some x ->
55+
Bsb_exception.config_error x "namespace field expects string or boolean"
56+
in
57+
(package_name, namespace)
58+
59+
let extract_reason_react (map : json_map) =
60+
let open Bsb_manifest_types.ReasonReact in
61+
let default : t option ref = ref None in
62+
map
63+
|? ( Bsb_build_schemas.reason,
64+
`Obj
65+
(fun m ->
66+
match m.?(Bsb_build_schemas.react_jsx) with
67+
| Some (Flo { loc; flo }) -> (
68+
match flo with
69+
| "3" -> default := Some { react_jsx = Jsx_v3 }
70+
| _ -> Bsb_exception.errorf ~loc "Unsupported jsx version %s" flo
71+
)
72+
| Some x ->
73+
Bsb_exception.config_error x
74+
"Unexpected input (expect a version number) for jsx, note \
75+
boolean is no longer allowed"
76+
| None -> ()) )
77+
|> ignore;
78+
!default
79+
80+
let extract_warning (map : json_map) =
81+
match map.?(Bsb_build_schemas.warnings) with
82+
| None -> Bsb_warning.use_default
83+
| Some (Obj { map }) -> Bsb_warning.from_map map
84+
| Some config -> Bsb_exception.config_error config "expect an object"
85+
86+
let extract_generators (map : json_map) =
87+
let generators = ref Map_string.empty in
88+
(match map.?(Bsb_build_schemas.generators) with
89+
| None -> ()
90+
| Some (Arr { content = s }) ->
91+
generators :=
92+
Ext_array.fold_left s Map_string.empty (fun acc json ->
93+
match json with
94+
| Obj { map = m; loc } -> (
95+
match
96+
(m.?(Bsb_build_schemas.name), m.?(Bsb_build_schemas.command))
97+
with
98+
| Some (Str { str = name }), Some (Str { str = command }) ->
99+
Map_string.add acc name command
100+
| _, _ ->
101+
Bsb_exception.errorf ~loc
102+
{| generators exepect format like { "name" : "cppo", "command" : "cppo $in -o $out"} |}
103+
)
104+
| _ -> acc)
105+
| Some config ->
106+
Bsb_exception.config_error config
107+
(Bsb_build_schemas.generators ^ " expect an array field"));
108+
!generators
109+
110+
let extract_package_specs (map : json_map) ~suffix =
111+
let bad_module_format_message_exn ~loc format =
112+
Bsb_exception.errorf ~loc
113+
"package-specs: `%s` isn't a valid output module format. It has to be one \
114+
of: %s, %s or %s"
115+
format Literals.commonjs Literals.es6 Literals.es6_global
116+
in
117+
let supported_format (x : string) loc : Ext_module_system.t =
118+
if x = Literals.commonjs then NodeJS
119+
else if x = Literals.es6 then Es6
120+
else if x = Literals.es6_global then Es6_global
121+
else bad_module_format_message_exn ~loc x
122+
in
123+
let from_json_single suffix (x : Ext_json_types.t) : Bsb_manifest_types.package_spec =
124+
match x with
125+
| Str { str = format; loc } ->
126+
{ format = supported_format format loc; in_source = false; suffix }
127+
| Obj { map; loc } -> (
128+
match map.?("module") with
129+
| Some (Str { str = format }) ->
130+
let in_source =
131+
match map.?(Bsb_build_schemas.in_source) with
132+
| Some (True _) -> true
133+
| Some _ | None -> false
134+
in
135+
let suffix =
136+
match map.?(Bsb_build_schemas.suffix) with
137+
| Some (Str { str = suffix; loc }) ->
138+
let s = Ext_js_suffix.of_string suffix in
139+
if s = Unknown_extension then
140+
Bsb_exception.errorf ~loc "expect .js,.bs.js,.mjs or .cjs"
141+
else s
142+
| Some _ ->
143+
Bsb_exception.errorf ~loc:(Ext_json.loc_of x)
144+
"expect a string field"
145+
| None -> suffix
146+
in
147+
{ format = supported_format format loc; in_source; suffix }
148+
| Some _ ->
149+
Bsb_exception.errorf ~loc
150+
"package-specs: when the configuration is an object, `module` \
151+
field should be a string, not an array. If you want to pass \
152+
multiple module specs, try turning package-specs into an array of \
153+
objects (or strings) instead."
154+
| None ->
155+
Bsb_exception.errorf ~loc
156+
"package-specs: when the configuration is an object, the `module` \
157+
field is mandatory.")
158+
| _ ->
159+
Bsb_exception.errorf ~loc:(Ext_json.loc_of x)
160+
"package-specs: we expect either a string or an object."
161+
in
162+
let from_json suffix arr =
163+
let spec = ref Bsb_spec_set.empty in
164+
let has_in_source = ref false in
165+
Ext_array.iter arr (fun x ->
166+
let result = from_json_single suffix x in
167+
if result.in_source then
168+
if not !has_in_source then has_in_source := true
169+
else
170+
Bsb_exception.errorf ~loc:(Ext_json.loc_of x)
171+
"package-specs: we've detected two module formats that are both \
172+
configured to be in-source.";
173+
spec := Bsb_spec_set.add result !spec);
174+
!spec
175+
(* TODO: FIXME: better API without mutating *)
176+
in
177+
match map.?(Bsb_build_schemas.package_specs) with
178+
| Some (Arr { content }) -> from_json suffix content
179+
| Some _ | None -> Bsb_spec_set.singleton ({ format = NodeJS; in_source = false; suffix })
180+
181+
let extract_ppx_specs (map : json_map) =
182+
let field = Bsb_build_schemas.ppx_flags in
183+
match map.?(field) with
184+
| None -> []
185+
| Some (Arr { content }) ->
186+
Ext_array.to_list_f content (fun x ->
187+
match x with
188+
| Str x -> { Bsb_manifest_types.name = x.str; args = [] }
189+
| Arr { content } -> (
190+
let xs = get_list_string content in
191+
match xs with
192+
| [] -> Bsb_exception.config_error x " empty array is not allowed"
193+
| name :: args -> { Bsb_manifest_types.name = name; args })
194+
| config ->
195+
Bsb_exception.config_error config
196+
(field ^ "expect each item to be either string or array"))
197+
| Some config -> Bsb_exception.config_error config (field ^ " expect an array")
198+
199+
let extract_suffix (map : json_map) : Ext_js_suffix.t =
200+
match map.?(Bsb_build_schemas.suffix) with
201+
| None -> Js
202+
| Some (Str { str; loc }) ->
203+
let s = Ext_js_suffix.of_string str in
204+
if s = Unknown_extension then
205+
Bsb_exception.errorf ~loc
206+
"expect .js, .mjs, .cjs or .bs.js, .bs.mjs, .bs.cjs here"
207+
else s
208+
| Some config ->
209+
Bsb_exception.config_error config
210+
"expect a string exteion like \".js\" here"
211+
212+
let extract_js_post_build (map : json_map) =
213+
let js_post_build_cmd = ref None in
214+
map
215+
|? ( Bsb_build_schemas.js_post_build,
216+
`Obj
217+
(fun m ->
218+
m
219+
|? ( Bsb_build_schemas.cmd,
220+
`Str (fun s -> js_post_build_cmd := Some(s)) )
221+
|> ignore) )
222+
|> ignore;
223+
!js_post_build_cmd
224+
225+
let extract_jsx (map : json_map) =
226+
let open Bsb_manifest_types.Jsx in
227+
228+
let version : version option ref = ref None in
229+
let module_ : module_ option ref = ref None in
230+
let mode : mode option ref = ref None in
231+
let v3_dependencies : dependencies ref = ref [] in
232+
map
233+
|? ( Bsb_build_schemas.jsx,
234+
`Obj
235+
(fun m ->
236+
match m.?(Bsb_build_schemas.jsx_version) with
237+
| Some (Flo { loc; flo }) -> (
238+
match flo with
239+
| "3" -> version := Some Jsx_v3
240+
| "4" -> version := Some Jsx_v4
241+
| _ -> Bsb_exception.errorf ~loc "Unsupported jsx version %s" flo
242+
)
243+
| Some x ->
244+
Bsb_exception.config_error x
245+
"Unexpected input (expect a version number) for jsx version"
246+
| None -> ()) )
247+
|? ( Bsb_build_schemas.jsx,
248+
`Obj
249+
(fun m ->
250+
match m.?(Bsb_build_schemas.jsx_module) with
251+
| Some (Str { loc; str }) -> (
252+
match str with
253+
| "react" -> module_ := Some React
254+
| _ -> Bsb_exception.errorf ~loc "Unsupported jsx module %s" str)
255+
| Some x ->
256+
Bsb_exception.config_error x
257+
"Unexpected input (jsx module name) for jsx module"
258+
| None -> ()) )
259+
|? ( Bsb_build_schemas.jsx,
260+
`Obj
261+
(fun m ->
262+
match m.?(Bsb_build_schemas.jsx_mode) with
263+
| Some (Str { loc; str }) -> (
264+
match str with
265+
| "classic" -> mode := Some Classic
266+
| "automatic" -> mode := Some Automatic
267+
| _ -> Bsb_exception.errorf ~loc "Unsupported jsx mode %s" str)
268+
| Some x ->
269+
Bsb_exception.config_error x
270+
"Unexpected input (expect classic or automatic) for jsx mode"
271+
| None -> ()) )
272+
|? ( Bsb_build_schemas.jsx,
273+
`Obj
274+
(fun m ->
275+
match m.?(Bsb_build_schemas.jsx_v3_dependencies) with
276+
| Some (Arr { content }) ->
277+
v3_dependencies := get_list_string content
278+
| Some x ->
279+
Bsb_exception.config_error x
280+
"Unexpected input for jsx v3-dependencies"
281+
| None -> ()) )
282+
|> ignore;
283+
{
284+
version = !version;
285+
module_ = !module_;
286+
mode = !mode;
287+
v3_dependencies = !v3_dependencies;
288+
}

0 commit comments

Comments
 (0)