diff --git a/.gitignore b/.gitignore index 386c70d047..35ce3492bf 100644 --- a/.gitignore +++ b/.gitignore @@ -44,7 +44,8 @@ _build_playground .idea .DS_Store -node_modules +**/node_modules/ +!tests/build_tests/*/node_modules/ *.dump coverage @@ -52,6 +53,7 @@ coverage .bsdeps .bsbuild lib/ocaml +/lib/ tests/build_tests/*/lib/ #ignore temporary directory *.goog.js diff --git a/compiler/bsb/bsb_config_parse.ml b/compiler/bsb/bsb_config_parse.ml index a185c56c44..9e7ec8a765 100644 --- a/compiler/bsb/bsb_config_parse.ml +++ b/compiler/bsb/bsb_config_parse.ml @@ -283,6 +283,14 @@ let interpret_json ~(filename : string) ~(json : Ext_json_types.t) | Dependency x -> ({jsx with version = x.jsx.version}, bsc_flags) | Toplevel -> (jsx, bsc_flags) in + let language : Bsb_spec_set.language = + match package_kind with + | Dependency x -> x.language + | Toplevel -> ( + match map.?(Bsb_build_schemas.language) with + | Some (Str {str = "typescript"}) -> Typescript + | Some _ | None -> Javascript) + in { gentype_config; package_name; @@ -308,13 +316,15 @@ let interpret_json ~(filename : string) ~(json : Ext_json_types.t) 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 + | Toplevel -> + Bsb_package_specs.from_map ~cwd:per_proj_dir ~language map | Dependency x -> x.package_specs); file_groups = groups; files_to_install = Queue.create (); jsx; generators = extract_generators map; cut_generators; + language; filename; } | None -> Bsb_exception.invalid_spec ("no sources specified in " ^ filename) @@ -323,8 +333,15 @@ let interpret_json ~(filename : string) ~(json : Ext_json_types.t) let deps_from_bsconfig () = let cwd = Bsb_global_paths.cwd in + let ( .?() ) = Map_string.find_opt in match Bsb_config_load.load_json ~per_proj_dir:cwd ~warn_legacy_config:false with - | _, Obj {map} -> (Bsb_package_specs.from_map ~cwd map, Bsb_jsx.from_map map) + | _, Obj {map} -> + let language : Bsb_spec_set.language = + match map.?(Bsb_build_schemas.language) with + | Some (Str {str = "typescript"}) -> Typescript + | Some _ | None -> Javascript + in + (Bsb_package_specs.from_map ~cwd ~language map, Bsb_jsx.from_map map) | _, _ -> assert false diff --git a/compiler/bsb/bsb_config_types.ml b/compiler/bsb/bsb_config_types.ml index 1d026dee53..b19e448ad7 100644 --- a/compiler/bsb/bsb_config_types.ml +++ b/compiler/bsb/bsb_config_types.ml @@ -29,6 +29,7 @@ type dependencies = dependency list type gentype_config = bool type command = string type ppx = {name: string; args: string list} +type language = Bsb_spec_set.language = Javascript | Typescript type t = { package_name: string; @@ -56,5 +57,6 @@ type t = { cut_generators: bool; (* note when used as a dev mode, we will always ignore it *) gentype_config: gentype_config; + language: language; filename: string; } diff --git a/compiler/bsb/bsb_ninja_gen.ml b/compiler/bsb/bsb_ninja_gen.ml index d6dbe62b8a..7abc6d691d 100644 --- a/compiler/bsb/bsb_ninja_gen.ml +++ b/compiler/bsb/bsb_ninja_gen.ml @@ -153,6 +153,8 @@ let output_ninja_and_namespace_map ~per_proj_dir ~package_kind namespace; warning; gentype_config; + language; + filename = _; } : Bsb_config_types.t) : unit = let lib_artifacts_dir = Bsb_config.lib_bs in @@ -197,7 +199,7 @@ let output_ninja_and_namespace_map ~per_proj_dir ~package_kind ~dpkg_incls (* dev dependencies *) ~lib_incls (* its own libs *) ~dev_incls (* its own devs *) - generators + ~language generators in let oc = open_out_bin (cwd_lib_bs // Literals.build_ninja) in diff --git a/compiler/bsb/bsb_ninja_rule.ml b/compiler/bsb/bsb_ninja_rule.ml index d12f845b20..9240db8e45 100644 --- a/compiler/bsb/bsb_ninja_rule.ml +++ b/compiler/bsb/bsb_ninja_rule.ml @@ -92,7 +92,8 @@ let make_custom_rules ~(gentype_config : Bsb_config_types.gentype_config) ~(namespace : string option) ~package_name ~warnings ~(ppx_files : Bsb_config_types.ppx list) ~bsc_flags ~(dpkg_incls : string) ~(lib_incls : string) ~(dev_incls : string) - (custom_rules : command Map_string.t) : builtin = + ~(language : Bsb_spec_set.language) (custom_rules : command Map_string.t) : + builtin = let bs_dep = Ext_filename.maybe_quote Bsb_global_paths.vendor_bsdep in let bsc = Ext_filename.maybe_quote Bsb_global_paths.vendor_bsc in (* FIXME: We don't need set [-o ${out}] when building ast @@ -122,6 +123,9 @@ let make_custom_rules ~(gentype_config : Bsb_config_types.gentype_config) (match gentype_config with | false -> () | true -> Ext_buffer.add_string buf " -bs-gentype"); + (match language with + | Bsb_spec_set.Typescript -> Ext_buffer.add_string buf " -bs-typescript" + | Bsb_spec_set.Javascript -> ()); if read_cmi <> `is_cmi then ( Ext_buffer.add_string buf " -bs-package-name "; Ext_buffer.add_string buf (Ext_filename.maybe_quote package_name); diff --git a/compiler/bsb/bsb_ninja_rule.mli b/compiler/bsb/bsb_ninja_rule.mli index b7678e0c93..5003341258 100644 --- a/compiler/bsb/bsb_ninja_rule.mli +++ b/compiler/bsb/bsb_ninja_rule.mli @@ -79,5 +79,6 @@ val make_custom_rules : dpkg_incls:string -> lib_incls:string -> dev_incls:string -> + language:Bsb_spec_set.language -> command Map_string.t -> builtin diff --git a/compiler/bsb/bsb_package_kind.ml b/compiler/bsb/bsb_package_kind.ml index f014aa884d..900e965f9f 100644 --- a/compiler/bsb/bsb_package_kind.ml +++ b/compiler/bsb/bsb_package_kind.ml @@ -22,7 +22,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -type dep_payload = {package_specs: Bsb_package_specs.t; jsx: Bsb_jsx.t} +type dep_payload = { + package_specs: Bsb_package_specs.t; + jsx: Bsb_jsx.t; + language: Bsb_spec_set.language; +} type t = Toplevel | Dependency of dep_payload (* This package specs comes from the toplevel to diff --git a/compiler/bsb/bsb_package_specs.ml b/compiler/bsb/bsb_package_specs.ml index eaf4ccee02..355312f870 100644 --- a/compiler/bsb/bsb_package_specs.ml +++ b/compiler/bsb/bsb_package_specs.ml @@ -65,9 +65,9 @@ let string_of_format (x : Ext_module_system.t) = | Esmodule -> Literals.esmodule | Es6_global -> Literals.es6_global -let js_suffix_regexp = Str.regexp "[A-Za-z0-9-_.]*\\.[cm]?js" +let suffix_regexp = Str.regexp "[A-Za-z0-9-_.]*\\.[cm]?[jt]s" -let validate_js_suffix suffix = Str.string_match js_suffix_regexp suffix 0 +let validate_suffix suffix = Str.string_match suffix_regexp suffix 0 let rec from_array suffix (arr : Ext_json_types.t array) : Spec_set.t = let spec = ref Spec_set.empty in @@ -98,16 +98,15 @@ and from_json_single suffix (x : Ext_json_types.t) : Bsb_spec_set.spec = in let suffix = match map.?(Bsb_build_schemas.suffix) with - | Some (Str {str = suffix; _}) when validate_js_suffix suffix -> suffix + | Some (Str {str = suffix; _}) when validate_suffix suffix -> suffix | Some (Str {str; loc}) -> Bsb_exception.errorf ~loc - "invalid suffix \"%s\". The suffix and may contain letters, \ - digits, \"-\", \"_\" and \".\" and must end with .js, .mjs or \ - .cjs." + "invalid suffix \"%s\". The suffix must end with .js, .mjs, .cjs, \ + .ts, .mts, or .cts." str | Some _ -> Bsb_exception.errorf ~loc:(Ext_json.loc_of x) - "expected a string extension like \".js\"" + "expected a string extension like \".js\" or \".ts\"" | None -> suffix in {format = supported_format format loc; in_source; suffix} @@ -192,20 +191,26 @@ let list_dirs_by (package_specs : t) (f : string -> unit) = type json_map = Ext_json_types.t Map_string.t -let extract_js_suffix_exn (map : json_map) : string = +let extract_suffix_exn ~(language : Bsb_spec_set.language) (map : json_map) : + string = + let default_suffix = + match language with + | Bsb_spec_set.Javascript -> Literals.suffix_js + | Bsb_spec_set.Typescript -> Literals.suffix_ts + in match map.?(Bsb_build_schemas.suffix) with - | None -> Literals.suffix_js - | Some (Str {str = suffix; _}) when validate_js_suffix suffix -> suffix + | None -> default_suffix + | Some (Str {str = suffix; _}) when validate_suffix suffix -> suffix | Some (Str {str; _} as config) -> Bsb_exception.config_error config ("invalid suffix \"" ^ str - ^ "\". The suffix and may contain letters, digits, \"-\", \"_\" and \".\" \ - and must end with .js, .mjs or .cjs.") + ^ "\". The suffix must end with .js, .mjs, .cjs, .ts, .mts, or .cts.") | Some config -> - Bsb_exception.config_error config "expected a string extension like \".js\"" + Bsb_exception.config_error config + "expected a string extension like \".js\" or \".ts\"" -let from_map ~(cwd : string) map = - let suffix = extract_js_suffix_exn map in +let from_map ~(cwd : string) ~(language : Bsb_spec_set.language) map = + let suffix = extract_suffix_exn ~language map in let modules = match map.?(Bsb_build_schemas.package_specs) with | Some x -> from_json suffix x diff --git a/compiler/bsb/bsb_package_specs.mli b/compiler/bsb/bsb_package_specs.mli index f797dd7878..0d2f43d201 100644 --- a/compiler/bsb/bsb_package_specs.mli +++ b/compiler/bsb/bsb_package_specs.mli @@ -24,7 +24,11 @@ type t -val from_map : cwd:string -> Ext_json_types.t Map_string.t -> t +val from_map : + cwd:string -> + language:Bsb_spec_set.language -> + Ext_json_types.t Map_string.t -> + t val get_list_of_output_js : t -> string -> string list diff --git a/compiler/bsb/bsb_spec_set.ml b/compiler/bsb/bsb_spec_set.ml index d60bc4374a..50c6506fb8 100644 --- a/compiler/bsb/bsb_spec_set.ml +++ b/compiler/bsb/bsb_spec_set.ml @@ -27,6 +27,8 @@ (* TODO: sync up with {!Js_packages_info.module_system} *) type format = Ext_module_system.t +type language = Javascript | Typescript + type spec = {format: format; in_source: bool; suffix: string} type t = spec list diff --git a/compiler/bsb/bsb_spec_set.mli b/compiler/bsb/bsb_spec_set.mli index 96312be026..1bf53c3955 100644 --- a/compiler/bsb/bsb_spec_set.mli +++ b/compiler/bsb/bsb_spec_set.mli @@ -23,6 +23,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) type format = Ext_module_system.t +type language = Javascript | Typescript + type spec = {format: format; in_source: bool; suffix: string} type t = private spec list diff --git a/compiler/bsb/bsb_world.ml b/compiler/bsb/bsb_world.ml index 73c47f0fa6..732897edf2 100644 --- a/compiler/bsb/bsb_world.ml +++ b/compiler/bsb/bsb_world.ml @@ -27,15 +27,16 @@ let vendor_ninja = Bsb_global_paths.vendor_ninja let make_world_deps cwd (config : Bsb_config_types.t option) (ninja_args : string array) = - let package_specs, jsx = + let package_specs, jsx, language = match config with | None -> (* 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 () - | Some config -> (config.package_specs, config.jsx) + let package_specs, jsx = Bsb_config_parse.deps_from_bsconfig () in + (package_specs, jsx, Bsb_spec_set.Javascript) + | Some config -> (config.package_specs, config.jsx, config.language) in let args = if Ext_array.is_empty ninja_args then [|vendor_ninja|] @@ -64,7 +65,7 @@ let make_world_deps cwd (config : Bsb_config_types.t option) Bsb_build_util.mkp lib_bs_dir; let _config : _ option = Bsb_ninja_regen.regenerate_ninja - ~package_kind:(Dependency {package_specs; jsx}) + ~package_kind:(Dependency {package_specs; jsx; language}) ~per_proj_dir:proj_dir ~forced:false ~warn_legacy_config:false ~warn_as_error:None in diff --git a/compiler/bsc/rescript_compiler_main.ml b/compiler/bsc/rescript_compiler_main.ml index ec40263bb6..feaf71a2b0 100644 --- a/compiler/bsc/rescript_compiler_main.ml +++ b/compiler/bsc/rescript_compiler_main.ml @@ -259,6 +259,12 @@ let command_line_flags : (string * Bsc_args.spec * string) array = string_call ignore, "*internal* Set jsx mode, this is no longer used and is a no-op." ); ("-bs-jsx-preserve", set Js_config.jsx_preserve, "*internal* Preserve jsx"); + ( "-bs-typescript", + unit_call (fun _ -> Js_config.ts_output := Js_config.Ts_typescript), + "*internal* Generate TypeScript output with type annotations" ); + ( "-bs-emit-dts", + unit_call (fun _ -> Js_config.emit_dts := true), + "*internal* Emit .d.ts declaration files alongside JavaScript output" ); ( "-bs-package-output", string_call Js_packages_state.update_npm_package_path, "*internal* Set npm-output-path: [opt_module]:path, for example: \ diff --git a/compiler/common/js_config.ml b/compiler/common/js_config.ml index 24aa8b69f1..61d9c39364 100644 --- a/compiler/common/js_config.ml +++ b/compiler/common/js_config.ml @@ -72,3 +72,13 @@ let jsx_module_of_string = function let as_pp = ref false let self_stack : string Stack.t = Stack.create () + +(** TypeScript output mode *) +type ts_output_mode = + | Ts_none (** Plain JavaScript output (default) *) + | Ts_typescript (** Full TypeScript output (.ts) *) + +let ts_output = ref Ts_none + +(** Whether to emit .d.ts declaration files *) +let emit_dts = ref false diff --git a/compiler/common/js_config.mli b/compiler/common/js_config.mli index d6f4bd8ba6..0a4fdf4785 100644 --- a/compiler/common/js_config.mli +++ b/compiler/common/js_config.mli @@ -101,3 +101,13 @@ val jsx_module_of_string : string -> jsx_module val as_pp : bool ref val self_stack : string Stack.t + +(** TypeScript output mode *) +type ts_output_mode = + | Ts_none (** Plain JavaScript output (default) *) + | Ts_typescript (** Full TypeScript output (.ts) *) + +val ts_output : ts_output_mode ref + +val emit_dts : bool ref +(** Whether to emit .d.ts declaration files *) diff --git a/compiler/core/j.ml b/compiler/core/j.ml index dc5aa2514d..d35fe3e0c7 100644 --- a/compiler/core/j.ml +++ b/compiler/core/j.ml @@ -138,6 +138,7 @@ and expression_desc = return_unit: bool; async: bool; directive: string option; + fn_type: Types.type_expr option; } | Str of {delim: delim; txt: string} (* A string is UTF-8 encoded, and may contain @@ -293,13 +294,23 @@ and variable_declaration = { value: expression option; property: property; ident_info: ident_info; + ident_type: Types.type_expr option; + (** Type annotation for TypeScript output *) } (* TODO: For efficency: block should not be a list, it should be able to be concatenated in both ways *) and block = statement list -and program = {block: block; exports: exports; export_set: Set_ident.t} +and program = { + block: block; + exports: exports; + export_set: Set_ident.t; + type_exports: Ts.type_decl list; + (** Exported type declarations for TypeScript output *) + value_exports: Ts.value_export list; + (** Exported values with types for .d.ts generation *) +} and deps_program = { program: program; diff --git a/compiler/core/js_dump.ml b/compiler/core/js_dump.ml index 43967a3f1c..afde62ce1a 100644 --- a/compiler/core/js_dump.ml +++ b/compiler/core/js_dump.ml @@ -55,6 +55,10 @@ module E = Js_exp_make module S = Js_stmt_make module L = Js_dump_lit +(** Current function return type for TypeScript as-assertion on return statements. + Set when entering a function, cleared when exiting. *) +let current_fn_return_type : Types.type_expr option ref = ref None + (* There modules are dynamically inserted in the last stage {Caml_curry} {Caml_option} @@ -175,6 +179,12 @@ let rec exp_need_paren ?(arrow = false) (e : J.expression) = | Optional_block (e, true) when arrow -> exp_need_paren ~arrow e | Optional_block _ -> false +(** Check if an expression needs parentheses when followed by an 'as' assertion. *) +let exp_need_paren_for_as (e : J.expression) : bool = + match e.expression_desc with + | Bin _ | String_append _ | Seq _ | Cond _ | In _ -> true + | _ -> false + (** Print as underscore for unused vars, may not be needed in the future *) (* let ipp_ident cxt f id (un_used : bool) = @@ -193,6 +203,12 @@ let pp_var_assign cxt f id = P.space f; acxt +(** Print `let id` without the `=` sign, for use with type annotations *) +let pp_var_declare_name cxt f id = + P.string f L.let_; + P.space f; + Ext_pp_scope.ident cxt f id + let pp_var_assign_this cxt f id = let cxt = pp_var_assign cxt f id in P.string f L.this; @@ -246,7 +262,36 @@ let continue f = P.string f L.continue; semi f -let formal_parameter_list cxt f l = iter_lst cxt f l Ext_pp_scope.ident comma_sp +(** Print a single parameter with optional type annotation *) +let formal_parameter_with_type cxt f (id : Ident.t) (ty : Ts.ts_type option) : + cxt = + let cxt = Ext_pp_scope.ident cxt f id in + (match (!Js_config.ts_output, ty) with + | Js_config.Ts_typescript, Some t -> Ts.pp_type_annotation f (Some t) + | _ -> ()); + cxt + +(** Print formal parameters with type annotations from fn_type *) +let formal_parameter_list_typed cxt f (params : Ident.t list) + (fn_type : Types.type_expr option) = + match !Js_config.ts_output with + | Js_config.Ts_none -> + (* Plain JS mode - no types *) + iter_lst cxt f params Ext_pp_scope.ident comma_sp + | Js_config.Ts_typescript -> + (* TypeScript mode - add type annotations *) + let typed_params = Ts.typed_idents_of_params params fn_type in + iter_lst cxt f typed_params + (fun cxt f {Ts.ident; ident_type} -> + formal_parameter_with_type cxt f ident ident_type) + comma_sp + +(** Print return type annotation if in TypeScript mode *) +let pp_return_type f (fn_type : Types.type_expr option) : unit = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> + Ts.pp_type_annotation f (Ts.return_type_of_fn_type fn_type) + | Js_config.Ts_none -> () (* IdentMap *) (* @@ -294,7 +339,7 @@ let rec try_optimize_curry cxt f len function_id = Curry_gen.pp_optimize_curry f len; P.paren_group f 1 (fun _ -> expression ~level:1 cxt f function_id) -and pp_function ~return_unit ~async ~is_method ?directive cxt (f : P.t) +and pp_function ~return_unit ~async ~is_method ?directive ?fn_type cxt (f : P.t) ~fn_state (l : Ident.t list) (b : J.block) (env : Js_fun_env.t) : cxt = match b with | [ @@ -374,8 +419,9 @@ and pp_function ~return_unit ~async ~is_method ?directive cxt (f : P.t) | this :: arguments -> let cxt = P.paren_group f 1 (fun _ -> - formal_parameter_list inner_cxt f arguments) + formal_parameter_list_typed inner_cxt f arguments fn_type) in + pp_return_type f fn_type; P.space f; P.brace_vgroup f 1 (fun _ -> let cxt = @@ -386,10 +432,22 @@ and pp_function ~return_unit ~async ~is_method ?directive cxt (f : P.t) else let cxt = match l with - | [single] when arrow -> Ext_pp_scope.ident inner_cxt f single + | [single] when arrow -> + let cxt = Ext_pp_scope.ident inner_cxt f single in + (* Add type annotation for single arrow param in TS mode *) + (match (!Js_config.ts_output, fn_type) with + | Js_config.Ts_typescript, Some ty -> ( + let typed_params = Ts.typed_idents_of_params [single] (Some ty) in + match typed_params with + | [{ident_type = Some t; _}] -> Ts.pp_type_annotation f (Some t) + | _ -> ()) + | _ -> ()); + cxt | l -> - P.paren_group f 1 (fun _ -> formal_parameter_list inner_cxt f l) + P.paren_group f 1 (fun _ -> + formal_parameter_list_typed inner_cxt f l fn_type) in + pp_return_type f fn_type; P.space f; if arrow then ( P.string f L.arrow; @@ -401,30 +459,63 @@ and pp_function ~return_unit ~async ~is_method ?directive cxt (f : P.t) P.string f "}" | ([{statement_desc = Return e}] | [{statement_desc = Exp e}]) when arrow && directive == None -> + let return_type = Ts.return_type_expr_of_fn_type fn_type in + let needs_opaque = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> + Ts.needs_opaque_return_assertion return_type + | Js_config.Ts_none -> false + in (if exp_need_paren ~arrow e then P.paren_group f 0 else P.group f 0) - (fun _ -> ignore (expression ~level:0 cxt f e)) + (fun _ -> + ignore + (P.cond_paren_group f + (needs_opaque && exp_need_paren_for_as e) + (fun _ -> expression ~level:0 cxt f e)); + if needs_opaque then Ts.pp_opaque_return_assertion f return_type) | _ -> + (* Set return type for nested Return statements to use *) + let old_return_type = !current_fn_return_type in + current_fn_return_type := Ts.return_type_expr_of_fn_type fn_type; P.brace_vgroup f 1 (fun _ -> - function_body ?directive ~return_unit cxt f b) + function_body ?directive ~return_unit cxt f b); + current_fn_return_type := old_return_type in let enclose () = + let pp_type_params () = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> Ts.pp_type_params_from_ml f fn_type + | Js_config.Ts_none -> () + in let handle () = match fn_state with | Is_return -> return_sp f; P.string f (L.function_ ~async ~arrow); + pp_type_params (); param_body () | No_name _ -> P.string f (L.function_ ~async ~arrow); + pp_type_params (); param_body () | Name_non_top x -> ignore (pp_var_assign inner_cxt f x : cxt); P.string f (L.function_ ~async ~arrow); + pp_type_params (); param_body (); semi f | Name_top x -> + (* For TypeScript mode, print GADT overloads before the function *) + (match !Js_config.ts_output with + | Js_config.Ts_typescript -> + let param_names = List.map Ident.name l in + (* Use the converted name (e.g., eval -> $$eval) for overloads *) + let js_name = Ext_ident.convert (Ident.name x) in + Ts.pp_gadt_overloads f js_name param_names fn_type + | Js_config.Ts_none -> ()); P.string f (L.function_ ~async ~arrow); ignore (Ext_pp_scope.ident inner_cxt f x : cxt); + pp_type_params (); param_body () in handle () @@ -511,9 +602,10 @@ and expression_desc cxt ~(level : int) f x : cxt = let cxt = expression ~level:0 cxt f e1 in comma_sp f; expression ~level:0 cxt f e2) - | Fun {is_method; params; body; env; return_unit; async; directive} -> + | Fun {is_method; params; body; env; return_unit; async; directive; fn_type} + -> (* TODO: dump for comments *) - pp_function ?directive ~is_method ~return_unit ~async + pp_function ?directive ?fn_type ~is_method ~return_unit ~async ~fn_state:default_fn_exp_state cxt f params body env (* TODO: when [e] is [Js_raw_code] with arity @@ -661,10 +753,12 @@ and expression_desc cxt ~(level : int) f x : cxt = return_unit; async; directive; + fn_type; }; }; ] -> - pp_function ?directive ~is_method ~return_unit ~async + pp_function ?directive ?fn_type ~is_method ~return_unit + ~async ~fn_state:(No_name {single_arg = true}) cxt f params body env | _ -> @@ -1291,7 +1385,8 @@ and variable_declaration top cxt f (variable : J.variable_declaration) : cxt = match variable with | {ident = i; value = None; ident_info; _} -> if ident_info.used_stats = Dead_pure then cxt else pp_var_declare cxt f i - | {ident = name; value = Some e; ident_info = {used_stats; _}} -> ( + | {ident = name; value = Some e; ident_info = {used_stats; _}; ident_type} + -> ( match used_stats with | Dead_pure -> cxt | Dead_non_pure -> @@ -1299,13 +1394,43 @@ and variable_declaration top cxt f (variable : J.variable_declaration) : cxt = statement_desc top cxt f (J.Exp e) | _ -> ( match e.expression_desc with - | Fun {is_method; params; body; env; return_unit; async; directive} -> - pp_function ?directive ~is_method ~return_unit ~async + | Fun + {is_method; params; body; env; return_unit; async; directive; fn_type} + -> + pp_function ?directive ?fn_type ~is_method ~return_unit ~async ~fn_state:(if top then Name_top name else Name_non_top name) cxt f params body env | _ -> - let cxt = pp_var_assign cxt f name in + (* For TypeScript mode, print type annotation between name and = *) + let ty, cxt = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> + let cxt = pp_var_declare_name cxt f name in + let ident_name = Ident.name name in + (* Try ident_type first, then exported value types, then module types *) + let ty = + match ident_type with + | Some _ -> ident_type + | None -> Ts.get_exported_type ident_name + in + (match ty with + | Some _ -> Ts.pp_type_annotation_from_ml f ty + | None -> ( + (* Try module type path for module declarations *) + match Ts.get_module_type_path ident_name with + | Some type_path -> + P.string f ": "; + P.string f type_path + | None -> ())); + P.space f; + P.string f L.eq; + P.space f; + (ty, cxt) + | Js_config.Ts_none -> (None, pp_var_assign cxt f name) + in let cxt = expression ~level:1 cxt f e in + (* Print as assertion for opaque types in TypeScript mode *) + Ts.pp_as_assertion f ty; semi f; cxt)) @@ -1501,9 +1626,10 @@ and statement_desc top cxt f (s : J.statement_desc) : cxt = cxt | Return e -> ( match e.expression_desc with - | Fun {is_method; params; body; env; return_unit; async; directive} -> + | Fun {is_method; params; body; env; return_unit; async; directive; fn_type} + -> let cxt = - pp_function ?directive ~return_unit ~is_method ~async + pp_function ?directive ?fn_type ~return_unit ~is_method ~async ~fn_state:Is_return cxt f params body env in semi f; @@ -1516,7 +1642,19 @@ and statement_desc top cxt f (s : J.statement_desc) : cxt = return_sp f; (* P.string f "return ";(\* ASI -- when there is a comment*\) *) P.group f 0 (fun _ -> - let cxt = expression ~level:0 cxt f e in + let needs_opaque = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> + Ts.needs_opaque_return_assertion !current_fn_return_type + | Js_config.Ts_none -> false + in + let cxt = + P.cond_paren_group f + (needs_opaque && exp_need_paren_for_as e) + (fun _ -> expression ~level:0 cxt f e) + in + if needs_opaque then + Ts.pp_opaque_return_assertion f !current_fn_return_type; semi f; cxt) (* There MUST be a space between the return and its diff --git a/compiler/core/js_dump_program.ml b/compiler/core/js_dump_program.ml index 0a35bdc26a..20be674f1c 100644 --- a/compiler/core/js_dump_program.ml +++ b/compiler/core/js_dump_program.ml @@ -31,7 +31,7 @@ let empty_explanation = let program_is_empty (x : J.program) = match x with - | {block = []; exports = []; export_set = _} -> true + | {block = []; exports = []; export_set = _; type_exports = _} -> true | _ -> false let deps_program_is_empty (x : J.deps_program) = @@ -87,7 +87,67 @@ let node_program ~output_dir f (x : J.deps_program) = in program f cxt x.program -let es6_program ~output_dir fmt f (x : J.deps_program) = +let es6_program ~output_dir ~module_name fmt f (x : J.deps_program) = + (* For TypeScript mode, initialize type state first to collect runtime types *) + let () = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> + Ts.init_type_decls ~module_name x.program.type_exports; + (* Also collect runtime types from value exports for variable type annotations *) + Ts.collect_runtime_types_from_value_exports x.program.value_exports + | Js_config.Ts_none -> () + in + (* Print runtime type import first (before regular imports) *) + let () = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> Ts.pp_runtime_type_import f + | Js_config.Ts_none -> () + in + (* Build a map of module names to their import paths for value imports *) + let value_module_paths = + Ext_list.fold_left x.modules Map_string.empty (fun acc m -> + let name = Ident.name m.id in + let path = Js_name_of_module_id.string_of_module_id m ~output_dir fmt in + Map_string.add acc name path) + in + let value_imported_modules = + Map_string.fold value_module_paths Ts.StringSet.empty (fun k _ acc -> + Ts.StringSet.add k acc) + in + (* Get locally defined modules from type exports *) + let local_modules = Ts.collect_local_module_names x.program.type_exports in + (* Print type-only imports for modules needed by type annotations but not imported for values *) + let () = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> + let type_only_modules = + Ts.get_type_only_modules ~value_imported_modules ~local_modules + in + (* Add blank line before type-only imports if no runtime types were printed *) + if type_only_modules <> [] && not (Ts.RuntimeTypes.has_any ()) then + P.at_least_two_lines f; + List.iter + (fun mod_name -> + (* Try to find the path from value modules first *) + let path = + match Map_string.find_opt value_module_paths mod_name with + | Some p -> p + | None -> + (* For modules not in value imports, use runtime package path. + This handles stdlib modules like Stdlib, Pervasives, Js, etc. *) + let js_file = mod_name ^ ".js" in + Js_packages_info.runtime_package_path fmt js_file + in + P.string f "import type * as "; + P.string f mod_name; + P.string f " from \""; + P.string f path; + P.string f "\";"; + P.newline f) + type_only_modules + | Js_config.Ts_none -> () + in + (* Print regular imports *) let cxt = Js_dump_import_export.imports Ext_pp_scope.empty f (* Not be emitted in import statements *) @@ -103,7 +163,19 @@ let es6_program ~output_dir fmt f (x : J.deps_program) = | External {import_attributes} -> import_attributes | _ -> None ))) in - let () = P.at_least_two_lines f in + (* Emit type declarations for TypeScript mode *) + let has_type_exports = + match !Js_config.ts_output with + | Js_config.Ts_typescript -> + Ts.pp_type_decls_only f x.program.type_exports; + (* Set up exported value types and module paths for variable annotation lookup *) + Ts.set_exported_modules x.program.type_exports; + Ts.set_exported_types x.program.value_exports; + x.program.type_exports <> [] + | Js_config.Ts_none -> false + in + (* Add blank line after imports/type exports before code *) + let () = if not has_type_exports then P.at_least_two_lines f in let cxt = Js_dump.statements true cxt f x.program.block in Js_dump_import_export.es6_export cxt f x.program.exports @@ -126,9 +198,11 @@ let pp_deps_program ~(output_prefix : string) P.string f comment; P.newline f); let output_dir = Filename.dirname output_prefix in + let module_name = Filename.basename output_prefix in ignore (match kind with - | Esmodule | Es6_global -> es6_program ~output_dir kind f program + | Esmodule | Es6_global -> + es6_program ~output_dir ~module_name kind f program | Commonjs -> node_program ~output_dir f program); P.newline f; P.string f diff --git a/compiler/core/js_exp_make.ml b/compiler/core/js_exp_make.ml index 210c0a58dd..fd7f4e8105 100644 --- a/compiler/core/js_exp_make.ml +++ b/compiler/core/js_exp_make.ml @@ -236,7 +236,7 @@ let unit : t = {expression_desc = Undefined {is_unit = true}; comment = None} *) let ocaml_fun ?comment ?immutable_mask ?directive ~return_unit ~async - ~one_unit_arg params body : t = + ~one_unit_arg ~fn_type params body : t = let params = if one_unit_arg then [] else params in let len = List.length params in { @@ -250,11 +250,13 @@ let ocaml_fun ?comment ?immutable_mask ?directive ~return_unit ~async return_unit; async; directive; + fn_type; }; comment; } -let method_ ?comment ?immutable_mask ~async ~return_unit params body : t = +let method_ ?comment ?immutable_mask ~async ~return_unit ~fn_type params body : + t = let len = List.length params in { expression_desc = @@ -267,6 +269,7 @@ let method_ ?comment ?immutable_mask ~async ~return_unit params body : t = return_unit; async; directive = None; + fn_type; }; comment; } @@ -1722,6 +1725,7 @@ let of_block ?comment ?e block : t = return_unit; async = false; directive = None; + fn_type = None; }; } [] diff --git a/compiler/core/js_exp_make.mli b/compiler/core/js_exp_make.mli index ec208532a5..ef21ab9916 100644 --- a/compiler/core/js_exp_make.mli +++ b/compiler/core/js_exp_make.mli @@ -104,6 +104,7 @@ val ocaml_fun : return_unit:bool -> async:bool -> one_unit_arg:bool -> + fn_type:Types.type_expr option -> J.ident list -> J.block -> t @@ -113,6 +114,7 @@ val method_ : ?immutable_mask:bool array -> async:bool -> return_unit:bool -> + fn_type:Types.type_expr option -> J.ident list -> J.block -> t diff --git a/compiler/core/js_fold.ml b/compiler/core/js_fold.ml index 1ffa5e0270..cbb033d0cb 100644 --- a/compiler/core/js_fold.ml +++ b/compiler/core/js_fold.ml @@ -293,7 +293,15 @@ class fold = list (fun _self -> _self#statement) _self method program : program -> 'self_type = - fun {block = _x0; exports = _x1; export_set = _x2} -> + fun { + block = _x0; + exports = _x1; + export_set = _x2; + type_exports = _x3; + value_exports = _x4; + } -> + let _ = _x3 in + let _ = _x4 in let _self = _self#block _x0 in _self diff --git a/compiler/core/js_implementation.ml b/compiler/core/js_implementation.ml index 5f4e4e6c76..a4d98967e4 100644 --- a/compiler/core/js_implementation.ml +++ b/compiler/core/js_implementation.ml @@ -133,7 +133,7 @@ let after_parsing_impl ppf outputprefix (ast : Parsetree.structure) = Lam_compile_env.reset (); let env = Res_compmisc.initial_env ~modulename () in Env.set_unit_name modulename; - let typedtree, coercion, _, _ = + let typedtree, coercion, _, interface_sig = Typemod.type_implementation_more ?check_exists:(if !Js_config.force_cmi then None else Some ()) !Location.input_name outputprefix modulename env ast @@ -146,9 +146,44 @@ let after_parsing_impl ppf outputprefix (ast : Parsetree.structure) = let lambda, exports = Translmod.transl_implementation modulename typedtree_coercion in + (* Set the environment for @as type renaming lookups *) + let () = + if + !Js_config.ts_output = Js_config.Ts_typescript + || !Js_config.emit_dts + then Ts.set_env typedtree.str_final_env + in + (* Extract type declarations for TypeScript or .d.ts output. + Use interface_sig if available (from .resi file), otherwise use str_type. *) + let type_decls = + if + !Js_config.ts_output = Js_config.Ts_typescript + || !Js_config.emit_dts + then Ts.extract_type_decls ~interface_sig typedtree + else [] + in + (* Extract value exports for TypeScript or .d.ts generation. + Filter to only include identifiers that are actually exported in JS. *) + let value_exports = + if + !Js_config.ts_output = Js_config.Ts_typescript + || !Js_config.emit_dts + then + let export_names = + List.fold_left + (fun acc id -> Set_string.add acc (Ident.name id)) + Set_string.empty exports + in + List.filter + (fun (ve : Ts.value_export) -> + Set_string.mem export_names ve.ve_name) + (Ts.extract_value_exports ~interface_sig typedtree) + else [] + in let js_program = print_if_pipe ppf Clflags.dump_rawlambda Printlambda.lambda lambda - |> Lam_compile_main.compile outputprefix exports + |> Lam_compile_main.compile outputprefix exports ~type_decls + ~value_exports in if not !Js_config.cmj_only then Lam_compile_main.lambda_as_module js_program outputprefix); diff --git a/compiler/core/js_name_of_module_id.ml b/compiler/core/js_name_of_module_id.ml index 1d6f30190c..2cd8a6e5a1 100644 --- a/compiler/core/js_name_of_module_id.ml +++ b/compiler/core/js_name_of_module_id.ml @@ -48,6 +48,15 @@ let fix_path_for_windows : string -> string = if Ext_sys.is_windows_or_cygwin then Ext_string.replace_backward_slash else fun s -> s +(** Map TypeScript suffixes to JavaScript suffixes for imports. + TypeScript requires imports to use .js extension even when source is .ts, + because at runtime the files will be .js *) +let ts_suffix_to_js_suffix (suffix : string) : string = + match suffix with + | ".ts" -> ".js" + | ".mts" -> ".mjs" + | ".cts" -> ".cjs" + | _ -> suffix (* dependency is runtime module *) let get_runtime_module_path @@ -139,12 +148,12 @@ let string_of_module_id | Package_found ({suffix} as pkg), Package_script -> let js_file = - Ext_namespace.js_name_of_modulename dep_module_id.id.name case suffix in + Ext_namespace.js_name_of_modulename dep_module_id.id.name case (ts_suffix_to_js_suffix suffix) in pkg.pkg_rel_path // js_file | Package_found ({suffix } as dep_pkg), Package_found cur_pkg -> let js_file = - Ext_namespace.js_name_of_modulename dep_module_id.id.name case suffix in + Ext_namespace.js_name_of_modulename dep_module_id.id.name case (ts_suffix_to_js_suffix suffix) in if Js_packages_info.same_package_by_name current_package_info dep_package_info then Ext_path.node_rebase_file diff --git a/compiler/core/js_record_fold.ml b/compiler/core/js_record_fold.ml index fe71e6f5f1..e02139871a 100644 --- a/compiler/core/js_record_fold.ml +++ b/compiler/core/js_record_fold.ml @@ -297,7 +297,16 @@ let block : 'a. ('a, block) fn = fun _self st arg -> list _self.statement _self st arg let program : 'a. ('a, program) fn = - fun _self st {block = _x0; exports = _x1; export_set = _x2} -> + fun _self st + { + block = _x0; + exports = _x1; + export_set = _x2; + type_exports = _x3; + value_exports = _x4; + } -> + ignore _x3; + ignore _x4; let st = _self.block _self st _x0 in st diff --git a/compiler/core/js_record_iter.ml b/compiler/core/js_record_iter.ml index e6c9ab9646..a08a16c67d 100644 --- a/compiler/core/js_record_iter.ml +++ b/compiler/core/js_record_iter.ml @@ -215,7 +215,16 @@ let variable_declaration : variable_declaration fn = let block : block fn = fun _self arg -> list _self.statement _self arg let program : program fn = - fun _self {block = _x0; exports = _x1; export_set = _x2} -> + fun _self + { + block = _x0; + exports = _x1; + export_set = _x2; + type_exports = _x3; + value_exports = _x4; + } -> + ignore _x3; + ignore _x4; _self.block _self _x0 let deps_program : deps_program fn = diff --git a/compiler/core/js_record_map.ml b/compiler/core/js_record_map.ml index b13fdb2a55..719e06a2fb 100644 --- a/compiler/core/js_record_map.ml +++ b/compiler/core/js_record_map.ml @@ -286,17 +286,37 @@ let statement : statement fn = {statement_desc = _x0; comment = _x1} let variable_declaration : variable_declaration fn = - fun _self {ident = _x0; value = _x1; property = _x2; ident_info = _x3} -> + fun _self + { + ident = _x0; + value = _x1; + property = _x2; + ident_info = _x3; + ident_type = _x4; + } -> let _x0 = _self.ident _self _x0 in let _x1 = option _self.expression _self _x1 in - {ident = _x0; value = _x1; property = _x2; ident_info = _x3} + {ident = _x0; value = _x1; property = _x2; ident_info = _x3; ident_type = _x4} let block : block fn = fun _self arg -> list _self.statement _self arg let program : program fn = - fun _self {block = _x0; exports = _x1; export_set = _x2} -> + fun _self + { + block = _x0; + exports = _x1; + export_set = _x2; + type_exports = _x3; + value_exports = _x4; + } -> let _x0 = _self.block _self _x0 in - {block = _x0; exports = _x1; export_set = _x2} + { + block = _x0; + exports = _x1; + export_set = _x2; + type_exports = _x3; + value_exports = _x4; + } let deps_program : deps_program fn = fun _self {program = _x0; modules = _x1; side_effect = _x2} -> diff --git a/compiler/core/js_stmt_make.ml b/compiler/core/js_stmt_make.ml index e4d87302e9..962b0591e5 100644 --- a/compiler/core/js_stmt_make.ml +++ b/compiler/core/js_stmt_make.ml @@ -52,7 +52,8 @@ let rec exp ?comment (e : E.t) : t = (* | _ when is_pure e -> block [] *) | _ -> {statement_desc = Exp e; comment} -let declare_variable ?comment ?ident_info ~kind (ident : Ident.t) : t = +let declare_variable ?comment ?ident_info ?ident_type ~kind (ident : Ident.t) : + t = let property : J.property = kind in let ident_info : J.ident_info = match ident_info with @@ -60,14 +61,15 @@ let declare_variable ?comment ?ident_info ~kind (ident : Ident.t) : t = | Some x -> x in { - statement_desc = Variable {ident; value = None; property; ident_info}; + statement_desc = + Variable {ident; value = None; property; ident_info; ident_type}; comment; } -let define_variable ?comment ?ident_info ~kind (v : Ident.t) +let define_variable ?comment ?ident_info ?ident_type ~kind (v : Ident.t) (exp : J.expression) : t = match exp.expression_desc with - | Undefined _ -> declare_variable ?comment ?ident_info ~kind v + | Undefined _ -> declare_variable ?comment ?ident_info ?ident_type ~kind v | _ -> let property : J.property = kind in let ident_info : J.ident_info = @@ -77,7 +79,7 @@ let define_variable ?comment ?ident_info ~kind (v : Ident.t) in { statement_desc = - Variable {ident = v; value = Some exp; property; ident_info}; + Variable {ident = v; value = Some exp; property; ident_info; ident_type}; comment; } diff --git a/compiler/core/js_stmt_make.mli b/compiler/core/js_stmt_make.mli index 00a5daae83..3f7fb5defe 100644 --- a/compiler/core/js_stmt_make.mli +++ b/compiler/core/js_stmt_make.mli @@ -83,6 +83,7 @@ val string_switch : val declare_variable : ?comment:string -> ?ident_info:J.ident_info -> + ?ident_type:Types.type_expr -> kind:Lam_compat.let_kind -> Ident.t -> t @@ -92,6 +93,7 @@ val declare_variable : val define_variable : ?comment:string -> ?ident_info:J.ident_info -> + ?ident_type:Types.type_expr -> kind:Lam_compat.let_kind -> Ident.t -> J.expression -> diff --git a/compiler/core/lam.ml b/compiler/core/lam.ml index 51b8bb3e38..5003cf5886 100644 --- a/compiler/core/lam.ml +++ b/compiler/core/lam.ml @@ -22,6 +22,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) +(* Alias to avoid shadowing by local Types module *) +module Ml_types = Types + type ident = Ident.t type apply_status = App_na | App_infer_full | App_uncurry @@ -47,6 +50,7 @@ module Types = struct params: ident list; body: t; attr: Lambda.function_attribute; + fn_type: Ml_types.type_expr option; } (* @@ -138,6 +142,7 @@ module X = struct params: ident list; body: t; attr: Lambda.function_attribute; + fn_type: Ml_types.type_expr option; } and t = Types.t = @@ -173,9 +178,9 @@ let inner_map (l : t) (f : t -> X.t) : X.t = let ap_func = f ap_func in let ap_args = Ext_list.map ap_args f in Lapply {ap_func; ap_args; ap_info; ap_transformed_jsx} - | Lfunction {body; arity; params; attr} -> + | Lfunction {body; arity; params; attr; fn_type} -> let body = f body in - Lfunction {body; arity; params; attr} + Lfunction {body; arity; params; attr; fn_type} | Llet (str, id, arg, body) -> let arg = f arg in let body = f body in @@ -451,8 +456,8 @@ let global_module ?(dynamic_import = false) id = Lglobal_module (id, dynamic_import) let const ct : t = Lconst ct -let function_ ~attr ~arity ~params ~body : t = - Lfunction {arity; params; body; attr} +let function_ ~attr ~arity ~params ~body ~fn_type : t = + Lfunction {arity; params; body; attr; fn_type} let let_ kind id e body : t = Llet (kind, id, e, body) let letrec bindings body : t = Lletrec (bindings, body) diff --git a/compiler/core/lam.mli b/compiler/core/lam.mli index 560d247669..4b380c5f0b 100644 --- a/compiler/core/lam.mli +++ b/compiler/core/lam.mli @@ -53,6 +53,7 @@ and lfunction = { params: ident list; body: t; attr: Lambda.function_attribute; + fn_type: Types.type_expr option; } and prim_info = private { @@ -116,6 +117,7 @@ val function_ : arity:int -> params:ident list -> body:t -> + fn_type:Types.type_expr option -> t val let_ : Lam_compat.let_kind -> ident -> t -> t -> t diff --git a/compiler/core/lam_bounded_vars.ml b/compiler/core/lam_bounded_vars.ml index e038e56798..5dbc148580 100644 --- a/compiler/core/lam_bounded_vars.ml +++ b/compiler/core/lam_bounded_vars.ml @@ -88,10 +88,10 @@ let rewrite (map : _ Hash_ident.t) (lam : Lam.t) : Lam.t = in let body = aux body in Lam.letrec bindings body - | Lfunction {arity; params; body; attr} -> + | Lfunction {arity; params; body; attr; fn_type} -> let params = Ext_list.map params rebind in let body = aux body in - Lam.function_ ~arity ~params ~body ~attr + Lam.function_ ~arity ~params ~body ~attr ~fn_type | Lstaticcatch (l1, (i, xs), l2) -> let l1 = aux l1 in let xs = Ext_list.map xs rebind in diff --git a/compiler/core/lam_compile.ml b/compiler/core/lam_compile.ml index 739056132b..f25bcbf0e4 100644 --- a/compiler/core/lam_compile.ml +++ b/compiler/core/lam_compile.ml @@ -60,7 +60,7 @@ let rec apply_with_arity_aux (fn : J.expression) (arity : int list) Ext_list.init (x - len) (fun _ -> Ext_ident.create "param") in E.ocaml_fun params ~return_unit:false (* unknown info *) - ~async:false ~one_unit_arg:false + ~async:false ~one_unit_arg:false ~fn_type:None [ S.return_stmt (E.call ~info:Js_call_info.ml_full_call fn @@ -329,7 +329,12 @@ let compile output_prefix = (id : Ident.t) (arg : Lam.t) : Js_output.t * initialization = match arg with | Lfunction - {params; body; attr = {return_unit; async; one_unit_arg; directive}} -> + { + params; + body; + attr = {return_unit; async; one_unit_arg; directive}; + fn_type; + } -> (* TODO: Think about recursive value {[ let rec v = ref (fun _ ... @@ -368,7 +373,7 @@ let compile output_prefix = it will be renamed into [method] when it is detected by a primitive *) - ~return_unit ~async ~one_unit_arg ?directive + ~return_unit ~async ~one_unit_arg ?directive ~fn_type ~immutable_mask:ret.immutable_mask (Ext_list.map params (fun x -> Map_ident.find_default ret.new_params x x)) @@ -382,7 +387,7 @@ let compile output_prefix = (* TODO: save computation of length several times *) E.ocaml_fun params (Js_output.output_as_block output) - ~return_unit ~async ~one_unit_arg ?directive + ~return_unit ~async ~one_unit_arg ?directive ~fn_type in ( Js_output.output_of_expression (Declare (Alias, id)) @@ -1623,9 +1628,9 @@ let compile output_prefix = | {primitive = Pjs_unsafe_downgrade _; args} -> assert false | {primitive = Pjs_fn_method; args = args_lambda} -> ( match args_lambda with - | [Lfunction {params; body; attr = {return_unit; async}}] -> + | [Lfunction {params; body; attr = {return_unit; async}; fn_type}] -> Js_output.output_of_block_and_expression lambda_cxt.continuation [] - (E.method_ ~async ~return_unit params + (E.method_ ~async ~return_unit ~fn_type params (* Invariant: jmp_table can not across function boundary, here we share env *) @@ -1740,10 +1745,16 @@ let compile output_prefix = Js_output.t = match cur_lam with | Lfunction - {params; body; attr = {return_unit; async; one_unit_arg; directive}} -> + { + params; + body; + attr = {return_unit; async; one_unit_arg; directive}; + fn_type; + } -> Js_output.output_of_expression lambda_cxt.continuation ~no_effects:no_effects_const (E.ocaml_fun params ~return_unit ~async ~one_unit_arg ?directive + ~fn_type (* Invariant: jmp_table can not across function boundary, here we share env *) diff --git a/compiler/core/lam_compile_main.ml b/compiler/core/lam_compile_main.ml index 5871d643eb..5e2b10eb79 100644 --- a/compiler/core/lam_compile_main.ml +++ b/compiler/core/lam_compile_main.ml @@ -121,9 +121,11 @@ let _j = Js_pass_debug.dump (** Actually simplify_lets is kind of global optimization since it requires you to know whether it's used or not *) -let compile +let compile (output_prefix : string) export_idents + ~(type_decls : Ts.type_decl list) + ~(value_exports : Ts.value_export list) (lam : Lambda.lambda) = let export_ident_sets = Set_ident.of_list export_idents in (* To make toplevel happy - reentrant for js-demo *) @@ -233,11 +235,14 @@ let () = Ext_log.dwarn ~__POS__ "\n@[[TIME:]Post-compile: %f@]@." (Sys.time () (* Ext_marshal.to_file (Ext_path.chop_extension filename ^ ".mj") js; *) let meta_exports = meta.exports in let export_set = Set_ident.of_list meta_exports in -let js : J.program = - { - exports = meta_exports ; - export_set; - block = body} +let js : J.program = + { + exports = meta_exports; + export_set; + block = body; + type_exports = type_decls; + value_exports; + } in js |> _j "initial" @@ -288,33 +293,84 @@ js let (//) = Filename.concat -let lambda_as_module +let lambda_as_module (lambda_output : J.deps_program) (output_prefix : string) - : unit = - let package_info = Js_packages_state.get_packages_info () in - if Js_packages_info.is_empty package_info && !Js_config.js_stdout then begin + : unit = + let package_info = Js_packages_state.get_packages_info () in + if Js_packages_info.is_empty package_info && !Js_config.js_stdout then begin Js_dump_program.dump_deps_program ~output_prefix Commonjs (lambda_output) stdout end else - Js_packages_info.iter package_info (fun {module_system; path; suffix} -> - let output_chan chan = + Js_packages_info.iter package_info (fun {module_system; path; suffix} -> + let output_chan chan = Js_dump_program.dump_deps_program ~output_prefix - module_system + module_system (lambda_output) chan in - let basename = + let basename = Ext_namespace.change_ext_ns_suffix (Filename.basename output_prefix) suffix in - let target_file = + let target_file = (Lazy.force Ext_path.package_dir // path // basename (* #913 only generate little-case js file *) - ) in - (if not !Clflags.dont_write_files then + ) in + (if not !Clflags.dont_write_files then Ext_pervasives.with_file_as_chan target_file output_chan ); - if !Warnings.has_warnings then begin + (* Generate .d.ts file when emit_dts is enabled *) + (if (not !Clflags.dont_write_files) && !Js_config.emit_dts then + (* Convert JS suffix to .d.ts suffix: + .js -> .d.ts, .mjs -> .d.mts, .cjs -> .d.cts, .res.js -> .res.d.ts *) + let js_to_dts ext = + match ext with + | ".mjs" -> ".d.mts" + | ".cjs" -> ".d.cts" + | _ -> ".d.ts" + in + let dts_file = + let base = Ext_filename.chop_extension_maybe target_file in + let ext = Ext_filename.get_extension_maybe target_file in + base ^ js_to_dts ext + in + let output_dir = Filename.dirname target_file in + (* Compute imports for .d.ts file - keep .js extension for imports + since TypeScript will automatically resolve to .d.ts *) + let dts_imports = + Ext_list.filter_map lambda_output.modules (fun (m : J.module_id) -> + if m.dynamic_import then None + else + let module_name = Ident.name m.id in + let module_path = + Js_name_of_module_id.string_of_module_id m ~output_dir + module_system + in + Some Ts.{module_name; module_path}) + in + let module_name = Filename.basename output_prefix in + (* Resolver function for type-only module imports. + Returns None for modules that can't be found (e.g., local module aliases). *) + let resolve_module_path mod_name = + let dep_id = Ident.create mod_name in + let dep_module_id = Lam_module_ident.of_ml dep_id in + (* Check if the CMJ file exists before trying to resolve *) + let cmj_file = mod_name ^ Literals.suffix_cmj in + match Config_util.find_opt cmj_file with + | None -> + (* CMJ not found - likely a local module alias *) + None + | Some _ -> + Some + (Js_name_of_module_id.string_of_module_id dep_module_id + ~output_dir module_system) + in + Ext_pervasives.with_file_as_chan dts_file (fun chan -> + let f = Ext_pp.from_channel chan in + Ts.pp_dts_file ~module_name ~resolve_module_path ~suffix f + dts_imports lambda_output.program.type_exports + lambda_output.program.value_exports)); + if !Warnings.has_warnings then begin Warnings.has_warnings := false ; #ifndef BROWSER (* 5206: When there were warnings found during the compilation, we want the file @@ -323,11 +379,11 @@ let lambda_as_module (Do *not* set the timestamp of the JS output file instead as that does not play well with every bundler.) *) let ast_file = output_prefix ^ Literals.suffix_ast in - if Sys.file_exists ast_file then begin + if Sys.file_exists ast_file then begin Bs_hash_stubs.set_as_old_file ast_file - end -#endif - end + end +#endif + end ) diff --git a/compiler/core/lam_compile_main.mli b/compiler/core/lam_compile_main.mli index fcd298ce3a..51b8e0499d 100644 --- a/compiler/core/lam_compile_main.mli +++ b/compiler/core/lam_compile_main.mli @@ -27,7 +27,13 @@ (** Compile and register the hook of function to compile a lambda to JS IR *) -val compile : string -> Ident.t list -> Lambda.lambda -> J.deps_program +val compile : + string -> + Ident.t list -> + type_decls:Ts.type_decl list -> + value_exports:Ts.value_export list -> + Lambda.lambda -> + J.deps_program (** For toplevel, [filename] is [""] which is the same as {!Env.get_unit_name ()} *) diff --git a/compiler/core/lam_compile_primitive.ml b/compiler/core/lam_compile_primitive.ml index e7c377e97a..1aac871d7c 100644 --- a/compiler/core/lam_compile_primitive.ml +++ b/compiler/core/lam_compile_primitive.ml @@ -64,7 +64,8 @@ let wrap_then import value = let arg = Ident.create "m" in E.call ~info:call_info (E.dot import "then") [ - E.ocaml_fun ~return_unit:false ~async:false ~one_unit_arg:false [arg] + E.ocaml_fun ~return_unit:false ~async:false ~one_unit_arg:false + ~fn_type:None [arg] [{statement_desc = J.Return (E.dot (E.var arg) value); comment = None}]; ] diff --git a/compiler/core/lam_convert.ml b/compiler/core/lam_convert.ml index 2e88a3b703..2cc8609432 100644 --- a/compiler/core/lam_convert.ml +++ b/compiler/core/lam_convert.ml @@ -405,19 +405,19 @@ let convert (exports : Set_ident.t) (lam : Lambda.lambda) : (Ext_list.map args convert_aux) {ap_loc = loc; ap_inlined; ap_status = App_uncurry} ~ap_transformed_jsx - | Lfunction {params; body; attr} -> + | Lfunction {params; body; attr; fn_type} -> let new_map, body = rename_optional_parameters Map_ident.empty params body in if Map_ident.is_empty new_map then Lam.function_ ~attr ~arity:(List.length params) ~params - ~body:(convert_aux body) + ~body:(convert_aux body) ~fn_type else let params = Ext_list.map params (fun x -> Map_ident.find_default new_map x x) in Lam.function_ ~attr ~arity:(List.length params) ~params - ~body:(convert_aux body) + ~body:(convert_aux body) ~fn_type | Llet (_, _, _, Lprim (Pgetglobal id, args, _), _body) when dynamic_import -> (* diff --git a/compiler/core/lam_eta_conversion.ml b/compiler/core/lam_eta_conversion.ml index 220fa76022..998531a44c 100644 --- a/compiler/core/lam_eta_conversion.ml +++ b/compiler/core/lam_eta_conversion.ml @@ -64,11 +64,13 @@ let transform_under_supply n ap_info fn args = Lam.function_ ~arity:n ~params:extra_args ~attr:Lambda.default_function_attribute ~body:(Lam.apply fn (Ext_list.append args extra_lambdas) ap_info) + ~fn_type:None | fn :: args, bindings -> let rest : Lam.t = Lam.function_ ~arity:n ~params:extra_args ~attr:Lambda.default_function_attribute ~body:(Lam.apply fn (Ext_list.append args extra_lambdas) ap_info) + ~fn_type:None in Ext_list.fold_left bindings rest (fun lam (id, x) -> Lam.let_ Strict id x lam) @@ -123,10 +125,11 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : if from = to_ || is_async_fn then fn else if to_ = 0 then match fn with - | Lfunction {params = [param]; body} -> + | Lfunction {params = [param]; body; fn_type} -> Lam.function_ ~arity:0 ~attr:Lambda.default_function_attribute ~params:[] ~body:(Lam.let_ Alias param Lam.unit body) + ~fn_type (* could be only introduced by {[ Pjs_fn_make 0 ]} <- {[ fun [@bs] () -> .. ]} @@ -151,6 +154,7 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : Lam.function_ ~attr:Lambda.default_function_attribute ~arity:0 ~params:[] ~body:(Lam.apply new_fn [Lam.unit] ap_info) + ~fn_type:None in match wrapper with @@ -158,7 +162,7 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : | Some partial_arg -> Lam.let_ Strict partial_arg fn cont) else if to_ > from then match fn with - | Lfunction {params; body} -> + | Lfunction {params; body; fn_type} -> (* {[fun x -> f]} -> {[ fun x y -> f y ]} *) @@ -173,6 +177,7 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : Lam.function_ ~attr:Lambda.default_function_attribute ~arity:to_ ~params:(Ext_list.append params extra_args) ~body:(mk_apply body (Ext_list.map extra_args Lam.var)) + ~fn_type | _ -> ( let arity = to_ in let extra_args = @@ -203,6 +208,7 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : {ap_info with ap_status = App_infer_full}) (Ext_list.map rest_args Lam.var) ap_info) + ~fn_type:None in match wrapper with | None -> cont @@ -216,7 +222,7 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : This is okay if the function is not held by other.. *) match fn with - | Lfunction {params; body} + | Lfunction {params; body; fn_type} (* TODO check arity = List.length params in debug mode *) -> let arity = to_ in let extra_outer_args, extra_inner_args = @@ -227,7 +233,8 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : ~body: (Lam.function_ ~arity:(from - to_) ~attr:Lambda.default_function_attribute ~params:extra_inner_args - ~body) + ~body ~fn_type:None) + ~fn_type | _ -> ( let extra_outer_args = Ext_list.init to_ (fun _ -> Ident.create Literals.param) @@ -261,7 +268,9 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : (Ext_list.map_append extra_outer_args (Ext_list.map extra_inner_args Lam.var) Lam.var) - {ap_info with ap_status = App_infer_full})) + {ap_info with ap_status = App_infer_full}) + ~fn_type:None) + ~fn_type:None in match wrapper with | None -> cont @@ -288,6 +297,7 @@ let unsafe_adjust_to_arity loc ~(to_ : int) ?(from : int option) (fn : Lam.t) : Lam.function_ ~attr:Lambda.default_function_attribute ~arity:0 ~params:[] ~body:(Lam.apply new_fn [Lam.unit] ap_info) + ~fn_type:None in match wrapper with diff --git a/compiler/core/lam_pass_alpha_conversion.ml b/compiler/core/lam_pass_alpha_conversion.ml index 1d80ae16ed..351630112d 100644 --- a/compiler/core/lam_pass_alpha_conversion.ml +++ b/compiler/core/lam_pass_alpha_conversion.ml @@ -75,19 +75,19 @@ let alpha_conversion (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = | Lprim {primitive = Pjs_fn_make_unit; args = [arg]; loc} -> let arg = match arg with - | Lfunction {arity = 1; params = [x]; attr; body} + | Lfunction {arity = 1; params = [x]; attr; body; fn_type} when Ident.name x = "param" (* "()" *) -> Lam.function_ ~params:[x] ~attr:{attr with one_unit_arg = true} - ~body ~arity:1 + ~body ~arity:1 ~fn_type | _ -> arg in simpl arg | Lprim {primitive; args; loc} -> Lam.prim ~primitive ~args:(Ext_list.map args simpl) loc - | Lfunction {arity; params; body; attr} -> + | Lfunction {arity; params; body; attr; fn_type} -> (* Lam_mk.lfunction kind params (simpl l) *) - Lam.function_ ~arity ~params ~body:(simpl body) ~attr + Lam.function_ ~arity ~params ~body:(simpl body) ~attr ~fn_type | Lswitch ( l, { diff --git a/compiler/core/lam_pass_deep_flatten.ml b/compiler/core/lam_pass_deep_flatten.ml index 11258e6a12..9437d10778 100644 --- a/compiler/core/lam_pass_deep_flatten.ml +++ b/compiler/core/lam_pass_deep_flatten.ml @@ -229,8 +229,8 @@ let deep_flatten (lam : Lam.t) : Lam.t = | Lprim {primitive; args; loc} -> let args = Ext_list.map args aux in Lam.prim ~primitive ~args loc - | Lfunction {arity; params; body; attr} -> - Lam.function_ ~arity ~params ~body:(aux body) ~attr + | Lfunction {arity; params; body; attr; fn_type} -> + Lam.function_ ~arity ~params ~body:(aux body) ~attr ~fn_type | Lswitch ( l, { diff --git a/compiler/core/lam_pass_exits.ml b/compiler/core/lam_pass_exits.ml index 2eb6295699..1e45e9dca8 100644 --- a/compiler/core/lam_pass_exits.ml +++ b/compiler/core/lam_pass_exits.ml @@ -203,8 +203,8 @@ let subst_helper (subst : subst_tbl) (query : int -> int) (lam : Lam.t) : Lam.t Lam.apply (simplif ap_func) (Ext_list.map ap_args simplif) ap_info ~ap_transformed_jsx - | Lfunction {arity; params; body; attr} -> - Lam.function_ ~arity ~params ~body:(simplif body) ~attr + | Lfunction {arity; params; body; attr; fn_type} -> + Lam.function_ ~arity ~params ~body:(simplif body) ~attr ~fn_type | Llet (kind, v, l1, l2) -> Lam.let_ kind v (simplif l1) (simplif l2) | Lletrec (bindings, body) -> Lam.letrec (Ext_list.map_snd bindings simplif) (simplif body) diff --git a/compiler/core/lam_pass_lets_dce.ml b/compiler/core/lam_pass_lets_dce.ml index bf32bbc56b..e352e496bd 100644 --- a/compiler/core/lam_pass_lets_dce.ml +++ b/compiler/core/lam_pass_lets_dce.ml @@ -147,8 +147,8 @@ let lets_helper (count_var : Ident.t -> Lam_pass_count.used_info) lam : Lam.t = | Lapply {ap_func = l1; ap_args = ll; ap_info; ap_transformed_jsx} -> Lam.apply (simplif l1) (Ext_list.map ll simplif) ap_info ~ap_transformed_jsx - | Lfunction {arity; params; body; attr} -> - Lam.function_ ~arity ~params ~body:(simplif body) ~attr + | Lfunction {arity; params; body; attr; fn_type} -> + Lam.function_ ~arity ~params ~body:(simplif body) ~attr ~fn_type | Lconst _ -> lam | Lletrec (bindings, body) -> Lam.letrec (Ext_list.map_snd bindings simplif) (simplif body) diff --git a/compiler/core/lam_pass_remove_alias.ml b/compiler/core/lam_pass_remove_alias.ml index 1dad7d3865..8f24c290b3 100644 --- a/compiler/core/lam_pass_remove_alias.ml +++ b/compiler/core/lam_pass_remove_alias.ml @@ -244,8 +244,8 @@ let simplify_alias (meta : Lam_stats.t) (lam : Lam.t) : Lam.t = (* simpl (Lam_beta_reduce.propogate_beta_reduce meta params body args) *) | Lapply {ap_func = l1; ap_args = ll; ap_info; ap_transformed_jsx} -> Lam.apply (simpl l1) (Ext_list.map ll simpl) ap_info ~ap_transformed_jsx - | Lfunction {arity; params; body; attr} -> - Lam.function_ ~arity ~params ~body:(simpl body) ~attr + | Lfunction {arity; params; body; attr; fn_type} -> + Lam.function_ ~arity ~params ~body:(simpl body) ~attr ~fn_type | Lswitch ( l, { diff --git a/compiler/core/lam_subst.ml b/compiler/core/lam_subst.ml index d5469619a3..83bd5e4fb3 100644 --- a/compiler/core/lam_subst.ml +++ b/compiler/core/lam_subst.ml @@ -35,8 +35,8 @@ let subst (s : Lam.t Map_ident.t) lam = | Lconst _ -> x | Lapply {ap_func; ap_args; ap_info} -> Lam.apply (subst_aux ap_func) (Ext_list.map ap_args subst_aux) ap_info - | Lfunction {arity; params; body; attr} -> - Lam.function_ ~arity ~params ~body:(subst_aux body) ~attr + | Lfunction {arity; params; body; attr; fn_type} -> + Lam.function_ ~arity ~params ~body:(subst_aux body) ~attr ~fn_type | Llet (str, id, arg, body) -> Lam.let_ str id (subst_aux arg) (subst_aux body) | Lletrec (decl, body) -> diff --git a/compiler/core/ts.ml b/compiler/core/ts.ml new file mode 100644 index 0000000000..62786039f2 --- /dev/null +++ b/compiler/core/ts.ml @@ -0,0 +1,5796 @@ +(** + TypeScript Codegen IR and its printer + + A typed intermediate representation for generating + TypeScript/JavaScript with type annotations and JSDoc. + + TODO(refactor): Unify the codegen IR with the existing JavaScript IR. + TODO(refactor): Split the core IR and printer as separate modules. +*) + +type type_ref = { + name: string; + (** Display name for the type (may include module path and @as renaming) *) + args: ts_type list; (** Type arguments *) +} +(** + Simplified type representation for TypeScript output. + This is derived from Types.type_expr but simplified for code generation. + *) + +and ts_type = + | Any + | Unknown + | Never + | Void (** Used for functions returning unit *) + | Null + | Undefined + | Boolean + | Number + | Bigint + | String + | Symbol + | Array of ts_type + | Tuple of ts_type list + | Object of object_type + | Function of fn_type + | Union of ts_type list + | Intersection of ts_type list + | TypeRef of type_ref (** Reference to a named type *) + | TypeVar of string (** Type variable 'a -> A *) + | Literal of literal_type + | Readonly of ts_type + | Promise of ts_type + | RuntimeType of runtime_type + (** Reference to a type from @rescript/runtime *) + +and runtime_type = { + rt_name: string; (** Type name, e.g. "result", "list" *) + rt_args: ts_type list; (** Type arguments *) +} +(** Types defined in @rescript/runtime/types.d.ts + TODO: make it as variant *) + +and literal_type = + | LitString of string + | LitNumber of float + | LitBigint of string + | LitBoolean of bool + +and object_type = { + properties: property_sig list; + index_sig: index_sig option; + call_sig: fn_type option; +} + +and property_sig = { + prop_name: string; + prop_type: ts_type; + prop_optional: bool; + prop_readonly: bool; +} + +and index_sig = { + index_key: ts_type; (** Usually String or Number *) + index_value: ts_type; +} + +and fn_type = { + fn_params: param_type list; + fn_rest: param_type option; + fn_return: ts_type; + fn_type_params: type_param list; + fn_async: bool; +} + +and param_type = { + param_name: string option; + param_type: ts_type; + param_optional: bool; +} + +and type_param = { + tp_name: string; + tp_constraint: ts_type option; + tp_default: ts_type option; +} + +(** Helper to create Object ts_type - needed because expression_desc.Object + shadows ts_type.Object after the expression type definition *) +let make_object_type ~properties ~index_sig ~call_sig : ts_type = + Object {properties; index_sig; call_sig} + +(** {1 Type Declarations} *) + +(** Payload representation for variant constructors *) +type variant_payload = + | NoPayload (** Nullary constructor - just the tag string *) + | TuplePayload of ts_type list (** Tuple payload: _0, _1, etc. *) + | InlineRecord of property_sig list + (** Inline record: named fields flattened *) + +(** The kind of tag for a variant constructor *) +type tag_kind = + | TagString of string (** String literal tag, e.g. "Ok" *) + | TagNull (** @as(null) - the literal null value *) + | TagUndefined (** @as(undefined) - the literal undefined value *) + | TagInt of int (** @as(123) - numeric literal *) + | TagBool of bool (** @as(true) or @as(false) *) + +type variant_case = { + vc_name: string; + vc_tag: tag_kind; (** The TAG value and its kind *) + vc_payload: variant_payload; (** Payload representation *) +} +(** Variant constructor for tagged unions *) + +type variant_config = { + vc_unboxed: bool; (** @unboxed - payload is the value directly *) + vc_tag_name: string; (** Tag field name, default Js_dump_lit.tag ("TAG") *) +} +(** Configuration for how a variant type is represented at runtime *) + +type gadt_case = { + gc_name: string; (** Constructor name *) + gc_tag: tag_kind; (** The TAG value and its kind *) + gc_payload: variant_payload; (** Payload representation *) + gc_result_type: ts_type; + (** The specific result type for this constructor (e.g., t for Int constructor) *) + gc_result_key: string option; + (** The key for grouping (e.g., "int", "bool") derived from result type arg. + None for existential types like expr<'a> *) +} +(** GADT constructor - each constructor has its own result type constraint *) + +type gadt_sub_union = { + gsu_key: string; (** The key (e.g., "int", "bool") *) + gsu_constructors: string list; (** Constructor names in this group *) +} +(** A phantom-constrained sub-union grouping constructors by result type *) + +(** How to import an external type *) +type ext_import_kind = + | ExtNamed of string (** Named import: import type { Name } from "module" *) + | ExtDefault (** Default import: import type LocalName from "module" *) + | ExtNamespace + (** Namespace import: import type * as LocalName from "module" *) + +type external_type_constraint = { + etc_name: string; (** The external TypeScript type name or local name *) + etc_module: string option; (** Optional module to import from *) + etc_use_external: bool; + (** If true, use the external type instead of ReScript shape *) + etc_import_kind: ext_import_kind; (** How to import this type *) +} +(** External type constraint for validating ReScript shape against external type *) + +type type_decl = + | TypeAlias of { + name: string; + type_params: type_param list; + body: ts_type; + external_type: external_type_constraint option; + (** Optional external type to validate against *) + is_opaque: bool; + (** If true, type has phantom params and should be intersected with opaque brand *) + } + | Interface of { + name: string; + type_params: type_param list; + extends: type_ref list; + body: object_type; + } + | VariantType of { + name: string; + type_params: type_param list; + cases: variant_case list; + config: variant_config; + } + | GadtType of { + name: string; + type_params: type_param list; + cases: gadt_case list; + sub_unions: gadt_sub_union list; + (** Phantom-constrained sub-unions grouping constructors by result type. + E.g., for expr: [{ key="int"; constructors=["IntLit";"Add"] }] *) + constraints: ts_type option list; + (** Constraints for each type parameter position. + Used for filtering GADT-related type variables from function signatures. + E.g., for number<_> with Int: number | Float: number, + constraints = [Some (number | number)] i.e., the union of all result types. *) + config: variant_config; + } + (** GADT type - generates separate type for each constructor. + For: type t<_> = Int(int): t | Float(float): t + Generates: type t$Int = ...; type t$Float = ...; type t = t$Int | t$Float. + Constructor types are NOT exported. *) + | OpaqueType of { + name: string; + type_params: type_param list; + underlying: ts_type option; + (** If Some, this is a branded opaque type from @opaque with underlying type. + If None, this is a pure abstract type. *) + } (** Opaque abstract type - represented with unique symbol *) + | ExternalType of { + name: string; + type_params: type_param list; + external_name: string; + (** The external TypeScript type name (or local name) *) + external_module: string option; (** Optional module to import from *) + external_import_kind: ext_import_kind; (** How to import this type *) + } (** Abstract external TypeScript type binding via @external *) + | ModuleDecl of module_decl (** Module with types and values *) + +and module_decl = { + mod_name: string; + mod_types: type_decl list; (** Types defined in the module (for namespace) *) + mod_values: module_value list; (** Values defined in the module *) + mod_submodules: module_decl list; (** Nested submodules *) +} +(** Module declaration - represents a ReScript module as TypeScript namespace + type *) + +and module_value = {mv_name: string; mv_type: ts_type} +(** A value in a module *) + +(** {1 Runtime Type Collection} *) + +(** The namespace alias for runtime types import *) +let runtime_types_namespace = "rescript" + +module StringSet = Set.Make (String) +module IntMap = Map.Make (Int) +module StringMap = Map.Make (String) + +(** {1 Unified Codegen State} + + All mutable state for TypeScript code generation is centralized in the State module. + This makes it easy to reset all state at entry points and reason about what state exists. + + The State module provides submodules for different aspects of state management: + - RuntimeTypes: tracking runtime type imports from @rescript/runtime + - TypeModuleDeps: tracking module dependencies from type references + - OpaqueTypes: tracking opaque/branded types for assertions + - ExternalTypeImports: tracking @external type imports + - LocalTypeQualifier: mapping type identifiers to qualified paths + - ExportedTypes: tracking exported value types + - ExportedModules: tracking exported module paths + - Context: module name, path, and environment for code generation *) + +(** Import kind for external type imports *) +type external_import_kind = + | ImportNamed of string (** import type \{ TypeName \} from "module" *) + | ImportDefault of string (** import type LocalName from "module" *) + | ImportNamespace of string (** import type * as LocalName from "module" *) + +module State = struct + (** {2 Internal State Record} *) + + type t = { + (* Import tracking *) + mutable runtime_types: StringSet.t; + mutable type_module_deps: StringSet.t; + mutable external_type_imports: external_import_kind list StringMap.t; + (* Opaque type tracking *) + mutable opaque_decls: (string * int * ts_type option) list; + (* GADT type parameter constraints: type name -> list of (param position, constraint) *) + mutable gadt_constraints: ts_type option list StringMap.t; + (* GADT sub-unions: type name -> list of (key, constructor names) *) + mutable gadt_sub_unions: (string * string list) list StringMap.t; + (* Name resolution *) + mutable local_type_qualifiers_by_stamp: string IntMap.t; + mutable local_type_qualifiers_by_name: string list StringMap.t; + mutable exported_types: Types.type_expr StringMap.t; + mutable exported_modules: string StringMap.t; + (* Module aliases: maps alias name to target path *) + mutable module_aliases: Path.t StringMap.t; + (* Context *) + mutable module_name: string; + mutable module_path: string list; + mutable env: Env.t option; + } + + let state : t = + { + runtime_types = StringSet.empty; + type_module_deps = StringSet.empty; + external_type_imports = StringMap.empty; + opaque_decls = []; + gadt_constraints = StringMap.empty; + gadt_sub_unions = StringMap.empty; + local_type_qualifiers_by_stamp = IntMap.empty; + local_type_qualifiers_by_name = StringMap.empty; + exported_types = StringMap.empty; + exported_modules = StringMap.empty; + module_aliases = StringMap.empty; + module_name = ""; + module_path = []; + env = None; + } + + (** Reset all codegen state. Call this at the start of each file's code generation. *) + let reset () = + state.runtime_types <- StringSet.empty; + state.type_module_deps <- StringSet.empty; + state.external_type_imports <- StringMap.empty; + state.opaque_decls <- []; + state.gadt_constraints <- StringMap.empty; + state.gadt_sub_unions <- StringMap.empty; + state.local_type_qualifiers_by_stamp <- IntMap.empty; + state.local_type_qualifiers_by_name <- StringMap.empty; + state.exported_types <- StringMap.empty; + state.exported_modules <- StringMap.empty; + state.module_aliases <- StringMap.empty; + state.module_name <- ""; + state.module_path <- []; + state.env <- None + + (** {2 Runtime Types} + + Tracks runtime types that need to be imported from @rescript/runtime/types.d.ts + (e.g., "option", "result", "list", "opaque") *) + module RuntimeTypes = struct + let reset () = state.runtime_types <- StringSet.empty + let add name = state.runtime_types <- StringSet.add name state.runtime_types + let use_opaque () = add "opaque" + let use_external () = add "external" + let get_used () = StringSet.elements state.runtime_types + let has_any () = not (StringSet.is_empty state.runtime_types) + end + + (** {2 Type Module Dependencies} + + Tracks module dependencies from qualified type references. + When we see a type like Stdlib_Array.arrayLike, we need to track + that Stdlib_Array needs to be imported. *) + module TypeModuleDeps = struct + let reset () = state.type_module_deps <- StringSet.empty + + let add name = + state.type_module_deps <- StringSet.add name state.type_module_deps + + let get_used () = StringSet.elements state.type_module_deps + let has_any () = not (StringSet.is_empty state.type_module_deps) + end + + (** {2 Opaque Types} + + Tracks opaque types for rescript.opaque brand generation. + Also tracks branded opaque types (those with @opaque attribute) for return assertions. + Each entry is (name, type_param_count, underlying_type option). + underlying_type is Some for branded opaque types, None for pure abstract types. *) + module OpaqueTypes = struct + let reset () = state.opaque_decls <- [] + + let add name param_count = + state.opaque_decls <- (name, param_count, None) :: state.opaque_decls + + let add_branded name param_count underlying = + state.opaque_decls <- + (name, param_count, Some underlying) :: state.opaque_decls + + let get_all () = + List.rev_map (fun (name, count, _) -> (name, count)) state.opaque_decls + + let has_any () = state.opaque_decls <> [] + + (** Check if a type name is registered as opaque. + Checks both the exact name and mangled names (e.g., "t" matches "Email.t" -> "Email$t") *) + let is_opaque name = + List.exists + (fun (opaque_name, _, _) -> + opaque_name = name + || String.ends_with ~suffix:("." ^ name) opaque_name + || String.ends_with ~suffix:("$" ^ name) opaque_name) + state.opaque_decls + + (** Get underlying type for a branded opaque type, if it exists *) + let get_underlying name = + List.find_map + (fun (opaque_name, _, underlying) -> + if + opaque_name = name + || String.ends_with ~suffix:("." ^ name) opaque_name + || String.ends_with ~suffix:("$" ^ name) opaque_name + then underlying + else None) + state.opaque_decls + + (** Check if a type name is a branded opaque type (has underlying type) *) + let is_branded name = + List.exists + (fun (opaque_name, _, underlying) -> + underlying <> None + && (opaque_name = name + || String.ends_with ~suffix:("." ^ name) opaque_name + || String.ends_with ~suffix:("$" ^ name) opaque_name)) + state.opaque_decls + + (** Get the full brand name for a local type name. + E.g., "t" might return "Modules.Email.t" if that's registered. *) + let get_full_name name = + List.find_map + (fun (opaque_name, _, _) -> + if + opaque_name = name + || String.ends_with ~suffix:("." ^ name) opaque_name + then Some opaque_name + else None) + state.opaque_decls + end + + (** {2 GADT Constraints} + + Tracks GADT type parameter constraints for function signature generation. + Maps type name to list of constraint types for each type parameter position. *) + module GadtConstraints = struct + let reset () = state.gadt_constraints <- StringMap.empty + + (** Register constraints for a GADT type. + @param name The type name (e.g., "t" or "expr") + @param constraints List of constraint types for each parameter position *) + let add name constraints = + state.gadt_constraints <- + StringMap.add name constraints state.gadt_constraints + + (** Get constraints for a type by name. + Returns list of (position, constraint) pairs. *) + let get name = StringMap.find_opt name state.gadt_constraints + + (** Get constraint for a specific type parameter position *) + let get_constraint_at name pos = + match StringMap.find_opt name state.gadt_constraints with + | Some constraints -> List.nth_opt constraints pos |> Option.join + | None -> None + end + + (** {2 GADT Sub-Unions} + + Tracks GADT sub-unions for transforming type references. + Maps type name to list of (key, constructor names) pairs. + E.g., "expr" -> [("int", ["IntLit"; "Add"]); ("bool", ["BoolLit"; "Eq"])] *) + module GadtSubUnions = struct + let reset () = state.gadt_sub_unions <- StringMap.empty + + (** Register sub-unions for a GADT type. + @param name The type name (e.g., "expr") + @param sub_unions List of (key, constructor names) pairs *) + let add name sub_unions = + state.gadt_sub_unions <- + StringMap.add name sub_unions state.gadt_sub_unions + + (** Check if a type is a GADT *) + let is_gadt name = StringMap.mem name state.gadt_sub_unions + + (** Get sub-unions for a GADT type *) + let get name = StringMap.find_opt name state.gadt_sub_unions + + (** Get the sub-union key for a type if one exists. + @param gadt_name The GADT type name (e.g., "expr") + @param type_arg_key The type argument key (e.g., "int", "bool") + @return Some key if a sub-union exists, None otherwise *) + let get_sub_union_key gadt_name type_arg_key = + match StringMap.find_opt gadt_name state.gadt_sub_unions with + | Some sub_unions -> + if List.exists (fun (k, _) -> k = type_arg_key) sub_unions then + Some type_arg_key + else None + | None -> None + end + + (** {2 External Type Imports} + + Tracks external type imports from @external(("package", "Type")) attribute. + Maps module path to list of import kinds. *) + module ExternalTypeImports = struct + let reset () = state.external_type_imports <- StringMap.empty + + let add ~module_path ~import_kind = + let current = + match StringMap.find_opt module_path state.external_type_imports with + | Some kinds -> kinds + | None -> [] + in + let already_exists = + List.exists + (fun k -> + match (k, import_kind) with + | ImportNamed n1, ImportNamed n2 -> n1 = n2 + | ImportDefault n1, ImportDefault n2 -> n1 = n2 + | ImportNamespace n1, ImportNamespace n2 -> n1 = n2 + | _ -> false) + current + in + if not already_exists then + state.external_type_imports <- + StringMap.add module_path (import_kind :: current) + state.external_type_imports + + let get_all () = + StringMap.fold + (fun module_path kinds acc -> (module_path, List.rev kinds) :: acc) + state.external_type_imports [] + |> List.rev + + let has_any () = not (StringMap.is_empty state.external_type_imports) + end + + (** {2 Local Type Qualifier} + + Mapping from type identifiers (by stamp) to their qualified paths. + Populated from type_exports to enable qualifying local type references + in implementation code. Maps ident stamp to qualified path like "Outer.Nested.t". *) + module LocalTypeQualifier = struct + let reset () = + state.local_type_qualifiers_by_stamp <- IntMap.empty; + state.local_type_qualifiers_by_name <- StringMap.empty + + (** Add a type with its qualified path. + @param stamp The ident stamp for the type + @param name Simple type name (e.g., "t") + @param qualified Full qualified path (e.g., "Outer.Nested.t") *) + let add ~stamp ~name ~qualified = + state.local_type_qualifiers_by_stamp <- + IntMap.add stamp qualified state.local_type_qualifiers_by_stamp; + let current = + match StringMap.find_opt name state.local_type_qualifiers_by_name with + | Some paths -> paths + | None -> [] + in + if not (List.mem qualified current) then + state.local_type_qualifiers_by_name <- + StringMap.add name (qualified :: current) + state.local_type_qualifiers_by_name + + (** Get the qualified path for a type identifier by stamp *) + let get_qualified_by_stamp stamp = + IntMap.find_opt stamp state.local_type_qualifiers_by_stamp + + (** Get the qualified path for a type by name (only if unambiguous) *) + let get_qualified_by_name name = + match StringMap.find_opt name state.local_type_qualifiers_by_name with + | Some [qualified] -> Some qualified + | _ -> None + + let has_any () = not (IntMap.is_empty state.local_type_qualifiers_by_stamp) + end + + (** {2 Exported Types} + + Maps exported value names to their types for annotation lookup. *) + module ExportedTypes = struct + let reset () = state.exported_types <- StringMap.empty + + let add name ty = + state.exported_types <- StringMap.add name ty state.exported_types + + let find name = StringMap.find_opt name state.exported_types + end + + (** {2 Exported Modules} + + Maps module names to qualified type paths for module object annotations + (e.g., "Nested" -> "Outer.Nested"). *) + module ExportedModules = struct + let reset () = state.exported_modules <- StringMap.empty + + let add name qualified_path = + state.exported_modules <- + StringMap.add name qualified_path state.exported_modules + + let get_type_path name = StringMap.find_opt name state.exported_modules + end + + (** {2 Module Aliases} + + Tracks module aliases like "module Inner = Outer". + Used to resolve type paths like Inner.t to Outer.t *) + module ModuleAliases = struct + let reset () = state.module_aliases <- StringMap.empty + + let add alias_name target_path = + state.module_aliases <- + StringMap.add alias_name target_path state.module_aliases + + let find alias_name = StringMap.find_opt alias_name state.module_aliases + end + + (** {2 Context} + + Current context for code generation including module name, path, and environment. *) + module Context = struct + let set_module_name name = state.module_name <- name + let get_module_name () = state.module_name + let set_module_path path = state.module_path <- path + let get_module_path () = state.module_path + + let push_module_path name = state.module_path <- state.module_path @ [name] + + let pop_module_path () = + match List.rev state.module_path with + | _ :: rest -> state.module_path <- List.rev rest + | [] -> () + + let set_env env = state.env <- Some env + let clear_env () = state.env <- None + let get_env () = state.env + end +end + +(** {1 State Module Aliases} + + For backward compatibility and convenience, we expose the State submodules + at the top level. *) + +let reset_state = State.reset + +module RuntimeTypes = State.RuntimeTypes +module TypeModuleDeps = State.TypeModuleDeps +module OpaqueTypes = State.OpaqueTypes +module GadtConstraints = State.GadtConstraints +module GadtSubUnions = State.GadtSubUnions +module ExternalTypeImports = State.ExternalTypeImports +module LocalTypeQualifier = State.LocalTypeQualifier +module ExportedTypes = State.ExportedTypes +module ExportedModules = State.ExportedModules +module ModuleAliases = State.ModuleAliases + +(** Context accessors exposed at top level for convenience *) +let set_module_name = State.Context.set_module_name + +let get_module_name = State.Context.get_module_name +let set_module_path = State.Context.set_module_path +let get_module_path = State.Context.get_module_path +let push_module_path = State.Context.push_module_path +let pop_module_path = State.Context.pop_module_path +let set_env = State.Context.set_env +let clear_env = State.Context.clear_env +let get_env = State.Context.get_env + +(** Collect all type variable names used in a ts_type *) +let rec collect_type_vars (ty : ts_type) : StringSet.t = + match ty with + | TypeVar name -> StringSet.singleton name + | Array ty | Readonly ty | Promise ty -> collect_type_vars ty + | Tuple types | Union types | Intersection types -> + List.fold_left + (fun acc t -> StringSet.union acc (collect_type_vars t)) + StringSet.empty types + | Object {properties; index_sig; call_sig} -> + let prop_vars = + List.fold_left + (fun acc p -> StringSet.union acc (collect_type_vars p.prop_type)) + StringSet.empty properties + in + let index_vars = + match index_sig with + | Some {index_key; index_value} -> + StringSet.union + (collect_type_vars index_key) + (collect_type_vars index_value) + | None -> StringSet.empty + in + let call_vars = + match call_sig with + | Some fn -> collect_type_vars_fn fn + | None -> StringSet.empty + in + StringSet.union prop_vars (StringSet.union index_vars call_vars) + | Function fn -> collect_type_vars_fn fn + | TypeRef {args; _} -> + List.fold_left + (fun acc t -> StringSet.union acc (collect_type_vars t)) + StringSet.empty args + | RuntimeType {rt_args; _} -> + List.fold_left + (fun acc t -> StringSet.union acc (collect_type_vars t)) + StringSet.empty rt_args + | Literal _ | Any | Unknown | Never | Void | Null | Undefined | Boolean + | Number | Bigint | String | Symbol -> + StringSet.empty + +and collect_type_vars_fn (fn : fn_type) : StringSet.t = + let param_vars = + List.fold_left + (fun acc p -> StringSet.union acc (collect_type_vars p.param_type)) + StringSet.empty fn.fn_params + in + let rest_vars = + match fn.fn_rest with + | Some p -> collect_type_vars p.param_type + | None -> StringSet.empty + in + let return_vars = collect_type_vars fn.fn_return in + StringSet.union param_vars (StringSet.union rest_vars return_vars) + +(** Check if a type alias has phantom type parameters (params not used in body) *) +let has_phantom_params (type_params : type_param list) (body : ts_type) : bool = + if type_params = [] then false + else + let declared_params = + List.fold_left + (fun acc (tp : type_param) -> StringSet.add tp.tp_name acc) + StringSet.empty type_params + in + let used_params = collect_type_vars body in + (* If any declared param is not used in the body, we have phantom params *) + not (StringSet.subset declared_params used_params) + +(** Extract module name from a qualified type path. + e.g., "Stdlib_Array.arrayLike" -> Some "Stdlib_Array" + "arrayLike" -> None *) +let extract_module_from_type_path (path : string) : string option = + match String.index_opt path '.' with + | Some idx -> Some (String.sub path 0 idx) + | None -> None + +(** Forward reference for printing a ts_type (set later to break cyclic dependency) *) +let pp_ts_type_ref : (Ext_pp.t -> ts_type -> unit) ref = ref (fun _ _ -> ()) + +(** Print opaque type using $res.opaque<"Brand", Params, Underlying> format. + @param brand_name The full brand name (e.g., "Email.t" or "Outer.Nested.t") + @param type_params Type parameters for phantom type support + @param underlying Optional underlying type; if None, only brand is used *) +let pp_opaque_type (f : Ext_pp.t) ~(brand_name : string) + ~(type_params : type_param list) ~(underlying : ts_type option) : unit = + RuntimeTypes.add "opaque"; + Ext_pp.string f runtime_types_namespace; + Ext_pp.string f ".opaque<\""; + Ext_pp.string f brand_name; + Ext_pp.string f "\", ["; + (* Print type params as tuple for phantom type support *) + (if type_params <> [] then + let param_names = + List.map (fun (tp : type_param) -> tp.tp_name) type_params + in + Ext_pp.string f (String.concat ", " param_names)); + Ext_pp.string f "]"; + (match underlying with + | Some ty -> + Ext_pp.string f ", "; + !pp_ts_type_ref f ty + | None -> ()); + Ext_pp.string f ">" + +(** Collect runtime types and module dependencies from a ts_type *) +let rec collect_type_deps (ty : ts_type) : unit = + match ty with + | RuntimeType {rt_name; rt_args} -> + RuntimeTypes.add rt_name; + List.iter collect_type_deps rt_args + | Array elem -> collect_type_deps elem + | Tuple types -> List.iter collect_type_deps types + | Object {properties; index_sig; call_sig} -> ( + List.iter (fun p -> collect_type_deps p.prop_type) properties; + (match index_sig with + | Some {index_key; index_value} -> + collect_type_deps index_key; + collect_type_deps index_value + | None -> ()); + match call_sig with + | Some fn -> collect_type_deps_fn fn + | None -> ()) + | Function fn -> collect_type_deps_fn fn + | Union types | Intersection types -> List.iter collect_type_deps types + | TypeRef {name; args} -> + (* Track module dependency from qualified type names *) + (match extract_module_from_type_path name with + | Some module_name -> TypeModuleDeps.add module_name + | None -> ()); + List.iter collect_type_deps args + | Readonly ty | Promise ty -> collect_type_deps ty + | Literal _ | TypeVar _ | Any | Unknown | Never | Void | Null | Undefined + | Boolean | Number | Bigint | String | Symbol -> + () + +and collect_type_deps_fn (fn : fn_type) : unit = + List.iter (fun p -> collect_type_deps p.param_type) fn.fn_params; + (match fn.fn_rest with + | Some p -> collect_type_deps p.param_type + | None -> ()); + collect_type_deps fn.fn_return + +(** Collect runtime types from a ts_type (legacy, calls collect_type_deps) *) +let collect_runtime_types = collect_type_deps + +let collect_runtime_types_fn = collect_type_deps_fn + +(** Collect type dependencies from a type declaration *) +let rec collect_type_deps_decl (decl : type_decl) : unit = + match decl with + | TypeAlias {body; external_type; is_opaque; _} -> ( + collect_type_deps body; + if is_opaque then RuntimeTypes.use_opaque (); + match external_type with + | Some {etc_name; etc_module; etc_import_kind; _} -> ( + RuntimeTypes.use_external (); + match etc_module with + | Some module_path -> + let import_kind = + match etc_import_kind with + | ExtNamed name -> ImportNamed name + | ExtDefault -> ImportDefault etc_name + | ExtNamespace -> ImportNamespace etc_name + in + ExternalTypeImports.add ~module_path ~import_kind + | None -> ()) + | None -> ()) + | Interface {body; _} -> ( + List.iter (fun p -> collect_type_deps p.prop_type) body.properties; + (match body.index_sig with + | Some {index_key; index_value} -> + collect_type_deps index_key; + collect_type_deps index_value + | None -> ()); + match body.call_sig with + | Some fn -> collect_type_deps_fn fn + | None -> ()) + | VariantType {cases; _} -> + List.iter + (fun case -> + match case.vc_payload with + | NoPayload -> () + | TuplePayload types -> List.iter collect_type_deps types + | InlineRecord props -> + List.iter (fun p -> collect_type_deps p.prop_type) props) + cases + | GadtType {name; constraints; cases; _} -> + (* Register GADT constraints for function signature generation *) + GadtConstraints.add name constraints; + List.iter + (fun (case : gadt_case) -> + (match case.gc_payload with + | NoPayload -> () + | TuplePayload types -> List.iter collect_type_deps types + | InlineRecord props -> + List.iter (fun p -> collect_type_deps p.prop_type) props); + collect_type_deps case.gc_result_type) + cases + | OpaqueType _ -> RuntimeTypes.use_opaque () + | ExternalType {external_name; external_module; external_import_kind; _} -> ( + (* Track external type imports for types from external packages *) + match external_module with + | Some module_path -> + let import_kind = + match external_import_kind with + | ExtNamed name -> ImportNamed name + | ExtDefault -> ImportDefault external_name + | ExtNamespace -> ImportNamespace external_name + in + ExternalTypeImports.add ~module_path ~import_kind + | None -> + (* Global TypeScript types don't need imports *) + ()) + | ModuleDecl {mod_types; mod_values; mod_submodules; _} -> + (* Collect dependencies from module contents *) + List.iter collect_type_deps_decl mod_types; + List.iter (fun v -> collect_type_deps v.mv_type) mod_values; + List.iter + (fun sub -> collect_type_deps_decl (ModuleDecl sub)) + mod_submodules + +(** Legacy alias for collect_type_deps_decl *) +let collect_runtime_types_decl = collect_type_deps_decl + +(** {1 Reused types from Js_op} *) + +type mutable_flag = Js_op.mutable_flag +type binop = Js_op.binop +type int_op = Js_op.int_op +type kind = Js_op.kind +type property = Js_op.property +type number = Js_op.number +type ident_info = Js_op.ident_info +type exports = Js_op.exports +type tag_info = Js_op.tag_info +type property_name = Js_op.property_name + +and ident = Ident.t + +(** {1 Module References} *) + +and module_id = {id: ident; kind: Js_op.kind; dynamic_import: bool} + +and required_modules = module_id list + +and vident = Id of ident | Qualified of module_id * string option + +(** {1 Core IR Types} *) + +and exception_ident = ident + +and for_ident = ident +and for_direction = Js_op.direction_flag +and property_map = (property_name * expression) list +and length_object = Js_op.length_object +and delim = External_arg_spec.delim = DNone | DStarJ | DNoQuotes | DBackQuotes + +(** {1 Expression Descriptors} *) + +and expression_desc = + | Length of expression * length_object + | Is_null_or_undefined of expression + | String_append of expression * expression + | Bool of bool + | Typeof of expression + | In of expression * expression + | Js_not of expression + | Js_bnot of expression + | Seq of expression * expression + | Cond of expression * expression * expression + | Bin of binop * expression * expression + | FlatCall of expression * expression + | Call of expression * expression list * Js_call_info.t + | String_index of expression * expression + | Array_index of expression * expression + | Tagged_template of expression * expression list * expression list + | Static_index of expression * string * int32 option + | New of expression * expression list option + | Var of vident + | Fun of { + is_method: bool; + params: typed_ident list; + (** Parameters with optional type annotations *) + body: block; + env: Js_fun_env.t; + return_unit: bool; + async: bool; + directive: string option; + fn_type: Types.type_expr option; (** Original ML type for conversion *) + return_type: ts_type option; (** Explicit return type annotation *) + type_params: type_param list; (** Generic type parameters *) + } + | Str of {delim: delim; txt: string} + | Raw_js_code of Js_raw_info.t + | Array of expression list * mutable_flag + | Optional_block of expression * bool + | Caml_block of expression list * mutable_flag * expression * tag_info + | Caml_block_tag of expression * string + | Number of number + | Object of expression option * property_map + | Undefined of {is_unit: bool} + | Null + | Await of expression + | Spread of expression + | As of expression * ts_type (** Type assertion: expr as Type *) + +and typed_ident = {ident: ident; ident_type: ts_type option} +(** Identifier with optional type annotation *) + +(** {1 Statements} *) + +and for_ident_expression = expression + +and finish_ident_expression = expression + +and case_clause = { + switch_body: block; + should_break: bool; + comment: string option; +} + +and string_clause = Ast_untagged_variants.tag_type * case_clause +and int_clause = int * case_clause + +and statement_desc = + | Block of block + | Variable of variable_declaration + | Exp of expression + | If of expression * block * block + | While of expression * block + | ForRange of + for_ident_expression option + * finish_ident_expression + * for_ident + * for_direction + * block + | Continue + | Break + | Return of expression + | Int_switch of expression * int_clause list * block option + | String_switch of expression * string_clause list * block option + | Throw of expression + | Try of block * (exception_ident * block) option * block option + | Debugger + | TypeDecl of type_decl (** Type declaration statement *) + +and expression = {expression_desc: expression_desc; comment: string option} + +and statement = {statement_desc: statement_desc; comment: string option} + +and variable_declaration = { + ident: ident; + value: expression option; + property: property; + ident_info: ident_info; + var_type: ts_type option; (** Optional type annotation *) +} + +and block = statement list + +(** {1 Program Structure} *) + +and program = { + block: block; + exports: exports; + export_set: Set_ident.t; + type_exports: type_decl list; (** Exported type declarations *) +} + +and deps_program = { + program: program; + modules: required_modules; + side_effect: string option; + type_imports: type_import list; (** Type-only imports *) +} + +and type_import = { + from_module: module_id; + type_name: string; + type_alias: string option; (** Local alias if renamed *) +} +(** Type import for cross-module type references *) + +(** {1 Conversion from Types.type_expr} *) + +(** Extract @as string from attributes, returning the renamed name or None. + Also marks the attribute as used to prevent "unused attribute" warnings. *) +let get_as_string (attrs : Parsetree.attributes) : string option = + let result = ref None in + List.iter + (fun ((attr_name, payload) as attr : Parsetree.attribute) -> + match attr_name.txt with + | "as" -> ( + match payload with + | PStr + [ + { + pstr_desc = + Pstr_eval + ({pexp_desc = Pexp_constant (Pconst_string (s, _)); _}, _); + _; + }; + ] -> + Used_attributes.mark_used_attribute attr; + result := Some s + | _ -> ()) + | _ -> ()) + attrs; + !result + +(** Check if type declaration has @opaque attribute. + Marks the attribute as used to prevent "unused attribute" warnings. *) +let has_opaque_attr (attrs : Parsetree.attributes) : bool = + List.exists + (fun (({txt}, _) as attr : Parsetree.attribute) -> + if txt = "opaque" then ( + Used_attributes.mark_used_attribute attr; + true) + else false) + attrs + +type external_type_info = { + ext_type_name: string; (** The TypeScript type name (or "default"/"*") *) + ext_module_path: string option; (** Optional module to import from *) + ext_use_external: bool; + (** If true, use the external type instead of ReScript shape *) + ext_import_kind: ext_import_kind; (** How to import this type *) +} +(** External type info from @external attribute *) + +(** Helper to determine import kind from type name *) +let import_kind_of_type_name (type_name : string) : ext_import_kind = + match type_name with + | "default" -> ExtDefault + | "*" -> ExtNamespace + | name -> ExtNamed name + +(** Extract @external attribute from type declaration. + Formats: + - @external("TypeName") -> global TypeScript type + - @external(("package", "TypeName")) -> named import from package + - @external(("package", "default")) -> default import from package + - @external(("package", "*")) -> namespace import from package + - @external(("package", "TypeName", true)) -> use external type *) +let get_external_type (attrs : Parsetree.attributes) : external_type_info option + = + let result = ref None in + List.iter + (fun ((attr_name, payload) as attr : Parsetree.attribute) -> + match attr_name.txt with + | "external" -> ( + match payload with + (* @external("TypeName") *) + | PStr + [ + { + pstr_desc = + Pstr_eval + ({pexp_desc = Pexp_constant (Pconst_string (s, _)); _}, _); + _; + }; + ] -> + Used_attributes.mark_used_attribute attr; + result := + Some + { + ext_type_name = s; + ext_module_path = None; + ext_use_external = false; + ext_import_kind = ExtNamed s; + } + (* @external(("package", "TypeName")) *) + | PStr + [ + { + pstr_desc = + Pstr_eval + ( { + pexp_desc = + Pexp_tuple + [ + { + pexp_desc = + Pexp_constant (Pconst_string (pkg, _)); + _; + }; + { + pexp_desc = + Pexp_constant (Pconst_string (type_name, _)); + _; + }; + ]; + _; + }, + _ ); + _; + }; + ] -> + Used_attributes.mark_used_attribute attr; + result := + Some + { + ext_type_name = type_name; + ext_module_path = Some pkg; + ext_use_external = false; + ext_import_kind = import_kind_of_type_name type_name; + } + (* @external(("package", "TypeName", true)) *) + | PStr + [ + { + pstr_desc = + Pstr_eval + ( { + pexp_desc = + Pexp_tuple + [ + { + pexp_desc = + Pexp_constant (Pconst_string (pkg, _)); + _; + }; + { + pexp_desc = + Pexp_constant (Pconst_string (type_name, _)); + _; + }; + { + pexp_desc = + Pexp_construct ({txt = Lident "true"; _}, None); + _; + }; + ]; + _; + }, + _ ); + _; + }; + ] -> + Used_attributes.mark_used_attribute attr; + result := + Some + { + ext_type_name = type_name; + ext_module_path = Some pkg; + ext_use_external = true; + ext_import_kind = import_kind_of_type_name type_name; + } + | _ -> ()) + | _ -> ()) + attrs; + !result + +(** Get the @as renamed name for a type from its declaration, or None if not renamed *) +let get_type_as_name (env : Env.t) (path : Path.t) : string option = + try + let decl = Env.find_type path env in + get_as_string decl.type_attributes + with Not_found -> None + +(** Compute the display name for a type path, applying @as renaming if available. + For local type references (Pident), tries to qualify using: + 1. current_module_path if set (for code generated within a module context) + 2. LocalTypeQualifier mapping by stamp (for hoisted implementation code) + 3. LocalTypeQualifier mapping by name (if unambiguous) + + For qualified paths (Pdot), module aliases are resolved to their actual + module names so that TypeScript imports work correctly. For example, + if `module N = Belt_internalBuckets`, then `N.t` becomes `Belt_internalBuckets.t`. *) +let type_display_name (path : Path.t) : string = + match get_env () with + | None -> Path.name path + | Some env -> ( + (* Split path into module prefix and type name *) + match path with + | Path.Pdot (prefix, type_name, pos) -> ( + (* Normalize the prefix path to resolve module aliases. + For example, if `module N = Belt_internalBuckets` and we have `N.t`, + this will resolve to `Belt_internalBuckets.t`. *) + let normalized_prefix = + try Env.normalize_path None env prefix with _ -> prefix + in + + let normalized_path = Path.Pdot (normalized_prefix, type_name, pos) in + match get_type_as_name env normalized_path with + | Some renamed -> Path.name normalized_prefix ^ "." ^ renamed + | None -> Path.name normalized_path) + | Path.Pident id -> ( + let base_name = + match get_type_as_name env path with + | Some renamed -> renamed + | None -> Ident.name id + in + (* Try to qualify local type references *) + match get_module_path () with + | _ :: _ as path_parts -> + (* If we have a current module path, use it *) + String.concat "." path_parts ^ "." ^ base_name + | [] -> ( + (* Try to look up from LocalTypeQualifier by stamp first *) + let stamp = Ident.binding_time id in + match LocalTypeQualifier.get_qualified_by_stamp stamp with + | Some qualified -> qualified + | None -> ( + (* Fall back to name-based lookup (only if unambiguous) *) + match LocalTypeQualifier.get_qualified_by_name base_name with + | Some qualified -> qualified + | None -> base_name))) + | Path.Papply _ -> Path.name path) + +(** Mapping from anonymous type variable IDs to generated names. + This is populated by collect_type_vars and used by ts_type_of_type_expr. *) +let anon_type_var_names : (int, string) Hashtbl.t = Hashtbl.create 16 + +(** Convert a Path.t to a list of strings for pattern matching. + e.g., Stdlib.Dict.t -> ["t"; "Dict"; "Stdlib"] (reversed) *) +let rec path_to_list (path : Path.t) : string list = + match path with + | Path.Pident id -> [Ident.name id] + | Path.Pdot (p, s, _) -> s :: path_to_list p + | Path.Papply _ -> [] + +(** Check if a type is the unit type *) +let rec is_unit_type (ty : Types.type_expr) : bool = + match ty.Types.desc with + | Types.Tconstr (path, [], _) -> Path.name path = "unit" + | Types.Tlink ty | Types.Tsubst ty -> is_unit_type ty + | _ -> false + +(** Remove option wrapper from optional labeled argument type. + For ~name: option=?, we want to emit name?: string, not name?: string | undefined *) +let rec remove_option_wrapper (lbl : Asttypes.arg_label) (ty : Types.type_expr) + : Types.type_expr option = + match (ty.Types.desc, lbl) with + | Types.Tconstr (Path.Pident id, [inner], _), Asttypes.Optional _ + when Ident.name id = "option" -> + Some inner + | Types.Tlink t, _ | Types.Tsubst t, _ -> remove_option_wrapper lbl t + | _ -> None + +(** {1 Polymorphic Variant Processing} *) + +type polyvar_field_info = { + pv_nullary: string list; (** Nullary constructors (no payload) *) + pv_with_payload: (string * Types.type_expr) list; + (** Constructors with payload *) + pv_has_unknown: bool; (** Has unknown/absent fields *) +} +(** Result of processing polymorphic variant row fields *) + +(** Process polymorphic variant row fields into categorized lists *) +let process_polyvar_fields (row_fields : (string * Types.row_field) list) : + polyvar_field_info = + let rec loop ~nullary ~with_payload ~has_unknown fields = + match fields with + | (label, Types.Rpresent None) :: rest -> + loop ~nullary:(label :: nullary) ~with_payload ~has_unknown rest + | (label, Types.Reither (true, [], _, _)) :: rest -> + loop ~nullary:(label :: nullary) ~with_payload ~has_unknown rest + | (label, Types.Rpresent (Some payload)) :: rest -> + loop ~nullary + ~with_payload:((label, payload) :: with_payload) + ~has_unknown rest + | (_, (Types.Rabsent | Types.Reither _)) :: rest -> + loop ~nullary ~with_payload ~has_unknown:true rest + | [] -> + { + pv_nullary = List.rev nullary; + pv_with_payload = List.rev with_payload; + pv_has_unknown = has_unknown; + } + in + loop ~nullary:[] ~with_payload:[] ~has_unknown:false row_fields + +(** Map from type variable name to the GADT type it's used with. + Used to convert type variables in return position to GADT union types. + Populated by collect_type_vars_with_constraints. *) +let gadt_type_var_map : string StringMap.t ref = ref StringMap.empty + +(** Check if a type variable is GADT-constrained and get the GADT type name *) +let get_gadt_for_type_var (var_name : string) : string option = + StringMap.find_opt var_name !gadt_type_var_map + +(** Check if a type name conflicts with TypeScript reserved words. + These need to be escaped to avoid syntax errors. + Includes primitive types and keywords that cannot be used as type alias names. *) +let is_ts_reserved_type_name name = + match name with + (* Primitive types *) + | "number" | "string" | "boolean" | "symbol" | "object" | "bigint" | "never" + | "unknown" | "any" | "void" | "null" | "undefined" + (* Reserved keywords that cannot be type alias names *) + | "function" | "class" | "enum" | "interface" | "type" | "namespace" + | "module" | "declare" | "abstract" | "as" | "implements" | "extends" + | "public" | "private" | "protected" | "static" | "readonly" -> + true + | _ -> false + +(** Escape a type name if it conflicts with TypeScript reserved words *) +let escape_ts_type_name name = + if is_ts_reserved_type_name name then name ^ "_" else name + +(** Collect type variables from a function type expression. + Returns a list of type_param for all free type variables in the function. + Used to add generic type parameters to function types like (x: A) => string. *) +let collect_fn_type_vars (ty : Types.type_expr) : type_param list = + let seen = Hashtbl.create 16 in + let vars = ref [] in + let rec collect ty = + match ty.Types.desc with + | Types.Tvar (Some name) -> + let var_name = String.capitalize_ascii name in + if not (Hashtbl.mem seen var_name) then ( + Hashtbl.add seen var_name (); + vars := + {tp_name = var_name; tp_constraint = None; tp_default = None} :: !vars) + | Types.Tvar None -> + (* Anonymous type var - use id as key *) + let key = Printf.sprintf "_anon_%d" ty.Types.id in + if not (Hashtbl.mem seen key) then ( + Hashtbl.add seen key (); + (* Generate a name based on position *) + let name = + match Hashtbl.find_opt anon_type_var_names ty.Types.id with + | Some n -> n + | None -> Printf.sprintf "T%d" (Hashtbl.length seen) + in + vars := + {tp_name = name; tp_constraint = None; tp_default = None} :: !vars) + | Types.Tarrow ({typ = arg_type; _}, return_type, _, _) -> + collect arg_type; + collect return_type + | Types.Ttuple types -> List.iter collect types + | Types.Tconstr (_, args, _) -> List.iter collect args + | Types.Tlink ty | Types.Tsubst ty -> collect ty + | _ -> () + in + collect ty; + List.rev !vars + +(** Convert ML type expression to TypeScript type. + This is the core function for type annotation generation. + Note: Set current_env before calling this for @as renaming support. *) +let rec ts_type_of_type_expr (ty : Types.type_expr) : ts_type = + match ty.desc with + | Tvar None -> ( + (* Look up the generated name for this anonymous type variable *) + match Hashtbl.find_opt anon_type_var_names ty.id with + | Some name -> ( + (* Check if this is a GADT-constrained type variable *) + match get_gadt_for_type_var name with + | Some gadt_name -> ( + (* Use the GADT constraint type (e.g., number | boolean) instead of the GADT union. + The constraint represents the actual types that can be returned. *) + match GadtConstraints.get_constraint_at gadt_name 0 with + | Some constraint_ty -> constraint_ty + | None -> TypeRef {name = gadt_name; args = []}) + | None -> TypeVar name) + | None -> Any (* Fallback if not collected *)) + | Tvar (Some name) -> ( + let var_name = String.capitalize_ascii name in + (* Check if this is a GADT-constrained type variable *) + match get_gadt_for_type_var var_name with + | Some gadt_name -> ( + (* Use the GADT constraint type (e.g., number | boolean) instead of the GADT union. + The constraint represents the actual types that can be returned. *) + match GadtConstraints.get_constraint_at gadt_name 0 with + | Some constraint_ty -> constraint_ty + | None -> TypeRef {name = gadt_name; args = []}) + | None -> TypeVar var_name) + | Tarrow _ -> + (* Convert arrow type to function. + Note: We do NOT collect type params here - that's done at the declaration + site via collect_type_vars_with_constraints. Nested arrow types (callbacks) + should not have their own type parameters. *) + let rec build_fn_type ty = + match ty.Types.desc with + | Types.Tarrow ({lbl; typ = arg_type}, return_type, _, _) -> ( + (* Check if this is a unit parameter that should be skipped *) + let is_unit_param = lbl = Nolabel && is_unit_type arg_type in + (* For optional labeled params, unwrap option to just T *) + let actual_type = + match lbl with + | Optional _ -> ( + match remove_option_wrapper lbl arg_type with + | Some inner -> inner + | None -> arg_type) + | _ -> arg_type + in + let param = + if is_unit_param then None + else + Some + { + param_name = + (match lbl with + | Nolabel -> None + | Labelled {txt} | Optional {txt} -> Some txt); + param_type = ts_type_of_type_expr actual_type; + param_optional = + (match lbl with + | Optional _ -> true + | _ -> false); + } + in + (* Recursively process nested arrows *) + match build_fn_type return_type with + | Function {fn_params; fn_rest; fn_return; fn_async; _} -> + Function + { + fn_params = + (match param with + | Some p -> p :: fn_params + | None -> fn_params); + fn_rest; + fn_return; + fn_type_params = []; + (* No type params for nested functions *) + fn_async; + } + | return_ts -> + Function + { + fn_params = + (match param with + | Some p -> [p] + | None -> []); + fn_rest = None; + fn_return = return_ts; + fn_type_params = []; + (* No type params for nested functions *) + fn_async = false; + }) + | Types.Tlink t | Types.Tsubst t -> build_fn_type t + | _ -> ts_type_of_type_expr ty + in + build_fn_type ty + | Ttuple types -> Tuple (List.map ts_type_of_type_expr types) + | Tconstr (path, args, _) -> ts_type_of_constr path args + | Tlink ty | Tsubst ty -> ts_type_of_type_expr ty + | Tpoly (ty, type_vars) -> ( + (* Polymorphic type with locally abstract types: type a. t => unit + Extract type variables and add them to the function's type params. + This is for explicitly polymorphic callback functions. *) + match ts_type_of_type_expr ty with + | Function fn when type_vars <> [] -> + (* Extract type parameter names from the locally abstract types *) + let extra_type_params = + List.filter_map + (fun tv -> + match tv.Types.desc with + | Types.Tvar (Some name) -> + Some + { + tp_name = String.capitalize_ascii name; + tp_constraint = None; + tp_default = None; + } + | Types.Tvar None -> + (* Anonymous type var - generate a name *) + Some {tp_name = "T"; tp_constraint = None; tp_default = None} + | _ -> None) + type_vars + in + Function {fn with fn_type_params = extra_type_params} + | other -> other) + | Tvariant row_desc -> ( + (* Polymorphic variants *) + let info = process_polyvar_fields row_desc.row_fields in + if info.pv_has_unknown then Any + else + let nullary_types = + List.map (fun label -> Literal (LitString label)) info.pv_nullary + in + let payload_types = + List.map + (fun (label, payload) -> + (* Polymorphic variant with payload: { readonly NAME: "label"; readonly VAL: payload } *) + (Object + { + properties = + [ + { + prop_name = Literals.polyvar_hash; + prop_type = Literal (LitString label); + prop_optional = false; + prop_readonly = true; + }; + { + prop_name = Literals.polyvar_value; + prop_type = ts_type_of_type_expr payload; + prop_optional = false; + prop_readonly = true; + }; + ]; + index_sig = None; + call_sig = None; + } + : ts_type)) + info.pv_with_payload + in + match nullary_types @ payload_types with + | [] -> Never + | [single] -> single + | types -> Union types) + | Tobject (t_obj, _) -> + (* Object types - extract fields from Tfield chain *) + let rec get_fields (ty : Types.type_expr) : (string * ts_type) list = + match ty.Types.desc with + | Types.Tfield (name, _, field_type, rest) -> + (* Skip internal fields starting with special characters *) + if String.length name > 0 && name.[0] = '#' then get_fields rest + else (name, ts_type_of_type_expr field_type) :: get_fields rest + | Types.Tlink ty | Types.Tsubst ty -> get_fields ty + | Types.Tnil -> [] + | _ -> [] (* Open object type - stop here *) + in + let fields = get_fields t_obj in + Object + { + properties = + List.map + (fun (name, ty) -> + { + prop_name = name; + prop_type = ty; + prop_optional = false; + prop_readonly = false; + }) + fields; + index_sig = None; + call_sig = None; + } + | Tfield _ | Tnil -> Any + | Tunivar None -> ( + (* Look up the generated name for this anonymous type variable *) + match Hashtbl.find_opt anon_type_var_names ty.id with + | Some name -> ( + (* Check if this is a GADT-constrained type variable *) + match get_gadt_for_type_var name with + | Some gadt_name -> ( + (* Use the GADT constraint type instead of the GADT union *) + match GadtConstraints.get_constraint_at gadt_name 0 with + | Some constraint_ty -> constraint_ty + | None -> TypeRef {name = gadt_name; args = []}) + | None -> TypeVar name) + | None -> Any (* Fallback if not collected *)) + | Tunivar (Some name) -> ( + let var_name = String.capitalize_ascii name in + (* Check if this is a GADT-constrained type variable *) + match get_gadt_for_type_var var_name with + | Some gadt_name -> ( + (* Use the GADT constraint type instead of the GADT union *) + match GadtConstraints.get_constraint_at gadt_name 0 with + | Some constraint_ty -> constraint_ty + | None -> TypeRef {name = gadt_name; args = []}) + | None -> TypeVar var_name) + | Tpackage _ -> Any + +and ts_type_of_constr (path : Path.t) (args : Types.type_expr list) : ts_type = + (* Normalize the path to resolve module aliases. + For example, Stdlib.Dict.t becomes Stdlib_Dict.t + and C.opt (where module C = Belt_internalBucketsType) becomes Belt_internalBucketsType.opt *) + let rec normalize_type_path env p = + match p with + | Path.Pdot (prefix, name, pos) -> + let normalized_prefix = + (* First try our tracked module aliases *) + match prefix with + | Path.Pident id -> ( + match ModuleAliases.find (Ident.name id) with + | Some alias_path -> alias_path + | None -> ( + (* Fall back to Env.normalize_path *) + try Env.normalize_path None env prefix + with _ -> normalize_type_path env prefix)) + | _ -> ( + try Env.normalize_path None env prefix + with _ -> normalize_type_path env prefix) + in + Path.Pdot (normalized_prefix, name, pos) + | Path.Pident id -> ( + (* For simple identifiers, try to resolve module aliases. + E.g., if we have "module C = Belt_internalBucketsType", + Pident(C) should become the path to Belt_internalBucketsType. *) + (* First check our tracked module aliases *) + match ModuleAliases.find (Ident.name id) with + | Some alias_path -> alias_path + | None -> ( + (* Fall back to Env.find_module *) + try + match Env.find_module p env with + | {md_type = Mty_alias (_, alias_path)} -> alias_path + | _ -> p + with Not_found -> p)) + | _ -> p + in + let normalized_path = + match get_env () with + | Some env -> normalize_type_path env path + | None -> path + in + (* Handle built-in types specially using path list for better matching *) + let path_list = path_to_list normalized_path in + match (List.rev path_list, args) with + | (["int"] | ["float"] | ["char"]), [] -> Number + | ["bool"], [] -> Boolean + | ["string"], [] -> String + | ["unit"], [] -> Void + | ["bigint"], [] -> Bigint + | ["symbol"], [] -> Symbol + | ["array"], [elem] -> Array (ts_type_of_type_expr elem) + | ["dict"], [value] -> + RuntimeType {rt_name = "dict"; rt_args = [ts_type_of_type_expr value]} + | ["option"], [elem] -> + RuntimeType {rt_name = "option"; rt_args = [ts_type_of_type_expr elem]} + | ["promise"], [elem] -> Promise (ts_type_of_type_expr elem) + | ["promise"], [] -> Promise Any + | ["result"], [ok; err] -> + RuntimeType + { + rt_name = "result"; + rt_args = [ts_type_of_type_expr ok; ts_type_of_type_expr err]; + } + | ["list"], [elem] -> + RuntimeType {rt_name = "list"; rt_args = [ts_type_of_type_expr elem]} + | ["exn"], [] -> RuntimeType {rt_name = "exn"; rt_args = []} + | ["unknown"], [] -> Unknown + | _ -> + (* Generic type reference with @as renaming applied. + Module aliases are resolved in type_display_name. *) + let type_name = type_display_name normalized_path in + let simple_name = Path.last normalized_path in + (* For GADT lookup, we need to check with escaped names since GADTs are registered + with escaped names (e.g., "number_" for a GADT named "number") *) + let escaped_simple_name = escape_ts_type_name simple_name in + let escaped_type_name = escape_ts_type_name type_name in + (* Check if this is a GADT type - if so, handle specially + Try both qualified and simple names since registration uses escaped name *) + if + GadtSubUnions.is_gadt escaped_type_name + || GadtSubUnions.is_gadt escaped_simple_name + then + let gadt_name = + if GadtSubUnions.is_gadt escaped_type_name then escaped_type_name + else escaped_simple_name + in + (* For GADT types, check if we can use a sub-union *) + match args with + | [arg] -> ( + (* Single type argument - try to find matching sub-union *) + let key = + match arg.Types.desc with + | Types.Tconstr (arg_path, [], _) -> + Some (String.lowercase_ascii (Path.last arg_path)) + | Types.Tlink t | Types.Tsubst t -> ( + match t.Types.desc with + | Types.Tconstr (arg_path, [], _) -> + Some (String.lowercase_ascii (Path.last arg_path)) + | _ -> None) + | _ -> None + in + match key with + | Some k when GadtSubUnions.get_sub_union_key gadt_name k <> None -> + (* Use sub-union type *) + TypeRef {name = gadt_name ^ "$" ^ k; args = []} + | _ -> + (* No sub-union, use main union type without args *) + TypeRef {name = gadt_name; args = []}) + | _ -> + (* No args or multiple args - use main union type *) + TypeRef {name = gadt_name; args = []} + else + (* Normal type reference. + We need to escape the last component if it's a TS reserved name, + because the type declaration would have been escaped. *) + let final_name = + if is_ts_reserved_type_name simple_name then + (* Escape the last component of the path *) + match String.rindex_opt type_name '.' with + | Some idx -> String.sub type_name 0 (idx + 1) ^ simple_name ^ "_" + | None -> simple_name ^ "_" + else type_name + in + TypeRef {name = final_name; args = List.map ts_type_of_type_expr args} + +(** {1 Utility Functions} *) + +(** Create a typed identifier from an ident and optional ML type *) +let typed_ident_of_ident ?(typ : Types.type_expr option) (id : ident) : + typed_ident = + {ident = id; ident_type = Option.map ts_type_of_type_expr typ} + +(** Create typed identifiers from a list of idents, extracting types from a function type *) +let typed_idents_of_params (params : ident list) + (fn_type : Types.type_expr option) : typed_ident list = + match fn_type with + | None -> List.map (fun id -> {ident = id; ident_type = None}) params + | Some ty -> + let rec extract_param_types ty acc = + match ty.Types.desc with + | Types.Tarrow ({typ = arg_type; _}, return_type, _, _) -> + extract_param_types return_type (ts_type_of_type_expr arg_type :: acc) + | Types.Tlink ty | Types.Tsubst ty -> extract_param_types ty acc + | _ -> List.rev acc + in + let param_types = extract_param_types ty [] in + let num_params = List.length params in + let num_types = List.length param_types in + let adjusted_types = + if num_types >= num_params then + (* Take only as many types as we have params *) + let rec take n lst = + match (n, lst) with + | 0, _ | _, [] -> [] + | n, x :: xs -> x :: take (n - 1) xs + in + take num_params param_types + else + (* Pad with Any if we have fewer types than params *) + param_types @ List.init (num_params - num_types) (fun _ -> Any) + in + List.map2 + (fun id typ -> {ident = id; ident_type = Some typ}) + params adjusted_types + +(** Extract return type from a function type expression *) +let return_type_of_fn_type (fn_type : Types.type_expr option) : ts_type option = + match fn_type with + | None -> None + | Some ty -> + let rec find_return ty = + match ty.Types.desc with + | Types.Tarrow (_, return_type, _, _) -> find_return return_type + | Types.Tlink ty | Types.Tsubst ty | Types.Tpoly (ty, _) -> find_return ty + | _ -> ts_type_of_type_expr ty + in + Some (find_return ty) + +(** Extract the raw return type expression from a function type. + Used for opaque type assertions on return statements. *) +let return_type_expr_of_fn_type (fn_type : Types.type_expr option) : + Types.type_expr option = + match fn_type with + | None -> None + | Some ty -> + let rec find_return ty = + match ty.Types.desc with + | Types.Tarrow (_, return_type, _, _) -> find_return return_type + | Types.Tlink ty | Types.Tsubst ty | Types.Tpoly (ty, _) -> find_return ty + | _ -> ty + in + Some (find_return ty) + +(** Generate a type variable name from an index (0 -> "A", 1 -> "B", etc.) *) +let type_var_name_of_index (i : int) : string = + if i < 26 then String.make 1 (Char.chr (Char.code 'A' + i)) + else Printf.sprintf "T%d" (i - 26) + +(** Collect all type variables from a type expression. + Returns the list of type variable names (both named and anonymous). + Also populates anon_type_var_names for anonymous type variables. *) +let collect_type_vars (fn_type : Types.type_expr option) : string list = + Hashtbl.clear anon_type_var_names; + match fn_type with + | None -> [] + | Some ty -> + let vars = ref [] in + let seen_named = Hashtbl.create 16 in + let seen_anon = Hashtbl.create 16 in + let anon_counter = ref 0 in + let rec collect ty = + match ty.Types.desc with + | Types.Tvar (Some name) -> + if not (Hashtbl.mem seen_named name) then ( + Hashtbl.add seen_named name (); + vars := String.capitalize_ascii name :: !vars) + | Types.Tvar None -> + if not (Hashtbl.mem seen_anon ty.Types.id) then ( + Hashtbl.add seen_anon ty.Types.id (); + let name = type_var_name_of_index !anon_counter in + incr anon_counter; + Hashtbl.add anon_type_var_names ty.Types.id name; + vars := name :: !vars) + | Types.Tarrow ({typ = arg_type; _}, return_type, _, _) -> + collect arg_type; + collect return_type + | Types.Ttuple types -> List.iter collect types + | Types.Tconstr (_, args, _) -> List.iter collect args + | Types.Tlink ty | Types.Tsubst ty -> collect ty + | Types.Tpoly (ty, type_vars) -> + (* Extract locally abstract type variables from Tpoly *) + List.iter + (fun tv -> + match tv.Types.desc with + | Types.Tunivar (Some name) | Types.Tvar (Some name) -> + if not (Hashtbl.mem seen_named name) then ( + Hashtbl.add seen_named name (); + vars := String.capitalize_ascii name :: !vars) + | Types.Tunivar None | Types.Tvar None -> + if not (Hashtbl.mem seen_anon tv.Types.id) then ( + Hashtbl.add seen_anon tv.Types.id (); + let name = type_var_name_of_index !anon_counter in + incr anon_counter; + Hashtbl.add anon_type_var_names tv.Types.id name; + vars := name :: !vars) + | _ -> ()) + type_vars; + collect ty + | Types.Tunivar (Some name) -> + (* Tunivar can appear in locally abstract types *) + if not (Hashtbl.mem seen_named name) then ( + Hashtbl.add seen_named name (); + vars := String.capitalize_ascii name :: !vars) + | Types.Tunivar None -> + if not (Hashtbl.mem seen_anon ty.Types.id) then ( + Hashtbl.add seen_anon ty.Types.id (); + let name = type_var_name_of_index !anon_counter in + incr anon_counter; + Hashtbl.add anon_type_var_names ty.Types.id name; + vars := name :: !vars) + | _ -> () + in + collect ty; + List.rev !vars + +(** Collect type variables with GADT constraints from a type expression. + For each type variable, looks up constraints from GADT types it's used with. + Returns list of type_param with constraints. + Also populates gadt_type_var_map for return type conversion. *) +let collect_type_vars_with_constraints (fn_type : Types.type_expr option) : + type_param list = + Hashtbl.clear anon_type_var_names; + gadt_type_var_map := StringMap.empty; + match fn_type with + | None -> [] + | Some ty -> + (* Map from type var name to (constraint option, gadt_type_name option) *) + let var_constraints : ts_type option StringMap.t ref = + ref StringMap.empty + in + (* Track which type variables are used with GADT types *) + let gadt_vars : string StringMap.t ref = ref StringMap.empty in + let vars = ref [] in + let seen_named = Hashtbl.create 16 in + let seen_anon = Hashtbl.create 16 in + let anon_counter = ref 0 in + (* Get var name for a type expression, following Tlink/Tsubst *) + let rec get_var_name tv = + match tv.Types.desc with + | Types.Tvar (Some name) | Types.Tunivar (Some name) -> + Some (String.capitalize_ascii name) + | Types.Tvar None | Types.Tunivar None -> ( + match Hashtbl.find_opt anon_type_var_names tv.Types.id with + | Some name -> Some name + | None -> None) + | Types.Tlink t | Types.Tsubst t -> get_var_name t + | _ -> None + in + let rec collect ty = + match ty.Types.desc with + | Types.Tvar (Some name) -> + if not (Hashtbl.mem seen_named name) then ( + Hashtbl.add seen_named name (); + vars := String.capitalize_ascii name :: !vars) + | Types.Tvar None -> + if not (Hashtbl.mem seen_anon ty.Types.id) then ( + Hashtbl.add seen_anon ty.Types.id (); + let name = type_var_name_of_index !anon_counter in + incr anon_counter; + Hashtbl.add anon_type_var_names ty.Types.id name; + vars := name :: !vars) + | Types.Tarrow ({typ = arg_type; _}, return_type, _, _) -> + collect arg_type; + collect return_type + | Types.Ttuple types -> List.iter collect types + | Types.Tconstr (path, args, _) -> + (* Check if any args are type vars and look up constraints *) + let type_name = Path.last path in + (* Escape to match how GADT is registered *) + let escaped_type_name = escape_ts_type_name type_name in + (match GadtConstraints.get escaped_type_name with + | Some constraints -> + List.iteri + (fun i arg -> + match get_var_name arg with + | Some var_name -> ( + (* Track that this type var is used with this GADT (with escaped name) *) + gadt_vars := StringMap.add var_name escaped_type_name !gadt_vars; + match List.nth_opt constraints i |> Option.join with + | Some constraint_ty -> + (* Merge constraints: if var already has constraint, union them *) + let existing = + StringMap.find_opt var_name !var_constraints |> Option.join + in + let merged = + match existing with + | None -> constraint_ty + | Some (Union types) -> Union (constraint_ty :: types) + | Some existing_ty -> + if existing_ty = constraint_ty then existing_ty + else Union [existing_ty; constraint_ty] + in + var_constraints := + StringMap.add var_name (Some merged) !var_constraints + | None -> ()) + | None -> ()) + args + | None -> ()); + List.iter collect args + | Types.Tlink ty | Types.Tsubst ty -> collect ty + | Types.Tpoly (ty, type_vars) -> + (* Extract locally abstract type variables from Tpoly *) + List.iter + (fun tv -> + match tv.Types.desc with + | Types.Tunivar (Some name) | Types.Tvar (Some name) -> + if not (Hashtbl.mem seen_named name) then ( + Hashtbl.add seen_named name (); + vars := String.capitalize_ascii name :: !vars) + | Types.Tunivar None | Types.Tvar None -> + if not (Hashtbl.mem seen_anon tv.Types.id) then ( + Hashtbl.add seen_anon tv.Types.id (); + let name = type_var_name_of_index !anon_counter in + incr anon_counter; + Hashtbl.add anon_type_var_names tv.Types.id name; + vars := name :: !vars) + | _ -> ()) + type_vars; + collect ty + | Types.Tunivar (Some name) -> + if not (Hashtbl.mem seen_named name) then ( + Hashtbl.add seen_named name (); + vars := String.capitalize_ascii name :: !vars) + | Types.Tunivar None -> + if not (Hashtbl.mem seen_anon ty.Types.id) then ( + Hashtbl.add seen_anon ty.Types.id (); + let name = type_var_name_of_index !anon_counter in + incr anon_counter; + Hashtbl.add anon_type_var_names ty.Types.id name; + vars := name :: !vars) + | _ -> () + in + collect ty; + (* Store the GADT type var map for later use in return type conversion *) + gadt_type_var_map := !gadt_vars; + (* Filter out type variables that are GADT-constrained *) + let non_gadt_vars = + List.filter (fun name -> not (StringMap.mem name !gadt_vars)) !vars + in + (* Convert to type_param list with constraints *) + let result = + List.rev_map + (fun name -> + { + tp_name = name; + tp_constraint = + StringMap.find_opt name !var_constraints |> Option.join; + tp_default = None; + }) + non_gadt_vars + in + (* Deduplicate result - there may be duplicates if the same name appears + in multiple places (e.g., 'a in Tvar and a in Tpoly type_vars) *) + let seen_in_result = Hashtbl.create 16 in + let deduped_result = + List.filter + (fun tp -> + if Hashtbl.mem seen_in_result tp.tp_name then false + else ( + Hashtbl.add seen_in_result tp.tp_name (); + true)) + result + in + deduped_result + +(** {1 Type Declaration Extraction} *) + +(** Extract type arguments from a GADT constructor result type. + For a result type like t, returns [int_ts_type, string_ts_type]. + The result type is expected to be a Tconstr with the same path as the GADT itself. *) +let extract_gadt_type_args (res_ty : Types.type_expr) : ts_type list = + let rec unwrap ty = + match ty.Types.desc with + | Types.Tlink t | Types.Tsubst t -> unwrap t + | Types.Tconstr (_, args, _) -> List.map ts_type_of_type_expr args + | _ -> [] + in + unwrap res_ty + +(** Extract a simple key from a GADT result type's type argument (from Types.type_expr). + Returns Some key for concrete types (int, float, bool, string, or named types). + Returns None for type variables or complex types where sub-union grouping doesn't make sense. + Uses original type_expr to preserve distinction between int/float. *) +let gadt_result_key_of_type_expr (ty : Types.type_expr) : string option = + let rec extract ty = + match ty.Types.desc with + | Types.Tconstr (path, [], _) -> + (* Concrete type without arguments *) + Some (String.lowercase_ascii (Path.last path)) + | Types.Tlink t | Types.Tsubst t -> extract t + | Types.Tvar _ -> None (* Type variable - can't group *) + | _ -> None + in + extract ty + +(** Extract the first type argument from a GADT constructor's result type. + For a result type like t, returns Some int_type_expr. + For a result type like t<'a>, returns Some 'a_type_expr. *) +let extract_gadt_first_type_arg (res_ty : Types.type_expr) : + Types.type_expr option = + let rec unwrap ty = + match ty.Types.desc with + | Types.Tlink t | Types.Tsubst t -> unwrap t + | Types.Tconstr (_, first_arg :: _, _) -> Some first_arg + | _ -> None + in + unwrap res_ty + +(** Compute constraints for GADT type parameters from constructor result types. + For each type parameter position, collects all the types that appear at that position + across all constructors, then creates a union constraint. + E.g., for t<_> with Int: t and Str: t, returns [Some (number | string)] *) +let compute_gadt_constraints (constructors : Types.constructor_declaration list) + (num_params : int) : ts_type option list = + if num_params = 0 then [] + else + (* Collect type arguments from each constructor *) + let all_args = + List.filter_map + (fun (cd : Types.constructor_declaration) -> + match cd.cd_res with + | Some res_ty -> + let args = extract_gadt_type_args res_ty in + if List.length args = num_params then Some args else None + | None -> None) + constructors + in + (* For each parameter position, collect all types and create union *) + List.init num_params (fun i -> + let types_at_pos = + List.filter_map (fun args -> List.nth_opt args i) all_args + in + (* Filter out type variables - they represent existential types and shouldn't + be part of the constraint. Only concrete types matter for the constraint union. *) + let concrete_types = + List.filter + (fun ty -> + match ty with + | TypeVar _ -> false + | _ -> true) + types_at_pos + in + (* Remove duplicates and create union if multiple types *) + let unique_types = + List.fold_left + (fun acc ty -> + if List.exists (fun t -> t = ty) acc then acc else ty :: acc) + [] concrete_types + |> List.rev + in + match unique_types with + | [] -> None + | [single] -> Some single + | multiple -> Some (Union multiple)) + +(** Compute sub-unions for GADT types. + Groups constructors by their result type's first type argument. + For expr<_> with IntLit: expr, Add: expr, BoolLit: expr: + Returns [{key="int"; constructors=["IntLit";"Add"]}; {key="bool"; constructors=["BoolLit"]}] + Only creates sub-unions for concrete type arguments (not type variables). *) +let compute_gadt_sub_unions (cases : gadt_case list) : gadt_sub_union list = + (* Group cases by their result key *) + let groups = Hashtbl.create 16 in + List.iter + (fun (case : gadt_case) -> + match case.gc_result_key with + | Some key -> + let existing = + match Hashtbl.find_opt groups key with + | Some l -> l + | None -> [] + in + Hashtbl.replace groups key (case.gc_name :: existing) + | None -> ()) + cases; + (* Convert to list, only keeping groups with 1+ constructors *) + Hashtbl.fold + (fun key constructors acc -> + {gsu_key = key; gsu_constructors = List.rev constructors} :: acc) + groups [] + |> List.sort (fun a b -> String.compare a.gsu_key b.gsu_key) + +(** Transform a ts_type to use sub-union references for GADT payload types. + Replaces TypeRef nodes like expr with expr$int if a sub-union exists. + @param gadt_name The name of the GADT type (e.g., "expr") + @param sub_unions List of available sub-unions with their keys *) +let rec transform_gadt_payload_type ~(gadt_name : string) + ~(sub_unions : gadt_sub_union list) (ty : ts_type) : ts_type = + match ty with + | TypeRef {name; args = [arg]} when name = gadt_name -> ( + (* This is a reference to the GADT type with one type argument *) + (* Try to find the corresponding sub-union key *) + let key = + match arg with + | Number -> Some "int" + | Boolean -> Some "bool" + | String -> Some "string" + | Bigint -> Some "bigint" + | TypeRef {name = tname; args = []} -> Some (String.lowercase_ascii tname) + | _ -> None + in + match key with + | Some k when List.exists (fun su -> su.gsu_key = k) sub_unions -> + (* Found a sub-union, use it *) + TypeRef {name = gadt_name ^ "$" ^ k; args = []} + | _ -> + (* No sub-union for this key, use the full union type without args *) + TypeRef {name = gadt_name; args = []}) + | TypeRef {name; args} when name = gadt_name -> + (* GADT reference without single arg - just use the union type *) + TypeRef {name = gadt_name; args = []} + | Array elem -> + Array (transform_gadt_payload_type ~gadt_name ~sub_unions elem) + | Tuple types -> + Tuple (List.map (transform_gadt_payload_type ~gadt_name ~sub_unions) types) + | Object {properties; index_sig; call_sig} -> + Object + { + properties = + List.map + (fun p -> + { + p with + prop_type = + transform_gadt_payload_type ~gadt_name ~sub_unions p.prop_type; + }) + properties; + index_sig = + Option.map + (fun is -> + { + index_key = + transform_gadt_payload_type ~gadt_name ~sub_unions + is.index_key; + index_value = + transform_gadt_payload_type ~gadt_name ~sub_unions + is.index_value; + }) + index_sig; + call_sig; + } + | Function fn -> + Function + { + fn with + fn_params = + List.map + (fun p -> + { + p with + param_type = + transform_gadt_payload_type ~gadt_name ~sub_unions + p.param_type; + }) + fn.fn_params; + fn_return = + transform_gadt_payload_type ~gadt_name ~sub_unions fn.fn_return; + } + | Union types -> + Union (List.map (transform_gadt_payload_type ~gadt_name ~sub_unions) types) + | Intersection types -> + Intersection + (List.map (transform_gadt_payload_type ~gadt_name ~sub_unions) types) + | Readonly t -> + Readonly (transform_gadt_payload_type ~gadt_name ~sub_unions t) + | Promise t -> Promise (transform_gadt_payload_type ~gadt_name ~sub_unions t) + | RuntimeType {rt_name; rt_args} -> + RuntimeType + { + rt_name; + rt_args = + List.map (transform_gadt_payload_type ~gadt_name ~sub_unions) rt_args; + } + | _ -> ty + +(** Transform a variant_payload to use sub-union references *) +let transform_gadt_payload ~(gadt_name : string) + ~(sub_unions : gadt_sub_union list) (payload : variant_payload) : + variant_payload = + match payload with + | NoPayload -> NoPayload + | TuplePayload types -> + TuplePayload + (List.map (transform_gadt_payload_type ~gadt_name ~sub_unions) types) + | InlineRecord properties -> + InlineRecord + (List.map + (fun p -> + { + p with + prop_type = + transform_gadt_payload_type ~gadt_name ~sub_unions p.prop_type; + }) + properties) + +(** Convert type parameters from Types.type_expr list to type_param list *) +let type_params_of_type_exprs (params : Types.type_expr list) : type_param list + = + List.mapi + (fun i param -> + match param.Types.desc with + | Types.Tvar (Some name) -> + { + tp_name = String.capitalize_ascii name; + tp_constraint = None; + tp_default = None; + } + | Types.Tvar None -> + { + tp_name = Printf.sprintf "T%d" i; + tp_constraint = None; + tp_default = None; + } + | _ -> + { + tp_name = Printf.sprintf "T%d" i; + tp_constraint = None; + tp_default = None; + }) + params + +(** Convert type parameters with GADT constraints. + For GADT types, we set the default equal to the constraint so the type + can be used without explicit type args (e.g., `expr` instead of `expr`). *) +let type_params_of_type_exprs_with_constraints (params : Types.type_expr list) + (constraints : ts_type option list) : type_param list = + List.mapi + (fun i param -> + let constraint_opt = + match List.nth_opt constraints i with + | Some c -> c + | None -> None + in + (* Set default equal to constraint so GADT types can be used without type args *) + let default_opt = constraint_opt in + match param.Types.desc with + | Types.Tvar (Some name) -> + { + tp_name = String.capitalize_ascii name; + tp_constraint = constraint_opt; + tp_default = default_opt; + } + | Types.Tvar None -> + { + tp_name = Printf.sprintf "T%d" i; + tp_constraint = constraint_opt; + tp_default = default_opt; + } + | _ -> + { + tp_name = Printf.sprintf "T%d" i; + tp_constraint = constraint_opt; + tp_default = default_opt; + }) + params + +(** Extract a type declaration from Types.type_declaration *) +let type_decl_of_type_declaration (id : Ident.t) (decl : Types.type_declaration) + : type_decl option = + let type_params = type_params_of_type_exprs decl.type_params in + let raw_type_name = + match get_as_string decl.type_attributes with + | Some renamed -> renamed + | None -> Ident.name id + in + (* Escape type names that conflict with TypeScript primitives *) + let type_name = escape_ts_type_name raw_type_name in + (* Check for @external attribute upfront for types with shapes *) + let external_type_info = get_external_type decl.type_attributes in + match decl.type_kind with + | Types.Type_record (labels, _) -> ( + (* Record type -> Interface or TypeAlias with external validation *) + let properties = + List.map + (fun (ld : Types.label_declaration) -> + let name = + match get_as_string ld.ld_attributes with + | Some renamed -> renamed + | None -> Ident.name ld.ld_id + in + { + prop_name = name; + prop_type = ts_type_of_type_expr ld.ld_type; + prop_optional = ld.ld_optional; + prop_readonly = ld.ld_mutable = Asttypes.Immutable; + }) + labels + in + let body = make_object_type ~properties ~index_sig:None ~call_sig:None in + match external_type_info with + | Some {ext_type_name; ext_module_path; ext_use_external; ext_import_kind} + -> + (* Record with @external - generate TypeAlias with validation *) + (* For default/namespace imports, use mangled name with $ prefix *) + let etc_name = + match ext_import_kind with + | ExtDefault | ExtNamespace -> "$" ^ type_name + | ExtNamed _ -> ext_type_name + in + Some + (TypeAlias + { + name = type_name; + type_params; + body; + external_type = + Some + { + etc_name; + etc_module = ext_module_path; + etc_use_external = ext_use_external; + etc_import_kind = ext_import_kind; + }; + is_opaque = false; + }) + | None -> + (* Regular record - generate Interface *) + Some + (Interface + { + name = type_name; + type_params; + extends = []; + body = {properties; index_sig = None; call_sig = None}; + })) + | Types.Type_variant constructors -> ( + (* Check if this variant has a manifest that maps to a runtime type. + For example: type t<'a> = option<'a> = None | Some('a) + In this case, we should generate a type alias to the runtime type + instead of the full variant definition. *) + match decl.type_manifest with + | Some manifest_ty -> ( + let ts_ty = ts_type_of_type_expr manifest_ty in + match ts_ty with + | RuntimeType _ -> + (* This variant re-exports a runtime type, generate alias instead *) + Some + (TypeAlias + { + name = type_name; + type_params; + body = ts_ty; + external_type = None; + is_opaque = false; + }) + | _ -> + (* Manifest exists but isn't a runtime type - generate full variant *) + let is_unboxed = + Ast_untagged_variants.has_untagged decl.type_attributes + in + let tag_name = + match Ast_untagged_variants.process_tag_name decl.type_attributes with + | Some custom_tag -> custom_tag + | None -> Js_dump_lit.tag + in + let config = {vc_unboxed = is_unboxed; vc_tag_name = tag_name} in + let cases = + List.map + (fun (cd : Types.constructor_declaration) -> + let name = Ident.name cd.cd_id in + let tag = + match + Ast_untagged_variants.process_tag_type cd.cd_attributes + with + | Some (Ast_untagged_variants.String s) -> TagString s + | Some (Ast_untagged_variants.Int i) -> TagInt i + | Some Ast_untagged_variants.Null -> TagNull + | Some Ast_untagged_variants.Undefined -> TagUndefined + | Some (Ast_untagged_variants.Bool b) -> TagBool b + | _ -> ( + match get_as_string cd.cd_attributes with + | Some renamed -> TagString renamed + | None -> TagString name) + in + let payload = + match cd.cd_args with + | Cstr_tuple [] -> NoPayload + | Cstr_tuple [arg] -> TuplePayload [ts_type_of_type_expr arg] + | Cstr_tuple args -> + TuplePayload (List.map ts_type_of_type_expr args) + | Cstr_record labels -> + let properties = + List.map + (fun (ld : Types.label_declaration) -> + let field_name = + match get_as_string ld.ld_attributes with + | Some renamed -> renamed + | None -> Ident.name ld.ld_id + in + { + prop_name = field_name; + prop_type = ts_type_of_type_expr ld.ld_type; + prop_optional = ld.ld_optional; + prop_readonly = ld.ld_mutable = Asttypes.Immutable; + }) + labels + in + InlineRecord properties + in + {vc_name = name; vc_tag = tag; vc_payload = payload}) + constructors + in + Some (VariantType {name = type_name; type_params; cases; config})) + | None -> + (* Check if this is a GADT - any constructor has a result type annotation *) + let is_gadt = + List.exists + (fun (cd : Types.constructor_declaration) -> cd.cd_res <> None) + constructors + in + let is_unboxed = + Ast_untagged_variants.has_untagged decl.type_attributes + in + let tag_name = + match Ast_untagged_variants.process_tag_name decl.type_attributes with + | Some custom_tag -> custom_tag + | None -> Js_dump_lit.tag + in + let config = {vc_unboxed = is_unboxed; vc_tag_name = tag_name} in + if is_gadt then ( + (* Generate GADT type with constructor-specific result types *) + (* First compute constraints for type parameters *) + let num_params = List.length decl.type_params in + let constraints = compute_gadt_constraints constructors num_params in + (* Register constraints for function signature generation *) + GadtConstraints.add type_name constraints; + let type_params_with_constraints = + type_params_of_type_exprs_with_constraints decl.type_params + constraints + in + let cases = + List.map + (fun (cd : Types.constructor_declaration) -> + let name = Ident.name cd.cd_id in + let tag = + match + Ast_untagged_variants.process_tag_type cd.cd_attributes + with + | Some (Ast_untagged_variants.String s) -> TagString s + | Some (Ast_untagged_variants.Int i) -> TagInt i + | Some Ast_untagged_variants.Null -> TagNull + | Some Ast_untagged_variants.Undefined -> TagUndefined + | Some (Ast_untagged_variants.Bool b) -> TagBool b + | _ -> ( + match get_as_string cd.cd_attributes with + | Some renamed -> TagString renamed + | None -> TagString name) + in + let payload = + match cd.cd_args with + | Cstr_tuple [] -> NoPayload + | Cstr_tuple [arg] -> TuplePayload [ts_type_of_type_expr arg] + | Cstr_tuple args -> + TuplePayload (List.map ts_type_of_type_expr args) + | Cstr_record labels -> + let properties = + List.map + (fun (ld : Types.label_declaration) -> + let field_name = + match get_as_string ld.ld_attributes with + | Some renamed -> renamed + | None -> Ident.name ld.ld_id + in + { + prop_name = field_name; + prop_type = ts_type_of_type_expr ld.ld_type; + prop_optional = ld.ld_optional; + prop_readonly = ld.ld_mutable = Asttypes.Immutable; + }) + labels + in + InlineRecord properties + in + (* For GADT, get the result type from cd_res *) + let result_type, result_key = + match cd.cd_res with + | Some res_ty -> + let ts_ty = ts_type_of_type_expr res_ty in + (* Extract the key from original type_expr to preserve int/float distinction *) + let key = + match extract_gadt_first_type_arg res_ty with + | Some first_arg -> gadt_result_key_of_type_expr first_arg + | None -> None + in + (ts_ty, key) + | None -> + (* Constructor without result type annotation - use base type *) + ( TypeRef + { + name = type_name; + args = + List.map + (fun tp -> TypeVar tp.tp_name) + type_params_with_constraints; + }, + None ) + in + { + gc_name = name; + gc_tag = tag; + gc_payload = payload; + gc_result_type = result_type; + gc_result_key = result_key; + }) + constructors + in + (* Compute sub-unions grouping constructors by result type *) + let sub_unions = compute_gadt_sub_unions cases in + (* Register sub-unions in state for type reference transformation *) + GadtSubUnions.add type_name + (List.map (fun su -> (su.gsu_key, su.gsu_constructors)) sub_unions); + (* Transform payload types to use sub-unions *) + let transformed_cases = + List.map + (fun (case : gadt_case) -> + { + case with + gc_payload = + transform_gadt_payload ~gadt_name:type_name ~sub_unions + case.gc_payload; + }) + cases + in + Some + (GadtType + { + name = type_name; + type_params = type_params_with_constraints; + cases = transformed_cases; + sub_unions; + constraints; + config; + })) + else + (* Regular variant type *) + let cases = + List.map + (fun (cd : Types.constructor_declaration) -> + let name = Ident.name cd.cd_id in + (* Use @as name for the tag if present, otherwise use the constructor name *) + let tag = + match + Ast_untagged_variants.process_tag_type cd.cd_attributes + with + | Some (Ast_untagged_variants.String s) -> TagString s + | Some (Ast_untagged_variants.Int i) -> TagInt i + | Some Ast_untagged_variants.Null -> TagNull + | Some Ast_untagged_variants.Undefined -> TagUndefined + | Some (Ast_untagged_variants.Bool b) -> TagBool b + | _ -> ( + (* Fall back to @as or constructor name *) + match get_as_string cd.cd_attributes with + | Some renamed -> TagString renamed + | None -> TagString name) + in + let payload = + match cd.cd_args with + | Cstr_tuple [] -> NoPayload + | Cstr_tuple [arg] -> TuplePayload [ts_type_of_type_expr arg] + | Cstr_tuple args -> + TuplePayload (List.map ts_type_of_type_expr args) + | Cstr_record labels -> + (* Inline record - flatten fields into the variant object *) + let properties = + List.map + (fun (ld : Types.label_declaration) -> + let field_name = + match get_as_string ld.ld_attributes with + | Some renamed -> renamed + | None -> Ident.name ld.ld_id + in + { + prop_name = field_name; + prop_type = ts_type_of_type_expr ld.ld_type; + prop_optional = ld.ld_optional; + prop_readonly = ld.ld_mutable = Asttypes.Immutable; + }) + labels + in + InlineRecord properties + in + {vc_name = name; vc_tag = tag; vc_payload = payload}) + constructors + in + Some (VariantType {name = type_name; type_params; cases; config})) + | Types.Type_abstract -> ( + let external_type_info = get_external_type decl.type_attributes in + let is_opaque_attr = has_opaque_attr decl.type_attributes in + match decl.type_manifest with + | Some ty when is_opaque_attr -> + (* @opaque type t = string - branded opaque type with underlying type *) + let body = ts_type_of_type_expr ty in + Some (OpaqueType {name = type_name; type_params; underlying = Some body}) + | Some ty -> + let external_type = + match external_type_info with + | Some + {ext_type_name; ext_module_path; ext_use_external; ext_import_kind} + -> + let etc_name = + match ext_import_kind with + | ExtDefault | ExtNamespace -> "$" ^ type_name + | ExtNamed _ -> ext_type_name + in + Some + { + etc_name; + etc_module = ext_module_path; + etc_use_external = ext_use_external; + etc_import_kind = ext_import_kind; + } + | None -> None + in + let body = ts_type_of_type_expr ty in + let is_opaque = has_phantom_params type_params body in + Some + (TypeAlias + {name = type_name; type_params; body; external_type; is_opaque}) + | None -> ( + (* Abstract type without manifest *) + match external_type_info with + | Some {ext_type_name; ext_module_path; ext_import_kind; _} -> + let external_name = + match ext_import_kind with + | ExtDefault | ExtNamespace -> "$" ^ type_name + | ExtNamed _ -> ext_type_name + in + Some + (ExternalType + { + name = type_name; + type_params; + external_name; + external_module = ext_module_path; + external_import_kind = ext_import_kind; + }) + | None -> + Some (OpaqueType {name = type_name; type_params; underlying = None}))) + | Types.Type_open -> None (* Open types not supported *) + +(** Register a type in LocalTypeQualifier with its stamp and qualified path. + Uses @as renamed name if available. + @param id The type's ident + @param decl The type declaration (to check for @as) + @param prefix The module prefix (e.g., "Outer.Nested" or "") *) +let register_local_type ~(prefix : string) (id : Ident.t) + (decl : Types.type_declaration) : unit = + let name = + match get_as_string decl.type_attributes with + | Some renamed -> renamed + | None -> Ident.name id + in + let stamp = Ident.binding_time id in + let qualified = if prefix = "" then name else prefix ^ "." ^ name in + LocalTypeQualifier.add ~stamp ~name ~qualified + +(** Extract all type declarations from a Typedtree structure. + Uses interface_sig (from .resi file) if available to determine what to export, + ensuring that private items are not included in .d.ts output. + Falls back to str_type if no interface signature is provided. + Also populates LocalTypeQualifier for stamp-based type lookup. *) +let rec extract_type_decls ~(interface_sig : Types.signature) + (str : Typedtree.structure) : type_decl list = + (* Reset LocalTypeQualifier at the start of extraction *) + LocalTypeQualifier.reset (); + (* Reset module aliases *) + ModuleAliases.reset (); + (* Extract module aliases from structure items. + This handles patterns like "module C = Belt_internalBucketsType" *) + List.iter + (fun (str_item : Typedtree.structure_item) -> + match str_item.str_desc with + | Typedtree.Tstr_module mb -> ( + match mb.mb_expr.mod_desc with + | Typedtree.Tmod_ident (path, _) -> + (* This is a module alias: module X = SomeOtherModule *) + ModuleAliases.add (Ident.name mb.mb_id) path + | _ -> ()) + | _ -> ()) + str.str_items; + let decls = ref [] in + (* Use interface_sig (from .resi/.cmi) if available, otherwise fall back to str_type. + This ensures we only export what's in the interface. *) + let sig_to_use = interface_sig in + List.iter + (fun (sig_item : Types.signature_item) -> + match sig_item with + | Types.Sig_type (id, decl, _) -> ( + register_local_type ~prefix:"" id decl; + match type_decl_of_type_declaration id decl with + | Some type_decl -> decls := type_decl :: !decls + | None -> ()) + | Types.Sig_module (id, md, _) -> ( + match extract_module_decl_from_sig ~prefix:"" id md with + | Some mod_decl -> decls := ModuleDecl mod_decl :: !decls + | None -> ()) + | _ -> ()) + sig_to_use; + List.rev !decls + +(** Extract a module declaration from a signature module declaration *) +and extract_module_decl_from_sig ~(prefix : string) (id : Ident.t) + (md : Types.module_declaration) : module_decl option = + let name = Ident.name id in + let module_prefix = if prefix = "" then name else prefix ^ "." ^ name in + match md.md_type with + | Types.Mty_signature sig_items -> + let types = ref [] in + let values = ref [] in + let submodules = ref [] in + List.iter + (fun (sig_item : Types.signature_item) -> + match sig_item with + | Types.Sig_type (id, decl, _) -> ( + register_local_type ~prefix:module_prefix id decl; + match type_decl_of_type_declaration id decl with + | Some td -> types := td :: !types + | None -> ()) + | Types.Sig_value (id, vd) -> ( + (* Skip externals (Val_prim) as they don't generate JS code *) + match vd.val_kind with + | Types.Val_prim _ -> () + | Types.Val_reg -> + values := + { + mv_name = Ident.name id; + mv_type = ts_type_of_type_expr vd.val_type; + } + :: !values) + | Types.Sig_module (id, md, _) -> ( + match extract_module_decl_from_sig ~prefix:module_prefix id md with + | Some sub -> submodules := sub :: !submodules + | None -> ()) + | _ -> ()) + sig_items; + Some + { + mod_name = name; + mod_types = List.rev !types; + mod_values = List.rev !values; + mod_submodules = List.rev !submodules; + } + | _ -> None + +type value_export = { + ve_name: string; + ve_type: Types.type_expr; + ve_params: string list; + ve_alias: string option; + (** If this is an alias like `let x = y`, stores "y" *) +} +(** Value export with its type for .d.ts generation *) + +(** Collect runtime types from value exports. + This processes all exported value types to ensure runtime type imports + are generated for types like dict, list, option etc. used in variable declarations. *) +let collect_runtime_types_from_value_exports (exports : value_export list) : + unit = + List.iter + (fun ve -> + (* Convert to ts_type and collect runtime type dependencies *) + let ts_ty = ts_type_of_type_expr ve.ve_type in + collect_type_deps ts_ty) + exports + +(** Extract parameter names from a function expression *) +let rec extract_param_names (expr : Typedtree.expression) : string list = + match expr.exp_desc with + | Typedtree.Texp_function {param; case; _} -> + Ident.name param :: extract_param_names case.c_rhs + | _ -> [] + +(** Extract alias target if expression is just an identifier *) +let extract_alias_target (expr : Typedtree.expression) : string option = + match expr.exp_desc with + | Typedtree.Texp_ident (path, _, _) -> Some (Path.last path) + | _ -> None + +(** Extract the identifier from a pattern, handling Tpat_var and Tpat_alias. + Note: Tpat_constraint is in pat_extra, not pat_desc, so we just need to handle + the core patterns. *) +let extract_pat_ident (pat : Typedtree.pattern) : Ident.t option = + match pat.pat_desc with + | Typedtree.Tpat_var (id, _) -> Some id + | Typedtree.Tpat_alias (_, id, _) -> Some id + | _ -> None + +(** Extract constraint type from pattern's pat_extra if present. + Returns the annotated type from Tpat_constraint, or falls back to pat_type. *) +let extract_constraint_type (pat : Typedtree.pattern) : Types.type_expr = + let rec find_constraint = function + | [] -> pat.pat_type + | (Typedtree.Tpat_constraint cty, _, _) :: _ -> cty.ctyp_type + | _ :: rest -> find_constraint rest + in + find_constraint pat.pat_extra + +(** Extract all value exports from a Typedtree structure. + Uses interface_sig (from .resi file) if available to filter what to export, + ensuring that private items are not included in .d.ts output. + Falls back to str_type if no interface signature is provided. *) +let extract_value_exports ~(interface_sig : Types.signature) + (str : Typedtree.structure) : value_export list = + (* Build a map of value names to their types from the public signature. + Use interface_sig to get the correct types as declared in the interface. *) + let sig_to_use = interface_sig in + let public_values = + List.fold_left + (fun acc (sig_item : Types.signature_item) -> + match sig_item with + | Types.Sig_value (id, vd) -> + Map_string.add acc (Ident.name id) vd.val_type + | _ -> acc) + Map_string.empty sig_to_use + in + let exports = ref [] in + List.iter + (fun (item : Typedtree.structure_item) -> + match item.str_desc with + | Typedtree.Tstr_value (_, bindings) -> + List.iter + (fun (vb : Typedtree.value_binding) -> + match extract_pat_ident vb.vb_pat with + | Some id -> ( + let name = Ident.name id in + (* Only export if the value is in the public signature *) + match Map_string.find_opt public_values name with + | Some interface_type -> + let params = extract_param_names vb.vb_expr in + let alias = extract_alias_target vb.vb_expr in + (* Use type from interface signature, not implementation. + This ensures types match what's declared in .resi files. *) + exports := + { + ve_name = name; + ve_type = interface_type; + ve_params = params; + ve_alias = alias; + } + :: !exports + | None -> ()) + | None -> ()) + bindings + | Typedtree.Tstr_primitive _ -> + (* Externals don't generate JS code, so skip them in .d.ts *) + () + | _ -> ()) + str.str_items; + List.rev !exports + +(** {1 Exported Value Type Tracking} *) + +(** Set exported value types from value_export list *) +let set_exported_types (exports : value_export list) : unit = + ExportedTypes.reset (); + List.iter (fun ve -> ExportedTypes.add ve.ve_name ve.ve_type) exports + +(** Recursively register all modules with their qualified paths *) +let rec register_module_with_prefix prefix (mod_decl : module_decl) : unit = + let qualified_path = + if prefix = "" then mod_decl.mod_name else prefix ^ "." ^ mod_decl.mod_name + in + ExportedModules.add mod_decl.mod_name qualified_path; + (* Register all submodules with updated prefix *) + List.iter (register_module_with_prefix qualified_path) mod_decl.mod_submodules + +(** Register module exports from type declarations *) +let set_exported_modules (decls : type_decl list) : unit = + ExportedModules.reset (); + List.iter + (fun decl -> + match decl with + | ModuleDecl mod_decl -> register_module_with_prefix "" mod_decl + | _ -> ()) + decls + +(** Get the type for an exported value by name *) +let get_exported_type (name : string) : Types.type_expr option = + ExportedTypes.find name + +(** Get the qualified type path for a module name, if it's an exported module *) +let get_module_type_path (name : string) : string option = + ExportedModules.get_type_path name + +(** Check if a Types.type_expr represents an opaque type that needs 'as' assertion. + This checks if the type is: + 1. A pure abstract type (type t) + 2. A type alias with phantom parameters (type t<'a> = string) + We check if the type name is registered in OpaqueTypes. *) +let rec type_needs_as_assertion (ty : Types.type_expr) : bool = + match ty.desc with + | Types.Tconstr (path, _args, _) -> + (* Check if this type constructor is registered as opaque *) + let type_name = Path.last path in + OpaqueTypes.has_any () && OpaqueTypes.is_opaque type_name + | Types.Tlink ty | Types.Tsubst ty -> type_needs_as_assertion ty + | _ -> false + +(** {1 Type Printing} *) + +module P = Ext_pp + +(** TypeScript/JavaScript reserved words that cannot be used as identifiers. + These need to be escaped when used as parameter names in .d.ts files. *) +let ts_reserved_words = + [ + (* Keywords *) + "break"; + "case"; + "catch"; + "class"; + "const"; + "continue"; + "debugger"; + "default"; + "delete"; + "do"; + "else"; + "enum"; + "export"; + "extends"; + "false"; + "finally"; + "for"; + "function"; + "if"; + "import"; + "in"; + "instanceof"; + "new"; + "null"; + "return"; + "super"; + "switch"; + "this"; + "throw"; + "true"; + "try"; + "typeof"; + "var"; + "void"; + "while"; + "with"; + (* Strict mode reserved words *) + "implements"; + "interface"; + "let"; + "package"; + "private"; + "protected"; + "public"; + "static"; + "yield"; + (* TypeScript keywords *) + "any"; + "boolean"; + "number"; + "string"; + "symbol"; + "abstract"; + "as"; + "async"; + "await"; + "declare"; + "from"; + "get"; + "is"; + "module"; + "namespace"; + "never"; + "readonly"; + "require"; + "set"; + "type"; + "undefined"; + "unique"; + "unknown"; + ] + +(** Check if a name is a TypeScript reserved word *) +let is_ts_reserved_word name = + Js_reserved_map.is_js_keyword name + || Js_reserved_map.is_js_special_word name + || Js_reserved_map.is_ts_keyword name + +(** Escape a name if it's a TypeScript reserved word by adding underscore suffix *) +let escape_ts_reserved name = + if is_ts_reserved_word name then name ^ "_" else name + +(** Check if a property name needs to be quoted in TypeScript. + Property names need quotes if they contain characters other than + alphanumerics, underscore, or dollar sign, or if they start with a digit. *) +let needs_property_quotes name = + let len = String.length name in + if len = 0 then true + else + let first = name.[0] in + (* Must start with letter, underscore, or dollar *) + let valid_start = + (first >= 'a' && first <= 'z') + || (first >= 'A' && first <= 'Z') + || first = '_' || first = '$' + in + if not valid_start then true + else + try + for i = 1 to len - 1 do + let c = name.[i] in + let valid = + (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || c = '_' || c = '$' + in + if not valid then raise_notrace Exit + done; + false + with Exit -> true + +(** Print a property name, quoting if necessary *) +let pp_property_name (f : P.t) (name : string) : unit = + if needs_property_quotes name then ( + P.string f "\""; + P.string f name; + P.string f "\"") + else P.string f name + +(** Threshold for multi-line function formatting *) +let function_line_width_threshold = 80 + +(** Estimate the length of a ts_type when printed *) +let rec estimate_ts_type_length (ty : ts_type) : int = + match ty with + | Any -> 3 + | Unknown -> 7 + | Never -> 5 + | Void -> 4 + | Null -> 4 + | Undefined -> 9 + | Boolean -> 7 + | Number -> 6 + | Bigint -> 6 + | String -> 6 + | Symbol -> 6 + | Array elem -> estimate_ts_type_length elem + 2 (* [] *) + | Tuple types -> + List.fold_left ( + ) 2 + (List.map (fun t -> estimate_ts_type_length t + 2) types) + | Object {properties; _} -> + List.fold_left ( + ) 4 + (List.map + (fun p -> + String.length p.prop_name + estimate_ts_type_length p.prop_type + 4) + properties) + | Function {fn_params; fn_return; _} -> + let params_len = + List.fold_left ( + ) 0 + (List.map (fun p -> estimate_ts_type_length p.param_type + 4) fn_params) + in + params_len + estimate_ts_type_length fn_return + 6 (* () => *) + | Union types | Intersection types -> + List.fold_left ( + ) 0 + (List.map (fun t -> estimate_ts_type_length t + 3) types) + | TypeRef {name; args} -> + String.length name + + List.fold_left ( + ) 0 + (List.map (fun t -> estimate_ts_type_length t + 2) args) + | TypeVar name -> String.length name + | Literal (LitString s) -> String.length s + 2 + | Literal (LitNumber n) -> String.length (string_of_float n) + | Literal (LitBigint s) -> String.length s + 1 + | Literal (LitBoolean _) -> 5 + | Readonly ty -> estimate_ts_type_length ty + 9 + | Promise ty -> estimate_ts_type_length ty + 8 + | RuntimeType {rt_name; rt_args} -> + String.length rt_name + 5 + + List.fold_left ( + ) 0 + (List.map (fun t -> estimate_ts_type_length t + 2) rt_args) + +(** Estimate the length of a param_type when printed *) +let estimate_param_length (p : param_type) ~(use_undefined_union : bool) : int = + let name_len = + match p.param_name with + | Some n -> String.length n + | None -> 4 + in + let optional_len = + if p.param_optional then + if use_undefined_union then 12 (* " | undefined" *) else 1 (* "?" *) + else 0 + in + name_len + 2 + estimate_ts_type_length p.param_type + optional_len (* ": " *) + +(** Estimate the length of a fn_type when printed as a type expression *) +let estimate_fn_type_length (fn : fn_type) : int = + let use_undefined_union = + let rec check seen_optional = function + | [] -> false + | p :: rest -> + if seen_optional && not p.param_optional then true + else check (seen_optional || p.param_optional) rest + in + check false fn.fn_params + in + let type_params_len = + if fn.fn_type_params = [] then 0 + else + List.fold_left ( + ) 2 + (List.map (fun p -> String.length p.tp_name + 2) fn.fn_type_params) + in + let params_len = + List.fold_left ( + ) 0 + (List.mapi + (fun i p -> + estimate_param_length p ~use_undefined_union + if i > 0 then 2 else 0) + fn.fn_params) + in + let rest_len = + match fn.fn_rest with + | Some r -> 5 + estimate_ts_type_length r.param_type (* "...: " + type *) + | None -> 0 + in + type_params_len + 2 + params_len + rest_len + 5 + + estimate_ts_type_length fn.fn_return +(* "()" + " => " + return type *) + +(** Print a TypeScript type to the pretty printer *) +let rec pp_ts_type (f : P.t) (ty : ts_type) : unit = + match ty with + | Any -> P.string f "any" + | Unknown -> P.string f "unknown" + | Never -> P.string f "never" + | Void -> P.string f "void" + | Null -> P.string f "null" + | Undefined -> P.string f "undefined" + | Boolean -> P.string f "boolean" + | Number -> P.string f "number" + | Bigint -> P.string f "bigint" + | String -> P.string f "string" + | Symbol -> P.string f "symbol" + | Array elem -> + pp_ts_type f elem; + P.string f "[]" + | Tuple types -> + P.string f "["; + pp_ts_type_list f types; + P.string f "]" + | Object obj -> pp_object_type f obj + | Function fn -> pp_fn_type f fn + | Union types -> pp_union f types + | Intersection types -> pp_intersection f types + | TypeRef {name; args} -> + P.string f name; + if args <> [] then ( + P.string f "<"; + pp_ts_type_list f args; + P.string f ">") + | TypeVar name -> P.string f (String.capitalize_ascii name) + | Literal lit -> pp_literal f lit + | Readonly ty -> + P.string f "Readonly<"; + pp_ts_type f ty; + P.string f ">" + | Promise ty -> + P.string f "Promise<"; + pp_ts_type f ty; + P.string f ">" + | RuntimeType {rt_name; rt_args} -> + P.string f runtime_types_namespace; + P.string f "."; + P.string f rt_name; + if rt_args <> [] then ( + P.string f "<"; + pp_ts_type_list f rt_args; + P.string f ">") + +and pp_ts_type_list (f : P.t) (types : ts_type list) : unit = + match types with + | [] -> () + | [ty] -> pp_ts_type f ty + | ty :: rest -> + pp_ts_type f ty; + P.string f ", "; + pp_ts_type_list f rest + +(** Print a type in union context, parenthesizing function types *) +and pp_ts_type_in_union (f : P.t) (ty : ts_type) : unit = + match ty with + | Function _ -> + (* Function types must be parenthesized in union types *) + P.string f "("; + pp_ts_type f ty; + P.string f ")" + | _ -> pp_ts_type f ty + +and pp_union (f : P.t) (types : ts_type list) : unit = + match types with + | [] -> P.string f "never" + | [ty] -> pp_ts_type f ty + | ty :: rest -> + pp_ts_type_in_union f ty; + P.string f " | "; + pp_union f rest + +and pp_intersection (f : P.t) (types : ts_type list) : unit = + match types with + | [] -> P.string f "unknown" + | [ty] -> pp_ts_type f ty + | ty :: rest -> + pp_ts_type f ty; + P.string f " & "; + pp_intersection f rest + +and pp_literal (f : P.t) (lit : literal_type) : unit = + match lit with + | LitString s -> + P.string f "\""; + P.string f s; + P.string f "\"" + | LitNumber n -> P.string f (Printf.sprintf "%g" n) + | LitBigint s -> + P.string f s; + P.string f "n" + | LitBoolean b -> P.string f (if b then "true" else "false") + +and pp_object_type (f : P.t) (obj : object_type) : unit = + let has_index = obj.index_sig <> None in + let prop_count = List.length obj.properties in + let use_multiline = prop_count > 1 || has_index in + if use_multiline then ( + P.string f "{"; + P.group f 1 (fun () -> + List.iter + (fun prop -> + P.newline f; + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type f prop.prop_type; + P.string f ";") + obj.properties; + match obj.index_sig with + | Some {index_key; index_value} -> + P.newline f; + P.string f "[key: "; + pp_ts_type f index_key; + P.string f "]: "; + pp_ts_type f index_value; + P.string f ";" + | None -> ()); + P.newline f; + P.string f "}") + else ( + P.string f "{ "; + List.iter + (fun prop -> + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type f prop.prop_type; + P.string f "; ") + obj.properties; + (match obj.index_sig with + | Some {index_key; index_value} -> + P.string f "[key: "; + pp_ts_type f index_key; + P.string f "]: "; + pp_ts_type f index_value; + P.string f "; " + | None -> ()); + P.string f "}") + +and pp_fn_type (f : P.t) (fn : fn_type) : unit = + (* Don't use multiline formatting for function types - they can appear nested + inside other types (e.g., as parameter types) where multiline would break + indentation. Multiline formatting is handled at the declaration level + via pp_fn_type_toplevel. *) + if fn.fn_type_params <> [] then ( + P.string f "<"; + pp_type_params f fn.fn_type_params; + P.string f ">"); + P.string f "("; + pp_params f fn.fn_params ~use_multiline:false; + (match fn.fn_rest with + | Some rest -> + if fn.fn_params <> [] then P.string f ", "; + P.string f "..."; + (match rest.param_name with + | Some n -> P.string f n + | None -> P.string f "args"); + P.string f ": "; + pp_ts_type f rest.param_type + | None -> ()); + P.string f ") => "; + pp_ts_type f fn.fn_return + +(** Print a function type at the top level (e.g., type alias body) with + multiline formatting support when the line would be too long. *) +and pp_fn_type_toplevel (f : P.t) (fn : fn_type) : unit = + let use_multiline = + estimate_fn_type_length fn > function_line_width_threshold + in + if fn.fn_type_params <> [] then ( + P.string f "<"; + pp_type_params f fn.fn_type_params; + P.string f ">"); + P.string f "("; + pp_params f fn.fn_params ~use_multiline; + (match fn.fn_rest with + | Some rest -> + if fn.fn_params <> [] then + if use_multiline then P.string f "," else P.string f ", "; + if use_multiline then ( + P.newline f; + P.string f " "); + P.string f "..."; + (match rest.param_name with + | Some n -> P.string f n + | None -> P.string f "args"); + P.string f ": "; + pp_ts_type f rest.param_type + | None -> ()); + if use_multiline then P.newline f; + P.string f ") => "; + pp_ts_type f fn.fn_return + +(** Check if there are required params after optional ones in a param list *) +and has_required_after_optional_params (params : param_type list) : bool = + let rec check seen_optional = function + | [] -> false + | p :: rest -> + if seen_optional && not p.param_optional then true + else check (seen_optional || p.param_optional) rest + in + check false params + +and pp_params (f : P.t) (params : param_type list) ~(use_multiline : bool) : + unit = + let unnamed_counter = ref 0 in + let use_undefined_union = has_required_after_optional_params params in + let rec loop first = function + | [] -> () + | [p] -> + if use_multiline then ( + P.newline f; + P.string f " ") + else if not first then P.string f ", "; + pp_param f p ~unnamed_counter ~use_undefined_union; + if use_multiline then P.string f "," + | p :: rest -> + if use_multiline then ( + P.newline f; + P.string f " ") + else if not first then P.string f ", "; + pp_param f p ~unnamed_counter ~use_undefined_union; + if use_multiline then P.string f ","; + loop false rest + in + loop true params + +and pp_param (f : P.t) (p : param_type) ~(unnamed_counter : int ref) + ~(use_undefined_union : bool) : unit = + (match p.param_name with + | Some name -> P.string f name + | None -> + (* Use arg0, arg1, etc. for unnamed parameters to avoid duplicate identifiers *) + P.string f "arg"; + P.string f (string_of_int !unnamed_counter); + incr unnamed_counter); + (* Use ? syntax only if no required params follow optional ones *) + if p.param_optional && not use_undefined_union then P.string f "?"; + P.string f ": "; + pp_ts_type f p.param_type; + (* Add | undefined for optional params when we can't use ? syntax *) + if p.param_optional && use_undefined_union then P.string f " | undefined" + +and pp_type_params (f : P.t) (params : type_param list) : unit = + match params with + | [] -> () + | [p] -> pp_type_param f p + | p :: rest -> + pp_type_param f p; + P.string f ", "; + pp_type_params f rest + +and pp_type_param (f : P.t) (p : type_param) : unit = + P.string f p.tp_name; + (match p.tp_constraint with + | Some c -> + P.string f " extends "; + pp_ts_type f c + | None -> ()); + match p.tp_default with + | Some d -> + P.string f " = "; + pp_ts_type f d + | None -> () + +(** Print type parameters for GADT union types with proper formatting. + When constraints exist, formats with newlines for readability. *) +and pp_gadt_type_params (f : P.t) ~(indent : string) (params : type_param list) + : unit = + match params with + | [] -> () + | _ -> + let has_constraints = + List.exists (fun p -> p.tp_constraint <> None) params + in + if has_constraints then ( + (* Multi-line format for complex constraints *) + P.string f "<"; + P.newline f; + let rec print_params = function + | [] -> () + | [p] -> + P.string f indent; + P.string f " "; + pp_type_param f p; + P.newline f + | p :: rest -> + P.string f indent; + P.string f " "; + pp_type_param f p; + P.string f ","; + P.newline f; + print_params rest + in + print_params params; + P.string f indent; + P.string f ">") + else ( + (* Simple inline format *) + P.string f "<"; + pp_type_params f params; + P.string f ">") + +(* Initialize the forward reference for pp_ts_type *) +let () = pp_ts_type_ref := pp_ts_type + +(** Print type annotation (: Type) if type is present *) +let pp_type_annotation (f : P.t) (ty : ts_type option) : unit = + match ty with + | None -> () + | Some t -> + P.string f ": "; + pp_ts_type f t + +(** Print type annotation from Types.type_expr *) +let pp_type_annotation_from_ml (f : P.t) (ty : Types.type_expr option) : unit = + pp_type_annotation f (Option.map ts_type_of_type_expr ty) + +(** Check if a type needs an 'as Type' assertion for opaque types. *) +let needs_as_assertion (ty : Types.type_expr option) : bool = + match ty with + | Some t -> type_needs_as_assertion t + | None -> false + +(** Print 'as Type' assertion if the type needs it (for opaque types). + This is needed in combined .ts output where the value's runtime type + differs from its declared opaque type. *) +let pp_as_assertion (f : P.t) (ty : Types.type_expr option) : unit = + match ty with + | Some t when type_needs_as_assertion t -> + P.string f " as "; + pp_ts_type f (ts_type_of_type_expr t) + | _ -> () + +(** Find the branded opaque type for a return type, if any. + For option/nullable wrappers, extracts the inner type since ReScript + unboxes option (Some(x) becomes just x at runtime). *) +let find_branded_return_type (return_type : Types.type_expr option) : + ts_type option = + match return_type with + | None -> None + | Some ty -> + if not (OpaqueTypes.has_any ()) then None + else + let ts_ty = ts_type_of_type_expr ty in + let rec find_branded_inner t = + match t with + | TypeRef {name; _} when OpaqueTypes.is_branded name -> Some t + | RuntimeType {rt_name = "option"; rt_args = [inner]} + | RuntimeType {rt_name = "nullable"; rt_args = [inner]} + | RuntimeType {rt_name = "null_"; rt_args = [inner]} -> + find_branded_inner inner + | _ -> None + in + find_branded_inner ts_ty + +(** Check if return type needs an 'as Type' assertion for opaque types. *) +let needs_opaque_return_assertion (return_type : Types.type_expr option) : bool + = + find_branded_return_type return_type <> None + +(** Print 'as Type' assertion for return statements if the return type + is a branded opaque type (from @opaque attribute). + This allows the underlying type to be returned while satisfying + the opaque type constraint. + + For option/nullable wrappers, we extract the inner type since ReScript + unboxes option (Some(x) becomes just x at runtime). *) +let pp_opaque_return_assertion (f : P.t) (return_type : Types.type_expr option) + : unit = + match find_branded_return_type return_type with + | Some inner_ty -> + P.string f " as "; + pp_ts_type f inner_ty + | None -> () + +(** Print generic type parameters if any type variables exist. + Also includes constraints from GADT types. *) +let pp_type_params_from_ml (f : P.t) (fn_type : Types.type_expr option) : unit = + let type_params = collect_type_vars_with_constraints fn_type in + match type_params with + | [] -> () + | _ -> + P.string f "<"; + pp_type_params f type_params; + P.string f ">" + +(** {1 GADT Function Overloads} + + For functions that take GADT types as parameters and return the GADT's type parameter, + we generate TypeScript function overloads. This allows TypeScript to narrow the return + type based on the specific GADT constructor passed. + + For example, for: + let eval: type a. expr => a + + We generate: + function eval(expr: expr$int): number; + function eval(expr: expr$bool): boolean; + function eval(expr: expr): number | boolean { ... } +*) + +type gadt_param_info = { + gadt_name: string; + param_index: int; + sub_unions: (string * string list) list; +} +(** Information about a GADT parameter in a function type. + @field gadt_name The name of the GADT type (e.g., "expr") + @field param_index The index of this parameter in the function + @field sub_unions List of (key, constructor names) pairs for this GADT *) + +(** Detect GADT parameters in a function type. + Returns information about each parameter that is a GADT type. + Only detects GADTs where the return type uses the GADT's type parameter. *) +let detect_gadt_params (fn_type : Types.type_expr option) : gadt_param_info list + = + match fn_type with + | None -> [] + | Some ty -> + let params = ref [] in + let param_index = ref 0 in + let return_type_var = ref None in + (* First pass: find the return type variable *) + let rec find_return_var ty = + match ty.Types.desc with + | Types.Tarrow (_, return_type, _, _) -> find_return_var return_type + | Types.Tlink ty | Types.Tsubst ty | Types.Tpoly (ty, _) -> + find_return_var ty + | Types.Tvar (Some name) | Types.Tunivar (Some name) -> + return_type_var := Some (String.capitalize_ascii name) + | Types.Tvar None | Types.Tunivar None -> ( + match Hashtbl.find_opt anon_type_var_names ty.Types.id with + | Some name -> return_type_var := Some name + | None -> ()) + | _ -> () + in + find_return_var ty; + (* Second pass: find GADT parameters *) + let rec collect ty = + match ty.Types.desc with + | Types.Tarrow ({typ = arg_type; _}, return_type, _, _) -> + (* Check if this argument is a GADT *) + (match arg_type.Types.desc with + | Types.Tconstr (path, args, _) -> ( + let type_name = Path.last path in + let escaped_name = escape_ts_type_name type_name in + match GadtSubUnions.get escaped_name with + | Some sub_unions when List.length sub_unions > 0 -> + (* This is a GADT with sub-unions *) + (* Check if the type argument matches the return type variable *) + let matches_return = + match (args, !return_type_var) with + | [arg], Some ret_var -> ( + match arg.Types.desc with + | Types.Tvar (Some name) | Types.Tunivar (Some name) -> + String.capitalize_ascii name = ret_var + | Types.Tvar None | Types.Tunivar None -> ( + match Hashtbl.find_opt anon_type_var_names arg.Types.id with + | Some name -> name = ret_var + | None -> false) + | Types.Tlink t | Types.Tsubst t -> ( + match t.Types.desc with + | Types.Tvar (Some name) | Types.Tunivar (Some name) -> + String.capitalize_ascii name = ret_var + | _ -> false) + | _ -> false) + | _ -> false + in + if matches_return then + params := + { + gadt_name = escaped_name; + param_index = !param_index; + sub_unions; + } + :: !params + | _ -> ()) + | Types.Tlink t | Types.Tsubst t -> ( + match t.Types.desc with + | Types.Tconstr (path, args, _) -> ( + let type_name = Path.last path in + let escaped_name = escape_ts_type_name type_name in + match GadtSubUnions.get escaped_name with + | Some sub_unions when List.length sub_unions > 0 -> + let matches_return = + match (args, !return_type_var) with + | [arg], Some ret_var -> ( + match arg.Types.desc with + | Types.Tvar (Some name) | Types.Tunivar (Some name) -> + String.capitalize_ascii name = ret_var + | Types.Tvar None | Types.Tunivar None -> ( + match Hashtbl.find_opt anon_type_var_names arg.Types.id with + | Some name -> name = ret_var + | None -> false) + | Types.Tlink t | Types.Tsubst t -> ( + match t.Types.desc with + | Types.Tvar (Some name) | Types.Tunivar (Some name) -> + String.capitalize_ascii name = ret_var + | _ -> false) + | _ -> false) + | _ -> false + in + if matches_return then + params := + { + gadt_name = escaped_name; + param_index = !param_index; + sub_unions; + } + :: !params + | _ -> ()) + | _ -> ()) + | _ -> ()); + incr param_index; + collect return_type + | Types.Tlink ty | Types.Tsubst ty | Types.Tpoly (ty, _) -> collect ty + | _ -> () + in + collect ty; + List.rev !params + +(** Get the constraint type for a GADT sub-union key. + @param gadt_name The GADT type name + @param key The sub-union key (e.g., "int", "bool") + @return The constraint type (e.g., Number for "int", Boolean for "bool") *) +let get_constraint_for_key (gadt_name : string) (key : string) : ts_type option + = + match GadtConstraints.get gadt_name with + | Some constraints -> ( + (* The constraint is a union of all possible return types. + For a specific key, we need to map key -> type: + "int" -> Number, "bool" -> Boolean, etc. *) + match key with + | "int" | "float" -> Some Number + | "bool" -> Some Boolean + | "string" -> Some String + | "bigint" -> Some Bigint + | _ -> + (* For other keys, try to find a matching type in constraints *) + let rec find_matching constraints = + match constraints with + | [] -> None + | Some (TypeRef {name; args = []}) :: _ + when String.lowercase_ascii name = key -> + Some (TypeRef {name; args = []}) + | _ :: rest -> find_matching rest + in + find_matching constraints) + | None -> None + +(** Check if a function needs GADT overloads. + Returns true if the function has GADT parameters that would benefit from overloads. *) +let needs_gadt_overloads (fn_type : Types.type_expr option) : bool = + match detect_gadt_params fn_type with + | [] -> false + | _ -> true + +(** Print a single overload signature for a GADT function. + @param f The printer + @param name The function name + @param param_names The parameter names + @param fn_type The function type + @param gadt_param The GADT parameter info + @param sub_union_key The sub-union key for this overload (e.g., "int") *) +let pp_gadt_overload_signature (f : P.t) (name : string) + (param_names : string list) (fn_type : Types.type_expr option) + (gadt_param : gadt_param_info) (sub_union_key : string) : unit = + (* Get the constraint type for this sub-union key *) + let return_type = get_constraint_for_key gadt_param.gadt_name sub_union_key in + match return_type with + | None -> () (* Skip if we can't determine the return type *) + | Some ret_ty -> + P.string f "function "; + P.string f name; + (* Name is already escaped by caller *) + P.string f "("; + (* Print parameters, substituting the GADT parameter with sub-union type *) + (match fn_type with + | None -> () + | Some ty -> + let param_names_ref = ref param_names in + let param_idx = ref 0 in + let first = ref true in + let rec print_params ty = + match ty.Types.desc with + | Types.Tarrow ({lbl; typ = arg_type}, return_type, _, _) -> + (* Skip unit parameters *) + if not (lbl = Nolabel && is_unit_type arg_type) then ( + if not !first then P.string f ", "; + first := false; + let pname = + match !param_names_ref with + | n :: rest -> + param_names_ref := rest; + if n = "_" then "arg" ^ string_of_int !param_idx + else escape_ts_reserved n + | [] -> "arg" ^ string_of_int !param_idx + in + P.string f pname; + P.string f ": "; + (* Use sub-union type if this is the GADT parameter *) + if !param_idx = gadt_param.param_index then ( + P.string f gadt_param.gadt_name; + P.string f "$"; + P.string f sub_union_key) + else pp_ts_type f (ts_type_of_type_expr arg_type)); + incr param_idx; + print_params return_type + | Types.Tlink ty | Types.Tsubst ty | Types.Tpoly (ty, _) -> + print_params ty + | _ -> () + in + print_params ty); + P.string f "): "; + pp_ts_type f ret_ty; + P.string f ";"; + P.newline f + +(** Print all GADT overload signatures for a function. + Should be called before printing the function implementation. + @param f The printer + @param name The function name + @param param_names The parameter names + @param fn_type The function type *) +let pp_gadt_overloads (f : P.t) (name : string) (param_names : string list) + (fn_type : Types.type_expr option) : unit = + let gadt_params = detect_gadt_params fn_type in + match gadt_params with + | [] -> () + | gadt_param :: _ -> + (* For now, only handle the first GADT parameter *) + (* Print an overload for each sub-union *) + List.iter + (fun (key, _constructors) -> + pp_gadt_overload_signature f name param_names fn_type gadt_param key) + gadt_param.sub_unions + +(** {1 Type Declaration Printing} *) + +(** Forward declaration for pp_tag_kind - will be defined after this function. + This is needed because pp_variant_case uses pp_tag_kind but is defined before it. *) +let pp_tag_kind_fwd : (P.t -> tag_kind -> unit) ref = ref (fun _ _ -> ()) + +(** Print a variant case for tagged unions. + @param tag_name The tag field name (default Js_dump_lit.tag, can be customized with @tag) + @param case The variant case to print *) + +let pp_variant_case (f : P.t) ~(tag_name : string) (case : variant_case) : unit + = + match case.vc_payload with + | NoPayload -> + (* Nullary constructor - just the tag literal (string, null, undefined, etc.) *) + !pp_tag_kind_fwd f case.vc_tag + | TuplePayload types -> + (* Tuple payload: { readonly TAG: "Name"; readonly _0: T0; ... } *) + (* Use multiline when there's more than 1 payload field *) + let use_multiline = List.length types > 1 in + if use_multiline then ( + P.string f "{"; + P.group f 1 (fun () -> + P.newline f; + P.string f "readonly "; + P.string f tag_name; + P.string f ": "; + !pp_tag_kind_fwd f case.vc_tag; + P.string f ";"; + List.iteri + (fun i ty -> + P.newline f; + P.string f "readonly _"; + P.string f (string_of_int i); + P.string f ": "; + pp_ts_type f ty; + P.string f ";") + types); + P.newline f; + P.string f "}") + else ( + P.string f "{ readonly "; + P.string f tag_name; + P.string f ": "; + !pp_tag_kind_fwd f case.vc_tag; + List.iteri + (fun i ty -> + P.string f "; readonly _"; + P.string f (string_of_int i); + P.string f ": "; + pp_ts_type f ty) + types; + P.string f " }") + | InlineRecord props -> + (* Inline record: { readonly TAG: "Name"; field1: T1; ... } *) + (* Use multiline when there's more than 1 field *) + let use_multiline = List.length props > 1 in + if use_multiline then ( + P.string f "{"; + P.group f 1 (fun () -> + P.newline f; + P.string f "readonly "; + P.string f tag_name; + P.string f ": "; + !pp_tag_kind_fwd f case.vc_tag; + P.string f ";"; + List.iter + (fun prop -> + P.newline f; + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type f prop.prop_type; + P.string f ";") + props); + P.newline f; + P.string f "}") + else ( + P.string f "{ readonly "; + P.string f tag_name; + P.string f ": "; + !pp_tag_kind_fwd f case.vc_tag; + List.iter + (fun prop -> + P.string f "; "; + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type f prop.prop_type) + props; + P.string f " }") + +(** Print a tag_kind value for TypeScript *) +let pp_tag_kind (f : P.t) (tag : tag_kind) : unit = + match tag with + | TagString s -> + P.string f "\""; + P.string f s; + P.string f "\"" + | TagNull -> P.string f "null" + | TagUndefined -> P.string f "undefined" + | TagInt i -> P.string f (string_of_int i) + | TagBool b -> P.string f (if b then "true" else "false") + +(* Initialize forward reference for pp_variant_case *) +let () = pp_tag_kind_fwd := pp_tag_kind + +(** Get the string representation of a tag_kind for use in object literals *) +let tag_kind_to_string (tag : tag_kind) : string = + match tag with + | TagString s -> "\"" ^ s ^ "\"" + | TagNull -> "null" + | TagUndefined -> "undefined" + | TagInt i -> string_of_int i + | TagBool b -> if b then "true" else "false" + +(** Print a variant case for @unboxed variants. + Just prints the payload type directly. + Uses pp_ts_type_in_union since unboxed variants are printed as union members. *) +let pp_unboxed_variant_case (f : P.t) (case : variant_case) : unit = + match case.vc_payload with + | NoPayload -> + (* Nullary constructor - just the tag literal *) + pp_tag_kind f case.vc_tag + | TuplePayload [single_type] -> + (* Single payload - just the type directly, parenthesizing if needed *) + pp_ts_type_in_union f single_type + | TuplePayload types -> + (* Multiple payloads - shouldn't happen for valid @unboxed, but handle gracefully *) + pp_ts_type f (Tuple types) + | InlineRecord props -> + (* Inline record - as object type *) + pp_object_type f {properties = props; index_sig = None; call_sig = None} + +(** Print a union type with each member on its own line (for type aliases). + Expects to be called within a P.group context that handles indentation. *) +let rec pp_union_multiline (f : P.t) (types : ts_type list) : unit = + match types with + | [] -> P.string f "never" + | [ty] -> + P.newline f; + P.string f "| "; + pp_ts_type_in_union f ty + | ty :: rest -> + P.newline f; + P.string f "| "; + pp_ts_type_in_union f ty; + pp_union_multiline f rest + +(** Helper to print the type body with optional external type wrapping *) +let pp_type_body_with_external (f : P.t) (type_params : type_param list) + (body : ts_type) (external_type : external_type_constraint option) : unit = + match external_type with + | Some {etc_name; etc_use_external; _} -> + (* Wrap with external + Format with newlines for readability: + rescript.external< + ExternalType, + { ... }, + true + > + *) + P.string f runtime_types_namespace; + P.string f ".external<"; + P.newline f; + P.string f " "; + P.string f etc_name; + if type_params <> [] then ( + P.string f "<"; + let param_names = + List.map (fun (tp : type_param) -> tp.tp_name) type_params + in + P.string f (String.concat ", " param_names); + P.string f ">"); + P.string f ","; + P.newline f; + P.string f " "; + pp_ts_type f body; + if etc_use_external then ( + P.string f ","; + P.newline f; + P.string f " true"); + P.newline f; + P.string f ">" + | None -> pp_ts_type f body + +(** Get type names defined in a module (for qualification) *) +let get_module_type_names (mod_decl : module_decl) : StringSet.t = + List.fold_left + (fun acc decl -> + match decl with + | TypeAlias {name; _} + | Interface {name; _} + | VariantType {name; _} + | GadtType {name; _} + | OpaqueType {name; _} + | ExternalType {name; _} -> + StringSet.add name acc + | ModuleDecl _ -> acc) + StringSet.empty mod_decl.mod_types + +(** Print a TypeScript type with module path qualification for local types. + @param module_path The current module namespace path (e.g., "Inner" or "Outer.Nested") + @param local_types Set of type names defined in the current module that need qualification *) +let rec pp_ts_type_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (ty : ts_type) : unit = + match ty with + | TypeRef {name; args} -> + (* If this is an unqualified type name that's defined locally, add the module path prefix *) + let qualified_name = + if (not (String.contains name '.')) && StringSet.mem name local_types then + module_path ^ "." ^ name + else name + in + P.string f qualified_name; + if args <> [] then ( + P.string f "<"; + pp_ts_type_list_qualified f ~module_path ~local_types args; + P.string f ">") + | Array elem -> + pp_ts_type_qualified f ~module_path ~local_types elem; + P.string f "[]" + | Tuple types -> + P.string f "["; + pp_ts_type_list_qualified f ~module_path ~local_types types; + P.string f "]" + | Object obj -> pp_object_type_qualified f ~module_path ~local_types obj + | Function fn -> pp_fn_type_qualified f ~module_path ~local_types fn + | Union types -> pp_union_qualified f ~module_path ~local_types types + | Intersection types -> + pp_intersection_qualified f ~module_path ~local_types types + | Readonly ty -> + P.string f "Readonly<"; + pp_ts_type_qualified f ~module_path ~local_types ty; + P.string f ">" + | Promise ty -> + P.string f "Promise<"; + pp_ts_type_qualified f ~module_path ~local_types ty; + P.string f ">" + | RuntimeType {rt_name; rt_args} -> + P.string f runtime_types_namespace; + P.string f "."; + P.string f rt_name; + if rt_args <> [] then ( + P.string f "<"; + pp_ts_type_list_qualified f ~module_path ~local_types rt_args; + P.string f ">") + (* Non-recursive types don't need special handling *) + | Any -> P.string f "any" + | Unknown -> P.string f "unknown" + | Never -> P.string f "never" + | Void -> P.string f "void" + | Null -> P.string f "null" + | Undefined -> P.string f "undefined" + | Boolean -> P.string f "boolean" + | Number -> P.string f "number" + | Bigint -> P.string f "bigint" + | String -> P.string f "string" + | Symbol -> P.string f "symbol" + | TypeVar name -> P.string f (String.capitalize_ascii name) + | Literal lit -> pp_literal f lit + +and pp_ts_type_list_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (types : ts_type list) : unit = + match types with + | [] -> () + | [ty] -> pp_ts_type_qualified f ~module_path ~local_types ty + | ty :: rest -> + pp_ts_type_qualified f ~module_path ~local_types ty; + P.string f ", "; + pp_ts_type_list_qualified f ~module_path ~local_types rest + +and pp_ts_type_in_union_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (ty : ts_type) : unit = + match ty with + | Function _ -> + P.string f "("; + pp_ts_type_qualified f ~module_path ~local_types ty; + P.string f ")" + | _ -> pp_ts_type_qualified f ~module_path ~local_types ty + +and pp_union_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (types : ts_type list) : unit = + match types with + | [] -> P.string f "never" + | [ty] -> pp_ts_type_qualified f ~module_path ~local_types ty + | ty :: rest -> + pp_ts_type_in_union_qualified f ~module_path ~local_types ty; + P.string f " | "; + pp_union_qualified f ~module_path ~local_types rest + +and pp_intersection_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (types : ts_type list) : unit = + match types with + | [] -> P.string f "unknown" + | [ty] -> pp_ts_type_qualified f ~module_path ~local_types ty + | ty :: rest -> + pp_ts_type_qualified f ~module_path ~local_types ty; + P.string f " & "; + pp_intersection_qualified f ~module_path ~local_types rest + +and pp_object_type_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (obj : object_type) : unit = + let has_index = obj.index_sig <> None in + let prop_count = List.length obj.properties in + let use_multiline = prop_count > 1 || has_index in + if use_multiline then ( + P.string f "{"; + List.iter + (fun prop -> + P.newline f; + P.string f " "; + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type_qualified f ~module_path ~local_types prop.prop_type; + P.string f ";") + obj.properties; + (match obj.index_sig with + | Some {index_key; index_value} -> + P.newline f; + P.string f " [key: "; + pp_ts_type_qualified f ~module_path ~local_types index_key; + P.string f "]: "; + pp_ts_type_qualified f ~module_path ~local_types index_value; + P.string f ";" + | None -> ()); + P.newline f; + P.string f " }") + else ( + P.string f "{ "; + List.iter + (fun prop -> + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type_qualified f ~module_path ~local_types prop.prop_type; + P.string f "; ") + obj.properties; + (match obj.index_sig with + | Some {index_key; index_value} -> + P.string f "[key: "; + pp_ts_type_qualified f ~module_path ~local_types index_key; + P.string f "]: "; + pp_ts_type_qualified f ~module_path ~local_types index_value; + P.string f "; " + | None -> ()); + P.string f "}") + +and pp_fn_type_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (fn : fn_type) : unit = + (* Don't use multiline formatting for function types - they can appear nested + inside other types (e.g., as parameter types) where multiline would break + indentation. Multiline formatting is handled at the declaration level. *) + if fn.fn_type_params <> [] then ( + P.string f "<"; + pp_type_params f fn.fn_type_params; + P.string f ">"); + P.string f "("; + pp_params_qualified f ~module_path ~local_types fn.fn_params + ~use_multiline:false; + (match fn.fn_rest with + | Some rest -> + if fn.fn_params <> [] then P.string f ", "; + P.string f "..."; + (match rest.param_name with + | Some n -> P.string f n + | None -> P.string f "args"); + P.string f ": "; + pp_ts_type_qualified f ~module_path ~local_types rest.param_type + | None -> ()); + P.string f ") => "; + pp_ts_type_qualified f ~module_path ~local_types fn.fn_return + +and pp_params_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (params : param_type list) + ~(use_multiline : bool) : unit = + let unnamed_counter = ref 0 in + let use_undefined_union = has_required_after_optional_params params in + let rec loop first = function + | [] -> () + | [p] -> + if use_multiline then ( + P.newline f; + P.string f " ") + else if not first then P.string f ", "; + pp_param_qualified f ~module_path ~local_types p ~unnamed_counter + ~use_undefined_union; + if use_multiline then P.string f "," + | p :: rest -> + if use_multiline then ( + P.newline f; + P.string f " ") + else if not first then P.string f ", "; + pp_param_qualified f ~module_path ~local_types p ~unnamed_counter + ~use_undefined_union; + if use_multiline then P.string f ","; + loop false rest + in + loop true params + +and pp_param_qualified (f : P.t) ~(module_path : string) + ~(local_types : StringSet.t) (p : param_type) ~(unnamed_counter : int ref) + ~(use_undefined_union : bool) : unit = + (match p.param_name with + | Some name -> P.string f name + | None -> + P.string f "arg"; + P.string f (string_of_int !unnamed_counter); + incr unnamed_counter); + (* Use ? syntax only if no required params follow optional ones *) + if p.param_optional && not use_undefined_union then P.string f "?"; + P.string f ": "; + pp_ts_type_qualified f ~module_path ~local_types p.param_type; + (* Add | undefined for optional params when we can't use ? syntax *) + if p.param_optional && use_undefined_union then P.string f " | undefined" + +(** Forward reference for module printing (to break mutual recursion) *) +let pp_module_decl_ref : (P.t -> module_decl -> unit) ref = ref (fun _ _ -> ()) + +(** Forward reference for module printing in combined .ts mode (no export const) *) +let pp_module_decl_ts_ref : (P.t -> module_decl -> unit) ref = + ref (fun _ _ -> ()) + +(** Print a type declaration *) +let pp_type_decl (f : P.t) (decl : type_decl) : unit = + match decl with + | TypeAlias {name; type_params; body; external_type; is_opaque} -> + P.string f "export type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + (if is_opaque then ( + P.string f " "; + (* Opaque type: wrap with $res.opaque<"brand", params, body> *) + let brand_name = + match OpaqueTypes.get_full_name name with + | Some full_name -> full_name + | None -> name + in + pp_opaque_type f ~brand_name ~type_params ~underlying:(Some body)) + else + match (body, external_type) with + | Union types, None -> + (* Print union types with newlines for readability *) + P.group f 1 (fun () -> pp_union_multiline f types) + | Function fn, None -> + (* Print function types with multiline support at top level *) + P.string f " "; + pp_fn_type_toplevel f fn + | _ -> + P.string f " "; + pp_type_body_with_external f type_params body external_type); + P.string f ";" + | Interface {name; type_params; extends; body} -> + P.string f "export interface "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + (match extends with + | [] -> () + | _ -> + P.string f " extends "; + let rec print_extends = function + | [] -> () + | [{name; args}] -> + P.string f name; + if args <> [] then ( + P.string f "<"; + pp_ts_type_list f args; + P.string f ">") + | {name; args} :: rest -> + P.string f name; + if args <> [] then ( + P.string f "<"; + pp_ts_type_list f args; + P.string f ">"); + P.string f ", "; + print_extends rest + in + print_extends extends); + P.string f " {"; + P.group f 1 (fun () -> + List.iter + (fun prop -> + P.newline f; + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type f prop.prop_type; + P.string f ";") + body.properties; + match body.index_sig with + | Some {index_key; index_value} -> + P.newline f; + P.string f "[key: "; + pp_ts_type f index_key; + P.string f "]: "; + pp_ts_type f index_value; + P.string f ";" + | None -> ()); + P.newline f; + P.string f "}" + | VariantType {name; type_params; cases; config} -> + P.string f "export type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + P.group f 1 (fun () -> + List.iter + (fun case -> + P.newline f; + P.string f "| "; + if config.vc_unboxed then pp_unboxed_variant_case f case + else pp_variant_case f ~tag_name:config.vc_tag_name case) + cases); + P.string f ";" + | GadtType {name; type_params; cases; sub_unions; config} -> + (* GADT generates: + 1. Phantom-constrained sub-unions (internal, not exported) + 2. Separate type for each constructor (internal, not exported) + 3. Main union type (exported with type params for constraint) + + For: type expr<_> = IntLit(int): expr | Add(...): expr | BoolLit(bool): expr + Generates: + type expr$int = expr$IntLit | expr$Add; + type expr$bool = expr$BoolLit; + type expr$IntLit = { TAG: "IntLit"; _0: number }; + type expr$Add = { TAG: "Add"; _0: expr$int; _1: expr$int }; + type expr$BoolLit = { TAG: "BoolLit"; _0: boolean }; + export type expr<_ extends number | boolean> = expr$IntLit | expr$Add | expr$BoolLit; *) + + (* First, generate phantom-constrained sub-unions (not exported) *) + List.iter + (fun (sub : gadt_sub_union) -> + P.string f "type "; + P.string f name; + P.string f "$"; + P.string f sub.gsu_key; + P.string f " = "; + (match sub.gsu_constructors with + | [] -> P.string f "never" + | first :: rest -> + P.string f name; + P.string f "$"; + P.string f first; + List.iter + (fun ctor -> + P.string f " | "; + P.string f name; + P.string f "$"; + P.string f ctor) + rest); + P.string f ";"; + P.newline f) + sub_unions; + if sub_unions <> [] then P.newline f; + + (* Second, generate a type for each GADT constructor (not exported) *) + List.iter + (fun (case : gadt_case) -> + P.string f "type "; + P.string f name; + P.string f "$"; + P.string f case.gc_name; + P.string f " = "; + if config.vc_unboxed then + pp_unboxed_variant_case f + { + vc_name = case.gc_name; + vc_tag = case.gc_tag; + vc_payload = case.gc_payload; + } + else + pp_variant_case f ~tag_name:config.vc_tag_name + { + vc_name = case.gc_name; + vc_tag = case.gc_tag; + vc_payload = case.gc_payload; + }; + P.string f ";"; + P.newline f) + cases; + + (* Finally, generate the main union type (exported with type params) *) + P.newline f; + P.string f "export type "; + P.string f name; + (match type_params with + | [] -> () + | _ -> + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + P.group f 1 (fun () -> + List.iter + (fun (case : gadt_case) -> + P.newline f; + P.string f "| "; + P.string f name; + P.string f "$"; + P.string f case.gc_name) + cases); + P.string f ";" + | OpaqueType {name; type_params; underlying} -> + (* For .ts files, generate: export type t = $res.opaque<"Brand", underlying> *) + P.string f "export type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " = "; + (* Use full brand name from OpaqueTypes if available *) + let brand_name = + match OpaqueTypes.get_full_name name with + | Some full_name -> full_name + | None -> name + in + pp_opaque_type f ~brand_name ~type_params ~underlying; + P.string f ";" + | ExternalType {name; type_params; external_name; external_module = _} -> + (* Abstract external type: export type t = Set; *) + (* For abstract types, just alias to the external type directly *) + P.string f "export type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " = "; + P.string f external_name; + if type_params <> [] then ( + P.string f "<"; + let param_names = + List.map (fun (tp : type_param) -> tp.tp_name) type_params + in + P.string f (String.concat ", " param_names); + P.string f ">"); + P.string f ";" + | ModuleDecl mod_decl -> !pp_module_decl_ref f mod_decl + +(** Print a type declaration for combined .ts files. + Same as pp_type_decl but doesn't emit 'export const' for modules + since the implementation will provide that. *) +let pp_type_decl_ts (f : P.t) (decl : type_decl) : unit = + match decl with + | ModuleDecl mod_decl -> !pp_module_decl_ts_ref f mod_decl + | _ -> pp_type_decl f decl + +(** Print type declarations for combined .ts output (no const for modules) *) +let pp_type_decls_ts (f : P.t) (decls : type_decl list) : unit = + List.iter + (fun decl -> + pp_type_decl_ts f decl; + P.at_least_two_lines f) + decls + +(** Print runtime type import based on collected types *) +let pp_runtime_type_import (f : P.t) : unit = + if RuntimeTypes.has_any () then ( + P.at_least_two_lines f; + P.string f "import type * as "; + P.string f runtime_types_namespace; + P.string f " from \"@rescript/runtime/types\";"; + P.newline f) + +(** Get the list of modules that need type-only imports. + @param value_imported_modules Set of module names already imported for values + @param local_modules Set of locally defined module names (should not be imported) + @return List of module names that need type-only imports *) +let get_type_only_modules ~(value_imported_modules : StringSet.t) + ~(local_modules : StringSet.t) : string list = + let required_modules = TypeModuleDeps.get_used () in + (* Filter out modules that are: + 1. Already imported for values + 2. Locally defined in this file *) + List.filter + (fun m -> + (not (StringSet.mem m value_imported_modules)) + && not (StringSet.mem m local_modules)) + required_modules + +(** Print type declarations only (without collecting runtime types). + Uses pp_type_decl_ts which doesn't emit const for modules. *) +let pp_type_decls_only (f : P.t) (decls : type_decl list) : unit = + List.iter + (fun decl -> + pp_type_decl_ts f decl; + P.at_least_two_lines f) + decls + +(** Collect opaque types from type declarations for $res.opaque brand generation. + Recursively processes module declarations to find nested opaque types. + For branded opaque types (@opaque), also registers the underlying type. + @param prefix Optional module path prefix *) +let rec collect_opaque_types_with_prefix ~(prefix : string option) + (decls : type_decl list) : unit = + List.iter + (fun decl -> + match decl with + | OpaqueType {name; type_params; underlying} -> ( + let full_name = + match prefix with + | Some p -> p ^ "." ^ name + | None -> name + in + match underlying with + | Some ty -> + (* Branded opaque type from @opaque - register with underlying type *) + OpaqueTypes.add_branded full_name (List.length type_params) ty + | None -> + (* Pure abstract type *) + OpaqueTypes.add full_name (List.length type_params)) + | TypeAlias {name; type_params; is_opaque = true; _} -> + let full_name = + match prefix with + | Some p -> p ^ "." ^ name + | None -> name + in + OpaqueTypes.add full_name (List.length type_params) + | ModuleDecl {mod_name; mod_types; mod_submodules; _} -> + (* Recursively collect from module types and submodules with updated prefix *) + let new_prefix = + match prefix with + | Some p -> Some (p ^ "." ^ mod_name) + | None -> Some mod_name + in + collect_opaque_types_with_prefix ~prefix:new_prefix mod_types; + List.iter + (fun sub -> + collect_opaque_types_with_prefix ~prefix:new_prefix [ModuleDecl sub]) + mod_submodules + | _ -> ()) + decls + +(** Collect opaque types from type declarations for $res.opaque brand generation. + @param module_name The file module name (e.g., "Modules") to prefix all brands *) +let collect_opaque_types ~(module_name : string) (decls : type_decl list) : unit + = + collect_opaque_types_with_prefix ~prefix:(Some module_name) decls + +(** Collect GADT sub-unions from type declarations. + This re-registers GADT sub-unions after reset_state() is called. *) +let rec collect_gadt_sub_unions (decls : type_decl list) : unit = + List.iter + (fun decl -> + match decl with + | GadtType {name; sub_unions; _} -> + GadtSubUnions.add name + (List.map (fun su -> (su.gsu_key, su.gsu_constructors)) sub_unions) + | ModuleDecl {mod_types; mod_submodules; _} -> + collect_gadt_sub_unions mod_types; + List.iter + (fun sub -> collect_gadt_sub_unions [ModuleDecl sub]) + mod_submodules + | _ -> ()) + decls + +(** Initialize state and collect type information without printing. + Call this before printing runtime import and type declarations separately. + Preserves the environment that was set before. *) +let init_type_decls ~(module_name : string) (decls : type_decl list) : unit = + let saved_env = State.state.env in + reset_state (); + State.state.env <- saved_env; + set_module_name module_name; + List.iter collect_runtime_types_decl decls; + collect_opaque_types ~module_name decls; + collect_gadt_sub_unions decls + +(** Print all type declarations with runtime type imports. + @param module_name The module name for opaque type brand prefixing *) +let pp_type_decls ~(module_name : string) (f : P.t) (decls : type_decl list) : + unit = + init_type_decls ~module_name decls; + (* Print import and declarations *) + pp_runtime_type_import f; + pp_type_decls_only f decls + +(** {1 Declaration File (.d.ts) Generation} *) + +(** Check if a type is a function type *) +let is_function_type (ty : Types.type_expr) : bool = + let rec check ty = + match ty.Types.desc with + | Types.Tarrow _ -> true + | Types.Tlink ty | Types.Tsubst ty | Types.Tpoly (ty, _) -> check ty + | _ -> false + in + check ty + +(** Check if there are any required (non-optional) parameters following + any optional parameter in the function type. If so, we cannot use + TypeScript's optional parameter syntax (?) and must use `| undefined` instead. *) +let has_required_after_optional (ty : Types.type_expr option) : bool = + match ty with + | None -> false + | Some ty -> + let rec check seen_optional ty = + match ty.Types.desc with + | Types.Tarrow ({lbl; typ = arg_type}, return_type, _, _) -> + (* Skip unit parameters *) + if lbl = Nolabel && is_unit_type arg_type then + check seen_optional return_type + else + let is_optional = + match lbl with + | Asttypes.Optional _ -> true + | _ -> false + in + if seen_optional && not is_optional then true + else check (seen_optional || is_optional) return_type + | Types.Tlink ty | Types.Tsubst ty | Types.Tpoly (ty, _) -> + check seen_optional ty + | _ -> false + in + check false ty + +(** Estimate the total length of a function declaration *) +let estimate_function_decl_length (name : string) (param_names : string list) + (fn_type : Types.type_expr option) : int = + let base_len = 16 + String.length name + 4 in + (* "export function " + name + "(): " *) + match fn_type with + | None -> base_len + | Some ty -> + (* Check if we need to use | undefined for optional params *) + let use_undefined_union = has_required_after_optional (Some ty) in + let param_names_ref = ref param_names in + let unnamed_counter = ref 0 in + let get_next_param_name () = + match !param_names_ref with + | pname :: rest -> + param_names_ref := rest; + if pname = "_" then ( + let n = !unnamed_counter in + incr unnamed_counter; + "arg" ^ string_of_int n) + else pname + | [] -> + let n = !unnamed_counter in + incr unnamed_counter; + "arg" ^ string_of_int n + in + let rec count_params_length ty = + match ty.Types.desc with + | Types.Tarrow ({lbl; typ = arg_type}, return_type, _, _) -> + if lbl = Nolabel && is_unit_type arg_type then ( + ignore (get_next_param_name ()); + count_params_length return_type) + else + let param_name = + match lbl with + | Asttypes.Nolabel -> get_next_param_name () + | Asttypes.Labelled {txt} | Asttypes.Optional {txt} -> + ignore (get_next_param_name ()); + txt + in + let is_optional = + match lbl with + | Asttypes.Optional _ -> true + | _ -> false + in + let actual_type = + match lbl with + | Asttypes.Optional _ -> ( + match remove_option_wrapper lbl arg_type with + | Some inner -> inner + | None -> arg_type) + | _ -> arg_type + in + (* Account for | undefined suffix when needed *) + let optional_suffix_len = + if is_optional && use_undefined_union then 12 (* " | undefined" *) + else 0 + in + String.length param_name + 2 + + estimate_ts_type_length (ts_type_of_type_expr actual_type) + + optional_suffix_len + 2 (* ", " *) + + count_params_length return_type + | Types.Tlink ty | Types.Tsubst ty -> count_params_length ty + | _ -> 0 + in + let params_len = count_params_length ty in + let return_len = + match return_type_of_fn_type (Some ty) with + | Some ret_ty -> estimate_ts_type_length ret_ty + | None -> 0 + in + base_len + params_len + return_len + +(** Print a function declaration for .d.ts + @param use_export if true, prints "export function", otherwise "declare function" *) +let pp_dts_function_decl ?(use_export = true) (f : P.t) (name : string) + (param_names : string list) (fn_type : Types.type_expr option) : unit = + let use_multiline = + estimate_function_decl_length name param_names fn_type + > function_line_width_threshold + in + (* If there are required params after optional ones, we cannot use TS optional syntax *) + let use_undefined_union = has_required_after_optional fn_type in + P.string f (if use_export then "export function " else "declare function "); + (* Don't escape function name - it must match the JavaScript export name exactly *) + P.string f name; + (* Print type parameters *) + pp_type_params_from_ml f fn_type; + (* Print parameters *) + P.string f "("; + (match fn_type with + | None -> () + | Some ty -> + let param_names_ref = ref param_names in + let unnamed_counter = ref 0 in + let get_next_param_name () = + match !param_names_ref with + | pname :: rest -> + param_names_ref := rest; + (* If name is "_", generate a unique arg name *) + if pname = "_" then ( + let n = !unnamed_counter in + incr unnamed_counter; + "arg" ^ string_of_int n) + else escape_ts_reserved pname + | [] -> + let n = !unnamed_counter in + incr unnamed_counter; + "arg" ^ string_of_int n + in + let rec print_params first ty = + match ty.Types.desc with + | Types.Tarrow ({lbl; typ = arg_type}, return_type, _, _) -> + (* Skip unit parameters *) + if lbl = Nolabel && is_unit_type arg_type then ( + ignore (get_next_param_name ()); + print_params first return_type) + else ( + if use_multiline then ( + P.newline f; + P.string f " ") + else if not first then P.string f ", "; + let is_optional = + match lbl with + | Asttypes.Optional _ -> true + | _ -> false + in + (match lbl with + | Asttypes.Nolabel -> P.string f (get_next_param_name ()) + | Asttypes.Labelled {txt} | Asttypes.Optional {txt} -> + ignore (get_next_param_name ()); + P.string f (escape_ts_reserved txt)); + (* Use ? syntax only if we can (no required params after optional) + and this param is optional *) + if is_optional && not use_undefined_union then P.string f "?"; + P.string f ": "; + (* For optional params, unwrap option to just T *) + let actual_type = + match lbl with + | Asttypes.Optional _ -> ( + match remove_option_wrapper lbl arg_type with + | Some inner -> inner + | None -> arg_type) + | _ -> arg_type + in + pp_ts_type f (ts_type_of_type_expr actual_type); + (* Add | undefined for optional params when we can't use ? syntax *) + if is_optional && use_undefined_union then P.string f " | undefined"; + if use_multiline then P.string f ","; + print_params false return_type) + | Types.Tlink ty | Types.Tsubst ty | Types.Tpoly (ty, _) -> + print_params first ty + | _ -> () + in + print_params true ty); + if use_multiline then P.newline f; + P.string f ")"; + (* Print return type *) + (match return_type_of_fn_type fn_type with + | Some ret_ty -> + P.string f ": "; + pp_ts_type f ret_ty + | None -> ()); + P.string f ";" + +(** Simplify types with free type variables for const declarations. + TypeScript doesn't support polymorphic constants, so we need to + replace option (where A is a free type variable) with undefined. *) +let rec simplify_const_type (ty : ts_type) : ts_type = + match ty with + | RuntimeType {rt_name = "option"; rt_args = [TypeVar _]} -> + (* option with free type var -> undefined (e.g., Js.undefined<'a>) *) + Undefined + | RuntimeType {rt_name; rt_args} -> + RuntimeType {rt_name; rt_args = List.map simplify_const_type rt_args} + | Array elem -> Array (simplify_const_type elem) + | Tuple elems -> Tuple (List.map simplify_const_type elems) + | Union types -> Union (List.map simplify_const_type types) + | Intersection types -> Intersection (List.map simplify_const_type types) + | TypeRef {name; args} -> + TypeRef {name; args = List.map simplify_const_type args} + | Readonly ty -> Readonly (simplify_const_type ty) + | Promise ty -> Promise (simplify_const_type ty) + | _ -> ty + +(** Print a value declaration for .d.ts + @param use_export if true, prints "export const", otherwise "declare const" *) +let pp_dts_value_decl ?(use_export = true) (f : P.t) (name : string) + (ty : ts_type) : unit = + P.string f (if use_export then "export const " else "declare const "); + (* Don't escape value name - it must match the JavaScript export name exactly *) + P.string f name; + P.string f ": "; + (* Simplify types with free type variables since TypeScript can't express them *) + pp_ts_type f (simplify_const_type ty); + P.string f ";" + +(** Print a single value export as either function or const declaration *) +let pp_dts_value_export (f : P.t) (ve : value_export) : unit = + let name = ve.ve_name in + (* Special handling for "default" - it's the ES module default export. *) + if name = "default" then + match ve.ve_alias with + | Some target -> + (* Simple case: let default = someFunction, just re-export *) + P.string f "export default "; + P.string f target; + P.string f ";" + | None -> + (* Complex case: need to declare and export *) + if is_function_type ve.ve_type then ( + pp_dts_function_decl ~use_export:false f "$$default" ve.ve_params + (Some ve.ve_type); + P.newline f; + P.string f "export default $$default;") + else ( + pp_dts_value_decl ~use_export:false f "$$default" + (ts_type_of_type_expr ve.ve_type); + P.newline f; + P.string f "export default $$default;") + else + (* Use Ext_ident.convert to match JS export name (e.g., catch -> $$catch) *) + let export_name = Ext_ident.convert name in + if is_function_type ve.ve_type then + pp_dts_function_decl f export_name ve.ve_params (Some ve.ve_type) + else pp_dts_value_decl f export_name (ts_type_of_type_expr ve.ve_type) + +(** Print a type declaration for .d.ts *) +let rec pp_dts_type_decl (f : P.t) (decl : type_decl) : unit = + match decl with + | TypeAlias {name; type_params; body; external_type; is_opaque} -> + P.string f "export type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + (if is_opaque then ( + P.string f " "; + (* Opaque type: wrap with $res.opaque<"brand", params, body> *) + let brand_name = + match OpaqueTypes.get_full_name name with + | Some full_name -> full_name + | None -> name + in + pp_opaque_type f ~brand_name ~type_params ~underlying:(Some body)) + else + match (body, external_type) with + | Union types, None -> + (* Print union types with newlines for readability *) + P.group f 1 (fun () -> pp_union_multiline f types) + | Function fn, None -> + (* Print function types with multiline support at top level *) + P.string f " "; + pp_fn_type_toplevel f fn + | _ -> + P.string f " "; + pp_type_body_with_external f type_params body external_type); + P.string f ";" + | Interface {name; type_params; extends; body} -> + P.string f "export interface "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + (match extends with + | [] -> () + | _ -> + P.string f " extends "; + let rec print_extends = function + | [] -> () + | [{name; args}] -> + P.string f name; + if args <> [] then ( + P.string f "<"; + pp_ts_type_list f args; + P.string f ">") + | {name; args} :: rest -> + P.string f name; + if args <> [] then ( + P.string f "<"; + pp_ts_type_list f args; + P.string f ">"); + P.string f ", "; + print_extends rest + in + print_extends extends); + P.string f " {"; + P.group f 1 (fun () -> + List.iter + (fun prop -> + P.newline f; + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type f prop.prop_type; + P.string f ";") + body.properties; + match body.index_sig with + | Some {index_key; index_value} -> + P.newline f; + P.string f "[key: "; + pp_ts_type f index_key; + P.string f "]: "; + pp_ts_type f index_value; + P.string f ";" + | None -> ()); + P.newline f; + P.string f "}" + | VariantType {name; type_params; cases; config} -> + P.string f "export type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + P.group f 1 (fun () -> + List.iter + (fun case -> + P.newline f; + P.string f "| "; + if config.vc_unboxed then pp_unboxed_variant_case f case + else pp_variant_case f ~tag_name:config.vc_tag_name case) + cases); + P.string f ";" + | GadtType {name; type_params; cases; sub_unions; config} -> + (* GADT: generate sub-unions, constructor types, then main union. + Sub-unions and constructor types are NOT exported. *) + + (* First, generate phantom-constrained sub-unions (not exported) *) + List.iter + (fun (sub : gadt_sub_union) -> + P.string f "type "; + P.string f name; + P.string f "$"; + P.string f sub.gsu_key; + P.string f " = "; + (match sub.gsu_constructors with + | [] -> P.string f "never" + | first :: rest -> + P.string f name; + P.string f "$"; + P.string f first; + List.iter + (fun ctor -> + P.string f " | "; + P.string f name; + P.string f "$"; + P.string f ctor) + rest); + P.string f ";"; + P.newline f) + sub_unions; + if sub_unions <> [] then P.newline f; + + (* Second, generate constructor types (not exported) *) + List.iter + (fun (case : gadt_case) -> + P.string f "type "; + P.string f name; + P.string f "$"; + P.string f case.gc_name; + P.string f " = "; + if config.vc_unboxed then + pp_unboxed_variant_case f + { + vc_name = case.gc_name; + vc_tag = case.gc_tag; + vc_payload = case.gc_payload; + } + else + pp_variant_case f ~tag_name:config.vc_tag_name + { + vc_name = case.gc_name; + vc_tag = case.gc_tag; + vc_payload = case.gc_payload; + }; + P.string f ";"; + P.newline f) + cases; + + (* Finally, generate the main union type (exported with type params) *) + P.newline f; + P.string f "export type "; + P.string f name; + (match type_params with + | [] -> () + | _ -> + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + P.group f 1 (fun () -> + List.iter + (fun (case : gadt_case) -> + P.newline f; + P.string f "| "; + P.string f name; + P.string f "$"; + P.string f case.gc_name) + cases); + P.string f ";" + | OpaqueType {name; type_params; underlying} -> + (* Generate: export type name = $res.opaque<"name", params, underlying> *) + P.string f "export type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " = "; + let brand_name = + match OpaqueTypes.get_full_name name with + | Some full_name -> full_name + | None -> name + in + pp_opaque_type f ~brand_name ~type_params ~underlying; + P.string f ";" + | ExternalType {name; type_params; external_name; external_import_kind; _} -> + (* Abstract external type: export type t = Set; *) + (* For abstract types, just alias to the external type directly *) + P.string f "export type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " = "; + (* Default and namespace imports need typeof since they import values/modules *) + (match external_import_kind with + | ExtDefault | ExtNamespace -> P.string f "typeof " + | ExtNamed _ -> ()); + P.string f external_name; + if type_params <> [] then ( + P.string f "<"; + let param_names = + List.map (fun (tp : type_param) -> tp.tp_name) type_params + in + P.string f (String.concat ", " param_names); + P.string f ">"); + P.string f ";" + | ModuleDecl mod_decl -> pp_module_decl f mod_decl + +(** Print a module declaration as namespace + type + const. + Takes an optional parent_path for nested module qualification. + @param emit_const If true, emit 'export const' for the module value. + Set to false for combined .ts output where implementation provides this. *) +and pp_module_decl_with_path (f : P.t) ~(parent_path : string option) + ~(emit_const : bool) (mod_decl : module_decl) : unit = + let {mod_name; mod_types; mod_values; mod_submodules} = mod_decl in + (* Compute the full module path for type qualification *) + let module_path = + match parent_path with + | Some parent -> parent ^ "." ^ mod_name + | None -> + (* Use file module name as prefix for top-level modules *) + let file_module = get_module_name () in + if file_module = "" then mod_name else file_module ^ "." ^ mod_name + in + (* Collect type names defined in this module for qualification *) + let local_types = get_module_type_names mod_decl in + (* Also include submodule names as they can be referenced as types *) + let local_types_with_submodules = + List.fold_left + (fun acc sub -> StringSet.add sub.mod_name acc) + local_types mod_submodules + in + (* Print namespace with types *) + let has_namespace_content = mod_types <> [] || mod_submodules <> [] in + if has_namespace_content then ( + P.string f "declare namespace "; + P.string f mod_name; + P.string f " {"; + (* Print types in namespace *) + List.iter + (fun decl -> + P.newline f; + P.string f " "; + pp_namespace_type_decl_with_path f ~module_path ~emit_const decl) + mod_types; + (* Print nested submodules *) + List.iter + (fun sub -> + P.newline f; + pp_nested_module_decl_with_path f sub ~indent:2 ~parent_path:module_path + ~emit_const) + mod_submodules; + P.newline f; + P.string f "}"; + P.newline f); + (* Print module type (interface for the module value) *) + P.string f "export type "; + P.string f mod_name; + P.string f " = {"; + let all_members = + List.map (fun v -> (v.mv_name, v.mv_type)) mod_values + @ List.map + (fun sub -> + ( sub.mod_name, + TypeRef {name = mod_name ^ "." ^ sub.mod_name; args = []} )) + mod_submodules + in + List.iter + (fun (name, ty) -> + P.newline f; + P.string f " "; + (* Use Ext_ident.convert to match JS property name (e.g., null -> $$null) *) + P.string f (Ext_ident.convert name); + P.string f ": "; + pp_ts_type_qualified f ~module_path + ~local_types:local_types_with_submodules ty; + P.string f ";") + all_members; + P.newline f; + P.string f "};"; + (* Print module value export only if emit_const is true *) + if emit_const then ( + P.newline f; + P.string f "export const "; + (* Use Ext_ident.convert to match JS export name (e.g., EvalError -> $$EvalError) *) + P.string f (Ext_ident.convert mod_name); + P.string f ": "; + P.string f mod_name; + P.string f ";") + +(** Wrapper for pp_module_decl_with_path for .d.ts output (emit const) *) +and pp_module_decl (f : P.t) (mod_decl : module_decl) : unit = + pp_module_decl_with_path f ~parent_path:None ~emit_const:true mod_decl + +(** Wrapper for pp_module_decl_with_path for combined .ts output (no const) *) +and pp_module_decl_ts (f : P.t) (mod_decl : module_decl) : unit = + pp_module_decl_with_path f ~parent_path:None ~emit_const:false mod_decl + +(** Print a type declaration inside a namespace with path context *) +and pp_namespace_type_decl_with_path (f : P.t) ~(module_path : string) + ~(emit_const : bool) (decl : type_decl) : unit = + match decl with + | TypeAlias {name; type_params; body; external_type = _; is_opaque = _} -> + P.string f "type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + (match body with + | Union types -> + (* Print union types with newlines for readability *) + P.group f 1 (fun () -> pp_union_multiline f types) + | _ -> + P.string f " "; + pp_ts_type f body); + P.string f ";" + | Interface {name; type_params; body; _} -> + P.string f "interface "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " { "; + List.iter + (fun prop -> + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type f prop.prop_type; + P.string f "; ") + body.properties; + P.string f "}" + | VariantType {name; type_params; cases; config} -> + P.string f "type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + (* Print variant cases on separate lines for readability *) + List.iter + (fun case -> + P.newline f; + P.string f " | "; + if config.vc_unboxed then pp_unboxed_variant_case f case + else pp_variant_case f ~tag_name:config.vc_tag_name case) + cases; + P.string f ";" + | GadtType {name; type_params; cases; config} -> + (* GADT inside module namespace: generate case types on separate lines *) + let is_first = ref true in + List.iter + (fun (case : gadt_case) -> + if !is_first then is_first := false + else ( + P.newline f; + P.string f " "); + P.string f "type "; + P.string f name; + P.string f "$"; + P.string f case.gc_name; + P.string f " = "; + if config.vc_unboxed then + pp_unboxed_variant_case f + { + vc_name = case.gc_name; + vc_tag = case.gc_tag; + vc_payload = case.gc_payload; + } + else + pp_variant_case f ~tag_name:config.vc_tag_name + { + vc_name = case.gc_name; + vc_tag = case.gc_tag; + vc_payload = case.gc_payload; + }; + P.string f ";") + cases; + (* Print the union type on a new line *) + P.newline f; + P.string f " type "; + P.string f name; + pp_gadt_type_params f ~indent:" " type_params; + P.string f " ="; + List.iter + (fun (case : gadt_case) -> + P.newline f; + P.string f " | "; + P.string f name; + P.string f "$"; + P.string f case.gc_name) + cases; + P.string f ";" + | OpaqueType {name; type_params; underlying} -> + (* Use full path for opaque brand to avoid conflicts between modules *) + let brand_name = module_path ^ "." ^ name in + P.string f "type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " = "; + pp_opaque_type f ~brand_name ~type_params ~underlying; + P.string f ";" + | ExternalType {name; type_params; external_name; _} -> + P.string f "type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " = "; + P.string f external_name; + if type_params <> [] then ( + P.string f "<"; + let param_names = + List.map (fun (tp : type_param) -> tp.tp_name) type_params + in + P.string f (String.concat ", " param_names); + P.string f ">"); + P.string f ";" + | ModuleDecl sub -> + pp_nested_module_decl_with_path f sub ~indent:0 ~parent_path:module_path + ~emit_const + +(** Print a nested module declaration with indentation and path context *) +and pp_nested_module_decl_with_path (f : P.t) (mod_decl : module_decl) + ~(indent : int) ~(parent_path : string) ~(emit_const : bool) : unit = + let {mod_name; mod_types; mod_values; mod_submodules} = mod_decl in + let indent_str = String.make indent ' ' in + (* Compute the full module path for type qualification *) + let module_path = parent_path ^ "." ^ mod_name in + (* Collect type names defined in this module for qualification *) + let local_types = get_module_type_names mod_decl in + (* Also include submodule names as they can be referenced as types *) + let local_types_with_submodules = + List.fold_left + (fun acc sub -> StringSet.add sub.mod_name acc) + local_types mod_submodules + in + (* Print namespace if there are types or submodules *) + let has_namespace_content = mod_types <> [] || mod_submodules <> [] in + if has_namespace_content then ( + P.string f indent_str; + P.string f "namespace "; + P.string f mod_name; + P.string f " {"; + List.iter + (fun decl -> + P.newline f; + P.string f indent_str; + P.string f " "; + pp_namespace_type_decl_with_path f ~module_path ~emit_const decl) + mod_types; + List.iter + (fun sub -> + P.newline f; + pp_nested_module_decl_with_path f sub ~indent:(indent + 2) + ~parent_path:module_path ~emit_const) + mod_submodules; + P.newline f; + P.string f indent_str; + P.string f "}"; + P.newline f); + (* Print module type *) + P.string f indent_str; + P.string f "type "; + P.string f mod_name; + P.string f " = {"; + let all_members = + List.map (fun v -> (v.mv_name, v.mv_type)) mod_values + @ List.map + (fun sub -> + ( sub.mod_name, + TypeRef {name = mod_name ^ "." ^ sub.mod_name; args = []} )) + mod_submodules + in + List.iter + (fun (name, ty) -> + P.newline f; + P.string f indent_str; + P.string f " "; + (* Use Ext_ident.convert to match JS property name (e.g., null -> $$null) *) + P.string f (Ext_ident.convert name); + P.string f ": "; + pp_ts_type_qualified f ~module_path + ~local_types:local_types_with_submodules ty; + P.string f ";") + all_members; + P.newline f; + P.string f indent_str; + P.string f "};" + +(** Print a type declaration inside a namespace (no export keyword) *) +and pp_namespace_type_decl (f : P.t) (decl : type_decl) : unit = + match decl with + | TypeAlias {name; type_params; body; external_type = _; is_opaque = _} -> + P.string f "type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + (match body with + | Union types -> + (* Print union types with newlines for readability *) + P.group f 1 (fun () -> pp_union_multiline f types) + | _ -> + P.string f " "; + pp_ts_type f body); + P.string f ";" + | Interface {name; type_params; body; _} -> + P.string f "interface "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " { "; + List.iter + (fun prop -> + if prop.prop_readonly then P.string f "readonly "; + pp_property_name f prop.prop_name; + if prop.prop_optional then P.string f "?"; + P.string f ": "; + pp_ts_type f prop.prop_type; + P.string f "; ") + body.properties; + P.string f "}" + | VariantType {name; type_params; cases; config} -> + P.string f "type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " ="; + (* Print variant cases on separate lines for readability *) + List.iter + (fun case -> + P.newline f; + P.string f " | "; + if config.vc_unboxed then pp_unboxed_variant_case f case + else pp_variant_case f ~tag_name:config.vc_tag_name case) + cases; + P.string f ";" + | GadtType {name; type_params; cases; config} -> + (* GADT in namespace: generate case types on separate lines *) + let is_first = ref true in + List.iter + (fun (case : gadt_case) -> + if !is_first then is_first := false + else ( + P.newline f; + P.string f " "); + P.string f "type "; + P.string f name; + P.string f "$"; + P.string f case.gc_name; + P.string f " = "; + if config.vc_unboxed then + pp_unboxed_variant_case f + { + vc_name = case.gc_name; + vc_tag = case.gc_tag; + vc_payload = case.gc_payload; + } + else + pp_variant_case f ~tag_name:config.vc_tag_name + { + vc_name = case.gc_name; + vc_tag = case.gc_tag; + vc_payload = case.gc_payload; + }; + P.string f ";") + cases; + (* Print the union type on a new line *) + P.newline f; + P.string f " type "; + P.string f name; + pp_gadt_type_params f ~indent:" " type_params; + P.string f " ="; + List.iter + (fun (case : gadt_case) -> + P.newline f; + P.string f " | "; + P.string f name; + P.string f "$"; + P.string f case.gc_name) + cases; + P.string f ";" + | OpaqueType {name; type_params; underlying} -> + (* Note: pp_namespace_type_decl without path is only used for non-module contexts. + For module-nested opaque types, pp_namespace_type_decl_with_path should be used. *) + P.string f "type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " = "; + let brand_name = + match OpaqueTypes.get_full_name name with + | Some full_name -> full_name + | None -> name + in + pp_opaque_type f ~brand_name ~type_params ~underlying; + P.string f ";" + | ExternalType {name; type_params; external_name; _} -> + P.string f "type "; + P.string f name; + if type_params <> [] then ( + P.string f "<"; + pp_type_params f type_params; + P.string f ">"); + P.string f " = "; + P.string f external_name; + if type_params <> [] then ( + P.string f "<"; + let param_names = + List.map (fun (tp : type_param) -> tp.tp_name) type_params + in + P.string f (String.concat ", " param_names); + P.string f ">"); + P.string f ";" + | ModuleDecl sub -> pp_nested_module_decl f sub ~indent:0 + +(** Print a nested module declaration with indentation *) +and pp_nested_module_decl (f : P.t) (mod_decl : module_decl) ~(indent : int) : + unit = + let {mod_name; mod_types; mod_values; mod_submodules} = mod_decl in + let indent_str = String.make indent ' ' in + (* Print namespace if there are types or submodules *) + let has_namespace_content = mod_types <> [] || mod_submodules <> [] in + if has_namespace_content then ( + P.string f indent_str; + P.string f "namespace "; + P.string f mod_name; + P.string f " {"; + List.iter + (fun decl -> + P.newline f; + P.string f indent_str; + P.string f " "; + pp_namespace_type_decl f decl) + mod_types; + List.iter + (fun sub -> + P.newline f; + pp_nested_module_decl f sub ~indent:(indent + 2)) + mod_submodules; + P.newline f; + P.string f indent_str; + P.string f "}"; + P.newline f); + (* Print module type *) + P.string f indent_str; + P.string f "type "; + P.string f mod_name; + P.string f " = {"; + let all_members = + List.map (fun v -> (v.mv_name, v.mv_type)) mod_values + @ List.map + (fun sub -> + ( sub.mod_name, + TypeRef {name = mod_name ^ "." ^ sub.mod_name; args = []} )) + mod_submodules + in + List.iter + (fun (name, ty) -> + P.newline f; + P.string f indent_str; + P.string f " "; + (* Use Ext_ident.convert to match JS property name (e.g., null -> $$null) *) + P.string f (Ext_ident.convert name); + P.string f ": "; + pp_ts_type f ty; + P.string f ";") + all_members; + P.newline f; + P.string f indent_str; + P.string f "};" + +(* Initialize the forward references for pp_module_decl *) +let () = pp_module_decl_ref := pp_module_decl +let () = pp_module_decl_ts_ref := pp_module_decl_ts + +(** Generate type-only import for .d.ts files *) +let pp_dts_import (f : P.t) (module_name : string) (module_path : string) : unit + = + P.string f "import type * as "; + P.string f module_name; + P.string f " from \""; + P.string f module_path; + P.string f "\";" + +(** Generate namespace import for runtime types (for .d.ts files) *) +let pp_runtime_types_import_dts (f : P.t) : unit = + if RuntimeTypes.has_any () then ( + P.string f "import type * as "; + P.string f runtime_types_namespace; + P.string f " from \"@rescript/runtime/types\";"; + P.newline f) + +type dts_import = { + module_name: string; + module_path: string; (** Path with .d.ts/.d.mts/.d.cts extension *) +} +(** Type import info for .d.ts generation *) + +(** Print type imports from external packages *) +let pp_external_type_imports (f : P.t) : unit = + let all_imports = ExternalTypeImports.get_all () in + List.iter + (fun (module_path, import_kinds) -> + let named_imports = + List.filter_map + (function + | ImportNamed name -> Some name + | _ -> None) + import_kinds + in + let default_import = + List.find_map + (function + | ImportDefault name -> Some name + | _ -> None) + import_kinds + in + let namespace_import = + List.find_map + (function + | ImportNamespace name -> Some name + | _ -> None) + import_kinds + in + (* Emit default import: import type LocalName from "module" *) + (match default_import with + | Some name -> + P.string f "import type "; + P.string f name; + P.string f " from \""; + P.string f module_path; + P.string f "\";"; + P.newline f + | None -> ()); + (* Emit namespace import: import type * as LocalName from "module" *) + (match namespace_import with + | Some name -> + P.string f "import type * as "; + P.string f name; + P.string f " from \""; + P.string f module_path; + P.string f "\";"; + P.newline f + | None -> ()); + (* Emit named imports: import type { A, B } from "module" *) + if named_imports <> [] then ( + P.string f "import type { "; + P.string f (String.concat ", " named_imports); + P.string f " } from \""; + P.string f module_path; + P.string f "\";"; + P.newline f)) + all_imports + +(** Collect names of locally defined modules from type declarations *) +let rec collect_local_module_names (decls : type_decl list) : StringSet.t = + List.fold_left + (fun acc decl -> + match decl with + | ModuleDecl {mod_name; mod_submodules; _} -> + (* Add this module and recursively add submodules *) + let with_this = StringSet.add mod_name acc in + let sub_decls = List.map (fun m -> ModuleDecl m) mod_submodules in + StringSet.union with_this (collect_local_module_names sub_decls) + | _ -> acc) + StringSet.empty decls + +type resolve_module_path = string -> string option +(** Type for resolving type-only module import paths. + This is passed from the caller to avoid circular dependencies. + Returns None if the module cannot be resolved (e.g., local module aliases). *) + +(** Generate the complete .d.ts file content + @param module_name The current module name + @param resolve_module_path Function to resolve import path for a module name + @param suffix The JS file suffix (e.g., ".js", ".mjs") + TODO(refactor): Move it to a part of dump program *) +let pp_dts_file ~(module_name : string) + ~(resolve_module_path : resolve_module_path) ~(suffix : string) (f : P.t) + (imports : dts_import list) (type_decls : type_decl list) + (value_exports : value_export list) : unit = + (* Save the environment that was set during extraction. + We need it to resolve module aliases in type paths. *) + let saved_env = State.state.env in + reset_state (); + (* Restore the environment for module alias resolution *) + State.state.env <- saved_env; + List.iter collect_type_deps_decl type_decls; + List.iter + (fun ve -> collect_type_deps (ts_type_of_type_expr ve.ve_type)) + value_exports; + let has_runtime_types = RuntimeTypes.has_any () in + let has_external_type_imports = ExternalTypeImports.has_any () in + let required_modules = TypeModuleDeps.get_used () in + let local_modules = collect_local_module_names type_decls in + let provided_imports = + List.fold_left + (fun acc imp -> StringSet.add imp.module_name acc) + StringSet.empty imports + in + (* Filter imports to only those that are actually used in types, + and add any missing module imports. + Exclude locally defined modules - they should not be imported. *) + let type_imports = + let used_provided = + List.filter + (fun imp -> + List.mem imp.module_name required_modules + && not (StringSet.mem imp.module_name local_modules)) + imports + in + (* Add missing imports for modules that are required but not provided, + excluding local modules *) + let missing_modules = + List.filter + (fun m -> + (not (StringSet.mem m provided_imports)) + && not (StringSet.mem m local_modules)) + required_modules + in + let missing_imports = + List.filter_map + (fun mod_name -> + (* Use the provided resolver to get the import path. + Skip modules that can't be resolved - these are local module aliases + (e.g., "module C = Belt_internalBucketsType") that don't need imports. *) + match resolve_module_path mod_name with + | Some path -> Some {module_name = mod_name; module_path = path} + | None -> None) + missing_modules + in + used_provided @ missing_imports + in + if not !Js_config.no_version_header then ( + P.string f Bs_version.header; + (* Only add blank line after header if there's content following *) + let has_content = + type_imports <> [] || has_runtime_types || has_external_type_imports + || type_decls <> [] || value_exports <> [] + in + if has_content then P.at_least_two_lines f); + pp_runtime_types_import_dts f; + pp_external_type_imports f; + List.iter + (fun imp -> + pp_dts_import f imp.module_name imp.module_path; + P.newline f) + type_imports; + if type_imports <> [] || has_runtime_types || has_external_type_imports then + P.at_least_two_lines f; + let all_items = + List.map (fun decl -> `Type decl) type_decls + @ List.map (fun ve -> `Value ve) value_exports + in + collect_opaque_types ~module_name type_decls; + set_module_name module_name; + let rec print_items = function + | [] -> () + | [`Type decl] -> pp_dts_type_decl f decl + | [`Value ve] -> pp_dts_value_export f ve + | `Type decl :: rest -> + pp_dts_type_decl f decl; + P.at_least_two_lines f; + print_items rest + | `Value ve :: rest -> + pp_dts_value_export f ve; + P.at_least_two_lines f; + print_items rest + in + print_items all_items; + P.newline f; + P.flush f () diff --git a/compiler/ext/js_reserved_map.ml b/compiler/ext/js_reserved_map.ml index 6daaff9760..6b45e349d5 100644 --- a/compiler/ext/js_reserved_map.ml +++ b/compiler/ext/js_reserved_map.ml @@ -241,3 +241,33 @@ let js_globals = STbl.of_array [| |] let is_js_global s = STbl.mem js_globals s + +(** TypeScript specific keywords *) +let ts_keywords = STbl.of_array + [| + "any"; + "boolean"; + "number"; + "string"; + "symbol"; + "abstract"; + "as"; + "async"; + "await"; + "declare"; + "from"; + "get"; + "is"; + "module"; + "namespace"; + "never"; + "readonly"; + "require"; + "set"; + "type"; + "undefined"; + "unique"; + "unknown"; + |] + +let is_ts_keyword s = STbl.mem ts_keywords s diff --git a/compiler/ext/js_reserved_map.mli b/compiler/ext/js_reserved_map.mli index 5ee19826fa..6fd333c34b 100644 --- a/compiler/ext/js_reserved_map.mli +++ b/compiler/ext/js_reserved_map.mli @@ -27,3 +27,5 @@ val is_js_keyword : string -> bool val is_js_special_word : string -> bool val is_js_global : string -> bool + +val is_ts_keyword : string -> bool diff --git a/compiler/ext/literals.ml b/compiler/ext/literals.ml index 2b469652ad..fc7e21d46d 100644 --- a/compiler/ext/literals.ml +++ b/compiler/ext/literals.ml @@ -115,6 +115,8 @@ let suffix_d = ".d" let suffix_js = ".js" +let suffix_ts = ".ts" + let suffix_gen_js = ".gen.js" let suffix_gen_tsx = ".gen.tsx" diff --git a/compiler/frontend/bs_ast_invariant.ml b/compiler/frontend/bs_ast_invariant.ml index cbe5a4432e..38e43d3dcf 100644 --- a/compiler/frontend/bs_ast_invariant.ml +++ b/compiler/frontend/bs_ast_invariant.ml @@ -76,6 +76,10 @@ let emit_external_warnings : iterator = if Ast_core_type.is_builtin_rank0_type txt then Location.raise_errorf ~loc:ptyp.ptype_loc "built-in type `%s` can not be redefined " txt; + (* Mark @as attribute as used on type declarations for type renaming in .d.ts *) + Ext_list.iter ptyp.ptype_attributes (fun ((attr_name, _) as attr) -> + if attr_name.txt = "as" then + Used_attributes.mark_used_attribute attr); super.type_declaration self ptyp); attribute = (fun _ attr -> warn_unused_attribute attr); structure_item = diff --git a/compiler/jsoo/jsoo_playground_main.ml b/compiler/jsoo/jsoo_playground_main.ml index 3100a3fc82..ae2f809899 100644 --- a/compiler/jsoo/jsoo_playground_main.ml +++ b/compiler/jsoo/jsoo_playground_main.ml @@ -521,7 +521,8 @@ module Compile = struct let () = Js_dump_program.pp_deps_program ~output_prefix:"" (* does not matter here *) module_system - (Lam_compile_main.compile "" exports lam) + (Lam_compile_main.compile "" exports ~type_decls:[] ~value_exports:[] + lam) (Ext_pp.from_buffer buffer) in let v = Buffer.contents buffer in diff --git a/compiler/ml/builtin_attributes.ml b/compiler/ml/builtin_attributes.ml index a4d073104b..c44296b252 100644 --- a/compiler/ml/builtin_attributes.ml +++ b/compiler/ml/builtin_attributes.ml @@ -252,3 +252,7 @@ let check l (x, _) = List.mem x.txt l let has_unboxed attr = List.exists (check ["ocaml.unboxed"; "unboxed"]) attr let has_boxed attr = List.exists (check ["ocaml.boxed"; "boxed"]) attr + +let has_external attr = List.exists (check ["external"]) attr + +let has_opaque attr = List.exists (check ["opaque"]) attr diff --git a/compiler/ml/builtin_attributes.mli b/compiler/ml/builtin_attributes.mli index 63bf762331..ea23789dc1 100644 --- a/compiler/ml/builtin_attributes.mli +++ b/compiler/ml/builtin_attributes.mli @@ -95,3 +95,5 @@ val immediate : Parsetree.attributes -> bool val has_unboxed : Parsetree.attributes -> bool val has_boxed : Parsetree.attributes -> bool +val has_external : Parsetree.attributes -> bool +val has_opaque : Parsetree.attributes -> bool diff --git a/compiler/ml/lambda.ml b/compiler/ml/lambda.ml index db810d4f91..e2493154fe 100644 --- a/compiler/ml/lambda.ml +++ b/compiler/ml/lambda.ml @@ -374,6 +374,7 @@ and lfunction = { body: lambda; attr: function_attribute; (* specified with [@inline] attribute *) loc: Location.t; + fn_type: Types.type_expr option; (* function type for typed codegen *) } and lambda_apply = { @@ -652,8 +653,8 @@ let subst_lambda s lam = ap_func = subst ap.ap_func; ap_args = List.map subst ap.ap_args; } - | Lfunction {params; body; attr; loc} -> - Lfunction {params; body = subst body; attr; loc} + | Lfunction {params; body; attr; loc; fn_type} -> + Lfunction {params; body = subst body; attr; loc; fn_type} | Llet (str, k, id, arg, body) -> Llet (str, k, id, subst arg, subst body) | Lletrec (decl, body) -> Lletrec (List.map subst_decl decl, subst body) | Lprim (p, args, loc) -> Lprim (p, List.map subst args, loc) diff --git a/compiler/ml/lambda.mli b/compiler/ml/lambda.mli index d8eaf57be6..392992be5f 100644 --- a/compiler/ml/lambda.mli +++ b/compiler/ml/lambda.mli @@ -345,6 +345,7 @@ and lfunction = { body: lambda; attr: function_attribute; (* specified with [@inline] attribute *) loc: Location.t; + fn_type: Types.type_expr option; (* function type for typed codegen *) } and lambda_apply = { diff --git a/compiler/ml/translcore.ml b/compiler/ml/translcore.ml index 078cbf133a..d46cdd9af6 100644 --- a/compiler/ml/translcore.ml +++ b/compiler/ml/translcore.ml @@ -461,6 +461,7 @@ let transl_primitive loc p env ty = attr = default_function_attribute; loc; body = Lprim (Pmakeblock Blk_tuple, [lam; Lvar param], loc); + fn_type = Some ty; } | _ -> assert false) | _ -> @@ -483,6 +484,7 @@ let transl_primitive loc p env ty = attr = default_function_attribute; loc; body = Lprim (prim, List.map (fun id -> Lvar id) params, loc); + fn_type = Some ty; } let transl_primitive_application loc prim env ty args = @@ -685,7 +687,8 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = } in let loc = e.exp_loc in - let lambda = Lfunction {params; body; attr; loc} in + let fn_type = Some e.exp_type in + let lambda = Lfunction {params; body; attr; loc; fn_type} in match arity with | Some arity -> let prim = @@ -981,8 +984,8 @@ and transl_apply ?(inlined = Default_inline) and id_arg = Ident.create "param" in let body = match build_apply handle ((Lvar id_arg, optional) :: args') l with - | Lfunction {params = ids; body = lam; attr; loc} -> - Lfunction {params = id_arg :: ids; body = lam; attr; loc} + | Lfunction {params = ids; body = lam; attr; loc; fn_type} -> + Lfunction {params = id_arg :: ids; body = lam; attr; loc; fn_type} | lam -> Lfunction { @@ -990,6 +993,7 @@ and transl_apply ?(inlined = Default_inline) body = lam; attr = default_function_attribute; loc; + fn_type = None; } in List.fold_left @@ -1031,6 +1035,7 @@ and transl_apply ?(inlined = Default_inline) body = l0; attr = default_function_attribute; loc; + fn_type = None; } | _ -> (build_apply lam [] diff --git a/compiler/ml/translmod.ml b/compiler/ml/translmod.ml index 87471ac26b..79f34ee0d9 100644 --- a/compiler/ml/translmod.ml +++ b/compiler/ml/translmod.ml @@ -102,6 +102,7 @@ and apply_coercion_result loc strict funct param arg cc_res = ap_inlined = Default_inline; ap_transformed_jsx = false; }); + fn_type = None; }) and wrap_id_pos_list loc id_pos_list get_field lam = @@ -250,6 +251,7 @@ let rec compile_functor mexp coercion root_path loc = }; loc; body; + fn_type = None; } (* Compile a module expression *) diff --git a/compiler/ml/typedecl.ml b/compiler/ml/typedecl.ml index da35de5288..049b7783c7 100644 --- a/compiler/ml/typedecl.ml +++ b/compiler/ml/typedecl.ml @@ -54,6 +54,7 @@ type error = | Bad_immediate_attribute | Bad_unboxed_attribute of string | Boxed_and_unboxed + | External_and_opaque | Nonrec_gadt | Variant_runtime_representation_mismatch of Variant_coercion.variant_error | Variant_spread_fail of Variant_type_spread.variant_type_spread_error @@ -75,6 +76,13 @@ let get_unboxed_from_attributes sdecl = | false, false, false -> unboxed_false_default_true | false, false, true -> unboxed_true_default_true +(* Check that @external and @opaque are not both present *) +let check_external_opaque_conflict sdecl = + let has_external = Builtin_attributes.has_external sdecl.ptype_attributes in + let has_opaque = Builtin_attributes.has_opaque sdecl.ptype_attributes in + if has_external && has_opaque then + raise (Error (sdecl.ptype_loc, External_and_opaque)) + (* Enter all declared types in the environment as abstract types *) let enter_type rec_flag env sdecl id = @@ -378,6 +386,7 @@ let transl_declaration ~type_record_as_object ~untagged_wfc env sdecl id = sdecl.ptype_cstrs in let raw_status = get_unboxed_from_attributes sdecl in + check_external_opaque_conflict sdecl; let check_untagged_variant () = match sdecl.ptype_kind with @@ -2268,6 +2277,9 @@ let report_error ppf = function fprintf ppf "@[This type cannot be unboxed because@ %s.@]" msg | Boxed_and_unboxed -> fprintf ppf "@[A type cannot be boxed and unboxed at the same time.@]" + | External_and_opaque -> + fprintf ppf + "@[A type cannot have both @@external and @@opaque attributes.@]" | Nonrec_gadt -> fprintf ppf "@[GADT case syntax cannot be used in a 'nonrec' block.@]" | Variant_runtime_representation_mismatch diff --git a/lib_dev/process.js b/lib_dev/process.js index ac24088871..eee95e7677 100644 --- a/lib_dev/process.js +++ b/lib_dev/process.js @@ -143,6 +143,18 @@ export function setup(cwd = process.cwd()) { return exec("yarn", [...command.split(" "), ...args], options); }, + /** + * Execute TypeScript check + * + * @param {string[]} [args] + * @param {ExecOptions} [options] + * @return {Promise} + */ + tsc(args = [], options = {}) { + const projectPath = path.join(cwd, "tsconfig.json"); + return exec("yarn", ["tsc", "--project", projectPath, ...args], options); + }, + /** * Execute Mocha CLI * diff --git a/packages/@rescript/runtime/Primitive_js_extern.res b/packages/@rescript/runtime/Primitive_js_extern.res index 2b9ea278b5..5c3cd1fc7d 100644 --- a/packages/@rescript/runtime/Primitive_js_extern.res +++ b/packages/@rescript/runtime/Primitive_js_extern.res @@ -1,7 +1,8 @@ @unboxed type null<+'a> = Value('a) | @as(null) Null -type undefined<+'a> +@unboxed +type undefined<+'a> = Value('a) | @as(undefined) Undefined @unboxed type nullable<+'a> = Value('a) | @as(null) Null | @as(undefined) Undefined diff --git a/packages/@rescript/runtime/Stdlib_Array.res b/packages/@rescript/runtime/Stdlib_Array.res index 30dd573fd7..8ec65123c6 100644 --- a/packages/@rescript/runtime/Stdlib_Array.res +++ b/packages/@rescript/runtime/Stdlib_Array.res @@ -1,4 +1,6 @@ type t<'a> = array<'a> + +@external("ArrayLike") type arrayLike<'a> @new external makeUninitializedUnsafe: int => array<'a> = "Array" diff --git a/packages/@rescript/runtime/Stdlib_ArrayBuffer.res b/packages/@rescript/runtime/Stdlib_ArrayBuffer.res index 4983aff64d..7bddda9297 100644 --- a/packages/@rescript/runtime/Stdlib_ArrayBuffer.res +++ b/packages/@rescript/runtime/Stdlib_ArrayBuffer.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("ArrayBuffer") type t @new external make: int => t = "ArrayBuffer" diff --git a/packages/@rescript/runtime/Stdlib_AsyncIterator.res b/packages/@rescript/runtime/Stdlib_AsyncIterator.res index b62128c821..98422c35de 100644 --- a/packages/@rescript/runtime/Stdlib_AsyncIterator.res +++ b/packages/@rescript/runtime/Stdlib_AsyncIterator.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("AsyncIterator") type t<'a> type value<'a> = { diff --git a/packages/@rescript/runtime/Stdlib_AsyncIterator.resi b/packages/@rescript/runtime/Stdlib_AsyncIterator.resi index 3a8b5d9ff7..f06b834dab 100644 --- a/packages/@rescript/runtime/Stdlib_AsyncIterator.resi +++ b/packages/@rescript/runtime/Stdlib_AsyncIterator.resi @@ -6,7 +6,7 @@ See [async iterator protocols](https://developer.mozilla.org/en-US/docs/Web/Java /** The type representing an async iterator. */ -@notUndefined +@notUndefined @external("AsyncIterator") type t<'a> type value<'a> = { diff --git a/packages/@rescript/runtime/Stdlib_Date.res b/packages/@rescript/runtime/Stdlib_Date.res index 95216e9a38..8f4b1cdc1b 100644 --- a/packages/@rescript/runtime/Stdlib_Date.res +++ b/packages/@rescript/runtime/Stdlib_Date.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("Date") type t type msSinceEpoch = float diff --git a/packages/@rescript/runtime/Stdlib_Date.resi b/packages/@rescript/runtime/Stdlib_Date.resi index c0e90397c1..634033a524 100644 --- a/packages/@rescript/runtime/Stdlib_Date.resi +++ b/packages/@rescript/runtime/Stdlib_Date.resi @@ -5,7 +5,7 @@ /** A type representing a JavaScript date. */ -@notUndefined +@notUndefined @external("Date") type t /** diff --git a/packages/@rescript/runtime/Stdlib_Intl_Collator.res b/packages/@rescript/runtime/Stdlib_Intl_Collator.res index 3626e96bc6..c13b498153 100644 --- a/packages/@rescript/runtime/Stdlib_Intl_Collator.res +++ b/packages/@rescript/runtime/Stdlib_Intl_Collator.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("Intl.Collator") type t type usage = [#sort | #search] diff --git a/packages/@rescript/runtime/Stdlib_Intl_DateTimeFormat.res b/packages/@rescript/runtime/Stdlib_Intl_DateTimeFormat.res index 070390d4f3..6589cb8fbf 100644 --- a/packages/@rescript/runtime/Stdlib_Intl_DateTimeFormat.res +++ b/packages/@rescript/runtime/Stdlib_Intl_DateTimeFormat.res @@ -2,7 +2,7 @@ Bindings to JavaScript's `Intl.DateTimeFormat`. */ -@notUndefined +@notUndefined @external("Intl.DateTimeFormat") type t type dateStyle = [#full | #long | #medium | #short] diff --git a/packages/@rescript/runtime/Stdlib_Intl_ListFormat.res b/packages/@rescript/runtime/Stdlib_Intl_ListFormat.res index 86715d4012..272d751528 100644 --- a/packages/@rescript/runtime/Stdlib_Intl_ListFormat.res +++ b/packages/@rescript/runtime/Stdlib_Intl_ListFormat.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("Intl.ListFormat") type t type listType = [ diff --git a/packages/@rescript/runtime/Stdlib_Intl_Locale.res b/packages/@rescript/runtime/Stdlib_Intl_Locale.res index 0e4bf97f75..20ad2923c6 100644 --- a/packages/@rescript/runtime/Stdlib_Intl_Locale.res +++ b/packages/@rescript/runtime/Stdlib_Intl_Locale.res @@ -2,7 +2,7 @@ Bindings to JavaScript's `Intl.Locale`. */ -@notUndefined +@notUndefined @external("Intl.Locale") type t type options = { diff --git a/packages/@rescript/runtime/Stdlib_Intl_NumberFormat.res b/packages/@rescript/runtime/Stdlib_Intl_NumberFormat.res index bd9d53da77..58f4a1e1be 100644 --- a/packages/@rescript/runtime/Stdlib_Intl_NumberFormat.res +++ b/packages/@rescript/runtime/Stdlib_Intl_NumberFormat.res @@ -1,6 +1,6 @@ module Grouping = Stdlib_Intl_NumberFormat_Grouping -@notUndefined +@notUndefined @external("Intl.NumberFormat") type t /** diff --git a/packages/@rescript/runtime/Stdlib_Intl_PluralRules.res b/packages/@rescript/runtime/Stdlib_Intl_PluralRules.res index c94c534c76..73adae0417 100644 --- a/packages/@rescript/runtime/Stdlib_Intl_PluralRules.res +++ b/packages/@rescript/runtime/Stdlib_Intl_PluralRules.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("Intl.PluralRules") type t type localeType = [#cardinal | #ordinal] diff --git a/packages/@rescript/runtime/Stdlib_Intl_RelativeTimeFormat.res b/packages/@rescript/runtime/Stdlib_Intl_RelativeTimeFormat.res index 37fa2f5ae9..6112e09a0c 100644 --- a/packages/@rescript/runtime/Stdlib_Intl_RelativeTimeFormat.res +++ b/packages/@rescript/runtime/Stdlib_Intl_RelativeTimeFormat.res @@ -3,7 +3,7 @@ Bindings to JavaScript's `Intl.RelativeTimeFormat`. See [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat) for API details. */ -@notUndefined +@notUndefined @external("Intl.RelativeTimeFormat") type t type numeric = [#always | #auto] diff --git a/packages/@rescript/runtime/Stdlib_Intl_Segmenter.res b/packages/@rescript/runtime/Stdlib_Intl_Segmenter.res index ff00a53c64..1c4ab9e19f 100644 --- a/packages/@rescript/runtime/Stdlib_Intl_Segmenter.res +++ b/packages/@rescript/runtime/Stdlib_Intl_Segmenter.res @@ -3,7 +3,7 @@ Bindings to JavaScript's `Intl.Segmenter`. See [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter) for API details. */ -@notUndefined +@notUndefined @external("Intl.Segmenter") type t type granularity = [#grapheme | #word | #sentence] diff --git a/packages/@rescript/runtime/Stdlib_Iterator.res b/packages/@rescript/runtime/Stdlib_Iterator.res index 1ef310d355..83a58862df 100644 --- a/packages/@rescript/runtime/Stdlib_Iterator.res +++ b/packages/@rescript/runtime/Stdlib_Iterator.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("Iterator") type t<'a> type value<'a> = { diff --git a/packages/@rescript/runtime/Stdlib_Iterator.resi b/packages/@rescript/runtime/Stdlib_Iterator.resi index 35c9b85107..65af001696 100644 --- a/packages/@rescript/runtime/Stdlib_Iterator.resi +++ b/packages/@rescript/runtime/Stdlib_Iterator.resi @@ -7,7 +7,7 @@ See [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referen /** The type representing an iterator. */ -@notUndefined +@notUndefined @external("Iterator") type t<'a> /** diff --git a/packages/@rescript/runtime/Stdlib_JsError.res b/packages/@rescript/runtime/Stdlib_JsError.res index 0622973178..f2f42cc40f 100644 --- a/packages/@rescript/runtime/Stdlib_JsError.res +++ b/packages/@rescript/runtime/Stdlib_JsError.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("Error") type t @get external stack: t => option = "stack" diff --git a/packages/@rescript/runtime/Stdlib_JsError.resi b/packages/@rescript/runtime/Stdlib_JsError.resi index 854d19c5d7..cfe2d19b29 100644 --- a/packages/@rescript/runtime/Stdlib_JsError.resi +++ b/packages/@rescript/runtime/Stdlib_JsError.resi @@ -5,7 +5,7 @@ See [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ */ /** Represents a JavaScript error. */ -@notUndefined +@notUndefined @external("Error") type t /** diff --git a/packages/@rescript/runtime/Stdlib_Map.res b/packages/@rescript/runtime/Stdlib_Map.res index 2c821c0021..db752a7880 100644 --- a/packages/@rescript/runtime/Stdlib_Map.res +++ b/packages/@rescript/runtime/Stdlib_Map.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("Map") type t<'k, 'v> @new external make: unit => t<'k, 'v> = "Map" diff --git a/packages/@rescript/runtime/Stdlib_Map.resi b/packages/@rescript/runtime/Stdlib_Map.resi index 8068ab9109..4dfc9be044 100644 --- a/packages/@rescript/runtime/Stdlib_Map.resi +++ b/packages/@rescript/runtime/Stdlib_Map.resi @@ -7,7 +7,7 @@ See [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Gl /** Type representing an instance of `Map`. */ -@notUndefined +@notUndefined @external("Map") type t<'k, 'v> /** diff --git a/packages/@rescript/runtime/Stdlib_RegExp.res b/packages/@rescript/runtime/Stdlib_RegExp.res index 9f1b5736a2..25efbf87e0 100644 --- a/packages/@rescript/runtime/Stdlib_RegExp.res +++ b/packages/@rescript/runtime/Stdlib_RegExp.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("RegExp") type t module Result = { diff --git a/packages/@rescript/runtime/Stdlib_RegExp.resi b/packages/@rescript/runtime/Stdlib_RegExp.resi index f682267897..d101bd41e4 100644 --- a/packages/@rescript/runtime/Stdlib_RegExp.resi +++ b/packages/@rescript/runtime/Stdlib_RegExp.resi @@ -7,7 +7,7 @@ See [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference /** Type representing an instantiated `RegExp`. */ -@notUndefined +@notUndefined @external("RegExp") type t module Result: { diff --git a/packages/@rescript/runtime/Stdlib_Set.res b/packages/@rescript/runtime/Stdlib_Set.res index 02a21ad1c9..952f50c2b7 100644 --- a/packages/@rescript/runtime/Stdlib_Set.res +++ b/packages/@rescript/runtime/Stdlib_Set.res @@ -1,4 +1,4 @@ -@notUndefined +@notUndefined @external("Set") type t<'a> @new external make: unit => t<'a> = "Set" diff --git a/packages/@rescript/runtime/Stdlib_Set.resi b/packages/@rescript/runtime/Stdlib_Set.resi index 5f9ca18668..db4f77bcdd 100644 --- a/packages/@rescript/runtime/Stdlib_Set.resi +++ b/packages/@rescript/runtime/Stdlib_Set.resi @@ -7,7 +7,7 @@ See [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Gl /** Type representing an instance of `Set`. */ -@notUndefined +@notUndefined @external("Set") type t<'a> /** diff --git a/packages/@rescript/runtime/Stdlib_WeakMap.res b/packages/@rescript/runtime/Stdlib_WeakMap.res index 4ac50a4930..f4ef910507 100644 --- a/packages/@rescript/runtime/Stdlib_WeakMap.res +++ b/packages/@rescript/runtime/Stdlib_WeakMap.res @@ -5,7 +5,7 @@ Weak maps keep key/value pairs where keys must be objects and the references do */ /** Mutable weak map storing values of type `'v` with object keys `'k`. */ -@notUndefined +@notUndefined @external("WeakMap") type t<'k, 'v> /** diff --git a/packages/@rescript/runtime/Stdlib_WeakSet.res b/packages/@rescript/runtime/Stdlib_WeakSet.res index 51ff206270..6f4b3e11b1 100644 --- a/packages/@rescript/runtime/Stdlib_WeakSet.res +++ b/packages/@rescript/runtime/Stdlib_WeakSet.res @@ -5,7 +5,7 @@ Weak sets store references to objects without preventing those objects from bein */ /** Mutable weak set storing object references of type `'a`. */ -@notUndefined +@notUndefined @external("WeakSet") type t<'a> /** diff --git a/packages/@rescript/runtime/lib/.npmignore b/packages/@rescript/runtime/lib/.npmignore deleted file mode 100644 index 9fb6c6decf..0000000000 --- a/packages/@rescript/runtime/lib/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -bs/ -*.ast -*.iast -rescript.lock -.compiler.log diff --git a/packages/@rescript/runtime/lib/es6/Belt.d.ts b/packages/@rescript/runtime/lib/es6/Belt.d.ts new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt.d.ts @@ -0,0 +1 @@ + diff --git a/packages/@rescript/runtime/lib/es6/Belt_Array.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Array.d.ts new file mode 100644 index 0000000000..a7b585b751 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Array.d.ts @@ -0,0 +1,220 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = A[]; + +export function get(arr: t, i: number): rescript.option; + +export function getOrThrow(arr: t, i: number): A; + +export function getExn(arg0: t, arg1: number): A; + +export function set(arr: t, i: number, v: A): boolean; + +export function setOrThrow(arr: t, i: number, v: A): void; + +export function setExn(arg0: t, arg1: number, arg2: A): void; + +export function shuffleInPlace(xs: t): void; + +export function shuffle(xs: t): t; + +export function reverseInPlace(xs: t): void; + +export function reverse(xs: t): t; + +export function make(l: number, f: A): t; + +export function makeBy(l: number, f: (arg0: number) => A): t; + +export function makeByAndShuffle(l: number, f: (arg0: number) => A): t; + +export function range(start: number, finish: number): number[]; + +export function rangeBy(start: number, finish: number, step: number): number[]; + +export function zip(xs: t, ys: B[]): [A, B][]; + +export function zipBy(xs: t, ys: B[], f: (arg0: A, arg1: B) => C): C[]; + +export function concat(a1: t, a2: t): t; + +export function concatMany(arrs: t[]): t; + +export function slice(a: t, offset: number, len: number): t; + +export function sliceToEnd(a: t, offset: number): t; + +export function fill(a: t, offset: number, len: number, v: A): void; + +export function blitUnsafe( + src: t, + srcOffset: number, + dst: t, + dstOffset: number, + len: number, +): void; + +export function blit( + src: t, + srcOffset: number, + dst: t, + dstOffset: number, + len: number, +): void; + +export function forEach(a: t, f: (arg0: A) => void): void; + +export function map(a: t, f: (arg0: A) => B): B[]; + +export function flatMap(a: t, f: (arg0: A) => B[]): B[]; + +export function getBy(a: t, p: (arg0: A) => boolean): rescript.option; + +export function getIndexBy( + a: t, + p: (arg0: A) => boolean, +): rescript.option; + +export function keep(a: t, f: (arg0: A) => boolean): t; + +export function keepWithIndex(a: t, f: (arg0: A, arg1: number) => boolean): t; + +export function keepMap(a: t, f: (arg0: A) => rescript.option): B[]; + +export function forEachWithIndex(a: t, f: (arg0: number, arg1: A) => void): void; + +export function mapWithIndex(a: t, f: (arg0: number, arg1: A) => B): B[]; + +export function reduce(a: B[], x: A, f: (arg0: A, arg1: B) => A): A; + +export function reduceReverse(a: B[], x: A, f: (arg0: A, arg1: B) => A): A; + +export function reduceReverse2( + a: t, + b: B[], + x: C, + f: (arg0: C, arg1: A, arg2: B) => C, +): C; + +export function reduceWithIndex( + a: t, + x: B, + f: (arg0: B, arg1: A, arg2: number) => B, +): B; + +export function every(arr: t, b: (arg0: A) => boolean): boolean; + +export function some(arr: t, b: (arg0: A) => boolean): boolean; + +export function every2(a: t, b: B[], p: (arg0: A, arg1: B) => boolean): boolean; + +export function some2(a: t, b: B[], p: (arg0: A, arg1: B) => boolean): boolean; + +export function eq(a: t, b: t, p: (arg0: A, arg1: A) => boolean): boolean; + +export function cmp(a: t, b: t, p: (arg0: A, arg1: A) => number): number; + +export function partition(a: t, f: (arg0: A) => boolean): [t, t]; + +export function unzip(a: [A, B][]): [t, B[]]; + +export function joinWith( + a: t, + sep: string, + toString: (arg0: A) => string, +): string; + +export function init(n: number, f: (arg0: number) => A): t; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => boolean, +): boolean; + +export function every2U( + arg0: t, + arg1: B[], + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function everyU(arg0: t, arg1: (arg0: A) => boolean): boolean; + +export function flatMapU(arg0: t, arg1: (arg0: A) => B[]): B[]; + +export function forEachU(arg0: t, arg1: (arg0: A) => void): void; + +export function forEachWithIndexU( + arg0: t, + arg1: (arg0: number, arg1: A) => void, +): void; + +export function getByU(arg0: t, arg1: (arg0: A) => boolean): rescript.option; + +export function getIndexByU( + arg0: t, + arg1: (arg0: A) => boolean, +): rescript.option; + +export function initU(arg0: number, arg1: (arg0: number) => A): t; + +export function joinWithU( + arg0: t, + arg1: string, + arg2: (arg0: A) => string, +): string; + +export function keepMapU(arg0: t, arg1: (arg0: A) => rescript.option): B[]; + +export function keepU(arg0: t, arg1: (arg0: A) => boolean): t; + +export function keepWithIndexU( + arg0: t, + arg1: (arg0: A, arg1: number) => boolean, +): t; + +export function makeByAndShuffleU(arg0: number, arg1: (arg0: number) => A): t; + +export function makeByU(arg0: number, arg1: (arg0: number) => A): t; + +export function mapU(arg0: t, arg1: (arg0: A) => B): B[]; + +export function mapWithIndexU(arg0: t, arg1: (arg0: number, arg1: A) => B): B[]; + +export function partitionU( + arg0: t, + arg1: (arg0: A) => boolean, +): [t, t]; + +export function reduceReverse2U( + arg0: t, + arg1: B[], + arg2: C, + arg3: (arg0: C, arg1: A, arg2: B) => C, +): C; + +export function reduceReverseU(arg0: B[], arg1: A, arg2: (arg0: A, arg1: B) => A): A; + +export function reduceU(arg0: B[], arg1: A, arg2: (arg0: A, arg1: B) => A): A; + +export function reduceWithIndexU( + arg0: t, + arg1: B, + arg2: (arg0: B, arg1: A, arg2: number) => B, +): B; + +export function some2U( + arg0: t, + arg1: B[], + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function someU(arg0: t, arg1: (arg0: A) => boolean): boolean; + +export function zipByU(arg0: t, arg1: B[], arg2: (arg0: A, arg1: B) => C): C[]; diff --git a/packages/@rescript/runtime/lib/es6/Belt_Float.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Float.d.ts new file mode 100644 index 0000000000..76979b0f1d --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Float.d.ts @@ -0,0 +1,3 @@ +import type * as rescript from "@rescript/runtime/types"; + +export function fromString(i: string): rescript.option; diff --git a/packages/@rescript/runtime/lib/es6/Belt_HashMap.d.ts b/packages/@rescript/runtime/lib/es6/Belt_HashMap.d.ts new file mode 100644 index 0000000000..ab4faf28ef --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_HashMap.d.ts @@ -0,0 +1,73 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_Id from "./Belt_Id.js"; + +export type t = rescript.opaque<"Belt_HashMap.t", [Key, Value, Id]>; + +export type id = Belt_Id.hashable; + +export function clear(arg0: t): void; + +export function size(h: t): number; + +export function forEach( + arg0: t, + arg1: (arg0: Key, arg1: Value) => void, +): void; + +export function reduce( + arg0: t, + arg1: C, + arg2: (arg0: C, arg1: Key, arg2: Value) => C, +): C; + +export function logStats(arg0: t): void; + +export function keepMapInPlace( + arg0: t, + arg1: (arg0: Key, arg1: Value) => rescript.option, +): void; + +export function toArray(arg0: t): [Key, Value][]; + +export function copy(arg0: t): t; + +export function keysToArray(arg0: t): Key[]; + +export function valuesToArray(arg0: t): Value[]; + +export function getBucketHistogram(arg0: t): number[]; + +export function isEmpty(arg0: t): boolean; + +export function set(h: t, key: Key, value: Value): void; + +export function remove(h: t, key: Key): void; + +export function get(h: t, key: Key): rescript.option; + +export function has(h: t, key: Key): boolean; + +export function make(hintSize: number, id: id): t; + +export function fromArray( + arr: [Key, Value][], + id: id, +): t; + +export function mergeMany(h: t, arr: [Key, Value][]): void; + +export function forEachU( + arg0: t, + arg1: (arg0: Key, arg1: Value) => void, +): void; + +export function reduceU( + arg0: t, + arg1: C, + arg2: (arg0: C, arg1: Key, arg2: Value) => C, +): C; + +export function keepMapInPlaceU( + arg0: t, + arg1: (arg0: Key, arg1: Value) => rescript.option, +): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_HashMapInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_HashMapInt.d.ts new file mode 100644 index 0000000000..3778427da6 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_HashMapInt.d.ts @@ -0,0 +1,59 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type key = number; + +export type t = rescript.opaque<"Belt_HashMapInt.t", [B]>; + +export function set(h: t, key: key, value: A): void; + +export function remove(h: t, key: key): void; + +export function get(h: t, key: key): rescript.option; + +export function has(h: t, key: key): boolean; + +export function make(hintSize: number): t; + +export function clear(arg0: t): void; + +export function size(h: t): number; + +export function forEach(arg0: t, arg1: (arg0: key, arg1: B) => void): void; + +export function reduce(arg0: t, arg1: C, arg2: (arg0: C, arg1: key, arg2: B) => C): C; + +export function logStats(arg0: t): void; + +export function keepMapInPlace( + arg0: t, + arg1: (arg0: key, arg1: A) => rescript.option, +): void; + +export function toArray(arg0: t): [key, A][]; + +export function copy(arg0: t): t; + +export function keysToArray(arg0: t): key[]; + +export function valuesToArray(arg0: t): A[]; + +export function getBucketHistogram(arg0: t): number[]; + +export function isEmpty(arg0: t): boolean; + +export function fromArray(arr: [key, A][]): t; + +export function mergeMany(h: t, arr: [key, A][]): void; + +export function forEachU(arg0: t, arg1: (arg0: key, arg1: B) => void): void; + +export function reduceU( + arg0: t, + arg1: C, + arg2: (arg0: C, arg1: key, arg2: B) => C, +): C; + +export function keepMapInPlaceU( + arg0: t, + arg1: (arg0: key, arg1: A) => rescript.option, +): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_HashMapString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_HashMapString.d.ts new file mode 100644 index 0000000000..47ea361b3b --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_HashMapString.d.ts @@ -0,0 +1,59 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type key = string; + +export type t = rescript.opaque<"Belt_HashMapString.t", [B]>; + +export function set(h: t, key: key, value: A): void; + +export function remove(h: t, key: key): void; + +export function get(h: t, key: key): rescript.option; + +export function has(h: t, key: key): boolean; + +export function make(hintSize: number): t; + +export function clear(arg0: t): void; + +export function size(h: t): number; + +export function forEach(arg0: t, arg1: (arg0: key, arg1: B) => void): void; + +export function reduce(arg0: t, arg1: C, arg2: (arg0: C, arg1: key, arg2: B) => C): C; + +export function logStats(arg0: t): void; + +export function keepMapInPlace( + arg0: t, + arg1: (arg0: key, arg1: A) => rescript.option, +): void; + +export function toArray(arg0: t): [key, A][]; + +export function copy(arg0: t): t; + +export function keysToArray(arg0: t): key[]; + +export function valuesToArray(arg0: t): A[]; + +export function getBucketHistogram(arg0: t): number[]; + +export function isEmpty(arg0: t): boolean; + +export function fromArray(arr: [key, A][]): t; + +export function mergeMany(h: t, arr: [key, A][]): void; + +export function forEachU(arg0: t, arg1: (arg0: key, arg1: B) => void): void; + +export function reduceU( + arg0: t, + arg1: C, + arg2: (arg0: C, arg1: key, arg2: B) => C, +): C; + +export function keepMapInPlaceU( + arg0: t, + arg1: (arg0: key, arg1: A) => rescript.option, +): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_HashSet.d.ts b/packages/@rescript/runtime/lib/es6/Belt_HashSet.d.ts new file mode 100644 index 0000000000..14464a26e0 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_HashSet.d.ts @@ -0,0 +1,40 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_Id from "./Belt_Id.js"; + +export type t = rescript.opaque<"Belt_HashSet.t", [A, Id]>; + +export type id = Belt_Id.hashable; + +export function remove(h: t, key: A): void; + +export function add(h: t, key: A): void; + +export function has(h: t, key: A): boolean; + +export function make(hintSize: number, id: id): t; + +export function clear(arg0: t): void; + +export function size(h: t): number; + +export function forEach(arg0: t, arg1: (arg0: A) => void): void; + +export function reduce(arg0: t, arg1: C, arg2: (arg0: C, arg1: A) => C): C; + +export function logStats(arg0: t): void; + +export function toArray(arg0: t): A[]; + +export function copy(arg0: t): t; + +export function getBucketHistogram(arg0: t): number[]; + +export function isEmpty(arg0: t): boolean; + +export function fromArray(arr: A[], id: id): t; + +export function mergeMany(h: t, arr: A[]): void; + +export function forEachU(arg0: t, arg1: (arg0: A) => void): void; + +export function reduceU(arg0: t, arg1: C, arg2: (arg0: C, arg1: A) => C): C; diff --git a/packages/@rescript/runtime/lib/es6/Belt_HashSetInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_HashSetInt.d.ts new file mode 100644 index 0000000000..f444e8c5b6 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_HashSetInt.d.ts @@ -0,0 +1,39 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type key = number; + +export type t = rescript.opaque<"Belt_HashSetInt.t", []>; + +export function remove(h: t, key: key): void; + +export function add(h: t, key: key): void; + +export function has(h: t, key: key): boolean; + +export function make(hintSize: number): t; + +export function clear(arg0: t): void; + +export function size(h: t): number; + +export function forEach(arg0: t, arg1: (arg0: key) => void): void; + +export function reduce(arg0: t, arg1: C, arg2: (arg0: C, arg1: key) => C): C; + +export function logStats(arg0: t): void; + +export function toArray(arg0: t): key[]; + +export function copy(arg0: t): t; + +export function getBucketHistogram(arg0: t): number[]; + +export function isEmpty(arg0: t): boolean; + +export function fromArray(arr: key[]): t; + +export function mergeMany(h: t, arr: key[]): void; + +export function forEachU(arg0: t, arg1: (arg0: key) => void): void; + +export function reduceU(arg0: t, arg1: C, arg2: (arg0: C, arg1: key) => C): C; diff --git a/packages/@rescript/runtime/lib/es6/Belt_HashSetString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_HashSetString.d.ts new file mode 100644 index 0000000000..8beec27b29 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_HashSetString.d.ts @@ -0,0 +1,39 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type key = string; + +export type t = rescript.opaque<"Belt_HashSetString.t", []>; + +export function remove(h: t, key: key): void; + +export function add(h: t, key: key): void; + +export function has(h: t, key: key): boolean; + +export function make(hintSize: number): t; + +export function clear(arg0: t): void; + +export function size(h: t): number; + +export function forEach(arg0: t, arg1: (arg0: key) => void): void; + +export function reduce(arg0: t, arg1: C, arg2: (arg0: C, arg1: key) => C): C; + +export function logStats(arg0: t): void; + +export function toArray(arg0: t): key[]; + +export function copy(arg0: t): t; + +export function getBucketHistogram(arg0: t): number[]; + +export function isEmpty(arg0: t): boolean; + +export function fromArray(arr: key[]): t; + +export function mergeMany(h: t, arr: key[]): void; + +export function forEachU(arg0: t, arg1: (arg0: key) => void): void; + +export function reduceU(arg0: t, arg1: C, arg2: (arg0: C, arg1: key) => C): C; diff --git a/packages/@rescript/runtime/lib/es6/Belt_Id.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Id.d.ts new file mode 100644 index 0000000000..0fdb5b41b7 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Id.d.ts @@ -0,0 +1,25 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type hash = rescript.opaque<"Belt_Id.hash", [A, Id]>; + +export type eq = rescript.opaque<"Belt_Id.eq", [A, Id]>; + +export type cmp = rescript.opaque<"Belt_Id.cmp", [A, Id]>; + +export type comparable = rescript.opaque<"Belt_Id.comparable", [Key, Id], any>; + +export type hashable = rescript.opaque<"Belt_Id.hashable", [Key, Id], any>; + +export function comparable(cmp: (arg0: A, arg1: A) => number): any; + +export function hashable( + hash: (arg0: A) => number, + eq: (arg0: A, arg1: A) => boolean, +): any; + +export function comparableU(cmp: (arg0: A, arg1: A) => number): any; + +export function hashableU( + hash: (arg0: A) => number, + eq: (arg0: A, arg1: A) => boolean, +): any; diff --git a/packages/@rescript/runtime/lib/es6/Belt_Int.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Int.d.ts new file mode 100644 index 0000000000..76979b0f1d --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Int.d.ts @@ -0,0 +1,3 @@ +import type * as rescript from "@rescript/runtime/types"; + +export function fromString(i: string): rescript.option; diff --git a/packages/@rescript/runtime/lib/es6/Belt_List.d.ts b/packages/@rescript/runtime/lib/es6/Belt_List.d.ts new file mode 100644 index 0000000000..7d65707b79 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_List.d.ts @@ -0,0 +1,298 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = rescript.list; + +export function head(x: t): rescript.option; + +export function headOrThrow(x: t): A; + +export function headExn(arg0: t): A; + +export function tail(x: t): rescript.option>; + +export function tailOrThrow(x: t): t; + +export function tailExn(arg0: t): t; + +export function add(xs: t, x: A): t; + +export function get(x: t, n: number): rescript.option; + +export function getOrThrow(x: t, n: number): A; + +export function getExn(arg0: t, arg1: number): A; + +export function take(lst: t, n: number): rescript.option>; + +export function drop(lst: t, n: number): rescript.option>; + +export function splitAt( + lst: t, + n: number, +): rescript.option<[rescript.list, rescript.list]>; + +export function concat(xs: t, ys: t): t; + +export function map(xs: t, f: (arg0: A) => B): t; + +export function zipBy(l1: t, l2: t, f: (arg0: A, arg1: B) => C): t; + +export function mapWithIndex(xs: t, f: (arg0: number, arg1: A) => B): t; + +export function makeBy(n: number, f: (arg0: number) => A): t; + +export function make(n: number, v: A): t; + +export function length(xs: t): number; + +export function size(arg0: t): number; + +export function fromArray(a: A[]): t; + +export function toArray(x: t): A[]; + +export function shuffle(xs: t): t; + +export function reverseConcat(l1: t, l2: t): t; + +export function reverse(l: t): t; + +export function flatten(xs: t>): t; + +export function concatMany(xs: t[]): t; + +export function mapReverse(l: t, f: (arg0: A) => B): t; + +export function forEach(xs: t, f: (arg0: A) => B): void; + +export function forEachWithIndex(l: t, f: (arg0: number, arg1: A) => B): void; + +export function reduce(l: t, accu: B, f: (arg0: B, arg1: A) => B): B; + +export function reduceReverse(l: t, acc: B, f: (arg0: B, arg1: A) => B): B; + +export function reduceWithIndex( + l: t, + acc: B, + f: (arg0: B, arg1: A, arg2: number) => B, +): B; + +export function mapReverse2(l1: t, l2: t, f: (arg0: A, arg1: B) => C): t; + +export function forEach2(l1: t, l2: t, f: (arg0: A, arg1: B) => C): void; + +export function reduce2( + l1: t, + l2: t, + accu: A, + f: (arg0: A, arg1: B, arg2: C) => A, +): A; + +export function reduceReverse2( + l1: t, + l2: t, + acc: C, + f: (arg0: C, arg1: A, arg2: B) => C, +): C; + +export function every(xs: t, p: (arg0: A) => boolean): boolean; + +export function some(xs: t, p: (arg0: A) => boolean): boolean; + +export function every2( + l1: t, + l2: t, + p: (arg0: A, arg1: B) => boolean, +): boolean; + +export function cmpByLength(l1: t, l2: t): number; + +export function cmp(l1: t, l2: t, p: (arg0: A, arg1: A) => number): number; + +export function eq(l1: t, l2: t, p: (arg0: A, arg1: A) => boolean): boolean; + +export function some2(l1: t, l2: t, p: (arg0: A, arg1: B) => boolean): boolean; + +export function has(xs: t, x: B, eq: (arg0: A, arg1: B) => boolean): boolean; + +export function getAssoc( + xs: t<[A, C]>, + x: B, + eq: (arg0: A, arg1: B) => boolean, +): rescript.option; + +export function hasAssoc( + xs: t<[A, C]>, + x: B, + eq: (arg0: A, arg1: B) => boolean, +): boolean; + +export function removeAssoc( + xs: t<[A, C]>, + x: B, + eq: (arg0: A, arg1: B) => boolean, +): t<[A, C]>; + +export function setAssoc( + xs: t<[A, C]>, + x: A, + k: C, + eq: (arg0: A, arg1: A) => boolean, +): t<[A, C]>; + +export function sort(xs: t, cmp: (arg0: A, arg1: A) => number): t; + +export function getBy(xs: t, p: (arg0: A) => boolean): rescript.option; + +export function keep(xs: t, p: (arg0: A) => boolean): t; + +export function filter(arg0: t, arg1: (arg0: A) => boolean): t; + +export function keepWithIndex(xs: t, p: (arg0: A, arg1: number) => boolean): t; + +export function filterWithIndex( + arg0: t, + arg1: (arg0: A, arg1: number) => boolean, +): t; + +export function keepMap(xs: t, p: (arg0: A) => rescript.option): t; + +export function partition(l: t, p: (arg0: A) => boolean): [t, t]; + +export function unzip(xs: t<[A, B]>): [t, t]; + +export function zip(l1: t, l2: t): t<[A, B]>; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => boolean, +): boolean; + +export function every2U( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function everyU(arg0: t, arg1: (arg0: A) => boolean): boolean; + +export function forEach2U( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: B) => C, +): void; + +export function forEachU(arg0: t, arg1: (arg0: A) => B): void; + +export function forEachWithIndexU( + arg0: t, + arg1: (arg0: number, arg1: A) => B, +): void; + +export function getAssocU( + arg0: t<[A, C]>, + arg1: B, + arg2: (arg0: A, arg1: B) => boolean, +): rescript.option; + +export function getByU(arg0: t, arg1: (arg0: A) => boolean): rescript.option; + +export function hasAssocU( + arg0: t<[A, C]>, + arg1: B, + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function hasU( + arg0: t, + arg1: B, + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function keepMapU(arg0: t, arg1: (arg0: A) => rescript.option): t; + +export function keepU(arg0: t, arg1: (arg0: A) => boolean): t; + +export function keepWithIndexU( + arg0: t, + arg1: (arg0: A, arg1: number) => boolean, +): t; + +export function makeByU(arg0: number, arg1: (arg0: number) => A): t; + +export function mapReverse2U( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: B) => C, +): t; + +export function mapReverseU(arg0: t, arg1: (arg0: A) => B): t; + +export function mapU(arg0: t, arg1: (arg0: A) => B): t; + +export function mapWithIndexU(arg0: t, arg1: (arg0: number, arg1: A) => B): t; + +export function partitionU( + arg0: t, + arg1: (arg0: A) => boolean, +): [t, t]; + +export function reduce2U( + arg0: t, + arg1: t, + arg2: A, + arg3: (arg0: A, arg1: B, arg2: C) => A, +): A; + +export function reduceReverse2U( + arg0: t, + arg1: t, + arg2: C, + arg3: (arg0: C, arg1: A, arg2: B) => C, +): C; + +export function reduceReverseU( + arg0: t, + arg1: B, + arg2: (arg0: B, arg1: A) => B, +): B; + +export function reduceU(arg0: t, arg1: B, arg2: (arg0: B, arg1: A) => B): B; + +export function reduceWithIndexU( + arg0: t, + arg1: B, + arg2: (arg0: B, arg1: A, arg2: number) => B, +): B; + +export function removeAssocU( + arg0: t<[A, C]>, + arg1: B, + arg2: (arg0: A, arg1: B) => boolean, +): t<[A, C]>; + +export function setAssocU( + arg0: t<[A, C]>, + arg1: A, + arg2: C, + arg3: (arg0: A, arg1: A) => boolean, +): t<[A, C]>; + +export function some2U( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function someU(arg0: t, arg1: (arg0: A) => boolean): boolean; + +export function sortU(arg0: t, arg1: (arg0: A, arg1: A) => number): t; + +export function zipByU(arg0: t, arg1: t, arg2: (arg0: A, arg1: B) => C): t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_Map.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Map.d.ts new file mode 100644 index 0000000000..b75db487a8 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Map.d.ts @@ -0,0 +1,195 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_MapDict from "./Belt_MapDict.js"; +import type * as Belt_Id from "./Belt_Id.js"; +import type * as Js from "./Js.js"; + +export type t = rescript.opaque<"Belt_Map.t", [Key, Value, Identity]>; + +export type id = Belt_Id.comparable; + +export function fromArray(data: [K, V][], id: id): t; + +export function remove(m: t, x: K): t; + +export function removeMany(m: t, x: K[]): t; + +export function set(m: t, key: K, d: V): t; + +export function mergeMany(m: t, e: [K, V][]): t; + +export function update( + m: t, + key: K, + f: (arg0: rescript.option) => rescript.option, +): t; + +export function split( + m: t, + x: K, +): [[t, t], rescript.option]; + +export function merge( + s1: t, + s2: t, + f: (arg0: K, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): t; + +export function make(id: id): t; + +export function isEmpty(map: t): boolean; + +export function findFirstBy( + m: t, + f: (arg0: K, arg1: V) => boolean, +): rescript.option<[K, V]>; + +export function forEach(m: t, f: (arg0: K, arg1: V) => void): void; + +export function reduce( + m: t, + acc: Acc, + f: (arg0: Acc, arg1: K, arg2: V) => Acc, +): Acc; + +export function every(m: t, f: (arg0: K, arg1: V) => boolean): boolean; + +export function some(m: t, f: (arg0: K, arg1: V) => boolean): boolean; + +export function keep(m: t, f: (arg0: K, arg1: V) => boolean): t; + +export function partition( + m: t, + p: (arg0: K, arg1: V) => boolean, +): [t, t]; + +export function map(m: t, f: (arg0: V) => V2): t; + +export function mapWithKey( + m: t, + f: (arg0: K, arg1: V) => V2, +): t; + +export function size(map: t): number; + +export function toList(map: t): rescript.list<[K, V]>; + +export function toArray(m: t): [K, V][]; + +export function keysToArray(m: t): K[]; + +export function valuesToArray(m: t): V[]; + +export function minKey(m: t): rescript.option; + +export function minKeyUndefined(m: t): Js.undefined_; + +export function maxKey(m: t): rescript.option; + +export function maxKeyUndefined(m: t): Js.undefined_; + +export function minimum(m: t): rescript.option<[K, V]>; + +export function minUndefined(m: t): Js.undefined_<[K, V]>; + +export function maximum(m: t): rescript.option<[K, V]>; + +export function maxUndefined(m: t): Js.undefined_<[K, V]>; + +export function get(map: t, x: K): rescript.option; + +export function getUndefined(map: t, x: K): Js.undefined_; + +export function getWithDefault(map: t, x: K, def: V): V; + +export function getOrThrow(map: t, x: K): V; + +export function getExn(arg0: t, arg1: K): V; + +export function has(map: t, x: K): boolean; + +export function checkInvariantInternal(m: t): void; + +export function eq( + m1: t, + m2: t, + veq: (arg0: V, arg1: V) => boolean, +): boolean; + +export function cmp( + m1: t, + m2: t, + vcmp: (arg0: V, arg1: V) => number, +): number; + +export function getData(m: t): Belt_MapDict.t; + +export function getId(m: t): id; + +export function packIdData( + id: id, + data: Belt_MapDict.t, +): t; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => boolean, +): boolean; + +export function everyU( + arg0: t, + arg1: (arg0: K, arg1: V) => boolean, +): boolean; + +export function findFirstByU( + arg0: t, + arg1: (arg0: K, arg1: V) => boolean, +): rescript.option<[K, V]>; + +export function forEachU(arg0: t, arg1: (arg0: K, arg1: V) => void): void; + +export function keepU( + arg0: t, + arg1: (arg0: K, arg1: V) => boolean, +): t; + +export function mapU(arg0: t, arg1: (arg0: V) => V2): t; + +export function mapWithKeyU( + arg0: t, + arg1: (arg0: K, arg1: V) => V2, +): t; + +export function mergeU( + arg0: t, + arg1: t, + arg2: (arg0: K, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): t; + +export function partitionU( + arg0: t, + arg1: (arg0: K, arg1: V) => boolean, +): [t, t]; + +export function reduceU( + arg0: t, + arg1: Acc, + arg2: (arg0: Acc, arg1: K, arg2: V) => Acc, +): Acc; + +export function someU( + arg0: t, + arg1: (arg0: K, arg1: V) => boolean, +): boolean; + +export function updateU( + arg0: t, + arg1: K, + arg2: (arg0: rescript.option) => rescript.option, +): t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MapDict.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MapDict.d.ts new file mode 100644 index 0000000000..44de022b87 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MapDict.d.ts @@ -0,0 +1,229 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_Id from "./Belt_Id.js"; +import type * as Js from "./Js.js"; + +export type t = rescript.opaque<"Belt_MapDict.t", [Key, Value, Id]>; + +export type cmp = Belt_Id.cmp; + +export const empty: t; + +export function fromArray(arg0: [K, A][], cmp: cmp): t; + +export function isEmpty(arg0: t): boolean; + +export function cmp( + arg0: t, + arg1: t, + kcmp: cmp, + vcmp: (arg0: V, arg1: V) => number, +): number; + +export function eq( + arg0: t, + arg1: t, + kcmp: cmp, + veq: (arg0: A, arg1: A) => boolean, +): boolean; + +export function has(arg0: t, arg1: K, cmp: cmp): boolean; + +export function findFirstBy( + arg0: t, + arg1: (arg0: K, arg1: V) => boolean, +): rescript.option<[K, V]>; + +export function forEach(arg0: t, arg1: (arg0: K, arg1: A) => void): void; + +export function reduce( + arg0: t, + arg1: B, + arg2: (arg0: B, arg1: K, arg2: A) => B, +): B; + +export function every( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): boolean; + +export function some( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): boolean; + +export function size(arg0: t): number; + +export function toList(arg0: t): rescript.list<[K, A]>; + +export function toArray(arg0: t): [K, A][]; + +export function keysToArray(arg0: t): K[]; + +export function valuesToArray(arg0: t): A[]; + +export function minimum(arg0: t): rescript.option<[K, A]>; + +export function maximum(arg0: t): rescript.option<[K, A]>; + +export function minKey(arg0: t): rescript.option; + +export function maxKey(arg0: t): rescript.option; + +export function minKeyUndefined(arg0: t): Js.undefined_; + +export function maxKeyUndefined(arg0: t): Js.undefined_; + +export function minUndefined(arg0: t): Js.undefined_<[K, A]>; + +export function maxUndefined(arg0: t): Js.undefined_<[K, A]>; + +export function get( + arg0: t, + arg1: K, + cmp: cmp, +): rescript.option; + +export function getUndefined( + arg0: t, + arg1: K, + cmp: cmp, +): Js.undefined_; + +export function getWithDefault( + arg0: t, + arg1: K, + arg2: A, + cmp: cmp, +): A; + +export function getOrThrow(arg0: t, arg1: K, cmp: cmp): A; + +export function getExn(arg0: t, arg1: K, cmp: cmp): A; + +export function mapWithKey( + arg0: t, + arg1: (arg0: K, arg1: A) => B, +): t; + +export function map(arg0: t, arg1: (arg0: A) => B): t; + +export function keep( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): t; + +export function partition( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): [t, t]; + +export function checkInvariantInternal(arg0: t): void; + +export function set( + t: t, + newK: A, + newD: B, + cmp: cmp, +): t; + +export function update( + t: t, + newK: A, + f: (arg0: rescript.option) => rescript.option, + cmp: cmp, +): t; + +export function remove(n: t, x: A, cmp: cmp): t; + +export function mergeMany( + h: t, + arr: [A, B][], + cmp: cmp, +): t; + +export function split( + n: t, + x: A, + cmp: cmp, +): [[t, t], rescript.option]; + +export function merge( + s1: t, + s2: t, + f: (arg0: A, arg1: rescript.option, arg2: rescript.option) => rescript.option, + cmp: cmp, +): t; + +export function removeMany( + t: t, + keys: A[], + cmp: cmp, +): t; + +export function cmpU( + arg0: t, + arg1: t, + kcmp: cmp, + vcmp: (arg0: V, arg1: V) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + kcmp: cmp, + veq: (arg0: A, arg1: A) => boolean, +): boolean; + +export function everyU( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): boolean; + +export function findFirstByU( + arg0: t, + arg1: (arg0: K, arg1: V) => boolean, +): rescript.option<[K, V]>; + +export function forEachU(arg0: t, arg1: (arg0: K, arg1: A) => void): void; + +export function keepU( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): t; + +export function mapU(arg0: t, arg1: (arg0: A) => B): t; + +export function mapWithKeyU( + arg0: t, + arg1: (arg0: K, arg1: A) => B, +): t; + +export function mergeU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: rescript.option, arg2: rescript.option) => rescript.option, + cmp: cmp, +): t; + +export function partitionU( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): [t, t]; + +export function reduceU( + arg0: t, + arg1: B, + arg2: (arg0: B, arg1: K, arg2: A) => B, +): B; + +export function someU( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): boolean; + +export function updateU( + arg0: t, + arg1: A, + arg2: (arg0: rescript.option) => rescript.option, + cmp: cmp, +): t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MapInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MapInt.d.ts new file mode 100644 index 0000000000..d3d13a7721 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MapInt.d.ts @@ -0,0 +1,166 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type key = number; + +export type t = rescript.opaque<"Belt_MapInt.t", [Value]>; + +export const empty: t; + +export function isEmpty(arg0: t): boolean; + +export function minKey(arg0: t): rescript.option; + +export function minKeyUndefined(arg0: t): Js.undefined_; + +export function maxKey(arg0: t): rescript.option; + +export function maxKeyUndefined(arg0: t): Js.undefined_; + +export function minimum(arg0: t): rescript.option<[key, V]>; + +export function minUndefined(arg0: t): Js.undefined_<[key, V]>; + +export function maximum(arg0: t): rescript.option<[key, V]>; + +export function maxUndefined(arg0: t): Js.undefined_<[key, V]>; + +export function findFirstBy( + arg0: t, + arg1: (arg0: key, arg1: V) => boolean, +): rescript.option<[key, V]>; + +export function forEach(arg0: t, arg1: (arg0: key, arg1: V) => void): void; + +export function map(arg0: t, arg1: (arg0: V) => V2): t; + +export function mapWithKey(arg0: t, arg1: (arg0: key, arg1: V) => V2): t; + +export function reduce( + arg0: t, + arg1: V2, + arg2: (arg0: V2, arg1: key, arg2: V) => V2, +): V2; + +export function every(arg0: t, arg1: (arg0: key, arg1: V) => boolean): boolean; + +export function some(arg0: t, arg1: (arg0: key, arg1: V) => boolean): boolean; + +export function keep(arg0: t, arg1: (arg0: key, arg1: V) => boolean): t; + +export function partition( + arg0: t, + arg1: (arg0: key, arg1: V) => boolean, +): [t, t]; + +export function size(arg0: t): number; + +export function toList(arg0: t): rescript.list<[key, V]>; + +export function toArray(arg0: t): [key, V][]; + +export function keysToArray(arg0: t): key[]; + +export function valuesToArray(arg0: t): V[]; + +export function checkInvariantInternal(arg0: t): void; + +export function set(t: t, newK: key, newD: V): t; + +export function update( + t: t, + x: key, + f: (arg0: rescript.option) => rescript.option, +): t; + +export function remove(n: t, x: key): t; + +export function removeMany(t: t, keys: key[]): t; + +export function mergeMany(h: t, arr: [key, V][]): t; + +export function has(arg0: t, arg1: key): boolean; + +export function cmp( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => number, +): number; + +export function eq( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => boolean, +): boolean; + +export function get(arg0: t, arg1: key): rescript.option; + +export function getUndefined(arg0: t, arg1: key): Js.undefined_; + +export function getWithDefault(arg0: t, arg1: key, arg2: V): V; + +export function getOrThrow(arg0: t, arg1: key): V; + +export function getExn(arg0: t, arg1: key): V; + +export function split(arg0: key, arg1: t): [t, rescript.option, t]; + +export function merge( + arg0: t, + arg1: t, + arg2: (arg0: key, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): t; + +export function fromArray(arg0: [key, V][]): t; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => boolean, +): boolean; + +export function everyU(arg0: t, arg1: (arg0: key, arg1: V) => boolean): boolean; + +export function findFirstByU( + arg0: t, + arg1: (arg0: key, arg1: V) => boolean, +): rescript.option<[key, V]>; + +export function forEachU(arg0: t, arg1: (arg0: key, arg1: V) => void): void; + +export function keepU(arg0: t, arg1: (arg0: key, arg1: V) => boolean): t; + +export function mapU(arg0: t, arg1: (arg0: V) => V2): t; + +export function mapWithKeyU(arg0: t, arg1: (arg0: key, arg1: V) => V2): t; + +export function mergeU( + arg0: t, + arg1: t, + arg2: (arg0: key, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): t; + +export function partitionU( + arg0: t, + arg1: (arg0: key, arg1: V) => boolean, +): [t, t]; + +export function reduceU( + arg0: t, + arg1: V2, + arg2: (arg0: V2, arg1: key, arg2: V) => V2, +): V2; + +export function someU(arg0: t, arg1: (arg0: key, arg1: V) => boolean): boolean; + +export function updateU( + arg0: t, + arg1: key, + arg2: (arg0: rescript.option) => rescript.option, +): t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MapString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MapString.d.ts new file mode 100644 index 0000000000..1bc7840403 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MapString.d.ts @@ -0,0 +1,166 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type key = string; + +export type t = rescript.opaque<"Belt_MapString.t", [Value]>; + +export const empty: t; + +export function isEmpty(arg0: t): boolean; + +export function minKey(arg0: t): rescript.option; + +export function minKeyUndefined(arg0: t): Js.undefined_; + +export function maxKey(arg0: t): rescript.option; + +export function maxKeyUndefined(arg0: t): Js.undefined_; + +export function minimum(arg0: t): rescript.option<[key, V]>; + +export function minUndefined(arg0: t): Js.undefined_<[key, V]>; + +export function maximum(arg0: t): rescript.option<[key, V]>; + +export function maxUndefined(arg0: t): Js.undefined_<[key, V]>; + +export function findFirstBy( + arg0: t, + arg1: (arg0: key, arg1: V) => boolean, +): rescript.option<[key, V]>; + +export function forEach(arg0: t, arg1: (arg0: key, arg1: V) => void): void; + +export function map(arg0: t, arg1: (arg0: V) => V2): t; + +export function mapWithKey(arg0: t, arg1: (arg0: key, arg1: V) => V2): t; + +export function reduce( + arg0: t, + arg1: V2, + arg2: (arg0: V2, arg1: key, arg2: V) => V2, +): V2; + +export function every(arg0: t, arg1: (arg0: key, arg1: V) => boolean): boolean; + +export function some(arg0: t, arg1: (arg0: key, arg1: V) => boolean): boolean; + +export function keep(arg0: t, arg1: (arg0: key, arg1: V) => boolean): t; + +export function partition( + arg0: t, + arg1: (arg0: key, arg1: V) => boolean, +): [t, t]; + +export function size(arg0: t): number; + +export function toList(arg0: t): rescript.list<[key, V]>; + +export function toArray(arg0: t): [key, V][]; + +export function keysToArray(arg0: t): key[]; + +export function valuesToArray(arg0: t): V[]; + +export function checkInvariantInternal(arg0: t): void; + +export function set(t: t, newK: key, newD: V): t; + +export function update( + t: t, + x: key, + f: (arg0: rescript.option) => rescript.option, +): t; + +export function remove(n: t, x: key): t; + +export function removeMany(t: t, keys: key[]): t; + +export function mergeMany(h: t, arr: [key, V][]): t; + +export function has(arg0: t, arg1: key): boolean; + +export function cmp( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => number, +): number; + +export function eq( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => boolean, +): boolean; + +export function get(arg0: t, arg1: key): rescript.option; + +export function getUndefined(arg0: t, arg1: key): Js.undefined_; + +export function getWithDefault(arg0: t, arg1: key, arg2: V): V; + +export function getOrThrow(arg0: t, arg1: key): V; + +export function getExn(arg0: t, arg1: key): V; + +export function split(arg0: key, arg1: t): [t, rescript.option, t]; + +export function merge( + arg0: t, + arg1: t, + arg2: (arg0: key, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): t; + +export function fromArray(arg0: [key, V][]): t; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: V, arg1: V) => boolean, +): boolean; + +export function everyU(arg0: t, arg1: (arg0: key, arg1: V) => boolean): boolean; + +export function findFirstByU( + arg0: t, + arg1: (arg0: key, arg1: V) => boolean, +): rescript.option<[key, V]>; + +export function forEachU(arg0: t, arg1: (arg0: key, arg1: V) => void): void; + +export function keepU(arg0: t, arg1: (arg0: key, arg1: V) => boolean): t; + +export function mapU(arg0: t, arg1: (arg0: V) => V2): t; + +export function mapWithKeyU(arg0: t, arg1: (arg0: key, arg1: V) => V2): t; + +export function mergeU( + arg0: t, + arg1: t, + arg2: (arg0: key, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): t; + +export function partitionU( + arg0: t, + arg1: (arg0: key, arg1: V) => boolean, +): [t, t]; + +export function reduceU( + arg0: t, + arg1: V2, + arg2: (arg0: V2, arg1: key, arg2: V) => V2, +): V2; + +export function someU(arg0: t, arg1: (arg0: key, arg1: V) => boolean): boolean; + +export function updateU( + arg0: t, + arg1: key, + arg2: (arg0: rescript.option) => rescript.option, +): t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MutableMap.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MutableMap.d.ts new file mode 100644 index 0000000000..f756fc9fd0 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MutableMap.d.ts @@ -0,0 +1,136 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_Id from "./Belt_Id.js"; +import type * as Js from "./Js.js"; + +export type t = rescript.opaque<"Belt_MutableMap.t", [K, V, Id]>; + +export type id = Belt_Id.comparable; + +export function remove(d: t, k: K): void; + +export function removeMany(d: t, xs: K[]): void; + +export function update( + t: t, + x: K, + f: (arg0: rescript.option) => rescript.option, +): void; + +export function make(id: id): t; + +export function clear(m: t): void; + +export function isEmpty(d: t): boolean; + +export function minKey(m: t): rescript.option; + +export function minKeyUndefined(m: t): Js.undefined_; + +export function maxKey(m: t): rescript.option; + +export function maxKeyUndefined(m: t): Js.undefined_; + +export function minimum(m: t): rescript.option<[K, A]>; + +export function minUndefined(m: t): Js.undefined_<[K, A]>; + +export function maximum(m: t): rescript.option<[K, A]>; + +export function maxUndefined(m: t): Js.undefined_<[K, A]>; + +export function forEach(d: t, f: (arg0: K, arg1: A) => void): void; + +export function reduce(d: t, acc: B, cb: (arg0: B, arg1: K, arg2: A) => B): B; + +export function every(d: t, p: (arg0: K, arg1: A) => boolean): boolean; + +export function some(d: t, p: (arg0: K, arg1: A) => boolean): boolean; + +export function size(d: t): number; + +export function toList(d: t): rescript.list<[K, A]>; + +export function toArray(d: t): [K, A][]; + +export function keysToArray(d: t): K[]; + +export function valuesToArray(d: t): A[]; + +export function checkInvariantInternal(d: t): void; + +export function cmp( + m1: t, + m2: t, + cmp: (arg0: A, arg1: A) => number, +): number; + +export function eq( + m1: t, + m2: t, + cmp: (arg0: A, arg1: A) => boolean, +): boolean; + +export function map(m: t, f: (arg0: A) => B): t; + +export function mapWithKey(m: t, f: (arg0: K, arg1: A) => B): t; + +export function get(m: t, x: K): rescript.option; + +export function getUndefined(m: t, x: K): Js.undefined_; + +export function getWithDefault(m: t, x: K, def: A): A; + +export function getOrThrow(m: t, x: K): A; + +export function getExn(arg0: t, arg1: K): A; + +export function has(m: t, x: K): boolean; + +export function fromArray(data: [K, A][], id: id): t; + +export function set(m: t, e: K, v: A): void; + +export function mergeMany(d: t, xs: [K, A][]): void; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => boolean, +): boolean; + +export function everyU( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): boolean; + +export function forEachU(arg0: t, arg1: (arg0: K, arg1: A) => void): void; + +export function mapU(arg0: t, arg1: (arg0: A) => B): t; + +export function mapWithKeyU( + arg0: t, + arg1: (arg0: K, arg1: A) => B, +): t; + +export function reduceU( + arg0: t, + arg1: B, + arg2: (arg0: B, arg1: K, arg2: A) => B, +): B; + +export function someU( + arg0: t, + arg1: (arg0: K, arg1: A) => boolean, +): boolean; + +export function updateU( + arg0: t, + arg1: K, + arg2: (arg0: rescript.option) => rescript.option, +): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MutableMapInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MutableMapInt.d.ts new file mode 100644 index 0000000000..05435c50b5 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MutableMapInt.d.ts @@ -0,0 +1,116 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type key = number; + +export type t = rescript.opaque<"Belt_MutableMapInt.t", [A]>; + +export function make(): t; + +export function isEmpty(m: t): boolean; + +export function clear(m: t): void; + +export function minKeyUndefined(m: t): Js.undefined_; + +export function minKey(m: t): rescript.option; + +export function maxKeyUndefined(m: t): Js.undefined_; + +export function maxKey(m: t): rescript.option; + +export function minimum(m: t): rescript.option<[key, A]>; + +export function minUndefined(m: t): Js.undefined_<[key, A]>; + +export function maximum(m: t): rescript.option<[key, A]>; + +export function maxUndefined(m: t): Js.undefined_<[key, A]>; + +export function set(m: t, k: key, v: A): void; + +export function forEach(d: t, f: (arg0: key, arg1: A) => void): void; + +export function map(d: t, f: (arg0: A) => B): t; + +export function mapWithKey(d: t, f: (arg0: key, arg1: A) => B): t; + +export function reduce(d: t, acc: B, f: (arg0: B, arg1: key, arg2: A) => B): B; + +export function every(d: t, f: (arg0: key, arg1: A) => boolean): boolean; + +export function some(d: t, f: (arg0: key, arg1: A) => boolean): boolean; + +export function size(d: t): number; + +export function toList(d: t): rescript.list<[key, A]>; + +export function toArray(d: t): [key, A][]; + +export function keysToArray(d: t): key[]; + +export function valuesToArray(d: t): A[]; + +export function checkInvariantInternal(d: t): void; + +export function has(d: t, v: key): boolean; + +export function remove(d: t, v: key): void; + +export function update( + t: t, + x: key, + f: (arg0: rescript.option) => rescript.option, +): void; + +export function removeMany(d: t, xs: key[]): void; + +export function fromArray(xs: [key, A][]): t; + +export function cmp(d0: t, d1: t, f: (arg0: A, arg1: A) => number): number; + +export function eq(d0: t, d1: t, f: (arg0: A, arg1: A) => boolean): boolean; + +export function get(d: t, x: key): rescript.option; + +export function getUndefined(d: t, x: key): Js.undefined_; + +export function getWithDefault(d: t, x: key, def: A): A; + +export function getOrThrow(d: t, x: key): A; + +export function getExn(arg0: t, arg1: key): A; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => boolean, +): boolean; + +export function everyU(arg0: t, arg1: (arg0: key, arg1: A) => boolean): boolean; + +export function forEachU(arg0: t, arg1: (arg0: key, arg1: A) => void): void; + +export function mapU(arg0: t, arg1: (arg0: A) => B): t; + +export function mapWithKeyU(arg0: t, arg1: (arg0: key, arg1: A) => B): t; + +export function reduceU( + arg0: t, + arg1: B, + arg2: (arg0: B, arg1: key, arg2: A) => B, +): B; + +export function someU(arg0: t, arg1: (arg0: key, arg1: A) => boolean): boolean; + +export function updateU( + arg0: t, + arg1: key, + arg2: (arg0: rescript.option) => rescript.option, +): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MutableMapString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MutableMapString.d.ts new file mode 100644 index 0000000000..09e4570a01 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MutableMapString.d.ts @@ -0,0 +1,116 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type key = string; + +export type t = rescript.opaque<"Belt_MutableMapString.t", [A]>; + +export function make(): t; + +export function isEmpty(m: t): boolean; + +export function clear(m: t): void; + +export function minKeyUndefined(m: t): Js.undefined_; + +export function minKey(m: t): rescript.option; + +export function maxKeyUndefined(m: t): Js.undefined_; + +export function maxKey(m: t): rescript.option; + +export function minimum(m: t): rescript.option<[key, A]>; + +export function minUndefined(m: t): Js.undefined_<[key, A]>; + +export function maximum(m: t): rescript.option<[key, A]>; + +export function maxUndefined(m: t): Js.undefined_<[key, A]>; + +export function set(m: t, k: key, v: A): void; + +export function forEach(d: t, f: (arg0: key, arg1: A) => void): void; + +export function map(d: t, f: (arg0: A) => B): t; + +export function mapWithKey(d: t, f: (arg0: key, arg1: A) => B): t; + +export function reduce(d: t, acc: B, f: (arg0: B, arg1: key, arg2: A) => B): B; + +export function every(d: t, f: (arg0: key, arg1: A) => boolean): boolean; + +export function some(d: t, f: (arg0: key, arg1: A) => boolean): boolean; + +export function size(d: t): number; + +export function toList(d: t): rescript.list<[key, A]>; + +export function toArray(d: t): [key, A][]; + +export function keysToArray(d: t): key[]; + +export function valuesToArray(d: t): A[]; + +export function checkInvariantInternal(d: t): void; + +export function has(d: t, v: key): boolean; + +export function remove(d: t, v: key): void; + +export function update( + t: t, + x: key, + f: (arg0: rescript.option) => rescript.option, +): void; + +export function removeMany(d: t, xs: key[]): void; + +export function fromArray(xs: [key, A][]): t; + +export function cmp(d0: t, d1: t, f: (arg0: A, arg1: A) => number): number; + +export function eq(d0: t, d1: t, f: (arg0: A, arg1: A) => boolean): boolean; + +export function get(d: t, x: key): rescript.option; + +export function getUndefined(d: t, x: key): Js.undefined_; + +export function getWithDefault(d: t, x: key, def: A): A; + +export function getOrThrow(d: t, x: key): A; + +export function getExn(arg0: t, arg1: key): A; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: A) => boolean, +): boolean; + +export function everyU(arg0: t, arg1: (arg0: key, arg1: A) => boolean): boolean; + +export function forEachU(arg0: t, arg1: (arg0: key, arg1: A) => void): void; + +export function mapU(arg0: t, arg1: (arg0: A) => B): t; + +export function mapWithKeyU(arg0: t, arg1: (arg0: key, arg1: A) => B): t; + +export function reduceU( + arg0: t, + arg1: B, + arg2: (arg0: B, arg1: key, arg2: A) => B, +): B; + +export function someU(arg0: t, arg1: (arg0: key, arg1: A) => boolean): boolean; + +export function updateU( + arg0: t, + arg1: key, + arg2: (arg0: rescript.option) => rescript.option, +): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MutableQueue.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MutableQueue.d.ts new file mode 100644 index 0000000000..84689a09d9 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MutableQueue.d.ts @@ -0,0 +1,50 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type t = rescript.opaque<"Belt_MutableQueue.t", [A]>; + +export function make(): t; + +export function clear(q: t): void; + +export function add(q: t, x: A): void; + +export function peek(q: t): rescript.option; + +export function peekUndefined(q: t): Js.undefined_; + +export function peekOrThrow(q: t): A; + +export function peekExn(arg0: t): A; + +export function pop(q: t): rescript.option; + +export function popOrThrow(q: t): A; + +export function popExn(arg0: t): A; + +export function popUndefined(q: t): Js.undefined_; + +export function copy(q: t): t; + +export function map(q: t, f: (arg0: A) => B): t; + +export function isEmpty(q: t): boolean; + +export function size(q: t): number; + +export function forEach(q: t, f: (arg0: A) => void): void; + +export function reduce(q: t, accu: B, f: (arg0: B, arg1: A) => B): B; + +export function transfer(q1: t, q2: t): void; + +export function toArray(x: t): A[]; + +export function fromArray(arr: A[]): t; + +export function forEachU(arg0: t, arg1: (arg0: A) => void): void; + +export function mapU(arg0: t, arg1: (arg0: A) => B): t; + +export function reduceU(arg0: t, arg1: B, arg2: (arg0: B, arg1: A) => B): B; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MutableSet.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MutableSet.d.ts new file mode 100644 index 0000000000..26d9693c4c --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MutableSet.d.ts @@ -0,0 +1,118 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_Id from "./Belt_Id.js"; +import type * as Js from "./Js.js"; + +export type t = rescript.opaque<"Belt_MutableSet.t", [Value, Identity]>; + +export type id = Belt_Id.comparable; + +export function remove(d: t, v: Value): void; + +export function removeMany(d: t, xs: Value[]): void; + +export function removeCheck(d: t, v: Value): boolean; + +export function addCheck(m: t, e: Value): boolean; + +export function add(m: t, e: Value): void; + +export function mergeMany(d: t, xs: Value[]): void; + +export function make(id: id): t; + +export function isEmpty(d: t): boolean; + +export function minimum(d: t): rescript.option; + +export function minUndefined(d: t): Js.undefined_; + +export function maximum(d: t): rescript.option; + +export function maxUndefined(d: t): Js.undefined_; + +export function forEach(d: t, f: (arg0: Value) => void): void; + +export function reduce(d: t, acc: A, cb: (arg0: A, arg1: Value) => A): A; + +export function every(d: t, p: (arg0: Value) => boolean): boolean; + +export function some(d: t, p: (arg0: Value) => boolean): boolean; + +export function size(d: t): number; + +export function toList(d: t): rescript.list; + +export function toArray(d: t): Value[]; + +export function fromSortedArrayUnsafe( + xs: Value[], + id: id, +): t; + +export function checkInvariantInternal(d: t): void; + +export function fromArray(data: Value[], id: id): t; + +export function cmp(d0: t, d1: t): number; + +export function eq(d0: t, d1: t): boolean; + +export function get(d: t, x: Value): rescript.option; + +export function getUndefined(d: t, x: Value): Js.undefined_; + +export function getOrThrow(d: t, x: Value): Value; + +export function getExn(arg0: t, arg1: Value): Value; + +export function split( + d: t, + key: Value, +): [[t, t], boolean]; + +export function keep(d: t, p: (arg0: Value) => boolean): t; + +export function partition( + d: t, + p: (arg0: Value) => boolean, +): [t, t]; + +export function subset(a: t, b: t): boolean; + +export function intersect(a: t, b: t): t; + +export function diff(a: t, b: t): t; + +export function union(a: t, b: t): t; + +export function has(d: t, x: Value): boolean; + +export function copy(d: t): t; + +export function everyU( + arg0: t, + arg1: (arg0: Value) => boolean, +): boolean; + +export function forEachU(arg0: t, arg1: (arg0: Value) => void): void; + +export function keepU( + arg0: t, + arg1: (arg0: Value) => boolean, +): t; + +export function partitionU( + arg0: t, + arg1: (arg0: Value) => boolean, +): [t, t]; + +export function reduceU( + arg0: t, + arg1: A, + arg2: (arg0: A, arg1: Value) => A, +): A; + +export function someU( + arg0: t, + arg1: (arg0: Value) => boolean, +): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MutableSetInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MutableSetInt.d.ts new file mode 100644 index 0000000000..b92a57483c --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MutableSetInt.d.ts @@ -0,0 +1,92 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type value = number; + +export type t = rescript.opaque<"Belt_MutableSetInt.t", []>; + +export function remove(d: t, v: value): void; + +export function removeMany(d: t, xs: value[]): void; + +export function removeCheck(d: t, v: value): boolean; + +export function addCheck(m: t, e: value): boolean; + +export function add(d: t, k: value): void; + +export function mergeMany(d: t, arr: value[]): void; + +export function make(): t; + +export function isEmpty(d: t): boolean; + +export function minimum(d: t): rescript.option; + +export function minUndefined(d: t): Js.undefined_; + +export function maximum(d: t): rescript.option; + +export function maxUndefined(d: t): Js.undefined_; + +export function forEach(d: t, f: (arg0: value) => void): void; + +export function reduce(d: t, acc: A, cb: (arg0: A, arg1: value) => A): A; + +export function every(d: t, p: (arg0: value) => boolean): boolean; + +export function some(d: t, p: (arg0: value) => boolean): boolean; + +export function size(d: t): number; + +export function toList(d: t): rescript.list; + +export function toArray(d: t): value[]; + +export function fromSortedArrayUnsafe(xs: value[]): t; + +export function checkInvariantInternal(d: t): void; + +export function fromArray(xs: value[]): t; + +export function cmp(d0: t, d1: t): number; + +export function eq(d0: t, d1: t): boolean; + +export function get(d: t, x: value): rescript.option; + +export function getUndefined(d: t, x: value): Js.undefined_; + +export function getOrThrow(d: t, x: value): value; + +export function getExn(arg0: t, arg1: value): value; + +export function split(d: t, key: value): [[t, t], boolean]; + +export function keep(d: t, p: (arg0: value) => boolean): t; + +export function partition(d: t, p: (arg0: value) => boolean): [t, t]; + +export function subset(a: t, b: t): boolean; + +export function intersect(dataa: t, datab: t): t; + +export function diff(dataa: t, datab: t): t; + +export function union(dataa: t, datab: t): t; + +export function has(d: t, x: value): boolean; + +export function copy(d: t): t; + +export function everyU(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function forEachU(arg0: t, arg1: (arg0: value) => void): void; + +export function keepU(arg0: t, arg1: (arg0: value) => boolean): t; + +export function partitionU(arg0: t, arg1: (arg0: value) => boolean): [t, t]; + +export function reduceU(arg0: t, arg1: A, arg2: (arg0: A, arg1: value) => A): A; + +export function someU(arg0: t, arg1: (arg0: value) => boolean): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MutableSetString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MutableSetString.d.ts new file mode 100644 index 0000000000..ce95fd0acc --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MutableSetString.d.ts @@ -0,0 +1,92 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type value = string; + +export type t = rescript.opaque<"Belt_MutableSetString.t", []>; + +export function remove(d: t, v: value): void; + +export function removeMany(d: t, xs: value[]): void; + +export function removeCheck(d: t, v: value): boolean; + +export function addCheck(m: t, e: value): boolean; + +export function add(d: t, k: value): void; + +export function mergeMany(d: t, arr: value[]): void; + +export function make(): t; + +export function isEmpty(d: t): boolean; + +export function minimum(d: t): rescript.option; + +export function minUndefined(d: t): Js.undefined_; + +export function maximum(d: t): rescript.option; + +export function maxUndefined(d: t): Js.undefined_; + +export function forEach(d: t, f: (arg0: value) => void): void; + +export function reduce(d: t, acc: A, cb: (arg0: A, arg1: value) => A): A; + +export function every(d: t, p: (arg0: value) => boolean): boolean; + +export function some(d: t, p: (arg0: value) => boolean): boolean; + +export function size(d: t): number; + +export function toList(d: t): rescript.list; + +export function toArray(d: t): value[]; + +export function fromSortedArrayUnsafe(xs: value[]): t; + +export function checkInvariantInternal(d: t): void; + +export function fromArray(xs: value[]): t; + +export function cmp(d0: t, d1: t): number; + +export function eq(d0: t, d1: t): boolean; + +export function get(d: t, x: value): rescript.option; + +export function getUndefined(d: t, x: value): Js.undefined_; + +export function getOrThrow(d: t, x: value): value; + +export function getExn(arg0: t, arg1: value): value; + +export function split(d: t, key: value): [[t, t], boolean]; + +export function keep(d: t, p: (arg0: value) => boolean): t; + +export function partition(d: t, p: (arg0: value) => boolean): [t, t]; + +export function subset(a: t, b: t): boolean; + +export function intersect(dataa: t, datab: t): t; + +export function diff(dataa: t, datab: t): t; + +export function union(dataa: t, datab: t): t; + +export function has(d: t, x: value): boolean; + +export function copy(d: t): t; + +export function everyU(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function forEachU(arg0: t, arg1: (arg0: value) => void): void; + +export function keepU(arg0: t, arg1: (arg0: value) => boolean): t; + +export function partitionU(arg0: t, arg1: (arg0: value) => boolean): [t, t]; + +export function reduceU(arg0: t, arg1: A, arg2: (arg0: A, arg1: value) => A): A; + +export function someU(arg0: t, arg1: (arg0: value) => boolean): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Belt_MutableStack.d.ts b/packages/@rescript/runtime/lib/es6/Belt_MutableStack.d.ts new file mode 100644 index 0000000000..adb95f17d1 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_MutableStack.d.ts @@ -0,0 +1,32 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type t = rescript.opaque<"Belt_MutableStack.t", [A]>; + +export function make(): t; + +export function clear(s: t): void; + +export function copy(s: t): t; + +export function push(s: t, x: A): void; + +export function topUndefined(s: t): Js.undefined_; + +export function top(s: t): rescript.option; + +export function isEmpty(s: t): boolean; + +export function popUndefined(s: t): Js.undefined_; + +export function pop(s: t): rescript.option; + +export function size(s: t): number; + +export function forEach(s: t, f: (arg0: A) => void): void; + +export function dynamicPopIter(s: t, f: (arg0: A) => void): void; + +export function dynamicPopIterU(arg0: t, arg1: (arg0: A) => void): void; + +export function forEachU(arg0: t, arg1: (arg0: A) => void): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_Option.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Option.d.ts new file mode 100644 index 0000000000..29a9f8bfa7 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Option.d.ts @@ -0,0 +1,80 @@ +import type * as rescript from "@rescript/runtime/types"; + +export function keep( + opt: rescript.option, + p: (arg0: A) => boolean, +): rescript.option; + +export function forEach(opt: rescript.option, f: (arg0: A) => void): void; + +export function getOrThrow(x: rescript.option): A; + +export function getExn(arg0: rescript.option): A; + +export function mapWithDefault( + opt: rescript.option, + default_: B, + f: (arg0: A) => B, +): B; + +export function map(opt: rescript.option, f: (arg0: A) => B): rescript.option; + +export function flatMap( + opt: rescript.option, + f: (arg0: A) => rescript.option, +): rescript.option; + +export function getWithDefault(opt: rescript.option, default_: A): A; + +export function orElse( + opt: rescript.option, + other: rescript.option, +): rescript.option; + +export function isSome(x: rescript.option): boolean; + +export function isNone(x: rescript.option): boolean; + +export function eq( + a: rescript.option, + b: rescript.option, + f: (arg0: A, arg1: B) => boolean, +): boolean; + +export function cmp( + a: rescript.option, + b: rescript.option, + f: (arg0: A, arg1: B) => number, +): number; + +export function cmpU( + arg0: rescript.option, + arg1: rescript.option, + arg2: (arg0: A, arg1: B) => number, +): number; + +export function eqU( + arg0: rescript.option, + arg1: rescript.option, + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function flatMapU( + arg0: rescript.option, + arg1: (arg0: A) => rescript.option, +): rescript.option; + +export function forEachU(arg0: rescript.option, arg1: (arg0: A) => void): void; + +export function keepU( + arg0: rescript.option, + arg1: (arg0: A) => boolean, +): rescript.option; + +export function mapU(arg0: rescript.option, arg1: (arg0: A) => B): rescript.option; + +export function mapWithDefaultU( + arg0: rescript.option, + arg1: B, + arg2: (arg0: A) => B, +): B; diff --git a/packages/@rescript/runtime/lib/es6/Belt_Range.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Range.d.ts new file mode 100644 index 0000000000..37445b3b9e --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Range.d.ts @@ -0,0 +1,63 @@ +export function forEach( + s: number, + f: number, + action: (arg0: number) => void, +): void; + +export function every( + s: number, + f: number, + p: (arg0: number) => boolean, +): boolean; + +export function everyBy( + s: number, + f: number, + step: number, + p: (arg0: number) => boolean, +): boolean; + +export function some( + s: number, + f: number, + p: (arg0: number) => boolean, +): boolean; + +export function someBy( + s: number, + f: number, + step: number, + p: (arg0: number) => boolean, +): boolean; + +export function everyByU( + arg0: number, + arg1: number, + step: number, + arg3: (arg0: number) => boolean, +): boolean; + +export function everyU( + arg0: number, + arg1: number, + arg2: (arg0: number) => boolean, +): boolean; + +export function forEachU( + arg0: number, + arg1: number, + arg2: (arg0: number) => void, +): void; + +export function someByU( + arg0: number, + arg1: number, + step: number, + arg3: (arg0: number) => boolean, +): boolean; + +export function someU( + arg0: number, + arg1: number, + arg2: (arg0: number) => boolean, +): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Belt_Result.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Result.d.ts new file mode 100644 index 0000000000..3e162d7e55 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Result.d.ts @@ -0,0 +1,45 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = rescript.result; + +export function getOrThrow(x: t): A; + +export function getExn(arg0: t): A; + +export function mapWithDefault(opt: t, default_: B, f: (arg0: A) => B): B; + +export function map(opt: t, f: (arg0: A) => B): t; + +export function flatMap(opt: t, f: (arg0: A) => t): t; + +export function getWithDefault(opt: t, default_: A): A; + +export function isOk(x: t): boolean; + +export function isError(x: t): boolean; + +export function eq( + a: t, + b: t, + f: (arg0: A, arg1: B) => boolean, +): boolean; + +export function cmp(a: t, b: t, f: (arg0: A, arg1: B) => number): number; + +export function cmpU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: B) => number, +): number; + +export function eqU( + arg0: t, + arg1: t, + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function flatMapU(arg0: t, arg1: (arg0: A) => t): t; + +export function mapU(arg0: t, arg1: (arg0: A) => B): t; + +export function mapWithDefaultU(arg0: t, arg1: B, arg2: (arg0: A) => B): B; diff --git a/packages/@rescript/runtime/lib/es6/Belt_Set.d.ts b/packages/@rescript/runtime/lib/es6/Belt_Set.d.ts new file mode 100644 index 0000000000..ed55b0383e --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_Set.d.ts @@ -0,0 +1,122 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_SetDict from "./Belt_SetDict.js"; +import type * as Belt_Id from "./Belt_Id.js"; +import type * as Js from "./Js.js"; + +export type t = rescript.opaque<"Belt_Set.t", [Value, Identity]>; + +export type id = Belt_Id.comparable; + +export function fromArray(data: Value[], id: id): t; + +export function remove(m: t, e: Value): t; + +export function add(m: t, e: Value): t; + +export function mergeMany(m: t, e: Value[]): t; + +export function removeMany(m: t, e: Value[]): t; + +export function union(m: t, n: t): t; + +export function intersect(m: t, n: t): t; + +export function diff(m: t, n: t): t; + +export function subset(m: t, n: t): boolean; + +export function split( + m: t, + e: Value, +): [[t, t], boolean]; + +export function make(id: id): t; + +export function isEmpty(m: t): boolean; + +export function cmp(m: t, n: t): number; + +export function eq(m: t, n: t): boolean; + +export function forEach(m: t, f: (arg0: Value) => void): void; + +export function reduce(m: t, acc: A, f: (arg0: A, arg1: Value) => A): A; + +export function every(m: t, f: (arg0: Value) => boolean): boolean; + +export function some(m: t, f: (arg0: Value) => boolean): boolean; + +export function keep(m: t, f: (arg0: Value) => boolean): t; + +export function partition( + m: t, + f: (arg0: Value) => boolean, +): [t, t]; + +export function size(m: t): number; + +export function toList(m: t): rescript.list; + +export function toArray(m: t): Value[]; + +export function minimum(m: t): rescript.option; + +export function minUndefined(m: t): Js.undefined_; + +export function maximum(m: t): rescript.option; + +export function maxUndefined(m: t): Js.undefined_; + +export function get(m: t, e: Value): rescript.option; + +export function getUndefined(m: t, e: Value): Js.undefined_; + +export function getOrThrow(m: t, e: Value): Value; + +export function getExn(arg0: t, arg1: Value): Value; + +export function has(m: t, e: Value): boolean; + +export function fromSortedArrayUnsafe( + xs: Value[], + id: id, +): t; + +export function getData(m: t): Belt_SetDict.t; + +export function getId(m: t): id; + +export function packIdData( + id: id, + data: Belt_SetDict.t, +): t; + +export function checkInvariantInternal(d: t): void; + +export function everyU( + arg0: t, + arg1: (arg0: Value) => boolean, +): boolean; + +export function forEachU(arg0: t, arg1: (arg0: Value) => void): void; + +export function keepU( + arg0: t, + arg1: (arg0: Value) => boolean, +): t; + +export function partitionU( + arg0: t, + arg1: (arg0: Value) => boolean, +): [t, t]; + +export function reduceU( + arg0: t, + arg1: A, + arg2: (arg0: A, arg1: Value) => A, +): A; + +export function someU( + arg0: t, + arg1: (arg0: Value) => boolean, +): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Belt_SetDict.d.ts b/packages/@rescript/runtime/lib/es6/Belt_SetDict.d.ts new file mode 100644 index 0000000000..cc80c783a7 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_SetDict.d.ts @@ -0,0 +1,183 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_Id from "./Belt_Id.js"; +import type * as Js from "./Js.js"; + +export type t = rescript.opaque<"Belt_SetDict.t", [Value, Identity]>; + +export type cmp = Belt_Id.cmp; + +export function add( + t: t, + x: Value, + cmp: cmp, +): t; + +export function remove( + t: t, + x: Value, + cmp: cmp, +): t; + +export function mergeMany( + h: t, + arr: Value[], + cmp: cmp, +): t; + +export function removeMany( + h: t, + arr: Value[], + cmp: cmp, +): t; + +export function split( + t: t, + x: Value, + cmp: cmp, +): [[t, t], boolean]; + +export function union( + s1: t, + s2: t, + cmp: cmp, +): t; + +export function intersect( + s1: t, + s2: t, + cmp: cmp, +): t; + +export function diff( + s1: t, + s2: t, + cmp: cmp, +): t; + +export const empty: t; + +export function fromArray(arg0: Value[], cmp: cmp): t; + +export function isEmpty(arg0: t): boolean; + +export function cmp( + arg0: t, + arg1: t, + cmp: cmp, +): number; + +export function eq( + arg0: t, + arg1: t, + cmp: cmp, +): boolean; + +export function has( + arg0: t, + arg1: Value, + cmp: cmp, +): boolean; + +export function forEachU(arg0: t, arg1: (arg0: Value) => void): void; + +export function forEach(arg0: t, arg1: (arg0: Value) => void): void; + +export function reduceU( + arg0: t, + arg1: A, + arg2: (arg0: A, arg1: Value) => A, +): A; + +export function reduce( + arg0: t, + arg1: A, + arg2: (arg0: A, arg1: Value) => A, +): A; + +export function everyU( + arg0: t, + arg1: (arg0: Value) => boolean, +): boolean; + +export function every( + arg0: t, + arg1: (arg0: Value) => boolean, +): boolean; + +export function someU( + arg0: t, + arg1: (arg0: Value) => boolean, +): boolean; + +export function some( + arg0: t, + arg1: (arg0: Value) => boolean, +): boolean; + +export function size(arg0: t): number; + +export function toList(arg0: t): rescript.list; + +export function toArray(arg0: t): Value[]; + +export function minimum(arg0: t): rescript.option; + +export function maximum(arg0: t): rescript.option; + +export function maxUndefined(arg0: t): Js.undefined_; + +export function minUndefined(arg0: t): Js.undefined_; + +export function get( + arg0: t, + arg1: Value, + cmp: cmp, +): rescript.option; + +export function getOrThrow( + arg0: t, + arg1: Value, + cmp: cmp, +): Value; + +export function getExn( + arg0: t, + arg1: Value, + cmp: cmp, +): Value; + +export function getUndefined( + arg0: t, + arg1: Value, + cmp: cmp, +): Js.undefined_; + +export function fromSortedArrayUnsafe(arg0: Value[]): t; + +export function subset( + arg0: t, + arg1: t, + cmp: cmp, +): boolean; + +export function keep( + arg0: t, + arg1: (arg0: Value) => boolean, +): t; + +export function keepU( + arg0: t, + arg1: (arg0: Value) => boolean, +): t; + +export function partitionU( + arg0: t, + arg1: (arg0: Value) => boolean, +): [t, t]; + +export function partition( + arg0: t, + arg1: (arg0: Value) => boolean, +): [t, t]; + +export function checkInvariantInternal(arg0: t): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_SetInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_SetInt.d.ts new file mode 100644 index 0000000000..1fd8cf936a --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_SetInt.d.ts @@ -0,0 +1,86 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type value = number; + +export type t = rescript.opaque<"Belt_SetInt.t", []>; + +export const empty: t; + +export function isEmpty(arg0: t): boolean; + +export function minimum(arg0: t): rescript.option; + +export function minUndefined(arg0: t): Js.undefined_; + +export function maximum(arg0: t): rescript.option; + +export function maxUndefined(arg0: t): Js.undefined_; + +export function forEach(arg0: t, arg1: (arg0: value) => void): void; + +export function reduce(arg0: t, arg1: A, arg2: (arg0: A, arg1: value) => A): A; + +export function every(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function some(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function keep(arg0: t, arg1: (arg0: value) => boolean): t; + +export function partition(arg0: t, arg1: (arg0: value) => boolean): [t, t]; + +export function size(arg0: t): number; + +export function toList(arg0: t): rescript.list; + +export function toArray(arg0: t): value[]; + +export function fromSortedArrayUnsafe(arg0: value[]): t; + +export function checkInvariantInternal(arg0: t): void; + +export function add(t: t, x: value): t; + +export function mergeMany(h: t, arr: value[]): t; + +export function remove(t: t, x: value): t; + +export function removeMany(h: t, arr: value[]): t; + +export function fromArray(arg0: value[]): t; + +export function cmp(arg0: t, arg1: t): number; + +export function eq(arg0: t, arg1: t): boolean; + +export function get(arg0: t, arg1: value): rescript.option; + +export function getUndefined(arg0: t, arg1: value): Js.undefined_; + +export function getOrThrow(arg0: t, arg1: value): value; + +export function getExn(arg0: t, arg1: value): value; + +export function subset(arg0: t, arg1: t): boolean; + +export function has(arg0: t, arg1: value): boolean; + +export function split(t: t, x: value): [[t, t], boolean]; + +export function union(s1: t, s2: t): t; + +export function intersect(s1: t, s2: t): t; + +export function diff(s1: t, s2: t): t; + +export function forEachU(arg0: t, arg1: (arg0: value) => void): void; + +export function reduceU(arg0: t, arg1: A, arg2: (arg0: A, arg1: value) => A): A; + +export function everyU(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function someU(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function keepU(arg0: t, arg1: (arg0: value) => boolean): t; + +export function partitionU(arg0: t, arg1: (arg0: value) => boolean): [t, t]; diff --git a/packages/@rescript/runtime/lib/es6/Belt_SetString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_SetString.d.ts new file mode 100644 index 0000000000..cc2956e6be --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_SetString.d.ts @@ -0,0 +1,86 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js from "./Js.js"; + +export type value = string; + +export type t = rescript.opaque<"Belt_SetString.t", []>; + +export const empty: t; + +export function isEmpty(arg0: t): boolean; + +export function minimum(arg0: t): rescript.option; + +export function minUndefined(arg0: t): Js.undefined_; + +export function maximum(arg0: t): rescript.option; + +export function maxUndefined(arg0: t): Js.undefined_; + +export function forEach(arg0: t, arg1: (arg0: value) => void): void; + +export function reduce(arg0: t, arg1: A, arg2: (arg0: A, arg1: value) => A): A; + +export function every(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function some(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function keep(arg0: t, arg1: (arg0: value) => boolean): t; + +export function partition(arg0: t, arg1: (arg0: value) => boolean): [t, t]; + +export function size(arg0: t): number; + +export function toList(arg0: t): rescript.list; + +export function toArray(arg0: t): value[]; + +export function fromSortedArrayUnsafe(arg0: value[]): t; + +export function checkInvariantInternal(arg0: t): void; + +export function add(t: t, x: value): t; + +export function mergeMany(h: t, arr: value[]): t; + +export function remove(t: t, x: value): t; + +export function removeMany(h: t, arr: value[]): t; + +export function fromArray(arg0: value[]): t; + +export function cmp(arg0: t, arg1: t): number; + +export function eq(arg0: t, arg1: t): boolean; + +export function get(arg0: t, arg1: value): rescript.option; + +export function getUndefined(arg0: t, arg1: value): Js.undefined_; + +export function getOrThrow(arg0: t, arg1: value): value; + +export function getExn(arg0: t, arg1: value): value; + +export function subset(arg0: t, arg1: t): boolean; + +export function has(arg0: t, arg1: value): boolean; + +export function split(t: t, x: value): [[t, t], boolean]; + +export function union(s1: t, s2: t): t; + +export function intersect(s1: t, s2: t): t; + +export function diff(s1: t, s2: t): t; + +export function forEachU(arg0: t, arg1: (arg0: value) => void): void; + +export function reduceU(arg0: t, arg1: A, arg2: (arg0: A, arg1: value) => A): A; + +export function everyU(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function someU(arg0: t, arg1: (arg0: value) => boolean): boolean; + +export function keepU(arg0: t, arg1: (arg0: value) => boolean): t; + +export function partitionU(arg0: t, arg1: (arg0: value) => boolean): [t, t]; diff --git a/packages/@rescript/runtime/lib/es6/Belt_SortArray.d.ts b/packages/@rescript/runtime/lib/es6/Belt_SortArray.d.ts new file mode 100644 index 0000000000..67469ccd93 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_SortArray.d.ts @@ -0,0 +1,108 @@ +export function strictlySortedLength( + xs: A[], + lt: (arg0: A, arg1: A) => boolean, +): number; + +export function isSorted(a: A[], cmp: (arg0: A, arg1: A) => number): boolean; + +export function union( + src: A[], + src1ofs: number, + src1len: number, + src2: A[], + src2ofs: number, + src2len: number, + dst: A[], + dstofs: number, + cmp: (arg0: A, arg1: A) => number, +): number; + +export function intersect( + src: A[], + src1ofs: number, + src1len: number, + src2: A[], + src2ofs: number, + src2len: number, + dst: A[], + dstofs: number, + cmp: (arg0: A, arg1: A) => number, +): number; + +export function diff( + src: A[], + src1ofs: number, + src1len: number, + src2: A[], + src2ofs: number, + src2len: number, + dst: A[], + dstofs: number, + cmp: (arg0: A, arg1: A) => number, +): number; + +export function stableSortInPlaceBy(a: A[], cmp: (arg0: A, arg1: A) => number): void; + +export function stableSortBy(a: A[], cmp: (arg0: A, arg1: A) => number): A[]; + +export function binarySearchBy( + sorted: A[], + key: A, + cmp: (arg0: A, arg1: A) => number, +): number; + +export function binarySearchByU( + arg0: A[], + arg1: A, + arg2: (arg0: A, arg1: A) => number, +): number; + +export function diffU( + arg0: A[], + arg1: number, + arg2: number, + arg3: A[], + arg4: number, + arg5: number, + arg6: A[], + arg7: number, + arg8: (arg0: A, arg1: A) => number, +): number; + +export function intersectU( + arg0: A[], + arg1: number, + arg2: number, + arg3: A[], + arg4: number, + arg5: number, + arg6: A[], + arg7: number, + arg8: (arg0: A, arg1: A) => number, +): number; + +export function isSortedU(arg0: A[], arg1: (arg0: A, arg1: A) => number): boolean; + +export function stableSortByU(arg0: A[], arg1: (arg0: A, arg1: A) => number): A[]; + +export function stableSortInPlaceByU( + arg0: A[], + arg1: (arg0: A, arg1: A) => number, +): void; + +export function strictlySortedLengthU( + arg0: A[], + arg1: (arg0: A, arg1: A) => boolean, +): number; + +export function unionU( + arg0: A[], + arg1: number, + arg2: number, + arg3: A[], + arg4: number, + arg5: number, + arg6: A[], + arg7: number, + arg8: (arg0: A, arg1: A) => number, +): number; diff --git a/packages/@rescript/runtime/lib/es6/Belt_SortArrayInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_SortArrayInt.d.ts new file mode 100644 index 0000000000..dba4b766c2 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_SortArrayInt.d.ts @@ -0,0 +1,44 @@ +export type element = number; + +export function strictlySortedLength(xs: element[]): number; + +export function isSorted(a: element[]): boolean; + +export function union( + src: element[], + src1ofs: number, + src1len: number, + src2: element[], + src2ofs: number, + src2len: number, + dst: element[], + dstofs: number, +): number; + +export function intersect( + src: element[], + src1ofs: number, + src1len: number, + src2: element[], + src2ofs: number, + src2len: number, + dst: element[], + dstofs: number, +): number; + +export function diff( + src: element[], + src1ofs: number, + src1len: number, + src2: element[], + src2ofs: number, + src2len: number, + dst: element[], + dstofs: number, +): number; + +export function stableSortInPlace(a: element[]): void; + +export function stableSort(a: element[]): element[]; + +export function binarySearch(sorted: element[], key: element): number; diff --git a/packages/@rescript/runtime/lib/es6/Belt_SortArrayString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_SortArrayString.d.ts new file mode 100644 index 0000000000..b4aa4c2d61 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_SortArrayString.d.ts @@ -0,0 +1,44 @@ +export type element = string; + +export function strictlySortedLength(xs: element[]): number; + +export function isSorted(a: element[]): boolean; + +export function union( + src: element[], + src1ofs: number, + src1len: number, + src2: element[], + src2ofs: number, + src2len: number, + dst: element[], + dstofs: number, +): number; + +export function intersect( + src: element[], + src1ofs: number, + src1len: number, + src2: element[], + src2ofs: number, + src2len: number, + dst: element[], + dstofs: number, +): number; + +export function diff( + src: element[], + src1ofs: number, + src1len: number, + src2: element[], + src2ofs: number, + src2len: number, + dst: element[], + dstofs: number, +): number; + +export function stableSortInPlace(a: element[]): void; + +export function stableSort(a: element[]): element[]; + +export function binarySearch(sorted: element[], key: element): number; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalAVLset.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalAVLset.d.ts new file mode 100644 index 0000000000..59df9c4cdb --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalAVLset.d.ts @@ -0,0 +1,107 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_Id from "./Belt_Id.js"; +import type * as Js from "./Js.js"; +import type * as Pervasives from "./Pervasives.js"; + +export type t = rescript.option>; + +export interface node { + v: Value; + h: number; + l: t; + r: t; +} + +export type cmp = Belt_Id.cmp; + +export function copy(n: t): t; + +export function create(l: t, v: A, r: t): t; + +export function singleton(x: A): t; + +export function bal(l: t, v: A, r: t): t; + +export function minimum(n: t): rescript.option; + +export function minUndefined(n: t): Js.undefined_; + +export function maximum(n: t): rescript.option; + +export function maxUndefined(n: t): Js.undefined_; + +export function removeMinAuxWithRef(n: node, v: Pervasives.ref): t; + +export function isEmpty(n: t): boolean; + +export function stackAllLeft( + v: t, + s: rescript.list>, +): rescript.list>; + +export function forEach(n: t, f: (arg0: A) => void): void; + +export function reduce(s: t, accu: B, f: (arg0: B, arg1: A) => B): B; + +export function every(n: t, p: (arg0: A) => boolean): boolean; + +export function some(n: t, p: (arg0: A) => boolean): boolean; + +export function joinShared(ln: t, v: A, rn: t): t; + +export function concatShared(t1: t, t2: t): t; + +export function partitionShared( + n: t, + p: (arg0: A) => boolean, +): [t, t]; + +export function lengthNode(n: node): number; + +export function size(n: t): number; + +export function toList(s: t): rescript.list; + +export function checkInvariantInternal(v: t): void; + +export function fillArray(n: node, i: number, arr: A[]): number; + +export function toArray(n: t): A[]; + +export function fromSortedArrayRevAux( + arr: A[], + off: number, + len: number, +): t; + +export function fromSortedArrayAux(arr: A[], off: number, len: number): t; + +export function fromSortedArrayUnsafe(arr: A[]): t; + +export function keepShared(n: t, p: (arg0: A) => boolean): t; + +export function keepCopy(n: t, p: (arg0: A) => boolean): t; + +export function partitionCopy(n: t, p: (arg0: A) => boolean): [t, t]; + +export function has(t: t, x: A, cmp: cmp): boolean; + +export function cmp(s1: t, s2: t, cmp: cmp): number; + +export function eq(s1: t, s2: t, cmp: cmp): boolean; + +export function subset(s1: t, s2: t, cmp: cmp): boolean; + +export function get(n: t, x: A, cmp: cmp): rescript.option; + +export function getUndefined(n: t, x: A, cmp: cmp): Js.undefined_; + +export function getOrThrow(n: t, x: A, cmp: cmp): A; + +export function balMutate(nt: node): node; + +export function addMutate(cmp: cmp, t: t, x: A): t; + +export function fromArray(xs: A[], cmp: cmp): t; + +export function removeMinAuxWithRootMutate(nt: node, n: node): t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalAVLtree.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalAVLtree.d.ts new file mode 100644 index 0000000000..78260f7290 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalAVLtree.d.ts @@ -0,0 +1,169 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_Id from "./Belt_Id.js"; +import type * as Js from "./Js.js"; +import type * as Pervasives from "./Pervasives.js"; + +export type t = rescript.option>; + +export interface node { + k: K; + v: V; + h: number; + l: t; + r: t; +} + +export type cmp = Belt_Id.cmp; + +export function copy(n: t): t; + +export function create(l: t, x: A, d: B, r: t): t; + +export function singleton(x: A, d: B): t; + +export function updateValue(n: node, newValue: V): node; + +export function bal(l: t, x: A, d: B, r: t): t; + +export function minKey(n: t): rescript.option; + +export function minKeyUndefined(n: t): Js.undefined_; + +export function maxKey(n: t): rescript.option; + +export function maxKeyUndefined(n: t): Js.undefined_; + +export function minimum(n: t): rescript.option<[A, B]>; + +export function minUndefined(n: t): Js.undefined_<[A, B]>; + +export function maximum(n: t): rescript.option<[A, B]>; + +export function maxUndefined(n: t): Js.undefined_<[A, B]>; + +export function removeMinAuxWithRef( + n: node, + kr: Pervasives.ref, + vr: Pervasives.ref, +): t; + +export function isEmpty(x: t): boolean; + +export function stackAllLeft( + v: t, + s: rescript.list>, +): rescript.list>; + +export function findFirstBy( + n: t, + p: (arg0: A, arg1: B) => boolean, +): rescript.option<[A, B]>; + +export function forEach(n: t, f: (arg0: A, arg1: B) => void): void; + +export function map(n: t, f: (arg0: A) => B): t; + +export function mapWithKey(n: t, f: (arg0: A, arg1: B) => C): t; + +export function reduce(m: t, accu: C, f: (arg0: C, arg1: A, arg2: B) => C): C; + +export function every(n: t, p: (arg0: A, arg1: B) => boolean): boolean; + +export function some(n: t, p: (arg0: A, arg1: B) => boolean): boolean; + +export function join(ln: t, v: A, d: B, rn: t): t; + +export function concat(t1: t, t2: t): t; + +export function concatOrJoin( + t1: t, + v: A, + d: rescript.option, + t2: t, +): t; + +export function keepShared(n: t, p: (arg0: A, arg1: B) => boolean): t; + +export function keepMap( + n: t, + p: (arg0: A, arg1: B) => rescript.option, +): t; + +export function partitionShared( + n: t, + p: (arg0: A, arg1: B) => boolean, +): [t, t]; + +export function lengthNode(n: node): number; + +export function size(n: t): number; + +export function toList(s: t): rescript.list<[A, B]>; + +export function checkInvariantInternal(v: t): void; + +export function fillArray(n: node, i: number, arr: [A, B][]): number; + +export function toArray(n: t): [A, B][]; + +export function keysToArray(n: t): A[]; + +export function valuesToArray(n: t): B[]; + +export function fromSortedArrayRevAux( + arr: [A, B][], + off: number, + len: number, +): t; + +export function fromSortedArrayAux( + arr: [A, B][], + off: number, + len: number, +): t; + +export function fromSortedArrayUnsafe(arr: [A, B][]): t; + +export function cmp( + s1: t, + s2: t, + kcmp: cmp, + vcmp: (arg0: B, arg1: C) => number, +): number; + +export function eq( + s1: t, + s2: t, + kcmp: cmp, + veq: (arg0: B, arg1: C) => boolean, +): boolean; + +export function get(n: t, x: A, cmp: cmp): rescript.option; + +export function getUndefined( + n: t, + x: A, + cmp: cmp, +): Js.undefined_; + +export function getOrThrow(n: t, x: A, cmp: cmp): B; + +export function getWithDefault(n: t, x: A, def: B, cmp: cmp): B; + +export function has(n: t, x: A, cmp: cmp): boolean; + +export function balMutate(nt: node): node; + +export function updateMutate( + t: t, + x: A, + data: B, + cmp: cmp, +): t; + +export function fromArray(xs: [A, B][], cmp: cmp): t; + +export function removeMinAuxWithRootMutate( + nt: node, + n: node, +): t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalBuckets.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalBuckets.d.ts new file mode 100644 index 0000000000..02faca9f84 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalBuckets.d.ts @@ -0,0 +1,41 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_internalBucketsType from "./Belt_internalBucketsType.js"; + +export interface bucket { + key: A; + value: B; + next: Belt_internalBucketsType.opt>; +} + +export type t = Belt_internalBucketsType.container>; + +export function copy(x: t): t; + +export function forEach(h: t, f: (arg0: A, arg1: B) => C): void; + +export function reduce( + h: t, + init: C, + f: (arg0: C, arg1: A, arg2: B) => C, +): C; + +export function getBucketHistogram(h: t): number[]; + +export function logStats(h: t): void; + +export function keepMapInPlace( + h: t, + f: (arg0: A, arg1: B) => rescript.option, +): void; + +export function fillArray( + i: number, + arr: [A, B][], + cell: bucket, +): number; + +export function keysToArray(h: t): A[]; + +export function valuesToArray(h: t): B[]; + +export function toArray(h: t): [A, B][]; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalBucketsType.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalBucketsType.d.ts new file mode 100644 index 0000000000..1914aa58c2 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalBucketsType.d.ts @@ -0,0 +1,22 @@ +import type * as Js from "./Js.js"; + +export type opt = Js.undefined_; + +export interface container { + size: number; + buckets: opt[]; + readonly hash: Hash; + readonly eq: Eq; +} + +export const emptyOpt: Js.undefined_; + +export function make( + hash: Hash, + eq: Eq, + hintSize: number, +): container; + +export function clear(h: container): void; + +export function isEmpty(h: container): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalMapInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalMapInt.d.ts new file mode 100644 index 0000000000..1508731d2b --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalMapInt.d.ts @@ -0,0 +1,102 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_internalAVLtree from "./Belt_internalAVLtree.js"; +import type * as Js from "./Js.js"; + +export type key = number; + +export type t = Belt_internalAVLtree.t; + +export function add( + t: Belt_internalAVLtree.t, + x: key, + data: A, +): Belt_internalAVLtree.t; + +export function get( + n: Belt_internalAVLtree.t, + x: key, +): rescript.option; + +export function getUndefined( + n: Belt_internalAVLtree.t, + x: key, +): Js.undefined_; + +export function getOrThrow(n: Belt_internalAVLtree.t, x: key): A; + +export function getWithDefault( + n: Belt_internalAVLtree.t, + x: key, + def: A, +): A; + +export function has(n: Belt_internalAVLtree.t, x: key): boolean; + +export function remove( + n: Belt_internalAVLtree.t, + x: key, +): Belt_internalAVLtree.t; + +export function splitAux( + x: key, + n: Belt_internalAVLtree.node, +): [t, rescript.option, t]; + +export function split( + x: key, + n: rescript.option>, +): [t, rescript.option, t]; + +export function merge( + s1: Belt_internalAVLtree.t, + s2: t, + f: (arg0: key, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): Belt_internalAVLtree.t; + +export function compareAux( + e1: rescript.list>, + e2: rescript.list>, + vcmp: (arg0: A, arg1: B) => number, +): number; + +export function cmp( + s1: Belt_internalAVLtree.t, + s2: Belt_internalAVLtree.t, + cmp: (arg0: A, arg1: B) => number, +): number; + +export function eqAux( + e1: rescript.list>, + e2: rescript.list>, + eq: (arg0: A, arg1: B) => boolean, +): boolean; + +export function eq( + s1: Belt_internalAVLtree.t, + s2: Belt_internalAVLtree.t, + eq: (arg0: A, arg1: B) => boolean, +): boolean; + +export function addMutate(t: t, x: key, data: A): t; + +export function fromArray( + xs: [key, A][], +): Belt_internalAVLtree.t; + +export function cmpU( + arg0: Belt_internalAVLtree.t, + arg1: Belt_internalAVLtree.t, + arg2: (arg0: A, arg1: B) => number, +): number; + +export function eqU( + arg0: Belt_internalAVLtree.t, + arg1: Belt_internalAVLtree.t, + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function mergeU( + arg0: Belt_internalAVLtree.t, + arg1: t, + arg2: (arg0: key, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): Belt_internalAVLtree.t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalMapString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalMapString.d.ts new file mode 100644 index 0000000000..b28ac52f42 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalMapString.d.ts @@ -0,0 +1,102 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_internalAVLtree from "./Belt_internalAVLtree.js"; +import type * as Js from "./Js.js"; + +export type key = string; + +export type t = Belt_internalAVLtree.t; + +export function add( + t: Belt_internalAVLtree.t, + x: key, + data: A, +): Belt_internalAVLtree.t; + +export function get( + n: Belt_internalAVLtree.t, + x: key, +): rescript.option; + +export function getUndefined( + n: Belt_internalAVLtree.t, + x: key, +): Js.undefined_; + +export function getOrThrow(n: Belt_internalAVLtree.t, x: key): A; + +export function getWithDefault( + n: Belt_internalAVLtree.t, + x: key, + def: A, +): A; + +export function has(n: Belt_internalAVLtree.t, x: key): boolean; + +export function remove( + n: Belt_internalAVLtree.t, + x: key, +): Belt_internalAVLtree.t; + +export function splitAux( + x: key, + n: Belt_internalAVLtree.node, +): [t, rescript.option, t]; + +export function split( + x: key, + n: rescript.option>, +): [t, rescript.option, t]; + +export function merge( + s1: Belt_internalAVLtree.t, + s2: t, + f: (arg0: key, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): Belt_internalAVLtree.t; + +export function compareAux( + e1: rescript.list>, + e2: rescript.list>, + vcmp: (arg0: A, arg1: B) => number, +): number; + +export function cmp( + s1: Belt_internalAVLtree.t, + s2: Belt_internalAVLtree.t, + cmp: (arg0: A, arg1: B) => number, +): number; + +export function eqAux( + e1: rescript.list>, + e2: rescript.list>, + eq: (arg0: A, arg1: B) => boolean, +): boolean; + +export function eq( + s1: Belt_internalAVLtree.t, + s2: Belt_internalAVLtree.t, + eq: (arg0: A, arg1: B) => boolean, +): boolean; + +export function addMutate(t: t, x: key, data: A): t; + +export function fromArray( + xs: [key, A][], +): Belt_internalAVLtree.t; + +export function cmpU( + arg0: Belt_internalAVLtree.t, + arg1: Belt_internalAVLtree.t, + arg2: (arg0: A, arg1: B) => number, +): number; + +export function eqU( + arg0: Belt_internalAVLtree.t, + arg1: Belt_internalAVLtree.t, + arg2: (arg0: A, arg1: B) => boolean, +): boolean; + +export function mergeU( + arg0: Belt_internalAVLtree.t, + arg1: t, + arg2: (arg0: key, arg1: rescript.option, arg2: rescript.option) => rescript.option, +): Belt_internalAVLtree.t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalSetBuckets.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalSetBuckets.d.ts new file mode 100644 index 0000000000..e9d5268870 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalSetBuckets.d.ts @@ -0,0 +1,22 @@ +import type * as Belt_internalBucketsType from "./Belt_internalBucketsType.js"; + +export interface bucket { + key: A; + next: Belt_internalBucketsType.opt>; +} + +export type t = Belt_internalBucketsType.container>; + +export function copy(x: t): t; + +export function forEach(h: t, f: (arg0: A) => void): void; + +export function fillArray(i: number, arr: A[], cell: bucket): number; + +export function toArray(h: t): A[]; + +export function reduce(h: t, init: B, f: (arg0: B, arg1: A) => B): B; + +export function getBucketHistogram(h: t): number[]; + +export function logStats(h: t): void; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalSetInt.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalSetInt.d.ts new file mode 100644 index 0000000000..17629a3de5 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalSetInt.d.ts @@ -0,0 +1,36 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_internalAVLset from "./Belt_internalAVLset.js"; +import type * as Js from "./Js.js"; + +export type value = number; + +export type t = Belt_internalAVLset.t; + +export function has(t: t, x: value): boolean; + +export function compareAux( + e1: rescript.list>, + e2: rescript.list>, +): number; + +export function cmp( + s1: Belt_internalAVLset.t, + s2: Belt_internalAVLset.t, +): number; + +export function eq(s1: t, s2: Belt_internalAVLset.t): boolean; + +export function subset(s1: t, s2: t): boolean; + +export function get(n: t, x: value): rescript.option; + +export function getUndefined(n: t, x: value): Js.undefined_; + +export function getOrThrow(n: t, x: value): value; + +export function addMutate( + t: Belt_internalAVLset.t, + x: value, +): Belt_internalAVLset.t; + +export function fromArray(xs: value[]): Belt_internalAVLset.t; diff --git a/packages/@rescript/runtime/lib/es6/Belt_internalSetString.d.ts b/packages/@rescript/runtime/lib/es6/Belt_internalSetString.d.ts new file mode 100644 index 0000000000..7fc154b62f --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Belt_internalSetString.d.ts @@ -0,0 +1,36 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Belt_internalAVLset from "./Belt_internalAVLset.js"; +import type * as Js from "./Js.js"; + +export type value = string; + +export type t = Belt_internalAVLset.t; + +export function has(t: t, x: value): boolean; + +export function compareAux( + e1: rescript.list>, + e2: rescript.list>, +): number; + +export function cmp( + s1: Belt_internalAVLset.t, + s2: Belt_internalAVLset.t, +): number; + +export function eq(s1: t, s2: Belt_internalAVLset.t): boolean; + +export function subset(s1: t, s2: t): boolean; + +export function get(n: t, x: value): rescript.option; + +export function getUndefined(n: t, x: value): Js.undefined_; + +export function getOrThrow(n: t, x: value): value; + +export function addMutate( + t: Belt_internalAVLset.t, + x: value, +): Belt_internalAVLset.t; + +export function fromArray(xs: value[]): Belt_internalAVLset.t; diff --git a/packages/@rescript/runtime/lib/es6/Char.d.ts b/packages/@rescript/runtime/lib/es6/Char.d.ts new file mode 100644 index 0000000000..58ba599ec9 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Char.d.ts @@ -0,0 +1,11 @@ +export type t = number; + +export function escaped(param: number): string; + +export function lowercase_ascii(c: number): number; + +export function uppercase_ascii(c: number): number; + +export function compare(c1: t, c2: t): number; + +export function equal(c1: t, c2: t): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Dom.d.ts b/packages/@rescript/runtime/lib/es6/Dom.d.ts new file mode 100644 index 0000000000..a8bbb34629 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Dom.d.ts @@ -0,0 +1,521 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type _baseClass = rescript.opaque<"Dom._baseClass", []>; + +export type animation = rescript.opaque<"Dom.animation", []>; + +export type cssStyleDeclaration = rescript.opaque<"Dom.cssStyleDeclaration", []>; + +export type cssStyleSheet = rescript.opaque<"Dom.cssStyleSheet", []>; + +export type eventTarget_like = rescript.opaque<"Dom.eventTarget_like", [A]>; + +export type eventTarget = eventTarget_like<_baseClass>; + +export type _node = rescript.opaque<"Dom._node", [A]>; + +export type node_like = eventTarget_like<_node>; + +export type node = node_like<_baseClass>; + +export type _attr = rescript.opaque<"Dom._attr", []>; + +export type attr = node_like<_attr>; + +export type _characterData = rescript.opaque<"Dom._characterData", [A]>; + +export type characterData_like = node_like<_characterData>; + +export type characterData = characterData_like<_baseClass>; + +export type _cdataSection = rescript.opaque<"Dom._cdataSection", []>; + +export type cdataSection = characterData_like<_cdataSection>; + +export type _comment = rescript.opaque<"Dom._comment", []>; + +export type comment = characterData_like<_comment>; + +export type _document = rescript.opaque<"Dom._document", [A]>; + +export type document_like = node_like<_document>; + +export type document = document_like<_baseClass>; + +export type _documentFragment = rescript.opaque<"Dom._documentFragment", []>; + +export type documentFragment = node_like<_documentFragment>; + +export type _documentType = rescript.opaque<"Dom._documentType", []>; + +export type documentType = node_like<_documentType>; + +export type domImplementation = rescript.opaque<"Dom.domImplementation", []>; + +export type _element = rescript.opaque<"Dom._element", [A]>; + +export type element_like = node_like<_element>; + +export type element = element_like<_baseClass>; + +export type htmlCollection = rescript.opaque<"Dom.htmlCollection", []>; + +export type htmlFormControlsCollection = rescript.opaque<"Dom.htmlFormControlsCollection", []>; + +export type htmlOptionsCollection = rescript.opaque<"Dom.htmlOptionsCollection", []>; + +export type intersectionObserver = rescript.opaque<"Dom.intersectionObserver", []>; + +export type intersectionObserverEntry = rescript.opaque<"Dom.intersectionObserverEntry", []>; + +export type mutationObserver = rescript.opaque<"Dom.mutationObserver", []>; + +export type mutationRecord = rescript.opaque<"Dom.mutationRecord", []>; + +export type performanceObserver = rescript.opaque<"Dom.performanceObserver", []>; + +export type performanceObserverEntryList = rescript.opaque<"Dom.performanceObserverEntryList", []>; + +export type reportingObserver = rescript.opaque<"Dom.reportingObserver", []>; + +export type reportingObserverOptions = rescript.opaque<"Dom.reportingObserverOptions", []>; + +export type resizeObserver = rescript.opaque<"Dom.resizeObserver", []>; + +export type resizeObserverEntry = rescript.opaque<"Dom.resizeObserverEntry", []>; + +export type namedNodeMap = rescript.opaque<"Dom.namedNodeMap", []>; + +export type nodeList = rescript.opaque<"Dom.nodeList", []>; + +export type radioNodeList = rescript.opaque<"Dom.radioNodeList", []>; + +export type processingInstruction = rescript.opaque<"Dom.processingInstruction", []>; + +export type _shadowRoot = rescript.opaque<"Dom._shadowRoot", []>; + +export type shadowRoot = node_like<_shadowRoot>; + +export type _text = rescript.opaque<"Dom._text", []>; + +export type text = characterData_like<_text>; + +export type domRect = rescript.opaque<"Dom.domRect", []>; + +export type dataTransfer = rescript.opaque<"Dom.dataTransfer", []>; + +export type domStringMap = rescript.opaque<"Dom.domStringMap", []>; + +export type history = rescript.opaque<"Dom.history", []>; + +export type _htmlDocument = rescript.opaque<"Dom._htmlDocument", []>; + +export type htmlDocument = document_like<_htmlDocument>; + +export type _htmlElement = rescript.opaque<"Dom._htmlElement", [A]>; + +export type htmlElement_like = element_like<_htmlElement>; + +export type htmlElement = htmlElement_like<_baseClass>; + +export type _htmlAnchorElement = rescript.opaque<"Dom._htmlAnchorElement", []>; + +export type htmlAnchorElement = htmlElement_like<_htmlAnchorElement>; + +export type _htmlAreaElement = rescript.opaque<"Dom._htmlAreaElement", []>; + +export type htmlAreaElement = htmlElement_like<_htmlAreaElement>; + +export type _htmlAudioElement = rescript.opaque<"Dom._htmlAudioElement", []>; + +export type htmlAudioElement = htmlElement_like<_htmlAudioElement>; + +export type _htmlBaseElement = rescript.opaque<"Dom._htmlBaseElement", []>; + +export type htmlBaseElement = htmlElement_like<_htmlBaseElement>; + +export type _htmlBodyElement = rescript.opaque<"Dom._htmlBodyElement", []>; + +export type htmlBodyElement = htmlElement_like<_htmlBodyElement>; + +export type _htmlBrElement = rescript.opaque<"Dom._htmlBrElement", []>; + +export type htmlBrElement = htmlElement_like<_htmlBrElement>; + +export type _htmlButtonElement = rescript.opaque<"Dom._htmlButtonElement", []>; + +export type htmlButtonElement = htmlElement_like<_htmlButtonElement>; + +export type _htmlCanvasElement = rescript.opaque<"Dom._htmlCanvasElement", []>; + +export type htmlCanvasElement = htmlElement_like<_htmlCanvasElement>; + +export type _htmlDataElement = rescript.opaque<"Dom._htmlDataElement", []>; + +export type htmlDataElement = htmlElement_like<_htmlDataElement>; + +export type _htmlDataListElement = rescript.opaque<"Dom._htmlDataListElement", []>; + +export type htmlDataListElement = htmlElement_like<_htmlDataListElement>; + +export type _htmlDialogElement = rescript.opaque<"Dom._htmlDialogElement", []>; + +export type htmlDialogElement = htmlElement_like<_htmlDialogElement>; + +export type _htmlDivElement = rescript.opaque<"Dom._htmlDivElement", []>; + +export type htmlDivElement = htmlElement_like<_htmlDivElement>; + +export type _htmlDlistElement = rescript.opaque<"Dom._htmlDlistElement", []>; + +export type htmlDlistElement = htmlElement_like<_htmlDlistElement>; + +export type _htmlEmbedElement = rescript.opaque<"Dom._htmlEmbedElement", []>; + +export type htmlEmbedElement = htmlElement_like<_htmlEmbedElement>; + +export type _htmlFieldSetElement = rescript.opaque<"Dom._htmlFieldSetElement", []>; + +export type htmlFieldSetElement = htmlElement_like<_htmlFieldSetElement>; + +export type _htmlFormElement = rescript.opaque<"Dom._htmlFormElement", []>; + +export type htmlFormElement = htmlElement_like<_htmlFormElement>; + +export type _htmlHeadElement = rescript.opaque<"Dom._htmlHeadElement", []>; + +export type htmlHeadElement = htmlElement_like<_htmlHeadElement>; + +export type _htmlHeadingElement = rescript.opaque<"Dom._htmlHeadingElement", []>; + +export type htmlHeadingElement = htmlElement_like<_htmlHeadingElement>; + +export type _htmlHrElement = rescript.opaque<"Dom._htmlHrElement", []>; + +export type htmlHrElement = htmlElement_like<_htmlHrElement>; + +export type _htmlHtmlElement = rescript.opaque<"Dom._htmlHtmlElement", []>; + +export type htmlHtmlElement = htmlElement_like<_htmlHtmlElement>; + +export type _htmlIframeElement = rescript.opaque<"Dom._htmlIframeElement", []>; + +export type htmlIframeElement = htmlElement_like<_htmlIframeElement>; + +export type _htmlImageElement = rescript.opaque<"Dom._htmlImageElement", []>; + +export type htmlImageElement = htmlElement_like<_htmlImageElement>; + +export type _htmlInputElement = rescript.opaque<"Dom._htmlInputElement", []>; + +export type htmlInputElement = htmlElement_like<_htmlInputElement>; + +export type _htmlLabelElement = rescript.opaque<"Dom._htmlLabelElement", []>; + +export type htmlLabelElement = htmlElement_like<_htmlLabelElement>; + +export type _htmlLegendElement = rescript.opaque<"Dom._htmlLegendElement", []>; + +export type htmlLegendElement = htmlElement_like<_htmlLegendElement>; + +export type _htmlLiElement = rescript.opaque<"Dom._htmlLiElement", []>; + +export type htmlLiElement = htmlElement_like<_htmlLiElement>; + +export type _htmlLinkElement = rescript.opaque<"Dom._htmlLinkElement", []>; + +export type htmlLinkElement = htmlElement_like<_htmlLinkElement>; + +export type _htmlMapElement = rescript.opaque<"Dom._htmlMapElement", []>; + +export type htmlMapElement = htmlElement_like<_htmlMapElement>; + +export type _htmlMediaElement = rescript.opaque<"Dom._htmlMediaElement", []>; + +export type htmlMediaElement = htmlElement_like<_htmlMediaElement>; + +export type _htmlMenuElement = rescript.opaque<"Dom._htmlMenuElement", []>; + +export type htmlMenuElement = htmlElement_like<_htmlMenuElement>; + +export type _htmlMetaElement = rescript.opaque<"Dom._htmlMetaElement", []>; + +export type htmlMetaElement = htmlElement_like<_htmlMetaElement>; + +export type _htmlMeterElement = rescript.opaque<"Dom._htmlMeterElement", []>; + +export type htmlMeterElement = htmlElement_like<_htmlMeterElement>; + +export type _htmlModElement = rescript.opaque<"Dom._htmlModElement", []>; + +export type htmlModElement = htmlElement_like<_htmlModElement>; + +export type _htmlOListElement = rescript.opaque<"Dom._htmlOListElement", []>; + +export type htmlOListElement = htmlElement_like<_htmlOListElement>; + +export type _htmlObjectElement = rescript.opaque<"Dom._htmlObjectElement", []>; + +export type htmlObjectElement = htmlElement_like<_htmlObjectElement>; + +export type _htmlOptGroupElement = rescript.opaque<"Dom._htmlOptGroupElement", []>; + +export type htmlOptGroupElement = htmlElement_like<_htmlOptGroupElement>; + +export type _htmlOptionElement = rescript.opaque<"Dom._htmlOptionElement", []>; + +export type htmlOptionElement = htmlElement_like<_htmlOptionElement>; + +export type _htmlOutputElement = rescript.opaque<"Dom._htmlOutputElement", []>; + +export type htmlOutputElement = htmlElement_like<_htmlOutputElement>; + +export type _htmlParagraphElement = rescript.opaque<"Dom._htmlParagraphElement", []>; + +export type htmlParagraphElement = htmlElement_like<_htmlParagraphElement>; + +export type _htmlParamElement = rescript.opaque<"Dom._htmlParamElement", []>; + +export type htmlParamElement = htmlElement_like<_htmlParamElement>; + +export type _htmlPreElement = rescript.opaque<"Dom._htmlPreElement", []>; + +export type htmlPreElement = htmlElement_like<_htmlPreElement>; + +export type _htmlProgressElement = rescript.opaque<"Dom._htmlProgressElement", []>; + +export type htmlProgressElement = htmlElement_like<_htmlProgressElement>; + +export type _htmlQuoteElement = rescript.opaque<"Dom._htmlQuoteElement", []>; + +export type htmlQuoteElement = htmlElement_like<_htmlQuoteElement>; + +export type _htmlScriptElement = rescript.opaque<"Dom._htmlScriptElement", []>; + +export type htmlScriptElement = htmlElement_like<_htmlScriptElement>; + +export type _htmlSelectElement = rescript.opaque<"Dom._htmlSelectElement", []>; + +export type htmlSelectElement = htmlElement_like<_htmlSelectElement>; + +export type _htmlSlotElement = rescript.opaque<"Dom._htmlSlotElement", []>; + +export type htmlSlotElement = htmlElement_like<_htmlSlotElement>; + +export type _htmlSourceElement = rescript.opaque<"Dom._htmlSourceElement", []>; + +export type htmlSourceElement = htmlElement_like<_htmlSourceElement>; + +export type _htmlSpanElement = rescript.opaque<"Dom._htmlSpanElement", []>; + +export type htmlSpanElement = htmlElement_like<_htmlSpanElement>; + +export type _htmlStyleElement = rescript.opaque<"Dom._htmlStyleElement", []>; + +export type htmlStyleElement = htmlElement_like<_htmlStyleElement>; + +export type _htmlTableCaptionElement = rescript.opaque<"Dom._htmlTableCaptionElement", []>; + +export type htmlTableCaptionElement = htmlElement_like<_htmlTableCaptionElement>; + +export type _htmlTableCellElement = rescript.opaque<"Dom._htmlTableCellElement", []>; + +export type htmlTableCellElement = htmlElement_like<_htmlTableCellElement>; + +export type _htmlTableColElement = rescript.opaque<"Dom._htmlTableColElement", []>; + +export type htmlTableColElement = htmlElement_like<_htmlTableColElement>; + +export type _htmlTableDataCellElement = rescript.opaque<"Dom._htmlTableDataCellElement", []>; + +export type htmlTableDataCellElement = htmlElement_like<_htmlTableDataCellElement>; + +export type _htmlTableElement = rescript.opaque<"Dom._htmlTableElement", []>; + +export type htmlTableElement = htmlElement_like<_htmlTableElement>; + +export type _htmlTableHeaderCellElement = rescript.opaque<"Dom._htmlTableHeaderCellElement", []>; + +export type htmlTableHeaderCellElement = htmlElement_like<_htmlTableHeaderCellElement>; + +export type _htmlTableRowElement = rescript.opaque<"Dom._htmlTableRowElement", []>; + +export type htmlTableRowElement = htmlElement_like<_htmlTableRowElement>; + +export type _htmlTableSectionElement = rescript.opaque<"Dom._htmlTableSectionElement", []>; + +export type htmlTableSectionElement = htmlElement_like<_htmlTableSectionElement>; + +export type _htmlTextAreaElement = rescript.opaque<"Dom._htmlTextAreaElement", []>; + +export type htmlTextAreaElement = htmlElement_like<_htmlTextAreaElement>; + +export type _htmlTimeElement = rescript.opaque<"Dom._htmlTimeElement", []>; + +export type htmlTimeElement = htmlElement_like<_htmlTimeElement>; + +export type _htmlTitleElement = rescript.opaque<"Dom._htmlTitleElement", []>; + +export type htmlTitleElement = htmlElement_like<_htmlTitleElement>; + +export type _htmlTrackElement = rescript.opaque<"Dom._htmlTrackElement", []>; + +export type htmlTrackElement = htmlElement_like<_htmlTrackElement>; + +export type _htmlUlistElement = rescript.opaque<"Dom._htmlUlistElement", []>; + +export type htmlUlistElement = htmlElement_like<_htmlUlistElement>; + +export type _htmlUnknownElement = rescript.opaque<"Dom._htmlUnknownElement", []>; + +export type htmlUnknownElement = htmlElement_like<_htmlUnknownElement>; + +export type _htmlVideoElement = rescript.opaque<"Dom._htmlVideoElement", []>; + +export type htmlVideoElement = htmlElement_like<_htmlVideoElement>; + +export type location = rescript.opaque<"Dom.location", []>; + +export type window = rescript.opaque<"Dom.window", []>; + +export type _xmlDocument = rescript.opaque<"Dom._xmlDocument", []>; + +export type xmlDocument = document_like<_xmlDocument>; + +export type event_like = rescript.opaque<"Dom.event_like", [A]>; + +export type event = event_like<_baseClass>; + +export type _uiEvent = rescript.opaque<"Dom._uiEvent", [A]>; + +export type uiEvent_like = event_like<_uiEvent>; + +export type uiEvent = uiEvent_like<_baseClass>; + +export type _animationEvent = rescript.opaque<"Dom._animationEvent", []>; + +export type animationEvent = event_like<_animationEvent>; + +export type _beforeUnloadEvent = rescript.opaque<"Dom._beforeUnloadEvent", []>; + +export type beforeUnloadEvent = event_like<_beforeUnloadEvent>; + +export type _clipboardEvent = rescript.opaque<"Dom._clipboardEvent", []>; + +export type clipboardEvent = event_like<_clipboardEvent>; + +export type _closeEvent = rescript.opaque<"Dom._closeEvent", []>; + +export type closeEvent = event_like<_closeEvent>; + +export type _compositionEvent = rescript.opaque<"Dom._compositionEvent", []>; + +export type compositionEvent = uiEvent_like<_compositionEvent>; + +export type _customEvent = rescript.opaque<"Dom._customEvent", []>; + +export type customEvent = event_like<_customEvent>; + +export type _dragEvent = rescript.opaque<"Dom._dragEvent", []>; + +export type dragEvent = event_like<_dragEvent>; + +export type _errorEvent = rescript.opaque<"Dom._errorEvent", []>; + +export type errorEvent = event_like<_errorEvent>; + +export type _focusEvent = rescript.opaque<"Dom._focusEvent", []>; + +export type focusEvent = uiEvent_like<_focusEvent>; + +export type _idbVersionChangeEvent = rescript.opaque<"Dom._idbVersionChangeEvent", []>; + +export type idbVersionChangeEvent = event_like<_idbVersionChangeEvent>; + +export type _inputEvent = rescript.opaque<"Dom._inputEvent", []>; + +export type inputEvent = uiEvent_like<_inputEvent>; + +export type _keyboardEvent = rescript.opaque<"Dom._keyboardEvent", []>; + +export type keyboardEvent = uiEvent_like<_keyboardEvent>; + +export type _mouseEvent = rescript.opaque<"Dom._mouseEvent", [A]>; + +export type mouseEvent_like = uiEvent_like<_mouseEvent>; + +export type mouseEvent = mouseEvent_like<_baseClass>; + +export type _pageTransitionEvent = rescript.opaque<"Dom._pageTransitionEvent", []>; + +export type pageTransitionEvent = event_like<_pageTransitionEvent>; + +export type _pointerEvent = rescript.opaque<"Dom._pointerEvent", []>; + +export type pointerEvent = mouseEvent_like<_pointerEvent>; + +export type _popStateEvent = rescript.opaque<"Dom._popStateEvent", []>; + +export type popStateEvent = event_like<_popStateEvent>; + +export type _progressEvent = rescript.opaque<"Dom._progressEvent", []>; + +export type progressEvent = event_like<_progressEvent>; + +export type _relatedEvent = rescript.opaque<"Dom._relatedEvent", []>; + +export type relatedEvent = event_like<_relatedEvent>; + +export type _storageEvent = rescript.opaque<"Dom._storageEvent", []>; + +export type storageEvent = event_like<_storageEvent>; + +export type _svgZoomEvent = rescript.opaque<"Dom._svgZoomEvent", []>; + +export type svgZoomEvent = event_like<_svgZoomEvent>; + +export type _timeEvent = rescript.opaque<"Dom._timeEvent", []>; + +export type timeEvent = event_like<_timeEvent>; + +export type _touchEvent = rescript.opaque<"Dom._touchEvent", []>; + +export type touchEvent = uiEvent_like<_touchEvent>; + +export type _trackEvent = rescript.opaque<"Dom._trackEvent", []>; + +export type trackEvent = event_like<_trackEvent>; + +export type _transitionEvent = rescript.opaque<"Dom._transitionEvent", []>; + +export type transitionEvent = event_like<_transitionEvent>; + +export type _webGlContextEvent = rescript.opaque<"Dom._webGlContextEvent", []>; + +export type webGlContextEvent = event_like<_webGlContextEvent>; + +export type _wheelEvent = rescript.opaque<"Dom._wheelEvent", []>; + +export type wheelEvent = uiEvent_like<_wheelEvent>; + +export type range = rescript.opaque<"Dom.range", []>; + +export type selection = rescript.opaque<"Dom.selection", []>; + +export type domTokenList = rescript.opaque<"Dom.domTokenList", []>; + +export type domSettableTokenList = rescript.opaque<"Dom.domSettableTokenList", []>; + +export interface nodeFilter { + readonly acceptNode: (arg0: element) => number; +} + +export type nodeIterator = rescript.opaque<"Dom.nodeIterator", []>; + +export type treeWalker = rescript.opaque<"Dom.treeWalker", []>; + +export type svgRect = rescript.opaque<"Dom.svgRect", []>; + +export type svgPoint = rescript.opaque<"Dom.svgPoint", []>; + +export type eventPointerId = rescript.opaque<"Dom.eventPointerId", []>; diff --git a/packages/@rescript/runtime/lib/es6/Dom_storage.d.ts b/packages/@rescript/runtime/lib/es6/Dom_storage.d.ts new file mode 100644 index 0000000000..3648bcc548 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Dom_storage.d.ts @@ -0,0 +1,12 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Dom_storage2 from "./Dom_storage2.js"; + +export type t = Dom_storage2.t; + +export function getItem(s: string, obj: t): rescript.option; + +export function setItem(k: string, v: string, obj: t): void; + +export function removeItem(s: string, obj: t): void; + +export function key(i: number, obj: t): rescript.option; diff --git a/packages/@rescript/runtime/lib/es6/Dom_storage2.d.ts b/packages/@rescript/runtime/lib/es6/Dom_storage2.d.ts new file mode 100644 index 0000000000..f35ec15b96 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Dom_storage2.d.ts @@ -0,0 +1,3 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = rescript.opaque<"Dom_storage2.t", []>; diff --git a/packages/@rescript/runtime/lib/es6/Js.d.ts b/packages/@rescript/runtime/lib/es6/Js.d.ts new file mode 100644 index 0000000000..ce8563eb15 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js.d.ts @@ -0,0 +1,21 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js_undefined from "./Js_undefined.js"; + +export type t = rescript.opaque<"Js.t", [T0], { }>; + +export type null_ = + | A + | null; + +export type undefined_ = Js_undefined.t; + +export type nullable = + | A + | null + | undefined; + +export type null_undefined = nullable; + +export type promise = rescript.opaque<"Js.promise", [A, E]>; + +export function undefinedToOption(arg0: undefined_): rescript.option; diff --git a/packages/@rescript/runtime/lib/es6/Js_OO.d.ts b/packages/@rescript/runtime/lib/es6/Js_OO.d.ts new file mode 100644 index 0000000000..cf14bf231b --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_OO.d.ts @@ -0,0 +1,27 @@ +declare namespace Callback { + interface arity1 { readonly I1: A; } + interface arity2 { readonly I2: A; } + interface arity3 { readonly I3: A; } + interface arity4 { readonly I4: A; } + interface arity5 { readonly I5: A; } + interface arity6 { readonly I6: A; } + interface arity7 { readonly I7: A; } + interface arity8 { readonly I8: A; } + interface arity9 { readonly I9: A; } + interface arity10 { readonly I10: A; } + interface arity11 { readonly I11: A; } + interface arity12 { readonly I12: A; } + interface arity13 { readonly I13: A; } + interface arity14 { readonly I14: A; } + interface arity15 { readonly I15: A; } + interface arity16 { readonly I16: A; } + interface arity17 { readonly I17: A; } + interface arity18 { readonly I18: A; } + interface arity19 { readonly I19: A; } + interface arity20 { readonly I20: A; } + interface arity21 { readonly I21: A; } + interface arity22 { readonly I22: A; } +} +export type Callback = { +}; +export const Callback: Callback; diff --git a/packages/@rescript/runtime/lib/es6/Js_array.d.ts b/packages/@rescript/runtime/lib/es6/Js_array.d.ts new file mode 100644 index 0000000000..54439c9814 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_array.d.ts @@ -0,0 +1,146 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js_array2 from "./Js_array2.js"; + +export type t = A[]; + +export type array_like = Js_array2.array_like; + +export function copyWithin(to_: number, obj: t): B; + +export function copyWithinFrom(to_: number, from_: number, obj: t): B; + +export function copyWithinFromRange( + to_: number, + start: number, + end_: number, + obj: t, +): B; + +export function fillInPlace(arg1: A, obj: t): B; + +export function fillFromInPlace(arg1: A, from_: number, obj: t): B; + +export function fillRangeInPlace( + arg1: A, + start: number, + end_: number, + obj: t, +): B; + +export function push(arg1: A, obj: t): number; + +export function pushMany(arg1: A[], obj: t): number; + +export function sortInPlaceWith( + arg1: (arg0: A, arg1: A) => number, + obj: t, +): B; + +export function spliceInPlace( + pos: number, + remove: number, + add: A[], + obj: t, +): B; + +export function removeFromInPlace(pos: number, obj: t): B; + +export function removeCountInPlace( + pos: number, + count: number, + obj: t, +): B; + +export function unshift(arg1: A, obj: t): number; + +export function unshiftMany(arg1: A[], obj: t): number; + +export function concat(arg1: A, obj: t): A; + +export function concatMany(arg1: A[], obj: t): A; + +export function includes(arg1: A, obj: t): boolean; + +export function indexOf(arg1: A, obj: t): number; + +export function indexOfFrom(arg1: A, from_: number, obj: t): number; + +export function joinWith(arg1: string, obj: t): string; + +export function lastIndexOf(arg1: A, obj: t): number; + +export function lastIndexOfFrom(arg1: A, from_: number, obj: t): number; + +export function slice(start: number, end_: number, obj: t): B; + +export function sliceFrom(arg1: number, obj: t): B; + +export function every(arg1: (arg0: A) => boolean, obj: t): boolean; + +export function everyi( + arg1: (arg0: A, arg1: number) => boolean, + obj: t, +): boolean; + +export function filter(arg1: (arg0: A) => boolean, obj: t): B; + +export function filteri( + arg1: (arg0: A, arg1: number) => boolean, + obj: t, +): B; + +export function find( + arg1: (arg0: A) => boolean, + obj: t, +): rescript.option; + +export function findi( + arg1: (arg0: A, arg1: number) => boolean, + obj: t, +): rescript.option; + +export function findIndex(arg1: (arg0: A) => boolean, obj: t): number; + +export function findIndexi( + arg1: (arg0: A, arg1: number) => boolean, + obj: t, +): number; + +export function forEach(arg1: (arg0: A) => void, obj: t): void; + +export function forEachi(arg1: (arg0: A, arg1: number) => void, obj: t): void; + +export function map(arg1: (arg0: A) => B, obj: t): t; + +export function mapi(arg1: (arg0: A, arg1: number) => B, obj: t): t; + +export function reduce( + arg1: (arg0: A, arg1: B) => A, + arg2: A, + obj: t, +): A; + +export function reducei( + arg1: (arg0: A, arg1: B, arg2: number) => A, + arg2: A, + obj: t, +): A; + +export function reduceRight( + arg1: (arg0: A, arg1: B) => A, + arg2: A, + obj: t, +): A; + +export function reduceRighti( + arg1: (arg0: A, arg1: B, arg2: number) => A, + arg2: A, + obj: t, +): A; + +export function some(arg1: (arg0: A) => boolean, obj: t): boolean; + +export function somei( + arg1: (arg0: A, arg1: number) => boolean, + obj: t, +): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Js_array2.d.ts b/packages/@rescript/runtime/lib/es6/Js_array2.d.ts new file mode 100644 index 0000000000..b1f26f5a0b --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_array2.d.ts @@ -0,0 +1,5 @@ +import type * as Stdlib_Array from "./Stdlib_Array.js"; + +export type t = A[]; + +export type array_like = Stdlib_Array.arrayLike; diff --git a/packages/@rescript/runtime/lib/es6/Js_bigint.d.ts b/packages/@rescript/runtime/lib/es6/Js_bigint.d.ts new file mode 100644 index 0000000000..60447571ca --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_bigint.d.ts @@ -0,0 +1 @@ +export function lnot(x: bigint): bigint; diff --git a/packages/@rescript/runtime/lib/es6/Js_blob.d.ts b/packages/@rescript/runtime/lib/es6/Js_blob.d.ts new file mode 100644 index 0000000000..d038a3c3fe --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_blob.d.ts @@ -0,0 +1,3 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = rescript.opaque<"Js_blob.t", []>; diff --git a/packages/@rescript/runtime/lib/es6/Js_console.d.ts b/packages/@rescript/runtime/lib/es6/Js_console.d.ts new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_console.d.ts @@ -0,0 +1 @@ + diff --git a/packages/@rescript/runtime/lib/es6/Js_date.d.ts b/packages/@rescript/runtime/lib/es6/Js_date.d.ts new file mode 100644 index 0000000000..728e7a8132 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_date.d.ts @@ -0,0 +1,3 @@ +import type * as Stdlib_Date from "./Stdlib_Date.js"; + +export type t = Stdlib_Date.t; diff --git a/packages/@rescript/runtime/lib/es6/Js_dict.d.ts b/packages/@rescript/runtime/lib/es6/Js_dict.d.ts new file mode 100644 index 0000000000..24c9f8fea6 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_dict.d.ts @@ -0,0 +1,19 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = rescript.dict; + +export type key = string; + +export function get(dict: t, k: key): rescript.option; + +export function unsafeDeleteKey(arg0: t, arg1: string): void; + +export function entries(dict: t): [key, A][]; + +export function values(dict: t): A[]; + +export function fromList(entries: rescript.list<[key, A]>): t; + +export function fromArray(entries: [key, A][]): t; + +export function map(f: (arg0: A) => B, source: t): t; diff --git a/packages/@rescript/runtime/lib/es6/Js_extern.d.ts b/packages/@rescript/runtime/lib/es6/Js_extern.d.ts new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_extern.d.ts @@ -0,0 +1 @@ + diff --git a/packages/@rescript/runtime/lib/es6/Js_file.d.ts b/packages/@rescript/runtime/lib/es6/Js_file.d.ts new file mode 100644 index 0000000000..c48d98f4a8 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_file.d.ts @@ -0,0 +1,3 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = rescript.opaque<"Js_file.t", []>; diff --git a/packages/@rescript/runtime/lib/es6/Js_float.d.ts b/packages/@rescript/runtime/lib/es6/Js_float.d.ts new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_float.d.ts @@ -0,0 +1 @@ + diff --git a/packages/@rescript/runtime/lib/es6/Js_global.d.ts b/packages/@rescript/runtime/lib/es6/Js_global.d.ts new file mode 100644 index 0000000000..79a6b6f52d --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_global.d.ts @@ -0,0 +1,5 @@ +import type * as Stdlib_Global from "./Stdlib_Global.js"; + +export type intervalId = Stdlib_Global.intervalId; + +export type timeoutId = Stdlib_Global.timeoutId; diff --git a/packages/@rescript/runtime/lib/es6/Js_int.d.ts b/packages/@rescript/runtime/lib/es6/Js_int.d.ts new file mode 100644 index 0000000000..2fe9193c24 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_int.d.ts @@ -0,0 +1,5 @@ +export function equal(x: number, y: number): boolean; + +export const max: number; + +export const min: number; diff --git a/packages/@rescript/runtime/lib/es6/Js_json.d.ts b/packages/@rescript/runtime/lib/es6/Js_json.d.ts new file mode 100644 index 0000000000..39072904f4 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_json.d.ts @@ -0,0 +1,65 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js_null from "./Js_null.js"; +import type * as Js_string from "./Js_string.js"; +import type * as Js_types from "./Js_types.js"; + +export type t = + | boolean + | null + | string + | number + | rescript.dict + | t[]; + +declare namespace Kind { + type json = t; + type t$String = "String"; + type t$Number = "Number"; + type t$Object = "Object"; + type t$Array = "Array"; + type t$Boolean = "Boolean"; + type t$Null = "Null"; + type t< + _ extends Js_string.t | number | rescript.dict | Kind.json[] | boolean | Js_types.null_val = Js_string.t | number | rescript.dict | Kind.json[] | boolean | Js_types.null_val + > = + | t$String + | t$Number + | t$Object + | t$Array + | t$Boolean + | t$Null; +} +export type Kind = { +}; +export const Kind: Kind; + +export type tagged_t = + | "JSONFalse" + | "JSONTrue" + | "JSONNull" + | { readonly TAG: "JSONString"; readonly _0: string } + | { readonly TAG: "JSONNumber"; readonly _0: number } + | { readonly TAG: "JSONObject"; readonly _0: rescript.dict } + | { readonly TAG: "JSONArray"; readonly _0: t[] }; + +export function classify(x: t): tagged_t; + +export function test(x: A, v: Kind.t | Kind.json[] | boolean | Js_types.null_val>): boolean; + +export function decodeString(json: t): rescript.option; + +export function decodeNumber(json: t): rescript.option; + +export function decodeObject(json: t): rescript.option>; + +export function decodeArray(json: t): rescript.option; + +export function decodeBoolean(json: t): rescript.option; + +export function decodeNull(json: t): rescript.option | Kind.json[] | boolean | Js_types.null_val>>; + +export function serializeExn( + x: A, +): string; + +export function deserializeUnsafe(s: string): A; diff --git a/packages/@rescript/runtime/lib/es6/Js_map.d.ts b/packages/@rescript/runtime/lib/es6/Js_map.d.ts new file mode 100644 index 0000000000..ba9a2554c8 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_map.d.ts @@ -0,0 +1,3 @@ +import type * as Stdlib_Map from "./Stdlib_Map.js"; + +export type t = Stdlib_Map.t; diff --git a/packages/@rescript/runtime/lib/es6/Js_math.d.ts b/packages/@rescript/runtime/lib/es6/Js_math.d.ts new file mode 100644 index 0000000000..afe7f38e29 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_math.d.ts @@ -0,0 +1,13 @@ +export function unsafe_ceil(arg0: number): number; + +export function ceil_int(f: number): number; + +export function ceil(arg0: number): number; + +export function unsafe_floor(arg0: number): number; + +export function floor_int(f: number): number; + +export function floor(arg0: number): number; + +export function random_int(min: number, max: number): number; diff --git a/packages/@rescript/runtime/lib/es6/Js_null.d.ts b/packages/@rescript/runtime/lib/es6/Js_null.d.ts new file mode 100644 index 0000000000..bd1cc0b38c --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_null.d.ts @@ -0,0 +1,17 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = + | A + | null; + +export function test(x: t): boolean; + +export function getExn(f: t): A; + +export function bind(x: t, f: (arg0: A) => B): t; + +export function iter(x: t, f: (arg0: A) => void): void; + +export function fromOption(x: rescript.option): t; + +export function from_opt(arg0: rescript.option): t; diff --git a/packages/@rescript/runtime/lib/es6/Js_null_undefined.d.ts b/packages/@rescript/runtime/lib/es6/Js_null_undefined.d.ts new file mode 100644 index 0000000000..06d13291e3 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_null_undefined.d.ts @@ -0,0 +1,14 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = + | A + | null + | undefined; + +export function bind(x: t, f: (arg0: A) => B): t; + +export function iter(x: t, f: (arg0: A) => void): void; + +export function fromOption(x: rescript.option): t; + +export function from_opt(arg0: rescript.option): t; diff --git a/packages/@rescript/runtime/lib/es6/Js_obj.d.ts b/packages/@rescript/runtime/lib/es6/Js_obj.d.ts new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_obj.d.ts @@ -0,0 +1 @@ + diff --git a/packages/@rescript/runtime/lib/es6/Js_option.d.ts b/packages/@rescript/runtime/lib/es6/Js_option.d.ts new file mode 100644 index 0000000000..c1c06f1445 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_option.d.ts @@ -0,0 +1,44 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = rescript.option; + +export function some(x: A): rescript.option; + +export function isSome(x: rescript.option): boolean; + +export function isSomeValue( + eq: (arg0: A, arg1: A) => boolean, + v: A, + x: rescript.option, +): boolean; + +export function isNone(x: rescript.option): boolean; + +export function getExn(x: rescript.option): A; + +export function equal( + eq: (arg0: A, arg1: B) => boolean, + a: rescript.option, + b: rescript.option, +): boolean; + +export function andThen( + f: (arg0: A) => rescript.option, + x: rescript.option, +): rescript.option; + +export function map(f: (arg0: A) => B, x: rescript.option): rescript.option; + +export function getWithDefault(a: A, x: rescript.option): A; + +export default getWithDefault; + +export function filter( + f: (arg0: A) => boolean, + x: rescript.option, +): rescript.option; + +export function firstSome( + a: rescript.option, + b: rescript.option, +): rescript.option; diff --git a/packages/@rescript/runtime/lib/es6/Js_promise.d.ts b/packages/@rescript/runtime/lib/es6/Js_promise.d.ts new file mode 100644 index 0000000000..fe26a82f1c --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_promise.d.ts @@ -0,0 +1,12 @@ +import type * as Js_promise2 from "./Js_promise2.js"; + +export type t = Promise; + +export type error = Js_promise2.error; + +export function then_(arg1: (arg0: A) => Promise, obj: Promise): Promise; + +export function $$catch( + arg1: (arg0: error) => Promise, + obj: Promise, +): Promise; diff --git a/packages/@rescript/runtime/lib/es6/Js_promise2.d.ts b/packages/@rescript/runtime/lib/es6/Js_promise2.d.ts new file mode 100644 index 0000000000..92340c03cd --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_promise2.d.ts @@ -0,0 +1,12 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type t = Promise; + +export type error = rescript.opaque<"Js_promise2.error", []>; + +export function then(arg0: Promise, arg1: (arg0: A) => Promise): Promise; + +export function $$catch( + arg0: Promise, + arg1: (arg0: error) => Promise, +): Promise; diff --git a/packages/@rescript/runtime/lib/es6/Js_re.d.ts b/packages/@rescript/runtime/lib/es6/Js_re.d.ts new file mode 100644 index 0000000000..3eae342720 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_re.d.ts @@ -0,0 +1,6 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Stdlib_RegExp from "./Stdlib_RegExp.js"; + +export type t = Stdlib_RegExp.t; + +export type result = rescript.opaque<"Js_re.result", []>; diff --git a/packages/@rescript/runtime/lib/es6/Js_result.d.ts b/packages/@rescript/runtime/lib/es6/Js_result.d.ts new file mode 100644 index 0000000000..f5ba03852f --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_result.d.ts @@ -0,0 +1,3 @@ +export type t = + | { readonly TAG: "Ok"; readonly _0: Good } + | { readonly TAG: "Error"; readonly _0: Bad }; diff --git a/packages/@rescript/runtime/lib/es6/Js_set.d.ts b/packages/@rescript/runtime/lib/es6/Js_set.d.ts new file mode 100644 index 0000000000..85cd11dae3 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_set.d.ts @@ -0,0 +1,3 @@ +import type * as Stdlib_Set from "./Stdlib_Set.js"; + +export type t = Stdlib_Set.t; diff --git a/packages/@rescript/runtime/lib/es6/Js_string.d.ts b/packages/@rescript/runtime/lib/es6/Js_string.d.ts new file mode 100644 index 0000000000..7c0949eabb --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_string.d.ts @@ -0,0 +1,100 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Js_re from "./Js_re.js"; + +export type t = string; + +export function charAt(arg1: number, obj: t): t; + +export function charCodeAt(arg1: number, obj: t): number; + +export function codePointAt(arg1: number, obj: t): rescript.option; + +export function concat(arg1: t, obj: t): t; + +export function concatMany(arg1: t[], obj: t): t; + +export function endsWith(arg1: t, obj: t): boolean; + +export function endsWithFrom(arg1: t, arg2: number, obj: t): boolean; + +export function includes(arg1: t, obj: t): boolean; + +export function includesFrom(arg1: t, arg2: number, obj: t): boolean; + +export function indexOf(arg1: t, obj: t): number; + +export function indexOfFrom(arg1: t, arg2: number, obj: t): number; + +export function lastIndexOf(arg1: t, obj: t): number; + +export function lastIndexOfFrom(arg1: t, arg2: number, obj: t): number; + +export function localeCompare(arg1: t, obj: t): number; + +export function match_(arg1: Js_re.t, obj: t): rescript.option[]>; + +export function normalizeByForm(arg1: t, obj: t): t; + +export function repeat(arg1: number, obj: t): t; + +export function replace(arg1: t, arg2: t, obj: t): t; + +export function replaceByRe(arg1: Js_re.t, arg2: t, obj: t): t; + +export function unsafeReplaceBy0( + arg1: Js_re.t, + arg2: (arg0: t, arg1: number, arg2: t) => t, + obj: t, +): t; + +export function unsafeReplaceBy1( + arg1: Js_re.t, + arg2: (arg0: t, arg1: t, arg2: number, arg3: t) => t, + obj: t, +): t; + +export function unsafeReplaceBy2( + arg1: Js_re.t, + arg2: (arg0: t, arg1: t, arg2: t, arg3: number, arg4: t) => t, + obj: t, +): t; + +export function unsafeReplaceBy3( + arg1: Js_re.t, + arg2: (arg0: t, arg1: t, arg2: t, arg3: t, arg4: number, arg5: t) => t, + obj: t, +): t; + +export function search(arg1: Js_re.t, obj: t): number; + +export function slice(from_: number, to_: number, obj: t): t; + +export function sliceToEnd(from_: number, obj: t): t; + +export function split(arg1: t, obj: t): t[]; + +export function splitAtMost(arg1: t, limit: number, obj: t): t[]; + +export function splitByRe(arg1: Js_re.t, obj: t): rescript.option[]; + +export function splitByReAtMost( + arg1: Js_re.t, + limit: number, + obj: t, +): rescript.option[]; + +export function startsWith(arg1: t, obj: t): boolean; + +export function startsWithFrom(arg1: t, arg2: number, obj: t): boolean; + +export function substr(from_: number, obj: t): t; + +export function substrAtMost(from_: number, length: number, obj: t): t; + +export function substring(from_: number, to_: number, obj: t): t; + +export function substringToEnd(from_: number, obj: t): t; + +export function anchor(arg1: t, obj: t): t; + +export function link(arg1: t, obj: t): t; diff --git a/packages/@rescript/runtime/lib/es6/Js_string2.d.ts b/packages/@rescript/runtime/lib/es6/Js_string2.d.ts new file mode 100644 index 0000000000..4dfcd0941a --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_string2.d.ts @@ -0,0 +1 @@ +export type t = string; diff --git a/packages/@rescript/runtime/lib/es6/Js_typed_array.d.ts b/packages/@rescript/runtime/lib/es6/Js_typed_array.d.ts new file mode 100644 index 0000000000..6df2195d5b --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_typed_array.d.ts @@ -0,0 +1,100 @@ +import type * as Js_typed_array2 from "./Js_typed_array2.js"; + +export type array_buffer = Js_typed_array2.array_buffer; + +export type array_like = Js_typed_array2.array_like; + +declare namespace ArrayBuffer { + type t = array_buffer; +} +export type ArrayBuffer = { +}; +export const $$ArrayBuffer: ArrayBuffer; + +declare namespace Int8Array { + type elt = number; + type typed_array = Js_typed_array2.Int8Array.typed_array; + type t = Int8Array.typed_array; +} +export type Int8Array = { +}; +export const $$Int8Array: Int8Array; + +declare namespace Uint8Array { + type elt = number; + type typed_array = Js_typed_array2.Uint8Array.typed_array; + type t = Uint8Array.typed_array; +} +export type Uint8Array = { +}; +export const $$Uint8Array: Uint8Array; + +declare namespace Uint8ClampedArray { + type elt = number; + type typed_array = Js_typed_array2.Uint8ClampedArray.typed_array; + type t = Uint8ClampedArray.typed_array; +} +export type Uint8ClampedArray = { +}; +export const $$Uint8ClampedArray: Uint8ClampedArray; + +declare namespace Int16Array { + type elt = number; + type typed_array = Js_typed_array2.Int16Array.typed_array; + type t = Int16Array.typed_array; +} +export type Int16Array = { +}; +export const $$Int16Array: Int16Array; + +declare namespace Uint16Array { + type elt = number; + type typed_array = Js_typed_array2.Uint16Array.typed_array; + type t = Uint16Array.typed_array; +} +export type Uint16Array = { +}; +export const $$Uint16Array: Uint16Array; + +declare namespace Int32Array { + type elt = number; + type typed_array = Js_typed_array2.Int32Array.typed_array; + type t = Int32Array.typed_array; +} +export type Int32Array = { +}; +export const $$Int32Array: Int32Array; + +declare namespace Uint32Array { + type elt = number; + type typed_array = Js_typed_array2.Uint32Array.typed_array; + type t = Uint32Array.typed_array; +} +export type Uint32Array = { +}; +export const $$Uint32Array: Uint32Array; + +declare namespace Float32Array { + type elt = number; + type typed_array = Js_typed_array2.Float32Array.typed_array; + type t = Float32Array.typed_array; +} +export type Float32Array = { +}; +export const $$Float32Array: Float32Array; + +declare namespace Float64Array { + type elt = number; + type typed_array = Js_typed_array2.Float64Array.typed_array; + type t = Float64Array.typed_array; +} +export type Float64Array = { +}; +export const $$Float64Array: Float64Array; + +declare namespace DataView { + type t = Js_typed_array2.DataView.t; +} +export type DataView = { +}; +export const $$DataView: DataView; diff --git a/packages/@rescript/runtime/lib/es6/Js_typed_array2.d.ts b/packages/@rescript/runtime/lib/es6/Js_typed_array2.d.ts new file mode 100644 index 0000000000..1610e14a5d --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_typed_array2.d.ts @@ -0,0 +1,101 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Stdlib_ArrayBuffer from "./Stdlib_ArrayBuffer.js"; + +export type array_buffer = Stdlib_ArrayBuffer.t; + +export type array_like = rescript.opaque<"Js_typed_array2.array_like", [A]>; + +declare namespace ArrayBuffer { + type t = array_buffer; +} +export type ArrayBuffer = { +}; +export const $$ArrayBuffer: ArrayBuffer; + +declare namespace Int8Array { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Int8Array.typed_array", [A]>; + type t = Int8Array.typed_array; +} +export type Int8Array = { +}; +export const $$Int8Array: Int8Array; + +declare namespace Uint8Array { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Uint8Array.typed_array", [A]>; + type t = Uint8Array.typed_array; +} +export type Uint8Array = { +}; +export const $$Uint8Array: Uint8Array; + +declare namespace Uint8ClampedArray { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Uint8ClampedArray.typed_array", [A]>; + type t = Uint8ClampedArray.typed_array; +} +export type Uint8ClampedArray = { +}; +export const $$Uint8ClampedArray: Uint8ClampedArray; + +declare namespace Int16Array { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Int16Array.typed_array", [A]>; + type t = Int16Array.typed_array; +} +export type Int16Array = { +}; +export const $$Int16Array: Int16Array; + +declare namespace Uint16Array { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Uint16Array.typed_array", [A]>; + type t = Uint16Array.typed_array; +} +export type Uint16Array = { +}; +export const $$Uint16Array: Uint16Array; + +declare namespace Int32Array { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Int32Array.typed_array", [A]>; + type t = Int32Array.typed_array; +} +export type Int32Array = { +}; +export const $$Int32Array: Int32Array; + +declare namespace Uint32Array { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Uint32Array.typed_array", [A]>; + type t = Uint32Array.typed_array; +} +export type Uint32Array = { +}; +export const $$Uint32Array: Uint32Array; + +declare namespace Float32Array { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Float32Array.typed_array", [A]>; + type t = Float32Array.typed_array; +} +export type Float32Array = { +}; +export const $$Float32Array: Float32Array; + +declare namespace Float64Array { + type elt = number; + type typed_array = rescript.opaque<"Js_typed_array2.Float64Array.typed_array", [A]>; + type t = Float64Array.typed_array; +} +export type Float64Array = { +}; +export const $$Float64Array: Float64Array; + +declare namespace DataView { + type t = rescript.opaque<"Js_typed_array2.DataView.t", []>; +} +export type DataView = { +}; +export const $$DataView: DataView; diff --git a/packages/@rescript/runtime/lib/es6/Js_types.d.ts b/packages/@rescript/runtime/lib/es6/Js_types.d.ts new file mode 100644 index 0000000000..df64422c48 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_types.d.ts @@ -0,0 +1,58 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Stdlib_Symbol from "./Stdlib_Symbol.js"; +import type * as Stdlib_Type from "./Stdlib_Type.js"; + +export type symbol_ = Stdlib_Symbol.t; + +export type obj_val = Stdlib_Type.Classify.object_; + +export type undefined_val = rescript.opaque<"Js_types.undefined_val", []>; + +export type null_val = rescript.opaque<"Js_types.null_val", []>; + +export type function_val = Stdlib_Type.Classify.function_; + +type t$bigint = t$BigInt; +type t$bool = t$Boolean; +type t$float = t$Number; +type t$function_val = t$Function; +type t$null_val = t$Null; +type t$obj_val = t$Object; +type t$string = t$String; +type t$symbol = t$Symbol; +type t$undefined_val = t$Undefined; +type t$Undefined = "Undefined"; +type t$Null = "Null"; +type t$Boolean = "Boolean"; +type t$Number = "Number"; +type t$String = "String"; +type t$Function = "Function"; +type t$Object = "Object"; +type t$Symbol = "Symbol"; +type t$BigInt = "BigInt"; +export type t<_ extends undefined_val | null_val | boolean | number | string | function_val | obj_val | symbol | bigint = undefined_val | null_val | boolean | number | string | function_val | obj_val | symbol | bigint> = + | t$Undefined + | t$Null + | t$Boolean + | t$Number + | t$String + | t$Function + | t$Object + | t$Symbol + | t$BigInt; + +export type tagged_t = + | "JSFalse" + | "JSTrue" + | "JSNull" + | "JSUndefined" + | { readonly TAG: "JSNumber"; readonly _0: number } + | { readonly TAG: "JSString"; readonly _0: string } + | { readonly TAG: "JSFunction"; readonly _0: function_val } + | { readonly TAG: "JSObject"; readonly _0: obj_val } + | { readonly TAG: "JSSymbol"; readonly _0: symbol } + | { readonly TAG: "JSBigInt"; readonly _0: bigint }; + +export function classify(x: A): tagged_t; + +export function test(x: A, v: t): boolean; diff --git a/packages/@rescript/runtime/lib/es6/Js_undefined.d.ts b/packages/@rescript/runtime/lib/es6/Js_undefined.d.ts new file mode 100644 index 0000000000..506519611d --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_undefined.d.ts @@ -0,0 +1,22 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Primitive_js_extern from "./Primitive_js_extern.js"; + +export type t = Primitive_js_extern.undefined_; + +export function to_opt(arg0: t): rescript.option; + +export function toOption(arg0: t): rescript.option; + +export function test(x: t): boolean; + +export function testAny(x: A): boolean; + +export function getExn(f: t): A; + +export function bind(x: t, f: (arg0: A) => B): t; + +export function iter(x: t, f: (arg0: A) => void): void; + +export function fromOption(x: rescript.option): t; + +export function from_opt(arg0: rescript.option): t; diff --git a/packages/@rescript/runtime/lib/es6/Js_weakmap.d.ts b/packages/@rescript/runtime/lib/es6/Js_weakmap.d.ts new file mode 100644 index 0000000000..b125328a62 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_weakmap.d.ts @@ -0,0 +1,3 @@ +import type * as Stdlib_WeakMap from "./Stdlib_WeakMap.js"; + +export type t = Stdlib_WeakMap.t; diff --git a/packages/@rescript/runtime/lib/es6/Js_weakset.d.ts b/packages/@rescript/runtime/lib/es6/Js_weakset.d.ts new file mode 100644 index 0000000000..bdccc0e918 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Js_weakset.d.ts @@ -0,0 +1,3 @@ +import type * as Stdlib_WeakSet from "./Stdlib_WeakSet.js"; + +export type t = Stdlib_WeakSet.t; diff --git a/packages/@rescript/runtime/lib/es6/Jsx.d.ts b/packages/@rescript/runtime/lib/es6/Jsx.d.ts new file mode 100644 index 0000000000..e744733d60 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Jsx.d.ts @@ -0,0 +1,7 @@ +import type * as rescript from "@rescript/runtime/types"; + +export type element = rescript.opaque<"Jsx.element", []>; + +export type componentLike = (arg0: Props) => Return; + +export type component = componentLike; diff --git a/packages/@rescript/runtime/lib/es6/JsxDOM.d.ts b/packages/@rescript/runtime/lib/es6/JsxDOM.d.ts new file mode 100644 index 0000000000..cf04482c03 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/JsxDOM.d.ts @@ -0,0 +1,536 @@ +import type * as rescript from "@rescript/runtime/types"; +import type * as Jsx from "./Jsx.js"; +import type * as JsxDOMStyle from "./JsxDOMStyle.js"; +import type * as JsxEvent from "./JsxEvent.js"; + +export type style = JsxDOMStyle.t; + +export type domRef = rescript.opaque<"JsxDOM.domRef", []>; + +export type popover = + | "auto" + | "manual" + | "hint"; + +export type popoverTargetAction = + | "toggle" + | "show" + | "hide"; + +export interface domProps { + readonly key?: rescript.option; + readonly children?: rescript.option; + readonly ref?: rescript.option; + readonly allow?: rescript.option; + readonly "aria-current"?: rescript.option<"page" | "false" | "time" | "location" | "true" | "step" | "date">; + readonly "aria-details"?: rescript.option; + readonly "aria-disabled"?: rescript.option; + readonly "aria-hidden"?: rescript.option; + readonly "aria-invalid"?: rescript.option<"false" | "spelling" | "grammar" | "true">; + readonly "aria-keyshortcuts"?: rescript.option; + readonly "aria-label"?: rescript.option; + readonly "aria-roledescription"?: rescript.option; + readonly "aria-autocomplete"?: rescript.option<"none" | "inline" | "both" | "list">; + readonly "aria-checked"?: rescript.option<"false" | "mixed" | "true">; + readonly "aria-expanded"?: rescript.option; + readonly "aria-haspopup"?: rescript.option<"tree" | "dialog" | "listbox" | "false" | "true" | "menu" | "grid">; + readonly "aria-level"?: rescript.option; + readonly "aria-modal"?: rescript.option; + readonly "aria-multiline"?: rescript.option; + readonly "aria-multiselectable"?: rescript.option; + readonly "aria-orientation"?: rescript.option<"undefined" | "horizontal" | "vertical">; + readonly "aria-placeholder"?: rescript.option; + readonly "aria-pressed"?: rescript.option<"false" | "mixed" | "true">; + readonly "aria-readonly"?: rescript.option; + readonly "aria-required"?: rescript.option; + readonly "aria-selected"?: rescript.option; + readonly "aria-sort"?: rescript.option; + readonly "aria-valuemax"?: rescript.option; + readonly "aria-valuemin"?: rescript.option; + readonly "aria-valuenow"?: rescript.option; + readonly "aria-valuetext"?: rescript.option; + readonly "aria-atomic"?: rescript.option; + readonly "aria-busy"?: rescript.option; + readonly "aria-live"?: rescript.option<"assertive" | "rude" | "polite" | "off">; + readonly "aria-relevant"?: rescript.option; + readonly "aria-dropeffect"?: rescript.option<"none" | "popup" | "execute" | "link" | "move" | "copy">; + readonly "aria-grabbed"?: rescript.option; + readonly "aria-activedescendant"?: rescript.option; + readonly "aria-colcount"?: rescript.option; + readonly "aria-colindex"?: rescript.option; + readonly "aria-colspan"?: rescript.option; + readonly "aria-controls"?: rescript.option; + readonly "aria-describedby"?: rescript.option; + readonly "aria-errormessage"?: rescript.option; + readonly "aria-flowto"?: rescript.option; + readonly "aria-labelledby"?: rescript.option; + readonly "aria-owns"?: rescript.option; + readonly "aria-posinset"?: rescript.option; + readonly "aria-rowcount"?: rescript.option; + readonly "aria-rowindex"?: rescript.option; + readonly "aria-rowspan"?: rescript.option; + readonly "aria-setsize"?: rescript.option; + readonly defaultChecked?: rescript.option; + readonly defaultValue?: rescript.option; + readonly accessKey?: rescript.option; + readonly capture?: rescript.option<"user" | "environment">; + readonly className?: rescript.option; + readonly contentEditable?: rescript.option; + readonly contextMenu?: rescript.option; + readonly "data-testid"?: rescript.option; + readonly dir?: rescript.option; + readonly draggable?: rescript.option; + readonly hidden?: rescript.option; + readonly id?: rescript.option; + readonly inert?: rescript.option; + readonly lang?: rescript.option; + readonly popover?: rescript.option; + readonly popoverTarget?: rescript.option; + readonly popoverTargetAction?: rescript.option; + readonly role?: rescript.option; + readonly style?: rescript.option