diff --git a/jscomp/bsb/bsb_build_schemas.ml b/jscomp/bsb/bsb_build_schemas.ml index 03439c3b9b..e85308764e 100644 --- a/jscomp/bsb/bsb_build_schemas.ml +++ b/jscomp/bsb/bsb_build_schemas.ml @@ -75,9 +75,15 @@ let warnings = "warnings" let number = "number" let error = "error" let suffix = "suffix" -let gentypeconfig = "gentypeconfig" -let language = "language" +let gentype = "gentypeconfig" +let gentype_language = "language" +let gentype_module = "module" +let gentype_module_resolution = "moduleResolution" +let gentype_export_interfaces = "exportInterfaces" +let gentype_generated_file_extension = "moduleResolution" +let gentype_shims = "shims" +let gentype_debug = "debug" let path = "path" let ignored_dirs = "ignored-dirs" -let uncurried = "uncurried" \ No newline at end of file +let uncurried = "uncurried" diff --git a/jscomp/bsb/bsb_build_util.ml b/jscomp/bsb/bsb_build_util.ml index 8d49c183fe..1f5247fe58 100644 --- a/jscomp/bsb/bsb_build_util.ml +++ b/jscomp/bsb/bsb_build_util.ml @@ -151,13 +151,12 @@ let extract_pinned_dependencies (map : Ext_json_types.t Map_string.t) : Set_stri | None -> Set_string.empty | Some (Arr { content }) -> Set_string.of_list (get_list_string content) - | Some config -> Bsb_exception.config_error config "expect an array of string" + | Some manifest -> Bsb_exception.manifest_error manifest "expect an array of string" let rec walk_all_deps_aux (visited : string Hash_string.t) (paths : string list) ~(top : top) (dir : string) (queue : _ Queue.t) ~pinned_dependencies = - let bsconfig_json = dir // Literals.bsconfig_json in - match Ext_json_parse.parse_json_from_file bsconfig_json with - | Obj { map; loc } -> + match Bsb_config_parse.parse_json ~per_proj_dir:dir ~warn_legacy_config:false with + | _, _, Obj { map; loc } -> let cur_package_name = match Map_string.find_opt map Bsb_build_schemas.name with | Some (Str { str; loc }) -> @@ -169,7 +168,7 @@ let rec walk_all_deps_aux (visited : string Hash_string.t) (paths : string list) "package name is expected to be %s but got %s" s str); str | Some _ | None -> - Bsb_exception.errorf ~loc "package name missing in %s/bsconfig.json" + Bsb_exception.errorf ~loc "package name missing in %s/rescript.json" dir in if Ext_list.mem_string paths cur_package_name then ( @@ -220,7 +219,7 @@ let rec walk_all_deps_aux (visited : string Hash_string.t) (paths : string list) | Expect_name _ -> ()); Queue.add { top; proj_dir = dir; is_pinned } queue; Hash_string.add visited cur_package_name dir - | _ -> () + | _, _, _ -> () let walk_all_deps dir ~pinned_dependencies : package_context Queue.t = let visited = Hash_string.create 0 in diff --git a/jscomp/bsb/bsb_clean.ml b/jscomp/bsb/bsb_clean.ml index ff8ed40da1..b3457678ec 100644 --- a/jscomp/bsb/bsb_clean.ml +++ b/jscomp/bsb/bsb_clean.ml @@ -51,7 +51,7 @@ let clean_bs_garbage proj_dir = Bsb_log.warn "@{Failed@} to clean due to %s" (Printexc.to_string e) let clean_bs_deps proj_dir = - let _, _, _, pinned_dependencies = Bsb_config_parse.deps_from_bsconfig () in + let _, _, _, pinned_dependencies = Bsb_config_interpret.deps_from_bsconfig () in let queue = Bsb_build_util.walk_all_deps proj_dir ~pinned_dependencies in Queue.iter (fun (pkg_cxt : Bsb_build_util.package_context) -> diff --git a/jscomp/bsb/bsb_config_interpret.ml b/jscomp/bsb/bsb_config_interpret.ml new file mode 100644 index 0000000000..57612f1040 --- /dev/null +++ b/jscomp/bsb/bsb_config_interpret.ml @@ -0,0 +1,367 @@ +(* Copyright (C) 2015 - 2016 Bloomberg Finance L.P. + * Copyright (C) 2017 - Hongbo Zhang, Authors of ReScript + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * In addition to the permissions granted to you by the LGPL, you may combine + * or link a "work that uses the Library" with a publicly distributed version + * of this file to produce a combined library or application, then distribute + * that combined work under the terms of your choosing, with no requirement + * to comply with the obligations normally placed on you by section 4 of the + * LGPL version 3 (or the corresponding section of a later version of the LGPL + * should you choose to use a 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) + +(* let get_list_string = Bsb_build_util.get_list_string *) +let ( // ) = Ext_path.combine + +let resolve_package cwd package_name = + let x = Bsb_pkg.resolve_bs_package ~cwd package_name in + { + Bsb_config_types.package_name; + package_install_path = x // Bsb_config.lib_ocaml; + } + +type json_map = Ext_json_types.t Map_string.t + +(* Key is the path *) +let ( |? ) m (key, cb) = m |> Ext_json.test key cb +let ( .?() ) = Map_string.find_opt + +(*TODO: it is a little mess that [cwd] and [project dir] are shared*) + +let extract_package_name_and_namespace (map : json_map) : string * string option + = + let package_name = + match map.?(Bsb_build_schemas.name) with + | Some (Str { str = "_" } as manifest) -> + Bsb_exception.manifest_error manifest "_ is a reserved package name" + | Some (Str { str = name }) -> name + | Some manifest -> + Bsb_exception.manifest_error manifest "name expect a string field" + | None -> Bsb_exception.invalid_spec "field name is required" + in + let namespace = + match map.?(Bsb_build_schemas.namespace) with + | None | Some (False _) -> None + | Some (True _) -> + Some (Ext_namespace.namespace_of_package_name package_name) + | Some (Str { str }) -> + (*TODO : check the validity of namespace *) + Some (Ext_namespace.namespace_of_package_name str) + | Some manifest -> + Bsb_exception.manifest_error manifest "namespace field expects string or boolean" + in + (package_name, namespace) + +(** + There are two things to check: + - the running bsb and vendoring bsb is the same + - the running bsb need delete stale build artifacts + (kinda check npm upgrade) + + Note if the setup is correct: + the running compiler and node_modules/rescript + should be the same version, + The exact check is that the running compiler should have a + compatible runtime version installed, the location of the + compiler is actually not relevant. + We disable the check temporarily + e.g, + ``` + bsc -runtime runtime_dir@version + ``` +*) +let check_stdlib (map : json_map) : bool = + (*built_in_package*) + match map.?(Bsb_build_schemas.use_stdlib) with + | Some (False _) -> false + | None | Some _ -> true + +let extract_gentype_config (map : json_map) : Bsb_config_types.gentype_config = + match map.?(Bsb_build_schemas.gentype) with + | None -> false + | Some (Obj _) -> true + | Some manifest -> + Bsb_exception.manifest_error manifest "gentypeconfig expect an object" + +let extract_uncurried (map : json_map) : bool = + match map.?(Bsb_build_schemas.uncurried) with + | None -> true + | Some (True _) -> true + | Some (False _) -> false + | Some manifest -> + Bsb_exception.manifest_error manifest "uncurried expects one of: true, false." + +let extract_string (map : json_map) (field : string) cb = + match map.?(field) with + | None -> None + | Some (Str { str }) -> cb str + | Some manifest -> Bsb_exception.manifest_error manifest (field ^ " expect a string") + +let extract_boolean (map : json_map) (field : string) (default : bool) : bool = + match map.?(field) with + | None -> default + | Some (True _) -> true + | Some (False _) -> false + | Some manifest -> + Bsb_exception.manifest_error manifest (field ^ " expect a boolean") + +let extract_reason_react_jsx (map : json_map) = + let default : Bsb_config_types.reason_react_jsx option ref = ref None in + map + |? ( Bsb_build_schemas.reason, + `Obj + (fun m -> + match m.?(Bsb_build_schemas.react_jsx) with + | Some (Flo { loc; flo }) -> ( + match flo with + | "3" -> default := Some Jsx_v3 + | _ -> Bsb_exception.errorf ~loc "Unsupported jsx version %s" flo + ) + | Some x -> + Bsb_exception.manifest_error x + "Unexpected input (expect a version number) for jsx, note \ + boolean is no longer allowed" + | None -> ()) ) + |> ignore; + !default + +let extract_warning (map : json_map) = + match map.?(Bsb_build_schemas.warnings) with + | None -> Bsb_warning.use_default + | Some (Obj { map }) -> Bsb_warning.from_map map + | Some manifest -> Bsb_exception.manifest_error manifest "expect an object" + +let extract_ignored_dirs (map : json_map) : Set_string.t = + match map.?(Bsb_build_schemas.ignored_dirs) with + | None -> Set_string.empty + | Some (Arr { content }) -> + Set_string.of_list (Bsb_build_util.get_list_string content) + | Some manifest -> Bsb_exception.manifest_error manifest "expect an array of string" + +let extract_generators (map : json_map) = + let generators = ref Map_string.empty in + (match map.?(Bsb_build_schemas.generators) with + | None -> () + | Some (Arr { content = s }) -> + generators := + Ext_array.fold_left s Map_string.empty (fun acc json -> + match json with + | Obj { map = m; loc } -> ( + match + (m.?(Bsb_build_schemas.name), m.?(Bsb_build_schemas.command)) + with + | Some (Str { str = name }), Some (Str { str = command }) -> + Map_string.add acc name command + | _, _ -> + Bsb_exception.errorf ~loc + {| generators exepect format like { "name" : "cppo", "command" : "cppo $in -o $out"} |} + ) + | _ -> acc) + | Some manifest -> + Bsb_exception.manifest_error manifest + (Bsb_build_schemas.generators ^ " expect an array field")); + !generators + +let extract_dependencies (map : json_map) cwd (field : string) : + Bsb_config_types.dependencies = + match map.?(field) with + | None -> [] + | Some (Arr { content = s }) -> + Ext_list.map (Bsb_build_util.get_list_string s) (fun s -> + resolve_package cwd (Bsb_pkg_types.string_as_package s)) + | Some manifest -> Bsb_exception.manifest_error manifest (field ^ " expect an array") + +(* return an empty array if not found *) +let extract_string_list (map : json_map) (field : string) : string list = + match map.?(field) with + | None -> [] + | Some (Arr { content = s }) -> Bsb_build_util.get_list_string s + | Some manifest -> Bsb_exception.manifest_error manifest (field ^ " expect an array") + +let extract_ppx (map : json_map) (field : string) ~(cwd : string) : + Bsb_config_types.ppx list = + match map.?(field) with + | None -> [] + | Some (Arr { content }) -> + let resolve s = + if s = "" then + Bsb_exception.invalid_spec "invalid ppx, empty string found" + else + (Bsb_build_util.resolve_bsb_magic_file ~cwd + ~desc:Bsb_build_schemas.ppx_flags s) + .path + in + Ext_array.to_list_f content (fun x -> + match x with + | Str x -> { Bsb_config_types.name = resolve x.str; args = [] } + | Arr { content } -> ( + let xs = Bsb_build_util.get_list_string content in + match xs with + | [] -> Bsb_exception.manifest_error x " empty array is not allowed" + | name :: args -> { Bsb_config_types.name = resolve name; args }) + | manifest -> + Bsb_exception.manifest_error manifest + (field ^ "expect each item to be either string or array")) + | Some manifest -> Bsb_exception.manifest_error manifest (field ^ " expect an array") + +let extract_js_post_build (map : json_map) cwd : string option = + let js_post_build_cmd = ref None in + map + |? ( Bsb_build_schemas.js_post_build, + `Obj + (fun m -> + m + |? ( Bsb_build_schemas.cmd, + `Str + (fun s -> + js_post_build_cmd := + Some + (Bsb_build_util.resolve_bsb_magic_file ~cwd + ~desc:Bsb_build_schemas.js_post_build s) + .path) ) + |> ignore) ) + |> ignore; + !js_post_build_cmd + +(** ATT: make sure such function is re-entrant. + With a given [cwd] it works anywhere*) +let interpret_json ~(package_kind : Bsb_package_kind.t) ~(per_proj_dir : string) ~(warn_legacy_config : bool) + : Bsb_config_types.t = + (* we should not resolve it too early, + since it is external configuration, no {!Bsb_build_util.convert_and_resolve_path} + *) + + (* When we plan to add more deps here, + Make sure check it is consistent that for nested deps, we have a + quck check by just re-parsing deps + Make sure it works with [-make-world] [-clean-world] + *) + + (* Setting ninja is a bit complex + 1. if [build.ninja] does use [ninja] we need set a variable + 2. we need store it so that we can call ninja correctly + *) + match + Bsb_config_parse.parse_json ~per_proj_dir ~warn_legacy_config + with + | filename, _, Obj { map } -> ( + let package_name, namespace = extract_package_name_and_namespace map in + let gentype_config = extract_gentype_config map in + + (* This line has to be before any calls to Bsb_global_backend.backend, because it'll read the entries + array from the bsconfig and set the backend_ref to the first entry, if any. *) + + (* The default situation is empty *) + let built_in_package : bool = check_stdlib map in + + let pp_flags : string option = + extract_string map Bsb_build_schemas.pp_flags (fun p -> + if p = "" then + Bsb_exception.invalid_spec "invalid pp, empty string found" + else + Some + (Bsb_build_util.resolve_bsb_magic_file ~cwd:per_proj_dir + ~desc:Bsb_build_schemas.pp_flags p) + .path) + in + let reason_react_jsx = extract_reason_react_jsx map in + let bs_dependencies = + extract_dependencies map per_proj_dir Bsb_build_schemas.bs_dependencies + in + let bs_dev_dependencies = + match package_kind with + | Toplevel | Pinned_dependency _ -> + extract_dependencies map per_proj_dir + Bsb_build_schemas.bs_dev_dependencies + | Dependency _ -> [] + in + let pinned_dependencies = Bsb_build_util.extract_pinned_dependencies map in + match map.?(Bsb_build_schemas.sources) with + | Some sources -> + let cut_generators = + extract_boolean map Bsb_build_schemas.cut_generators false + in + let groups = + Bsb_parse_sources.scan ~ignored_dirs:(extract_ignored_dirs map) + ~package_kind ~root:per_proj_dir ~cut_generators + (* ~namespace *) + sources + in + let bsc_flags = extract_string_list map Bsb_build_schemas.bsc_flags in + let jsx = Bsb_jsx.from_map map in + let jsx, bsc_flags = + match package_kind with + | Pinned_dependency x | Dependency x -> + if List.mem package_name x.jsx.v3_dependencies then + ( { jsx with version = Some Jsx_v3 }, + "-open ReactV3" :: bsc_flags ) + else (x.jsx, bsc_flags) + | _ -> (jsx, bsc_flags) + in + { + pinned_dependencies; + gentype_config; + package_name; + namespace; + warning = extract_warning map; + external_includes = + extract_string_list map Bsb_build_schemas.bs_external_includes; + bsc_flags; + ppx_files = + extract_ppx map ~cwd:per_proj_dir Bsb_build_schemas.ppx_flags; + pp_file = pp_flags; + bs_dependencies; + bs_dev_dependencies; + (* + reference for quoting + {[ + let tmpfile = Filename.temp_file "ocamlpp" "" in + let comm = Printf.sprintf "%s %s > %s" + pp (Filename.quote sourcefile) tmpfile + in + ]} + *) + js_post_build_cmd = extract_js_post_build map per_proj_dir; + package_specs = + (match package_kind with + | Toplevel -> Bsb_package_specs.from_map ~cwd:per_proj_dir map + | Pinned_dependency x | Dependency x -> x.package_specs); + file_groups = groups; + files_to_install = Queue.create (); + built_in_dependency = built_in_package; + reason_react_jsx; + jsx; + generators = extract_generators map; + cut_generators; + uncurried = + (match package_kind with + | Toplevel -> extract_uncurried map + | Pinned_dependency x | Dependency x -> x.uncurried); + filename; + } + | None -> + Bsb_exception.invalid_spec ("no sources specified in " ^ filename)) + | filename, _, _ -> Bsb_exception.invalid_spec (filename ^ " expect a json object {}") + +let deps_from_bsconfig () = + let cwd = Bsb_global_paths.cwd in + let json = Bsb_config_parse.parse_json ~per_proj_dir:cwd ~warn_legacy_config:false in + match json with + | _, _, Obj { map } -> + ( Bsb_package_specs.from_map ~cwd map, + Bsb_jsx.from_map map, + extract_uncurried map, + Bsb_build_util.extract_pinned_dependencies map ) + | _, _, _ -> assert false diff --git a/jscomp/bsb/bsb_config_parse.mli b/jscomp/bsb/bsb_config_interpret.mli similarity index 93% rename from jscomp/bsb/bsb_config_parse.mli rename to jscomp/bsb/bsb_config_interpret.mli index 3ce5d5e166..84e18eb1ff 100644 --- a/jscomp/bsb/bsb_config_parse.mli +++ b/jscomp/bsb/bsb_config_interpret.mli @@ -25,4 +25,4 @@ val deps_from_bsconfig : unit -> Bsb_package_specs.t * Bsb_jsx.t * bool * Set_string.t val interpret_json : - package_kind:Bsb_package_kind.t -> per_proj_dir:string -> Bsb_config_types.t + package_kind:Bsb_package_kind.t -> per_proj_dir:string -> warn_legacy_config:bool -> Bsb_config_types.t diff --git a/jscomp/bsb/bsb_config_parse.ml b/jscomp/bsb/bsb_config_parse.ml index 0ef2c2da33..1927c6392a 100644 --- a/jscomp/bsb/bsb_config_parse.ml +++ b/jscomp/bsb/bsb_config_parse.ml @@ -1,365 +1,24 @@ -(* Copyright (C) 2015 - 2016 Bloomberg Finance L.P. - * Copyright (C) 2017 - Hongbo Zhang, Authors of ReScript - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * In addition to the permissions granted to you by the LGPL, you may combine - * or link a "work that uses the Library" with a publicly distributed version - * of this file to produce a combined library or application, then distribute - * that combined work under the terms of your choosing, with no requirement - * to comply with the obligations normally placed on you by section 4 of the - * LGPL version 3 (or the corresponding section of a later version of the LGPL - * should you choose to use a 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) - -(* let get_list_string = Bsb_build_util.get_list_string *) -let ( // ) = Ext_path.combine - -let resolve_package cwd package_name = - let x = Bsb_pkg.resolve_bs_package ~cwd package_name in - { - Bsb_config_types.package_name; - package_install_path = x // Bsb_config.lib_ocaml; - } - -type json_map = Ext_json_types.t Map_string.t - -(* Key is the path *) -let ( |? ) m (key, cb) = m |> Ext_json.test key cb -let ( .?() ) = Map_string.find_opt - -(*TODO: it is a little mess that [cwd] and [project dir] are shared*) - -let extract_package_name_and_namespace (map : json_map) : string * string option - = - let package_name = - match map.?(Bsb_build_schemas.name) with - | Some (Str { str = "_" } as config) -> - Bsb_exception.config_error config "_ is a reserved package name" - | Some (Str { str = name }) -> name - | Some config -> - Bsb_exception.config_error config "name expect a string field" - | None -> Bsb_exception.invalid_spec "field name is required" +let parse_json ~(per_proj_dir : string) ~(warn_legacy_config : bool) + : string * string * Ext_json_types.t = + let ( // ) = Ext_path.combine in + let filename, abs, in_chan = + let filename = Literals.rescript_json in + let abs = (per_proj_dir // filename) in + match open_in abs + with + | in_chan -> (filename, abs, in_chan) + | exception e -> + let filename = Literals.bsconfig_json in + let abs = (per_proj_dir // filename) in + match open_in abs + with + | in_chan -> (filename, abs, in_chan) + | exception _ -> raise e (* forward error from rescript.json *) in - let namespace = - match map.?(Bsb_build_schemas.namespace) with - | None | Some (False _) -> None - | Some (True _) -> - Some (Ext_namespace.namespace_of_package_name package_name) - | Some (Str { str }) -> - (*TODO : check the validity of namespace *) - Some (Ext_namespace.namespace_of_package_name str) - | Some x -> - Bsb_exception.config_error x "namespace field expects string or boolean" - in - (package_name, namespace) - -(** - There are two things to check: - - the running bsb and vendoring bsb is the same - - the running bsb need delete stale build artifacts - (kinda check npm upgrade) - - Note if the setup is correct: - the running compiler and node_modules/rescript - should be the same version, - The exact check is that the running compiler should have a - compatible runtime version installed, the location of the - compiler is actually not relevant. - We disable the check temporarily - e.g, - ``` - bsc -runtime runtime_dir@version - ``` -*) -let check_stdlib (map : json_map) : bool = - (*built_in_package*) - match map.?(Bsb_build_schemas.use_stdlib) with - | Some (False _) -> false - | None | Some _ -> true - -let extract_gentype_config (map : json_map) : Bsb_config_types.gentype_config = - match map.?(Bsb_build_schemas.gentypeconfig) with - | None -> false - | Some (Obj _) -> true - | Some config -> - Bsb_exception.config_error config "gentypeconfig expect an object" - -let extract_uncurried (map : json_map) : bool = - match map.?(Bsb_build_schemas.uncurried) with - | None -> true - | Some (True _) -> true - | Some (False _) -> false - | Some config -> - Bsb_exception.config_error config "uncurried expects one of: true, false." - -let extract_string (map : json_map) (field : string) cb = - match map.?(field) with - | None -> None - | Some (Str { str }) -> cb str - | Some config -> Bsb_exception.config_error config (field ^ " expect a string") - -let extract_boolean (map : json_map) (field : string) (default : bool) : bool = - match map.?(field) with - | None -> default - | Some (True _) -> true - | Some (False _) -> false - | Some config -> - Bsb_exception.config_error config (field ^ " expect a boolean") - -let extract_reason_react_jsx (map : json_map) = - let default : Bsb_config_types.reason_react_jsx option ref = ref None in - map - |? ( Bsb_build_schemas.reason, - `Obj - (fun m -> - match m.?(Bsb_build_schemas.react_jsx) with - | Some (Flo { loc; flo }) -> ( - match flo with - | "3" -> default := Some Jsx_v3 - | _ -> Bsb_exception.errorf ~loc "Unsupported jsx version %s" flo - ) - | Some x -> - Bsb_exception.config_error x - "Unexpected input (expect a version number) for jsx, note \ - boolean is no longer allowed" - | None -> ()) ) - |> ignore; - !default - -let extract_warning (map : json_map) = - match map.?(Bsb_build_schemas.warnings) with - | None -> Bsb_warning.use_default - | Some (Obj { map }) -> Bsb_warning.from_map map - | Some config -> Bsb_exception.config_error config "expect an object" - -let extract_ignored_dirs (map : json_map) : Set_string.t = - match map.?(Bsb_build_schemas.ignored_dirs) with - | None -> Set_string.empty - | Some (Arr { content }) -> - Set_string.of_list (Bsb_build_util.get_list_string content) - | Some config -> Bsb_exception.config_error config "expect an array of string" - -let extract_generators (map : json_map) = - let generators = ref Map_string.empty in - (match map.?(Bsb_build_schemas.generators) with - | None -> () - | Some (Arr { content = s }) -> - generators := - Ext_array.fold_left s Map_string.empty (fun acc json -> - match json with - | Obj { map = m; loc } -> ( - match - (m.?(Bsb_build_schemas.name), m.?(Bsb_build_schemas.command)) - with - | Some (Str { str = name }), Some (Str { str = command }) -> - Map_string.add acc name command - | _, _ -> - Bsb_exception.errorf ~loc - {| generators exepect format like { "name" : "cppo", "command" : "cppo $in -o $out"} |} - ) - | _ -> acc) - | Some config -> - Bsb_exception.config_error config - (Bsb_build_schemas.generators ^ " expect an array field")); - !generators - -let extract_dependencies (map : json_map) cwd (field : string) : - Bsb_config_types.dependencies = - match map.?(field) with - | None -> [] - | Some (Arr { content = s }) -> - Ext_list.map (Bsb_build_util.get_list_string s) (fun s -> - resolve_package cwd (Bsb_pkg_types.string_as_package s)) - | Some config -> Bsb_exception.config_error config (field ^ " expect an array") - -(* return an empty array if not found *) -let extract_string_list (map : json_map) (field : string) : string list = - match map.?(field) with - | None -> [] - | Some (Arr { content = s }) -> Bsb_build_util.get_list_string s - | Some config -> Bsb_exception.config_error config (field ^ " expect an array") - -let extract_ppx (map : json_map) (field : string) ~(cwd : string) : - Bsb_config_types.ppx list = - match map.?(field) with - | None -> [] - | Some (Arr { content }) -> - let resolve s = - if s = "" then - Bsb_exception.invalid_spec "invalid ppx, empty string found" - else - (Bsb_build_util.resolve_bsb_magic_file ~cwd - ~desc:Bsb_build_schemas.ppx_flags s) - .path - in - Ext_array.to_list_f content (fun x -> - match x with - | Str x -> { Bsb_config_types.name = resolve x.str; args = [] } - | Arr { content } -> ( - let xs = Bsb_build_util.get_list_string content in - match xs with - | [] -> Bsb_exception.config_error x " empty array is not allowed" - | name :: args -> { Bsb_config_types.name = resolve name; args }) - | config -> - Bsb_exception.config_error config - (field ^ "expect each item to be either string or array")) - | Some config -> Bsb_exception.config_error config (field ^ " expect an array") - -let extract_js_post_build (map : json_map) cwd : string option = - let js_post_build_cmd = ref None in - map - |? ( Bsb_build_schemas.js_post_build, - `Obj - (fun m -> - m - |? ( Bsb_build_schemas.cmd, - `Str - (fun s -> - js_post_build_cmd := - Some - (Bsb_build_util.resolve_bsb_magic_file ~cwd - ~desc:Bsb_build_schemas.js_post_build s) - .path) ) - |> ignore) ) - |> ignore; - !js_post_build_cmd - -(** ATT: make sure such function is re-entrant. - With a given [cwd] it works anywhere*) -let interpret_json ~(package_kind : Bsb_package_kind.t) ~(per_proj_dir : string) - : Bsb_config_types.t = - (* we should not resolve it too early, - since it is external configuration, no {!Bsb_build_util.convert_and_resolve_path} - *) - - (* When we plan to add more deps here, - Make sure check it is consistent that for nested deps, we have a - quck check by just re-parsing deps - Make sure it works with [-make-world] [-clean-world] - *) - - (* Setting ninja is a bit complex - 1. if [build.ninja] does use [ninja] we need set a variable - 2. we need store it so that we can call ninja correctly - *) + if warn_legacy_config && filename = Literals.bsconfig_json then + print_endline "TODO: deprecation warning" ; match - Ext_json_parse.parse_json_from_file (per_proj_dir // Literals.bsconfig_json) + Ext_json_parse.parse_json_from_chan filename in_chan with - | Obj { map } -> ( - let package_name, namespace = extract_package_name_and_namespace map in - let gentype_config = extract_gentype_config map in - - (* This line has to be before any calls to Bsb_global_backend.backend, because it'll read the entries - array from the bsconfig and set the backend_ref to the first entry, if any. *) - - (* The default situation is empty *) - let built_in_package : bool = check_stdlib map in - - let pp_flags : string option = - extract_string map Bsb_build_schemas.pp_flags (fun p -> - if p = "" then - Bsb_exception.invalid_spec "invalid pp, empty string found" - else - Some - (Bsb_build_util.resolve_bsb_magic_file ~cwd:per_proj_dir - ~desc:Bsb_build_schemas.pp_flags p) - .path) - in - let reason_react_jsx = extract_reason_react_jsx map in - let bs_dependencies = - extract_dependencies map per_proj_dir Bsb_build_schemas.bs_dependencies - in - let bs_dev_dependencies = - match package_kind with - | Toplevel | Pinned_dependency _ -> - extract_dependencies map per_proj_dir - Bsb_build_schemas.bs_dev_dependencies - | Dependency _ -> [] - in - let pinned_dependencies = Bsb_build_util.extract_pinned_dependencies map in - match map.?(Bsb_build_schemas.sources) with - | Some sources -> - let cut_generators = - extract_boolean map Bsb_build_schemas.cut_generators false - in - let groups = - Bsb_parse_sources.scan ~ignored_dirs:(extract_ignored_dirs map) - ~package_kind ~root:per_proj_dir ~cut_generators - (* ~namespace *) - sources - in - let bsc_flags = extract_string_list map Bsb_build_schemas.bsc_flags in - let jsx = Bsb_jsx.from_map map in - let jsx, bsc_flags = - match package_kind with - | Pinned_dependency x | Dependency x -> - if List.mem package_name x.jsx.v3_dependencies then - ( { jsx with version = Some Jsx_v3 }, - "-open ReactV3" :: bsc_flags ) - else (x.jsx, bsc_flags) - | _ -> (jsx, bsc_flags) - in - { - pinned_dependencies; - gentype_config; - package_name; - namespace; - warning = extract_warning map; - external_includes = - extract_string_list map Bsb_build_schemas.bs_external_includes; - bsc_flags; - ppx_files = - extract_ppx map ~cwd:per_proj_dir Bsb_build_schemas.ppx_flags; - pp_file = pp_flags; - bs_dependencies; - bs_dev_dependencies; - (* - reference for quoting - {[ - let tmpfile = Filename.temp_file "ocamlpp" "" in - let comm = Printf.sprintf "%s %s > %s" - pp (Filename.quote sourcefile) tmpfile - in - ]} - *) - js_post_build_cmd = extract_js_post_build map per_proj_dir; - package_specs = - (match package_kind with - | Toplevel -> Bsb_package_specs.from_map ~cwd:per_proj_dir map - | Pinned_dependency x | Dependency x -> x.package_specs); - file_groups = groups; - files_to_install = Queue.create (); - built_in_dependency = built_in_package; - reason_react_jsx; - jsx; - generators = extract_generators map; - cut_generators; - uncurried = - (match package_kind with - | Toplevel -> extract_uncurried map - | Pinned_dependency x | Dependency x -> x.uncurried); - } - | None -> - Bsb_exception.invalid_spec "no sources specified in bsconfig.json") - | _ -> Bsb_exception.invalid_spec "bsconfig.json expect a json object {}" - -let deps_from_bsconfig () = - let json = Ext_json_parse.parse_json_from_file Literals.bsconfig_json in - match json with - | Obj { map } -> - ( Bsb_package_specs.from_map ~cwd:Bsb_global_paths.cwd map, - Bsb_jsx.from_map map, - extract_uncurried map, - Bsb_build_util.extract_pinned_dependencies map ) - | _ -> assert false + | v -> close_in in_chan ; (filename, abs, v) + | exception e -> close_in in_chan ; raise e diff --git a/jscomp/bsb/bsb_config_types.ml b/jscomp/bsb/bsb_config_types.ml index 4404ad727d..3b0f4e9ff9 100644 --- a/jscomp/bsb/bsb_config_types.ml +++ b/jscomp/bsb/bsb_config_types.ml @@ -65,4 +65,5 @@ type t = { (* note when used as a dev mode, we will always ignore it *) gentype_config : gentype_config; uncurried: bool; + filename: string; } diff --git a/jscomp/bsb/bsb_exception.ml b/jscomp/bsb/bsb_exception.ml index c6bd9fbdc2..c7e69875f6 100644 --- a/jscomp/bsb/bsb_exception.ml +++ b/jscomp/bsb/bsb_exception.ml @@ -24,7 +24,7 @@ type error = | Package_not_found of Bsb_pkg_types.t * string option (* json file *) - | Json_config of Ext_position.t * string + | Json_manifest of Ext_position.t * string | Invalid_json of string | Invalid_spec of string | Conflict_module of string * string * string @@ -58,17 +58,17 @@ let print (fmt : Format.formatter) (x : error) = let name = Bsb_pkg_types.to_string name in if Ext_string.equal name !Bs_version.package_name then Format.fprintf fmt - "File \"bsconfig.json\", line 1\n\ + "File \"rescript.json\", line 1\n\ @{Error:@} package @{%s@} is not found %s\n\ It's the basic, required package. If you have it installed globally,\n\ Please run `npm link rescript` to make it available" name in_json else Format.fprintf fmt - "File \"bsconfig.json\", line 1\n\ + "File \"rescript.json\", line 1\n\ @{Error:@} package @{%s@} not found or built %s\n\ - Did you install it?\n\ - If you did, did you run `rescript build -with-deps`?" name in_json - | Json_config (pos, s) -> + | Json_manifest (pos, s) -> Format.fprintf fmt "File %S, line %d:\n\ @{Error:@} %s \n\ @@ -76,7 +76,7 @@ let print (fmt : Format.formatter) (x : error) = https://rescript-lang.org/docs/manual/latest/build-configuration-schema" pos.pos_fname pos.pos_lnum s | Invalid_spec s -> - Format.fprintf fmt "@{Error: Invalid bsconfig.json %s@}" s + Format.fprintf fmt "@{Error: Invalid rescript.json %s@}" s | Invalid_json s -> Format.fprintf fmt "File %S, line 1\n@{Error: Invalid json format@}" s @@ -89,12 +89,12 @@ let no_implementation modname = error (No_implementation modname) let not_consistent modname = error (Not_consistent modname) let errorf ~loc fmt = - Format.ksprintf (fun s -> error (Json_config (loc, s))) fmt + Format.ksprintf (fun s -> error (Json_manifest (loc, s))) fmt -let config_error config fmt = - let loc = Ext_json.loc_of config in +let manifest_error manifest fmt = + let loc = Ext_json.loc_of manifest in - error (Json_config (loc, fmt)) + error (Json_manifest (loc, fmt)) let invalid_spec s = error (Invalid_spec s) diff --git a/jscomp/bsb/bsb_exception.mli b/jscomp/bsb/bsb_exception.mli index 9f40866583..0d8cb4acba 100644 --- a/jscomp/bsb/bsb_exception.mli +++ b/jscomp/bsb/bsb_exception.mli @@ -37,7 +37,7 @@ val conflict_module : string -> string -> string -> exn val errorf : loc:Ext_position.t -> ('a, unit, string, 'b) format4 -> 'a -val config_error : Ext_json_types.t -> string -> 'a +val manifest_error : Ext_json_types.t -> string -> 'a val invalid_spec : string -> 'a diff --git a/jscomp/bsb/bsb_jsx.ml b/jscomp/bsb/bsb_jsx.ml index b4a66de189..260de7a4a5 100644 --- a/jscomp/bsb/bsb_jsx.ml +++ b/jscomp/bsb/bsb_jsx.ml @@ -48,7 +48,7 @@ let from_map map = | _ -> Bsb_exception.errorf ~loc "Unsupported jsx version %s" flo ) | Some x -> - Bsb_exception.config_error x + Bsb_exception.manifest_error x "Unexpected input (expect a version number) for jsx version" | None -> ()) ) |? ( Bsb_build_schemas.jsx, @@ -60,7 +60,7 @@ let from_map map = | "react" -> module_ := Some React | _ -> Bsb_exception.errorf ~loc "Unsupported jsx module %s" str) | Some x -> - Bsb_exception.config_error x + Bsb_exception.manifest_error x "Unexpected input (jsx module name) for jsx module" | None -> ()) ) |? ( Bsb_build_schemas.jsx, @@ -73,7 +73,7 @@ let from_map map = | "automatic" -> mode := Some Automatic | _ -> Bsb_exception.errorf ~loc "Unsupported jsx mode %s" str) | Some x -> - Bsb_exception.config_error x + Bsb_exception.manifest_error x "Unexpected input (expect classic or automatic) for jsx mode" | None -> ()) ) |? ( Bsb_build_schemas.jsx, @@ -83,7 +83,7 @@ let from_map map = | Some (Arr { content }) -> v3_dependencies := get_list_string content | Some x -> - Bsb_exception.config_error x + Bsb_exception.manifest_error x "Unexpected input for jsx v3-dependencies" | None -> ()) ) |> ignore; diff --git a/jscomp/bsb/bsb_manifest.ml b/jscomp/bsb/bsb_manifest.ml new file mode 100644 index 0000000000..ffdaf0d43e --- /dev/null +++ b/jscomp/bsb/bsb_manifest.ml @@ -0,0 +1,62 @@ +let ( // ) = Ext_path.combine + +let ( |? ) m (key, cb) = m |> Ext_json.test key cb +let ( .?() ) = Map_string.find_opt + +let load_json ~(per_proj_dir : string) ~(warn_legacy_manifest : bool) : string * string * Ext_json_types.t = + let filename, absolute_path, in_chan = + let filename = Literals.rescript_json in + let absolute_path = (per_proj_dir // filename) in + match open_in absolute_path + with + | in_chan -> (filename, absolute_path, in_chan) + | exception e -> + let filename = Literals.bsconfig_json in + let absolute_path = (per_proj_dir // filename) in + match open_in absolute_path + with + | in_chan -> (filename, absolute_path, in_chan) + | exception _ -> raise e (* forward error from rescript.json *) + in + if warn_legacy_manifest && filename = Literals.bsconfig_json then + print_endline "TODO: deprecation warning" ; + match + Ext_json_parse.parse_json_from_chan filename in_chan + with + | v -> close_in in_chan ; (filename, absolute_path, v) + | exception e -> close_in in_chan ; raise e + +let from_json (json : Ext_json_types.t) ~(filename : string) : Bsb_manifest_types.t = + match json with + | Obj { map } -> ( + let open Bsb_manifest_fields in + let package_name, namespace = extract_package_name_and_namespace map in + let suffix = extract_suffix map in + let package_specs = extract_package_specs map ~suffix in + { + package_name; + namespace; + suffix; + package_specs; + warning = extract_warning map; + external_includes = extract_string_list map Bsb_build_schemas.bs_external_includes; + bsc_flags = extract_string_list map Bsb_build_schemas.bsc_flags; + generators = extract_generators map; + bs_dependencies = extract_string_list map Bsb_build_schemas.bs_dependencies; + bs_dev_dependencies = extract_string_list map Bsb_build_schemas.bs_dev_dependencies; + pinned_dependencies = extract_string_list map Bsb_build_schemas.pinned_dependencies |> Set_string.of_list; + ppx_flags = extract_ppx_flags map; + pp_flags = extract_string map Bsb_build_schemas.pp_flags; + sources = extract_sources map; + js_post_build_cmd = extract_js_post_build map; + ignored_dirs = extract_string_list map Bsb_build_schemas.ignored_dirs; + use_stdlib = extract_boolean map Bsb_build_schemas.use_stdlib true; + external_stdlib = extract_string map Bsb_build_schemas.external_stdlib; + reason_react = extract_reason_react map; + jsx = extract_jsx map; + cut_generators = extract_boolean map Bsb_build_schemas.cut_generators false; + uncurried = extract_boolean map Bsb_build_schemas.uncurried true; + gentype = extract_gentype map ~package_specs; + } + ) + | _ -> Bsb_exception.invalid_spec (filename ^ " expect a json object {}") diff --git a/jscomp/bsb/bsb_manifest_fields.ml b/jscomp/bsb/bsb_manifest_fields.ml new file mode 100644 index 0000000000..07ce270f4a --- /dev/null +++ b/jscomp/bsb/bsb_manifest_fields.ml @@ -0,0 +1,470 @@ +let ( |? ) m (key, cb) = m |> Ext_json.test key cb +let ( .?() ) = Map_string.find_opt + +let get_list_string (arr : Ext_json_types.t array) = + Ext_array.to_list_f arr (function + | Str { str } -> str + | field -> Bsb_exception.manifest_error field "expects a string") + +type json_map = Ext_json_types.t Map_string.t + +let extract_string (map : json_map) (field_name : string) = + match map.?(field_name) with + | None -> None + | Some (Str { str }) -> Some(str) + | Some field -> Bsb_exception.manifest_error field (field_name ^ " expects a string") + +let extract_boolean (map : json_map) (field_name : string) (default : bool) : bool = + match map.?(field_name) with + | None -> default + | Some (True _) -> true + | Some (False _) -> false + | Some field -> + Bsb_exception.manifest_error field (field_name ^ " expects a boolean") + +(* return an empty array if not found *) +let extract_string_list (map : json_map) (field_name : string) = + match map.?(field_name) with + | None -> [] + | Some (Arr { content = s }) -> get_list_string s + | Some field -> Bsb_exception.manifest_error field (field_name ^ " expects an array of string") + +let extract_package_name_and_namespace (map : json_map) : string * string option + = + let package_name = + match map.?(Bsb_build_schemas.name) with + | Some (Str { str = "_" } as manifest) -> + Bsb_exception.manifest_error manifest "_ is a reserved package name" + | Some (Str { str = name }) -> name + | Some field -> + Bsb_exception.manifest_error field "name field expects a string" + | None -> Bsb_exception.invalid_spec "name field is required" + in + let namespace = + match map.?(Bsb_build_schemas.namespace) with + | None | Some (False _) -> None + | Some (True _) -> + Some (Ext_namespace.namespace_of_package_name package_name) + | Some (Str { str }) -> + (*TODO : check the validity of namespace *) + Some (Ext_namespace.namespace_of_package_name str) + | Some field -> + Bsb_exception.manifest_error field "namespace field expects string or boolean" + in + (package_name, namespace) + +let extract_reason_react (map : json_map) = + let open Bsb_manifest_types.ReasonReact in + let default : t option ref = ref None in + map + |? ( Bsb_build_schemas.reason, + `Obj + (fun m -> + match m.?(Bsb_build_schemas.react_jsx) with + | Some (Flo { loc; flo }) -> ( + match flo with + | "3" -> default := Some { react_jsx = Jsx_v3 } + | _ -> Bsb_exception.errorf ~loc "Unsupported jsx version %s" flo + ) + | Some field -> + Bsb_exception.manifest_error field + "Unexpected input (expect a version number) for jsx, note \ + boolean is no longer allowed" + | None -> ()) ) + |> ignore; + !default + +let extract_warning (map : json_map) = + let open Bsb_manifest_types.Warning in + match map.?(Bsb_build_schemas.warnings) with + | None -> None + | Some (Obj { map }) -> ( + let number_opt = Map_string.find_opt map Bsb_build_schemas.number in + let error_opt = Map_string.find_opt map Bsb_build_schemas.error in + match (number_opt, error_opt) with + | None, None -> None + | _, _ -> + let error = + match error_opt with + | Some (True _) -> Warn_error_true + | Some (False _) -> Warn_error_false + | Some (Str { str }) -> Warn_error_number str + | Some field -> Bsb_exception.manifest_error field "expects boolean or string" + | None -> Warn_error_false + (* To make it less intrusive : warning error has to be enabled*) + in + let number = + match number_opt with + | Some (Str { str = number }) -> Some number + | None -> None + | Some field -> Bsb_exception.manifest_error field "expects a string" + in + Some { number; error } + ) + | Some field -> Bsb_exception.manifest_error field "expects an object" + +let extract_generators (map : json_map) = + let generators = ref Map_string.empty in + (match map.?(Bsb_build_schemas.generators) with + | None -> () + | Some (Arr { content = s }) -> + generators := + Ext_array.fold_left s Map_string.empty (fun acc json -> + match json with + | Obj { map = m; loc } -> ( + match + (m.?(Bsb_build_schemas.name), m.?(Bsb_build_schemas.command)) + with + | Some (Str { str = name }), Some (Str { str = command }) -> + Map_string.add acc name command + | _, _ -> + Bsb_exception.errorf ~loc + {| generators field exepects format like { "name" : "cppo", "command" : "cppo $in -o $out"} |} + ) + | _ -> acc) + | Some field -> + Bsb_exception.manifest_error field + (Bsb_build_schemas.generators ^ " expects an array field")); + !generators + +let extract_sources (map : json_map) = + let open Bsb_manifest_types.SourceItem in + let rec parse_source (json: Ext_json_types.t) = + match json with + | Str { str = dir } -> from_string dir + | Obj { map } -> + let dir = + match map.?(Bsb_build_schemas.dir) with + | Some Str { str = dir } -> dir + | Some field -> Bsb_exception.manifest_error field "dir field expects string" + | None -> Bsb_exception.invalid_spec "dir field is required for source entry" + in + let type_ = + match map.?(Bsb_build_schemas.type_) with + | Some Str { str = "dev" } -> Some Dev + | Some field -> Bsb_exception.manifest_error field {|type field expects "dev" literal |} + | None -> None + in + let files = + match map.?(Bsb_build_schemas.files) with + | None | Some Arr { content = [||] } -> Files_auto + | Some Arr { content } -> Files_set (Set_string.of_list (get_list_string content)) + | Some Obj { map } -> + let regex = + match map.?(Bsb_build_schemas.slow_re) with + | Some Str { str } -> Str.regexp str + | Some field -> Bsb_exception.manifest_error field "slow-re expects a string" + | None -> Bsb_exception.invalid_spec "slow-re is required for files object" + in + let excludes = + match map.?(Bsb_build_schemas.excludes) with + | Some Arr { content } -> get_list_string content + | Some field -> Bsb_exception.manifest_error field "excludes expects an array of string" + | None -> [] + in + Files_predicate { regex; excludes } + | Some field -> Bsb_exception.manifest_error field "files field expects an array of string or a object" + in + let generators = + let parse_input_output (edge : Ext_json_types.t) : string list * string list = + let error () = + Bsb_exception.manifest_error edge {| invalid edge format, expect ["output" , ":", "input" ]|} + in + match edge with + | Arr { content } -> ( + match + Ext_array.find_and_split content + (fun x () -> match x with Str { str = ":" } -> true | _ -> false) + () + with + | No_split -> error () + | Split (output, input) -> + ( Ext_array.to_list_map output (fun x -> + match x with + | Str { str = ":" } -> error () + | Str { str } -> Some str + | _ -> None), + Ext_array.to_list_map input (fun x -> + match x with + | Str { str = ":" } -> error () + | Str { str } -> + Some str + (* More rigirous error checking: It would trigger a ninja syntax error *) + | _ -> None) )) + | _ -> error () + in + match map.?(Bsb_build_schemas.generators) with + | None -> [] + | Some (Arr { content } as field) -> Ext_array.to_list_f content (function + | Obj { map } -> + let name = + match extract_string map Bsb_build_schemas.name with + | Some name -> name + | None -> Bsb_exception.manifest_error field "Invalid generator format" + in + let output, input = + match map.?(Bsb_build_schemas.edge) with + | Some edge -> parse_input_output edge + | None -> Bsb_exception.manifest_error field "Invalid generator format" + in + { name; output; input } + | _ -> Bsb_exception.manifest_error field "Invalid generator format" + ) + | Some field -> Bsb_exception.manifest_error field "Invalid generator format" + in + let public = + match map.?(Bsb_build_schemas.public) with + | None | Some Str { str = "all" } -> Export_all + | Some Arr { content } -> Export_set (Set_string.of_list (get_list_string content)) + | Some field -> Bsb_exception.manifest_error field "" + in + let resources = extract_string_list map Bsb_build_schemas.resources in + let subdirs = + match map.?(Bsb_build_schemas.subdirs) with + | None -> None + | Some True _ -> Some Recursive_all + | Some False _ -> Some Recursive_none + | Some json -> Some (Recursive_source (parse_source json)) + in + { + dir; + type_; + files; + generators; + public; + resources; + subdirs; + } + | field -> Bsb_exception.manifest_error field "sources entry expects a string or an object" + in + match map.?(Bsb_build_schemas.sources) with + | None -> [] + | Some Arr { content } -> Ext_array.to_list_f content parse_source + | Some field -> [parse_source field] + +let extract_package_specs (map : json_map) ~suffix = + let supported_format (x : string) loc : Ext_module_system.t = + if x = Literals.commonjs then NodeJS + else if x = Literals.es6 then Es6 + else if x = Literals.es6_global then Es6_global + else + Bsb_exception.errorf ~loc + "package-specs: `%s` isn't a valid output module format. It has to be one \ + of: %s, %s or %s" + x Literals.commonjs Literals.es6 Literals.es6_global + in + let from_json_single suffix (x : Ext_json_types.t) : Bsb_manifest_types.package_spec = + match x with + | Str { str = format; loc } -> + { format = supported_format format loc; in_source = false; suffix } + | Obj { map; loc } -> ( + match map.?("module") with + | Some (Str { str = format }) -> + let in_source = + match map.?(Bsb_build_schemas.in_source) with + | Some (True _) -> true + | Some _ | None -> false + in + let suffix = + match map.?(Bsb_build_schemas.suffix) with + | Some (Str { str = suffix; loc }) -> + let s = Ext_js_suffix.of_string suffix in + if s = Unknown_extension then + Bsb_exception.errorf ~loc "expect .js,.bs.js,.mjs or .cjs" + else s + | Some _ -> + Bsb_exception.errorf ~loc:(Ext_json.loc_of x) + "expect a string field" + | None -> suffix + in + { format = supported_format format loc; in_source; suffix } + | Some _ -> + Bsb_exception.errorf ~loc + "package-specs: when the configuration is an object, `module` \ + field should be a string, not an array. If you want to pass \ + multiple module specs, try turning package-specs into an array of \ + objects (or strings) instead." + | None -> + Bsb_exception.errorf ~loc + "package-specs: when the configuration is an object, the `module` \ + field is mandatory.") + | _ -> + Bsb_exception.errorf ~loc:(Ext_json.loc_of x) + "package-specs: we expect either a string or an object." + in + let from_json_array suffix arr = + let spec = ref Bsb_spec_set.empty in + let has_in_source = ref false in + Ext_array.iter arr (fun x -> + let result = from_json_single suffix x in + if result.in_source then + if not !has_in_source then has_in_source := true + else + Bsb_exception.errorf ~loc:(Ext_json.loc_of x) + "package-specs: we've detected two module formats that are both \ + configured to be in-source."; + spec := Bsb_spec_set.add result !spec); + !spec + (* TODO: FIXME: better API without mutating *) + in + match map.?(Bsb_build_schemas.package_specs) with + | Some (Arr { content }) -> from_json_array suffix content + | Some _ | None -> Bsb_spec_set.singleton ({ format = NodeJS; in_source = false; suffix }) + +let extract_ppx_flags (map : json_map) = + let field_name = Bsb_build_schemas.ppx_flags in + match map.?(field_name) with + | None -> [] + | Some (Arr { content }) -> + Ext_array.to_list_f content (fun field -> + match field with + | Str { str } -> { Bsb_manifest_types.name = str; args = [] } + | Arr { content } -> ( + let xs = get_list_string content in + match xs with + | [] -> Bsb_exception.manifest_error field "empty array is not allowed" + | name :: args -> { Bsb_manifest_types.name = name; args }) + | field -> + Bsb_exception.manifest_error field + (field_name ^ "expects each item to be either string or array")) + | Some manifest -> Bsb_exception.manifest_error manifest (field_name ^ " expects an array") + +let extract_suffix (map : json_map) : Ext_js_suffix.t = + match map.?(Bsb_build_schemas.suffix) with + | None -> Js + | Some (Str { str; loc }) -> + let s = Ext_js_suffix.of_string str in + if s = Unknown_extension then + Bsb_exception.errorf ~loc + "expects .js, .mjs, .cjs or .bs.js, .bs.mjs, .bs.cjs here" + else s + | Some field -> + Bsb_exception.manifest_error field + "expects a string extension like \".js\" here" + +let extract_js_post_build (map : json_map) = + let js_post_build_cmd = ref None in + map + |? ( Bsb_build_schemas.js_post_build, + `Obj + (fun m -> + m + |? ( Bsb_build_schemas.cmd, + `Str (fun s -> js_post_build_cmd := Some(s)) ) + |> ignore) ) + |> ignore; + !js_post_build_cmd + +let extract_jsx (map : json_map) = + let open Bsb_manifest_types.Jsx in + let version : version option ref = ref None in + let module_ : module_ option ref = ref None in + let mode : mode option ref = ref None in + let v3_dependencies : dependencies ref = ref [] in + map + |? ( Bsb_build_schemas.jsx, + `Obj + (fun m -> + match m.?(Bsb_build_schemas.jsx_version) with + | Some (Flo { loc; flo }) -> ( + match flo with + | "3" -> version := Some Jsx_v3 + | "4" -> version := Some Jsx_v4 + | _ -> Bsb_exception.errorf ~loc "Unsupported jsx version %s" flo + ) + | Some x -> + Bsb_exception.manifest_error x + "Unexpected input (expect a version number) for jsx version" + | None -> ()) ) + |? ( Bsb_build_schemas.jsx, + `Obj + (fun m -> + match m.?(Bsb_build_schemas.jsx_module) with + | Some (Str { loc; str }) -> ( + match str with + | "react" -> module_ := Some React + | _ -> Bsb_exception.errorf ~loc "Unsupported jsx module %s" str) + | Some x -> + Bsb_exception.manifest_error x + "Unexpected input (jsx module name) for jsx module" + | None -> ()) ) + |? ( Bsb_build_schemas.jsx, + `Obj + (fun m -> + match m.?(Bsb_build_schemas.jsx_mode) with + | Some (Str { loc; str }) -> ( + match str with + | "classic" -> mode := Some Classic + | "automatic" -> mode := Some Automatic + | _ -> Bsb_exception.errorf ~loc "Unsupported jsx mode %s" str) + | Some x -> + Bsb_exception.manifest_error x + "Unexpected input (expect classic or automatic) for jsx mode" + | None -> ()) ) + |? ( Bsb_build_schemas.jsx, + `Obj + (fun m -> + match m.?(Bsb_build_schemas.jsx_v3_dependencies) with + | Some (Arr { content }) -> + v3_dependencies := get_list_string content + | Some x -> + Bsb_exception.manifest_error x + "Unexpected input for jsx v3-dependencies" + | None -> ()) ) + |> ignore; + { + version = !version; + module_ = !module_; + mode = !mode; + v3_dependencies = !v3_dependencies; + } + +let extract_gentype (map : json_map) ~package_specs = + let open Bsb_manifest_types.Gentype in + match map.?(Bsb_build_schemas.gentype) with + | None -> None + | Some (Obj { map }) -> ( + let { Bsb_manifest_types.format } = List.hd package_specs in + let module_ = + match (extract_string map Bsb_build_schemas.gentype_module, format) with + | Some "commonjs", _ -> CommonJS + | Some "es6", _ -> ES6 + | None, NodeJS -> CommonJS + | None, (Es6 | Es6_global) -> ES6 + | _ -> ES6 + in + let moduleResolution = + match extract_string map Bsb_build_schemas.gentype_module_resolution with + | Some "node" -> Node + | Some "node16" -> Node16 + | Some "bundler" -> Bundler + | _ -> Node + in + let shims = + match map.?(Bsb_build_schemas.gentype_shims) with + | None -> Map_string.empty + | Some (Obj { map }) -> + Map_string.map map + (fun x -> + match x with + | Str { str } -> str + | x -> Bsb_exception.manifest_error x "shims expects a record" + ) + | Some manifest -> + Bsb_exception.manifest_error manifest "shims expects a record" + in + let debug = + match map.?(Bsb_build_schemas.gentype_debug) with + | Some (Obj { map }) -> Some map + | _ -> None + in + Some { + module_; + moduleResolution; + shims; + debug; + exportInterfaces = extract_boolean map Bsb_build_schemas.gentype_export_interfaces false; + generatedFileExtension = extract_string map Bsb_build_schemas.gentype_generated_file_extension; + } + ) + | Some field -> Bsb_exception.manifest_error field "gentypeconfig expects an object" diff --git a/jscomp/bsb/bsb_manifest_types.ml b/jscomp/bsb/bsb_manifest_types.ml new file mode 100644 index 0000000000..663c1c0b6d --- /dev/null +++ b/jscomp/bsb/bsb_manifest_types.ml @@ -0,0 +1,131 @@ +module SourceItem = struct + type type_ = Dev + type public = Export_all | Export_set of Set_string.t + + type source = + | Files_auto + | Files_set of Set_string.t + | Files_predicate of { regex : Str.regexp; excludes : string list } + + type build_generator = { + name : string; + input : string list; + output : string list; + } + + type subdirs = Recursive_none | Recursive_all | Recursive_source of t + and t = { + dir : string; + type_ : type_ option; + files : source; + generators : build_generator list; + public : public; + resources : string list; + subdirs : subdirs option; + } + + let from_string dir = + { + dir; + type_ = None; + files = Files_auto; + generators = []; + public = Export_all; + resources = []; + subdirs = None; + } + + let from_string_array dirs = + Ext_list.map dirs from_string +end + +type package_spec = { + format : Ext_module_system.t; + in_source : bool; + suffix : Ext_js_suffix.t; +} + +type ppx_spec = { + name : string; + args : string list; +} + +module Warning = struct + type error = + | Warn_error_false + (* default [false] to make our changes non-intrusive *) + | Warn_error_true + | Warn_error_number of string + + type t = { + number : string option; + error : error; + } +end + +module ReasonReact = struct + type jsx_version = Jsx_v3 + type t = { + react_jsx : jsx_version; + } +end + +module Jsx = struct + type dependencies = string list + type version = Jsx_v3 | Jsx_v4 + type module_ = React + type mode = Classic | Automatic + type t = { + version : version option; + module_ : module_ option; + mode : mode option; + v3_dependencies : dependencies; + } +end + +module Gentype = struct + type module_ = CommonJS | ES6 + + (** Compatibility for `compilerOptions.moduleResolution` in TypeScript projects. *) + type moduleResolution = + | Node (** should drop extension on import statements *) + | Node16 + (** should use TS output's extension (e.g. `.gen.js`) on import statements *) + | Bundler + (** should use TS input's extension (e.g. `.gen.tsx`) on import statements *) + + type t = { + module_ : module_; + moduleResolution : moduleResolution; + exportInterfaces : bool; + generatedFileExtension : string option; + shims : string Map_string.t; + debug : Ext_json_types.t Map_string.t option; + } +end + +type t = { + package_name : string; + namespace : string option; + external_includes : string list; + bsc_flags : string list; + ppx_flags: ppx_spec list; + pp_flags: string option; + bs_dependencies : string list; + bs_dev_dependencies : string list; + pinned_dependencies : Set_string.t; + warning : Warning.t option; + js_post_build_cmd : string option; + sources : SourceItem.t list; + package_specs : package_spec list; + suffix : Ext_js_suffix.t; + reason_react : ReasonReact.t option; + jsx: Jsx.t; + generators : string Map_string.t; + cut_generators : bool; + uncurried : bool; + ignored_dirs : string list; + use_stdlib : bool; + external_stdlib : string option; + gentype : Gentype.t option; +} diff --git a/jscomp/bsb/bsb_ninja_regen.ml b/jscomp/bsb/bsb_ninja_regen.ml index 9481d6cb63..4802323294 100644 --- a/jscomp/bsb/bsb_ninja_regen.ml +++ b/jscomp/bsb/bsb_ninja_regen.ml @@ -30,7 +30,7 @@ let ( // ) = Ext_path.combine return None if we dont need regenerate otherwise return Some info *) -let regenerate_ninja ~(package_kind : Bsb_package_kind.t) ~forced ~per_proj_dir +let regenerate_ninja ~(package_kind : Bsb_package_kind.t) ~forced ~per_proj_dir ~warn_legacy_config : Bsb_config_types.t option = let lib_artifacts_dir = Bsb_config.lib_bs in let lib_bs_dir = per_proj_dir // lib_artifacts_dir in @@ -52,7 +52,7 @@ let regenerate_ninja ~(package_kind : Bsb_package_kind.t) ~forced ~per_proj_dir Bsb_clean.clean_self per_proj_dir); let config : Bsb_config_types.t = - Bsb_config_parse.interpret_json ~package_kind ~per_proj_dir + Bsb_config_interpret.interpret_json ~package_kind ~per_proj_dir ~warn_legacy_config in (* create directory, lib/bs, lib/js, lib/es6 etc *) Bsb_build_util.mkp lib_bs_dir; @@ -75,5 +75,5 @@ let regenerate_ninja ~(package_kind : Bsb_package_kind.t) ~forced ~per_proj_dir since it may add files in the future *) Bsb_ninja_check.record ~package_kind ~per_proj_dir ~config ~file:output_deps - (Literals.bsconfig_json :: config.file_groups.globbed_dirs); + (config.filename :: config.file_groups.globbed_dirs); Some config diff --git a/jscomp/bsb/bsb_ninja_regen.mli b/jscomp/bsb/bsb_ninja_regen.mli index 5409f022f9..b92cf0b115 100644 --- a/jscomp/bsb/bsb_ninja_regen.mli +++ b/jscomp/bsb/bsb_ninja_regen.mli @@ -26,6 +26,7 @@ val regenerate_ninja : package_kind:Bsb_package_kind.t -> forced:bool -> per_proj_dir:string -> + warn_legacy_config:bool -> Bsb_config_types.t option (** Regenerate ninja file by need based on [.bsdeps] return None if we dont need regenerate diff --git a/jscomp/bsb/bsb_package_specs.ml b/jscomp/bsb/bsb_package_specs.ml index eed738e2cc..cf693d1864 100644 --- a/jscomp/bsb/bsb_package_specs.ml +++ b/jscomp/bsb/bsb_package_specs.ml @@ -191,8 +191,8 @@ let extract_bs_suffix_exn (map : json_map) : Ext_js_suffix.t = Bsb_exception.errorf ~loc "expect .js, .mjs, .cjs or .bs.js, .bs.mjs, .bs.cjs here" else s - | Some config -> - Bsb_exception.config_error config + | Some manifest -> + Bsb_exception.manifest_error manifest "expect a string exteion like \".js\" here" let from_map ~(cwd : string) map = diff --git a/jscomp/bsb/bsb_parse_sources.ml b/jscomp/bsb/bsb_parse_sources.ml index e9969e957d..982b39063a 100644 --- a/jscomp/bsb/bsb_parse_sources.ml +++ b/jscomp/bsb/bsb_parse_sources.ml @@ -76,13 +76,13 @@ let extract_pub (input : Ext_json_types.t Map_string.t) else errorf x "invalid str for %s " s | Some (Arr { content }) -> Export_set (collect_pub_modules content cur_sources) - | Some config -> Bsb_exception.config_error config "expect array or string" + | Some x -> Bsb_exception.manifest_error x "expect array or string" | None -> Export_all let extract_resources (input : Ext_json_types.t Map_string.t) : string list = match input.?(Bsb_build_schemas.resources) with | Some (Arr x) -> Bsb_build_util.get_list_string x.content - | Some config -> Bsb_exception.config_error config "expect array " + | Some x -> Bsb_exception.manifest_error x "expect array " | None -> [] let extract_input_output (edge : Ext_json_types.t) : string list * string list = @@ -138,7 +138,7 @@ let extract_predicate (m : json_map) : string -> bool = match m.?(Bsb_build_schemas.excludes) with | None -> [] | Some (Arr { content = arr }) -> Bsb_build_util.get_list_string arr - | Some x -> Bsb_exception.config_error x "excludes expect array " + | Some x -> Bsb_exception.manifest_error x "excludes expect array " in let slow_re = m.?(Bsb_build_schemas.slow_re) in match (slow_re, excludes) with @@ -149,8 +149,8 @@ let extract_predicate (m : json_map) : string -> bool = let re = Str.regexp s in fun name -> Str.string_match re name 0 && not (Ext_list.mem_string excludes name) - | Some config, _ -> - Bsb_exception.config_error config + | Some x, _ -> + Bsb_exception.manifest_error x (Bsb_build_schemas.slow_re ^ " expect a string literal") | None, _ -> fun name -> not (Ext_list.mem_string excludes name) @@ -222,7 +222,7 @@ let rec parsing_source_dir_map ({ cwd = dir } as cxt) then acc else Bsb_db_util.add_basename ~dir acc basename) | Some x -> - Bsb_exception.config_error x "files field expect array or object " + Bsb_exception.manifest_error x "files field expect array or object " in let resources = extract_resources input in let public = extract_pub input sources in @@ -289,7 +289,7 @@ and parsing_single_source ({ package_kind; is_dev; cwd } as cxt) match map.?(Bsb_build_schemas.type_) with | Some (Str { str = "dev" }) -> true | Some _ -> - Bsb_exception.config_error x {|type field expect "dev" literal |} + Bsb_exception.manifest_error x {|type field expect "dev" literal |} | None -> is_dev in match (package_kind, current_dir_index) with @@ -299,13 +299,13 @@ and parsing_single_source ({ package_kind; is_dev; cwd } as cxt) match map.?(Bsb_build_schemas.dir) with | Some (Str { str }) -> if str = Literals.library_file then - Bsb_exception.config_error x (Printf.sprintf "dir field should be different from `%s`" Literals.library_file) + Bsb_exception.manifest_error x (Printf.sprintf "dir field should be different from `%s`" Literals.library_file) else Ext_path.simple_convert_node_path_to_os_path str | Some x -> - Bsb_exception.config_error x "dir expected to be a string" + Bsb_exception.manifest_error x "dir expected to be a string" | None -> - Bsb_exception.config_error x + Bsb_exception.manifest_error x ("required field :" ^ Bsb_build_schemas.dir ^ " missing") in @@ -408,11 +408,11 @@ and walk_source_dir_map (cxt : walk_cxt) sub_dirs_field = TODO: make it configurable *) let clean_re_js root = + let cwd = Bsb_global_paths.cwd in match - Ext_json_parse.parse_json_from_file - (Filename.concat root Literals.bsconfig_json) + Bsb_config_parse.parse_json ~per_proj_dir:cwd ~warn_legacy_config:false with - | Obj { map } -> + | _, _, Obj { map } -> let ignored_dirs = match map.?(Bsb_build_schemas.ignored_dirs) with | Some (Arr { content = x }) -> @@ -420,10 +420,10 @@ let clean_re_js root = | Some _ | None -> Set_string.empty in let gentype_language = - match map.?(Bsb_build_schemas.gentypeconfig) with + match map.?(Bsb_build_schemas.gentype) with | None -> "" | Some (Obj { map }) -> ( - match map.?(Bsb_build_schemas.language) with + match map.?(Bsb_build_schemas.gentype_language) with | None -> "" | Some (Str { str }) -> str | Some _ -> "") @@ -441,5 +441,5 @@ let clean_re_js root = } config with _ -> ()) - | _ -> () + | _, _, _ -> () | exception _ -> () diff --git a/jscomp/bsb/bsb_spec_set.ml b/jscomp/bsb/bsb_spec_set.ml index 829d46a793..c0700cfdbd 100644 --- a/jscomp/bsb/bsb_spec_set.ml +++ b/jscomp/bsb/bsb_spec_set.ml @@ -24,10 +24,7 @@ [@@@warning "+9"] -(* TODO: sync up with {!Js_packages_info.module_system} *) -type format = Ext_module_system.t = NodeJS | Es6 | Es6_global - -type spec = { format : format; in_source : bool; suffix : Ext_js_suffix.t } +type spec = Bsb_manifest_types.package_spec type t = spec list diff --git a/jscomp/bsb/bsb_spec_set.mli b/jscomp/bsb/bsb_spec_set.mli index c59ebb87f5..719b679c4a 100644 --- a/jscomp/bsb/bsb_spec_set.mli +++ b/jscomp/bsb/bsb_spec_set.mli @@ -21,11 +21,10 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -type format = Ext_module_system.t -type spec = { format : format; in_source : bool; suffix : Ext_js_suffix.t } +type spec = Bsb_manifest_types.package_spec -type t = private spec list +type t = spec list val empty : t diff --git a/jscomp/bsb/bsb_warning.ml b/jscomp/bsb/bsb_warning.ml index 179b77a9b6..c7106d118e 100644 --- a/jscomp/bsb/bsb_warning.ml +++ b/jscomp/bsb/bsb_warning.ml @@ -22,15 +22,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -type warning_error = - | Warn_error_false - (* default [false] to make our changes non-intrusive *) - | Warn_error_true - | Warn_error_number of string - -type t0 = { number : string option; error : warning_error } - -type nonrec t = t0 option +open Bsb_manifest_types.Warning +type t = Bsb_manifest_types.Warning.t option let use_default = None @@ -68,7 +61,7 @@ let from_map (m : Ext_json_types.t Map_string.t) = | Some (True _) -> Warn_error_true | Some (False _) -> Warn_error_false | Some (Str { str }) -> Warn_error_number str - | Some x -> Bsb_exception.config_error x "expect true/false or string" + | Some x -> Bsb_exception.manifest_error x "expect true/false or string" | None -> Warn_error_false (* To make it less intrusive : warning error has to be enabled*) in @@ -76,7 +69,7 @@ let from_map (m : Ext_json_types.t Map_string.t) = match number_opt with | Some (Str { str = number }) -> Some number | None -> None - | Some x -> Bsb_exception.config_error x "expect a string" + | Some x -> Bsb_exception.manifest_error x "expect a string" in Some { number; error } diff --git a/jscomp/bsb/bsb_warning.mli b/jscomp/bsb/bsb_warning.mli index d5c3ef923d..cc2f18aa60 100644 --- a/jscomp/bsb/bsb_warning.mli +++ b/jscomp/bsb/bsb_warning.mli @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -type t +type t = Bsb_manifest_types.Warning.t option val to_merlin_string : t -> string (** Extra work is need to make merlin happy *) diff --git a/jscomp/bsb/bsb_world.ml b/jscomp/bsb/bsb_world.ml index df6cdf747a..f3db4362d8 100644 --- a/jscomp/bsb/bsb_world.ml +++ b/jscomp/bsb/bsb_world.ml @@ -30,11 +30,11 @@ let make_world_deps cwd (config : Bsb_config_types.t option) let package_specs, jsx, uncurried, pinned_dependencies = match config with | None -> - (* When this running bsb does not read bsconfig.json, + (* When this running bsb does not read rescript.json, we will read such json file to know which [package-specs] it wants *) - Bsb_config_parse.deps_from_bsconfig () + Bsb_config_interpret.deps_from_bsconfig () | Some config -> (config.package_specs, config.jsx, config.uncurried, config.pinned_dependencies) in @@ -69,7 +69,7 @@ let make_world_deps cwd (config : Bsb_config_types.t option) ~package_kind: (if is_pinned then Pinned_dependency { package_specs; jsx; uncurried } else Dependency { package_specs; jsx; uncurried }) - ~per_proj_dir:proj_dir ~forced:false + ~per_proj_dir:proj_dir ~forced:false ~warn_legacy_config:false in let command = { Bsb_unix.cmd = vendor_ninja; cwd = lib_bs_dir; args } diff --git a/jscomp/bsb_exe/rescript_main.ml b/jscomp/bsb_exe/rescript_main.ml index d3d03c16e7..9506da4f44 100644 --- a/jscomp/bsb_exe/rescript_main.ml +++ b/jscomp/bsb_exe/rescript_main.ml @@ -148,7 +148,7 @@ let build_subcommand ~start argv argv_len = ( "-regen", unit_set_spec force_regenerate, "*internal* \n\ - Always regenerate build.ninja no matter bsconfig.json is changed or \ + Always regenerate build.ninja no matter rescript.json is changed or \ not" ); ("-verbose", call_spec Bsb_log.verbose, "Set the output to be verbose"); |] @@ -162,7 +162,7 @@ let build_subcommand ~start argv argv_len = | _ -> let config_opt = Bsb_ninja_regen.regenerate_ninja ~package_kind:Toplevel - ~per_proj_dir:Bsb_global_paths.cwd ~forced:!force_regenerate + ~per_proj_dir:Bsb_global_paths.cwd ~forced:!force_regenerate ~warn_legacy_config:false in let implict_build = check_deps_installation_directory config_opt in (match (!make_world, implict_build) with @@ -199,7 +199,7 @@ let info_subcommand ~start argv = if !list_files then match Bsb_ninja_regen.regenerate_ninja ~package_kind:Toplevel ~forced:true - ~per_proj_dir:Bsb_global_paths.cwd + ~per_proj_dir:Bsb_global_paths.cwd ~warn_legacy_config:false with | None -> assert false | Some { file_groups = { files } } -> @@ -226,7 +226,7 @@ let () = (* specialize this path which is used in watcher *) let config_opt = Bsb_ninja_regen.regenerate_ninja ~package_kind:Toplevel ~forced:false - ~per_proj_dir:Bsb_global_paths.cwd + ~per_proj_dir:Bsb_global_paths.cwd ~warn_legacy_config:true in if !make_world || check_deps_installation_directory config_opt then Bsb_world.make_world_deps Bsb_global_paths.cwd config_opt [||]; diff --git a/jscomp/build_tests/case/bsconfig.json b/jscomp/build_tests/case/rescript.json similarity index 100% rename from jscomp/build_tests/case/bsconfig.json rename to jscomp/build_tests/case/rescript.json diff --git a/jscomp/build_tests/case2/bsconfig.json b/jscomp/build_tests/case2/rescript.json similarity index 100% rename from jscomp/build_tests/case2/bsconfig.json rename to jscomp/build_tests/case2/rescript.json diff --git a/jscomp/build_tests/case3/bsconfig.json b/jscomp/build_tests/case3/rescript.json similarity index 100% rename from jscomp/build_tests/case3/bsconfig.json rename to jscomp/build_tests/case3/rescript.json diff --git a/jscomp/build_tests/custom_namespace/bsconfig.json b/jscomp/build_tests/custom_namespace/rescript.json similarity index 100% rename from jscomp/build_tests/custom_namespace/bsconfig.json rename to jscomp/build_tests/custom_namespace/rescript.json diff --git a/jscomp/build_tests/cycle/bsconfig.json b/jscomp/build_tests/cycle/rescript.json similarity index 100% rename from jscomp/build_tests/cycle/bsconfig.json rename to jscomp/build_tests/cycle/rescript.json diff --git a/jscomp/build_tests/cycle1/bsconfig.json b/jscomp/build_tests/cycle1/rescript.json similarity index 100% rename from jscomp/build_tests/cycle1/bsconfig.json rename to jscomp/build_tests/cycle1/rescript.json diff --git a/jscomp/build_tests/devdeps/bsconfig.json b/jscomp/build_tests/devdeps/rescript.json similarity index 100% rename from jscomp/build_tests/devdeps/bsconfig.json rename to jscomp/build_tests/devdeps/rescript.json diff --git a/jscomp/build_tests/devonly/bsconfig.json b/jscomp/build_tests/devonly/rescript.json similarity index 100% rename from jscomp/build_tests/devonly/bsconfig.json rename to jscomp/build_tests/devonly/rescript.json diff --git a/jscomp/build_tests/duplicated_symlinked_packages/bsconfig.json b/jscomp/build_tests/duplicated_symlinked_packages/rescript.json similarity index 100% rename from jscomp/build_tests/duplicated_symlinked_packages/bsconfig.json rename to jscomp/build_tests/duplicated_symlinked_packages/rescript.json diff --git a/jscomp/build_tests/exports/bsconfig.json b/jscomp/build_tests/exports/rescript.json similarity index 100% rename from jscomp/build_tests/exports/bsconfig.json rename to jscomp/build_tests/exports/rescript.json diff --git a/jscomp/build_tests/hyphen2/bsconfig.json b/jscomp/build_tests/hyphen2/rescript.json similarity index 100% rename from jscomp/build_tests/hyphen2/bsconfig.json rename to jscomp/build_tests/hyphen2/rescript.json diff --git a/jscomp/build_tests/in_source/bsconfig.json b/jscomp/build_tests/in_source/rescript.json similarity index 100% rename from jscomp/build_tests/in_source/bsconfig.json rename to jscomp/build_tests/in_source/rescript.json diff --git a/jscomp/build_tests/install/bsconfig.json b/jscomp/build_tests/install/rescript.json similarity index 100% rename from jscomp/build_tests/install/bsconfig.json rename to jscomp/build_tests/install/rescript.json diff --git a/jscomp/build_tests/legacy_config/.gitignore b/jscomp/build_tests/legacy_config/.gitignore new file mode 100644 index 0000000000..2f2c18dc12 --- /dev/null +++ b/jscomp/build_tests/legacy_config/.gitignore @@ -0,0 +1,26 @@ +*.exe +*.obj +*.out +*.compile +*.native +*.byte +*.cmo +*.annot +*.cmi +*.cmx +*.cmt +*.cmti +*.cma +*.a +*.cmxa +*.obj +*~ +*.annot +*.cmj +*.bak +lib/bs +*.mlast +*.mliast +.vscode +.merlin +src/**/*.js diff --git a/jscomp/build_tests/legacy_config/bsconfig.json b/jscomp/build_tests/legacy_config/bsconfig.json new file mode 100644 index 0000000000..936efb8c6d --- /dev/null +++ b/jscomp/build_tests/legacy_config/bsconfig.json @@ -0,0 +1,12 @@ +{ + "name": "legacy_config", + "version": "0.1.0", + "sources": [ + "src" + ], + "package-specs": { + "module": "commonjs", + "in-source": true + }, + "suffix": ".bs.js" +} diff --git a/jscomp/build_tests/legacy_config/input.js b/jscomp/build_tests/legacy_config/input.js new file mode 100644 index 0000000000..f8658ed572 --- /dev/null +++ b/jscomp/build_tests/legacy_config/input.js @@ -0,0 +1,10 @@ +var p = require("child_process"); +var assert = require("assert"); +var fs = require("fs"); +var path = require("path"); +var {rescript_exe} = require("../../../scripts/bin_path"); + +var out = p.spawnSync(rescript_exe, { cwd: __dirname }); + +// console.log(out); +// TODO: test deprecation warning diff --git a/jscomp/build_tests/legacy_config/package.json b/jscomp/build_tests/legacy_config/package.json new file mode 100644 index 0000000000..eec69f6ab2 --- /dev/null +++ b/jscomp/build_tests/legacy_config/package.json @@ -0,0 +1,13 @@ +{ + "name": "legacy_config", + "version": "0.1.0", + "scripts": { + "clean": "rescript clean -with-deps", + "build": "rescript", + "watch": "rescript build -w" + }, + "license": "MIT", + "devDependencies": { + "rescript": "11.0.0" + } +} diff --git a/jscomp/build_tests/legacy_config/src/X.res b/jscomp/build_tests/legacy_config/src/X.res new file mode 100644 index 0000000000..8d0b19151f --- /dev/null +++ b/jscomp/build_tests/legacy_config/src/X.res @@ -0,0 +1 @@ +let () = Js.log("Hello, ReScript") diff --git a/jscomp/build_tests/nested/bsconfig.json b/jscomp/build_tests/nested/rescript.json similarity index 100% rename from jscomp/build_tests/nested/bsconfig.json rename to jscomp/build_tests/nested/rescript.json diff --git a/jscomp/build_tests/nnest/bsconfig.json b/jscomp/build_tests/nnest/rescript.json similarity index 100% rename from jscomp/build_tests/nnest/bsconfig.json rename to jscomp/build_tests/nnest/rescript.json diff --git a/jscomp/build_tests/ns/bsconfig.json b/jscomp/build_tests/ns/rescript.json similarity index 100% rename from jscomp/build_tests/ns/bsconfig.json rename to jscomp/build_tests/ns/rescript.json diff --git a/jscomp/build_tests/post-build/bsconfig.json b/jscomp/build_tests/post-build/rescript.json similarity index 100% rename from jscomp/build_tests/post-build/bsconfig.json rename to jscomp/build_tests/post-build/rescript.json diff --git a/jscomp/build_tests/react_ppx/bsconfig.json b/jscomp/build_tests/react_ppx/rescript.json similarity index 100% rename from jscomp/build_tests/react_ppx/bsconfig.json rename to jscomp/build_tests/react_ppx/rescript.json diff --git a/jscomp/build_tests/rerror/bsconfig.json b/jscomp/build_tests/rerror/rescript.json similarity index 100% rename from jscomp/build_tests/rerror/bsconfig.json rename to jscomp/build_tests/rerror/rescript.json diff --git a/jscomp/build_tests/scoped_ppx/bsconfig.json b/jscomp/build_tests/scoped_ppx/rescript.json similarity index 100% rename from jscomp/build_tests/scoped_ppx/bsconfig.json rename to jscomp/build_tests/scoped_ppx/rescript.json diff --git a/jscomp/build_tests/super_errors/expected/modules1.res.expected b/jscomp/build_tests/super_errors/expected/modules1.res.expected index 1ea2fe29e5..f2751af4aa 100644 --- a/jscomp/build_tests/super_errors/expected/modules1.res.expected +++ b/jscomp/build_tests/super_errors/expected/modules1.res.expected @@ -7,7 +7,7 @@ The module or file Foo can't be found. - If it's a third-party dependency: - - Did you list it in bsconfig.json? + - Did you list it in rescript.json? - Did you run `rescript build` instead of `rescript build -with-deps` (latter builds third-parties)? - - Did you include the file's directory in bsconfig.json? \ No newline at end of file + - Did you include the file's directory in rescript.json? diff --git a/jscomp/build_tests/transitive_pinned_dependency1/package.json b/jscomp/build_tests/transitive_pinned_dependency1/rescript.json similarity index 100% rename from jscomp/build_tests/transitive_pinned_dependency1/package.json rename to jscomp/build_tests/transitive_pinned_dependency1/rescript.json diff --git a/jscomp/build_tests/transitive_pinned_dependency2/package.json b/jscomp/build_tests/transitive_pinned_dependency2/rescript.json similarity index 100% rename from jscomp/build_tests/transitive_pinned_dependency2/package.json rename to jscomp/build_tests/transitive_pinned_dependency2/rescript.json diff --git a/jscomp/build_tests/uncurried-always/bsconfig.json b/jscomp/build_tests/uncurried-always/rescript.json similarity index 100% rename from jscomp/build_tests/uncurried-always/bsconfig.json rename to jscomp/build_tests/uncurried-always/rescript.json diff --git a/jscomp/build_tests/unicode/bsconfig.json b/jscomp/build_tests/unicode/rescript.json similarity index 100% rename from jscomp/build_tests/unicode/bsconfig.json rename to jscomp/build_tests/unicode/rescript.json diff --git a/jscomp/build_tests/weird_names/bsconfig.json b/jscomp/build_tests/weird_names/rescript.json similarity index 100% rename from jscomp/build_tests/weird_names/bsconfig.json rename to jscomp/build_tests/weird_names/rescript.json diff --git a/jscomp/build_tests/x-y/bsconfig.json b/jscomp/build_tests/x-y/rescript.json similarity index 100% rename from jscomp/build_tests/x-y/bsconfig.json rename to jscomp/build_tests/x-y/rescript.json diff --git a/jscomp/build_tests/xpkg/bsconfig.json b/jscomp/build_tests/xpkg/rescript.json similarity index 100% rename from jscomp/build_tests/xpkg/bsconfig.json rename to jscomp/build_tests/xpkg/rescript.json diff --git a/jscomp/build_tests/zerocycle/bsconfig.json b/jscomp/build_tests/zerocycle/rescript.json similarity index 100% rename from jscomp/build_tests/zerocycle/bsconfig.json rename to jscomp/build_tests/zerocycle/rescript.json diff --git a/jscomp/ext/ext_path.ml b/jscomp/ext/ext_path.ml index 9ad999077e..4bed4626c3 100644 --- a/jscomp/ext/ext_path.ml +++ b/jscomp/ext/ext_path.ml @@ -269,6 +269,6 @@ let rec find_root_filename ~cwd filename = find_root_filename ~cwd:cwd' filename else Ext_fmt.failwithf ~loc:__LOC__ "%s not found from %s" filename cwd -let find_package_json_dir cwd = find_root_filename ~cwd Literals.bsconfig_json +let find_package_json_dir cwd = find_root_filename ~cwd Literals.package_json let package_dir = lazy (find_package_json_dir (Lazy.force cwd)) diff --git a/jscomp/ext/literals.ml b/jscomp/ext/literals.ml index 6810267cf5..ed410ee8d7 100644 --- a/jscomp/ext/literals.ml +++ b/jscomp/ext/literals.ml @@ -76,6 +76,8 @@ let package_json = "package.json" let bsconfig_json = "bsconfig.json" +let rescript_json = "rescript.json" + let build_ninja = "build.ninja" (* Name of the library file created for each external dependency. *) diff --git a/jscomp/gentype/GenTypeConfig.ml b/jscomp/gentype/GenTypeConfig.ml index 125d94fb5c..ebff24ce1b 100644 --- a/jscomp/gentype/GenTypeConfig.ml +++ b/jscomp/gentype/GenTypeConfig.ml @@ -101,10 +101,14 @@ let setDebug ~gtconf = | Some (Obj {map}) -> Map_string.iter map Debug.setItem | _ -> () -let compilerConfigFile = "bsconfig.json" +let compilerConfigFile = "rescript.json" +let legacyCompilerConfigFile = "bsconfig.json" let rec findProjectRoot ~dir = - if Sys.file_exists (Filename.concat dir compilerConfigFile) then dir + if + Sys.file_exists (Filename.concat dir compilerConfigFile) + || Sys.file_exists (Filename.concat dir legacyCompilerConfigFile) + then dir else let parent = dir |> Filename.dirname in if parent = dir then ( @@ -114,7 +118,7 @@ let rec findProjectRoot ~dir = assert false) else findProjectRoot ~dir:parent -let readConfig ~getBsConfigFile ~namespace = +let readConfig ~getConfigFile ~namespace = let projectRoot = findProjectRoot ~dir:(Sys.getcwd ()) in let bsbProjectRoot = match Sys.getenv_opt "BSB_PROJECT_ROOT" with @@ -230,7 +234,7 @@ let readConfig ~getBsConfigFile ~namespace = sources; } in - match getBsConfigFile ~projectRoot with + match getConfigFile ~projectRoot with | Some bsConfigFile -> ( try let json = bsConfigFile |> Ext_json_parse.parse_json_from_file in diff --git a/jscomp/gentype/Paths.ml b/jscomp/gentype/Paths.ml index b64b5c0b36..ed95905268 100644 --- a/jscomp/gentype/Paths.ml +++ b/jscomp/gentype/Paths.ml @@ -61,10 +61,14 @@ let getCmtFile cmt = in cmtFile -let getBsConfigFile ~projectRoot = - let bsconfig = concat projectRoot Config.compilerConfigFile in - match bsconfig |> Sys.file_exists with - | true -> Some bsconfig - | false -> None +let getConfigFile ~projectRoot = + let config = concat projectRoot Config.compilerConfigFile in + match config |> Sys.file_exists with + | true -> Some config + | false -> ( + let config = concat projectRoot Config.legacyCompilerConfigFile in + match config |> Sys.file_exists with + | true -> Some config + | false -> None) -let readConfig ~namespace = Config.readConfig ~getBsConfigFile ~namespace +let readConfig ~namespace = Config.readConfig ~getConfigFile ~namespace diff --git a/jscomp/gentype_tests/typescript-react-example/package-lock.json b/jscomp/gentype_tests/typescript-react-example/package-lock.json index ba9633e710..85b00f49ec 100644 --- a/jscomp/gentype_tests/typescript-react-example/package-lock.json +++ b/jscomp/gentype_tests/typescript-react-example/package-lock.json @@ -21,7 +21,7 @@ }, "../../..": { "name": "rescript", - "version": "11.0.0-alpha.5", + "version": "11.0.0-alpha.6", "dev": true, "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE", @@ -35,6 +35,9 @@ "nyc": "^15.0.0", "prettier": "^2.7.1", "rollup": "^0.49.2" + }, + "engines": { + "node": ">=10" } }, "node_modules/@rescript/react": { diff --git a/jscomp/gentype_tests/typescript-react-example/bsconfig.json b/jscomp/gentype_tests/typescript-react-example/rescript.json similarity index 100% rename from jscomp/gentype_tests/typescript-react-example/bsconfig.json rename to jscomp/gentype_tests/typescript-react-example/rescript.json diff --git a/jscomp/ml/typetexp.ml b/jscomp/ml/typetexp.ml index 8074e6b7b3..b39f5d5204 100644 --- a/jscomp/ml/typetexp.ml +++ b/jscomp/ml/typetexp.ml @@ -993,10 +993,10 @@ let report_error env ppf = function Format.fprintf ppf "@[\ @{The module or file %a can't be found.@}@,\ @[- If it's a third-party dependency:@,\ - - Did you list it in bsconfig.json?@,\ + - Did you list it in rescript.json?@,\ - @[Did you run `rescript build` instead of `rescript build -with-deps`@ (latter builds third-parties)@]?\ @]@,\ - - Did you include the file's directory in bsconfig.json?@]\ + - Did you include the file's directory in rescript.json?@]\ @]" Printtyp.longident lid end diff --git a/packages/std/README.md b/packages/std/README.md index 84c0f3463a..87a1ce4f49 100644 --- a/packages/std/README.md +++ b/packages/std/README.md @@ -4,7 +4,7 @@ The motiviation of this repo is that when ReScript users want to share their lib It shares the same version schema with ReScript compiler. -When you use this library, the config would be adding such things in bsconfig.json +When you use this library, the config would be adding such things in rescript.json ```json "external-stdlib" : "@rescript/std" diff --git a/rescript b/rescript index 6369e5decb..d2b0dc8eae 100755 --- a/rescript +++ b/rescript @@ -13,7 +13,6 @@ var path = require("path"); var fs = require("fs"); var bsc_exe = require("./scripts/bin_path").bsc_exe; var rescript_exe = require("./scripts/bin_path").rescript_exe; -var bsconfig = "bsconfig.json"; var LAST_BUILD_START = 0; var LAST_FIRED_EVENT = 0; @@ -28,13 +27,20 @@ var lockFileName = path.join(cwd, ".bsb.lock"); process.env.BSB_PROJECT_ROOT = cwd; // console.log('BSB_PROJECT_ROOT:', process.env.BSB_PROJECT_ROOT) +var bsConfig = "bsconfig.json" +var resConfig = "rescript.json"; +var resConfigFile = path.join(cwd, resConfig); +if (!fs.existsSync(resConfigFile)) { + resConfig = bsConfig; + resConfigFile = path.join(cwd, bsConfig); +} + // If the project uses gentype and uses custom file extension // via generatedFileExtension, ignore them in watch mode -var bsConfigFile = path.join(cwd, bsconfig); var genTypeFileExtension = undefined; -if (fs.existsSync(bsConfigFile)) { - var genTypeConfig = require(bsConfigFile).gentypeconfig +if (fs.existsSync(resConfigFile)) { + var genTypeConfig = require(resConfigFile).gentypeconfig if (genTypeConfig) { genTypeFileExtension = genTypeConfig.generatedFileExtension } @@ -373,7 +379,7 @@ if ( watch_generated = watch_config.generated; // close and remove all unused watchers watchers = watchers.filter(function (watcher) { - if (watcher.dir === bsconfig) { + if (watcher.dir === resConfig) { return true; } else if (watch_files.indexOf(watcher.dir) < 0) { dlog(`${watcher.dir} is no longer watched`); @@ -583,7 +589,7 @@ if ( } } - watchers.push({ watcher: fs.watch(bsconfig, on_change), dir: bsconfig }); + watchers.push({ watcher: fs.watch(resConfig, on_change), dir: resConfig }); build(0); } }