Skip to content

Commit 39fdfe8

Browse files
authored
Add gentypeconfig.moduleResolution options: node16 and bundler for better interop with TS+ESM projects (#6182)
1 parent 5fef8d3 commit 39fdfe8

File tree

11 files changed

+104
-61
lines changed

11 files changed

+104
-61
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
#### :rocket: Main New Feature
1616

1717
- Add support for Dynamic import. https://github.com/rescript-lang/rescript-compiler/pull/5703
18+
- GenType: Add `moduleResolution` option to customize extensions on emitted import statements. This helps to adjust output compatibility with TypeScript projects using ESM. https://github.com/rescript-lang/rescript-compiler/pull/6182
19+
- `node` (default): Drop extensions.
20+
- `node16`: Use TS output's extensions. Make it ESM-compatible.
21+
- `bundler`: Use TS input's extensions. Make it ESM-compatible.
1822

1923
#### :boom: Breaking Change
2024

jscomp/gentype/EmitType.ml

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,6 @@ let fileHeader ~sourceFile =
1313
~lines:["TypeScript file generated from " ^ sourceFile ^ " by genType."]
1414
^ "/* eslint-disable import/first */\n\n"
1515

16-
let generatedFilesExtension ~(config : Config.t) =
17-
match config.generatedFileExtension with
18-
| Some s ->
19-
(* from .foo.bar to .foo *)
20-
Filename.remove_extension s
21-
| None -> ".gen"
22-
23-
let outputFileSuffix ~(config : Config.t) =
24-
match config.generatedFileExtension with
25-
| Some s when Filename.extension s <> "" (* double extension *) -> s
26-
| _ -> generatedFilesExtension ~config ^ ".tsx"
27-
28-
let generatedModuleExtension ~config = generatedFilesExtension ~config
29-
let shimExtension = ".shim.ts"
30-
3116
let interfaceName ~(config : Config.t) name =
3217
match config.exportInterfaces with
3318
| true -> "I" ^ name
@@ -387,6 +372,13 @@ let emitRequire ~importedValueOrComponent ~early ~emitters ~(config : Config.t)
387372
| true -> "// tslint:disable-next-line:no-var-requires\n"
388373
| false -> "// @ts-ignore: Implicit any on import\n"
389374
in
375+
let importPath =
376+
match config.moduleResolution with
377+
| Node ->
378+
importPath
379+
|> ImportPath.chopExtensionSafe (* for backward compatibility *)
380+
| _ -> importPath
381+
in
390382
match config.module_ with
391383
| ES6 when not importedValueOrComponent ->
392384
let moduleNameString = ModuleName.toString moduleName in

jscomp/gentype/GenTypeConfig.ml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
module ModuleNameMap = Map.Make (ModuleName)
22

33
type module_ = CommonJS | ES6
4+
5+
(** Compatibility for `compilerOptions.moduleResolution` in TypeScript projects. *)
6+
type moduleResolution =
7+
| Node (** should drop extension on import statements *)
8+
| Node16
9+
(** should use TS output's extension (e.g. `.gen.js`) on import statements *)
10+
| Bundler
11+
(** should use TS input's extension (e.g. `.gen.tsx`) on import statements *)
12+
413
type bsVersion = int * int * int
514

615
type t = {
@@ -13,6 +22,7 @@ type t = {
1322
exportInterfaces: bool;
1423
generatedFileExtension: string option;
1524
module_: module_;
25+
moduleResolution: moduleResolution;
1626
namespace: string option;
1727
platformLib: string;
1828
mutable projectRoot: string;
@@ -32,12 +42,13 @@ let default =
3242
exportInterfaces = false;
3343
generatedFileExtension = None;
3444
module_ = ES6;
45+
moduleResolution = Node;
3546
namespace = None;
3647
platformLib = "";
3748
projectRoot = "";
3849
shimsMap = ModuleNameMap.empty;
3950
sources = None;
40-
suffix = "";
51+
suffix = ".bs.js";
4152
}
4253

4354
let bsPlatformLib ~config =
@@ -112,6 +123,7 @@ let readConfig ~getBsConfigFile ~namespace =
112123
in
113124
let parseConfig ~bsconf ~gtconf =
114125
let moduleString = gtconf |> getStringOption "module" in
126+
let moduleResolutionString = gtconf |> getStringOption "moduleResolution" in
115127
let exportInterfacesBool = gtconf |> getBool "exportInterfaces" in
116128
let generatedFileExtensionStringOption =
117129
gtconf |> getStringOption "generatedFileExtension"
@@ -143,6 +155,13 @@ let readConfig ~getBsConfigFile ~namespace =
143155
| None, Some ("es6" | "es6-global") -> ES6
144156
| _ -> default.module_
145157
in
158+
let moduleResolution =
159+
match moduleResolutionString with
160+
| Some "node" -> Node
161+
| Some "node16" -> Node16
162+
| Some "bundler" -> Bundler
163+
| _ -> default.moduleResolution
164+
in
146165
let exportInterfaces =
147166
match exportInterfacesBool with
148167
| None -> default.exportInterfaces
@@ -171,9 +190,8 @@ let readConfig ~getBsConfigFile ~namespace =
171190
in
172191
let suffix =
173192
match bsconf |> getStringOption "suffix" with
174-
| Some ".bs.js" -> ".bs"
175193
| Some s -> s
176-
| _ -> ".bs"
194+
| _ -> default.suffix
177195
in
178196
let bsDependencies =
179197
match bsconf |> getOpt "bs-dependencies" with
@@ -204,6 +222,7 @@ let readConfig ~getBsConfigFile ~namespace =
204222
exportInterfaces;
205223
generatedFileExtension;
206224
module_;
225+
moduleResolution;
207226
namespace;
208227
platformLib;
209228
projectRoot;

jscomp/gentype/GenTypeMain.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ let processCmtFile cmt =
103103
let fileName = cmt |> Paths.getModuleName in
104104
let isInterface = Filename.check_suffix cmtFile ".cmti" in
105105
let resolver =
106-
ModuleResolver.createLazyResolver ~config
107-
~extensions:[".res"; EmitType.shimExtension] ~excludeFile:(fun fname ->
106+
ModuleResolver.createLazyResolver ~config ~extensions:[".res"; ".shim.ts"]
107+
~excludeFile:(fun fname ->
108108
fname = "React.res" || fname = "ReasonReact.res")
109109
in
110110
let inputCMT, hasGenTypeAnnotations =

jscomp/gentype/ImportPath.ml

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,17 @@ let fromModule ~dir ~importExtension moduleName =
1313

1414
let fromStringUnsafe s = ("", s)
1515

16-
let chopExtensionSafe s =
17-
try s |> Filename.chop_extension with Invalid_argument _ -> s
16+
let chopExtensionSafe (dir, s) =
17+
try (dir, s |> Filename.chop_extension) with Invalid_argument _ -> (dir, s)
1818

1919
let dump (dir, s) = NodeFilename.concat dir s
2020

2121
let toCmt ~(config : Config.t) ~outputFileRelative (dir, s) =
2222
let open Filename in
23-
concat
24-
(outputFileRelative |> dirname)
25-
(((dir, s |> chopExtensionSafe) |> dump)
26-
^ (match config.namespace with
27-
| None -> ""
28-
| Some name -> "-" ^ name)
29-
^ ".cmt")
23+
concat (outputFileRelative |> dirname) ((dir, s) |> chopExtensionSafe |> dump)
24+
^ (match config.namespace with
25+
| None -> ""
26+
| Some name -> "-" ^ name)
27+
^ ".cmt"
3028

3129
let emit (dir, s) = (dir, s) |> dump

jscomp/gentype/ImportPath.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ open GenTypeCommon
33
type t
44

55
val bsCurryPath : config:Config.t -> t
6+
val chopExtensionSafe : t -> t
67
val dump : t -> string
78
val emit : t -> string
89
val fromModule : dir:string -> importExtension:string -> ModuleName.t -> t

jscomp/gentype/ModuleExtension.ml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
open GenTypeCommon
2+
3+
let shimTsOutputFileExtension ~(config : Config.t) =
4+
match config.moduleResolution with
5+
| Node -> ".shim"
6+
| Node16 -> ".shim.js"
7+
| Bundler -> ".shim.ts"
8+
9+
let generatedFilesExtension ~(config : Config.t) =
10+
match config.generatedFileExtension with
11+
| Some s ->
12+
(* from .foo.bar to .foo *)
13+
Filename.remove_extension s
14+
| None -> ".gen"
15+
16+
let tsInputFileSuffix ~(config : Config.t) =
17+
match config.generatedFileExtension with
18+
| Some s when Filename.extension s <> "" (* double extension *) -> s
19+
| _ -> generatedFilesExtension ~config ^ ".tsx"
20+
21+
let tsOutputFileSuffix ~(config : Config.t) =
22+
generatedFilesExtension ~config ^ ".js"
23+
24+
let generatedModuleExtension ~(config : Config.t) =
25+
match config.moduleResolution with
26+
| Node -> generatedFilesExtension ~config
27+
| Node16 -> tsOutputFileSuffix ~config
28+
| Bundler -> tsInputFileSuffix ~config

jscomp/gentype/ModuleResolver.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ let resolveGeneratedModule ~config ~outputFileRelative ~resolver moduleName =
256256
(moduleName |> ModuleName.toString);
257257
let importPath =
258258
resolveModule ~config
259-
~importExtension:(EmitType.generatedModuleExtension ~config)
259+
~importExtension:(ModuleExtension.generatedModuleExtension ~config)
260260
~outputFileRelative ~resolver ~useBsDependencies:true moduleName
261261
in
262262
if !Debug.moduleResolution then
@@ -272,9 +272,10 @@ let importPathForReasonModuleName ~(config : Config.t) ~outputFileRelative
272272
| shimModuleName ->
273273
if !Debug.moduleResolution then
274274
Log_.item "ShimModuleName: %s\n" (shimModuleName |> ModuleName.toString);
275+
let importExtension = ModuleExtension.shimTsOutputFileExtension ~config in
275276
let importPath =
276-
resolveModule ~config ~importExtension:".shim" ~outputFileRelative
277-
~resolver ~useBsDependencies:false shimModuleName
277+
resolveModule ~config ~importExtension ~outputFileRelative ~resolver
278+
~useBsDependencies:false shimModuleName
278279
in
279280
if !Debug.moduleResolution then
280281
Log_.item "Import Path: %s\n" (importPath |> ImportPath.dump);

jscomp/gentype/Paths.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ let findNameSpace cmt =
2929
|> keepAfterDash
3030

3131
let getOutputFileRelative ~config cmt =
32-
(cmt |> handleNamespace) ^ EmitType.outputFileSuffix ~config
32+
(cmt |> handleNamespace) ^ ModuleExtension.tsInputFileSuffix ~config
3333

3434
let getOutputFile ~(config : Config.t) cmt =
3535
Filename.concat config.projectRoot (getOutputFileRelative ~config cmt)

jscomp/gentype_tests/typescript-react-example/package-lock.json

Lines changed: 25 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jscomp/gentype_tests/typescript-react-example/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
"tsc": "tsc -p tsconfig.json"
1515
},
1616
"devDependencies": {
17-
"@types/node": "^13.13.4",
18-
"@types/react-dom": "^16.9.7",
17+
"@types/node": "^18.15.12",
18+
"@types/react-dom": "^18.0.11",
1919
"rescript": "file:../../..",
20-
"typescript": "3.9.2"
20+
"typescript": "^5.0.4"
2121
}
2222
}

0 commit comments

Comments
 (0)