diff --git a/cli/bin/grain.js b/cli/bin/grain.js index aba8237951..4d52daabce 100755 --- a/cli/bin/grain.js +++ b/cli/bin/grain.js @@ -215,6 +215,10 @@ program program .command("doc ") .description("generate documentation for a grain file") + .forwardOption( + "--current-version ", + "provide a version to use as current when generating markdown for `@since` and `@history` attributes" + ) .action( wrapAction(function (file, options, program) { doc(file, program); diff --git a/compiler/graindoc/docblock.re b/compiler/graindoc/docblock.re index cebfe311e5..0808a0baa2 100644 --- a/compiler/graindoc/docblock.re +++ b/compiler/graindoc/docblock.re @@ -11,6 +11,27 @@ type t = { attributes: list(Comments.Attribute.t), }; +exception + MissingFlag({ + flag: string, + attr: string, + }); + +let () = + Printexc.register_printer(exn => { + switch (exn) { + | MissingFlag({flag, attr}) => + let msg = + Printf.sprintf( + "Must provide %s when generating docs with `%s` attribute.", + flag, + attr, + ); + Some(msg); + | _ => None + } + }); + let module_name_of_location = (loc: Grain_parsing.Location.t) => { Grain_utils.Files.filename_to_module_name(loc.loc_start.pos_fname); }; @@ -27,6 +48,35 @@ let title_for_api = (~module_name, ident: Ident.t) => { Format.asprintf("%s.**%a**", module_name, Printtyp.ident, ident); }; +let output_for_since = (~current_version, attr_version) => { + let current_version = + switch (current_version) { + | Some(version) => version + | None => raise(MissingFlag({flag: "--current-version", attr: "@since"})) + }; + let (<) = Version.String.less_than; + if (current_version < attr_version) { + Format.sprintf("Added in %s", Html.code("next")); + } else { + Format.sprintf("Added in %s", Html.code(attr_version)); + }; +}; + +let output_for_history = (~current_version, attr_version, attr_desc) => { + let current_version = + switch (current_version) { + | Some(version) => version + | None => + raise(MissingFlag({flag: "--current-version", attr: "@history"})) + }; + let (<) = Version.String.less_than; + if (current_version < attr_version) { + [Html.code("next"), attr_desc]; + } else { + [Html.code(attr_version), attr_desc]; + }; +}; + let types_for_function = (~ident, vd: Types.value_description) => { switch (Ctype.repr(vd.val_type).desc) { | TTyArrow(_) => @@ -162,12 +212,7 @@ let to_markdown = (~current_version, docblock) => { |> Option.map((attr: Comments.Attribute.t) => { switch (attr) { | Since({attr_version}) => - let (<) = Version.String.less_than; - if (current_version < attr_version) { - Format.sprintf("Added in %s", Html.code("next")); - } else { - Format.sprintf("Added in %s", Html.code(attr_version)); - }; + output_for_since(~current_version, attr_version) | _ => failwith("Unreachable: Non-`since` attribute can't exist here.") } @@ -178,12 +223,7 @@ let to_markdown = (~current_version, docblock) => { |> List.map((attr: Comments.Attribute.t) => { switch (attr) { | History({attr_version, attr_desc}) => - let (<) = Version.String.less_than; - if (current_version < attr_version) { - [Html.code("next"), attr_desc]; - } else { - [Html.code(attr_version), attr_desc]; - }; + output_for_history(~current_version, attr_version, attr_desc) | _ => failwith("Unreachable: Non-`since` attribute can't exist here.") } diff --git a/compiler/graindoc/graindoc.re b/compiler/graindoc/graindoc.re index 69257930e4..8d528ba275 100644 --- a/compiler/graindoc/graindoc.re +++ b/compiler/graindoc/graindoc.re @@ -67,6 +67,12 @@ type params = { /** Output filename */ [@name "o"] [@docv "FILE"] output: option(Output.t), + /** + The version to use as current when generating markdown for `@since` and `@history` attributes. + Any future versions will be replace with `next` in the output. + */ + [@name "current-version"] [@docv "VERSION"] + current_version: option(string), }; let compile_typed = (opts: params) => { @@ -97,11 +103,7 @@ let compile_typed = (opts: params) => { }; let generate_docs = - ( - ~version as current_version, - opts: params, - program: Typedtree.typed_program, - ) => { + ({current_version, output}: params, program: Typedtree.typed_program) => { Comments.setup_comments(program.comments); let env = program.env; @@ -132,12 +134,7 @@ let generate_docs = |> Option.map((attr: Comments.Attribute.t) => { switch (attr) { | Since({attr_version}) => - let (<) = Version.String.less_than; - if (current_version < attr_version) { - Format.sprintf("Added in %s", Html.code("next")); - } else { - Format.sprintf("Added in %s", Html.code(attr_version)); - }; + Docblock.output_for_since(~current_version, attr_version) | _ => failwith("Unreachable: Non-`since` attribute can't exist here.") } @@ -148,12 +145,11 @@ let generate_docs = |> List.map((attr: Comments.Attribute.t) => { switch (attr) { | History({attr_version, attr_desc}) => - let (<) = Version.String.less_than; - if (current_version < attr_version) { - [Html.code("next"), attr_desc]; - } else { - [Html.code(attr_version), attr_desc]; - }; + Docblock.output_for_history( + ~current_version, + attr_version, + attr_desc, + ) | _ => failwith("Unreachable: Non-`since` attribute can't exist here.") } @@ -240,7 +236,7 @@ let generate_docs = }; let contents = Buffer.to_bytes(buf); - switch (opts.output) { + switch (output) { | Some(outfile) => let oc = Fs_access.open_file_for_writing(outfile); output_bytes(oc, contents); @@ -251,13 +247,14 @@ let generate_docs = `Ok(); }; -let graindoc = (~version, opts) => - try({ - let program = compile_typed(opts); - generate_docs(~version, opts, program); - }) { - | e => `Error((false, Printexc.to_string(e))) +let graindoc = opts => { + let program = compile_typed(opts); + try(generate_docs(opts, program)) { + | exn => + Format.eprintf("@[%s@]@.", Printexc.to_string(exn)); + exit(2); }; +}; let cmd = { open Term; @@ -270,8 +267,7 @@ let cmd = { }; ( - Grain_utils.Config.with_cli_options(graindoc(~version)) - $ params_cmdliner_term(), + Grain_utils.Config.with_cli_options(graindoc) $ params_cmdliner_term(), Term.info(Sys.argv[0], ~version, ~doc), ); }; diff --git a/stdlib/array.md b/stdlib/array.md index f3919b88c1..2b777e9b2c 100644 --- a/stdlib/array.md +++ b/stdlib/array.md @@ -266,7 +266,7 @@ Returns: ### Array.**cycle**
-Added in next +Added in 0.4.4 No other changes yet.
@@ -1030,7 +1030,7 @@ Returns: ### Array.**sort**
-Added in next +Added in 0.4.5 No other changes yet.
@@ -1052,7 +1052,7 @@ Parameters: ### Array.**rotate**
-Added in next +Added in 0.4.5 No other changes yet.
diff --git a/stdlib/number.md b/stdlib/number.md index 6f7ee7a81b..e783e35345 100644 --- a/stdlib/number.md +++ b/stdlib/number.md @@ -459,7 +459,7 @@ Returns: ### Number.**parseInt**
-Added in next +Added in 0.4.5 No other changes yet.
diff --git a/stdlib/option.md b/stdlib/option.md index 95c3a3cf1f..3e49ba1f71 100644 --- a/stdlib/option.md +++ b/stdlib/option.md @@ -533,7 +533,7 @@ No other changes yet. ```grain -( or ) : (Option, Option) -> Option +or : (Option, Option) -> Option ``` Behaves like a logical OR (`||`) where the first Option is only returned if it is the `Some` variant and falling back to the second Option in all other cases. diff --git a/stdlib/result.md b/stdlib/result.md index f2f178c154..6bfe4c76dc 100644 --- a/stdlib/result.md +++ b/stdlib/result.md @@ -272,7 +272,7 @@ No other changes yet. ```grain -( or ) : (Result, Result) -> Result +or : (Result, Result) -> Result ``` Behaves like a logical OR (`||`) where the first Result is only returned if it is the `Ok` variant and falling back to the second Result in all other cases. diff --git a/stdlib/string.md b/stdlib/string.md index 11c1d79dac..93994daf2c 100644 --- a/stdlib/string.md +++ b/stdlib/string.md @@ -266,7 +266,7 @@ String.implode([> 'H', 'e', 'l', 'l', 'o']) == "Hello" ### String.**reverse**
-Added in next +Added in 0.4.5 No other changes yet.