Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 1f808d9

Browse files
committed
Clean up Js.t object parsing, printing and converting
Fixes #277 Fixes #263 Now that rescript-lang/rescript#4967 has landed: - Parse `{"foo": int}` as ocaml `{. foo: int}`. Previously it parsed into ocaml `{. foo: int} Js.t` - Remove a tiny printing optimizations for `Js.t`. - For React's PPX 3, generate objects directly instead of `Js.t` objects. cc @rickyvetter @ryyppy for ppx4. - The re->res converter automatically removes the `Js.t` part. - Said converter has a bug (#263) that converts `Js.t({..}) as 'a` into `{..} as 'a` from naturally forgetting to special-case that path. Now this bug is conveniently ~~made into a feature~~ obsolete.
1 parent 2a4cd8e commit 1f808d9

File tree

10 files changed

+167
-182
lines changed

10 files changed

+167
-182
lines changed

src/reactjs_jsx_ppx_v3.ml

+3-12
Original file line numberDiff line numberDiff line change
@@ -216,23 +216,14 @@ let makePropsExternalSig fnName loc namedArgListWithKeyAndRef propsType =
216216
{ psig_loc = loc; psig_desc = Psig_value (makePropsValue fnName loc namedArgListWithKeyAndRef propsType) }
217217
[@@raises Invalid_argument]
218218

219-
(* Build an AST node for the props name when converted to a Js.t inside the function signature *)
219+
(* Build an AST node for the props name when converted to an object inside the function signature *)
220220
let makePropsName ~loc name = { ppat_desc = Ppat_var { txt = name; loc }; ppat_loc = loc; ppat_attributes = [] }
221221

222222
let makeObjectField loc (str, attrs, type_) = Otag ({ loc; txt = str }, attrs, type_)
223223

224-
(* Build an AST node representing a "closed" Js.t object representing a component's props *)
224+
(* Build an AST node representing a "closed" object representing a component's props *)
225225
let makePropsType ~loc namedTypeList =
226-
Typ.mk ~loc
227-
(Ptyp_constr
228-
( { txt = Ldot (Lident "Js", "t"); loc },
229-
[
230-
{
231-
ptyp_desc = Ptyp_object (List.map (makeObjectField loc) namedTypeList, Closed);
232-
ptyp_loc = loc;
233-
ptyp_attributes = [];
234-
};
235-
] ))
226+
Typ.mk ~loc (Ptyp_object (List.map (makeObjectField loc) namedTypeList, Closed))
236227

237228
(* Builds an AST node for the entire `external` definition of props *)
238229
let makeExternalDecl fnName loc namedArgListWithKeyAndRef namedTypeList =

src/res_ast_conversion.ml

+17-1
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,23 @@ let normalize =
383383
| _ ->
384384
default_mapper.pat mapper p
385385
end;
386+
typ = (fun mapper typ ->
387+
match typ.ptyp_desc with
388+
| Ptyp_constr(
389+
{txt = Longident.Ldot(Longident.Lident "Js", "t")},
390+
[{ptyp_desc = Ptyp_object (fields, openFlag)} as objectType]
391+
) ->
392+
(* Js.t({"a": b}) -> {"a": b}. Since compiler >9.0.1 objects don't
393+
need Js.t wrapping anymore *)
394+
let newFields = fields |> List.map (fun (field: Parsetree.object_field) ->
395+
match field with
396+
| Otag (label, attributes, typ) -> Parsetree.Otag (label, attributes, mapper.typ mapper typ)
397+
| Oinherit typ -> Oinherit (mapper.typ mapper typ)
398+
)
399+
in
400+
{objectType with ptyp_desc = Ptyp_object (newFields, openFlag)}
401+
| _ -> default_mapper.typ mapper typ
402+
);
386403
expr = (fun mapper expr ->
387404
match expr.pexp_desc with
388405
| Pexp_constant (Pconst_string (txt, None)) ->
@@ -569,4 +586,3 @@ let replaceStringLiteralStructure stringData structure =
569586
let replaceStringLiteralSignature stringData signature =
570587
let mapper = stringLiteralMapper stringData in
571588
mapper.Ast_mapper.signature mapper signature
572-

src/res_core.ml

+5-16
Original file line numberDiff line numberDiff line change
@@ -375,17 +375,6 @@ let makeListPattern loc seq ext_opt =
375375
in
376376
handle_seq seq
377377

378-
379-
(* {"foo": bar} -> Js.t({. foo: bar})
380-
* {.. "foo": bar} -> Js.t({.. foo: bar})
381-
* {..} -> Js.t({..}) *)
382-
let makeBsObjType ~attrs ~loc ~closed rows =
383-
let obj = Ast_helper.Typ.object_ ~loc rows closed in
384-
let jsDotTCtor =
385-
Location.mkloc (Longident.Ldot (Longident.Lident "Js", "t")) loc
386-
in
387-
Ast_helper.Typ.constr ~loc ~attrs jsDotTCtor [obj]
388-
389378
(* TODO: diagnostic reporting *)
390379
let lidentOfPath longident =
391380
match Longident.flatten longident |> List.rev with
@@ -3816,7 +3805,7 @@ and parseRecordOrBsObjectType ~attrs p =
38163805
in
38173806
Parser.expect Rbrace p;
38183807
let loc = mkLoc startPos p.prevEndPos in
3819-
makeBsObjType ~attrs ~loc ~closed:closedFlag fields
3808+
Ast_helper.Typ.object_ ~loc ~attrs fields closedFlag
38203809

38213810
(* TODO: check associativity in combination with attributes *)
38223811
and parseTypeAlias p typ =
@@ -4218,7 +4207,7 @@ and parseConstrDeclArgs p =
42184207
in
42194208
Parser.expect Rbrace p;
42204209
let loc = mkLoc startPos p.prevEndPos in
4221-
let typ = makeBsObjType ~attrs:[] ~loc ~closed:closedFlag fields in
4210+
let typ = Ast_helper.Typ.object_ ~loc ~attrs:[] fields closedFlag in
42224211
Parser.optional p Comma |> ignore;
42234212
let moreArgs =
42244213
parseCommaDelimitedRegion
@@ -4269,7 +4258,7 @@ and parseConstrDeclArgs p =
42694258
) in
42704259
Parser.expect Rbrace p;
42714260
let loc = mkLoc startPos p.prevEndPos in
4272-
let typ = makeBsObjType ~attrs:[] ~loc ~closed:closedFlag fields in
4261+
let typ = Ast_helper.Typ.object_ ~loc ~attrs:[] fields closedFlag in
42734262
Parser.optional p Comma |> ignore;
42744263
let moreArgs =
42754264
parseCommaDelimitedRegion
@@ -4601,7 +4590,7 @@ and parseRecordOrBsObjectDecl p =
46014590
Parser.expect Rbrace p;
46024591
let loc = mkLoc startPos p.prevEndPos in
46034592
let typ =
4604-
makeBsObjType ~attrs:[] ~loc ~closed:closedFlag fields
4593+
Ast_helper.Typ.object_ ~loc ~attrs:[] fields closedFlag
46054594
|> parseTypeAlias p
46064595
in
46074596
let typ = parseArrowTypeRest ~es6Arrow:true ~startPos typ p in
@@ -4648,7 +4637,7 @@ and parseRecordOrBsObjectDecl p =
46484637
Parser.expect Rbrace p;
46494638
let loc = mkLoc startPos p.prevEndPos in
46504639
let typ =
4651-
makeBsObjType ~attrs:[] ~loc ~closed:closedFlag fields |> parseTypeAlias p
4640+
Ast_helper.Typ.object_ ~loc ~attrs:[] fields closedFlag |> parseTypeAlias p
46524641
in
46534642
let typ = parseArrowTypeRest ~es6Arrow:true ~startPos typ p in
46544643
(Some typ, Asttypes.Public, Parsetree.Ptype_abstract)

src/res_printer.ml

+16-23
Original file line numberDiff line numberDiff line change
@@ -1423,16 +1423,22 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl =
14231423
doc
14241424
in
14251425
Doc.concat [typ; Doc.text " as "; Doc.concat [Doc.text "'"; printIdentLike alias]]
1426-
| Ptyp_constr({txt = Longident.Ldot(Longident.Lident "Js", "t")}, [{ptyp_desc = Ptyp_object (_fields, _openFlag)} as typ]) ->
1427-
let bsObject = printTypExpr typ cmtTbl in
1428-
begin match typExpr.ptyp_attributes with
1429-
| [] -> bsObject
1430-
| attrs ->
1431-
Doc.concat [
1432-
printAttributes ~inline:true attrs cmtTbl;
1433-
printTypExpr typ cmtTbl;
1434-
]
1435-
end
1426+
1427+
(* object printings *)
1428+
| Ptyp_object (fields, openFlag) ->
1429+
(* TODO: remove this once Js.t is gone for good *)
1430+
printBsObjectSugar ~inline:false fields openFlag cmtTbl
1431+
| Ptyp_constr(longidentLoc, [{ptyp_desc = Ptyp_object (fields, openFlag)}]) ->
1432+
(* for foo<{"a": b}>, when the object is long and needs a line break, we
1433+
want the <{ and }> to stay hugged together *)
1434+
let constrName = printLidentPath longidentLoc cmtTbl in
1435+
Doc.concat([
1436+
constrName;
1437+
Doc.lessThan;
1438+
printBsObjectSugar ~inline:true fields openFlag cmtTbl;
1439+
Doc.greaterThan;
1440+
])
1441+
14361442
| Ptyp_constr(longidentLoc, [{ ptyp_desc = Parsetree.Ptyp_tuple tuple }]) ->
14371443
let constrName = printLidentPath longidentLoc cmtTbl in
14381444
Doc.group(
@@ -1447,17 +1453,6 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl =
14471453
let constrName = printLidentPath longidentLoc cmtTbl in
14481454
begin match constrArgs with
14491455
| [] -> constrName
1450-
| [{
1451-
Parsetree.ptyp_desc =
1452-
Ptyp_constr({txt = Longident.Ldot(Longident.Lident "Js", "t")},
1453-
[{ptyp_desc = Ptyp_object (fields, openFlag)}])
1454-
}] ->
1455-
Doc.concat([
1456-
constrName;
1457-
Doc.lessThan;
1458-
printBsObjectSugar ~inline:true fields openFlag cmtTbl;
1459-
Doc.greaterThan;
1460-
])
14611456
| _args -> Doc.group(
14621457
Doc.concat([
14631458
constrName;
@@ -1561,8 +1556,6 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl =
15611556
)
15621557
end
15631558
| Ptyp_tuple types -> printTupleType ~inline:false types cmtTbl
1564-
| Ptyp_object (fields, openFlag) ->
1565-
printBsObjectSugar ~inline:false fields openFlag cmtTbl
15661559
| Ptyp_poly([], typ) ->
15671560
printTypExpr typ cmtTbl
15681561
| Ptyp_poly(stringLocs, typ) ->

tests/parsing/errors/typeDef/__snapshots__/parse.spec.js.snap

+4-5
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,14 @@ exports[`inlineRecord.res 1`] = `
4242
"=====Parsetree==========================================
4343
type nonrec entity =
4444
| Director
45-
| Student of
46-
{
45+
| Student of {
4746
name: string ;
48-
reportCard: < passing: bool ;score: int > Js.t }
47+
reportCard: < passing: bool ;score: int > }
4948
type nonrec user =
5049
{
5150
name: string ;
52-
address: < street: string ;country: string > Js.t }
53-
let make (props : < handleClick: Click.t -> unit ;value: string > Js.t) =
51+
address: < street: string ;country: string > }
52+
let make (props : < handleClick: Click.t -> unit ;value: string > ) =
5453
render props
5554
=====Errors=============================================
5655

tests/parsing/errors/typexpr/__snapshots__/parse.spec.js.snap

+11-13
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,22 @@ module Error3 =
5959
exports[`bsObjSugar.js 1`] = `
6060
"=====Parsetree==========================================
6161
type nonrec state =
62-
< url: [%rescript.typehole ] ;protocols: string array > Js.t
62+
< url: [%rescript.typehole ] ;protocols: string array >
6363
type nonrec state =
64-
< url: [%rescript.typehole ] [@attr ] ;protocols: string array > Js.t
64+
< url: [%rescript.typehole ] [@attr ] ;protocols: string array >
6565
type nonrec state =
6666
< url: string ;protocols: [%rescript.typehole ] ;websocket: Websocket.t
67-
> Js.t
67+
>
68+
type nonrec state = < url: string ;protocols: [%rescript.typehole ] >
69+
type nonrec state = < send: string -> [%rescript.typehole ] [@bs.meth ] >
70+
type nonrec state = < age: [%rescript.typehole ] ;name: string >
6871
type nonrec state =
69-
< url: string ;protocols: [%rescript.typehole ] > Js.t
70-
type nonrec state =
71-
< send: string -> [%rescript.typehole ] [@bs.meth ] > Js.t
72-
type nonrec state = < age: [%rescript.typehole ] ;name: string > Js.t
73-
type nonrec state =
74-
< age: [%rescript.typehole ] [@bs.set ] ;name: string > Js.t
75-
type nonrec state = < age: [%rescript.typehole ] ;.. > Js.t
76-
type nonrec state = < age: [%rescript.typehole ] ;name: string ;.. > Js.t
72+
< age: [%rescript.typehole ] [@bs.set ] ;name: string >
73+
type nonrec state = < age: [%rescript.typehole ] ;.. >
74+
type nonrec state = < age: [%rescript.typehole ] ;name: string ;.. >
7775
type nonrec websocket =
78-
< id: [%rescript.typehole ] ;channel: channelTyp > Js.t
79-
type nonrec websocket = < id: [%rescript.typehole ] > Js.t
76+
< id: [%rescript.typehole ] ;channel: channelTyp >
77+
type nonrec websocket = < id: [%rescript.typehole ] >
8078
=====Errors=============================================
8179
8280
Syntax error!

tests/parsing/grammar/structure/__snapshots__/parse.spec.js.snap

+16-17
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,22 @@ exports[`exceptionDefinition.js 1`] = `
55
exception ExitEarly of int
66
exception ExitEarly of {
77
x: int }
8-
exception ExitEarly of < jsExit: int > Js.t
9-
exception ExitEarly of < jsExit: int [@attr ] > Js.t
10-
exception ExitEarly of < jsExit: int [@attr ] > Js.t
11-
exception ExitEarly of < jsExit: int [@attr ] ;code: int [@attr ] > Js.t
12-
exception ExitEarly of < jsExit: int > Js.t
13-
exception ExitEarly of < jsExit: int > Js.t * < code: int > Js.t
14-
exception ExitEarly of < jsExit: int > Js.t * int * < code: int > Js.t
15-
exception ExitEarly of < jsExit: int [@attr ] ;code: int [@attr ] > Js.t *
16-
< jsExit: int [@attr ] ;code: int [@attr ] > Js.t
17-
exception ExitJsStyle of < .. > Js.t
18-
exception ExitJsStyle of < code: int ;.. > Js.t
19-
exception ExitJsStyle of < code: int ;.. > Js.t
20-
exception ExitJsStyle of < code: int [@attr ] ;.. > Js.t
21-
exception ExitJsStyle of < code: int [@attr ] ;.. > Js.t
22-
exception ExitJsStyle of < code: int ;time: int ;.. > Js.t
23-
exception ExitJsStyle of < code: int [@attr ] ;time: int [@attr ] ;.. >
24-
Js.t
8+
exception ExitEarly of < jsExit: int >
9+
exception ExitEarly of < jsExit: int [@attr ] >
10+
exception ExitEarly of < jsExit: int [@attr ] >
11+
exception ExitEarly of < jsExit: int [@attr ] ;code: int [@attr ] >
12+
exception ExitEarly of < jsExit: int >
13+
exception ExitEarly of < jsExit: int > * < code: int >
14+
exception ExitEarly of < jsExit: int > * int * < code: int >
15+
exception ExitEarly of < jsExit: int [@attr ] ;code: int [@attr ] > *
16+
< jsExit: int [@attr ] ;code: int [@attr ] >
17+
exception ExitJsStyle of < .. >
18+
exception ExitJsStyle of < code: int ;.. >
19+
exception ExitJsStyle of < code: int ;.. >
20+
exception ExitJsStyle of < code: int [@attr ] ;.. >
21+
exception ExitJsStyle of < code: int [@attr ] ;.. >
22+
exception ExitJsStyle of < code: int ;time: int ;.. >
23+
exception ExitJsStyle of < code: int [@attr ] ;time: int [@attr ] ;.. >
2524
exception ExitEarly [@onConstructor ]
2625
exception ExitEarly of int [@onConstructor ]
2726
exception Exit = Terminate

0 commit comments

Comments
 (0)