diff --git a/CHANGELOG.md b/CHANGELOG.md index e13fb46245..c9db29e839 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ # 11.0.0-beta.5 (Unreleased) +#### :rocket: New Feature + +- GenType: Propagate comments from record fields to emitted TypeScript types. https://github.com/rescript-lang/rescript-compiler/pull/6333 + # 11.0.0-beta.4 #### :rocket: New Feature diff --git a/jscomp/gentype/Annotation.ml b/jscomp/gentype/Annotation.ml index c24d9dd321..a3521a2af2 100644 --- a/jscomp/gentype/Annotation.ml +++ b/jscomp/gentype/Annotation.ml @@ -33,7 +33,10 @@ let tagIsOneOfTheGenTypeAnnotations s = let tagIsGenTypeIgnoreInterface s = s = "genType.ignoreInterface" || s = "gentype.ignoreInterface" -let tagIsOcamlDoc s = s = "ocaml.doc" +let tagIsDoc s = + match s with + | "ocaml.doc" | "res.doc" -> true + | _ -> false let tagIsInternLocal s = s = "internal.local" let rec getAttributePayload checkText (attributes : Typedtree.attributes) = @@ -143,12 +146,19 @@ let getAttributeImportRenaming attributes = (Some importString, Some renameString) | _ -> (None, genTypeAsRenaming) -let getDocString attributes = - let docPayload = attributes |> getAttributePayload tagIsOcamlDoc in +let getDocPayload attributes = + let docPayload = attributes |> getAttributePayload tagIsDoc in match docPayload with - | Some (_, StringPayload docString) -> "/** " ^ docString ^ " */\n" + | Some (_, StringPayload docString) -> Some docString + | _ -> None + +let mkDocString maybeDoc = + match maybeDoc with + | Some docString -> "/** " ^ docString ^ " */\n" | _ -> "" +let getDocString attributes = getDocPayload attributes |> mkDocString + let hasAttribute checkText (attributes : Typedtree.attributes) = getAttributePayload checkText attributes <> None diff --git a/jscomp/gentype/EmitType.ml b/jscomp/gentype/EmitType.ml index 8b60601e2b..aa3792b72e 100644 --- a/jscomp/gentype/EmitType.ml +++ b/jscomp/gentype/EmitType.ml @@ -47,6 +47,7 @@ let typeReactRef ~type_ = nameJS = reactRefCurrent; optional = Mandatory; type_ = Null type_; + docString = None; }; ] ) @@ -162,12 +163,13 @@ let rec renderType ~(config : Config.t) ?(indent = None) ~typeNameIsInterface type_ |> renderType ~config ~indent ~typeNameIsInterface ~inFunType) in let noPayloadsRendered = noPayloads |> List.map labelJSToString in - let field ~name value = + let field ~name ?docString value = { mutable_ = Mutable; nameJS = name; optional = Mandatory; type_ = TypeVar value; + docString; } in let fields fields = @@ -232,7 +234,7 @@ let rec renderType ~(config : Config.t) ?(indent = None) ~typeNameIsInterface ^ "| ")) and renderField ~config ~indent ~typeNameIsInterface ~inFunType - {mutable_; nameJS = lbl; optional; type_} = + {mutable_; nameJS = lbl; optional; type_; docString} = let optMarker = match optional == Optional with | true -> "?" @@ -249,8 +251,16 @@ and renderField ~config ~indent ~typeNameIsInterface ~inFunType | false -> EmitText.quotes lbl in - Indent.break ~indent ^ mutMarker ^ lbl ^ optMarker ^ ": " - ^ (type_ |> renderType ~config ~indent ~typeNameIsInterface ~inFunType) + let defStr = + mutMarker ^ lbl ^ optMarker ^ ": " + ^ (type_ |> renderType ~config ~indent ~typeNameIsInterface ~inFunType) + in + match docString with + | None -> Indent.break ~indent ^ defStr + | Some docString -> + (* Always print comments on newline before definition. *) + let indentStr = indent |> Option.value ~default:"" in + "\n" ^ indentStr ^ "/**" ^ docString ^ "*/\n" ^ indentStr ^ defStr and renderFields ~config ~indent ~inFunType ~typeNameIsInterface fields = let indent1 = indent |> Indent.more in diff --git a/jscomp/gentype/ExportModule.ml b/jscomp/gentype/ExportModule.ml index 467166f143..de799570fa 100644 --- a/jscomp/gentype/ExportModule.ml +++ b/jscomp/gentype/ExportModule.ml @@ -39,6 +39,7 @@ and exportModuleItemToFields = nameJS = fieldName; optional = Mandatory; type_ = typeForType; + docString = None; } in let fieldForValue = {fieldForType with type_ = typeForValue} in diff --git a/jscomp/gentype/GenTypeCommon.ml b/jscomp/gentype/GenTypeCommon.ml index f90b6fb549..b41c98a8fc 100644 --- a/jscomp/gentype/GenTypeCommon.ml +++ b/jscomp/gentype/GenTypeCommon.ml @@ -78,6 +78,7 @@ and field = { nameJS: string; optional: optional; type_: type_; + docString: string option; } and function_ = {argTypes: argType list; retType: type_; typeVars: string list} diff --git a/jscomp/gentype/NamedArgs.ml b/jscomp/gentype/NamedArgs.ml index 18b39ab58d..bd3190e7e5 100644 --- a/jscomp/gentype/NamedArgs.ml +++ b/jscomp/gentype/NamedArgs.ml @@ -14,13 +14,25 @@ let rec groupReversed ~revCurGroup ~revResult labeledTypes = (* Add it to the current group, not result. *) groupReversed ~revCurGroup: - ({mutable_ = Immutable; nameJS = name; optional = Optional; type_} + ({ + mutable_ = Immutable; + nameJS = name; + optional = Optional; + type_; + docString = None; + } :: revCurGroup) ~revResult tl | _, (Label name, type_) :: tl -> groupReversed ~revCurGroup: - ({mutable_ = Immutable; nameJS = name; optional = Mandatory; type_} + ({ + mutable_ = Immutable; + nameJS = name; + optional = Mandatory; + type_; + docString = None; + } :: revCurGroup) ~revResult tl | [], [] -> revResult diff --git a/jscomp/gentype/TranslateTypeDeclarations.ml b/jscomp/gentype/TranslateTypeDeclarations.ml index 3b5d86e8b4..7a3ac0b149 100644 --- a/jscomp/gentype/TranslateTypeDeclarations.ml +++ b/jscomp/gentype/TranslateTypeDeclarations.ml @@ -103,23 +103,26 @@ let traslateDeclarationKind ~config ~loc ~outputFileRelative ~resolver mutability, ld_type |> TranslateTypeExprFromTypes.translateTypeExprFromTypes ~config - ~typeEnv )) + ~typeEnv, + Annotation.getDocPayload ld_attributes )) in let dependencies = fieldTranslations - |> List.map (fun (_, _, {TranslateTypeExprFromTypes.dependencies}) -> + |> List.map (fun (_, _, {TranslateTypeExprFromTypes.dependencies}, _) -> dependencies) |> List.concat in let fields = fieldTranslations - |> List.map (fun (name, mutable_, {TranslateTypeExprFromTypes.type_}) -> + |> List.map + (fun (name, mutable_, {TranslateTypeExprFromTypes.type_}, docString) + -> let optional, type1 = match type_ with | Option type1 when isOptional name -> (Optional, type1) | _ -> (Mandatory, type_) in - {mutable_; nameJS = name; optional; type_ = type1}) + {mutable_; nameJS = name; optional; type_ = type1; docString}) in let type_ = match fields with diff --git a/jscomp/gentype/TranslateTypeExprFromTypes.ml b/jscomp/gentype/TranslateTypeExprFromTypes.ml index d97f817ba3..c7c2569a32 100644 --- a/jscomp/gentype/TranslateTypeExprFromTypes.ml +++ b/jscomp/gentype/TranslateTypeExprFromTypes.ml @@ -45,7 +45,7 @@ let translateObjType closedFlag fieldsTranslations = | _ -> (Mandatory, t) in let name = name |> Runtime.mangleObjectField in - {mutable_; nameJS = name; optional; type_}) + {mutable_; nameJS = name; optional; type_; docString = None}) in let type_ = Object (closedFlag, fields) in {dependencies; type_} @@ -126,6 +126,7 @@ let translateConstr ~config ~paramsTranslation ~(path : Path.t) ~typeEnv = nameJS = "contents"; optional = Mandatory; type_ = paramTranslation.type_; + docString = None; }; ] ); } @@ -465,7 +466,7 @@ and signatureToModuleRuntimeRepresentation ~config ~typeVarsGen ~typeEnv |> List.map (fun signatureItem -> match signatureItem with | Types.Sig_value (_id, {val_kind = Val_prim _}) -> ([], []) - | Types.Sig_value (id, {val_type = typeExpr}) -> + | Types.Sig_value (id, {val_type = typeExpr; val_attributes}) -> let {dependencies; type_} = typeExpr |> translateTypeExprFromTypes_ ~config ~typeVarsGen ~typeEnv @@ -476,6 +477,7 @@ and signatureToModuleRuntimeRepresentation ~config ~typeVarsGen ~typeEnv nameJS = id |> Ident.name; optional = Mandatory; type_; + docString = Annotation.getDocPayload val_attributes; } in (dependencies, [field]) @@ -499,6 +501,8 @@ and signatureToModuleRuntimeRepresentation ~config ~typeVarsGen ~typeEnv nameJS = id |> Ident.name; optional = Mandatory; type_; + docString = + Annotation.getDocPayload moduleDeclaration.md_attributes; } in (dependencies, [field]) diff --git a/jscomp/gentype_tests/typescript-react-example/package-lock.json b/jscomp/gentype_tests/typescript-react-example/package-lock.json index 03ddaf278c..5c0087119d 100644 --- a/jscomp/gentype_tests/typescript-react-example/package-lock.json +++ b/jscomp/gentype_tests/typescript-react-example/package-lock.json @@ -21,7 +21,7 @@ }, "../../..": { "name": "rescript", - "version": "11.0.0-beta.2", + "version": "11.0.0-beta.5", "dev": true, "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE", diff --git a/jscomp/gentype_tests/typescript-react-example/src/Comments.bs.js b/jscomp/gentype_tests/typescript-react-example/src/Comments.bs.js new file mode 100644 index 0000000000..2575585401 --- /dev/null +++ b/jscomp/gentype_tests/typescript-react-example/src/Comments.bs.js @@ -0,0 +1,15 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +function _placeholder(run, times) { + +} + +var DecideSubject = { + _placeholder: _placeholder +}; + +export { + DecideSubject , +} +/* No side effect */ diff --git a/jscomp/gentype_tests/typescript-react-example/src/Comments.gen.tsx b/jscomp/gentype_tests/typescript-react-example/src/Comments.gen.tsx new file mode 100644 index 0000000000..796a3ffcdd --- /dev/null +++ b/jscomp/gentype_tests/typescript-react-example/src/Comments.gen.tsx @@ -0,0 +1,30 @@ +/* TypeScript file generated from Comments.res by genType. */ +/* eslint-disable import/first */ + + +// @ts-ignore: Implicit any on import +import * as CommentsBS__Es6Import from './Comments.bs'; +const CommentsBS: any = CommentsBS__Es6Import; + +// tslint:disable-next-line:interface-over-type-literal +export type DecideSubject_payload = { +/** A hint to use as a guide when thinking of your poem.*/ +readonly hint: string }; + +// tslint:disable-next-line:max-classes-per-file +export abstract class DecideSubject_input { protected opaque!: any }; /* simulate opaque types */ + +// tslint:disable-next-line:interface-over-type-literal +export type DecideSubject_output = { + /** The text of the poem.*/ + readonly text: string; + /** The prompt used to generate the poem.*/ + readonly prompt: string; + /** The system prompt used to generate the poem.*/ + readonly systemPrompt: string +}; + +/** Decide on a subject matter for a poem. */ +export const DecideSubject__placeholder: (run:string, times:number) => void = CommentsBS.DecideSubject._placeholder; + +export const DecideSubject: { _placeholder: (run:string, times:number) => void } = CommentsBS.DecideSubject diff --git a/jscomp/gentype_tests/typescript-react-example/src/Comments.res b/jscomp/gentype_tests/typescript-react-example/src/Comments.res new file mode 100644 index 0000000000..e70c756021 --- /dev/null +++ b/jscomp/gentype_tests/typescript-react-example/src/Comments.res @@ -0,0 +1,24 @@ +@genType /** A module for deciding on a subject matter for a poem.*/ +module DecideSubject = { + type payload = { + /** A hint to use as a guide when thinking of your poem.*/ + hint: string, + } + /** The input used to generate the prompt and system prompt.*/ + type input + /** The output from evaluating the llm prompt*/ + type output = { + /** The text of the poem.*/ + text: string, + /** The prompt used to generate the poem.*/ + prompt: string, + /** The system prompt used to generate the poem.*/ + systemPrompt: string, + } + + @genType /** Decide on a subject matter for a poem.*/ + let _placeholder = ( + @ocaml.doc("The runner specification") run: string, + @ocaml.doc("The number of times to cycle through the runner") times: int, + ) => (run, times)->ignore +}