From 21ef5bb1f508af95977737c5d1b35ae75a7ac8ba Mon Sep 17 00:00:00 2001 From: Cheng Lou Date: Sat, 27 Feb 2021 04:41:56 -0800 Subject: [PATCH 1/3] Clean up Js.t object parsing, printing and converting Fixes #277 Fixes #263 Now that https://github.com/rescript-lang/rescript-compiler/pull/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. --- src/reactjs_jsx_ppx_v3.ml | 15 +-- src/res_ast_conversion.ml | 18 +++- src/res_core.ml | 21 +--- src/res_printer.ml | 38 +++---- .../typeDef/__snapshots__/parse.spec.js.snap | 9 +- .../typexpr/__snapshots__/parse.spec.js.snap | 24 +++-- .../__snapshots__/parse.spec.js.snap | 33 +++---- .../__snapshots__/parse.spec.js.snap | 98 +++++++++---------- .../typexpr/__snapshots__/parse.spec.js.snap | 89 +++++++++-------- .../typexpr/__snapshots__/render.spec.js.snap | 3 +- 10 files changed, 166 insertions(+), 182 deletions(-) diff --git a/src/reactjs_jsx_ppx_v3.ml b/src/reactjs_jsx_ppx_v3.ml index 90459954..87a08ed5 100644 --- a/src/reactjs_jsx_ppx_v3.ml +++ b/src/reactjs_jsx_ppx_v3.ml @@ -216,23 +216,14 @@ let makePropsExternalSig fnName loc namedArgListWithKeyAndRef propsType = { psig_loc = loc; psig_desc = Psig_value (makePropsValue fnName loc namedArgListWithKeyAndRef propsType) } [@@raises Invalid_argument] -(* Build an AST node for the props name when converted to a Js.t inside the function signature *) +(* Build an AST node for the props name when converted to an object inside the function signature *) let makePropsName ~loc name = { ppat_desc = Ppat_var { txt = name; loc }; ppat_loc = loc; ppat_attributes = [] } let makeObjectField loc (str, attrs, type_) = Otag ({ loc; txt = str }, attrs, type_) -(* Build an AST node representing a "closed" Js.t object representing a component's props *) +(* Build an AST node representing a "closed" object representing a component's props *) let makePropsType ~loc namedTypeList = - Typ.mk ~loc - (Ptyp_constr - ( { txt = Ldot (Lident "Js", "t"); loc }, - [ - { - ptyp_desc = Ptyp_object (List.map (makeObjectField loc) namedTypeList, Closed); - ptyp_loc = loc; - ptyp_attributes = []; - }; - ] )) + Typ.mk ~loc (Ptyp_object (List.map (makeObjectField loc) namedTypeList, Closed)) (* Builds an AST node for the entire `external` definition of props *) let makeExternalDecl fnName loc namedArgListWithKeyAndRef namedTypeList = diff --git a/src/res_ast_conversion.ml b/src/res_ast_conversion.ml index 86de056a..c4ef8d87 100644 --- a/src/res_ast_conversion.ml +++ b/src/res_ast_conversion.ml @@ -383,6 +383,23 @@ let normalize = | _ -> default_mapper.pat mapper p end; + typ = (fun mapper typ -> + match typ.ptyp_desc with + | Ptyp_constr( + {txt = Longident.Ldot(Longident.Lident "Js", "t")}, + [{ptyp_desc = Ptyp_object (fields, openFlag)} as objectType] + ) -> + (* Js.t({"a": b}) -> {"a": b}. Since compiler >9.0.1 objects don't + need Js.t wrapping anymore *) + let newFields = fields |> List.map (fun (field: Parsetree.object_field) -> + match field with + | Otag (label, attributes, typ) -> Parsetree.Otag (label, attributes, mapper.typ mapper typ) + | Oinherit typ -> Oinherit (mapper.typ mapper typ) + ) + in + {objectType with ptyp_desc = Ptyp_object (newFields, openFlag)} + | _ -> default_mapper.typ mapper typ + ); expr = (fun mapper expr -> match expr.pexp_desc with | Pexp_constant (Pconst_string (txt, None)) -> @@ -569,4 +586,3 @@ let replaceStringLiteralStructure stringData structure = let replaceStringLiteralSignature stringData signature = let mapper = stringLiteralMapper stringData in mapper.Ast_mapper.signature mapper signature - diff --git a/src/res_core.ml b/src/res_core.ml index bdb172b3..ecd8439c 100644 --- a/src/res_core.ml +++ b/src/res_core.ml @@ -375,17 +375,6 @@ let makeListPattern loc seq ext_opt = in handle_seq seq - -(* {"foo": bar} -> Js.t({. foo: bar}) - * {.. "foo": bar} -> Js.t({.. foo: bar}) - * {..} -> Js.t({..}) *) -let makeBsObjType ~attrs ~loc ~closed rows = - let obj = Ast_helper.Typ.object_ ~loc rows closed in - let jsDotTCtor = - Location.mkloc (Longident.Ldot (Longident.Lident "Js", "t")) loc - in - Ast_helper.Typ.constr ~loc ~attrs jsDotTCtor [obj] - (* TODO: diagnostic reporting *) let lidentOfPath longident = match Longident.flatten longident |> List.rev with @@ -3816,7 +3805,7 @@ and parseRecordOrBsObjectType ~attrs p = in Parser.expect Rbrace p; let loc = mkLoc startPos p.prevEndPos in - makeBsObjType ~attrs ~loc ~closed:closedFlag fields + Ast_helper.Typ.object_ ~loc ~attrs fields closedFlag (* TODO: check associativity in combination with attributes *) and parseTypeAlias p typ = @@ -4218,7 +4207,7 @@ and parseConstrDeclArgs p = in Parser.expect Rbrace p; let loc = mkLoc startPos p.prevEndPos in - let typ = makeBsObjType ~attrs:[] ~loc ~closed:closedFlag fields in + let typ = Ast_helper.Typ.object_ ~loc ~attrs:[] fields closedFlag in Parser.optional p Comma |> ignore; let moreArgs = parseCommaDelimitedRegion @@ -4269,7 +4258,7 @@ and parseConstrDeclArgs p = ) in Parser.expect Rbrace p; let loc = mkLoc startPos p.prevEndPos in - let typ = makeBsObjType ~attrs:[] ~loc ~closed:closedFlag fields in + let typ = Ast_helper.Typ.object_ ~loc ~attrs:[] fields closedFlag in Parser.optional p Comma |> ignore; let moreArgs = parseCommaDelimitedRegion @@ -4601,7 +4590,7 @@ and parseRecordOrBsObjectDecl p = Parser.expect Rbrace p; let loc = mkLoc startPos p.prevEndPos in let typ = - makeBsObjType ~attrs:[] ~loc ~closed:closedFlag fields + Ast_helper.Typ.object_ ~loc ~attrs:[] fields closedFlag |> parseTypeAlias p in let typ = parseArrowTypeRest ~es6Arrow:true ~startPos typ p in @@ -4648,7 +4637,7 @@ and parseRecordOrBsObjectDecl p = Parser.expect Rbrace p; let loc = mkLoc startPos p.prevEndPos in let typ = - makeBsObjType ~attrs:[] ~loc ~closed:closedFlag fields |> parseTypeAlias p + Ast_helper.Typ.object_ ~loc ~attrs:[] fields closedFlag |> parseTypeAlias p in let typ = parseArrowTypeRest ~es6Arrow:true ~startPos typ p in (Some typ, Asttypes.Public, Parsetree.Ptype_abstract) diff --git a/src/res_printer.ml b/src/res_printer.ml index e3506d8c..8c77d9e2 100644 --- a/src/res_printer.ml +++ b/src/res_printer.ml @@ -1423,16 +1423,21 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = doc in Doc.concat [typ; Doc.text " as "; Doc.concat [Doc.text "'"; printIdentLike alias]] - | Ptyp_constr({txt = Longident.Ldot(Longident.Lident "Js", "t")}, [{ptyp_desc = Ptyp_object (_fields, _openFlag)} as typ]) -> - let bsObject = printTypExpr typ cmtTbl in - begin match typExpr.ptyp_attributes with - | [] -> bsObject - | attrs -> - Doc.concat [ - printAttributes ~inline:true attrs cmtTbl; - printTypExpr typ cmtTbl; - ] - end + + (* object printings *) + | Ptyp_object (fields, openFlag) -> + printBsObjectSugar ~inline:false fields openFlag cmtTbl + | Ptyp_constr(longidentLoc, [{ptyp_desc = Ptyp_object (fields, openFlag)}]) -> + (* for foo<{"a": b}>, when the object is long and needs a line break, we + want the <{ and }> to stay hugged together *) + let constrName = printLidentPath longidentLoc cmtTbl in + Doc.concat([ + constrName; + Doc.lessThan; + printBsObjectSugar ~inline:true fields openFlag cmtTbl; + Doc.greaterThan; + ]) + | Ptyp_constr(longidentLoc, [{ ptyp_desc = Parsetree.Ptyp_tuple tuple }]) -> let constrName = printLidentPath longidentLoc cmtTbl in Doc.group( @@ -1447,17 +1452,6 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = let constrName = printLidentPath longidentLoc cmtTbl in begin match constrArgs with | [] -> constrName - | [{ - Parsetree.ptyp_desc = - Ptyp_constr({txt = Longident.Ldot(Longident.Lident "Js", "t")}, - [{ptyp_desc = Ptyp_object (fields, openFlag)}]) - }] -> - Doc.concat([ - constrName; - Doc.lessThan; - printBsObjectSugar ~inline:true fields openFlag cmtTbl; - Doc.greaterThan; - ]) | _args -> Doc.group( Doc.concat([ constrName; @@ -1561,8 +1555,6 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = ) end | Ptyp_tuple types -> printTupleType ~inline:false types cmtTbl - | Ptyp_object (fields, openFlag) -> - printBsObjectSugar ~inline:false fields openFlag cmtTbl | Ptyp_poly([], typ) -> printTypExpr typ cmtTbl | Ptyp_poly(stringLocs, typ) -> diff --git a/tests/parsing/errors/typeDef/__snapshots__/parse.spec.js.snap b/tests/parsing/errors/typeDef/__snapshots__/parse.spec.js.snap index 2c46ccc8..7535bb43 100644 --- a/tests/parsing/errors/typeDef/__snapshots__/parse.spec.js.snap +++ b/tests/parsing/errors/typeDef/__snapshots__/parse.spec.js.snap @@ -42,15 +42,14 @@ exports[`inlineRecord.res 1`] = ` "=====Parsetree========================================== type nonrec entity = | Director - | Student of - { + | Student of { name: string ; - reportCard: < passing: bool ;score: int > Js.t } + reportCard: < passing: bool ;score: int > } type nonrec user = { name: string ; - address: < street: string ;country: string > Js.t } -let make (props : < handleClick: Click.t -> unit ;value: string > Js.t) = + address: < street: string ;country: string > } +let make (props : < handleClick: Click.t -> unit ;value: string > ) = render props =====Errors============================================= diff --git a/tests/parsing/errors/typexpr/__snapshots__/parse.spec.js.snap b/tests/parsing/errors/typexpr/__snapshots__/parse.spec.js.snap index 4c3a5ad6..a5825d0d 100644 --- a/tests/parsing/errors/typexpr/__snapshots__/parse.spec.js.snap +++ b/tests/parsing/errors/typexpr/__snapshots__/parse.spec.js.snap @@ -59,24 +59,22 @@ module Error3 = exports[`bsObjSugar.js 1`] = ` "=====Parsetree========================================== type nonrec state = - < url: [%rescript.typehole ] ;protocols: string array > Js.t + < url: [%rescript.typehole ] ;protocols: string array > type nonrec state = - < url: [%rescript.typehole ] [@attr ] ;protocols: string array > Js.t + < url: [%rescript.typehole ] [@attr ] ;protocols: string array > type nonrec state = < url: string ;protocols: [%rescript.typehole ] ;websocket: Websocket.t - > Js.t + > +type nonrec state = < url: string ;protocols: [%rescript.typehole ] > +type nonrec state = < send: string -> [%rescript.typehole ] [@bs.meth ] > +type nonrec state = < age: [%rescript.typehole ] ;name: string > type nonrec state = - < url: string ;protocols: [%rescript.typehole ] > Js.t -type nonrec state = - < send: string -> [%rescript.typehole ] [@bs.meth ] > Js.t -type nonrec state = < age: [%rescript.typehole ] ;name: string > Js.t -type nonrec state = - < age: [%rescript.typehole ] [@bs.set ] ;name: string > Js.t -type nonrec state = < age: [%rescript.typehole ] ;.. > Js.t -type nonrec state = < age: [%rescript.typehole ] ;name: string ;.. > Js.t + < age: [%rescript.typehole ] [@bs.set ] ;name: string > +type nonrec state = < age: [%rescript.typehole ] ;.. > +type nonrec state = < age: [%rescript.typehole ] ;name: string ;.. > type nonrec websocket = - < id: [%rescript.typehole ] ;channel: channelTyp > Js.t -type nonrec websocket = < id: [%rescript.typehole ] > Js.t + < id: [%rescript.typehole ] ;channel: channelTyp > +type nonrec websocket = < id: [%rescript.typehole ] > =====Errors============================================= Syntax error! diff --git a/tests/parsing/grammar/structure/__snapshots__/parse.spec.js.snap b/tests/parsing/grammar/structure/__snapshots__/parse.spec.js.snap index 2d6e1a9e..185ea1ae 100644 --- a/tests/parsing/grammar/structure/__snapshots__/parse.spec.js.snap +++ b/tests/parsing/grammar/structure/__snapshots__/parse.spec.js.snap @@ -5,23 +5,22 @@ exports[`exceptionDefinition.js 1`] = ` exception ExitEarly of int exception ExitEarly of { x: int } -exception ExitEarly of < jsExit: int > Js.t -exception ExitEarly of < jsExit: int [@attr ] > Js.t -exception ExitEarly of < jsExit: int [@attr ] > Js.t -exception ExitEarly of < jsExit: int [@attr ] ;code: int [@attr ] > Js.t -exception ExitEarly of < jsExit: int > Js.t -exception ExitEarly of < jsExit: int > Js.t * < code: int > Js.t -exception ExitEarly of < jsExit: int > Js.t * int * < code: int > Js.t -exception ExitEarly of < jsExit: int [@attr ] ;code: int [@attr ] > Js.t * - < jsExit: int [@attr ] ;code: int [@attr ] > Js.t -exception ExitJsStyle of < .. > Js.t -exception ExitJsStyle of < code: int ;.. > Js.t -exception ExitJsStyle of < code: int ;.. > Js.t -exception ExitJsStyle of < code: int [@attr ] ;.. > Js.t -exception ExitJsStyle of < code: int [@attr ] ;.. > Js.t -exception ExitJsStyle of < code: int ;time: int ;.. > Js.t -exception ExitJsStyle of < code: int [@attr ] ;time: int [@attr ] ;.. > - Js.t +exception ExitEarly of < jsExit: int > +exception ExitEarly of < jsExit: int [@attr ] > +exception ExitEarly of < jsExit: int [@attr ] > +exception ExitEarly of < jsExit: int [@attr ] ;code: int [@attr ] > +exception ExitEarly of < jsExit: int > +exception ExitEarly of < jsExit: int > * < code: int > +exception ExitEarly of < jsExit: int > * int * < code: int > +exception ExitEarly of < jsExit: int [@attr ] ;code: int [@attr ] > * + < jsExit: int [@attr ] ;code: int [@attr ] > +exception ExitJsStyle of < .. > +exception ExitJsStyle of < code: int ;.. > +exception ExitJsStyle of < code: int ;.. > +exception ExitJsStyle of < code: int [@attr ] ;.. > +exception ExitJsStyle of < code: int [@attr ] ;.. > +exception ExitJsStyle of < code: int ;time: int ;.. > +exception ExitJsStyle of < code: int [@attr ] ;time: int [@attr ] ;.. > exception ExitEarly [@onConstructor ] exception ExitEarly of int [@onConstructor ] exception Exit = Terminate diff --git a/tests/parsing/grammar/typedefinition/__snapshots__/parse.spec.js.snap b/tests/parsing/grammar/typedefinition/__snapshots__/parse.spec.js.snap index 830e5d94..ba2a0346 100644 --- a/tests/parsing/grammar/typedefinition/__snapshots__/parse.spec.js.snap +++ b/tests/parsing/grammar/typedefinition/__snapshots__/parse.spec.js.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`bsObject.js 1`] = ` -"type nonrec 'a foo = < foo: int ;.. > Js.t as 'a -type nonrec 'a foo = < foo: int > Js.t as 'a" +"type nonrec 'a foo = < foo: int ;.. > as 'a +type nonrec 'a foo = < foo: int > as 'a" `; exports[`constructorDeclaration.js 1`] = ` @@ -25,23 +25,23 @@ type nonrec t = g: int ; b: int ; a: int } - | JsColor of < gradient: int > Js.t - | JsColor of < gradient: int > Js.t - | JsColor of < gradient: int > Js.t - | JsColor of < gradient: int [@attr ] > Js.t - | JsColor of < gradient: int > Js.t * color - | JsColor of < gradient: int > Js.t * color - | JsColor of < gradient: int > Js.t * < hex: string > Js.t * int - | JsColor of < gradient: int [@attr ] > Js.t * < hex: string [@attr ] > - Js.t * int - | JsT of < .. > Js.t - | JsT of < gradient: int ;.. > Js.t - | JsT of < gradient: int ;.. > Js.t - | JsT of < gradient: int [@attr ] ;.. > Js.t - | JsT of < gradient: int ;hex: string ;.. > Js.t * - < gradient: int ;hex: string ;.. > Js.t - | JsT of < gradient: int [@attr ] ;hex: string [@attr ] ;.. > Js.t * - < gradient: int [@attr ] ;hex: string [@attr ] ;.. > Js.t + | JsColor of < gradient: int > + | JsColor of < gradient: int > + | JsColor of < gradient: int > + | JsColor of < gradient: int [@attr ] > + | JsColor of < gradient: int > * color + | JsColor of < gradient: int > * color + | JsColor of < gradient: int > * < hex: string > * int + | JsColor of < gradient: int [@attr ] > * < hex: string [@attr ] > * + int + | JsT of < .. > + | JsT of < gradient: int ;.. > + | JsT of < gradient: int ;.. > + | JsT of < gradient: int [@attr ] ;.. > + | JsT of < gradient: int ;hex: string ;.. > * + < gradient: int ;hex: string ;.. > + | JsT of < gradient: int [@attr ] ;hex: string [@attr ] ;.. > * + < gradient: int [@attr ] ;hex: string [@attr ] ;.. > type nonrec t = | Rgb: t type nonrec t = @@ -61,24 +61,24 @@ type nonrec t = g: int ; b: int ; a: int } -> t - | JsColor: < gradient: int > Js.t -> t - | JsColor: < gradient: int > Js.t -> t - | JsColor: < gradient: int > Js.t -> t - | JsColor: < gradient: int > Js.t -> t - | JsColor: < gradient: int [@attr ] > Js.t -> t - | JsColor: < gradient: int > Js.t * color -> t - | JsColor: < gradient: int > Js.t * color -> t - | JsColor: < gradient: int > Js.t * < hex: string > Js.t * int -> t - | JsT: < .. > Js.t -> t - | JsT: < gradient: int ;.. > Js.t -> t - | JsT: < gradient: int [@attr ] ;.. > Js.t -> t - | JsT: < gradient: int ;.. > Js.t -> t - | JsT: < gradient: int [@attr ] ;.. > Js.t -> t - | JsT: < gradient: int ;.. > Js.t -> t - | JsT: < gradient: int ;hex: string ;.. > Js.t * - < gradient: int ;hex: string ;.. > Js.t -> t - | JsT: < gradient: int [@attr ] ;hex: string [@attr ] ;.. > Js.t * - < gradient: int [@attr ] ;hex: string [@attr ] ;.. > Js.t -> t + | JsColor: < gradient: int > -> t + | JsColor: < gradient: int > -> t + | JsColor: < gradient: int > -> t + | JsColor: < gradient: int > -> t + | JsColor: < gradient: int [@attr ] > -> t + | JsColor: < gradient: int > * color -> t + | JsColor: < gradient: int > * color -> t + | JsColor: < gradient: int > * < hex: string > * int -> t + | JsT: < .. > -> t + | JsT: < gradient: int ;.. > -> t + | JsT: < gradient: int [@attr ] ;.. > -> t + | JsT: < gradient: int ;.. > -> t + | JsT: < gradient: int [@attr ] ;.. > -> t + | JsT: < gradient: int ;.. > -> t + | JsT: < gradient: int ;hex: string ;.. > * + < gradient: int ;hex: string ;.. > -> t + | JsT: < gradient: int [@attr ] ;hex: string [@attr ] ;.. > * + < gradient: int [@attr ] ;hex: string [@attr ] ;.. > -> t type nonrec t = | EmptyColor [@attr ] | White: grayscale -> ((t)[@onGadt ]) [@onConstr ] @@ -214,18 +214,18 @@ type nonrec t = { type nonrec t = { mutable form: form ; mutable answers: answers } -type nonrec t = < age: int > Js.t -type nonrec t = < .. > Js.t -type nonrec t = < age: int > Js.t -type nonrec t = < age: int ;.. > Js.t -type nonrec t = < age: int ;name: string ;.. > Js.t -type nonrec t = < age: int [@attr ] ;.. > Js.t -type nonrec t = < age: int [@attr ] ;.. > Js.t -type nonrec t = < age: int [@attr ] ;name: string [@attr ] ;.. > Js.t -type nonrec t = < age: int [@attr ] > Js.t -type nonrec t = < age: int [@attr ] > Js.t -type nonrec t = < age: int [@attr ] ;name: string > Js.t -type nonrec t = < age: int [@attr ] ;name: string [@attr2 ] > Js.t +type nonrec t = < age: int > +type nonrec t = < .. > +type nonrec t = < age: int > +type nonrec t = < age: int ;.. > +type nonrec t = < age: int ;name: string ;.. > +type nonrec t = < age: int [@attr ] ;.. > +type nonrec t = < age: int [@attr ] ;.. > +type nonrec t = < age: int [@attr ] ;name: string [@attr ] ;.. > +type nonrec t = < age: int [@attr ] > +type nonrec t = < age: int [@attr ] > +type nonrec t = < age: int [@attr ] ;name: string > +type nonrec t = < age: int [@attr ] ;name: string [@attr2 ] > type nonrec domProps = { label: string [@bs.optional ]; diff --git a/tests/parsing/grammar/typexpr/__snapshots__/parse.spec.js.snap b/tests/parsing/grammar/typexpr/__snapshots__/parse.spec.js.snap index 29816760..9376bc76 100644 --- a/tests/parsing/grammar/typexpr/__snapshots__/parse.spec.js.snap +++ b/tests/parsing/grammar/typexpr/__snapshots__/parse.spec.js.snap @@ -39,15 +39,15 @@ let (t : _) = x" `; exports[`bsObject.js 1`] = ` -"type nonrec t = < age: int > Js.t -type nonrec t = < age: int > Js.t -type nonrec t = < age: int ;name: string > Js.t -type nonrec t = < age: int ;name: string > Js.t +"type nonrec t = < age: int > +type nonrec t = < age: int > +type nonrec t = < age: int ;name: string > +type nonrec t = < age: int ;name: string > type nonrec t = - < age: int [@attr ] ;name: ((string)[@onTypeString ]) [@attr2 ] > Js.t -type nonrec t = < > Js.t -type nonrec t = private < > Js.t -type nonrec t = < .. > Js.t" + < age: int [@attr ] ;name: ((string)[@onTypeString ]) [@attr2 ] > +type nonrec t = < > +type nonrec t = private < > +type nonrec t = < .. > " `; exports[`es6Arrow.js 1`] = ` @@ -95,7 +95,7 @@ type nonrec t = [@attrBeforeLblA ]) type nonrec t = ((a:((int)[@ns.namedArgLoc ]) -> unit)[@attr ]) type nonrec 'a getInitialPropsFn = - < query: string Js.Dict.t ;req: 'a Js.t Js.Nullable.t > Js.t -> + < query: string Js.Dict.t ;req: 'a Js.t Js.Nullable.t > -> 'a Js.t Js.Promise.t" `; @@ -126,8 +126,8 @@ exports[`poly.js 1`] = ` unit -> < log: 'a -> unit ;log2: 'a . int -> int ;log3: 'a 'b . 'a -> 'b -> int - > - Js.t = \\"./src/logger.mock.js\\"" + > = + \\"./src/logger.mock.js\\"" `; exports[`polyVariant.res 1`] = ` @@ -165,20 +165,20 @@ type nonrec t = (a, b, c) Mod.Sub.t type nonrec t = (a, b, c) Mod.Sub.t type nonrec t = list type nonrec t = string list -type nonrec t = < age: int > Js.t list -type nonrec t = (< age: int > Js.t, < name: string > Js.t) list -type nonrec t = < .. > Js.t -type nonrec t = < .. > Js.t list -type nonrec t = < age: int ;.. > Js.t -type nonrec t = < age: int ;.. > Js.t list -type nonrec t = < age: int [@attr ] ;.. > Js.t -type nonrec t = < age: int [@attr ] ;.. > Js.t list -type nonrec t = < age: int [@attr ] ;name: string [@attr ] ;.. > Js.t -type nonrec t = < age: int [@attr ] ;name: string [@attr ] ;.. > Js.t list -type nonrec t = < age: int ;.. > Js.t -type nonrec t = < age: int ;.. > Js.t list -type nonrec t = < age: int ;name: string ;.. > Js.t -type nonrec t = < age: int ;name: string ;.. > Js.t list +type nonrec t = < age: int > list +type nonrec t = (< age: int > , < name: string > ) list +type nonrec t = < .. > +type nonrec t = < .. > list +type nonrec t = < age: int ;.. > +type nonrec t = < age: int ;.. > list +type nonrec t = < age: int [@attr ] ;.. > +type nonrec t = < age: int [@attr ] ;.. > list +type nonrec t = < age: int [@attr ] ;name: string [@attr ] ;.. > +type nonrec t = < age: int [@attr ] ;name: string [@attr ] ;.. > list +type nonrec t = < age: int ;.. > +type nonrec t = < age: int ;.. > list +type nonrec t = < age: int ;name: string ;.. > +type nonrec t = < age: int ;name: string ;.. > list let (t : string) = x let (t : Parser.t) = x let (t : Lang.Parser.t) = x @@ -190,28 +190,27 @@ let (t : (a, b, c) Mod.Sub.t) = x let (t : (a, b, c) Mod.Sub.t) = x let (t : list) = x let (t : string list) = x -let (t : < age: int > Js.t list) = x -let (t : < age: int > Js.t list) = x -let (t : < age: int [@attr ] > Js.t list) = x -let (t : < age: int [@attr ] > Js.t list) = x -let (t : < age: int [@attr ] ;name: string [@attr ] > Js.t list) = x -let (t : (< age: int > Js.t, < name: string > Js.t) list) = x +let (t : < age: int > list) = x +let (t : < age: int > list) = x +let (t : < age: int [@attr ] > list) = x +let (t : < age: int [@attr ] > list) = x +let (t : < age: int [@attr ] ;name: string [@attr ] > list) = x +let (t : (< age: int > , < name: string > ) list) = x +let (t : (< age: int [@attr ] > , < name: string [@attr ] > ) list) = x let (t : - (< age: int [@attr ] > Js.t, < name: string [@attr ] > Js.t) list) = x -let (t : - (< age: int [@attr ] ;name: string [@attr ] > Js.t, - < name: string [@attr ] ;age: int [@attr ] > Js.t) list) + (< age: int [@attr ] ;name: string [@attr ] > , + < name: string [@attr ] ;age: int [@attr ] > ) list) = x -let (t : < .. > Js.t list) = x -let (t : < > Js.t list) = x -let (t : < age: int ;.. > Js.t list) = x -let (t : < age: int > Js.t list) = x -let (t : < age: int ;.. > Js.t list) = x -let (t : < age: int [@attr ] ;.. > Js.t list) = x -let (t : < age: int [@attr ] > Js.t list) = x -let (t : < age: int [@attr ] ;.. > Js.t list) = x -let (t : < age: int ;name: string ;.. > Js.t list) = x -let (t : < age: int [@attr ] ;name: string [@attr ] ;.. > Js.t list) = x +let (t : < .. > list) = x +let (t : < > list) = x +let (t : < age: int ;.. > list) = x +let (t : < age: int > list) = x +let (t : < age: int ;.. > list) = x +let (t : < age: int [@attr ] ;.. > list) = x +let (t : < age: int [@attr ] > list) = x +let (t : < age: int [@attr ] ;.. > list) = x +let (t : < age: int ;name: string ;.. > list) = x +let (t : < age: int [@attr ] ;name: string [@attr ] ;.. > list) = x let (t : string list) = x" `; diff --git a/tests/printer/typexpr/__snapshots__/render.spec.js.snap b/tests/printer/typexpr/__snapshots__/render.spec.js.snap index ad537259..741bf27b 100644 --- a/tests/printer/typexpr/__snapshots__/render.spec.js.snap +++ b/tests/printer/typexpr/__snapshots__/render.spec.js.snap @@ -327,7 +327,8 @@ external test: ( foo, bar, baz, -) => @attr {.. +) => @attr +{.. \\"age\\": int, \\"name\\": string, \\"moreFields\\": veryVeryVeryLongtype, From 7b2fce969109bd5c4fa02abaac6d0abd6554a918 Mon Sep 17 00:00:00 2001 From: Cheng Lou Date: Sat, 27 Feb 2021 05:12:06 -0800 Subject: [PATCH 2/3] Clean up name, Remove another specialized Js.t printer logic The removal of this printer logic fixes a bug where `type a = @b Js.t<{"a": b}>`, when printed, loses the attribute --- src/res_printer.ml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/res_printer.ml b/src/res_printer.ml index 8c77d9e2..b64c4106 100644 --- a/src/res_printer.ml +++ b/src/res_printer.ml @@ -1426,7 +1426,7 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = (* object printings *) | Ptyp_object (fields, openFlag) -> - printBsObjectSugar ~inline:false fields openFlag cmtTbl + printObject ~inline:false fields openFlag cmtTbl | Ptyp_constr(longidentLoc, [{ptyp_desc = Ptyp_object (fields, openFlag)}]) -> (* for foo<{"a": b}>, when the object is long and needs a line break, we want the <{ and }> to stay hugged together *) @@ -1434,7 +1434,7 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = Doc.concat([ constrName; Doc.lessThan; - printBsObjectSugar ~inline:true fields openFlag cmtTbl; + printObject ~inline:true fields openFlag cmtTbl; Doc.greaterThan; ]) @@ -1641,8 +1641,7 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = ) in let shouldPrintItsOwnAttributes = match typExpr.ptyp_desc with - | Ptyp_arrow _ (* es6 arrow types print their own attributes *) - | Ptyp_constr({txt = Longident.Ldot(Longident.Lident "Js", "t")}, _) -> true + | Ptyp_arrow _ (* es6 arrow types print their own attributes *) -> true | _ -> false in let doc = begin match typExpr.ptyp_attributes with @@ -1658,7 +1657,7 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = in printComments doc cmtTbl typExpr.ptyp_loc -and printBsObjectSugar ~inline fields openFlag cmtTbl = +and printObject ~inline fields openFlag cmtTbl = let doc = match fields with | [] -> Doc.concat [ Doc.lbrace; From 4d221742342cc2c2f6c639cd9bf3fe05f91fd44a Mon Sep 17 00:00:00 2001 From: Cheng Lou Date: Sat, 27 Feb 2021 08:49:49 -0800 Subject: [PATCH 3/3] Add conversion test for Js.t --- src/res_ast_conversion.ml | 17 ++++----------- .../reason/__snapshots__/render.spec.js.snap | 21 +++++++++++++++++++ tests/conversion/reason/jsObject.re | 9 ++++++++ tests/conversion/reason/jsObject.rei | 8 +++++++ 4 files changed, 42 insertions(+), 13 deletions(-) create mode 100644 tests/conversion/reason/jsObject.rei diff --git a/src/res_ast_conversion.ml b/src/res_ast_conversion.ml index c4ef8d87..f583cd66 100644 --- a/src/res_ast_conversion.ml +++ b/src/res_ast_conversion.ml @@ -385,19 +385,10 @@ let normalize = end; typ = (fun mapper typ -> match typ.ptyp_desc with - | Ptyp_constr( - {txt = Longident.Ldot(Longident.Lident "Js", "t")}, - [{ptyp_desc = Ptyp_object (fields, openFlag)} as objectType] - ) -> - (* Js.t({"a": b}) -> {"a": b}. Since compiler >9.0.1 objects don't - need Js.t wrapping anymore *) - let newFields = fields |> List.map (fun (field: Parsetree.object_field) -> - match field with - | Otag (label, attributes, typ) -> Parsetree.Otag (label, attributes, mapper.typ mapper typ) - | Oinherit typ -> Oinherit (mapper.typ mapper typ) - ) - in - {objectType with ptyp_desc = Ptyp_object (newFields, openFlag)} + | Ptyp_constr({txt = Longident.Ldot(Longident.Lident "Js", "t")}, [arg]) -> + (* Js.t({"a": b}) -> {"a": b} + Since compiler >9.0.1 objects don't need Js.t wrapping anymore *) + mapper.typ mapper arg | _ -> default_mapper.typ mapper typ ); expr = (fun mapper expr -> diff --git a/tests/conversion/reason/__snapshots__/render.spec.js.snap b/tests/conversion/reason/__snapshots__/render.spec.js.snap index 511ab3e4..7f6e76d7 100644 --- a/tests/conversion/reason/__snapshots__/render.spec.js.snap +++ b/tests/conversion/reason/__snapshots__/render.spec.js.snap @@ -1257,6 +1257,27 @@ let element = props[\\"element\\"] let y = {\\"age\\": 30} let y = {\\"age\\": 30, \\"name\\": \\"steve\\"} + +type propField<'a> = {.} +type propField<'a> = {..} as 'a +type propField<'a> = {..} as 'a +type propField<'a> = Js.nullable<{..} as 'a> + +type propField<'a> = {\\"a\\": b} +type propField<'a> = {..\\"a\\": b} +type propField<'a> = {\\"a\\": {\\"b\\": c}} +" +`; + +exports[`jsObject.rei 1`] = ` +"type propField<'a> = {.} +type propField<'a> = {..} as 'a +type propField<'a> = {..} as 'a +type propField<'a> = Js.nullable<{..} as 'a> + +type propField<'a> = {\\"a\\": b} +type propField<'a> = {..\\"a\\": b} +type propField<'a> = {\\"a\\": {\\"b\\": c}} " `; diff --git a/tests/conversion/reason/jsObject.re b/tests/conversion/reason/jsObject.re index ec85c76e..48aa165b 100644 --- a/tests/conversion/reason/jsObject.re +++ b/tests/conversion/reason/jsObject.re @@ -4,3 +4,12 @@ let element = props##element let y = {"age": 30} let y = {"age": 30, "name": "steve"} + +type propField('a) = Js.t({.}) +type propField('a) = Js.t({..} as 'a) +type propField('a) = Js.t({..}) as 'a +type propField('a) = Js.nullable(Js.t({..} as 'a)) + +type propField('a) = {. "a": b} +type propField('a) = {.. "a": b} +type propField('a) = Js.t(Js.t({. "a": Js.t({. "b": c})})) diff --git a/tests/conversion/reason/jsObject.rei b/tests/conversion/reason/jsObject.rei new file mode 100644 index 00000000..6e72edd7 --- /dev/null +++ b/tests/conversion/reason/jsObject.rei @@ -0,0 +1,8 @@ +type propField('a) = Js.t({.}) +type propField('a) = Js.t({..} as 'a) +type propField('a) = Js.t({..}) as 'a +type propField('a) = Js.nullable(Js.t({..} as 'a)) + +type propField('a) = {. "a": b} +type propField('a) = {.. "a": b} +type propField('a) = Js.t(Js.t({. "a": Js.t({. "b": c})}))