diff --git a/build/build.fs b/build/build.fs index 748454b..08e6554 100644 --- a/build/build.fs +++ b/build/build.fs @@ -184,8 +184,10 @@ module Test = // "safe" package which depends on another "safe" package "safe", !! "node_modules/@types/yargs-parser/index.d.ts", []; "safe", !! "node_modules/@types/yargs/index.d.ts", []; - "minimal", !! "node_modules/@types/vscode/index.d.ts", ["--readable-names"]; + + // #404: package with mutually recursive files (requires --merge) + "minimal", !! "node_modules/playwright-core/index.d.ts" ++ "node_modules/playwright-core/types/*.d.ts", ["--merge"]; ] for preset, package, additionalOptions in packages do @@ -194,6 +196,15 @@ module Test = $"--preset {preset}"; $"-o {outputDir}"] @ additionalOptions) package + // patches for playwright-core + Shell.replaceInFiles [ + "Readable.t", "Readable.t<'t>" + "URL.t", "NodeJs.Url.t" + ] [ + outputDir "playwright_core.resi" + outputDir "playwright_core.res" + ] + let build () = Shell.mkdir srcGeneratedDir for file in outputDir |> Shell.copyRecursiveTo true srcGeneratedDir do diff --git a/dist/res/src/ts2ocaml.res b/dist/res/src/ts2ocaml.res index 9721b3c..c05624e 100644 --- a/dist/res/src/ts2ocaml.res +++ b/dist/res/src/ts2ocaml.res @@ -25,7 +25,9 @@ type true_ = bool type false_ = bool type intrinsic = private string type object = Type.Classify.object +module Object = { type t = object } type function = Type.Classify.function +module Function = { type t = function } module Union = { type container<+'cases> diff --git a/lib/Extensions.fs b/lib/Extensions.fs index fcd9b8c..4e647ef 100644 --- a/lib/Extensions.fs +++ b/lib/Extensions.fs @@ -147,6 +147,26 @@ type StringBuilder (s: string) = type StringBuilder = System.Text.StringBuilder #endif +type OptionBuilder() = + member inline _.Bind (v,f) = Option.bind f v + member inline _.Return v = Some v + member inline _.BindReturn (v, f) = Option.map f v + member inline _.Bind2Return (v1, v2, f) = Option.map2 f v1 v2 + member inline _.Bind3Return (v1, v2, v3, f) = Option.map3 f v1 v2 v3 + member _.MergeSources (v1, v2) = + match v1, v2 with + | Some x1, Some x2 -> Some (x1, x2) + | _, _ -> None + member _.MergeSources3 (v1, v2, v3) = + match v1, v2, v3 with + | Some x1, Some x2, Some x3 -> Some (x1, x2, x3) + | _, _, _ -> None + member inline _.For (xs, f) = Seq.tryPick f xs + member inline _.ReturnFrom o = o + member inline _.Zero () = None + +let option = new OptionBuilder() + open Fable.Core open Fable.Core.JsInterop diff --git a/lib/JsHelper.fs b/lib/JsHelper.fs index 456c1f9..0a1f678 100644 --- a/lib/JsHelper.fs +++ b/lib/JsHelper.fs @@ -247,3 +247,85 @@ let resolveRelativeImportPath (info: Syntax.PackageInfo option) (currentFile: Pa getJsModuleName info targetPath else Valid path + +[] +type NodeBuiltin = + | Assert + | AsyncHooks + | Buffer + | ChildProcess + | Cluster + | Console + | Constants + | Crypto + | Dgram + | DiagnosticsChannel + | Dns + | Domain + | Events + | Fs + | Http + | [] Http2 + | Https + | Inspector + | Module + | Net + | Os + | Path + | PerfHooks + | Process + | Punycode + | Querystring + | Readline + | Repl + | Stream + | StringDecoder + | Timers + | Tls + | TraceEvents + | Tty + | Url + | Util + | [] V8 + | Vm + | Wasi + | WorkerThreads + | Zlib + +let nodeBuiltins : Set = + set [ + NodeBuiltin.Assert; NodeBuiltin.AsyncHooks; NodeBuiltin.Buffer; NodeBuiltin.ChildProcess; + NodeBuiltin.Cluster; NodeBuiltin.Console; NodeBuiltin.Constants; NodeBuiltin.Crypto; + NodeBuiltin.Dgram; NodeBuiltin.DiagnosticsChannel; NodeBuiltin.Dns; NodeBuiltin.Domain; + NodeBuiltin.Events; NodeBuiltin.Fs; NodeBuiltin.Http; NodeBuiltin.Http2; NodeBuiltin.Https; + NodeBuiltin.Inspector; NodeBuiltin.Module; NodeBuiltin.Net; NodeBuiltin.Net; NodeBuiltin.Os; + NodeBuiltin.Path; NodeBuiltin.PerfHooks; NodeBuiltin.Process; NodeBuiltin.Punycode; + NodeBuiltin.Querystring; NodeBuiltin.Readline; NodeBuiltin.Repl; NodeBuiltin.Stream; + NodeBuiltin.StringDecoder; NodeBuiltin.Timers; NodeBuiltin.Tls; NodeBuiltin.TraceEvents; + NodeBuiltin.Tty; NodeBuiltin.Url; NodeBuiltin.Util; NodeBuiltin.V8; NodeBuiltin.Vm; + NodeBuiltin.Wasi; NodeBuiltin.WorkerThreads; NodeBuiltin.Zlib; + ] + +type NodeBuiltinResult = { + name: NodeBuiltin; + subpath: string option; +} + +open System.Text.RegularExpressions + +let nodeBuiltinPattern = new Regex("^(?:node:)?(\\w+)(?:\\/(.+))?$") + +let getNodeBuiltin (specifier: string) : NodeBuiltinResult option = + let res = nodeBuiltinPattern.Match(specifier) + if isNull res || res.Groups.Count < 2 then None + else + let name : NodeBuiltin = !!res.Groups[1].Value + if nodeBuiltins |> Set.contains name |> not then None + else + let subpath = + if res.Groups.Count < 3 then None + else + let subpath = res.Groups[2].Value + if System.String.IsNullOrWhiteSpace subpath then None + else Some subpath + Some { name = name; subpath = subpath } diff --git a/lib/Parser.fs b/lib/Parser.fs index f911c4a..18dc26e 100644 --- a/lib/Parser.fs +++ b/lib/Parser.fs @@ -1145,6 +1145,10 @@ let createDependencyGraph (sourceFiles: Ts.SourceFile[]) = let n = n :?> Ts.ImportDeclaration n.moduleSpecifier |> handleModuleSpecifier sourceFile + | Ts.SyntaxKind.ExportDeclaration -> + let n = n :?> Ts.ExportDeclaration + n.moduleSpecifier + |> Option.iter (handleModuleSpecifier sourceFile) | _ -> () ns |> Array.collect (fun n -> n.getChildren(sourceFile)) diff --git a/lib/Syntax.fs b/lib/Syntax.fs index 61fda9e..8065772 100644 --- a/lib/Syntax.fs +++ b/lib/Syntax.fs @@ -754,6 +754,13 @@ and ImportClause = /// import name = identifier /// ``` | LocalImport of {| name: string; kind: Set option; target: Ident |} + member this.importedName = + match this with + | NamespaceImport i -> Some i.name + | ES6WildcardImport _ -> None + | ES6Import i -> i.renameAs |> Option.orElse (Some i.name) + | ES6DefaultImport i -> Some i.name + | LocalImport i -> Some i.name member this.kind = match this with | NamespaceImport i -> i.kind diff --git a/package.json b/package.json index 5d8483f..fc4cbc3 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "cassandra-driver": "^4.6.3", "cdk8s": "^2.2.41", "monaco-editor": "0.47.0", + "playwright": "^1.43.1", "react-player": "2.16.0", "rescript": "11.1.0", "ts2fable": "0.8.0-build.723", diff --git a/src/Targets/ReScript/ReScriptHelper.fs b/src/Targets/ReScript/ReScriptHelper.fs index 5591ecc..27e0b73 100644 --- a/src/Targets/ReScript/ReScriptHelper.fs +++ b/src/Targets/ReScript/ReScriptHelper.fs @@ -152,7 +152,7 @@ module Naming = let reservedModuleNames = Set.ofList [ - "Export"; "Default"; "Types" + "Export"; "Default"; "Types"; "NodeJs" ] |> Set.union keywords let moduleNameReserved (name: string) = @@ -588,3 +588,165 @@ module Binding = | Binding.Ext x -> yield Statement.external x.attrs x.name x.ty x.target | Binding.Unknown x -> match x.msg with Some msg -> yield comment msg | None -> () ] + +module Import = + open Fable.Core.JsInterop + open JsHelper + type Node = NodeBuiltin + + let isModule (ctx: Typer.TyperContext<_, _>) (name: string) (kind: Set option) = + kind |> Option.map Kind.generatesReScriptModule + |> Option.defaultValue false + || ctx |> Typer.TyperContext.tryCurrentSourceInfo (fun i -> i.unknownIdentTypes |> Trie.containsKey [name]) + |> Option.defaultValue false + || name |> Naming.isCase Naming.PascalCase + + [] + type Statement = + /// `module Name = Target` + | Alias of name:string * target:string + /// `open Name` + | Open of name:string + /// `module Name = { type t = typeName }` + | Type of name:string * typeName:string * typeArgs:string list + /// `module Name = Y.Make()` + | FunctorInstance of name:string * expr:string + | Comment of text + + let alias name target = Statement.Alias (name, target) + let open_ name = Statement.Open name + let type_ name typeName typeArgs = Statement.Type (name, typeName, typeArgs) + let instance name expr = Statement.FunctorInstance (name, expr) + let comment text = Statement.Comment text + + let private getDedicatedImportStatementForNodeBuiltin (ctx: Typer.TyperContext<_, _>) (c: ImportClause) = + option { + let! specifier = c.moduleSpecifier + let! builtin = getNodeBuiltin specifier + let moduleName = + match builtin.name with + | Node.Vm -> "VM" + | _ -> Naming.toCase Naming.PascalCase !!builtin.name + let importedName = c.importedName |? "" // this becomes None only when ES6WildcardImport is used + + match builtin.name, builtin.subpath, c with + // special cases + | Node.ChildProcess, None, ES6Import x -> + match x.name with + | "ChildProcess" -> + return alias (Naming.moduleName importedName) "NodeJs.ChildProcess" + | name when name.StartsWith("ExecOptions") -> + return type_ (Naming.moduleName importedName) "NodeJs.ChildProcess.execOptions" [] + | name when name.StartsWith("ExecFileOptions") -> + return type_ (Naming.moduleName importedName) "NodeJs.ChildProcess.execFileOptions" [] + | _ -> + return alias (Naming.moduleName importedName) $"NodeJs.ChildProcess.{x.name}" + | Node.Console, None, ES6Import x when x.name = "ConsoleConstructorOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Console.consoleOptions" [] + | Node.Dns, None, ES6Import x when x.name.StartsWith("Lookup") && x.name.EndsWith("Options") -> + return type_ (Naming.moduleName importedName) "NodeJs.Dns.options" [] + | Node.Events, None, ES6Import x when x.name = "EventEmitter" -> + return instance (Naming.moduleName importedName) "NodeJs.EventEmitter.Make()" + | Node.Fs, _, ES6Import x -> + match builtin.subpath, x.name with + | None, "ReadStreamOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Fs.createReadStreamOptions" [] + | None, "WriteStreamOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Fs.createWriteStreamOptions" ["'t"] + | None, "WriteFileOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Fs.writeFileOptions" [] + | _, _ -> + return alias (Naming.moduleName importedName) $"NodeJs.Fs.{x.name}" + | Node.Http, None, ES6Import x -> + match x.name with + | "IncomingHttpHeaders" | "OutgoingHttpHeaders" -> + return type_ (Naming.moduleName importedName) "NodeJs.Http.headersObject" [] + | "ServerOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Http.createServerOptions" [] + | "RequestOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Http.requestOptions" [] + | _ -> + return alias (Naming.moduleName importedName) $"NodeJs.Http.{x.name}" + | Node.Http2, None, ES6Import x when x.name = "Settings" -> + return type_ (Naming.moduleName importedName) "NodeJs.Http2.settingsObject" [] + | Node.Https, None, ES6Import x -> + match x.name with + | "Server" -> + return alias (Naming.moduleName importedName) "NodeJs.Https.HttpsServer" + | "Agent" -> + return alias (Naming.moduleName importedName) "NodeJs.Https.Agent" + // rescript-nodejs doesn't have these, but it has fallback types + | "ServerOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Http.createServerOptions" [] + | "RequestOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Http.requestOptions" [] + | _ -> + return alias (Naming.moduleName importedName) $"NodeJs.Https.{x.name}" + | Node.Net, None, ES6Import x when x.name = "AddressInfo" -> + return type_ (Naming.moduleName importedName) "NodeJs.Net.address" [] + | Node.Os, None, ES6Import x when x.name = "CpuInfo" -> + return type_ (Naming.moduleName importedName) "NodeJs.Os.cpu" [] + | Node.Os, None, ES6Import x when x.name = "ParsedPath" || x.name = "FormatInputPathObject" -> + return type_ (Naming.moduleName importedName) "NodeJs.Path.t" [] + | Node.Tls, None, ES6Import x -> + match x.name with + | "TLSSocket" -> + return alias (Naming.moduleName importedName) "NodeJs.Tls.TlsSocket" + | "Server" -> + return alias (Naming.moduleName importedName) "NodeJs.Tls.TlsServer" + | _ -> + return alias (Naming.moduleName importedName) $"NodeJs.Tls.{x.name}" + | Node.Url, None, ES6Import x -> + match x.name with + | "UrlObject" | "Url" | "UrlWithParsedQuery" | "UrlWithStringQuery" | "URL" -> + return alias (Naming.moduleName importedName) "NodeJs.Url" + | "URLSearchParams" -> + return alias (Naming.moduleName importedName) "NodeJs.Url.SearchParams" + | "URLFormatOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Url.urlFormatOptions" [] + | _ -> + return alias (Naming.moduleName importedName) $"NodeJs.Url.{x.name}" + | Node.Util, None, ES6Import x -> + match x.name with + | "InspectOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.Util.inspectOptions" [] + | _ -> + return alias (Naming.moduleName importedName) $"NodeJs.Util.{x.name}" + | Node.V8, None, ES6Import x -> + match x.name with + | "HeapSpaceInfo" -> + return type_ (Naming.moduleName importedName) "NodeJs.V8.heapSpaceStats" [] + | "HeapInfo" -> + return type_ (Naming.moduleName importedName) "NodeJs.V8.heapStats" [] + | "HeapCodeStatistics" -> + return type_ (Naming.moduleName importedName) "NodeJs.V8.heapCodeStats" [] + | _ -> + return alias (Naming.moduleName importedName) $"NodeJs.V8.{x.name}" + | Node.Vm, None, ES6Import x -> + match x.name with + | "CreateContextOptions" -> + return type_ (Naming.moduleName importedName) "NodeJs.VM.createContextOptions" [] + | "Context" -> + return type_ (Naming.moduleName importedName) "NodeJs.VM.contextifiedObject" ["'t"] + | _ -> + return alias (Naming.moduleName importedName) $"NodeJs.VM.{x.name}" + + // general cases + // 1. the `t` type right under the module + | (Node.Buffer | Node.ChildProcess | Node.Console | Node.Module | Node.Stream | Node.StringDecoder), None, ES6Import x when x.name = moduleName -> + return alias (Naming.moduleName importedName) $"NodeJs.{moduleName}" + // 2. the module contains submodules with their `t` type + | _, _, _ -> + match c with + | (NamespaceImport _ | ES6DefaultImport _) -> + return alias (Naming.moduleName importedName) $"NodeJs.{moduleName}" + | ES6Import x when isModule ctx x.name x.kind -> + return alias (Naming.moduleName importedName) $"NodeJs.{moduleName}.{x.name}" + | ES6WildcardImport _ -> + return open_ $"NodeJs.{moduleName}" + | _ -> () + } + + let getDedicatedImportStatement (ctx: Typer.TyperContext<_, _>) (c: ImportClause) = + getDedicatedImportStatementForNodeBuiltin ctx c + // TODO: add more dedicated imports? \ No newline at end of file diff --git a/src/Targets/ReScript/Writer.fs b/src/Targets/ReScript/Writer.fs index ce3e7df..94afea0 100644 --- a/src/Targets/ReScript/Writer.fs +++ b/src/Targets/ReScript/Writer.fs @@ -525,9 +525,9 @@ and getLabelOfFullName flags overrideFunc (ctx: Context) (fullName: FullName) (t let inheritingType = InheritingType.KnownIdent {| fullName = fullName; tyargs = typeParams |> List.map (fun tp -> TypeVar tp.name) |} getLabelsFromInheritingTypes flags overrideFunc ctx (Set.singleton inheritingType) |> Choice1Of2 -type StructuredTextItemBase<'TypeDefText, 'Binding, 'EnumCaseText> = +type StructuredTextItemBase<'ImportText, 'TypeDefText, 'Binding, 'EnumCaseText> = /// Will always be emitted at the top of the module. - | ImportText of text + | ImportText of 'ImportText /// Will always be emitted at the next top of the module. | TypeDefText of 'TypeDefText | TypeAliasText of text @@ -538,6 +538,7 @@ type StructuredTextItemBase<'TypeDefText, 'Binding, 'EnumCaseText> = | EnumCaseText of 'EnumCaseText and StructuredTextItem = StructuredTextItemBase< + ImportItem, TypeDefText, (OverloadRenamer -> CurrentScope -> Binding), {| name: string; comments: Comment list |} @@ -574,6 +575,8 @@ and [] Scope = | Global | Ignore +and [] ImportItem = Import.Statement + and [] ExportItem = | Export of {| comments: Comment list; clauses: (ExportClause * Set) list; loc: Location; origText: string |} | ReExport of {| comments: Comment list; clauses: (ReExportClause * Set) list; loc: Location; specifier: string; origText: string |} @@ -1466,6 +1469,7 @@ let emitImport (ctx: Context) (i: Import) : StructuredTextItem list = else match JsHelper.tryGetActualFileNameFromRelativeImportPath ctx.currentSourceFile ctx.state.fileNames specifier with | Some _ -> None // if the imported file is included in the input files, skip emitting it + | _ when ctx.options.merge -> None // if --merge is specified, skip emitting it | None -> JsHelper.resolveRelativeImportPath (ctx.state.info |> Result.toOption) ctx.currentSourceFile ctx.state.fileNames specifier |> JsHelper.InferenceResult.tryUnwrap @@ -1488,21 +1492,21 @@ let emitImport (ctx: Context) (i: Import) : StructuredTextItem list = | Some kind -> kind |> Kind.generatesReScriptModule | None -> x.target |> Ident.getKind ctx |> Kind.generatesReScriptModule if shouldEmit then - [Statement.moduleAlias (Naming.moduleName x.name) (x.target.name |> Naming.structured Naming.moduleName) |> ImportText] + [Import.alias (Naming.moduleName x.name) (x.target.name |> Naming.structured Naming.moduleName) |> ImportText] else [] | NamespaceImport x when isModule x.name x.kind -> getModuleName x.specifier |> Option.map (fun moduleName -> - [Statement.moduleAlias (Naming.moduleName x.name) (sprintf "%s.Export" moduleName) |> ImportText]) + [Import.alias (Naming.moduleName x.name) (sprintf "%s.Export" moduleName) |> ImportText]) |> Option.defaultValue [] | ES6WildcardImport s -> getModuleName s - |> Option.map (fun moduleName -> [Statement.open_ (sprintf "%s.Export" moduleName) |> ImportText]) + |> Option.map (fun moduleName -> [Import.open_ (sprintf "%s.Export" moduleName) |> ImportText]) |> Option.defaultValue [] | ES6DefaultImport x when isModule x.name x.kind -> getModuleName x.specifier |> Option.map (fun moduleName -> - [Statement.moduleAlias (Naming.moduleName x.name) (sprintf "%s.Export.Default" moduleName) |> ImportText]) + [Import.alias (Naming.moduleName x.name) (sprintf "%s.Export.Default" moduleName) |> ImportText]) |> Option.defaultValue [] | ES6Import x when isModule x.name x.kind -> let name = @@ -1511,14 +1515,16 @@ let emitImport (ctx: Context) (i: Import) : StructuredTextItem list = | None -> Naming.moduleName x.name getModuleName x.specifier |> Option.map (fun moduleName -> - [Statement.moduleAlias name (sprintf "%s.Export.%s" moduleName (Naming.moduleName x.name)) |> ImportText]) + [Import.alias name (sprintf "%s.Export.%s" moduleName (Naming.moduleName x.name)) |> ImportText]) |> Option.defaultValue [] | NamespaceImport _ | ES6DefaultImport _ | ES6Import _ -> [] - [ yield! emitComments true i.comments |> List.map ImportText - yield commentStr i.origText |> ImportText + [ yield! emitComments true i.comments |> List.map (Import.comment >> ImportText) + yield commentStr i.origText |> Import.comment |> ImportText for c in i.clauses do - yield! emitImportClause c] + match Import.getDedicatedImportStatement ctx c with + | Some stmt -> yield ImportText stmt + | None -> yield! emitImportClause c ] let createStructuredText (rootCtx: Context) (stmts: Statement list) : StructuredText = let emitTypeFlags = EmitTypeFlags.defaultValue @@ -1743,7 +1749,7 @@ type EmitModuleFlags = {| |} type EmitModuleResult = {| - imports: text list + imports: {| types: text; impl: text; intf: text |} list /// The `Types` module types: text list /// The content of the `.res` file @@ -1833,8 +1839,34 @@ let rec emitModule (dt: DependencyTrie) flags (ctx: Context) st = | Some b, true -> attrs + tmp +@ " = " + b {| types = actual; intf = actual; impl = alias |} + let emitImportStatement (i: ImportItem) = + match i with + | ImportItem.Alias (name, target) -> + let txt = Statement.moduleAlias name target + {| types = txt; intf = txt; impl = txt |} + | ImportItem.Open name -> + let txt = Statement.open_ name + {| types = txt; intf = txt; impl = txt |} + | ImportItem.Type (name, tyName, tyArgs) -> + let typeArgs = tyArgs |> List.map str + let alias = + Statement.typeAlias false "t" typeArgs (Some (Type.appOpt (str tyName) typeArgs)) + let resi = + tprintf "module %s : { " name + alias +@ " }" + let res = + tprintf "module %s = { " name + alias +@ " }" + {| types = resi; intf = resi; impl = res |} + | ImportItem.FunctorInstance (name, expr) -> + let resi = + tprintf "module %s : module type of %s" name expr + let res = + tprintf "module %s = %s" name expr + {| types = resi; intf = resi; impl = res |} + | ImportItem.Comment c -> + {| types = c; intf = c; impl = c |} + let rec f = function - | ImportText t -> ImportText t + | ImportText t -> ImportText (emitImportStatement t) | TypeAliasText t -> TypeAliasText t | TypeDefText d -> TypeDefText (emitTypeDefText d) | Binding b -> Binding (b renamer currentScope) @@ -1855,7 +1887,7 @@ let rec emitModule (dt: DependencyTrie) flags (ctx: Context) st = let children = children |> List.filter (fun (_, _, c) -> c.types |> List.isEmpty |> not) - |> List.map (fun (k, _, c) -> {| k with content = c.imports @ c.types; comments = [] |}) + |> List.map (fun (k, _, c) -> {| k with content = (c.imports |> List.map (fun i -> i.types)) @ c.types; comments = [] |}) |> Statement.moduleSCC dt Statement.moduleSigRec Statement.moduleSigNonRec ctx children @ items @@ -1869,7 +1901,7 @@ let rec emitModule (dt: DependencyTrie) flags (ctx: Context) st = children |> List.filter (fun (_, _, c) -> c.intf |> List.isEmpty |> not) |> List.map (fun (k, _, c) -> - let content = c.imports @ c.intf + let content = (c.imports |> List.map (fun i -> i.intf)) @ c.intf {| k with content = content; comments = c.comments |}) |> Statement.moduleSigRec let typeDefs = @@ -1907,11 +1939,12 @@ let rec emitModule (dt: DependencyTrie) flags (ctx: Context) st = children |> List.filter (fun (_, _, c) -> c.impl |> List.isEmpty |> not) |> List.map (fun (k, openTypesModule, c) -> + let imports = c.imports |> List.map (fun i -> i.impl) let content = if not isLinear && openTypesModule then - Statement.open_ k.name :: c.imports @ c.impl + Statement.open_ k.name :: imports @ c.impl else - c.imports @ c.impl + imports @ c.impl {| k with content = content; comments = c.comments |}) |> Statement.moduleSCC dt fixmeRecursiveModules Statement.moduleValMany ctx let typeDefs = @@ -2114,7 +2147,7 @@ let private emitImpl (sources: SourceFile list) (info: PackageInfo option) (ctx: yield! header yield! m.comments yield! opens - yield! m.imports + yield! m.imports |> List.map (fun i -> i.impl) yield! emitTypes m.types yield! m.impl ] @@ -2124,7 +2157,7 @@ let private emitImpl (sources: SourceFile list) (info: PackageInfo option) (ctx: yield! header yield! m.comments yield! opens - yield! m.imports + yield! m.imports |> List.map (fun i -> i.intf) yield! m.intf ] |> Some else None diff --git a/test/res/package.json b/test/res/package.json index d508aa9..fcbfd25 100644 --- a/test/res/package.json +++ b/test/res/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@rescript/core": "^1.1.0", - "rescript": "11.0.1" + "rescript": "11.0.1", + "rescript-nodejs": "^16.1.0" } } diff --git a/test/res/rescript.json b/test/res/rescript.json index 62b8f63..cce8bf4 100644 --- a/test/res/rescript.json +++ b/test/res/rescript.json @@ -11,7 +11,8 @@ }, "suffix": ".bs.js", "bs-dependencies": [ - "@rescript/core" + "@rescript/core", + "rescript-nodejs" ], "uncurried": true } diff --git a/test/res/src/placeholder/SVGElement.res b/test/res/src/placeholder/SVGElement.res new file mode 100644 index 0000000..d19ccd7 --- /dev/null +++ b/test/res/src/placeholder/SVGElement.res @@ -0,0 +1,3 @@ +type _svgElement<'a> +type svgElement_like<'a> = Dom.element_like<_svgElement<'a>> +type t = svgElement_like \ No newline at end of file diff --git a/test/res/yarn.lock b/test/res/yarn.lock index 6e255a4..83033c6 100644 --- a/test/res/yarn.lock +++ b/test/res/yarn.lock @@ -143,6 +143,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +rescript-nodejs@^16.1.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/rescript-nodejs/-/rescript-nodejs-16.1.0.tgz#2278d8880d9e4a5c46cd845d5ac4ee2bd69277ee" + integrity sha512-RyXGIEsb8UhuShf5PwKcTkYNPz+cPQ0CZq74lbYCbCa5YFidbmiIWpQhCMtpsgP1PkLClhKGDkfZfmwwNOil4Q== + rescript@11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/rescript/-/rescript-11.0.1.tgz#c74af134dc8a16d152169b2456d0720324835f54" @@ -171,10 +176,10 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -typescript@^5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" - integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== +typescript@5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== wrap-ansi@^7.0.0: version "7.0.0" diff --git a/yarn.lock b/yarn.lock index 4acf672..121c459 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1855,7 +1855,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@~2.3.2: +fsevents@2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -2814,6 +2814,20 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +playwright-core@1.43.1: + version "1.43.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.43.1.tgz#0eafef9994c69c02a1a3825a4343e56c99c03b02" + integrity sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg== + +playwright@^1.43.1: + version "1.43.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.43.1.tgz#8ad08984ac66c9ef3d0db035be54dd7ec9f1c7d9" + integrity sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA== + dependencies: + playwright-core "1.43.1" + optionalDependencies: + fsevents "2.3.2" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"