|
| 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