Skip to content

Commit 94ef666

Browse files
fix: record field names incorrectly emitted by genType (#8087)
I managed to find the source of this with Claude's help, though I don't have enough experience with ocaml to know for sure if this is an idiomatic fix. resolves #8086 Signed-off-by: Rob <[email protected]> Co-authored-by: Christoph Knittel <[email protected]>
1 parent 1798a6d commit 94ef666

File tree

6 files changed

+72
-3
lines changed

6 files changed

+72
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
- Fix rewatch panic on duplicate module name. https://github.com/rescript-lang/rescript/pull/8102
3131
- Fix `let?` unwrap to use actual variable names from pattern instead of hardcoded "x"/"e". When using `let? Some(myVar) = ...`, the variable name `myVar` is now properly propagated in early returns. https://github.com/rescript-lang/rescript/issues/8085
3232
- Fix 'Ill-formed list of warnings' errors for ppx's with rescript-legacy. https://github.com/rescript-lang/rescript/pull/8103
33+
- Fix gentype generating invalid syntax for exotic / escaped record field names and type names. https://github.com/rescript-lang/rescript/pull/8087
3334

3435
#### :memo: Documentation
3536

compiler/gentype/GenTypeCommon.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ let ident ?(builtin = true) ?(type_args = []) name =
180180
Ident {builtin; name; type_args}
181181

182182
let sanitize_type_name name =
183-
name
183+
name |> Ext_ident.unwrap_uppercase_exotic
184184
|> String.map (function
185185
| '\'' -> '_'
186186
| c -> c)

compiler/gentype/TranslateTypeDeclarations.ml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,15 @@ let create_case (label, attributes) ~poly =
4141
* If @genType.as is used, perform renaming conversion.
4242
* If @as is used (with records-as-objects active), escape and quote if
4343
* the identifier contains characters which are invalid as JS property names.
44+
* For escaped identifiers like \"foo-bar", strip the surrounding \"..."
45+
* since they are part of the ReScript syntax, not the actual field name.
46+
* The resulting name will be quoted later in EmitType if needed.
4447
*)
4548
let rename_record_field ~attributes ~name =
4649
attributes |> Annotation.check_unsupported_gentype_as_renaming;
4750
match attributes |> Annotation.get_as_string with
4851
| Some s -> s |> String.escaped
49-
| None -> name
52+
| None -> name |> Ext_ident.unwrap_uppercase_exotic
5053

5154
let traslate_declaration_kind ~config ~loc ~output_file_relative ~resolver
5255
~type_attributes ~type_env ~type_name ~type_vars declaration_kind :
@@ -290,7 +293,9 @@ let traslate_declaration_kind ~config ~loc ~output_file_relative ~resolver
290293
create_variant ~inherits:[] ~no_payloads ~payloads ~polymorphic:false
291294
~tag:tag_annotation ~unboxed:unboxed_annotation
292295
in
293-
let resolved_type_name = type_name |> TypeEnv.add_module_path ~type_env in
296+
let resolved_type_name =
297+
type_name |> sanitize_type_name |> TypeEnv.add_module_path ~type_env
298+
in
294299
let export_from_type_declaration =
295300
{
296301
CodeItem.export_type =
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* TypeScript file generated from EscapedNames.res by genType. */
2+
3+
/* eslint-disable */
4+
/* tslint:disable */
5+
6+
import * as EscapedNamesJS from './EscapedNames.res.js';
7+
8+
export type variant = "Illegal\"Name";
9+
10+
export type UppercaseVariant = "Illegal\"Name";
11+
12+
export type polymorphicVariant = "Illegal\"Name";
13+
14+
export type object_ = { readonly normalField: number; readonly "escape\"me": number };
15+
16+
export type record = {
17+
readonly normalField: variant;
18+
readonly "Renamed'Field": number;
19+
readonly "Illegal-field name": number;
20+
readonly UPPERCASE: number
21+
};
22+
23+
export const myRecord: record = EscapedNamesJS.myRecord as any;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@genType
2+
type variant = | @as("Illegal\"Name") IllegalName
3+
4+
@genType
5+
type \"UppercaseVariant" = | @as("Illegal\"Name") IllegalName
6+
7+
@genType
8+
type polymorphicVariant = [#"Illegal\"Name"]
9+
10+
@genType
11+
type object_ = {"normalField": int, "escape\"me": int}
12+
13+
@genType
14+
type record = {
15+
normalField: variant,
16+
@as("Renamed'Field") renamedField: int,
17+
\"Illegal-field name": int,
18+
\"UPPERCASE": int,
19+
}
20+
@genType
21+
let myRecord = {
22+
normalField: IllegalName,
23+
renamedField: 42,
24+
\"Illegal-field name": 7,
25+
\"UPPERCASE": 100,
26+
}

tests/gentype_tests/typescript-react-example/src/EscapedNames.res.js

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

0 commit comments

Comments
 (0)